前回までの複数のESP8266を用いた音声認識Wifiスイッチの続きです。
複数の部屋(リビング、寝室、トイレなど)に異なるIPアドレスを割り振ったESP8266があるので、リビングの電源をON/OFFするには、リビングに設置したESP8266のIPアドレスにリクエストしていましたが、リビングから寝室の電源をON/OFFするには、寝室のIPアドレスへ画面遷移してリクエストを送るというややこしい仕組みになってました。
仕組みとしてはこんな感じで、電源をON/OFFさせたい場所のESP8266へ直接リクエストを送って、それぞれのサーバからレスポンスを受け取っていたという感じです。画面遷移しないで、AからBあるいはBからAへリクエストできないものかと、以下のようなシステムに変更してみました。
この場合は、serverAがメインサーバとなり、端末からもこのIPアドレスにアクセスして、Aの電源をON/OFFする場合は従来通りAへリクエストを送り、Bの電源をON/OFFするには、Aにリクエストを送り、Aが内部的にBへHTTPリクエストを送ることになります。
逆にBのIPアドレスへアクセスしても、同様にAに対してリクエストを送ることができるので、AであれBであれ、どちらにアクセスしようと画面遷移せずに両方の電源を制御できます。
今までは、サーバはクライアントからのリクエストを待ち、リクエストがあるときだけレスポンスするのだと思っていたので、サーバから別のURLへHTTPリクエストを送ることはできないと思っていました。しかし、サーバからも普通にHTTPリクエストできるということでした(もっと早く気づけば)。
以下がサンプルコード。今回は音声認識の部分は外しています。単にサーバAを介してサーバBを制御するという仕組みの部分だけです。
ということで、http_request()という関数をつくり、他のIPアドレスのボタンを押したら、レスポンスとしてHTMLデータ(webPage:ボタン画面)を返しつつ、リクエストをもう一方のESP8266へ送るということにしました。setup()内にある以下の部分です。
少しずつ曖昧な部分の理解が深まってきたので、徐々にまともなシステムになりつつあります。
Raspberry Pi上にNode-REDで全体を管理するサーバを立ち上げようと思いましたが、今回のやり方で大丈夫そうなので、Node-REDやMQTTなどは使わずいけそうです。
電気的な制御は単純なON/OFFですが、Wifiが絡んでくると、サーバだとかクライアントだとか、通信の仕組みで手間がかかります。ということで、またもやRaspberry Pi(サーバ利用)は不要となってしまいました。もっと複雑なことをしない限り、しばらくは中枢的なサーバはいらなさそうです。
このシステムは近々完成させて、次は再度IPカメラに戻りたいと思います。
追記:
改良案はこちら(XMLHttpRequestを使ったサンプル)
音声認識Wifiスイッチ/ESP8266使用(まとめ)についてはこちら。
複数の部屋(リビング、寝室、トイレなど)に異なるIPアドレスを割り振ったESP8266があるので、リビングの電源をON/OFFするには、リビングに設置したESP8266のIPアドレスにリクエストしていましたが、リビングから寝室の電源をON/OFFするには、寝室のIPアドレスへ画面遷移してリクエストを送るというややこしい仕組みになってました。
仕組みとしてはこんな感じで、電源をON/OFFさせたい場所のESP8266へ直接リクエストを送って、それぞれのサーバからレスポンスを受け取っていたという感じです。画面遷移しないで、AからBあるいはBからAへリクエストできないものかと、以下のようなシステムに変更してみました。
この場合は、serverAがメインサーバとなり、端末からもこのIPアドレスにアクセスして、Aの電源をON/OFFする場合は従来通りAへリクエストを送り、Bの電源をON/OFFするには、Aにリクエストを送り、Aが内部的にBへHTTPリクエストを送ることになります。
逆にBのIPアドレスへアクセスしても、同様にAに対してリクエストを送ることができるので、AであれBであれ、どちらにアクセスしようと画面遷移せずに両方の電源を制御できます。
今までは、サーバはクライアントからのリクエストを待ち、リクエストがあるときだけレスポンスするのだと思っていたので、サーバから別のURLへHTTPリクエストを送ることはできないと思っていました。しかし、サーバからも普通にHTTPリクエストできるということでした(もっと早く気づけば)。
以下がサンプルコード。今回は音声認識の部分は外しています。単にサーバAを介してサーバBを制御するという仕組みの部分だけです。
#include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include <WiFiClient.h> #define ledPin 2 const char* ssid = "******"; const char* password = "******"; const char* reqHost = "192.168.3.13"; String webPage = ""; ESP8266WebServer server(80); void setup(void){ webPage="<http><head><meta charset='utf-8'><title>WIFI SWITCH</title></head><body>"; webPage+="<div style='text-align:center; font-size:30px;'>"; webPage+="<a href='/this_on'><button>THIS: ON</button></a><br/>"; webPage+="<a href='/this_off'><button>THIS: OFF</button></a><br/>"; webPage+="<a href='/other_on'><button>OTHER: ON</button></a><br/>"; webPage+="<a href='/other_off'><button>OTHER: OFF</button></a><br/>"; webPage+="</div></body></html>"; pinMode(ledPin, OUTPUT); Serial.begin(115200); delay(500); WiFi.begin(ssid, password); Serial.println(""); while (WiFi.status() != WL_CONNECTED) { delay(5000); Serial.print("."); } WiFi.config(IPAddress(192,168,3,12),IPAddress(192,168,3,1),IPAddress(255,255,255,0)); Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); server.on("/", [](){ server.send(200, "text/html", webPage); }); server.on("/this_on", [](){ server.send(200, "text/html", webPage); digitalWrite(ledPin, HIGH); delay(1000); }); server.on("/this_off", [](){ server.send(200, "text/html", webPage); digitalWrite(ledPin, LOW); delay(1000); }); server.on("/other_on", [](){ server.send(200, "text/html", webPage); http_request(reqHost,"/this_on"); delay(1000); }); server.on("/other_off", [](){ server.send(200, "text/html", webPage); http_request(reqHost,"/this_off"); delay(1000); }); server.begin(); Serial.println("HTTP server started"); } void http_request(const char* host, String url){ //host="192.168.3.13"; //url="/this_on"; WiFiClient client; const int httpPort = 80; if (!client.connect(host, httpPort)) { Serial.println("connection failed"); return; } client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); unsigned long timeout = millis(); while (client.available() == 0) { if (millis() - timeout > 5000) { Serial.println("Client Timeout!"); client.stop(); return; } } } void loop(void){ server.handleClient(); }
ということで、http_request()という関数をつくり、他のIPアドレスのボタンを押したら、レスポンスとしてHTMLデータ(webPage:ボタン画面)を返しつつ、リクエストをもう一方のESP8266へ送るということにしました。setup()内にある以下の部分です。
server.on("/other_on", [](){ server.send(200, "text/html", webPage); http_request(reqHost,"/this_on"); delay(1000); }); server.on("/other_off", [](){ server.send(200, "text/html", webPage); http_request(reqHost,"/this_off"); delay(1000); });
少しずつ曖昧な部分の理解が深まってきたので、徐々にまともなシステムになりつつあります。
Raspberry Pi上にNode-REDで全体を管理するサーバを立ち上げようと思いましたが、今回のやり方で大丈夫そうなので、Node-REDやMQTTなどは使わずいけそうです。
電気的な制御は単純なON/OFFですが、Wifiが絡んでくると、サーバだとかクライアントだとか、通信の仕組みで手間がかかります。ということで、またもやRaspberry Pi(サーバ利用)は不要となってしまいました。もっと複雑なことをしない限り、しばらくは中枢的なサーバはいらなさそうです。
このシステムは近々完成させて、次は再度IPカメラに戻りたいと思います。
追記:
改良案はこちら(XMLHttpRequestを使ったサンプル)
音声認識Wifiスイッチ/ESP8266使用(まとめ)についてはこちら。