本チュートリアルでは、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 10
uint8_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_ZCZR
zigbee_role_t role = ZIGBEE_ROUTER; // または ZIGBEE_COORDINATOR に設定可能ですが、自身はスキャンしません
#else
zigbee_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)