目的
今までは,Panasonic製のかってにスイッチシリーズのWTK1811WKを使ってトイレの照明のON/OFF(および換気扇のON/OFF)を行っていた.このスイッチは壁に設置できるのでメンテナンスフリーであるのだが,静止検知はできないためにトイレが長い場合*1に照明がOFFになってしまう場合がある.
また,昨年度の異動で引越が発生し,トイレの外にトイレの照明スイッチがあるので,かってにスイッチが使えなくなった.そのため,静止検知もできるトイレ体験ができるモノをゆるりと探していたが,せっかくなので自作してみようと思い立ってほぼ完成形のところまでは進めたので記載しておく.
ポイントは,Passive Infrared Ray(PIR,受動赤外線センサー)ではなくてミリ波センサー*2を使うことである.ミリ波センサーであれば静止検知ができる.

| 名称 | 規格 | 製造会社 | 備考 |
|---|---|---|---|
| ボット | CR2電池タイプ,Bluetooth Low Energy | SwitchBot | メルカリにて3,300JPYで購入 |
| ミリ波センサーキット | MR60BHA2(XIAO ESP32C6内蔵) | Seeed Studio | AliExpressにて5,211JPYで購入 |
| 指ロボット用取付台 | コスモシリーズワイド21用,土台B+マウントA | にゃん工房 | Amazon.co.jpにて1,830JPYで購入 |
| 統合開発環境 | Arduino IDE,1.8.19 | Arduino | 新規インストールならば2.x系がよいと思う |
| ESP32ボード設定 | esp32,3.3.11 | Espressif Systems | |
| BLE制御ライブラリー | NimBLE-Arduino,2.5.1 | Ryan Powell | |
| RGB LED制御ライブラリー | Adafruit NeoPixel,1.15.5 | Adafruit | |
| Androidスマートフォン | AQUOS Sense9(SH-M29),Android 16 | SHARP | |
| 無線通信デバイスの開発・テスト・検証支援アプリ | nRF Connect,4.29.1 | Nordic Semiconductor | Android版 |
| SwitchBot制御アプリ | SwitchBot,10.0.1 | SwitchBot(wonderlabs) | Android版 |
| 開発用PC | Ryzen 7 3700X,RAM 32[GB],Windows 10など | --- |
想定読者
- XIAO ESP32C6を初めて使う方
- SwitchBotボットをBLEで「押したい」方
- 動体検知だけでなく静止検知もしたい方
- トイレの照明を自動化したい方
結論
試作のソフトがほぼ完成してきたところで,重大な問題を忘れていた.
MR60BHA2のミリ波センサー部分には,技適こと技術基準適合証明がない*3! つまり,日本国内で自由に使えないものであったということ.
試作するところまでの過程をもったいないので記載する.
おもに在不在判定ループと照明消灯用の消灯待ちタイマー,状態表示灯で構成される.
在不在判定ループ
ミリ波センサーから約120[ms]ごとに出力されるUARTデータから在不在を読み取る.0F 09のデータ受信の後ろの1バイトを飛ばして,01が来ていたら在室,00が来ていたら不在となる*4.
- 在室判定:01 ?? ?? 00 02 0F 09 ?? 01 00 FE
- 不在判定:01 ?? ?? 00 02 0F 09 ?? 00 00 FF
上記の在不在データ受信により,以下の動作をする:
- 在室判定のとき
- 不在カウンターを0にする
- 初回は即時照明スイッチを押下
- 2回目以降は消灯待ちタイマー動作中(直前にいったん不在判定に入っていた場合)には照明スイッチを押さずに消灯待ちタイマーをキャンセルして停止する
- 不在判定のとき
- 不在カウンターを+1する
- 不在カウンターが16に達したら不在確定とし,消灯待ちタイマーを開始する
消灯待ちタイマー
トイレの運用上,退室して戻ることは少ない.場合によっては,忘れ物(スマホなど)を取りに来たり,掃除のために出たり入ったりすることが考えられる.そのため,消灯確定時に即時照明を消すのではなく,消灯するまで待つタイマーを設けた.消灯待ちタイマーは不在確定でカウントスタート,在室確定でカウントリセットおよび停止する.
状態表示灯
以下のパターンでRGB LEDの色を切り替える.白または赤の点滅動作中は色を重ねない*5.
| 表示色 | 点灯パターン | 割り当てた状態 | 備考 |
|---|---|---|---|
| 青 | 点灯 | 在室判定中 | |
| 黄 | 点灯 | 在不在切替中 | この動きはしなかった気がする |
| 緑 | 点灯 | 不在判定中 | 基本はこの状態 |
| 白 | 点滅 | 指ロボット動作要求送信中 | |
| 赤 | 点滅 | 指ロボット動作要求送信失敗 |
最終形「仮」のフローチャートおよびソースコードは以下のとおりである.

/* * トイレ照明自動化+RGB LED状態表示 * * ベースボードのRGB LED(D1)で状態表示を追加。 * * LED色の割り当て: * 在室 → 青 * 不在切替の判定中 → 黄(不在フレームが連続カウント中) * 不在確定 → 緑 * SwitchBot送信中 → 白点滅 * 送信失敗 → 赤点滅 * * 必要なライブラリ: * NimBLE-Arduino * Adafruit NeoPixel */ #include <NimBLEDevice.h> #include <Adafruit_NeoPixel.h> // ================= 設定 ================= // --- レーダー --- #define RADAR_RX_PIN 17 #define RADAR_TX_PIN 16 #define RADAR_BAUD 115200 // --- RGB LED --- #define LED_PIN D1 // 0〜255の範囲.まあぶしいので12くらいで十分 #define LED_BRIGHTNESS 12 // --- SwitchBot --- // BOT_MACの後半3バイトは個体ごとに異なる(調べ方は後述) static const char* BOT_MAC = "f4:a3:99:**:**:**"; static const char* SERVICE_UUID = "cba20d00-224d-11e6-9fb8-0002a5d5c51b"; static const char* WRITE_UUID = "cba20002-224d-11e6-9fb8-0002a5d5c51b"; static const uint8_t PRESS_CMD[3] = { 0x57, 0x01, 0x01 }; // --- 判定パラメータ --- // 不在確定までの連続フレーム数 // (約120msごとにデータ受信するため16回の連続判定で約2秒) static const uint8_t ABSENT_CONFIRM_COUNT = 16; // 退室確定から消灯までを制御する消灯待ちタイマータイムアウト値(10秒) static const uint32_t OFF_DELAY_MS = 10000; static const uint8_t MAX_RETRY = 3; // ================= 状態 ================= HardwareSerial RadarSerial(1); Adafruit_NeoPixel led(1, LED_PIN, NEO_GRB + NEO_KHZ800); bool presence = false; uint8_t absentStreak = 0; bool offTimerRunning = false; uint32_t offTimerStart = 0; uint8_t frameBuf[32]; uint8_t frameIdx = 0; bool inFrame = false; uint32_t pressCount = 0; uint32_t successCount = 0; // LEDの現在状態を表す種別 enum LedState { LED_PRESENT, LED_JUDGING, LED_ABSENT, LED_SENDING, LED_FAILED }; LedState ledState = LED_ABSENT; // ================= LED ================= void setLed(uint8_t r, uint8_t g, uint8_t b) { led.setPixelColor(0, led.Color(r, g, b)); led.show(); } // 通常状態(在室/判定中/不在)を色で表示する void updateLedNormal() { if (presence) { ledState = LED_PRESENT; setLed(0, 0, 255); // 青 } else if (absentStreak > 0) { ledState = LED_JUDGING; setLed(255, 180, 0); // 黄 } else { ledState = LED_ABSENT; setLed(0, 255, 0); // 緑 } } // 白点滅(送信中) void blinkWhite(uint8_t times) { for (uint8_t i = 0; i < times; i++) { setLed(255, 255, 255); delay(120); setLed(0, 0, 0); delay(120); } } // 赤点滅(失敗) void blinkRed(uint8_t times) { for (uint8_t i = 0; i < times; i++) { setLed(255, 0, 0); delay(200); setLed(0, 0, 0); delay(200); } } // ================= ユーティリティ ================= void printTime() { Serial.printf("[%7.1fs] ", millis() / 1000.0); } // ================= BLE ================= bool pressOnce() { NimBLEClient* client = nullptr; if (NimBLEDevice::getCreatedClientCount() > 0) { client = NimBLEDevice::getClientByPeerAddress(NimBLEAddress(BOT_MAC, BLE_ADDR_RANDOM)); if (client == nullptr) { client = NimBLEDevice::getDisconnectedClient(); } } if (client == nullptr) { client = NimBLEDevice::createClient(); client->setConnectTimeout(5 * 1000); } NimBLEAddress addr(BOT_MAC, BLE_ADDR_RANDOM); if (!client->connect(addr)) { return false; } NimBLERemoteService* service = client->getService(SERVICE_UUID); if (service == nullptr) { client->disconnect(); return false; } NimBLERemoteCharacteristic* chr = service->getCharacteristic(WRITE_UUID); if (chr == nullptr) { client->disconnect(); return false; } bool ok = chr->writeValue(PRESS_CMD, sizeof(PRESS_CMD), true); delay(200); client->disconnect(); return ok; } void pressSwitchBot(const char* reason) { pressCount++; printTime(); Serial.printf("SwitchBot を押します(%s)\n", reason); // 送信中は白点滅 ledState = LED_SENDING; bool ok = false; for (uint8_t retry = 0; retry < MAX_RETRY && !ok; retry++) { if (retry > 0) { printTime(); Serial.printf(" リトライ %d/%d\n", retry, MAX_RETRY - 1); } blinkWhite(2); // 送信の合図(白点滅) ok = pressOnce(); } printTime(); if (ok) { successCount++; Serial.printf(" ★ 成功(通算 %lu/%lu)\n", successCount, pressCount); } else { Serial.printf(" × 失敗(通算 %lu/%lu)\n", successCount, pressCount); blinkRed(3); // 失敗は赤点滅 } // 送信が終わったら通常表示に戻す updateLedNormal(); } // ================= 在室判定 ================= void handleRawPresence(bool raw) { if (raw) { absentStreak = 0; if (!presence) { presence = true; printTime(); Serial.println(">>> 入室を検知"); if (offTimerRunning) { offTimerRunning = false; printTime(); Serial.println(" 消灯予定をキャンセル(照明は点いたまま)"); updateLedNormal(); } else { pressSwitchBot("点灯"); } } else { updateLedNormal(); // 在室継続(青を維持) } } else { if (presence) { absentStreak++; updateLedNormal(); // 判定中(黄)を表示 if (absentStreak >= ABSENT_CONFIRM_COUNT) { presence = false; absentStreak = 0; printTime(); Serial.printf(">>> 退室を検知(%lu秒後に消灯)\n", OFF_DELAY_MS / 1000); offTimerRunning = true; offTimerStart = millis(); updateLedNormal(); // 不在確定(緑) } } } } // ================= メイン ================= void setup() { Serial.begin(115200); delay(2000); Serial.println(); Serial.println("================================================="); Serial.println(" トイレ照明自動化 + RGB LED表示"); Serial.println("================================================="); Serial.println("色:在室=青 / 判定中=黄 / 不在=緑 / 送信中=白点滅 / 失敗=赤点滅"); Serial.println(); // LED led.begin(); led.setBrightness(LED_BRIGHTNESS); led.clear(); led.show(); // レーダーUART RadarSerial.begin(RADAR_BAUD, SERIAL_8N1, RADAR_RX_PIN, RADAR_TX_PIN); // BLE NimBLEDevice::init(""); NimBLEDevice::setPower(ESP_PWR_LVL_P9); updateLedNormal(); // 起動時は不在(緑) Serial.println("起動完了。待機中..."); } void loop() { while (RadarSerial.available()) { uint8_t b = RadarSerial.read(); if (!inFrame) { if (b == 0x01) { inFrame = true; frameIdx = 0; frameBuf[frameIdx++] = b; } } else { if (frameIdx < sizeof(frameBuf)) { frameBuf[frameIdx++] = b; } if (frameIdx == 7) { uint16_t type = ((uint16_t)frameBuf[5] << 8) | frameBuf[6]; if (type != 0x0F09) { inFrame = false; } } if (inFrame && frameIdx >= 9) { handleRawPresence(frameBuf[8] == 0x01); inFrame = false; } } } if (offTimerRunning && (millis() - offTimerStart >= OFF_DELAY_MS)) { offTimerRunning = false; pressSwitchBot("消灯"); } }
詳細
[Arduino IDE]XIAO ESP32C6ボードのArduino登録
以下の手順でESP32シリーズのボード登録を有効にして,XIAO ESP32C6を登録する:
- [ファイル]→[環境設定...]を選択する

環境設定を開く - 環境設定ウィンドウの追加のボードマネージャのURL:欄に
https://espressif.github.io/arduino-esp32/package_esp32_index.jsonを入力して,[OK]を押す
追加のボードマネージャにESP32のURLを記載 - [ツール]→[ボード:]→[ボードマネージャ...]を選択する

ボードマネージャを開く - 入力欄に
esp32と入力して,esp32 by Espressif Systemsのほうの[インストール]を押す.インストールが完了したら[閉じる]を押す
esp32 by Espressif Systemsのインストール - 再度,[ツール]→[ボード:]の順にたどると[ESP32 Arduino]が増えているので,XIAO_ESP32C6を探して選択する

XIAO_ESP32C6の選択 - 再度,[ツール]を開くとXIAO_ESP32C6のメニューが増える.特に変更は不要だが,[ポート]の項目にてXIAO ESP32C6が接続されたCOMポートを選択する(ここではCOM3)

XIAO_ESP32C6の接続ポート選択
[Arduino IDE]ライブラリーの登録
今回のソフトでは,以下のライブラリーを利用する:
- NimBLE-Arduino:Bluetooth Low Energyの通信制御(SwitchBotボットの通信用)
- Adafruit NeoPixel:RGB LEDの制御
たとえば,NimBLE-Arduinoライブラリーの場合の追加手順は以下のとおりである:
- [ツール]→[ライブラリを管理...]を選択する

ライブラリマネージャを開く - ライブラリマネージャウィンドウの入力欄に
nimble-arduinoと入力して,読み込みを待つ.読み込み完了後,リストからNimBLE-Arduinoを探して,[インストール]を押す.インストールが完了したら[閉じる]を押す
NimBLE-Arduinoのインストール
[Arduino IDE][XIAO ESP32C6][MR60BHA2]ミリ波センサー在不在検出方法
仕様が不明であったため(調べてないだけ),ミリ波センサーの生の通信データを受信して,部屋に人がいるときといないときのデータを解析した(Claudeが).その結果,上述のとおりの在不在判定にたどり着いた.在不在のみを判別するソースコードは以下のとおり:
/* * ステップ1: mmWaveレーダー(MR60BHA2)のUART生データ確認 * * 目的: 在室フレームと不在フレームが正しく届いているかを目視確認する * * ハードウェア: XIAO ESP32C6 + MR60BHA2 (Sensor Kit 内蔵接続) * UART: 115200bps, RX=GPIO17, TX=GPIO16 * * 期待する出力: * 在室: 01 XX XX 00 02 0F 09 CS 01 00 FE * 不在: 01 XX XX 00 02 0F 09 CS 00 00 FF * ^^ ^^ * チェックサム 在室フラグ(01=在室 / 00=不在) */ #define RADAR_RX_PIN 17 #define RADAR_TX_PIN 16 #define RADAR_BAUD 115200 // レーダー用のシリアルポート(UART1を使う) HardwareSerial RadarSerial(1); // フレーム組み立て用 uint8_t frameBuf[32]; uint8_t frameIdx = 0; bool inFrame = false; void setup() { // USB経由のデバッグ出力 Serial.begin(115200); delay(2000); // シリアルモニタが開くのを待つ Serial.println(); Serial.println("================================================="); Serial.println(" ステップ1: レーダーUART生データ確認"); Serial.println("================================================="); Serial.println("在室フレーム(0F09)だけを抽出して表示します。"); Serial.println("人が居る時と居ない時で 9バイト目 が変わるはずです。"); Serial.println(); // レーダーとのUARTを開始 RadarSerial.begin(RADAR_BAUD, SERIAL_8N1, RADAR_RX_PIN, RADAR_TX_PIN); } void loop() { while (RadarSerial.available()) { uint8_t b = RadarSerial.read(); if (!inFrame) { // フレーム先頭(0x01)を探す if (b == 0x01) { inFrame = true; frameIdx = 0; frameBuf[frameIdx++] = b; } } else { if (frameIdx < sizeof(frameBuf)) { frameBuf[frameIdx++] = b; } // ヘッダー(1)+ID(2)+LEN(2)+TYPE(2) = 7バイトで種別を判定 if (frameIdx == 7) { uint16_t type = ((uint16_t)frameBuf[5] << 8) | frameBuf[6]; if (type != 0x0F09) { inFrame = false; // 在室フレーム以外は捨てる } } // 在室フレームなら11バイト集めて表示 if (inFrame && frameIdx >= 11) { Serial.print("0F09: "); for (uint8_t i = 0; i < 11; i++) { if (frameBuf[i] < 0x10) Serial.print('0'); Serial.print(frameBuf[i], HEX); Serial.print(' '); } // 在室フラグ(インデックス8)を人間向けに表示 Serial.print(" => "); Serial.println(frameBuf[8] == 0x01 ? "在室" : "不在"); inFrame = false; } } } }
また,実行時のログは以下のように表示される:

[Arduino IDE][XIAO ESP32C6][SwitchBotボット]ESP32C6でのSwitchBotボット操作
本記事,ここで初めてスマホ,Android OSのAQUOS*6が登場する.
以下の方法にてSwitchBotボットのMACアドレスを確認した.nRF Connectアプリはバックグラウンドで起動しておけば,BLEのデバイスと通信したときに各種情報が確認できる!
- nRF Connectアプリ,SwitchBotアプリの両方をインストールする

nRF ConnectアプリとSwitchBotアプリのインストール - SwitchBotボットを操作する前にBLE通信を観測用のnRF Connectを起動させて,バックグラウンドで起動させたままにしておく

nRF Connect起動後の画面(特にまだ操作しない) - SwitchBotのアカウントを作成して,SwitchBotアプリのトップ画面を表示後,中央の[+デバイスを追加]をタップする

デバイスを追加をタップ - SwitchBotアプリが自動で周辺のSwitchBotデバイスを検出するため,[ボット]をタップする

ボットをタップ - SwitchBotアプリの画面にて,用意したボットとそのMACアドレスの最下位バイトが表示される.ボットの枠の電源ボタンイラストのボタンをタップすると,その後にnRF Connectのバナー(WoHand has connected)が表示されるので[Yes and open]にタップする

ボットが表示されるので操作する - nRF Connectのアプリに表示切替後,右上に表示されているMACアドレスが制御対象のSwitchBotボットのMACアドレスである

SwitchBotボットのMACアドレス
このMACアドレスを元に,SwitchBotボットの操作を10秒ごとに行うソースコードは以下のとおり.ただし,指押しの押下の処理であり,指は押してはいないものの出たままの状態になる.
/* * ステップ2: BLEでSwitchBot Botを動かす確認 * * 目的: 10秒ごとに press コマンドを送り、繰り返し動作するかを確認する * * 必要なライブラリ: * NimBLE-Arduino(ライブラリマネージャからインストール) * ※ESP32標準のBLEライブラリより軽量・安定で、 * 接続の再確立まわりの挙動が素直なため採用 * * SwitchBot Bot のパラメータ: * MAC : F4:A3:99:**:**:** * Service UUID : cba20d00-224d-11e6-9fb8-0002a5d5c51b * Write Char UUID : cba20002-224d-11e6-9fb8-0002a5d5c51b * Press コマンド : 57 01 01 */ #include <NimBLEDevice.h> // ----- SwitchBot の設定 ----- // MACアドレスは実際のアドレスを記載する static const char* BOT_MAC = "f4:a3:99:**:**:**"; // 小文字で指定 static const char* SERVICE_UUID = "cba20d00-224d-11e6-9fb8-0002a5d5c51b"; static const char* WRITE_UUID = "cba20002-224d-11e6-9fb8-0002a5d5c51b"; static const uint8_t PRESS_CMD[3] = { 0x57, 0x01, 0x01 }; // ----- 動作設定 ----- static const uint32_t PRESS_INTERVAL_MS = 10000; // 10秒ごとに押す static const uint8_t MAX_RETRY = 3; // 接続リトライ回数 unsigned long lastPressTime = 0; uint32_t pressCount = 0; uint32_t successCount = 0; /* * SwitchBot に press コマンドを1回送る * 戻り値: true=成功 / false=失敗 */ bool pressSwitchBot() { NimBLEClient* client = nullptr; // 既存のクライアントがあれば再利用、なければ新規作成 if (NimBLEDevice::getCreatedClientCount() > 0) { client = NimBLEDevice::getClientByPeerAddress(NimBLEAddress(BOT_MAC, BLE_ADDR_RANDOM)); if (client == nullptr) { client = NimBLEDevice::getDisconnectedClient(); } } if (client == nullptr) { client = NimBLEDevice::createClient(); client->setConnectTimeout(5 * 1000); // 接続タイムアウト5秒 } // --- 接続 --- Serial.println(" [BLE] 接続を試みます..."); // SwitchBotはランダムアドレスを使うため BLE_ADDR_RANDOM を指定する NimBLEAddress addr(BOT_MAC, BLE_ADDR_RANDOM); if (!client->connect(addr)) { Serial.println(" [BLE] 接続失敗"); return false; } Serial.println(" [BLE] 接続成功"); // --- サービスとキャラクタリスティックを取得 --- NimBLERemoteService* service = client->getService(SERVICE_UUID); if (service == nullptr) { Serial.println(" [BLE] サービスが見つかりません"); client->disconnect(); return false; } NimBLERemoteCharacteristic* chr = service->getCharacteristic(WRITE_UUID); if (chr == nullptr) { Serial.println(" [BLE] キャラクタリスティックが見つかりません"); client->disconnect(); return false; } // --- コマンド書き込み --- bool ok = chr->writeValue(PRESS_CMD, sizeof(PRESS_CMD), true); // true=応答待ち if (ok) { Serial.println(" [BLE] ★ press コマンド送信成功!"); } else { Serial.println(" [BLE] 書き込み失敗"); } // --- 切断 --- // SwitchBotは繋ぎっぱなしにすると約15秒で自分から切るため、 // 用が済んだらこちらから明示的に切る delay(200); client->disconnect(); Serial.println(" [BLE] 切断しました"); return ok; } void setup() { Serial.begin(115200); delay(2000); Serial.println(); Serial.println("================================================="); Serial.println(" ステップ2: SwitchBot BLE動作確認"); Serial.println("================================================="); Serial.printf("10秒ごとに press コマンドを送信します。\n"); Serial.printf("対象: %s\n", BOT_MAC); Serial.println("Botのアームが繰り返し動けば成功です。"); Serial.println(); // BLE初期化 NimBLEDevice::init(""); NimBLEDevice::setPower(ESP_PWR_LVL_P9); // 送信出力を最大にする lastPressTime = millis() - PRESS_INTERVAL_MS; // 起動直後に1回実行 } void loop() { if (millis() - lastPressTime >= PRESS_INTERVAL_MS) { lastPressTime = millis(); pressCount++; Serial.printf("\n--- %lu回目の press (経過 %lu 秒) ---\n", pressCount, millis() / 1000); // 失敗したらリトライする bool ok = false; for (uint8_t retry = 0; retry < MAX_RETRY && !ok; retry++) { if (retry > 0) { Serial.printf(" リトライ %d/%d\n", retry, MAX_RETRY - 1); delay(500); } ok = pressSwitchBot(); } if (ok) successCount++; Serial.printf("成績: %lu / %lu 成功\n", successCount, pressCount); } delay(10); }
[Arduino IDE][XIAO ESP32C6]LED制御
RGB LEDのLチカ動作チェックとして2秒ごとに赤,緑,青,白,消灯を繰り返すソースコードは以下のとおり:
/* * LEDテスト: ベースボードの WS2812 RGB LED 確認 * * 判明したこと(Seeed公式サンプルより): * RGB LED はベースボード上にあり、XIAOの D1 ピンに接続されている * 制御には Adafruit_NeoPixel ライブラリを使う * * 事前準備: * Sketch > ライブラリを管理 で「Adafruit NeoPixel」をインストール * * 期待する動作: * 赤 → 緑 → 青 → 白 → 消灯 を2秒ずつ繰り返す */ #include <Adafruit_NeoPixel.h> const int pixelPin = D1; // ベースボードのRGB LED Adafruit_NeoPixel pixels(1, pixelPin, NEO_GRB + NEO_KHZ800); void showColor(const char* name, uint8_t r, uint8_t g, uint8_t b) { Serial.printf("色: %s (R=%d G=%d B=%d)\n", name, r, g, b); pixels.setPixelColor(0, pixels.Color(r, g, b)); pixels.show(); } void setup() { Serial.begin(115200); delay(2000); Serial.println(); Serial.println("================================================="); Serial.println(" LEDテスト3: ベースボードRGB LED (D1)"); Serial.println("================================================="); Serial.println("赤→緑→青→白→消灯 を繰り返します。"); Serial.println(); pixels.begin(); pixels.clear(); pixels.show(); } void loop() { showColor("赤", 64, 0, 0); delay(2000); showColor("緑", 0, 64, 0); delay(2000); showColor("青", 0, 0, 64); delay(2000); showColor("白", 64, 64, 64); delay(2000); showColor("消灯", 0, 0, 0); delay(2000); Serial.println("--- 一巡しました ---"); }
その他
当初はESP Homeをベースに実装する手はずで進んでいたが,2日間の夜3時間程度のパワーでは解決できなかったので諦め.その後,何とか動いたんじゃないか,これ? と思った時点でふと冷静になったら技術基準適合証明通ってないから180日の評価を除き使えないことに気づいた悲痛な私のツイッター(の始まりのツイート):
MR60BHA2使ってClaudeでソフトを組んでたけどESPHomeのバグだそうです(ホントかな?):
— AKETO, Tomu (@so2akt) July 20, 2026
seeed_mr60bha2 コンポーネントが ESPHome 2026.x でコンパイル不能(.cpp が breath_rate_sensor_ 等を参照するが、2026.xのマクロ仕様変更で該当メンバーが生成されない。ESPHome/Seeed側のバグ。
改訂履歴
| # | 日付 | 内容 |
|---|---|---|
| 1 | 2026/08/12 | ステップ2: BLEでSwitchBot Botを動かす確認のソースコードのMACアドレス末尾に:が付いていたのを削除 |
参考サイト
- [壁取付]かってにスイッチ(2線式) | 商品ラインアップ | コスモシリーズワイド21 | スイッチ・コンセント(配線器具) | Panasonic(2026/08/11現在)
- MR60BHA2 入門ガイド | Seeed Studio Wiki(2026/08/11現在)
※本記事におけるソフトウェア作成にはClaudeを利用している
































































