Watchy v3でiPhoneの通知を受け取れるか試した記録

作ってみた

Watchy v3は、電子ペーパー画面のオープンソース腕時計です。もともとは時刻を表示するだけの端末でしたが、これにiPhoneの通知を表示させられないか、という話から今回の作業が始まりました。

最終的に目指す形はこうです。

iPhone → Bluetooth LE → ANCS → Watchy v3 → 電子ペーパーに通知表示

結論を先に書きます。核心部分では「できる」ところまで到達しました。ただし、「通知が一瞬表示された」と「毎日腕につけて使える」は別の話です。今回はその手前までの記録になります。

段階を先に分解する

いきなりWatchy本体に機能を組み込むのではなく、まず「どこまでできたら成功と呼ぶか」を先に決めました。コンパイルできるか、BLEでadvertisingできるか、接続できるか、ANCSのサービスが見えるか、通知イベントを受け取れるか、本文まで取得できるか。ここまでを独立した実験用コードで確認してから、Watchy本体に統合する順番にしました。

iPhoneに見えないのはBLEが壊れているからではなかった

NimBLE-Arduinoで実装したANCSの実験コードは、MacからはWatchy BLE Testとして普通に見えました。ところが、これをiPhoneのBluetooth設定画面で見ようとすると、何も出てきません。

最初はBLEの実装自体を疑いました。原因は別のところにありました。iPhoneの設定画面は、汎用のBLEスキャナではないのです。ANCSのUUIDを普通の方法でadvertiseしても、iPhone側は「これはANCS対応のアクセサリだ」と認識してくれません。

正解は、ANCSのUUIDを通常のService UUIDとしてではなく、128-bit Service Solicitation(Advertising Data Type 0x15)として載せることでした。これに変えた瞬間、iPhone側にANCSの利用許可画面が表示され、接続まで進みました。

通知の中身まで取れた

Notification Sourceをsubscribeし、Control Pointから詳細な属性を要求すると、Data Sourceからアプリ名・送信者・タイトル・本文・日時まで取得できました。実験用コードとしては、目標の地点に到達したことになります。

Watchy本体に組み込んだら、リンクエラーの山になった

ここからが長かったです。既存のWatchy本体のコードを壊さないようwatchy_notificationsという別スケッチを作って組み込んだところ、multiple definition of ble_sm_alg_gen_key_pairのようなリンクエラーが大量に出ました。

原因は、Watchyのライブラリ自体が内部にBLE.cppというBLE実装を持っていて、それが今回使っているNimBLE-Arduinoと衝突していたことでした。Watchyのライブラリ本体をプロジェクト内にコピーし、内蔵のBLE実装をビルド対象から外した版(WatchyNoBLE)を自分で作ることで、この衝突を避けました。

Arduino CLIに--librariesでこの独自版の場所を指定しても、なぜかグローバルにインストールされている方のWatchyライブラリが優先されます。フォルダ名を.backupに変えても、それでもライブラリの候補としてスキャンされてしまう。最終的にはグローバル版を/tmpへ物理的に退避させてから、ようやく自分の版を使わせることができました。

USBの書き込みでも一度詰まりました。ポート自体は認識されているのにNo serial data receivedで失敗する。Watchyをブートローダーモードに手動で入れることで書き込みが通りました。deep sleep中はUSBシリアル自体が消えるので、書き込みのタイミングにも注意が要ります。

通知が一瞬、画面に映った

一連の統合が終わった後、実機でテストしていたときに、電子ペーパーの画面にPokémon GOという文字列が一瞬表示されました。iPhone側の通知に由来するものと考えられます。

派手な瞬間ではありませんでしたが、iPhoneの通知からANCS、ESP32-S3、統合コード、電子ペーパー描画までの経路が、少なくとも一度は通ったという証拠になりました。表示が保持されるところまでは確認できていません。これをもって「完成」とは判定していません。

BLEのコールバックから直接画面を描かない

最初の統合版では、BLEのデータ受信コールバックの中から直接電子ペーパーを更新していました。BLEの処理と、遅い画面描画をひとつの流れに詰め込むと、他の処理を巻き込んで不安定になります。コールバック側はタイトルと本文を保存してフラグを立てるだけにし、実際の描画はメインループ側でそのフラグを見て行う形に直しました。

まだ残っていること

通知だけを見れば技術的な核心には到達したものの、通知統合後にWi-FiとNTPの同期がうまくいかなくなるという新しい問題も出てきました。通知、BLE、Wi-Fi、NTP、OTA、deep sleepをすべて共存させる統合作業は、まだ途中です。

表示の保持、日本語フォント対応、通知が来たときの見せ方、BLEが切れたときの再接続、通常の時計表示との共存、バッテリーの実測。やることはまだ並んでいます。

—

今回はっきりしたのは、「動いた」と「完成した」は全く別の状態だということでした。「一瞬表示された」を成功と呼んでしまうと、そこで満足して統合作業から目を逸らしてしまいます。今回はあえて、途中の失敗や、成功と呼べる条件をどう分解したかまで含めて記録に残すことにしました。

腕時計として毎日使えるようになるところまでは、もう少しかかりそうです。

コメント

タイトルとURLをコピーしました