M5 Atome Lite・Atom Matrixでおうちハック! ECHONET Lite対応の電動ブラインドを動かす
https://scrapbox.io/files/685e3b0c69c171c52a7dc5b4.mp4
関連ページ
1. やりたいこと
Atom Lite、Atom MatrixでECHONET Lite対応電動ブラインドを操作する
Atom Lite/Marix から UDP通信でECHONET Liteコマンドを投げて制御
電動ブラインド 開/閉じる
2. 対象機器
ニチベイ ELアダプターに接続された電動ブラインド
3. IoTルームでの構成 ※神奈川工科大学 電気電子情報工学科の施設です
code:構成
└──電動プリーツスクリーン (インスタンス0x02) └──電動ロールスクリーン (インスタンス0x03) 4 電文の例:
参考資料:
3.3.1 電動ブラインド ・日よけ クラス規定(pp.184)
3.6.2 コントローラクラス規定(pp.622)
4.1 電文の例:
code:ECHONET Lite電文
1081 # EHD(ECHONETヘッダ)← "1081"で固定
0001 # TID(トランザクションID)← 何でもよい
60 # ESV(ECHONET Lite サービス)← プロパティを SetI0x60に設定) 01 # OPC(処理プロパティ数)← 1個に設定
E0 # EPC(プロパティコード:開閉動作)
01 # PDC(データ長:1バイト)
41 # EDT(データ:開 = 0x41,閉 = 0x42,停止 = 0x43 )
code:ECHONET Lite電文(0x表記)
0x10, 0x81, // EHD(ECHONETヘッダ)← "1081"で固定
0x00,0x01, // TID(トランザクションID)← 何でもよい
0x02, 0x60, 0x01, // DEOJ(宛先)← 電動ブラインド(グループ 0x02+クラス 0x60+インスタンス0x01) 0x60, // ESV(ECHONET Lite サービス)← プロパティを SetI0x60に設定) 0x01, // OPC(処理プロパティ数)← 1個に設定
0xE0, // EPC(プロパティコード:開閉動作)
0x01, // PDC(データ長:1バイト)
0x42, // EDT(データ:開 = 0x41,閉 = 0x42,停止 = 0x43)
4.2 電文作成のおおまかなポイント
DEOJとEPC、PDC、EDTを設定(EHD、TID、SEOJは変更の必要なし)
DEOJ(宛先)は動かしたい機器に応じて次のように設定:
電動ブラインド(インスタンス1):026001(0x02, 0x60, 0x01)
電動プリーツスクリーン(インスタンス2):026002(0x02, 0x60, 0x02)
電動ロールスクリーン(インスタンス3):026003(0x02, 0x60, 0x03)
ESV、OPCは変更の必要なし(必要に応じて変更してもよい)
※以下に詳細な設定のしかたを示しますが、最初はわからなくても大丈夫です。
4.2.1 DEOJ(宛先)の設定のしかた(詳細)
code:DEOJ
DEOJ = クラスグループコード(0x02) + クラスコード(0x60) + インスタンスコード(0x01)
https://gyazo.com/b25b27d0d38e4834abce3494a3a7d622
4.2.2 EPC、PDC、EDTの設定のしかた(詳細)
https://gyazo.com/f7d1a91a53a26b931e9914c78dd46c6e
4.3 作成した電文を試すには
code:UDP/IPテストツール用電文例
開:
<10><81><00><00><05><FF><01><02><60><01><60><01><E0><01><41>
閉:
<10><81><00><00><05><FF><01><02><60><01><60><01><E0><01><42>
4.2 Atome Liteから操作する
code: Switch_ELBlind.ino
const char* ssid = "YOURSSID"; //自分の環境に合わせて書き換える
const char* password = "YOURPASSWORD"; //自分の環境に合わせて書き換える
WiFiUDP udp;
IPAddress deviceIP(192, 168, 0, 153); // 宛先(電動ブラインドELアダプターのIPアドレス)
const int echonetPort = 3610;
bool BlindOpen = false;
bool lastButton = false;
void sendECHONET(bool powerOn) {
byte echonetFrame[] = {
0x10, 0x81, // EHD(ECHONETヘッダ)← "1081"で固定
0x00,0x01, // TID(トランザクションID)← 何でもよい
0x02, 0x60, 0x01, // DEOJ(宛先)← 電動ブラインド(グループ 0x02+クラス 0x60+インスタンス0x01) 0x60, // ESV(ECHONET Lite サービス)← プロパティを SetI0x60に設定) 0x01, // OPC(処理プロパティ数)← 1個に設定
0xE0, // EPC(プロパティコード:開閉動作)
0x01, // PDC(データ長:1バイト)
powerOn ? 0x41 : 0x42 // EDT (開 = 0x41,閉 = 0x42)
};
udp.beginPacket(deviceIP, echonetPort);
udp.write(echonetFrame, sizeof(echonetFrame));
udp.endPacket();
Serial.printf("ECHONET Lite電文を送信しました(%s)\n", powerOn ? "ON" : "OFF");
}
void setup() {
M5.begin(true, false, true); // LED使用のためI2C無効化(M5 Atom用)
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting...");
}
Serial.println("Connected!");
// WiFi接続成功時にLEDを白色に点灯
M5.dis.drawpix(0, 0xFFFFFF);
}
void loop() {
M5.update();
bool button = M5.Btn.isPressed();
if (button && !lastButton) {
// ボタン押下時のみトグル処理(チャタリング防止)
BlindOpen= !BlindOpen;
sendECHONET(BlindOpen);
// LED表示切替
uint32_t color = BlindOpen ? 0x00FF00 : 0xFF0000; // 緑 or 赤
M5.dis.drawpix(0, color);
}
lastButton = button;
delay(20); // ポーリング間隔
}
解説
Wi-Fi接続したM5 Atomを使って、ECHONET Lite形式の開/閉電文をUDPで送信します。
内蔵ボタンを押すたびにブラインドの開/閉を切り替え、その状態をLEDの色(緑=開、赤=閉)で表示します。
table:動作結果
ボタンを押す 開/閉の状態を切り替える
ブラインドが閉じているとき 開 電文送信(EDT=0x41)LED緑 点灯
ブラインドが開いているとき 閉 電文送信(EDT=0x42)LED赤 点灯
開と閉を区別するために、ECHONET Lite電文の最後の EDT(データ本体)部分だけが変わります。
開:0x41(=動作状態ON)
閉:0x42(=動作状態OFF)
この切り替えは、 三項演算子(条件 ? 真の場合 : 偽の場合)を使って以下のように書いています。
code:powerOn
powerOn ? 0x41 : 0x42
//powerOn(sendECHONETの引数) が true(=ON状態)なら 0x41、そうでなければ 0x42(=OFF)
Pythonの三項演算子とはやや表記が異なるので補足で説明しました。
※おまけ: 長押しでDEOJ(ブラインド・プリーツ・ロール)を切り替えられるようにしたコード
table: DEOJ
DEOJ 機器 LED
026001 ブラインド 緑
026002 プリーツスクリーン 青
026003 ロールスクリーン 黄
挙動
短押しで開閉トグル
長押し(1秒以上)でDEOJ切り替え
現在のDEOJに応じてLED色変化
code:Switch_ELBlind_Three.ino
const char* ssid = "YOURSSID";
const char* password = "YOURPASSWORD";
WiFiUDP udp;
IPAddress deviceIP(192, 168, 0, 153);
const int echonetPort = 3610;
// ブラインド開閉状態
bool BlindOpen = false;
bool lastButton = false;
// DEOJ一覧(インスタンス01〜03)
{0x02, 0x60, 0x01}, // 電動ブラインド
{0x02, 0x60, 0x02}, // 電動プリーツスクリーン
{0x02, 0x60, 0x03} // 電動ロールスクリーン
};
int currentDeojIndex = 0;
// ボタン長押し検出用
unsigned long buttonPressTime = 0;
bool longPressHandled = false;
void sendECHONET(bool powerOn) {
byte echonetFrame[] = {
0x10, 0x81,
0x00, 0x01,
0x05, 0xFF, 0x01,
0x00, 0x00, 0x00, // ← DEOJはここで差し替え
0x60,
0x01,
0xE0,
0x01,
powerOn ? 0x41 : 0x42
};
// 現在のDEOJを挿入
udp.beginPacket(deviceIP, echonetPort);
udp.write(echonetFrame, sizeof(echonetFrame));
udp.endPacket();
Serial.printf("送信:DEOJ=%02X%02X%02X(%s)\n",
echonetFrame7, echonetFrame8, echonetFrame9, powerOn ? "開" : "閉");
}
void updateLED() {
// インスタンスごとにLED色を変える
uint32_t colors3 = { 0x00FF00, 0x0000FF, 0xFFFF00 }; // 緑・青・黄 }
void setup() {
M5.begin(true, false, true);
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting...");
}
Serial.println("Connected!");
updateLED();
}
void loop() {
M5.update();
bool button = M5.Btn.isPressed();
// ボタン押した瞬間
if (button && !lastButton) {
buttonPressTime = millis();
longPressHandled = false;
}
// ボタンを押し続けているとき
if (button && !longPressHandled) {
if (millis() - buttonPressTime > 1000) { // 長押し1秒
currentDeojIndex = (currentDeojIndex + 1) % 3; // DEOJ切り替え
updateLED();
Serial.printf("DEOJ切替:%02X%02X%02X\n",
longPressHandled = true;
}
}
// ボタンを離した瞬間(短押し)
if (!button && lastButton) {
if (!longPressHandled) {
BlindOpen = !BlindOpen;
sendECHONET(BlindOpen);
}
}
lastButton = button;
delay(20);
}
https://gyazo.com/71c7de59f100448c29cdb7f29fbd171b