[ESP8266 IoT] 人感センサーでESP8266の目をさまさす

人感センサーと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ブローカーへ接続できないときは、永久に接続を試行するのではなく、何回か試行した後に短い期間ディープスリープするようにしています。

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
/*
 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を他の論理回路にすることで対応できそうです。