ESP8266お風呂スイッチを、ラズパイ経由でNode-RED化

https://qiita.com/ABK28/items/0681be13afca40687dff
で作った、お風呂スイッチですが、fauxmoESPがalexaで応答しなくなりました。
とても困って、espalexaに置き換えてみたり、いろいろやってみたんですが、直りません。
そこで、思い切って、ラズパイを購入し、Node-REDを使って、Node-REDスキル経由でAlexaに接続することにしました。

##ラズパイの構築
前記事のこれ↓です。
https://qiita.com/ABK28/items/d4d4b766fef03d50027b

##Node-REDのインストール
VNCでつないだラズパイの画面でNode-REDをインストールしました。

[ラズベリーメニュー]->[設定]->[Recommended Software]
![スクリーンショット 2020-12-01 19.32.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/e731eee9-6b74-5425-edf7-90e555baead2.png)

[Programming]の中の[Node-RED]にチェックしてインストールしました。
ちょっと時間かかります。
![スクリーンショット 2020-12-01 19.32.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/ae3872ab-2a75-aea3-873b-10035db156f9.png)

[ラズベリーメニュー]->[プログラミング]->[Node-RED]で、起動します。
![スクリーンショット 2020-12-01 19.37.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/8a22e4d3-f665-ff92-fbf8-bcee41a642c0.png)

コンソール画面が出てきます。
![nodered-sc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/06e169c2-cd87-7f71-2064-f12714833119.png)


下記コマンドで、自動実行するようにしておきます。

```
$ sudo su
```

```
# systemctl enable nodered.service
```

これで、Node-REDが使える状態になりました。

ラズパイは、mDNS化していますので、パソコンのブラウザから下記で、接続できます。
http://raspberrypi.local:1880/


##Node-RED Alexa Home Skill Bridge に登録
下記にアクセスして、デバイスを作ります。
https://alexa-node-red.bm.hardill.me.uk/

[Register]を押して、アカウントを登録します。
![スクリーンショット 2020-12-01 19.49.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/400e11ec-41cf-ef1d-cb1d-d147be752b39.png)

ログインしたら、
[Devices]タブを押して、デバイスを登録します。
![スクリーンショット 2020-12-01 19.52.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/de432638-885f-488a-4dd8-cda252c42732.png)

これだけでOK。

##Alexaスキル「Node-RED」の登録
スマホのAlexaアプリのスキルメニューで、「Node-RED」を登録します。
「有効」にすると、ログイン画面が出ますので、「Node-RED Alexa Home Skill Bridge」で登録したアカウントでログインします。
![IMG_9778.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/f7fa5d26-4cee-ccdd-3d94-d06b4af265cc.png)

デバイスの検索で、「お風呂」をみつけます。
あ、さきに、前に登録した動かないデバイスは消しておきます。

これだけでOK。

##Node-REDのフローの作成
先ず、Alexaのノードを使えるようにします。
右上のメニューから「パレットの管理」を選びます。
![スクリーンショット 2020-12-01 20.01.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/497406a2-05f8-609f-a31d-f4ae86ed734b.png)

「alexa」とかいれて検索し、「node-red-contrib-alexa-home-skill」を追加します。
![スクリーンショット 2020-12-01 20.17.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/b5604d24-3686-ad71-1a19-a0daaae2f7cc.png)

下記スクショのようなフローを作ります。
![node-red_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/555be459-4e5f-58d3-2e5e-fa215e3b1473.png)

一番左のノードは、上記でAlexaを追加したことにより、選択できるノードです。
ダブルクリックすると編集画面になるので、
「アカウント」に「Node-RED Alexa Home Skill Bridge」で登録したアカウントを設定します。
名前は、「お風呂」にしました。
![node-red_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/4ce44508-407d-019b-aad9-d87144ec053a.png)

ESP8266で作っていたお風呂スイッチのスケッチでは、WEB画面で操作できるようになっていましたので、これをHTTPリクエストで呼ぶことでスイッチのON/OFFをします。
そのURLをここに書き込みます。
![node-red_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/6e507207-a87d-7b75-bb5f-dd640a78ed3b.png)

できたら「デプロイ」します。

Node-REDのフローは、これだけで完成です。
びっくりするくらい簡単です。

##使ってみる。
「アレクサ！　お風呂をつけて！」

動いたー。


##おまけでスケッチのシンプル化
使わなくなった、fauxmoESPのコードを削除して、改めてESP8266に書き込んでおきました。

```
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <Servo.h>
#include <ESP8266HTTPClient.h>
#include <DNSServer.h>
#include <WiFiManager.h>
#include <ESP8266mDNS.h>
#include <WiFiClient.h>

#define SERIAL_SPEED 115200

// mDNS
static const char* mdns_name = "ofro-sw";

// Servo
Servo servo; 
const int servoIni = 90;
const int servoOn = 120;
int flag = 0;
int deg;

// Pin No
const int ServoPin = 12;
const int GreenLEDPin = 13;
const int BlueLEDPin = 15;

// Web page (Port 8080)
ESP8266WebServer server(8080);
static const char* cpResponse200 = "<HTML>"
 "<BODY style='background-color:#ffffde;font-family:sans-serif;font-size:40px;'>"
 "OFRO-SW WEB<br/><br/>"
 "<a href=/cmd?POS=zero>Zero Position</a><br/>"
 "<a href=/cmd?POS=push>Push!</a><br/>"
 "<a href=/cmd?POS=PLUS10>PLUS 10</a><br/>"
 "<a href=/cmd?POS=MINUS10>MINUS 10</a><br/>"
 "<br/>"
 "<a href=/cmd?POS=reset>Reset WiFi Setting.</a><br/>"
 "</BODY></HTML>\r\n";

 
void setup() {
  Serial.begin(SERIAL_SPEED);
  Serial.println("");
  
  // LED
  pinMode(GreenLEDPin, OUTPUT);
  pinMode(BlueLEDPin, OUTPUT);
  digitalWrite(GreenLEDPin, LOW);
  digitalWrite(BlueLEDPin, LOW);
  
  // WiFi
  //WiFiManager
  WiFiManager wifiManager;
  digitalWrite(BlueLEDPin, HIGH);
  wifiManager.setBreakAfterConfig(true);
  if (!wifiManager.autoConnect("Auto Connect AP", "password")) {
    Serial.println("failed to connect, we should reset as see if it connects");
    delay(3000);
    digitalWrite(BlueLEDPin, LOW);
    ESP.reset();
    delay(5000);
  }

  digitalWrite(BlueLEDPin, LOW);
  Serial.println("");
  Serial.println("WiFi Connected.");
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.println("");
  Serial.println("");
  digitalWrite(GreenLEDPin, HIGH);

  // Set up mDNS responder:
  if (!MDNS.begin(mdns_name)) {
    Serial.println("Error setting up MDNS responder!");
    while (1) {
      delay(1000);
    }
  }
  Serial.println("mDNS responder started");
  Serial.println("");

  // WebServer
  server.on("/cmd", WebCommand);
  server.begin();
  Serial.println("Web Server started");
  Serial.println("0:deg=" +String(deg) );
  deg=servoIni; //スタート位置
  servo.write(deg);
  Serial.println("1:deg=" +String(deg) );

  // Add service to MDNS-SD
  MDNS.addService("http", "tcp", 8080);

}

void WebCommand() {
  String cmd = server.arg("POS");
  if (cmd == "zero")  { deg=0; servomove(deg); }
  else if (cmd == "push") livingOn();
  else if (cmd == "PLUS10") { if ((deg+=10)>180) deg=180; servomove(deg);}
  else if (cmd == "MINUS10") { if ((deg-=10)<0) deg=0; servomove(deg);}
  else if (cmd == "reset")  {
    WiFiManager wifiManager;
    digitalWrite(GreenLEDPin, LOW);
    digitalWrite(BlueLEDPin, LOW);
    delay(1000);
    Serial.println("");
    Serial.println("WiFi Reset !");
    Serial.println("");
    for(int i=0;i<3;i++) {
      digitalWrite(BlueLEDPin, HIGH);
      delay(250);
      digitalWrite(BlueLEDPin, LOW);
      delay(250);
    }
    wifiManager.resetSettings();
    delay(3000);
    digitalWrite(BlueLEDPin, HIGH);
    delay(250);
    digitalWrite(BlueLEDPin, LOW);
    ESP.reset();
  }
  Serial.print("deg=" +String(deg) );
  Serial.println("  cmd=" + cmd);
  server.send(200, "text/html", cpResponse200);
}

void loop() {
  MDNS.update();
  server.handleClient();
  delay(1);
}
 
void livingOn() {
  digitalWrite(BlueLEDPin, HIGH);
  servo.attach(ServoPin);
  delay(300);
  servo.write(servoOn);
  delay(500);
  servo.write(servoIni);
  delay(300);
  servo.detach();
  digitalWrite(BlueLEDPin, LOW);
  Serial.println("Switch turn on ...");
}
 
void livingOff() {
  digitalWrite(BlueLEDPin, HIGH);
  servo.attach(ServoPin);
  delay(300);
  servo.write(servoOn);
  delay(500);
  servo.write(servoIni);
  delay(300);
  servo.detach();
  digitalWrite(BlueLEDPin, LOW);
  Serial.println("Switch turn off ...");
}

void servomove(int d) {
  digitalWrite(BlueLEDPin, HIGH);
  servo.attach(ServoPin);
  servo.write(d);
  delay(100);
  servo.detach();
  digitalWrite(BlueLEDPin, LOW);
}

String ipToString(uint32_t ip){
    String result = "";
    result += String((ip & 0xFF), 10);
    result += ".";
    result += String((ip & 0xFF00) >> 8, 10);
    result += ".";
    result += String((ip & 0xFF0000) >> 16, 10);
    result += ".";
    result += String((ip & 0xFF000000) >> 24, 10);
    return result;
}

```

##おしまい。
めでたしめでたし。