fauxmoESP で スマートホームデバイス自作
ずいぶん長いことAmazon Echoを愛用させていただき、esp8266-alexa-wemo-emulator ライブラリで自作のAlexa連携デバイスも使用してきました。
What an IoT!!#AmazonEcho #Alexa #ESP8266 #messy pic.twitter.com/STYYOVFgst
— HomeMadeGarbage (@H0meMadeGarbage) October 5, 2018
ご覧のようにテレビやリビング照明や電気スタンドを声でコントロールして家族みんなで便利に使ってきておりました。
しかし急に機能しなくなったのです。。。alexa-wemo-emulatorライブラリはもう何年も更新されておらず、使用できないとの噂もチラホラ入ってきており遂に来たか。。という感じでございました。
もうすでにAmazon Echoによるテレビや電気のコントロールは生活に浸透しており、無いと成り立たない状況です。
そこで以下の記事を参考にさせていただき、fauxmoESPというライブラリへの移行を実施いたしました。
目次
fauxmoESPライブラリ
今回採用するfauxmoESPはalexa-wemo-emulatorライブラリと同様にWiFi搭載マイコンのESP8266やESP32を疑似的にAlexa対応ホームデバイスにしてくれるライブラリです。本当にありがたいライブラリでございます。感謝
Arduino用ライブラリは以下よりダウンロードできます。
https://bitbucket.org/xoseperez/fauxmoesp/src/master/
ダウンロードしたzipファイルを所定のArduinoライブラリフォルダに展開します。
2019/9/10現在の最新のライブラリバージョンは3.1.0でした。
今回はESP8266を使用しますので以下のライブラリも追加します。
https://github.com/me-no-dev/ESPAsyncTCP
壁スイッチ ON/OFF
まずはリビングの照明をON/OFFするスイッチをfauxmoESPに変更します。
構成
Amazon EchoでデバイスをON/OFFしてサーボモータを動かして壁スイッチを押します。安物のESP8266ボードを使用しています。
部品
- サーボモータ SG90
- WiFi搭載マイコン HiLetgo ESP8266
Arduinoコード
サンプルコード fauxmoESP_Basic.ino を参考にコード作成しました。
ESP8266のArduino用パッケージはESP8266 Community ver. 2.5.2を使用しています。安物ESP8266ボードの設定は以下のとおりです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
#include <Arduino.h> #include <ESP8266WiFi.h> #include "fauxmoESP.h" #include <Servo.h> Servo myservo; int servoIni = 90; int servoOn = 55; int servoState = 0; int flag = 0; #define WIFI_SSID "〇〇〇〇〇〇" #define WIFI_PASS "□□□□□□" fauxmoESP fauxmo; // ----------------------------------------------------------------------------- #define SERIAL_BAUDRATE 115200 #define ID "リビング" // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // Wifi // ----------------------------------------------------------------------------- void wifiSetup() { // Set WIFI module to STA mode WiFi.mode(WIFI_STA); // Connect Serial.printf("[WIFI] Connecting to %s ", WIFI_SSID); WiFi.begin(WIFI_SSID, WIFI_PASS); // Wait while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(100); } Serial.println(); // Connected! Serial.printf("[WIFI] STATION Mode, SSID: %s, IP address: %s\n", WiFi.SSID().c_str(), WiFi.localIP().toString().c_str()); } void setup() { // Init serial port and clean garbage Serial.begin(SERIAL_BAUDRATE); Serial.println(); Serial.println(); // Wifi wifiSetup(); // By default, fauxmoESP creates it's own webserver on the defined port // The TCP port must be 80 for gen3 devices (default is 1901) // This has to be done before the call to enable() fauxmo.createServer(true); // not needed, this is the default value fauxmo.setPort(80); // This is required for gen3 devices // You have to call enable(true) once you have a WiFi connection // You can enable or disable the library at any moment // Disabling it will prevent the devices from being discovered and switched fauxmo.enable(true); // Add virtual devices fauxmo.addDevice(ID); 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); // Checking for device_id is simpler if you are certain about the order they are loaded and it does not change. // Otherwise comparing the device_name is safer. if (strcmp(device_name, ID)==0) { if(state){ flag = 1; }else{ flag = 2; } } }); } void loop() { // fauxmoESP uses an async TCP server but a sync UDP server // Therefore, we have to manually poll for UDP packets fauxmo.handle(); if(flag == 1){ livingOn(); flag = 0; }else if(flag == 2){ livingOff(); flag = 0; } } void livingOn() { myservo.attach(D8); delay(1000); myservo.write(servoOn); delay(1000); myservo.write(servoIni); delay(1000); myservo.detach(); Serial.print("Switch turn on ..."); } void livingOff() { myservo.attach(D8); delay(1000); myservo.write(servoOn); delay(1000); myservo.write(servoIni); delay(1000); myservo.detach(); Serial.print("Switch turn off ..."); } |
デバイス名を”リビング”としAmazon Echoで「リビングつけて」、「リビング消して」と発話してonSetState()コールバックでstateとして状態変化を検出します。
onSetState()コールバックではGPIOピンのHigh/Low設定などの簡単なことしかできないので、ここではstateの変化を変数flagで検出してloop()内でサーボを動かしています。
ちなみに「リビングを30にて」などと数字と共に発話するとonSetState()コールバックのvalueで受信されます。
発話の数字:0~100 [%] → Value:8bit値 0~255 に変換されます。
照明やLEDの調光に使えそうですね。
Alexaアプリ設定
スマホのAlexaアプリで”リビング”デバイスをホームデバイスとして追加します。
- アプリの”デバイス”をクリック
- ⊕をクリック
- “デバイス追加”をクリック
- “その他”をクリック
- “デバイスを検出”をクリック
しばらく待つと
“リビング”がホームデバイスとして検出されます。
動作
fauxmoESPに変更しました。#Alexa #ESP8266 pic.twitter.com/njXwHr5WUk
— HomeMadeGarbage (@H0meMadeGarbage) September 9, 2019
よし!なおった!
おわりに
テレビと電気スタンドも同様にfauxmoESPライブラリに移行しました。
無事にAmazon Echoによる家電制御生活に戻れてよかったです 🙂
No Alexa, No life#金魚 pic.twitter.com/8kBgUCjziM
— HomeMadeGarbage (@H0meMadeGarbage) September 10, 2019
テレビ制御コード (2019/10/29 追記)
リクエストありましたのでテレビ制御コードも記載いたします。赤外線コードは我が家のテレビの場合ですので適宜 赤外線解析して差し替えてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
#include <Arduino.h> #include <ESP8266WiFi.h> #include "fauxmoESP.h" #include <IRremoteESP8266.h> #include <IRsend.h> #define IR_LED 4 IRsend irsend(IR_LED); int flagTV = 0; int flagSound = 0; int flagA = 0; int flagB = 0; int flagC = 0; int flagD = 0; int flagE = 0; #define WIFI_SSID "xxxxx" #define WIFI_PASS "xxxxx" fauxmoESP fauxmo; // ----------------------------------------------------------------------------- #define SERIAL_BAUDRATE 115200 #define IDtv "テレビ" #define IDsound "sound" #define IDchA "chA" #define IDchB "chB" #define IDchC "chC" #define IDchD "chD" #define IDchE "chE" // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // Wifi // ----------------------------------------------------------------------------- void wifiSetup() { // Set WIFI module to STA mode WiFi.mode(WIFI_STA); // Connect Serial.printf("[WIFI] Connecting to %s ", WIFI_SSID); WiFi.begin(WIFI_SSID, WIFI_PASS); // Wait while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(100); } Serial.println(); // Connected! Serial.printf("[WIFI] STATION Mode, SSID: %s, IP address: %s\n", WiFi.SSID().c_str(), WiFi.localIP().toString().c_str()); } void setup() { // Init serial port and clean garbage Serial.begin(SERIAL_BAUDRATE); Serial.println(); Serial.println(); irsend.begin(); // Wifi wifiSetup(); // By default, fauxmoESP creates it's own webserver on the defined port // The TCP port must be 80 for gen3 devices (default is 1901) // This has to be done before the call to enable() fauxmo.createServer(true); // not needed, this is the default value fauxmo.setPort(80); // This is required for gen3 devices // You have to call enable(true) once you have a WiFi connection // You can enable or disable the library at any moment // Disabling it will prevent the devices from being discovered and switched fauxmo.enable(true); // Add virtual devices fauxmo.addDevice(IDtv); fauxmo.addDevice(IDsound); fauxmo.addDevice(IDchA); fauxmo.addDevice(IDchB); fauxmo.addDevice(IDchC); fauxmo.addDevice(IDchD); fauxmo.addDevice(IDchE); 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); // Checking for device_id is simpler if you are certain about the order they are loaded and it does not change. // Otherwise comparing the device_name is safer. if (strcmp(device_name, IDtv)==0) { if(state){ flagTV = 1; }else{ flagTV = 2; } }else if (strcmp(device_name, IDsound)==0) { if(state){ flagSound = 1; }else{ flagSound = 2; } }else if (strcmp(device_name, IDchA)==0) { if(state){ flagA = 1; }else{ flagA = 2; } }else if (strcmp(device_name, IDchB)==0) { if(state){ flagB = 1; }else{ flagB = 2; } }else if (strcmp(device_name, IDchC)==0) { if(state){ flagC = 1; }else{ flagC = 2; } }else if (strcmp(device_name, IDchD)==0) { if(state){ flagD = 1; }else{ flagD = 2; } }else if (strcmp(device_name, IDchE)==0) { if(state){ flagE = 1; }else{ flagE = 2; } } }); } void loop() { // fauxmoESP uses an async TCP server but a sync UDP server // Therefore, we have to manually poll for UDP packets fauxmo.handle(); if(flagTV == 1){ tvOn(); flagTV = 0; }else if(flagTV == 2){ tvOff(); flagTV = 0; } if(flagSound == 1){ soundUp(); flagSound = 0; }else if(flagSound == 2){ soundDown(); flagSound = 0; } if(flagA == 1){ ch1(); flagA = 0; }else if(flagA == 2){ ch2(); flagA = 0; } if(flagB == 1){ ch3(); flagB = 0; }else if(flagB == 2){ ch5(); flagB = 0; } if(flagC == 1){ ch6(); flagC = 0; }else if(flagC == 2){ ch7(); flagC = 0; } if(flagD == 1){ ch8(); flagD = 0; }else if(flagD == 2){ chgIn(); flagD = 0; } if(flagE == 1){ digital(); flagE = 0; }else if(flagE == 2){ bs(); flagE = 0; } } void tvOn() { Serial.print("TV turn on ..."); irsend.sendNEC(0x001C6F00F, 32); } void tvOff() { Serial.print("TV turn off ..."); irsend.sendNEC(0x001C6F00F, 32); } void soundUp() { Serial.print("sound Up ..."); irsend.sendNEC(0x001C630CF, 32); } void soundDown() { Serial.print("sound Down ..."); irsend.sendNEC(0x001C6B04F, 32); delay(400); irsend.sendNEC(0x001C6B04F, 32); } void ch1() { Serial.print("ch1 on ..."); irsend.sendNEC(0x001C600FF, 32); } void ch2() { Serial.print("ch2 on ..."); irsend.sendNEC(0x001C6807F, 32); } void ch3() { Serial.print("ch3 on ..."); irsend.sendNEC(0x001C640BF, 32); } void ch5() { Serial.print("ch5 on ..."); irsend.sendNEC(0x001C620DF, 32); } void ch6() { Serial.print("ch6 on ..."); irsend.sendNEC(0x001C6A05F, 32); } void ch7() { Serial.print("ch7 on ..."); irsend.sendNEC(0x001C6609F, 32); } void ch8() { Serial.print("ch8 on ..."); irsend.sendNEC(0x001C6E01F, 32); } //入力切り替え void chgIn() { Serial.print("change input ..."); irsend.sendNEC(0x001C648B7, 32); delay(400); irsend.sendNEC(0x001C648B7, 32); } //地デジ void digital() { Serial.print("terrestrial digital ..."); irsend.sendNEC(0x001C6A25D, 32); } //BS void bs() { Serial.print("bs ..."); irsend.sendNEC(0x001C6629D, 32); } |
TV電源ON/OFF、音量大小、各チャンネル、入力切替、地デジ、BSなどをコントロールできるようにしました。
esp8266-alexa-wemo-emulator の時と同様に音量大小、各チャンネル、入力切替、地デジ、BSの制御にはAlexaアプリの定型アクションを使用しております。
コード修正 (2021/6/24 追記)
2021/6/20ころからリビングのスイッチをON/OFFするデバイスが動かなくなった。
コード修正で解決。
念のためFauxmoESPのバージョンも更新しておいた (3.1.0 -> 3.4.0)。
どうやら fauxmoESPでIDに日本語つかうと
Alexaが認識できなくなったっぽいIDを英語でつけなおして
定型文で日本語にして解決— HomeMadeGarbage (@H0meMadeGarbage) June 24, 2021
すみませんメールアドレス忘れたのでもう一度書きます。
fauxmoESPライブラリを用いた、テレビ制御のコードを教えていただくことは可能でしょうか
コメントありがとうございます。
テレビ制御用コード追記しておきました。
ご確認ください。
素早い対応大変ありがとうございます。助かりました。
参考にさせていただきます!!
私もスマートデバイスを作りたく試してみましたがwifiには接続できるのですが、デバイス検索できません原因としては何が考えられますか??
横からすみません。私もそこで詰まっていて探してみたところ
https://bitbucket.org/xoseperez/fauxmoesp/issues/94/cannot-create-more-than-3-devices
ここの通りにやったところつながるようになりました!
ここで一緒に言ってしまって申し訳ないですが、サイト主のお父ちゃん様のおかげでスマートホーム化できました!ありがとうございます!
TVはalexaから送信することができました。ありがとうございます。
現在LEDシーリングライトも上記のコードにIDLEDとして追加し、付けたり消したりしようとしているのですが、プロトコルがUNKNOWNのため、同じようにできません。irsend.sendRawで送信するように設定したのですがうまくできません。よろしければ方法をご教授いただけませんでしょうか?よろしくお願いいたします。
以下のサンプルコードのように、赤外線生データをirsend.sendRawしかないと思うのですが。
https://github.com/crankyoldgit/IRremoteESP8266/blob/master/examples/IRsendDemo/IRsendDemo.ino
ちょっと不明ですね。申し訳ございません。
すみません。少しお聞きしたいことがあります。よろしいでしょうか?私は、fauxmoを用いて、自宅の赤外線で扱える機器全てを登録したIOT化に成功しました。ただ、alexaから機器をつけようとすると、機器の制御は出来るものの、”デバイスを検出できませんでした”とalexaが言います。このような現象はそちらでは起きていますでしょうか?
コメントありがとうございます。
この記事の “Alexaアプリ設定”節に記載している
デバイスの検出作業は実行できてますでしょうか?
こんばんは
我が家のIoT化に大変参考にさせていただきました。
恐縮ですが、2点教えていただけますでしょうか?
1)USBから通電後、一回目の実行時だけサーボの角度が90度になってしまいます。2度目以降は指定した角度です。なお、USBを差し直す度、同様の動作をします。
2)コード内に2つのIDを定義できないでしょうか?ESP一つで、オンとオフのサーボを2つ付けるイメージです。
Arduinoの経験が浅く、ズレた質問でしたらすみません。ご教示の程、お願い致します。。
コメントありがとうございます!
>1)USBから通電後、一回目の実行時だけサーボの角度が90度になってしまいます。
私の場合 起動後に90度になってほしいので
初期角度を
int servoIni = 90;
としています。ここを変えるとよいかと思います。
>2)コード内に2つのIDを定義できないでしょうか?
ここではON( livingOn() 関数)とOFF(livingOff() 関数)で同じサーボを使っていますが
違うサーボを指定しても問題なく動くと思います。
ご返信ありがとうございます。
1)起動後に90度になる件
すでに0度で初期化しておりますが、ダメなようです。。サーボの問題でしょうか・・
2)コード内に2つのIDを定義
ご指摘ありがとうございます。隣のPINを指定したら、無事に動きました。
>すでに0度で初期化しておりますが、ダメなようです。。サーボの問題でしょうか・・
それでは setup() 内で
myservo.attach(D8);
delay(1000);
myservo.write(servoIni);
を追加でいかがでしょうか?
ご確認よろしくお願い致します。
こんばんわ。
この記事を参考に、LEDをオンにする単純なプログラムを作成しました。2か月ほど前までは正常に動作していたのですが、ESP32やその他回路を入れるケースを作りいざ実装と思い、2日ほど前に動作確認した所、使えなくなっていました😭
Wifiには、正常に接続しているのですが、AlexaがEsp32を検出してくれません。
環境はesp32FauxmoESPver3.1.1とEchodot 3でesp32,Echodot共に同じwifi(24Ghz)に接続しています。
これはAlexaソフトウェアのアップデートが原因とかですかね….?主さんの以前組んだFauxmoを用いたデバイスは今でも正常に動作しておりますか?
何か解決方法や、思い当たる伏があれば教えて頂けませんでしょうか。ご迷惑おかけしますがよろしくお願いいたします。
これが私が書いたコードです。↓
#include
#include
#include “fauxmoESP.h”
fauxmoESP fauxmo;
#define SERIAL_BAUDRATE 115200
#define light 13
#define id “light”
char ssid[] = “BCW720J-3115E-G”;
char password[] = “35cf47a7c7474”;
void wifiSetup() {
// Set WIFI module to STA mode
WiFi.mode(WIFI_STA);
// Connect
Serial.printf(“[WIFI] Connecting to %s “,ssid);
WiFi.begin(ssid, password);
// Wait
while (WiFi.status() != WL_CONNECTED) {
Serial.print(“.”);
delay(100);
}
Serial.println();
// Connected!
Serial.printf(“Wifi[SSID: %s, IP address: %s]につながりました。\n”, WiFi.SSID().c_str(), WiFi.localIP().toString().c_str());
}
void setup() {
// Init serial port and clean garbage
Serial.begin(SERIAL_BAUDRATE);
// Wifi
wifiSetup();
// LED
pinMode(light, OUTPUT);
digitalWrite(light,HIGH);
//fauxmoESP
fauxmo.createServer(true);
fauxmo.setPort(80);
fauxmo.enable(true);
fauxmo.addDevice(id);
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)==0) {
digitalWrite(light, state ? HIGH : LOW);
}
});
}
void loop(){
fauxmo.handle();
static unsigned long last = millis();
if (millis() – last > 5000) {
last = millis();
Serial.printf(“[MAIN] Free heap: %d bytes\n”, ESP.getFreeHeap());
}
}
コードがぐちゃぐちゃになっていたので
#include
#include
#include “fauxmoESP.h”
fauxmoESP fauxmo;
#define SERIAL_BAUDRATE 115200
#define light 13
#define id “light”
char ssid[] = “my ssid”;
char password[] = “my password”;
void wifiSetup() {
// Set WIFI module to STA mode
WiFi.mode(WIFI_STA);
// Connect
Serial.printf(“[WIFI] Connecting to %s “,ssid);
WiFi.begin(ssid, password);
// Wait
while (WiFi.status() != WL_CONNECTED) {
Serial.print(“.”);
delay(100);
}
Serial.println();
// Connected!
Serial.printf(“Wifi[SSID: %s, IP address: %s]につながりました。\n”, WiFi.SSID().c_str(), WiFi.localIP().toString().c_str());
}
void setup() {
// Init serial port and clean garbage
Serial.begin(SERIAL_BAUDRATE);
// Wifi
wifiSetup();
// LED
pinMode(light, OUTPUT);
digitalWrite(light,HIGH);
//fauxmoESP
fauxmo.createServer(true);
fauxmo.setPort(80);
fauxmo.enable(true);
fauxmo.addDevice(id);
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)==0) {
digitalWrite(light, state ? HIGH : LOW);
}
});
}
void loop(){
fauxmo.handle();
static unsigned long last = millis();
if (millis() – last > 5000) {
last = millis();
Serial.printf(“[MAIN] Free heap: %d bytes\n”, ESP.getFreeHeap());
}
}