人感センサーと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を他の論理回路にすることで対応できそうです。

