仕事の中でECHONET Lite(エコーネットライト)というプロトコルを知ったのですが、このプロトコルで部屋にあるSharp製のエアコン(型番 AY-H22S-W
) を操作できそうなので使ってみました。
- ECHONET Liteとは
- 部屋のエアコンが対応しているか調べてみた
- 調べてみる & やってみる
- ECHONET Liteへの通信
- ECHONET Liteフレーム
- PythonでEHD (ヘッダー部分)を作る
- PythonでEDATA(データ部分)を作る
- ECHONET Liteのコマンド完成
- エアコンにコマンド送信と結果取得
- エアコンの電源をOffにする
- 参考
ECHONET Liteとは
まず、ECHONET Liteとはからですが、ホームページが存在しています。とても情報量豊富、リンクも纏まっていて、かつ日本語なので、ここを読むのが一番早いです。
そこから引用すると以下のように書かれています。家電の制御に使えるプロトコルのようです。
エコーネットとはスマートハウスを実現する通信プロトコルです。現在、家庭内でもWiFi規格などの無線ネットワークが簡単に活用できる中、スマートフォンやコントローラから、家にあるエアコン、照明などを制御したいとか、電力の無駄遣いを抑えるために家の電気代を把握したいとかいう要望が増えています。
このように省エネ、快適、安全・安心な生活を実現するためには、どのメーカーの機器でも共通に理解できる約束(通信プロトコル)が必要で、その役割を果たすのがエコーネットです。
引用元: エコーネットとは? | ECHONET
部屋のエアコンが対応しているか調べてみた
IoT系のお仕事で、繋ぎ先の機器がECHONET Liteを話せると聞いて調べ始めましたが、成り立ちをみる限り家電でも使えそうです。
もしかして、うちのエアコンも使えたりして・・ということで調べてみました。
対応機種はECHONETのページから探すことができます。
Sharp製品のAY-H22S-Wという型番ですが・・・ありました!!
Sharpのホームページにも「ECHONET Lite連携 動作確認済機種」としてしっかり記載されてました。
このエアコン、WiFi繋ぐとスマホから操作できるというところに惹かれて購入したのですが、このECHONET Liteプロトコル使えばWiFi経由でPythonからも操作できそうです。
調べてみる & やってみる
このリンクに資料が大量にあったのですが、ECHONET規格書から以下の2つのPDF資料を読むことで、ECHONET Liteで通信するところまでいけました。
ECHONET Lite規格書 Ver.1.13(日本語版)
- 第2部 ECHONET Lite 通信ミドルウェア仕様
- ファイル名:
ECHONET-Lite_Ver.1.13_02.pdf
- ファイル名:
APPENDIX ECHONET機器オブジェクト詳細規定 Release M Revised (日本語)
- APPENDIX ECHONET機器オブジェクト詳細規定Release M Revised
- ファイル名:
Appendix_Release_M_Revised.pdf
- ファイル名:
ECHONET Liteへの通信
ECHONET-Lite_Ver.1.13_02.pdf
に記載があります。
ECHONET Lite ノードは、ポート 3610 にて、UDP ユニキャスト、および、マルチキャストのパケットを待ち受けるものとする。
3610
ポートで UDP
でやりとりすれば良さそうです。
ECHONET Liteフレーム
送受信するフレームについても規定があります。このフレームでECHONET Lite対応の機器に命令を出すします。
フレームの構成は、 ECHONET-Lite_Ver.1.13_02.pdf
の 3.2 電文構成
に記載がありますが、以下の図のように、バイト単位で意味を持たせながら以下のようなフレームを構成します。
引用元: ECHONET-Lite_Ver.1.13_02.pdf
PythonでEHD (ヘッダー部分)を作る
まずは、ヘッダー部分を作っていきます。内容はコメントに入れ込んでいます。「第2部 ECHONET Lite 通信ミドルウェア仕様」のドキュメントに沿って書いています。
値は16進数です。最後にByte変換しますが、一旦Stringで設定します。
# --------------------------------------------------- # 3.2.1 ECHONET Lite ヘッダ(EHD) # --------------------------------------------------- # 3.2.1.1 ECHONET Lite ヘッダ 1(EHD1) EHD1 = "10" # ECHONET Lite規格 # 3.2.1.2 ECHONET Lite ヘッダ 2(EHD2) EHD2 = "81" # 形式1(規定電文形式) # 3.2.2 Transaction ID(TID) TID = "0001" # IDなのでこの検証ではどの値でもOK # フレームのヘッダ-を構成 EHD = EHD1 + EHD2 + TID
PythonでEDATA(データ部分)を作る
今度はデータ部分のEDATAです。
例として、電源のOn/Off情報と、温度設定を取得してみることにします。
# --------------------------------------------------- # 3.2.1 ECHONET Lite データ(EDATA) # --------------------------------------------------- # 3.2.4 ECHONETオブジェクト # EOJ = ECHONET Lite オブジェクト # SEOJ = 送信元ECHONET Lite オブジェクト SEOJ_CLS_GROUP = "05" # 管理・操作関連クラスグループ SEOJ_CLS_CODE = "ff" # コントローラー SEOJ_CLS_INSTANCE = "01" # インスタンス番号 SEOJ = SEOJ_CLS_GROUP + SEOJ_CLS_CODE + SEOJ_CLS_INSTANCE # DEOJ = 送信先ECHONET Lite オブジェクト DEOJ_CLS_GROUP = "01" # 空調関連機器クラスグループ DEOJ_CLS_CODE = "30" # 家庭用エアコンクラス DEOJ_CLS_INSTANCE = "01" # All Instanses DEOJ = DEOJ_CLS_GROUP + DEOJ_CLS_CODE + DEOJ_CLS_INSTANCE # 3.2.5 ECHONET Lite サービス(ESV) ESV = "62" # プロパティ値読み出し要求 (Get) ############### # APPENDIX ECHONET機器オブジェクト詳細規定 # - 空調関連機器クラスグループ # - 家庭用エアコンクラス規定 # を確認 # 3.2.6 処理プロパティカウンタ OPC = "02" # 2件 # プロパティ 1件目 EPC1 = "80" # 動作状態の取得(On or Off) PDC1 = "00" # Getの場合は0でOK EDT1 = "" # Getの場合はEDTは不要 PROP1 = EPC1 + PDC1 + EDT1 # プロパティ 2件目 EPC2 = "b3" # 温度設定の取得 PDC2 = "00" # Getの場合は0でOK EDT2 = "" # Getの場合はEDTは不要 PROP2 = EPC2 + PDC2 + EDT2 # フレームのデータ部分であるEDATAを構成 EDATA = SEOJ + DEOJ + ESV + OPC + PROP1 + PROP2
ECHONET Liteのコマンド完成
ヘッダとデータ部分を合わせるとECHONET Liteの要求コマンドができます。送信用と受信用のSocketを作って通信しているのがポイントです。
echonet_command = EHD + EDATA
今回の場合は中身はこんなデータになります。送る時には bytes.fromhex(command)
とByte変換してあげます。
1081000105ff0101300162028000b300
エアコンにコマンド送信と結果取得
UDPでエアコンにECHONET Liteのコマンド投げてみます。
送信用とは別途、応答を受け取るための受信用のSocketを準備してあげるのがポイントです。
import socket echonet_port = 3610 aircon_ip = "192.168.1.10" # 224.0.23.0のアドレスを使うとマルチキャストもできます # 応答待ち受け用ソケット recv_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) recv_sock.bind(("0.0.0.0", echonet_port)) # 要求送信用ソケットでコマンド送信 send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) send_sock.sendto(bytes.fromhex(echonet_command), (aircon_ip, echonet_port)) # 応答を受け取る data, addr = recv_sock.recvfrom(1024) send_sock.close() recv_sock.close()
dataに応答が入っています。このままだと見づらいので、16進数の配列で出力して中身見てみます。
>>> data b'\x10\x81\x00\x01\x010\x01\x05\xff\x01r\x02\x80\x010\xb3\x01\x1c' >>> [hex(b) for b in data] ['0x10', '0x81', '0x0', '0x1', '0x1', '0x30', '0x1', '0x5', '0xff', '0x1', '0x72', '0x2', '0x80', '0x1', '0x30', '0xb3', '0x1', '0x1c']
まず、 data[10]
が 0x72
となっていますが、0x7*
が返ってきている場合は正常に応答していることを示しています。
次に、hex(data[12]) -> 0x80
で要求した、エアコンのOn/Off情報に関する応答が data[14]
に入っています。0x30
はONを示します。
>>> hex(data[14]) '0x30'
そして、data[15] -> 0xb3
の応答として data[17]
に入っている 0x1c = 28
が温度ですね。
>>> print(f"{data[17]} 度") 28 度
エアコンの電源をOffにする
上ではエアコンの電源のOn/Off情報を取得しましたが、ESVという値を書き換えることで、同じプロパティからエアコンの操作を行うこともできます。
以下のように上記を修正して実行すれば、エアコンが停止されるはずです。
OPC = "01" # 今回操作するプロパティは電源の1件だけなので1を設定 ESV = "60" # プロパティ値書き込み要求(応答不要) EPC1 = "80" # 動作状態の取得(On or Off) PDC1 = "01" # 1Byteを指定 EDT1 = "31" # 0x31がOFFを表す PROP1 = EPC1 + PDC1 + EDT1 EDATA = SEOJ + DEOJ + ESV + OPC + PROP1 echonet_command = EHD + EDATA # echonet_command -> '1081000105ff010130016101800131' # 応答不要なので、送信Socketだけ準備してUDPで送ります。 send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) send_sock.sendto(bytes.fromhex(echonet_command), (aircon_ip, echonet_port)) send_sock .close()
参考
自分の勉強のためにあえて愚直な実装してみましたが、その際に以下の2つのリポジトリを大いに参考にさせていただきました。
特にnodeのリポジトリはすぐに動かすことができるので、そもそも繋がっているか心配なタイミングでは大変助かりました。