ArduinoをWiFi接続してPostRequestに応じて家電を操作する

#最終目標
Arduinoでシーリングライト・エアコンを支配する。<-前回の続き
Wifiを用いて外部から操作できるようにする。<-機材届いてないのであとで

##謝罪
本当に申し訳ございません。
ESP8266を買ってあったのですが、どうやら電力の問題的に3.3Vから直接電源を取ることが出来ないらしい(自分もその辺はあまり詳しくないのでわからない)
ということで5Vから電源を取る必要がある分けだがとても回路がとてもめんどくさい。
そして、スマートではない。
ということで、Arduino uno R3から[ESPDuino-32](https://www.amazon.co.jp/gp/product/B074PNFJGF/ref=ppx_yo_dt_b_asin_title_o08_s00?ie=UTF8&psc=1)に変えてしまいました。
わかりやすくいうとunoR3のコア部分をESP32にしていてWiFiとBluetoothを使えるようにしてあるやつ（多分

##機材
* [ESPDuino-32](https://www.amazon.co.jp/gp/product/B074PNFJGF/ref=ppx_yo_dt_b_asin_title_o08_s00?ie=UTF8&psc=1)
* タクトスイッチ×３
* 抵抗１００Ω
* IRLED

##回路図
[大体の回路図は前回の回路図と同様](https://qiita.com/SnowDango/items/a699e4afd1fcf37a397c#%E5%9B%9E%E8%B7%AF-1)

###前回からの変更点
* Arduino uno r3からESPDuinoに変更したためピンの番号が変更される
    * 冷房ボタン 7 -> 17
    * 暖房ボタン 4 -> 25
    * 停止ボタン 2 -> 26
    * IRLED 3 -> 13

* シーリングライトのオンオフボタンの設置
    * on     27
    * off    16 

* WiFi接続時の電力量が多いため９V電源での電源供給は不可能

##ソースコード
[github](https://github.com/SnowDango/Arduino_Wifi_IR_Control)

```c++:Arduino_Wifi_IR_Control.ino

#include "WebTextCtl.h" 
#include "IRSendControl.h"
#include "WifiControl.h"

// pin number
#define light_on_button 27
#define light_off_button 16
#define cool_button 17
#define hot_button 25
#define stop_button 26


//実際の開発環境とは異なる
IPAddress ip(192,168,1,50); //自分のIP
IPAddress gateway(192,168,1,1); //gateWayのIP
IPAddress subnet(255,255,255,0); // subnet
IPAddress DNS(192,168,1,1); //dns

// ポート80番を使用
WiFiServer server(80); //ポート設定

void setup() {
  Serial.begin(115200);

  WiFi.config(ip, gateway, subnet, DNS); //config設定

  if(connectWifi()){ //WiFiserverとして起動
    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    server.begin();
  }

  pinMode(light_on_button,INPUT) ;
  pinMode(light_off_button,INPUT) ; 
  pinMode(cool_button,INPUT);
  pinMode(hot_button,INPUT);
  pinMode(stop_button,INPUT);
}

void loop(){
  
  if(WiFi.status() != WL_CONNECTED){ // Wifi切れた時
    Serial.println("Wifi disconnect."); 
    if(connectWifi()){
      Serial.println("");
      Serial.println("WiFi connected.");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
      server.begin();
    }
  }else{
    WiFiClient client = server.available();   // Listen for incoming clients
    if (client) {                    
      Serial.println("New Client.");  
      String currentLine = "";           
      while (client.connected()) {     
        if (client.available()) {      
          char c = client.read();       
          Serial.write(c);
          header += c;
          if (c == '\n') {
            if (currentLine.length() == 0) {
              break;
            } else {
              currentLine = "";
            }
          } else if (c != '\r') {
            currentLine += c;
          }
        }
      }  
      String requestBody = readRequestBody(client);
      String systemStr = getSystem(requestBody);
      String modeStr = getModeSystem(requestBody);
      if(systemStr!="NOT" || modeStr!="NOT"){
        irControl(systemStr,modeStr);//postrequestでのコントロール用
      } 

      client.stop();
    }
  }
  irControl(digitalRead(light_on_button), digitalRead(light_off_button) ,
    digitalRead(cool_button) , digitalRead(hot_button) , digitalRead(stop_button)); //buttonコントロール用
}
```

```c++:WebTextCtl.h

#include <ArduinoJson.h>
#include <WiFi.h>

String getSystem(String body) { //Systemの取り出し
  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& json = jsonBuffer.parseObject(body);
  if (!json.success()) {
    Serial.println("parseObject() failed");
    return "NOT";
  }
  return json["system"];
}

String getModeSystem(String body) { //Modeの取り出し
  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& json = jsonBuffer.parseObject(body);
  if (!json.success()) {
    Serial.println("parseObject() failed");
    return "NOT";
  }
  return json["mode"];
}

String readRequestBody(WiFiClient client) { //Bodyの取得
  int i = 0;
  char * res = (char *) malloc(sizeof(char) * 255);
  while (client.available()) {
    res[i++] = client.read();
  }
  String stringMain = res;
  char t[64];
  int len = stringMain.indexOf("}");
  strncpy( t, res, len + 1);
  String mainBody = t;

  return mainBody;
}

```

```c++:IRsendControl.h

#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <HeatpumpIR.h>
#include <PanasonicHeatpumpIR.h>

const uint16_t send_light_pin = 12;
const uint16_t send_air_pin = 13;

void irControl(String systemStr, String modeStr) {
  if (systemStr == "cellingLight") {
    if (modeStr == "on") {
      Serial.println("CellingLight ON");
      IRsend irsend(send_light_pin);
      irsend.begin();
      irsend.sendNEC(0xE73045BA, 32);
    } else if (modeStr == "off") {
      Serial.println("CellingLight OFF");
      IRsend irsend(send_light_pin);
      irsend.begin();
      irsend.sendNEC(0xE730D12E, 32);
    }
  } else if (systemStr == "airConditionar") {
    if (modeStr == "cool") {
      Serial.println("AirConditinar Cool");
      IRSenderESP32 irSender(send_air_pin, 0);
      PanasonicDKEHeatpumpIR *heatpumpIR;
      heatpumpIR = new PanasonicDKEHeatpumpIR();
      heatpumpIR->send(irSender, POWER_ON, MODE_COOL, FAN_AUTO, 26, VDIR_AUTO, HDIR_AUTO);
    } else if (modeStr == "hot" ) {
      Serial.println("AirConditinar HOT");
      IRSenderESP32 irSender(send_air_pin, 0);
      PanasonicDKEHeatpumpIR *heatpumpIR;
      heatpumpIR = new PanasonicDKEHeatpumpIR();
      heatpumpIR->send(irSender, POWER_ON, MODE_HEAT, FAN_AUTO, 22, VDIR_AUTO, HDIR_AUTO);
    } else if (modeStr == "off") {
      Serial.println("AirConditinar OFF");
      IRSenderESP32 irSender(send_air_pin, 0);
      PanasonicHeatpumpIR *heatpumpIR;
      heatpumpIR = new PanasonicDKEHeatpumpIR();
      heatpumpIR->send(irSender, POWER_OFF, MODE_COOL, FAN_AUTO, 26, VDIR_AUTO, HDIR_AUTO);
    }
  }
}

void irControl(int lightOn, int lightOff, int airCool, int airHot, int airOff) {
  if (lightOff == HIGH) { //　light off
    IRsend irsend(send_light_pin);
    irsend.begin();
    irsend.sendNEC(0xE730D12E, 32);
    Serial.println("light off");
    delay(500);
  } else if (airOff == HIGH) { // air conditioner off
    Serial.println("air off");
    IRSenderESP32 irSender(send_air_pin, 0);
    PanasonicHeatpumpIR *heatpumpIR;
    heatpumpIR = new PanasonicDKEHeatpumpIR();
    heatpumpIR->send(irSender, POWER_OFF, MODE_COOL, FAN_AUTO, 26, VDIR_AUTO, HDIR_AUTO);
    delay(500);
  } else if (lightOff == HIGH) { // light on
    IRsend irsend(send_light_pin);
    irsend.begin();
    irsend.sendNEC(0xE73045BA, 32);
    Serial.println("light on");
    delay(500);
  } else if (airCool == HIGH) { // air conditioner mode cool
    Serial.println("cool on");
    IRSenderESP32 irSender(send_air_pin, 0);
    PanasonicDKEHeatpumpIR *heatpumpIR;
    heatpumpIR = new PanasonicDKEHeatpumpIR();
    heatpumpIR->send(irSender, POWER_ON, MODE_COOL, FAN_AUTO, 26, VDIR_AUTO, HDIR_AUTO);
    delay(500);
  } else if (airHot == HIGH) { // air conditioner mode hot
    Serial.println("hot on");
    IRSenderESP32 irSender(send_air_pin, 0);
    PanasonicDKEHeatpumpIR *heatpumpIR;
    heatpumpIR = new PanasonicDKEHeatpumpIR();
    heatpumpIR->send(irSender, POWER_ON, MODE_HEAT, FAN_AUTO, 22, VDIR_AUTO, HDIR_AUTO);
    delay(500);
  }
}

```

```c++:WifiControl.h

#include <WiFi.h>

//自分の環境に合わせて
const char* ssid     = "ssid";
const char* password = "password";

bool connectWifi(){
    unsigned long startTime = millis();
    bool returnBool = true;

    Serial.print("Connecting to ");
    Serial.println(ssid);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
        if(millis() - startTime > 10000){
          Serial.println();
            returnBool = false;
            break;
        }
    }
    return returnBool;
} 

```


##動作について

自分の設定したIPに向けてBodyがJson型のHttpPostをする。
ex:

* シーリングライトオンの場合
    * {"system" : "cellingLight", "mode" : "on"}

* エアコン冷房起動の場合
    * {"system" : "airConditionar", "mode" : "cool"}

WebTextCtl.hのreadRequestBodyでpostからbodyだけを抽出
getSystemでsystemを抽出、getModeSystemでmodeの抽出
その後IRSendControl.hのいirControlでpost内容に応じて送信する。

##結果
しっかりと動かすことに成功した。
（動画を撮ったがどっかに行ったため見つけ次第アップ）

##改善点
postに対するresponseの仕方がわからないのでわかる方いたら教えてください。
WiFiが不安定（たまに切れるためloopで再接続させてたりしてる）原因は不明。