ESPHome の ble_scanner から受信したJSONデータから必要な要素の値を取り出すことを試したが、思ったよりも時間がかかったので、備忘録を残しておく。
目次
背景
ESPHomeから構造をもったデータをHome Assistantに送って、Home Assistantで蓄積や表示などの処理をしたい。構造をもっているということと、個々の要素を送る方式では、データのタイムスタンプと要素の間の関連が曖昧になるためである。これは、Home Assistantが受信したデータのタイムスタンプがHome Assistantのクロックに基づくタイムスタンプになってしまい、同一構造内のデータでも個別に送るとHome Assistantでは受信時点が異なると異なるタイムスタンプになってしまい。タイムスタンプが近いという曖昧な基準でしか同じ構造データの要素であるという判定ができないためである。
まず、練習として ESPHome の ble_scannerの以下のような比較的単純な構造のJSONデータからタグ付けされた要素の値をHome Assistantで抽出して、Home Assistantのオーバービューにカードで表示する。
1 |
{"timestamp":1684637892,"address":"DC:23:4D:2D:69:70","rssi":-72,"name":"TY"} |
環境
- M5Stack Atom Lite
- Windows 11 Pro 22H2 22621.1702
- CP210x Universal Windows Driver v11.2.0 (10/21/2022)
- ESPHome version: 2023.6.0-dev
- Home Assistant 2023.5.3 (Supervisor 2023.04.1, Operating System 10.1, フロントエンド: 20230503.3)
ESPHome BLE Scanner
JSON形式のデータを出力するコンポーネントとして ESPHome の ESP32 Bluetooth Low Energy Scanner を利用する。
ESPHome で利用した yaml ファイル(87fb58.blescanner.yaml)は以下の通り 。 text_sensor: – platform: ble_scanner name: "BLE Scan" のところで、ble_scanner を利用している。
esp32_ble_tracker の scan_parameters で interval: 2000ms として、2秒ごとに BLE の scan をするように指定している。
BLEのscanが先に行われると WiFiの接続がされないままにある場合が頻発したので、WiFiが接続してから(wifi.connected が成立してから) BLE scan を行うようにしている (id(ble_tracker).start_scan())。この条件判定を interval: の部分で10秒ごとに行うようにしていて、WiFi接続に時間がかかる場合でも、WiFi接続がされてから BLE scanが開始されるようにしている。このままだと、BLE scanが開始されてからも10秒ごとに BLE scanを開始しようとしてすでに開始しているという warning がログに出る ([W][esp32_ble_tracker:228]: Scan requested when a scan is already in progress. Ignoring.)。一度は、BLE Scanの開始した状態を記憶して、一度開始した後は、start_scan()を呼び出さないようにしてみたが、BLE Scanが止まってしまう場合があり、定期的に start_scan() を呼び出した方が安定しているので、以下のプログラムに示すようにしている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
substitutions: device_name: m5stack_atom_lite _friendly_name: "ESPHome Web 87fb58 Atom Lite" esphome: name: esphome-web-87fb58 friendly_name: $_friendly_name esp32: board: m5stack-atom framework: type: arduino # Enable logging logger: level: VERBOSE # NONE, ERROR, WARN, DEBUG, VERBOSE, or VERY_VERBOSE # Enable Home Assistant API api: encryption: key: "Owuf3MWnoaRnBG8e/tq991ghF2egw4gUUnqZxLTbnhQ=" ota: wifi: ssid: !secret wifi_ssid password: !secret wifi_password # Enable fallback hotspot (captive portal) in case wifi connection fails ap: ssid: "Esphome-Web-87Fb58" password: "xX7uJTmmdIVy" captive_portal: text_sensor: - platform: ble_scanner name: "BLE Scan" esp32_ble_tracker: id: ble_tracker scan_parameters: continuous: false interval: 2000ms interval: - interval: 10s then: if: condition: wifi.connected: then: - lambda: |- id(ble_tracker).start_scan(); time: - platform: sntp servers: - pool.ntp.org - ntp.nict.jp |
yamlの初期生成
上記のyamlファイルは、Home Assistantで生成した yaml ファイルを修正して作ったものである。api: encryption: key: ("Owuf3MWnoaRnBG8e/tq991ghF2egw4gUUnqZxLTbnhQ=")や ap: password: ("xX7uJTmmdIVy") は、Home Assistantによって自動生成されたものをそのまま使っている。
Home Assistant の「設定」→「アドオン」で ESPHome をインストールした後に、 ESPHome を選択し、「Web UIを開く」をしてから「+ New Device」をクリックする。
「Create configuration」で名前を付ける()。Select your device type で適切なものを選択する(この例では ESP32を選択している)。そうすると Configuration created! が表示され、Encription key も表示される(Home Assistantへ登録する際に必要となるが、yamlファイルなどをから参照できる)。「INSTALL」をクリックすると インストールがされる。
How do you want to install <名前>.yaml on you device? というメッセージが表示されるので、接続方法を選択する。Over-The-Air (OTA) のファームウェアが書き込まれていないデバイスでは、USB接続が必要である。ここでは、Plug into this computer を選択し、Webブラウザを起動しているローカルコンピュータとESP32デバイスがUSBで接続されているとする。
Install ESPHome via the browser の 1. Download project をクリックすると <名前>-factory.bin ()がローカルコンピュータにダウンロードされる。 2. Open ESPHome Web をクリックして、ESP Deviceの CONNECT をクリックする。Web Serialでの接続ポートの選択が求められる。適切なデバイスドライバがインストールされ、Webブラウザで Serial の利用が許可されている必要がある。
手元の環境ではWeb Serial での接続が高い頻度で失敗してフラストレーションが溜まった。
compile と upload
PowerShell では、以下のコマンドを実行することで、コンパイルとアップロードがされる。compile と upload に分けてもよい。
1 |
esphome run 87fb58.blescanner.yaml |
ファームウェアの書き込みは、初回は USB接続で行う必要がある。以下のようにアップロード方法の選択が求められたら1 を選ぶ。もちろん、2回目以降もUSB接続で書き込むことが可能だが、M5Stack Atom Lite では、INFO Upload with baud rate 460800 failed. Trying again with baud rate 115200.という表示が出て通信速度 115200bpsでアップロードがされるので遅い。
一度 OTA用のファームウェアを書き込み済みで、デバイス名も同じならUSB接続は必要なく、以下のように Over The Air を選択することができる。OTAの方が速い。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Found multiple options, please choose one: [1] COM5 (USB Serial Port (COM5)) [2] Over The Air (esphome-web-87fb58.local) (number): 1 esptool.py v4.5.1 Serial port COM5 Connecting..... Chip is ESP32-PICO-D4 (revision v1.0) Features: WiFi, BT, Dual Core, 240MHz, Embedded Flash, VRef calibration in efuse, Coding Scheme None Crystal is 40MHz MAC: 50:02:91:87:fb:58 Uploading stub... Running stub... Stub running... Changing baud rate to 460800 Changed. ERROR Running command failed: Unable to verify flash chip connection (No serial data received.). ERROR Please try running esptool.py --before default_reset --after hard_reset --baud 460800 --port COM5 --chip esp32 write_flash -z --flash_size detect 0x10000 'C:\Dr.IoT\esphome\.esphome\build\esphome-web-87fb58\.pioenvs\esphome-web-87fb58\firmware.bin' 0x1000 'C:\Dr.IoT\esphome\.esphome\build\esphome-web-87fb58\.pioenvs\esphome-web-87fb58\bootloader.bin' 0x8000 'C:\Dr.IoT\esphome\.esphome\build\esphome-web-87fb58\.pioenvs\esphome-web-87fb58\partitions.bin' 0xe000 'C:\Users\driot\.platformio\packages\framework-arduinoespressif32@3.20005.220925\tools\partitions\boot_app0.bin' locally. INFO Upload with baud rate 460800 failed. Trying again with baud rate 115200. esptool.py v4.5.1 Serial port COM5 Connecting.... Chip is ESP32-PICO-D4 (revision v1.0) Features: WiFi, BT, Dual Core, 240MHz, Embedded Flash, VRef calibration in efuse, Coding Scheme None |
Home AssistantでJSONから値を抽出するセンサー
BLE Scanner からのJSONデータから値を抽出し、Home Assistant のセンサーとして機能させるようにする。
Home Assistantへの登録
Home Assistantの「設定」→「デバイスとサービス」で「+ 統合を追加」をクリックし、ブランド名「ESPHome」で検索し、ESPHomeを選択する。
ホスト名は、ESPHomeのyaml (87fb58.blescanner.yaml)の中で esphome: name: で指定したもの( esphome-web-87fb58 )を基に、Multicast DNS (mDNS)で名前解決されるように .local をつける( esphome-web-87fb58.local )。
ESPHome で設定した暗号化キーには、ESPHomeのyaml (87fb58.blescanner.yaml)の api: encryption: key にあるものを指定する。
デフォルトのデバイス名は、ESPHomeの yaml (87fb58.blescanner.yaml)の中でesphome: friendly_name: で指定したもの (87fb58 Atom Lite)になる。デバイス名は変更することができる。
Home Assistant でのエンティティ名
エンティティ名は domain.id の形式であり、BLE Scan (text sensor) の domainはsensor である。BLE Scanner のエンティティ名は、 esphome: friendly_name: で定めた "87fb58 Atom Lite" と text_sensor: – platform: ble_scanner name:で指定した "BLE Scan"を「_」で連結したものがエンティティ名の基になる。大文字は小文字に変換され、空白はアンダースコアに変換される。この場合には、連結したものは sensor.87fb58_atom_lite_ble_scan となる。
JSON形式データからのセンサーデータ抽出
BLE Scanner からのJSONデータから値を抽出し、Home Assistant のセンサーとして機能させるためには、Template Sensor を利用する。 Home Assistantのtemplateは、jinja2 を使用している。
Home Assistantで利用できるようにするセンサーの名前は、JSONデータ全体を ble_json_data、タイムスタンプ(timestamp)を timestamp、MACアドレス(address)を ble_address、RSSI (rssi)を ble_rssi、名前(name)を ble_nameとする。
Home Assistantの /config/configuration.yaml に以下を追加した。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
sensor: - platform: template sensors: ble_json_data: friendly_name: "BLE JSON data" value_template: "{{ states('sensor.87fb58_atom_lite_ble_scan') }}" ble_timestamp: friendly_name: "BLE timestamp" value_template: "{{ (states('sensor.87fb58_atom_lite_ble_scan') | from_json) ['timestamp'] }}" ble_address: friendly_name: "BLE address" value_template: "{{ (states('sensor.87fb58_atom_lite_ble_scan') | from_json) ['address'] }}" ble_rssi: friendly_name: "BLE RSSI" value_template: "{{ (states('sensor.87fb58_atom_lite_ble_scan') | from_json) ['rssi'] }}" ble_name: friendly_name: "BLE name" value_template: "{{ (states('sensor.87fb58_atom_lite_ble_scan') | from_json) ['name'] }}" |
states を使って受信したデータを取り出しているが、他によりよい方法があるかははっきりしていない。sensor.87fb58_atom_lite_ble_scan はHome AssistantでBLE scannerを参照するエンティティ名であり、適切に変更する必要がある。
ble_json_data は、BLE scannerからのデータそのままである。ble_timestamp、ble_address、ble_rssi、ble_name は、BLE scanner のデータをstates を使って取得し、それをJSONに変換し(| from_json)、JSONオブジェクトから必要な属性(timestamp、address、rssi、name)の値を取り出している。もっとすっきりした方法があってもよさそうである。
Home Assistantのオーバービュー
Home Assistantのダッシュボードへのエンティティカード追加
Home Assistantのダッシュボードにエンティティカードを追加する。BLE Scanからのデータをそのまま文字列として表示するには、エンティティ名 ( sensor.87fb58_atom_lite_ble_scan ) を選択する。
ble_json_data など、先に Home Assistantのyamlで定義したセンサーを表示するには、sensor.ble_json_data を選択する。他の ble_timestamp、ble_address、ble_rssi、ble_nameも同様に、それぞれ、sensor.ble_timestamp、sensor.ble_address、sensor.ble_rssi、sensor.ble_nameを選択する。
Home Assistantのオーバービュー表示
オーバービューでは次のように表示され、データを受信すると更新されることがわかる。エンティティカードでは、エンティティ名ではなく、friendly_nameが表示されている。