黒電話 Bluetooth ハンズフリー機化-その7

KRay
Written by KRay on
黒電話 Bluetooth ハンズフリー機化-その7

前回 黒電話でダイヤルして番号を取得できるようになったので、今回はその取得した番号にスマホから実際に電話できるようにしていきたいと思います。

Bluetooth 接続テスト

スマホとしては iPhone を用意しました。
まずはスマホと RasPi と Bluetooth 接続してみます。
Bluetooth 接続は、以前説明したとおり、BlueZ を使います。

bluetoothctl で接続

まずは BlueZ が提供している CLI ツールである bluetoothctl を使って接続してみます。
今回は、Bluetooth 接続がどんな流れで行われるのかを確認することを目的とします(ゆくゆくは、アプリから D-Bus 経由で Bluetooth 接続できるようにします)。

BlueZ は Raspberry Pi OS にはじめからインストールされています。

➜  Kurodenwa git:(master) ✗ bluetoothctl -v
bluetoothctl: 5.55
➜  Kurodenwa git:(master) ✗ /etc/init.d/bluetooth status
● bluetooth.service - Bluetooth service
     Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2022-04-04 13:17:38 BST; 2 months 26 days ago
       Docs: man:bluetoothd(8)
   Main PID: 560 (bluetoothd)
     Status: "Running"
      Tasks: 1 (limit: 1598)
        CPU: 125ms
     CGroup: /system.slice/bluetooth.service
             └─560 /usr/libexec/bluetooth/bluetoothd

もちろんデーモンも自動起動しています。

接続テスト

参考にしたサイト
nical Notes
HFP on Raspberry Pi

  1. power on ~ scan
      ➜  Projects bluetoothctl
      # bluetoothctl を起動
      Agent registered
      [bluetooth]# power on
      Changing power on succeeded
      [bluetooth]# agent on
      Agent is already registered
      [bluetooth]# default-agent
      Default agent request successful
      # RasPi 側からスキャンする
      [bluetooth]# scan on
      Discovery started
      ...
      # iPhone のデバイス ID がわかる
      [NEW] Device XX:XX:XX:XX:XX:XX iPhone923
      [bluetooth]# scan off
    

    iPhone のデバイス ID がわかりました。
    この ID をもとに接続など行うようですね。

  2. pair
      [bluetooth]# pair XX:XX:XX:XX:XX:XX
      Attempting to pair with XX:XX:XX:XX:XX:XX
      [CHG] Device XX:XX:XX:XX:XX:XX Connected: yes
      Request confirmation
    

    image

      [agent] Confirm passkey 128871 (yes/no): yes
      Pairing successful
    

    pairing できました。

  3. trust
    ペアリングのあとは trust というステップが必要なんですね。
      [bluetooth]# trust XX:XX:XX:XX:XX:XX
      [CHG] Device XX:XX:XX:XX:XX:XX Trusted: yes
      Changing XX:XX:XX:XX:XX:XX trust succeeded
    

    trust できました。 これで Raspi 側と iPhone 側とで、お互いに Bluetooth 機器としての登録が完了したようです。

  4. connect
    実際に繋げてみます。
      [bluetooth]# connect XX:XX:XX:XX:XX:XX
      Attempting to connect to XX:XX:XX:XX:XX:XX
      [CHG] Device XX:XX:XX:XX:XX:XX Connected: yes
      Connection successful
      [iPhone923]# 
    

    iPhone 側でも paspberrypiConnected になりました。 image

ここまでで iPhone との接続が完了しました。
接続の流れもなんとなくわかりましたね。

課題の発見

今回は、bluetoothctl 側(RasPi 側)から scan しました。
この方法だと、黒電話として完成したとき、ペアリングしたい場合、黒電話の RasPi にいちいち別のコンピュータからターミナル接続して bluetoothctl を立ち上げて scan して… とすることになります(←課題)。
多分ですが、 RasPi 側を scan 待ちにして iPhone からみつけてもらう、ということもできると思います。
後ほど調べてみます。

oFono 経由で電話をかける

前回までに説明したとおり、Bluetooth 接続機能は BlueZ が、 電話機能は oFono がそれぞれ提供しています。 この状態で、oFono で電話をかければ iPhone で電話ができるはずです。

さて、どうやって oFono で電話をかければいいのでしょうか。
oFono の詳細な説明はリポジトリにある(というか、リポジトリにしかない)ので、最新版を DL してその中を漁ってみます。

まさに、手探り状態

まあ、いつもそうですが..。

サンプルコードを発見

image

test ディレクトリにサンプルコードがたくさん置いてあり、電話をかけるコードもありました。公式サイトではここ

なるほど。サンプルコードから oFono サービスに D-Bus 経由で接続して、電話をかける命令を実行しているようです。
ということは、 RasPi 上に oFono のサービスが立ち上がっている必要があります。

oFono のインストール

では、RasPi に oFono をインストールします。

➜  ~ sudo apt install ofono -y
➜  ~ /etc/init.d/ofono status
● ofono.service - Telephony service
     Loaded: loaded (/lib/systemd/system/ofono.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2022-07-03 14:08:34 BST; 2min 34s ago
   Main PID: 14459 (ofonod)
      Tasks: 1 (limit: 1598)
        CPU: 106ms
     CGroup: /system.slice/ofono.service
             └─14459 /usr/sbin/ofonod -n

Jul 03 14:08:34 raspberrypi systemd[1]: Starting Telephony service...
Jul 03 14:08:34 raspberrypi ofonod[14459]: oFono version 1.31
Jul 03 14:08:34 raspberrypi systemd[1]: Started Telephony service.

oFono サービスが起動しました。

サンプルコードで電話をかけてみる

サンプルコード実行のため、RasPi 側でも oFono の最新のソースを取得します。
git でも取得できるので、こちらを使いました。

➜  Projects git clone git://git.kernel.org/pub/scm/network/ofono/ofono.git
➜  Projects cd ofono
➜  ofono git:(master) 

RasPi と iPhone とが Bluetooth 接続されていることを確認して、 サンプルコード dial-number を実行します。

➜  ofono git:(master) python test/dial-number 000
Using modem /hfp/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX
/hfp/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/voicecall01

かかりました!

電話番号は 000 にしたので、「おかけになった電話番号は現在使われておりません…」 と自動アナウンスが流れます。
image

今回は音声の入出力を iPhone にしましたが、audio と書いてあるボタンを押すと RasPi も選べました。RasPi(黒電話)側でマイクとスピーカの準備が必要ですね。

プログラミング

Python のコード(test/dial-number)を Ruby に移植して、それを黒電話が番号を検知したあとに呼び出せばよいです。

require 'timers'
require 'dbus'
require './context'

# TODO: 接続時に取得できるようにする
MODEM = "/hfp/org/bluez/hci0/dev_xx_xx_xx_xx_xx_xx"

class Dial
  ...
  def call
    return if @dial_nums.length < 3

    context = Context.instance
    context.notify_event Events::OUTGO

    dial_str = @dial_nums.join

    # 実際に電話をかける
    bus = DBus::SystemBus.instance
    rb_service = bus.service("org.ofono")
    rb_object = rb_service.object(MODEM)
    vcm = rb_object["org.ofono.VoiceCallManager"]
    # puts vcm

    hide_callerid = 'default'
    path = vcm.Dial(dial_str, hide_callerid)
    context.notify_event Events::RESPONSED
    # puts path
  end
  ...
end

前回の Dial クラスの call メソッドに処理を追加しました。
Rury の D-Bus 用ライブラリ Ruby D-Bus を使用します。

MODEM として Bluetooth の機器 ID が必要なので、iPhone の ID を直接記載しています。
そのうちアプリから RasPi とスマホとの Bluetooth 接続を実装すれば、接続するときのスマホの ID が判明しますので、その値を代入できるようにすれば良いです。その時までは直接記載しておきます。

電話番号が3桁以上あれば、正しい番号として電話を試みます。 このとき、すぐに OUTGO イベントを発生させて context に通知します。 context では、Outgoing 状態(発信中)に遷移させます。

電話は D-Bus 経由で oFono サービスを呼び出し、 VoiceCallManager オブジェクトに対して Dial メソッドを実行します。このとき電話番号を渡します。
成功すると、 path が返ります。
本来なら、電話がかからなかったケース等、異常パターンもコーディングするべきですが今回は割愛します。
このとき、RESPONSED イベントを発生させて context に通知します。 context では、Talking 状態(通話中)に遷移させます。

状態遷移図(再掲)

今回は、簡易的に Talking 状態に遷移させました。

本来は、通話が開始すると oFono から通知がきますので、これを検知して状態を遷移させます。

次回は、このあたりを説明します。

主な機能の実装状況

  • 受話器の上げ下ろしの検出(フック操作)
  • ダイヤル回転検出
  • ダイヤル番号検出
  • スマホとの Bluetooth 接続
    • D-Bus 経由で接続する ←追加
    • RasPi 側を Scan 待ちにする ←追加
  • 着信
  • 発信 ←完了
  • 音声出力(スピーカ)
  • 音声入力(マイク)
  • ベルの鳴動
  • 電池駆動
  • 充電機能
KRay

KRay

KRay です。物作りが好きでいつも何かしら作っています。できるまでの過程から共有できたら嬉しいです。こんな情報でも必要な人がいると信じて。

Comments

comments powered by Disqus