Nature Remo BLE マクロベータテスト機能をちょっと深堀り

ファームウェアエンジニアの中林 (id:tomo-wait-for-it-yuki) です。 昨日より Nature Remo BLE マクロのベータテストを実施しています。 本エントリでは、ベータテストで使える機能 (nRF Connect マクロのオペレーション) について、ちょっとだけ深堀りしてみます。

これまでどおりリファレンスデバイスとして Philips Hue を使います。 Hue を操作するマクロを例にベータテストで試せる機能を紹介します。

マクロの作成例はこちらです。

github.com

利用可能なオペレーション

nRF Connect のマクロでは、XML のエレメント (下記 XML では write の部分) を「オペレーション」と呼んでいるので、便宜上、BLE マクロで行う各操作をオペレーションと表記します。

<write description="Write 0x01 to 932c32bd-0002-47a2-835a-a8d455b859dd" characteristic-uuid="932c32bd-0002-47a2-835a-a8d455b859dd" service-uuid="932c32bd-0000-47a2-835a-a8d455b859dd" value="01" type="WRITE_REQUEST"/>

nRF Connect では、write 以外にも様々なオペレーションがサポートされています。 完全なリストは公式ドキュメントをご参照ください。

github.com

2023年12月現在、Nature Remo BLE マクロのベータテストに取り込めるオペレーションは次の通りです。

  • assert-service
  • write
  • write descriptor
  • read
  • wait-for-notification
  • sleep

1つずつ簡単に紹介します。

assert-service

対象のサービス、キャラクタリスティクス、ディスクリプターが存在しているかどうかをチェックします。 事前にマクロ内で使うサービスをチェックしておくことで、以降のマクロ実行時にサービスやキャラクタリスティクスが存在することを確定できます。 マクロを手書きするときは、最初に書いておきましょう。

   <assert-service description="Ensure 932c32bd-0000-47a2-835a-a8d455b859dd service" uuid="932c32bd-0000-47a2-835a-a8d455b859dd">
      <assert-characteristic description="Ensure 932c32bd-0002-47a2-835a-a8d455b859dd characteristic" uuid="932c32bd-0002-47a2-835a-a8d455b859dd">
         <assert-cccd description="Ensure CCCD"/>
         <property name="READ" requirement="MANDATORY"/>
         <property name="WRITE" requirement="MANDATORY"/>
         <property name="NOTIFY" requirement="MANDATORY"/>
      </assert-characteristic>
   </assert-service>

write

対象のキャラクタリスティック characteristic-uuidvalue を書き込みます。

<write description="Write 0x01 to 932c32bd-0002-47a2-835a-a8d455b859dd" characteristic-uuid="932c32bd-0002-47a2-835a-a8d455b859dd" service-uuid="932c32bd-0000-47a2-835a-a8d455b859dd" value="01" type="WRITE_REQUEST"/>

type アトリビュートWRITE_REQUEST もしくは WRITE_COMMAND を選択できます。 これは書き込みに対して、返答を期待するか (WRITE_REQUEST) 、返答なしか (WRITE_COMMAND) を意味します。 書き込み後に対象デバイスが意図通り動かない場合は、REQUEST / COMMAND の指定が異なっている場合があります。

<!-- 
  The type value is case-sensitive and may have one of the following values:
  - WRITE_REQUEST (default) - Write With Response
  - WRITE_COMMAND - Write Without Response
-->

write descriptor

対象のディスクリプタuuidvalue を書き込みます。 GATT サーバーからの通知を有効にする enable notification に使うことがほとんどでしょう。 nRF Connect では下矢印3つのマークをタップしたときに、このオペレーションが実行されます。

<write-descriptor description="Enable notifications for 932c32bd-0002-47a2-835a-a8d455b859dd" characteristic-uuid="932c32bd-0002-47a2-835a-a8d455b859dd" service-uuid="932c32bd-0000-47a2-835a-a8d455b859dd" uuid="00002902-0000-1000-8000-00805f9b34fb" value="0100"/>

read

対象のキャラクタリスティック characteristic-uuid から値を読み込みます。 assert-value に有効な value を指定している場合、読み込んだ値がその値と一致しているかチェックします。

   <read description="Read value of 932c32bd-0002-47a2-835a-a8d455b859dd" characteristic-uuid="932c32bd-0002-47a2-835a-a8d455b859dd" service-uuid="932c32bd-0000-47a2-835a-a8d455b859dd">
      <assert-value description="Assert value equals 0x00" value="00"/>
   </read>

センサー値の読み込みに使うことも多いですが、読み込んだ値を利用する機能は今後実装する計画となっています。

wait-for-notification

GATT サーバーからの通知を1つ待ちます。 assert-value に有効な value を指定している場合、通知で届いた値がその値と一致しているかチェックします。

   <wait-for-notification description="Wait for notification to 932c32bd-0002-47a2-835a-a8d455b859dd" characteristic-uuid="932c32bd-0002-47a2-835a-a8d455b859dd" service-uuid="932c32bd-0000-47a2-835a-a8d455b859dd">
      <assert-value description="Assert value equals 0x01" value="01"/>
   </wait-for-notification>

通知はセンサー値が更新されたときの通知などに使われることも多いですが、読み込んだ値を利用する機能は今後実装する計画となっています。

sleep

その名の通り、マクロの実行を timeout ミリ秒停止します。 タイミングの調整にご使用ください。

<sleep description="Sleep 500 ms" timeout="500"/>

Philips Hue を操作するマクロの意味を理解してみよう!

まずはこちらの blink.xml です。

<macro name="blink" icon="PLAY">
   <assert-service description="Ensure 932c32bd-0000-47a2-835a-a8d455b859dd service" uuid="932c32bd-0000-47a2-835a-a8d455b859dd">
      <assert-characteristic description="Ensure 932c32bd-0002-47a2-835a-a8d455b859dd characteristic" uuid="932c32bd-0002-47a2-835a-a8d455b859dd">
         <property name="WRITE" requirement="MANDATORY"/>
      </assert-characteristic>
   </assert-service>
   <write description="Write 0x01 to 932c32bd-0002-47a2-835a-a8d455b859dd" characteristic-uuid="932c32bd-0002-47a2-835a-a8d455b859dd" service-uuid="932c32bd-0000-47a2-835a-a8d455b859dd" value="01" type="WRITE_REQUEST"/>
   <sleep description="Sleep 500 ms" timeout="500"/>
   <write description="Write 0x00 to 932c32bd-0002-47a2-835a-a8d455b859dd" characteristic-uuid="932c32bd-0002-47a2-835a-a8d455b859dd" service-uuid="932c32bd-0000-47a2-835a-a8d455b859dd" value="00" type="WRITE_REQUEST"/>
   <sleep description="Sleep 500 ms" timeout="500"/>
</macro>

Philips Hue はキャラクタリスティック 932c32bd-0002-47a2-835a-a8d455b859dd0x01 を書き込むと点灯、0x00 を書き込むと消灯します。 そのため、このマクロはまず、キャラクタリスティック 932c32bd-0002-47a2-835a-a8d455b859dd が存在するかどうかを assert-service でチェックしています。 マクロの残りは Hue を点灯して、500ミリ秒待って、 Hue を消灯して、500ミリ秒待つ、というマクロになっている、と読むことができます。

ちなみに Hue の操作は WRITE_REQUEST で値を書き込む必要があるようで、 write オペレーションの typeWRITE_COMMAND にすると動きません。

上級編 turn on if off

では次は turn_on_if_off.xml です。 ファイル名でネタバレしていますが、このマクロは、マクロを実行しようとしたときに Hue が消灯状態だった場合のみ、点灯操作を行うマクロとなっています *1 。 また、キャラクタリスティックの通知を write-descriptor で有効にすることで、値を書き込んだあと、その値がそのまま通知されてくるかどうかを wait-for-notification でチェックしています。

<macro name="turn_on_if_off" icon="PLAY">
   <assert-service description="Ensure 932c32bd-0000-47a2-835a-a8d455b859dd service" uuid="932c32bd-0000-47a2-835a-a8d455b859dd">
      <assert-characteristic description="Ensure 932c32bd-0002-47a2-835a-a8d455b859dd characteristic" uuid="932c32bd-0002-47a2-835a-a8d455b859dd">
         <assert-cccd description="Ensure CCCD"/>
         <property name="READ" requirement="MANDATORY"/>
         <property name="WRITE" requirement="MANDATORY"/>
         <property name="NOTIFY" requirement="MANDATORY"/>
      </assert-characteristic>
   </assert-service>
   <read description="Read value of 932c32bd-0002-47a2-835a-a8d455b859dd" characteristic-uuid="932c32bd-0002-47a2-835a-a8d455b859dd" service-uuid="932c32bd-0000-47a2-835a-a8d455b859dd">
      <assert-value description="Assert value equals 0x00" value="00"/>
   </read>
   <write-descriptor description="Enable notifications for 932c32bd-0002-47a2-835a-a8d455b859dd" characteristic-uuid="932c32bd-0002-47a2-835a-a8d455b859dd" service-uuid="932c32bd-0000-47a2-835a-a8d455b859dd" uuid="00002902-0000-1000-8000-00805f9b34fb" value="0100"/>
   <write description="Write 0x01 to 932c32bd-0002-47a2-835a-a8d455b859dd" characteristic-uuid="932c32bd-0002-47a2-835a-a8d455b859dd" service-uuid="932c32bd-0000-47a2-835a-a8d455b859dd" value="01" type="WRITE_REQUEST"/>
   <wait-for-notification description="Wait for notification to 932c32bd-0002-47a2-835a-a8d455b859dd" characteristic-uuid="932c32bd-0002-47a2-835a-a8d455b859dd" service-uuid="932c32bd-0000-47a2-835a-a8d455b859dd">
      <assert-value description="Assert value equals 0x01" value="01"/>
   </wait-for-notification>
</macro>

マクロを最初から読んでいきましょう。

このマクロでもまず、キャラクタリスティック 932c32bd-0002-47a2-835a-a8d455b859dd が存在するかどうかをチェックしています。 blink.xml と比べると、さらに追加でディスクリプターが存在するかどうかを <assert-cccd description="Ensure CCCD"/> の部分でチェックしています。

次の read オペレーションでは、キャラクタリスティック 932c32bd-0002-47a2-835a-a8d455b859dd の値を読み込んで、00 (つまり消灯状態) であるかどうかチェックしています。 ここで、01 が読めてしまった場合は、その時点でマクロの実行が失敗となります。

続く write-descriptor では、キャラクタリスティック 932c32bd-0002-47a2-835a-a8d455b859dd の通知を有効にしています。 これで、キャラクタリスティック 932c32bd-0002-47a2-835a-a8d455b859dd の値が更新されれば、通知を受信できます。

write は blink.xml のときと同様です。

最後に wait-for-notification で自分が更新した値で、通知が届くことをチェックしています。 このとき、01 を書き込んでいるので、値が 01 になっていることをチェックします。

BLE マクロ完全に理解した

ここまで本エントリを読んでくださった方は、現時点での BLE マクロを完全に理解したと言っても過言ではありません! 現状ではまだまだできることに限りがありますが、今後も機能を改善していきますので、ぜひ遊び方を様々考えていただけるとうれしいです。

BLE マクロベータテスト実施中

もし本エントリを見て Nature Remo BLE マクロに興味を持った場合は、Nature Developer Community にてベータテストの様子を見ることができます。 ぜひ覗きにきてください。

discord.gg

*1:点灯状態だった場合、途中でマクロ実行が失敗します