Wi-Fi対応エアコンをM5stackCore2で動かす

# Wi-Fi対応エアコンをM5Core2で動かす


### 注意
当記事で作成したプログラムによって発生する事象に関しては一切の責任を負いかねますのでご注意ください。

### 基本環境
-Windows10以上のPC又はMAC(Apple Silicon)
-Arduino IDE 2.0以降
-Arduino IDEにM5Core2用ライブラリをインストール済み

## 1.どうやってメーカー問わずにエアコンを動かす？
あまり知られていませんが
**日本の家庭用エアコン出荷台数の約7割はECHONET Lite対応のエアコンです。**
ECHONET Liteは日本で作られたIoTの国際規格です。

![エアコン出荷.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638852/b1e0bef3-dcdf-b5e1-6e67-7175f986a305.png)
以下二つの統計を基に作成
*[エコーネットコンソーシアム出荷状況調査](https://echonet.jp/shipments/)
*日本冷凍空調工業会　家庭用エアコン（ルームエアコン）国内出荷実績

#### 自宅のエアコンがECHONET Lite対応か確認する方法
[ECHONETコンソーシアム　エコネット製品紹介](https://echonet.jp/product/echonet-lite/)に行き検索をクリック
![スクリーンショット 2024-02-15 180544.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638852/7b0f56aa-f86d-8367-ca21-e9055c5543f6.png)

#### キーワードにエアコンの型番を入力
対応製品で有れば検索結果が表示されます。
![スクリーンショット 2024-02-15 180756.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638852/26f11f76-7552-10aa-7dc3-18b07eeb7826.png)
**Wi-Fi機種の場合は事前にメーカーの取扱説明書に従いWi-Fiへの接続設定を行ってください**

## 2.エアコンのIPアドレスを調べる
無料のIoT機器統合管理&ヘルスケアアプリ**PLIS**を使用します。
[PLIS公式サイト](https://plis.sugi-lab.net/index.html)

PLISは神奈川工科杉村研究室で開発中のアプリです。
本アプリの使用関する一切の責任を負いかねます。

### 1.PLISをインストール
Windowsをお使いの方は[Microsoft Store版PLIS](https://www.microsoft.com/store/productId/9NQ6XZG0KPL3?ocid=pdpshare)
MAC OSをお使いの方は[MAC OS版PLIS](https://github.com/Hiroshi-Sugimura/plis/releases)

### 2.PCのWi-Fiをエアコンと同じWi-Fiや有線LANのネットワークに接続してください
### 3.PLISを起動
### 4.PLISのコントロールボタンを押す
![スクリーンショット 2024-02-15 182149.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638852/e28ace3f-1e96-a5a5-c4fc-6614b881cd1d.png)

### 5.エアコンのアイコンにカーソルを合わせる
![PLIS_EL画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638852/8e67e0c3-4da5-422a-8ae6-3ab0451bd828.png)

### 6.エアコンが複数台ある場合はON・OFFしてみてどれが動いたかで判断
![PLIS_ELエアコンIP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638852/1296487c-645c-a963-1866-485ba83d52c3.png)

## 3.Arduino用ECHONET Liteライブラリをインストールしよう

**Arduino用ECHONET Liteライブラリ[EL_dev_arduino](https://github.com/Hiroshi-Sugimura/EL_dev_arduino)を使用します。**
このライブラリを使用することで簡単にECHONET Lite対応のデバイスやコントローラを作れます。

EL_dev_arduinoはArduinoのECHONET Liteプロトコル通信をサポートします．
(ECHONET Liteプロトコルはスマートハウス機器の通信プロトコルです．)
M5Stack Core2を中心にテストしています。

**本モジュールはECHONET Lite認証を受けたものではありませんので、商品化する際には開発者自らが認証を受ける必要があります。**
本ライブラリは神奈川工科杉村研究室で開発中のライブラリです。
MIT License
Copyright (c) 2018 Hiroshi SUGIMURA

### 1.Arduino IDEを起動
### 2.ライブラリを選択
![スクリーンショット 2024-02-15 174841.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638852/3f702561-bc94-4b9f-19b5-139615a19aff.png)

### 3.検索バーに```ECHONET Lite```を入力
![スクリーンショット 2024-02-15 174946.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638852/6047522b-013d-51c1-4e6a-4ca3cfc5dc68.png)
### 4.インストールをクリック
![スクリーンショット 2024-02-09 144627.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638852/21b3879e-c9fc-b22c-2ab6-4edbc5c1df9d.png)


## 4.エアコン操作用のサンプルプログラムを書いてみよう
以下のプログラムをコピペする
Wi-FiのSSIDとパスワードと宛先のエアコンIPアドレスを変更する。
```
// 使い方
// ボード設定はM5Core2を選択
// SSIDとパスワードを変更
// エアコンのIPアドレスを設定

/*エアコンのIPアドレスが分からない場合
1) microsoft StoreでPLISをインストール
2) Control をクリック
3) 動かしたい家電のアイコンにカーソルを合わせるとIPアドレスが見れる
4) どの家電かわからない場合はONボタンを押し、動いた家電を見て判断
5) IPアドレスは , 区切りで書かないと動かないので注意
*/

// #include <M5Stack.h>
#include <M5Core2.h>
#include <WiFi.h>
#include <EL.h>

#define WIFI_SSID "WiFiのSSID"                // WiFiのSSIDに変更する
#define WIFI_PASS "WiFiのPassword"            // WiFiのパスワードに変更する
IPAddress toip = IPAddress(192, 168, 86, 75); // ここのIPアドレスを動かす家電のIPアドレスに変更する

WiFiClient client;
WiFiUDP elUDP;
EL echo(elUDP, {{EL_Controller, 0x01}});     // Controller = 0x05, 0xFF
byte airconditioner[3] = {0x01, 0x30, 0x01}; // fix
byte controller[3] = {0x05, 0xff, 0x01};     // fix

//====================================================================
// user用のcallback
// 受信したらこの関数が呼ばれるので、SetやGetに対して動けばよい、基本はSETだけ動けばよい
// 戻り値や引数は決まっている

// bool (*ELCallback) (   tid,  seoj,   deoj,   esv,  opc,  epc, pdc, edt);
bool callback(byte tid[], byte seoj[], byte deoj[], byte esv, byte opc, byte epc, byte pdc, byte edt[])
{
  bool ret = false; // デフォルトで失敗としておく
  if (deoj[0] != 0x05 || deoj[1] != 0xff)
  {
    return false;
  } // コントローラ宛てではないので無視
  if (deoj[2] != 0x00 && deoj[2] != 0x01)
  {
    return false;
  } // インスタンスがないので無視

  // -----------------------------------
  // ESVがSETとかGETとかで動作をかえる、基本的にはSETのみ対応すればよい
  switch (esv)
  {
  // -----------------------------------
  // 動作状態の変更 Set対応
  case EL_SETI:
  case EL_SETC:
    switch (epc)
    {
    case 0x80: // 電源
      if (edt[0] == 0x30)
      {                              // ON
        Serial.println("ON");        // 設定した値にする
        echo.update(0, epc, {0x30}); // ON
        ret = true;                  // 処理できたので成功
      }
      else if (edt[0] == 0x31)
      { // OFF
        Serial.println("OFF");
        echo.update(0, epc, {0x31}); // 設定した値にするが、
        echo.update(0, epc, {0x30}); // コントローラは常時ON
        ret = true;                  // 処理できたので成功
      }
      break;

    case 0x81:                       // 位置情報
      echo.update(0, epc, {edt[0]}); // その値にする
      break;

    case 0x88:                       // エラー情報
      echo.update(0, epc, {edt[0]}); // その値にする
      break;
    }
    break; // SETI, SETCここまで

  default: // それ以外はfalseを返却
    ret = false;
    break;
  }

  return ret;
}

//====================================================================
// setup
void setup()
{
  M5.begin();
  Serial.println("start");

  M5.Lcd.setTextSize(2);
  M5.Lcd.println("wifi connect start");

  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED)
  {
    M5.Lcd.print(".");
    delay(1000);
  }
  M5.Lcd.println("wifi connect ok");
  M5.update();

  // print your WiFi IP address:
  IPAddress ip = WiFi.localIP();
  M5.Lcd.print("MyIP Address");
  M5.Lcd.println(ip);

  M5.Lcd.setTextDatum(6); // 左下
  M5.Lcd.setTextColor(RED, BLACK);
  M5.Lcd.drawString("ON", 0, 240, 4);

  M5.Lcd.setTextDatum(7); // 中央下
  M5.Lcd.setTextColor(YELLOW, BLACK);
  M5.Lcd.drawString("Mode", 152, 240, 4);

  M5.Lcd.setTextDatum(8); // 右下
  M5.Lcd.setTextColor(BLUE, BLACK);
  M5.Lcd.drawString("OFF", 320, 240, 4);

  // ECHONET Lite initialize
  // 初期値設定
  echo.update(0, 0x80, {0x30});                                           // off
  echo.update(0, 0x9D, {0x80});                                           // INFプロパティマップ
  echo.update(0, 0x9E, {0x80});                                           // Setプロパティマップ
  echo.update(0, 0x9F, {0x80, 0x81, 0x82, 0x83, 0x88, 0x9d, 0x9e, 0x9f}); // Getプロパティマップ
  echo.printAll();                                                        // 全設定値の確認
  echo.begin(callback);                                                   // EL 起動シーケンス
  // 繋がった宣言として立ち上がったことをコントローラに知らせるINFを飛ばす
  echo.sendMultiOPC1(airconditioner, controller, EL_INF, 0x80, {0x30});
}

//====================================================================
// setup
int timeCont = 0;
int ModeNanber = 0;

void loop()
{
  M5.update();

  if (M5.BtnA.wasPressed())
  {
    M5.Lcd.setTextSize(2);
    M5.Lcd.setTextColor(RED, BLACK);
    M5.Lcd.print("ON");
    Serial.println("ON");
    //            宛先IP   SEOJ        DEOJ           ESV    EPC    EDT
    echo.sendOPC1(toip, controller, airconditioner, EL_SETI, 0x80, {0x30}); // 0x30が起動を意味する
  }

  if (M5.BtnB.wasPressed())
  {
    M5.Lcd.setTextSize(2);
    Serial.print("Mode");
    M5.Lcd.setTextColor(YELLOW, BLACK);
    // M5.Lcd.print("B");
    ModeNanber += 1;
    if (ModeNanber > 5)
    {
      ModeNanber = 0;
    }
    switch (ModeNanber)
    {
    case 0:
      M5.Lcd.print("Automatic ");
      Serial.println("Automatic");
      //            宛先IP   SEOJ        DEOJ           ESV    EPC    EDT
      echo.sendOPC1(toip, controller, airconditioner, EL_SETI, 0xB0, {0x41}); // 0X41が自動を意味する
      break;

    case 1:
      M5.Lcd.print("Cooling ");
      Serial.println("Cooling");
      //            宛先IP   SEOJ        DEOJ           ESV    EPC    EDT
      echo.sendOPC1(toip, controller, airconditioner, EL_SETI, 0xB0, {0x42}); // 0x42が冷房を意味する
      break;

    case 2:
      M5.Lcd.print("Heating ");
      Serial.println("Heating");
      //            宛先IP   SEOJ        DEOJ           ESV    EPC    EDT
      echo.sendOPC1(toip, controller, airconditioner, EL_SETI, 0xB0, {0x43}); // 0x43が暖房を意味する
      break;

    case 3:
      M5.Lcd.print("Dehumidification ");
      Serial.println("Dehumidification");
      //            宛先IP   SEOJ        DEOJ           ESV    EPC    EDT
      echo.sendOPC1(toip, controller, airconditioner, EL_SETI, 0xB0, {0x44}); // 0X44が除湿を意味する
      break;

    case 4:
      M5.Lcd.print("Air circulation ");
      Serial.println("Air circulation");
      //            宛先IP   SEOJ        DEOJ           ESV    EPC    EDT
      echo.sendOPC1(toip, controller, airconditioner, EL_SETI, 0xB0, {0x45}); // 0x45が送風を意味する
      break;

    case 5:
      M5.Lcd.print("Other ");
      Serial.println("Other");
      //            宛先IP   SEOJ        DEOJ           ESV    EPC    EDT
      echo.sendOPC1(toip, controller, airconditioner, EL_SETI, 0xB0, {0x40}); // 0x40がその他を意味する
      break;

    default:
      break;
    }
  }

  if (M5.BtnC.wasPressed())
  {
    M5.Lcd.setTextSize(2);
    M5.Lcd.setTextColor(BLUE, BLACK);
    M5.Lcd.print("OFF");
    Serial.println("OFF");
    //            宛先IP   SEOJ        DEOJ           ESV    EPC    EDT
    echo.sendOPC1(toip, controller, airconditioner, EL_SETI, 0x80, {0x31}); // 0x31が電源をOFFを意味する
  }

  echo.recvProcess();
  delay(10);
}

 ```