ArduinoとIRLEDで自宅のエアコンを支配下に置く

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

##エアコンの赤外線リモコンを解析する。
前回同様エアコンのリモコンを解析しよう。そうしよう。
（この時、苦労することなんて知るよしもなかった......）

###機材
* ~~Arduino uno R3~~  <- WiFiモジュールの回路めんどくさくて[ESPDuino-32](https://www.amazon.co.jp/gp/product/B074PNFJGF/ref=ppx_yo_dt_b_asin_title_o08_s00?ie=UTF8&psc=1)に変更した
(機材変更のためpinの設定が変わるがここでは省略)
* 赤外線リモコン受信モジュール
* Panasonic Eolia リモコン

###回路
前回同様の回路を使用する。
![IRreceiver.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556423/823262b1-505b-5a9b-2db2-466ba918a849.jpeg)

###ソースコード
前回同様[IRremote](https://github.com/z3t0/Arduino-IRremote)のSampleCode（IRrecvDumpV2）を用いて解析しようと思う。 

```c++:IRrecvDumpV2.ino
//------------------------------------------------------------------------------
// Include the IRremote library header
//
#include <IRremote.h>

//------------------------------------------------------------------------------
// Tell IRremote which Arduino pin is connected to the IR Receiver (TSOP4838)
//
int recvPin = 11;
IRrecv irrecv(recvPin);

//+=============================================================================
// Configure the Arduino
//
void  setup ( )
{
  Serial.begin(9600);   // Status message will be sent to PC at 9600 baud
  irrecv.enableIRIn();  // Start the receiver
}

//+=============================================================================
// Display IR code
//
void  ircode (decode_results *results)
{
  // Panasonic has an Address
  if (results->decode_type == PANASONIC) {
    Serial.print(results->address, HEX);
    Serial.print(":");
  }

  // Print Code
  Serial.print(results->value, HEX);
}

//+=============================================================================
// Display encoding type
//
void  encoding (decode_results *results)
{
  switch (results->decode_type) {
    default:
    case UNKNOWN:      Serial.print("UNKNOWN");       break ;
    case NEC:          Serial.print("NEC");           break ;
    case SONY:         Serial.print("SONY");          break ;
    case RC5:          Serial.print("RC5");           break ;
    case RC6:          Serial.print("RC6");           break ;
    case DISH:         Serial.print("DISH");          break ;
    case SHARP:        Serial.print("SHARP");         break ;
    case JVC:          Serial.print("JVC");           break ;
    case SANYO:        Serial.print("SANYO");         break ;
    case MITSUBISHI:   Serial.print("MITSUBISHI");    break ;
    case SAMSUNG:      Serial.print("SAMSUNG");       break ;
    case LG:           Serial.print("LG");            break ;
    case WHYNTER:      Serial.print("WHYNTER");       break ;
    case AIWA_RC_T501: Serial.print("AIWA_RC_T501");  break ;
    case PANASONIC:    Serial.print("PANASONIC");     break ;
    case DENON:        Serial.print("Denon");         break ;
  }
}

//+=============================================================================
// Dump out the decode_results structure.
//
void  dumpInfo (decode_results *results)
{
  // Check if the buffer overflowed
  if (results->overflow) {
    Serial.println("IR code too long. Edit IRremoteInt.h and increase RAWBUF");
    return;
  }

  // Show Encoding standard
  Serial.print("Encoding  : ");
  encoding(results);
  Serial.println("");

  // Show Code & length
  Serial.print("Code      : ");
  ircode(results);
  Serial.print(" (");
  Serial.print(results->bits, DEC);
  Serial.println(" bits)");
}

//+=============================================================================
// Dump out the decode_results structure.
//
void  dumpRaw (decode_results *results)
{
  // Print Raw data
  Serial.print("Timing[");
  Serial.print(results->rawlen-1, DEC);
  Serial.println("]: ");

  for (int i = 1;  i < results->rawlen;  i++) {
    unsigned long  x = results->rawbuf[i] * USECPERTICK;
    if (!(i & 1)) {  // even
      Serial.print("-");
      if (x < 1000)  Serial.print(" ") ;
      if (x < 100)   Serial.print(" ") ;
      Serial.print(x, DEC);
    } else {  // odd
      Serial.print("     ");
      Serial.print("+");
      if (x < 1000)  Serial.print(" ") ;
      if (x < 100)   Serial.print(" ") ;
      Serial.print(x, DEC);
      if (i < results->rawlen-1) Serial.print(", "); //',' not needed for last one
    }
    if (!(i % 8))  Serial.println("");
  }
  Serial.println("");                    // Newline
}

//+=============================================================================
// Dump out the decode_results structure.
//
void  dumpCode (decode_results *results)
{
  // Start declaration
  Serial.print("unsigned int  ");          // variable type
  Serial.print("rawData[");                // array name
  Serial.print(results->rawlen - 1, DEC);  // array size
  Serial.print("] = {");                   // Start declaration

  // Dump data
  for (int i = 1;  i < results->rawlen;  i++) {
    Serial.print(results->rawbuf[i] * USECPERTICK, DEC);
    if ( i < results->rawlen-1 ) Serial.print(","); // ',' not needed on last one
    if (!(i & 1))  Serial.print(" ");
  }

  // End declaration
  Serial.print("};");  // 

  // Comment
  Serial.print("  // ");
  encoding(results);
  Serial.print(" ");
  ircode(results);

  // Newline
  Serial.println("");

  // Now dump "known" codes
  if (results->decode_type != UNKNOWN) {

    // Some protocols have an address
    if (results->decode_type == PANASONIC) {
      Serial.print("unsigned int  addr = 0x");
      Serial.print(results->address, HEX);
      Serial.println(";");
    }

    // All protocols have data
    Serial.print("unsigned int  data = 0x");
    Serial.print(results->value, HEX);
    Serial.println(";");
  }
}

//+=============================================================================
// The repeating section of the code
//
void  loop ( )
{
  decode_results  results;        // Somewhere to store the results

  if (irrecv.decode(&results)) {  // Grab an IR code
    dumpInfo(&results);           // Output the results
    dumpRaw(&results);            // Output the results in RAW format
    dumpCode(&results);           // Output the results as source code
    Serial.println("");           // Blank line between entries
    irrecv.resume();              // Prepare for the next value
  }
}
```
###結果
```
IR code too long. Edit IRremoteInt.h and increase RAWBUF
Timing[100]: 
     +3450, -1700     + 450, - 400     + 450, -1250     + 500, - 400
     + 450, - 400     + 450, - 400     + 500, - 350     + 500, - 400
     + 450, - 400     + 450, - 400     + 450, - 400     + 500, - 400
     + 450, - 400     + 450, - 400     + 500, -1250     + 450, - 400
     + 450, - 400     + 450, - 450     + 450, - 400     + 450, - 400
     + 450, - 400     + 500, - 400     + 450, -1250     + 450, -1300
     + 450, -1250     + 450, - 400     + 500, - 400     + 450, -1250
     + 450, - 400     + 500, - 400     + 450, - 400     + 450, - 400
     + 450, - 400     + 500, - 400     + 450, - 400     + 450, - 400
     + 450, - 400     + 500, - 400     + 450, - 400     + 450, - 400
     + 450, - 400     + 500, - 400     + 450, - 400     + 450, - 400
     + 450, - 400     + 500, - 400     + 450, - 400     + 450, - 400
     + 450, - 400     + 500, - 400
unsigned int  rawData[100] = {3450,1700, 450,400, 450,1250, 500,400, 450,400, 
 450,400, 500,350, 500,400, 450,400, 450,400, 450,400, 500,400, 450,400, 450,400, 
 500,1250, 450,400, 450,400, 450,450, 450,400, 450,400, 450,400, 500,400, 
 450,1250, 450,1300, 450,1250, 450,400, 500,400, 450,1250, 450,400, 500,400, 
 450,400, 450,400, 450,400, 500,400, 450,400, 450,400, 450,400, 500,400, 450,400, 
 450,400, 450,400, 500,400, 450,400, 450,400, 450,400, 500,400, 450,400, 450,400, 
 450,400, 500,400 };  // UNKNOWN 68D13F41
```
？？？？？？？？？？？？？？？？
さっぱりわからん物が出てきた。
上の英語を読む限り赤外線で送られた情報が長すぎて解析できないような模様。
IRremoteInt.hを編集してRAWBUFを増やせ！！って行ってますね。

```c++: 
#define RAWBUF  101 // Maximum length of raw duration buffer
```
こんなんになってたのでこうしてやった。

```c++:
#define RAWBUF  256 // Maximum length of raw duration buffer
```
コレで受け取れるだろう...多分......

```
Encoding  : UNKNOWN
Code      : 9DCF5C22 (32 bits)
Timing[131]: 
     +3450, -1750     + 400, - 450     + 400, -1300     + 450, - 450
     + 400, - 450     + 400, - 450     + 450, - 450     + 400, - 450
     + 400, - 450     + 400, - 450     + 450, - 450     + 400, - 450
     + 400, - 450     + 400, - 450     + 450, -1300     + 400, - 450
     + 400, - 450     + 450, - 450     + 400, - 450     + 400, - 450
     + 400, - 500     + 400, - 450     + 400, -1300     + 450, -1300
     + 400, -1300     + 450, - 450     + 400, - 450     + 400, -1300
     + 450, - 450     + 400, - 450     + 400, - 450     + 400, - 500
     + 400, - 450     + 400, - 450     + 400, - 450     + 450, - 450
     + 400, - 450     + 400, - 450     + 400, - 450     + 450, - 450
     + 400, - 450     + 400, - 450     + 400, - 450     + 450, - 450
     + 400, - 450     + 400, - 450     + 400, - 450     + 450, - 450
     + 400, - 450     + 400, - 450     + 400, - 500     + 400, - 450
     + 400, - 450     + 400, - 450     + 450, - 450     + 400, - 450
     + 400, - 450     + 400, - 450     + 450, -1300     + 400, -1300
     + 450, - 450     + 400, - 450     + 400, - 450     + 400, - 500
     + 400, - 450     + 400
unsigned int  rawData[131] = {3450,1750, 400,450, 400,1300, 450,450, 400,450,
 400,450, 450,450, 400,450, 400,450, 400,450, 450,450, 400,450, 400,450, 400,450,  
 450,1300, 400,450, 400,450, 450,450, 400,450, 400,450, 400,500, 400,450, 
 400,1300,  450,1300, 400,1300, 450,450, 400,450, 400,1300, 450,450, 400,450, 
 400,450,  400,500, 400,450, 400,450, 400,450, 450,450, 400,450, 400,450, 400,450, 
 450,450, 400,450, 400,450, 400,450, 450,450, 400,450, 400,450, 400,450, 450,450, 
 400,450, 400,450, 400,500, 400,450, 400,450, 400,450, 450,450, 400,450, 400,450, 
 400,450, 450,1300, 400,1300, 450,450, 400,450, 400,450, 400,500, 400,450, 400};  
 // UNKNOWN 9DCF5C22
```
んーー、結局わからんかった......
いろいろ調べてみるとコレでも全部は受け取れてないっぽい.....
ただ最大値256にしたのに１３１しか受け取れてないってのもわからんが赤外線のこととかこのライブラリにもそれほど詳しくないのでわかりませんでした。

###対策

新たな自分では一からコーディングできそうにもない（えー、ぶっちゃけ勉強するのめんどいし）ライブラリを探してgithubへ......。

##Panasonic製エアコンをArduinoの支配下に置く

ここでいいライブラリを発見！！
[ToniAさんのarduino-heatpumpir](https://github.com/ToniA/arduino-heatpumpir)
どうやらMitsubishi,Toshiba,Panasonicなどのエアコンの赤外線を送れる模様。
早速使ってみる。

###機材
*　Arduino uno R3
*　IRLED
*　タクトスイッチ×３
*　抵抗１００Ω

###回路

環境とかモジュールによって回路はことなるので自分で調べてね。

![IRsendAC.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556423/5a613c92-7eaf-ab0c-5a6c-fc372a4d6d87.jpeg)


###ソースコード

```c++:ACController.ino
#include <Arduino.h>
#include <PanasonicHeatpumpIR.h>

#define cool_button 7
#define hot_button 4
#define stop_button 2

void setup(){
  // setting button pin mode  
    pinMode(cool_button,INPUT);
    pinMode(hot_button,INPUT);
    pinMode(stop_button,INPUT);

    // Serial begin speed = 115200
    Serial.begin(115200);
}

void loop(){

IRSenderPWM irSender(3); // irSender(IRLEDpinNum);
PanasonicDKEHeatpumpIR *heatpumpIR;

  // read button state 
    unsigned int air_cool_on_status = digitalRead(cool_button);
    unsigned int air_hot_on_status = digitalRead(hot_button);
    unsigned int air_off_status = digitalRead(stop_button);

    // 
    
    if(air_off_status == LOW){ // air conditioner off
        Serial.println("air off");
        heatpumpIR = new PanasonicDKEHeatpumpIR();
        heatpumpIR->send(irSender, POWER_OFF, MODE_COOL, FAN_AUTO, 26, VDIR_AUTO, HDIR_AUTO);
                  //send(irSender,スイッチON,OFF,冷暖房とか除湿,風量,温度,風向（上下）,風向（右左）);
      }else if(air_cool_on_status == LOW){ // air conditioner mode cool
        Serial.println("cool on");
        heatpumpIR = new PanasonicDKEHeatpumpIR();
        heatpumpIR->send(irSender, POWER_ON, MODE_COOL, FAN_AUTO, 26, VDIR_AUTO, HDIR_AUTO);
      }else if(air_hot_on_status == LOW){ // air conditioner mode hot
        Serial.println("hot on");
        heatpumpIR = new PanasonicDKEHeatpumpIR();
        heatpumpIR->send(irSender, POWER_ON, MODE_HEAT, FAN_AUTO, 22, VDIR_AUTO, HDIR_AUTO);
      }

      //delay time between this loop and next loop
    delay(500);
}
```

とりあえず設定に使うやつ書き出しときます。

- POWER (電源) 
    - POWER_ON (on)
    - POWER_OFF (off)
- MODE （モード) 
    - MODE_AUTO (自動) 
    - MODE_COOL　（冷房）
    - MODE_HEAT　（暖房）
    - MODE_DRY　（除湿）
    - MODE_ON　（自分には不明）
    - MODE_OFF　（自分には不明）
- FAN　（風量）
    - FAN1
    - FAN2
    - FAN3
    - FAN4
    - FAN5
    - FAN_AUTO
- VDIR　（風向高さ）
    - VDIR_AUTO
    - VDIR_UP
    - VDIR_MUP
    - VDIR_MIDDLE
    - VDIR_MDOWN
    - VDIR_DOWN
- HDIR　（風向左右）
    - HDIR_AUTO
    - HDIR_LEFT
    - HDIR_MLEFT
    - HDIR_MIDDLE
    - HDIR_MRIGHT
    - HDIR_RIGHT 

多分使えるはず......
###結果
ちゃんと動いた。
解析せずにACを操作できるなんてマジ便利。
温度とか操作するボタンを実装させれば温度を変化できるけど、温度をほとんどいじらない自分には必要ないので実装はしない。

#次回
ESP8266モジュールがと届いたらAndroidからのWebPostで操作を可能にします。