ESP8266でホームモニタリングシステム構築
こんにちは、くろべこです。
前回からだいぶ日が空いてしまいましたが引き続きESP8266を使用したホームモニタリングシステムを構築していきたいと思いますよ。
今回はTCPソケット通信のクライアント側を構築したいと思います。サーバー編で作ったプログラムではTCPソケット通信による1対1通信なので、実質クライアントをスイッチさせながら通信を行えばいくらでもクライアントの数を増やすことが可能です。
とりあえずホームをモニタリングするために、温湿度&気圧を測定できる【BME280】を積んだクライアントプログラムを作成していきたいと思います。
ESP8266クライアントの配線を行う
配線といってもESP8266とBME280を繋ぐだけの簡単なお仕事です。インジケータ用のLEDも結線していますが、その程度です。
※LEDインジケータはサーバーとコネクションを開設しているときを点灯とし、コネクションが閉じているときを消灯とするために取り付けています。
ESP8266ホームモニタリングシステムClientプログラム
ちなみに、TCPソケット通信の状態遷移図の中で今回のクライアントはサーバーに対してコネクションの開設要求を行うアクティブオープンという立ち位置にあります。状態遷移図の詳細についてはmogulla3がまとめている記事がとってもわかりやすいので参考に見てみてください。
とりあえずクライアントプログラムを紹介します。
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 |
#include <ESP8266WiFi.h> IPAddress ip(100, 64, 1, 30); //ip IPAddress gateway(100, 64, 1, 100); IPAddress subnet(255, 255, 255, 0); IPAddress DNS(100, 64, 1, 100); #include <Wire.h> #include "Seeed_BME280.h" BME280 bme280; #ifndef STASSID "" #define STASSID "" #define STAPSK #endif const char* ssid = STASSID; const char* password = STAPSK; const char dmt=',';//送信データデリミタ const char* host = "100.64.1.100";//接続先サーバーのIP const uint16_t port = 9600;//接続先サーバーのポート static uint32_t t=0;//点滅周期カウンタ static bool st=0;//LED状態 uint8_t ls=0; uint32_t cnt=0;//ClientToServer送信カウンタ //サーバーからデータ送受信するためのClientクラス作成 WiFiClient client; void setup() { Serial.begin(115200); pinMode(15,OUTPUT); Serial.println(); Serial.print("Connecting to "); //WiFiをステーションモードで起動 WiFi.config(ip, gateway, subnet, DNS); //static_ip WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); //WiFiがステータスが接続になるまでループ while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } //WiFi接続完了 Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); Serial.print("connecting to "); Serial.print(host);//サーバー側のIP Serial.print(':'); Serial.println(port);//サーバー側のポート //BME280イニシャライズ if(!bme280.init()){ Serial.println("Device error!"); } } void SocketLed(uint8_t led, uint8_t pwm){ switch(led){ case 1: analogWrite(15,pwm); break; case 2: analogWrite(15, pwm); break; } } String GetRoomState(){ String rd; float temp, humt, pres; uint16_t alti; float pressure; //get and print temperatures Serial.print("Temp: "); temp=bme280.getTemperature(); Serial.print(temp); Serial.println("C");//The unit for Celsius because original arduino don't support speical symbols //get and print atmospheric pressure data Serial.print("Pressure: "); pres=bme280.getPressure()/100; Serial.print(pres); Serial.println("hPa"); //get and print altitude data Serial.print("Altitude: "); alti=bme280.calcAltitude(bme280.getPressure()); Serial.print(alti); Serial.println("m"); //get and print humidity data Serial.print("Humidity: "); humt=bme280.getHumidity(); Serial.print(humt); Serial.println("%"); rd=(String)temp+"*C"+','+(String)humt+"%"+','+(String)pres+"hPa"+','+(String)alti+"m"; return rd; } void loop() { while (!client.connect(host, port)) {//コネクション開設確認 Serial.println("connection failed"); Serial.println("Retry"); SocketLed(2,0);//コネクションClose(消灯) } //ソケット接続成功 SocketLed(1,50);//コネクション開設完了(点灯) Serial.println("sending data to server"); if (client.connected()) {//コネクション確認 client.println(GetRoomState());//サーバーにデータ送信 //client.write(0x06);//1byteデータ送信 Serial.print("送信回数:");Serial.println(cnt++); } //サーバーからのACK読み取りタイムアウト管理 //読み取り可能バッファが0だったらループ待機 unsigned long timeout = millis(); while (client.available() == 0) { if (millis() - timeout > 10000) { Serial.println(">>> Client Timeout !"); client.stop(); SocketLed(2,0);//コネクションClose(消灯) return; } } // ACK受信 Serial.println("receiving from remote server"); // 読み取り可能データが0になるまでループ //シリアル表示 while (client.available()) { //char ch = static_cast<char>(client.read()); String st = client.readStringUntil('\r');//受信データを終端文字受信orタイムアウトまで読み込み if(sizeof(st) != 0){ Serial.println(st); } } //Close the connection Serial.println(); Serial.println("closing connection"); client.stop(); SocketLed(2,0);//コネクションClose(消灯) delay(10000);//再接続まで10秒待機 } |
今回のホームモニタリングシステムは最終的に複数のクライアントの接続を想定しているので、クライアントのIPアドレスは静的アドレスで設定します。設定方法は、Wifi.beginの前にWifi.config(ip, gateway, subnetmask, DNS)で設定を行います。今回はSTAモードで静的IPを設定するので、IPアドレスやサブネットマスクはipconfigなどで確認して良い感じのやつを設定してみてください。
プログラムを上から追っていくと、、、
【セットアップ】
- WifiをSTAモード&静的IPアドレスで起動させる
- BME280のイニシャライズを行う
【LED点灯用関数:SocketLed(uint8_t led, uint8_t pwm)】
- 光量を調整したかったのでanalogWriteを使用しています。
【BME280データ取得用関数:GetRoomState()】
BME280から温度/湿度/気圧をゲットして、デリミタ(カンマ)で結合させた文字列を返り値とする。
【ループ】
- サーバーに対してコネクション開設要求を行う。開設できなかった場合は出来るまでループする。この時LEDは消灯。
- コネクションの接続確認が出来たらLEDを点灯。
- GetRoomState()返り値をデータとして送信。
- サーバーからのACK待ち(タイムアウト管理)
- 受信データ読み取り
- コネクションクローズ&LED消灯
- 再接続まで10秒待機
ざっくり説明するとこんな感じですね。
そこまで難しくないでしょ?このプログラムを複数作ってサーバーに送ってあげればホームデータを収集するモニタリングシステムの完成です。
ちょっとブレイクタイム(ESP8266に最適な入れ物)
今回のようにスタンドアローンのクライアントを作るときにESP8266を何かしらに格納したいと思います。そこでお勧めしたい入れ物が、Daisoに売っている【透明ケース(ミッキー)2個】です。
これに、アマゾンで安価に売っているミニブレッドボードがジャストフィットなんです。
クライアントのテスト動画
では、最後に今回作成したクライアント動作を動画に取りましたので紹介いたします。サーバーも一緒に映っているので察しが付くと思いますが、クライアントを3つ繋げています(第4オクテットが10,20,30)。各クライアントに対して3つのLEDを割り当てていてコネクションを開設しているクライアントに対応するLEDを点灯させています。
コメント