人感センサーとESP8266のスリープ機能と充電池を使った、省電力の実験をしてみました。検知するとESP8266のディープスリープをリセットしMQTTを介して検知状態をネットへ通知します。
接続
電源はニッケル水素充電池4本を直列接続し、三端子レギュレーターで3.3Vにしたものを回路へ供給しています。
人感センサー(焦電センサー)には、SB412Aを使いました。検知でVOピンが「ハイ」となる仕様です。
人感センサーの検知出力でESP8266のスリープモードから復帰させるために、人感センサーの信号は、ESP8266のGPIO16のスリープモードリセット信号出力とNANDした後に、0.1μFのキャパシタを介してESP8266のリセットピンへ接続しています。
ESP8266はスリープ状態でGPIO16が「ハイ」となります。スリープ中でかつ人感センサーの出力が「ハイ」となったときに、NAND回路の出力が「ロー」となり、ESP8266がリセットされスリープ状態から復帰します。
センサー値 | GPIO16 | NAND回路出力 |
L | L | H |
H | L | H |
L | H | H |
H | H | L |
GPIO16とリセットピン間にダイオードを入れることで、スリープタイムアウト時(GPIO16が「ロー」)にもリセットされスリープから復帰するようにしました。
スケッチ例
人感センサーの状態 ONまたはOFFをMQTTブリーカーへパブリッシュしてディープスリープするスケッチです。検知しない状態でも1時間毎に人感センサーの状態をパブリッシュします。
人感センサーの検知でスリープモードから復帰させる部分はハードウェアで行うため、特別なコードを追加する必要はありません。
検知時により早くMQTTブローカーへ検知結果を通知させるため、IPアドレスはDHCPによる動的割り当てではなく、静的に設定しています。
また、WiFiやMQTTブローカーへ接続できないときは、永久に接続を試行するのではなく、何回か試行した後に短い期間ディープスリープするようにしています。
/* ESP8266 IR Motion deep sleep wake-up test by MONOxIT inc. Based on Basic ESP8266 MQTT example with pubsubclient library. */ #include <ESP8266WiFi.h> #include <PubSubClient.h> //ネットワーク環境に合わせる const char* ssid = YOUR_SSID; const char* password = YOUR_PASSWORD; const char* mqttServer = YOUR_MQTT_BROKER; // 静的IPアドレス IPAddress ip(192, 168, 1, 170); IPAddress gateway(192, 168, 1, 1); IPAddress subnet(255, 255, 255, 0); const char* mqttDeviceId = "HS02"; const char* mqttTopic = "home/sensor02"; const int motionPin = 14; //短いスリープ(マイクロ秒) 5分 const unsigned long updateIntervalMicrosShort = 5*60*1000*1000; //長いスリープ(マイクロ秒) 1時間 const unsigned long updateIntervalMicrosLong = 60*60*1000*1000; WiFiClient espClient; PubSubClient client(espClient); uint8_t motionPinStatus = LOW; void connectToMqttBroker() { for(int i = 0; (i < 3) && (!client.connected()); i++){ if (!client.connect(mqttDeviceId)) { delay(5000); } } // MQTTブローカーへ接続できないときは、短い時間ディープスリープ if(!client.connected()) ESP.deepSleep(updateIntervalMicrosShort); } void setupWifi() { delay(10); WiFi.begin(ssid, password); for(int i = 0; (i < 20) && (WiFi.status() != WL_CONNECTED); i++) { delay(500); } // WiFi接続できないときは、短い時間ディープスリープ if(WiFi.status() != WL_CONNECTED) ESP.deepSleep(updateIntervalMicrosShort); } void updateMotionStatus(){ String motionStr = "\"OFF\""; if (motionPinStatus == HIGH) { motionStr = "\"ON\""; } //JSON形式でセンサーの状態ONかOFFをパブリッシュ String payload = "{\"motion\":"; payload += motionStr; payload += "}"; client.publish(mqttTopic, (char*) payload.c_str()); } void setup() { pinMode(motionPin,INPUT); //人感センサーの値を取得 motionPinStatus = digitalRead(motionPin); WiFi.mode(WIFI_STA); WiFi.config(ip, gateway, subnet); setupWifi();// WiFi接続 // MQTTブローカーへ接続 client.setServer(mqttServer, 1883); connectToMqttBroker(); updateMotionStatus();// 人感センサーの値をパブリッシュ delay(100); client.disconnect();// MQTTブローカーから切断 delay(100); uint32_t sleepTime = updateIntervalMicrosLong; if (motionPinStatus == HIGH) { // 検知状態なら短いスリープ時間をセット sleepTime = updateIntervalMicrosShort; } ESP.deepSleep(sleepTime);//ディープスリープへ移行し省電力に } void loop() { client.loop(); delay(100); }
まとめ
三端子レギュレーターやNAND回路、ディープスリープ状態のESP8266の消費電力が常に消費される電力の主なものですが、2700mAhの単三型ニッケル水素充電池を四本直列にして電源として供給し、検知回数6回程度でおよそ6日~程稼働しました。週に1度電池を交換すればよいので実用的に使用できています。
人感センサー以外にも検知で「ハイ」となるセンサーであれば、同じ回路を使うことができます。検知で「ロー」となるセンサーでもNANDを他の論理回路にすることで対応できそうです。