自宅内でガラケー・ガラホ・スマホの着信を大音量化する

前回と同様のネタです。

実は祖母の家での携帯電話運用にはもう1つ問題があり、それはガラケーの着信音が小さすぎて着信に気づかない、という問題です。
外出時は問題ないのですが、家の中、特に別の部屋に置きっぱなしになっている場合この問題が発生します。
お年寄りにはありがちな問題かと思いますが、意外とこの問題に対する解決策が見当たらないんですよね。
個人的に思いついたのは以下3つ。

①セルラー回線に対応した固定電話を設置する
要はワイモバ等で販売されているイエデンワみたいなやつです。
これなら着信音量も上げられますし前回のネタにあった充電忘れの問題もなくなります。
デメリットは、回線契約を追加しないと携帯電話として持ち運びできなくなること、回線契約を追加した場合維持費がかかること、そして何より固定電話機自体が結構お高いことです。

②Bluetooth対応の固定電話を設置する
世の中には結構面白い製品があって、それがBluetooth対応の固定電話です。
例えばこちらの固定電話、スマートフォンの着信がとれる「スマホコネクト」という機能があり、スマートフォンがマナーモードや充電中でも、固定電話の着信音で電話に気づき、取り逃し防止になります。
恐らくガラケーでもBluetoothに対応した機種であれば使えると思います。
このような製品を買うというのも一つですね。中古なら①より安く上がると思います。




③Raspberry Pi Zeroを用いて解決する。
今回は既に前回のネタを実現するためにRPI Zeroを使っているので、なるべく物を増やさないためにもRPI Zeroで解決しました。
一応2パターン用意しており、
Aパターン:Android端末(Bluetooth非対応機種やガラホでもOK)
Bパターン:Bluetooth対応機器(ガラケーでもOK)
このどちらかを満たしていれば使えるようになっています。
※本当は祖母のかんたん携帯がBluetooth非対応なのでBluetooth非対応ガラケーでも何とかしたかったのですが、それは私の技量では対応不可能でした。結局Bluetooth対応ガラケーを中古で買いました。

Aパターン


まずはAパターンです。構成は前回と変わらず以下の通りです。

スピーカー ⇔ (イヤホンジャック接続) ⇔ RPI Zero ⇔ (USB接続) ⇔ Android端末

ここで、Android端末はadb接続してください。
RPI Zeroへのadbのインストールは以下のページを参考にしました。




そして、以下のpythonプログラムをcrontabでRPI Zero起動時に実行するようにしました。



  1. import commands
  2. import time
  3. from mutagen.mp3 import MP3 as mp3
  4. import pygame
  5. filename = 'incoming.mp3'
  6. pygame.mixer.init()
  7. pygame.mixer.music.load(filename)
  8. mp3_length = mp3(filename).info.length
  9. while 1:
  10.     usb = commands.getoutput('adb pull /mnt/sdcard/incoming ~/Desktop')
  11.     if usb == '[100%] /mnt/sdcard/incoming':
  12.         print('incoming')
  13.         pygame.mixer.music.play(1)
  14.         time.sleep(mp3_length+0.25)
  15.         pygame.mixer.music.stop()
  16.     elif usb == 'adb: error: remote object \'/mnt/sdcard/incoming\' does not exist':
  17.         print('not incoming')
  18.     elif usb == 'adb: error: connect failed: no devices/emulators found':
  19.         print('not connected')
  20.     else:
  21.         print('other state')


このプログラムでは12行目で常時adb pullをしています。adb pullが成功したら着信状態と判定し、6行目で指定したmp3ファイルを再生します。
ここでは黒電話の1コール分の音声ファイルを指定しました。

続いて、Android端末側の設定です。Android端末側にはmacrodroidというアプリを入れます。




このmacrodroidを用いて、「着信があったら/mnt/sdcard/に'incoming'というファイルを作成」し、「不在着信または通話終了があったら/mnt/sdcard/incomingというファイルを削除する」ように設定します。

着信時


不在着信または通話終了時


正確には受話する際もファイル削除するべきなのですが、多分電話を受けるときはケーブルから端末を抜き、adb pullに失敗して音が止まるので現状はこの仕様です。




Bパターン


Bパターンは少し構成が変わります。

スピーカー ⇔ (イヤホンジャック接続) ⇔ RPI Zero ⇔ (Bluetooth接続) ⇔ 携帯端末

RPI Zeroと携帯端末のBluetooth接続は以下のサイトを参考にしました。



ガラケーがPINコードがないと接続できないと言うのでその場合はこちらを。



そしてこちらのサイトを参考にofonoをインストールしました。



Bluetooth接続し、"python /usr/local/lib/ofono/test/monitor-ofono" を実行すると、着信などのイベントが表示されます。
このmonitor-ofonoを少し改造したmonitor-ofono-origがこちらになります。


  1. #!/usr/bin/python3
  2. from gi.repository import GLib
  3. import dbus
  4. import dbus.mainloop.glib
  5. import commands
  6. _dbus2py = {
  7.     dbus.String : str,
  8.     dbus.UInt32 : int,
  9.     dbus.Int32 : int,
  10.     dbus.Int16 : int,
  11.     dbus.UInt16 : int,
  12.     dbus.UInt64 : int,
  13.     dbus.Int64 : int,
  14.     dbus.Byte : int,
  15.     dbus.Boolean : bool,
  16.     dbus.ByteArray : str,
  17.     dbus.ObjectPath : str
  18.     }
  19. def dbus2py(d):
  20.     t = type(d)
  21.     if t in _dbus2py:
  22.         return _dbus2py[t](d)
  23.     if t is dbus.Dictionary:
  24.         return dict([(dbus2py(k), dbus2py(v)) for k, v in d.items()])
  25.     if t is dbus.Array and d.signature == "y":
  26.         return "".join([chr(b) for b in d])
  27.     if t is dbus.Array or t is list:
  28.         return [dbus2py(v) for v in d]
  29.     if t is dbus.Struct or t is tuple:
  30.         return tuple([dbus2py(v) for v in d])
  31.     return d
  32. def pretty(d):
  33.     d = dbus2py(d)
  34.     t = type(d)
  35.     if t in (dict, tuple, list) and len(d) > 0:
  36.         if t is dict:
  37.             d = ", ".join(["%s = %s" % (k, pretty(v))
  38.                     for k, v in d.items()])
  39.             return "{ %s }" % d
  40.         d = " ".join([pretty(e) for e in d])
  41.         if t is tuple:
  42.             return "( %s )" % d
  43.     if t is str:
  44.         return "%s" % d
  45.     return str(d)
  46. def property_changed(name, value, path, interface):
  47.     iface = interface[interface.rfind(".") + 1:]
  48.     print("{%s} [%s] %s = %s" % (iface, path, name, pretty(value)))
  49.         print("reception")
  50.         file = commands.getoutput('sudo rm /boot/program/incoming.file')
  51. def added(name, value, member, path, interface):
  52.     iface = interface[interface.rfind(".") + 1:]
  53.     print("{%s} [%s] %s %s" % (iface, member, name, pretty(value)))
  54.     print("incoming")
  55.     file = commands.getoutput('sudo touch /boot/program/incoming.file')
  56. def removed(name, member, path, interface):
  57.     iface = interface[interface.rfind(".") + 1:]
  58.     print("{%s} [%s] %s" % (iface, name, member))
  59.     print("incoming finished")
  60.     file = commands.getoutput('sudo rm /boot/program/incoming.file')
  61. def event(member, path, interface):
  62.     iface = interface[interface.rfind(".") + 1:]
  63.     print("{%s} [%s] %s" % (iface, path, member))
  64. def message(msg, args, member, path, interface):
  65.     iface = interface[interface.rfind(".") + 1:]
  66.     print("{%s} [%s] %s %s (%s)" % (iface, path, member,
  67.                     msg, pretty(args)))
  68. def ussd(msg, member, path, interface):
  69.     iface = interface[interface.rfind(".") + 1:]
  70.     print("{%s} [%s] %s %s" % (iface, path, member, msg))
  71. def value(value, member, path, interface):
  72.     iface = interface[interface.rfind(".") + 1:]
  73.     print("{%s} [%s] %s %s" % (iface, path, member, str(value)))
  74. if __name__ == '__main__':
  75.     dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
  76.     bus = dbus.SystemBus()
  77.     bus.add_signal_receiver(property_changed,
  78.                 bus_name="org.ofono",
  79.                 signal_name = "PropertyChanged",
  80.                 path_keyword="path",
  81.                 interface_keyword="interface")
  82.     for member in ["IncomingBarringInEffect",
  83.             "OutgoingBarringInEffect",
  84.             "NearMaximumWarning"]:
  85.         bus.add_signal_receiver(event,
  86.                     bus_name="org.ofono",
  87.                     signal_name = member,
  88.                     member_keyword="member",
  89.                     path_keyword="path",
  90.                     interface_keyword="interface")
  91.     for member in ["ModemAdded",
  92.             "ContextAdded",
  93.             "CallAdded",
  94.             "MessageAdded"]:
  95.         bus.add_signal_receiver(added,
  96.                     bus_name="org.ofono",
  97.                     signal_name = member,
  98.                     member_keyword="member",
  99.                     path_keyword="path",
  100.                     interface_keyword="interface")
  101.     for member in ["ModemRemoved",
  102.             "ContextRemoved",
  103.             "CallRemoved",
  104.             "MessageRemoved"]:
  105.         bus.add_signal_receiver(removed,
  106.                     bus_name="org.ofono",
  107.                     signal_name = member,
  108.                     member_keyword="member",
  109.                     path_keyword="path",
  110.                     interface_keyword="interface")
  111.     for member in ["DisconnectReason", "Forwarded", "BarringActive"]:
  112.         bus.add_signal_receiver(value,
  113.                     bus_name="org.ofono",
  114.                     signal_name = member,
  115.                     member_keyword="member",
  116.                     path_keyword="path",
  117.                     interface_keyword="interface")
  118.     for member in ["IncomingBroadcast", "EmergencyBroadcast",
  119.             "IncomingMessage", "ImmediateMessage"]:
  120.         bus.add_signal_receiver(message,
  121.                     bus_name="org.ofono",
  122.                     signal_name = member,
  123.                     member_keyword="member",
  124.                     path_keyword="path",
  125.                     interface_keyword="interface")
  126.     for member in ["NotificationReceived", "RequestReceived"]:
  127.         bus.add_signal_receiver(ussd,
  128.                     bus_name="org.ofono",
  129.                     signal_name = member,
  130.                     member_keyword="member",
  131.                     path_keyword="path",
  132.                     interface_keyword="interface")
  133.     mainloop = GLib.MainLoop()
  134.     mainloop.run()


67行目が着信時の動作で、/boot/program/incoming.fileというファイルを作成します。
57行目、73行目が受話時または不在着信時の動作で、/boot/program/incoming.fileというファイルを削除します。
つまり、AパターンでAndroid端末側が行っていた動作と同じ動作になります。
このminitor-ofono-origははオリジナルのmonitor-ofonoと同じディレクトリに置き、起動時に実行しておきます。

その上で、以下のプログラムをcrontabでRPI Zero起動時に実行します。



  1. import commands
  2. import time
  3. from mutagen.mp3 import MP3 as mp3
  4. import pygame
  5. filename = 'incoming.mp3'
  6. pygame.mixer.init()
  7. pygame.mixer.music.load(filename)
  8. mp3_length = mp3(filename).info.length
  9. commands.getoutput('sudo rm /boot/program/incoming.file')
  10. while 1:
  11.     usb = commands.getoutput('ls incoming.file')
  12.     if usb == 'incoming.file':
  13.         print('incoming')
  14.         pygame.mixer.music.play(1)
  15.         time.sleep(mp3_length+0.25)
  16.         pygame.mixer.music.stop()
  17.     else:
  18.         print('not incoming')


やっていることはAパターンとほぼ同様で、14行目でlsを行いファイルの有無を確認し、ファイルがあれば着信状態なので6行目で指定した着信音を鳴らします。



Bパターンの方を今度祖母の家に納品したいと思います。

コメント

このブログの人気の投稿

湾岸ミッドナイトの聖地についてまとめてみる

MakeMKVでリッピングに失敗する時の対処方法

中華タブレットのバッテリー交換に挑戦した話