本チュートリアルでは、Module Gateway H2 を使用して Zigbee および Thread Arduino サンプルプログラムを実行し、ネットワーク通信を実現する方法を紹介します。
1.環境設定: Arduino IDE 入門チュートリアル を参照して IDE のインストールを完了してください。
設定画面の「追加のボードマネージャー URL」の入力欄を探し、以下の URL を追加してください:
https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json
ボードマネージャーで ESP32
を検索し、ボードのインストールを完了してください。
注: この手順では多数のツールチェーンをダウンロードする必要があり、ダウンロードに失敗する場合は、ネットワーク環境を変更するかプロキシの設定を試みてください。
2.使用するドライバライブラリ:
3.使用するハードウェア製品:
Module Gateway H2
と ESP32 Downloader
を使用してデモを行います。Module Gateway H2 のコアモジュールは ESP32-H2-MINI-1-N2
を採用しており、独立して動作する能力を持っています。本チュートリアルでは、ESP32 Downloader を介して直接サンプルプログラムを Module Gateway H2 に書き込み、独立したデバイスとして使用します。ESP32-H2-MINI-1-N2
を使用しているため、プログラムをコンパイルする前に使用するパーティションテーブルを調整する必要があります。custom
オプションを使用します。このオプションを有効にする際は、カスタムパーティションテーブルファイルを用意し、プロジェクトファイル (.ino) と同じディレクトリに配置し、partitions.csv
と命名してください。以下の各サンプルプログラムでは異なるパーティションテーブルが使用される場合があるので、各サンプルの具体的な説明を参照してください。Arduino IDE ツールメニューの設定:
Tools -> Board: ESP32H2 Dev Module
Tools -> Erase All Flash Before Sketch Upload: Enable
(無効にすると接続に失敗する可能性があります) Tools -> Flash Size: 2MB
Tools -> Zigbee mode: Zigbee ED (end device)
Tools -> Partition Scheme: custom
custom
パーティションテーブルオプションを有効にし、以下のパーティションテーブルをコピーして partitions.csv
という名前でプロジェクトファイル (.ino) と同じディレクトリに保存してください。# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0xC0000,
app1, app, ota_1, 0xd0000, 0xC0000,
spiffs, data, spiffs, 0x190000,0x5a000,
zb_storage, data, fat, 0x1ea000,0x4000,
zb_fct, data, fat, 0x1ee000,0x1000,
coredump, data, coredump,0x1f0000,0x10000,
#ifndef ZIGBEE_MODE_ED#error "Tools->Zigbee mode で Zigbee エンドデバイスモードが選択されていません"#endif #include "Zigbee.h" /* Zigbee 電球の設定 */#define ZIGBEE_LIGHT_ENDPOINT 10uint8_t led = RGB_BUILTIN;uint8_t button = BOOT_PIN; ZigbeeLight zbLight = ZigbeeLight(ZIGBEE_LIGHT_ENDPOINT); /********************* RGB LED 関数 **************************/void setLED(bool value) { if(value){ Serial.println("LED ON!"); } else { Serial.println("LED OFF!"); } digitalWrite(led, value);} /********************* Arduino 関数 **************************/void setup() { Serial.begin(115200); // LED の初期化と消灯 (もし LED_PIN が RGB_BUILTIN なら、内部で rgbLedWrite() が使用されます) pinMode(led, OUTPUT); digitalWrite(led, LOW); // ファクトリーリセット用ボタンの初期化 pinMode(button, INPUT_PULLUP); // オプション: Zigbee デバイスの名前とモデルを設定 zbLight.setManufacturerAndModel("Espressif", "ZBLightBulb"); // ライト変更時のコールバック関数を設定 zbLight.onLightChange(setLED); // Zigbee Core にエンドポイントを追加 Serial.println("Zigbee Core に ZigbeeLight エンドポイントを追加中"); Zigbee.addEndpoint(&zbLight); // すべてのエンドポイントが登録されたら、Zigbee を開始。デフォルトでは ZIGBEE_END_DEVICE として動作します if (!Zigbee.begin()) { Serial.println("Zigbee の起動に失敗しました!"); Serial.println("再起動します..."); ESP.restart(); } Serial.println("ネットワークに接続中"); while (!Zigbee.connected()) { Serial.print("."); delay(100); } Serial.println();} void loop() { // ファクトリーリセット用ボタンのチェック if (digitalRead(button) == LOW) { // ボタンが押された場合 // チャタリング防止処理 delay(100); int startTime = millis(); while (digitalRead(button) == LOW) { delay(50); if ((millis() - startTime) > 3000) { // 3 秒以上ボタンが押された場合、Zigbee を工場出荷状態にリセットし再起動 Serial.println("Zigbee を工場出荷状態にリセットし、1 秒後に再起動します。"); delay(1000); Zigbee.factoryReset(); } } // ボタン押下でライトの状態を切り替え zbLight.setLight(!zbLight.getLightState()); } delay(100);}
Arduino IDE ツールメニューの設定:
Tools -> Board: ESP32H2 Dev Module
Tools -> Erase All Flash Before Sketch Upload: Enable
(無効にすると接続に失敗する可能性があります) Tools -> Flash Size: 2MB
Tools -> Zigbee mode: Zigbee ZCZR (coordinator/router)
Tools -> Partition Scheme: custom
custom
パーティションテーブルオプションを有効にし、以下のパーティションテーブルをコピーして partitions.csv
という名前でプロジェクトファイル (.ino) と同じディレクトリに保存してください。# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0xC0000,
app1, app, ota_1, 0xd0000, 0xC0000,
spiffs, data, spiffs, 0x190000,0x5a000,
zb_storage, data, fat, 0x1ea000,0x4000,
zb_fct, data, fat, 0x1ee000,0x1000,
rcp_fw, data, spiffs, 0x1ef000,0x1000,
coredump, data, coredump,0x1f0000,0x10000,
#ifndef ZIGBEE_MODE_ZCZR#error "Tools->Zigbee mode で Zigbee コーディネーターモードが選択されていません"#endif #include "Zigbee.h" #define SWITCH_ENDPOINT_NUMBER 5#define TOGGLE_INTERVAL 5000 // 切り替え間隔(ミリ秒) ZigbeeSwitch zbSwitch = ZigbeeSwitch(SWITCH_ENDPOINT_NUMBER); void setup() { Serial.begin(115200); // オプション: Zigbee デバイスの名前とモデルを設定 zbSwitch.setManufacturerAndModel("Espressif", "ZigbeeSwitch"); // オプション: 複数のライトがスイッチにバインドできるようにする zbSwitch.allowMultipleBinding(true); // Zigbee Core にエンドポイントを追加 Serial.println("Zigbee Core に ZigbeeSwitch エンドポイントを追加中"); Zigbee.addEndpoint(&zbSwitch); // 起動後 180 秒間、ネットワークをオープンにする Zigbee.setRebootOpenNetwork(180); // すべてのエンドポイントが登録されたら、ZIGBEE_COORDINATOR モードで Zigbee を開始 if (!Zigbee.begin(ZIGBEE_COORDINATOR)) { Serial.println("Zigbee の起動に失敗しました!"); Serial.println("再起動します..."); ESP.restart(); } Serial.println("スイッチにバインドされるライトを待機中"); // スイッチがライトにバインドされるのを待つ: while (!zbSwitch.bound()) { Serial.printf("."); delay(500); } // オプション: バインドされたデバイス一覧を表示し、メーカーとモデル名を読み取る std::list<zb_device_params_t *> boundLights = zbSwitch.getBoundDevices(); for (const auto &device : boundLights) { Serial.printf("エンドポイント %d のデバイス、ショートアドレス: 0x%x\r\n", device->endpoint, device->short_addr); Serial.printf( "IEEE アドレス: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\r\n", device->ieee_addr[7], device->ieee_addr[6], device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3], device->ieee_addr[2], device->ieee_addr[1], device->ieee_addr[0] ); char *manufacturer = zbSwitch.readManufacturer(device->endpoint, device->short_addr, device->ieee_addr); char *model = zbSwitch.readModel(device->endpoint, device->short_addr, device->ieee_addr); if (manufacturer != nullptr) { Serial.printf("ライトのメーカー: %s\r\n", manufacturer); } if (model != nullptr) { Serial.printf("ライトのモデル: %s\r\n", model); } } Serial.println(); } void loop() { static unsigned long lastToggleTime = 0; // 一定間隔でライトの状態を切り替える if (millis() - lastToggleTime > TOGGLE_INTERVAL) { lastToggleTime = millis(); Serial.println("ライトの状態を切り替えます..."); zbSwitch.lightToggle(); } // 10 秒ごとにバインドされたライトを表示 static uint32_t lastPrint = 0; if (millis() - lastPrint > 10000) { lastPrint = millis(); zbSwitch.printBoundDevices(Serial); }}
Arduino IDE ツールメニューの設定:
Tools -> Board: ESP32H2 Dev Module
Tools -> Erase All Flash Before Sketch Upload: Enable
(無効にすると接続に失敗する可能性があります) Tools -> Flash Size: 2MB
Tools -> Zigbee mode: Zigbee ZCZR (coordinator/router)
Tools -> Partition Scheme: custom
custom
パーティションテーブルオプションを有効にし、以下のパーティションテーブルを partitions.csv
という名前でプロジェクトファイル (.ino) と同じディレクトリに保存してください。# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0xC0000,
app1, app, ota_1, 0xd0000, 0xC0000,
spiffs, data, spiffs, 0x190000,0x5a000,
zb_storage, data, fat, 0x1ea000,0x4000,
zb_fct, data, fat, 0x1ee000,0x1000,
rcp_fw, data, spiffs, 0x1ef000,0x1000,
coredump, data, coredump,0x1f0000,0x10000,
#if !defined(ZIGBEE_MODE_ED) && !defined(ZIGBEE_MODE_ZCZR)#error "Tools->Zigbee mode で Zigbee デバイスモードが選択されていません"#endif #include "Zigbee.h" #ifdef ZIGBEE_MODE_ZCZRzigbee_role_t role = ZIGBEE_ROUTER; // または ZIGBEE_COORDINATOR に設定可能ですが、自身はスキャンしません#elsezigbee_role_t role = ZIGBEE_END_DEVICE;#endif void printScannedNetworks(uint16_t networksFound) { if (networksFound == 0) { Serial.println("ネットワークが見つかりませんでした"); } else { zigbee_scan_result_t *scan_result = Zigbee.getScanResult(); Serial.println("\nスキャン完了"); Serial.print(networksFound); Serial.println(" 件のネットワークが見つかりました:"); Serial.println("Nr | PAN ID | CH | Permit Joining | Router Capacity | End Device Capacity | Extended PAN ID"); for (int i = 0; i < networksFound; ++i) { // 各ネットワークの全情報を出力 Serial.printf("%2d", i + 1); Serial.print(" | "); Serial.printf("0x%04hx", scan_result[i].short_pan_id); Serial.print(" | "); Serial.printf("%2d", scan_result[i].logic_channel); Serial.print(" | "); Serial.printf("%-14.14s", scan_result[i].permit_joining ? "Yes" : "No"); Serial.print(" | "); Serial.printf("%-15.15s", scan_result[i].router_capacity ? "Yes" : "No"); Serial.print(" | "); Serial.printf("%-19.19s", scan_result[i].end_device_capacity ? "Yes" : "No"); Serial.print(" | "); Serial.printf( "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", scan_result[i].extended_pan_id[7], scan_result[i].extended_pan_id[6], scan_result[i].extended_pan_id[5], scan_result[i].extended_pan_id[4], scan_result[i].extended_pan_id[3], scan_result[i].extended_pan_id[2], scan_result[i].extended_pan_id[1], scan_result[i].extended_pan_id[0] ); Serial.println(); delay(10); } Serial.println(""); // 以下のコードのためにメモリを解放するため、スキャン結果を削除 Zigbee.scanDelete(); }} void setup() { Serial.begin(115200); // スキャン専用に、エンドポイントなしで Zigbee スタックを初期化 if (!Zigbee.begin(role)) { Serial.println("Zigbee の起動に失敗しました!"); Serial.println("再起動します..."); ESP.restart(); } Serial.println("セットアップ完了、Zigbee ネットワークスキャンを開始します..."); // デフォルトパラメータ (全チャンネル、スキャン時間 5) で Zigbee ネットワークスキャンを開始 Zigbee.scanNetworks();} void loop() { // Zigbee ネットワークスキャンの進行状況を確認 int16_t ZigbeeScanStatus = Zigbee.scanComplete(); if (ZigbeeScanStatus < 0) { // スキャン中またはエラーが発生 if (ZigbeeScanStatus == ZB_SCAN_FAILED) { Serial.println("Zigbee スキャンに失敗しました。再度開始します。"); delay(1000); Zigbee.scanNetworks(); } delay(100); // もうひとつの選択肢はステータス ZB_SCAN_RUNNING - 待機します。 } else { // 0 件以上の無線ネットワークが見つかった printScannedNetworks(ZigbeeScanStatus); delay(1000); Zigbee.scanNetworks(); // 再度スキャン開始... } // ループ内で他の処理も可能です...}
File -> Examples -> OpenThread
で OpenThread 関連のサンプルプログラムを確認できます。プログラムをコンパイルする前に、以下のパーティションテーブル設定等の情報を参照してください。Arduino IDE ツールメニューの設定:
Tools -> Board: ESP32H2 Dev Module
Tools -> Erase All Flash Before Sketch Upload: Enable
(無効にすると接続に失敗する可能性があります) Tools -> Flash Size: 2MB
Tools -> Partition Scheme: Minimal SPIFFS (1.3MB APP/700K SPIFFS)