ESP8266(ESPrDeveloper)＋fauxmoESPとTAMIYAのラダーチェーンでカーテン開閉

##カーテンの開閉
今回は、いよいよ、みんなが１回はやりたくなる？カーテンの開閉です。

前回はSwitchBot風にお風呂のスイッチをサーボで押すのを作りました。
https://qiita.com/ABK28/items/0681be13afca40687dff
基本的にはこのソースをベースにしていますが、前回の課題であった、DHCPで付与された自分のIPアドレスを知るために、Google Home NotiferでIPアドレスを喋らせることにし、mDNSでWEBでもアクセスできるようにしました。(下記参照)。
↓
https://qiita.com/ABK28/items/1672fe26837c364a8de3

カーテンはタミヤのラダーチェーンで引っ張ります。
アイデアは下記から拝借しました。ありがとうございます。
↓
https://cadottie.hatenadiary.org/entry/20110329/1301373783

##使ったもの
・ESPr Developer (Switch Science製)
・モータードライバ（HiLetgo L9110S）（Amazonで購入）
・タミヤ　ミニモーター低速ギヤボックス（yodobashiで購入）
・タミヤ　ラダーチェーン＆スプロケットセットを２セット（yodobashiで購入）
・Arduino IDE
　・ESP8266ライブラリ
　・fauxmoESPライブラリ
　・Google Home Notiferライブラリ
・ダイソーの糸ようじの空箱
・木板（ダイソーで購入）
・プラ版（ダイソーで購入）
・ジャンパー線
・両面テープ（強力で剥がせるやつ。ホームセンターで購入）

##参考URL
前回同様下記を参考にさせていただきました。
https://homemadegarbage.com/espalexa04
https://www.pentacreation.com/blog/2017/08/170822.html
http://okiraku-camera.tokyo/blog/?p=3426

さらに、Google Home Notiferで喋らせる方法
https://qiita.com/horihiro/items/4ab0edf415916a2cd542
https://www.mgo-tec.com/blog-entry-google-home-notifier-m5stack-esp32.html
と、IPアドレスを喋らせるための文字列変換
https://qiita.com/dojyorin/items/ac56a1c2c620782d90a6
のソースを拝借させていただきました。ありがとうございます。

##工作
今回は、こっちが大変かも。

###ギアボックスの組み立て
一番遅いギア比で組み立て。ちょっと遅すぎたかも・・
###ラダーチェーンの組み立て
地道につなぎます・・。
１セットで90cmくらいだったので、２セット使いました。ちょっと足らなかったですが・・。
片端は木板につけます。
###箱に収める・・
ダイソーの糸ようじの空き箱に、まるっと収めます。
材質が柔らかいので、ピンバイスやキリで穴をあけたり、ハサミで切っちゃったり・・・。
また、取り外しを考えてプラ版にビスをつけベースとします。収めた箱と連結できるようにしました。
配線は下記の通りにしました。
・ESPrDeveloperの04ピン ＝モータドライバのA-1Aピン
・ESPrDeveloperの05ピン ＝モータドライバのA-1Bピン
・モータドライバのVCCピン＝ESP8266の3V3ピン
・モータドライバのGNDピン＝ESP8266のGNDピン
・モータドライバAのプラスマイナス＝モータのプラスマイナス
###カーテンへの取り付け
・場所を考えて、ベース（プラ版）と片端木版の裏に両面テープをつけてカーテンレールに取り付けます。
・チェーンをつけます。

##アレクサに登録
前述のお風呂スイッチの投稿を参照ください・・。

##使い方
オンオフスイッチ型なんで、少し変ですが、下記のようになります。
「アレクサ！、カーテンをオン！」
「アレクサ！、カーテンをオフ！」
又は、
curtain-web.local:8080/cmd
で・・

##ソース
```
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <fauxmoESP.h>
#include <esp8266-google-home-notifier.h>

#define SERIAL_SPEED 115200

// Pin No
const int MotorFwdPin = 4;
const int MotorRevPin = 5;

// WiFi
const char* ssid="あなたのSSID";
const char* password="あなたのパスフレーズ";

// Google Home
GoogleHomeNotifier ghn;
const char displayName[] = "あなたのデバイスネーム";
String mes;

// Alexa
fauxmoESP fauxmo;
int CurtainFlag = 0;
#define ID_sw "カーテン"

// Web page (Port 8080)
ESP8266WebServer server(8080);
static const char* cpResponse200 = "<HTML>"
 "<BODY style='background-color:#ffffde;font-family:sans-serif;font-size:32px;'>"
 "Curtain Control Web<br/><br/><br/>"
 "<a href=/cmd?POS=stop>Stop</a><br/>"
 "<a href=/cmd?POS=fwd_always>Forword Always</a><br/>"
 "<a href=/cmd?POS=rev_always>Reverse Always</a><br/>"
 "<a href=/cmd?POS=fwd_10>Forword 10 sec.</a><br/>"
 "<a href=/cmd?POS=rev_10>Reverse 10 sec.</a><br/>"
 "<a href=/cmd?POS=fwd_1>Forword 1 sec.</a><br/>"
 "<a href=/cmd?POS=rev_1>Reverse 1 sec.</a><br/>"
 "</BODY></HTML>\r\n";


void setup() {
  Serial.begin(SERIAL_SPEED);
  Serial.println("");
  // Motor
  pinMode(MotorFwdPin, OUTPUT);
  pinMode(MotorRevPin, OUTPUT);
  digitalWrite(MotorFwdPin, LOW);
  digitalWrite(MotorRevPin, LOW);
  // WiFi
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid,password);
  while(WiFi.status() != WL_CONNECTED){
    delay(300);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println(WiFi.localIP());
  // Google Home Notifer
  mes = "カーテンマシンのIPアドレスは、";
  mes += ipToString(WiFi.localIP());
  mes += "です。";
  googleHomeConnection( "ja", mes.c_str() );
  // mDNS
  if (!MDNS.begin("curtain-web")) {
    Serial.println("Error setting up MDNS responder!");
    while (1) {
      delay(1000);
    }
  }
  Serial.println("mDNS responder started");
  // WebServer
  server.on("/cmd", WebCommand);
  server.begin();
  Serial.println("Web Server started");
  // Add service to MDNS-SD
  MDNS.addService("http", "tcp", 8080);
  // Alexa
  fauxmo.createServer(true);
  fauxmo.setPort(80);
  fauxmo.enable(true);
  fauxmo.addDevice(ID_sw); // Add virtual devices
  fauxmo.onSetState([](unsigned char device_id, const char * device_name, bool state, unsigned char value) {
    Serial.printf("[MAIN] Device #%d (%s) state: %s value: %d\n", device_id, device_name, state ? "ON" : "OFF", value);
    if (strcmp(device_name, ID_sw)==0) {
      if (state) CurtainFlag = 1;
      else CurtainFlag = 2;
    }
  });
}

void WebCommand() {
  String cmd = server.arg("POS");
  if (cmd == "stop")  MotorOff();
  else if (cmd == "fwd_10") MotorFwd(10000);
  else if (cmd == "rev_10") MotorRev(10000);
  else if (cmd == "fwd_1") MotorFwd(1000);
  else if (cmd == "rev_1") MotorRev(1000);
  else if (cmd == "fwd_always") MotorFwd(0);
  else if (cmd == "rev_always") MotorRev(0);
  Serial.println("cmd=" + cmd);
  server.send(200, "text/html", cpResponse200);
}

void loop() {
  // fauxmoESP uses an async TCP server but a sync UDP server
  // Therefore, we have to manually poll for UDP packets
  MDNS.update();
  server.handleClient();
  fauxmo.handle(); 
  if (CurtainFlag==1) { MotorFwd(60000); CurtainFlag=0; }
  else if (CurtainFlag==2) { MotorRev(60000); CurtainFlag=0; }
}
 
void MotorFwd(int d) {
  Serial.println("FWD Start " + String(d) );
  digitalWrite(MotorRevPin, LOW);
  digitalWrite(MotorFwdPin, HIGH);
  if (d>0) { // if d<=0 then always ON !
    delay(d);
    digitalWrite(MotorFwdPin, LOW);
  }
}

void MotorRev(int d) {
  Serial.println("REV Start " + String(d) );
  digitalWrite(MotorFwdPin, LOW);
  digitalWrite(MotorRevPin, HIGH);
  if (d>0) {
    delay(d);
    digitalWrite(MotorRevPin, LOW);
  }
}

void MotorOff() {
  Serial.println("Moter Off ");
  digitalWrite(MotorFwdPin, LOW);
  digitalWrite(MotorRevPin, 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;
}

void googleHomeConnection( String lang_str1, String talk_str1 ){
  Serial.println("connecting to Google Home...");
  if (ghn.device( displayName, lang_str1.c_str() ) != true) {
    Serial.println(ghn.getLastError());
    return;
  }
  Serial.print("found Google Home(");
  Serial.print(ghn.getIPAddress());
  Serial.print(":");
  Serial.print(ghn.getPort());
  Serial.println(")");
 
  if (ghn.notify( talk_str1.c_str() ) != true) {
    Serial.println(ghn.getLastError());
    return;
  }
  Serial.println("");
}
```

##参考写真
↓モータドライバ
![IMG_7380.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/c5744143-b983-6f9c-9055-724f1f13edd8.jpeg)

↓ミニモータ低速ギヤボックス
![IMG_7381.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/3a7cb13b-3d6e-d61b-d710-0dd841688077.jpeg)

↓ラダーチェーンの片端部分
![IMG_7387.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/f52fbcfa-d9aa-1a5a-752b-a43c1f37065e.jpeg)

↓操作画面
<img width="560" alt="web.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/d1e34066-e9ca-4abc-40f1-e5edd73ef4f7.png">