Posted at

M5StickC をドアセンサー(&開閉通知)にする

日曜DIY。家人の外出や帰宅が何となく分かるように、M5StickC + ENV Hatで家のドアセンサーを作った(3000円前後)。

m5stickc.jpg


ハードウェアの調達


開発


開発環境


プログラム

#include <M5StickC.h>

#include <Wire.h>
#include "bmm150.h"
#include "bmm150_defs.h"
#include <WiFi.h>
#include <WiFiClientSecure.h>

const char* wifi_ap_ssid = "XXXXXXXX";
const char* wifi_ap_pass = "XXXXXXXX";

String door_state = "close";
uint16_t door_thr_close = 1600;
uint16_t door_thr_open = 800;
uint16_t door_ignore = 60000;
uint32_t door_lastpost = -door_ignore;

BMM150 bmm = BMM150();

void setup() {
Serial.begin(115200);
Serial.println("start debugging");
Wire.begin(0,26);
M5.begin();
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(BLACK);
pinMode(M5_BUTTON_HOME, INPUT);
initdev();
M5.Lcd.fillScreen(BLACK);
}

void initdev(){
M5.Lcd.setCursor(0, 0, 2);
if(bmm.initialize() == BMM150_E_ID_NOT_CONFORM){ while(1); }
M5.Lcd.printf("Mag sensor OK.\n");

WiFi.begin(wifi_ap_ssid, wifi_ap_pass);
while (WiFi.status() != WL_CONNECTED){ delay(500); }
IPAddress ip = WiFi.localIP();
M5.Lcd.printf("Wifi: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
delay(2000);
}

uint8_t setup_flag = 1;
void loop() {
bmm.read_mag_data();
int magval = (int)(sqrt(pow(bmm.raw_mag_data.raw_datax, 2) + pow(bmm.raw_mag_data.raw_datay, 2) + pow(bmm.raw_mag_data.raw_dataz, 2)));
String state = "-----";
if (door_thr_close < magval){ state = "close"; }
if (magval < door_thr_open ){ state = "open"; }

M5.Lcd.setCursor(0, 0, 2);
M5.Lcd.printf("%06d [%s] \n", magval, state);
if ((state != "-----") && ((millis()-door_lastpost) > door_ignore) && (door_state != state)){
door_state = state;
door_lastpost = millis();
String r = https_Web_Get("example.com", "/update?1=door&2=" + state + "&3=" + String(magval));
M5.Lcd.printf("send: %s \n", state);
M5.Lcd.println(r);
}
delay(200);

if(!setup_flag){
setup_flag = 1;
initdev();
}
if(digitalRead(M5_BUTTON_HOME) == LOW){
setup_flag = 0;
while(digitalRead(M5_BUTTON_HOME) == LOW);
}
return;
}

String https_Web_Get(const char* host, String target_page){
String res;
WiFiClientSecure https_client;
if (https_client.connect(host, 443)){
String s = "GET https://" + String(host) + target_page + " HTTP/1.1\r\nHost: " + String(host) + "\r\n";
s += "User-Agent: ESP32\r\nConnection: close\r\n\r\n\0";
https_client.print(s);
https_client.flush();
}
if(https_client){
while(https_client.connected()){
String r = https_client.readStringUntil('\n');
if(0 <= r.indexOf("HTTP")){res = r;}
Serial.println(r);
if (r == "\r") break;
}
while (https_client.available()){ https_client.read(); }
https_client.stop();
}
return res;
}


  • 上記では磁力の閾値は800以下でclose、1600以上でopenとしてある。

  • チャタリング防止のため、状態変化通知後60秒間は次の通知を行わないようにしている。

  • 通知先のAPIは当初IFTTTからのEmailとしていたが、通知が遅いことがあったため、自作+Slackにした。

  • 通信はhttpsだが、ライブラリではサーバ証明書の検証まではしていないようなので、その点留意。

  • 機能加除、各種デバッグ行いたい場合は、SerialかDisplayにて適宜printfデバッグ。

  • ENV HATは気温/湿度/気圧のデータも取れるほか、StickC本体にはマイクもあるため、ドアが開いたら録音、など様々な拡張の妄想が広がります。StickVだとさらに。


設置と調整


  • ドア側にマグネットを付ける

  • 閾値を環境に合わせて調整

  • 当初USB電源に安価なものを使ったら、過電流で熱くなり液晶がダメになって1台つぶしてしまった。USB電源接続後は3分ほど本体温度や見た目に異状ないか要確認。