Edited at

ドアポストに投函されたら、google homeでお知らせする。

※記事が間に合いませんでした。端折りましたことをご了承ください。


概要

超めんどくさがりなので、家のドアポストにCDSセンサーを取り付け、変化があれば、MQTTであるmosquittoサーバを中継させて、google homeにアクションさせたいと思います。

ローカル環境で実行する分には、MQTTは大げさな気がしますが、いづれ外部ネットワーク経由で通知させたくなるのと、push/subscribe実行がしやすいので、IFTTTを使わない構成としました。


用意するもの

ESP8266とCDSセンサー: 動きを検知して通知します。

raspberry pi:簡易サーバとmosquittoサーバとgoogle homeに通知します。

google-home-notifier:google homeに喋らせるソフト

mosquitto:メッセージングサーバ

google home:google homeちゃん

流れは、Wifi付きのESP8266でセンサーを読み取り、raspberrypiの簡易サーバで受けとり、MQTTに通知します。それをbashでMQTTでsubscribeしておき、通知がきたらgoogle-home-notifierでgoogle homeで喋らせます。

google-home-notifierをラズパイにインストールしておきます。

https://qiita.com/SatoTakumi/items/c9de7ff27e5b70508066

MQTTサーバインストールをラズパイにインストールしておきます。

https://qiita.com/s_edward/items/c044f3d3e4d4a05d2dee

ESPのセンサー部分はメインではないので、記事の最後にソースを載せておきます。


簡易サーバです。

require 'sinatra'

require 'mqtt'

get '/iot' do
client = MQTT::Client.connect(host: "localhost",port: "1883", username: "user",password: "token")
client.publish("iot",params["token"])
end

ここで、ESPから受け取ったデータをMQTTサーバに流します。頑張れば、ESPから直接MQTTプロトコルが使えたかもしれないです。


受け取りプログラムです。

#!/bin/bash

while read msg; do
if [ $(echo $msg | grep "XXXXXXXXXXXXXXXバス") ] ; then
node main.js "次のバスは$(./bus.sh) です。";
fi
if [ $(echo $msg | grep "XXXXXXXXXXXXXXX") ] ; then
node main.js "何か荷物が届いていますよ。";
fi
done < <(mosquitto_sub -t iot -h localhost -u user -P password -q 1)

mosquitto_subでsubscribeしています。


センサーとESP8266と電池ボックスです。



cdsと10k抵抗を繋げてESP8266に繋げて、バッテリーと共に、箱に詰めた様子。


結果とこれから

あまり暗すぎることがなければ、そこそこ動いてくれました。誤動作はほぼありませんでした。

現在は4日ほどで電池が切れます。DeepSleepを繋げるともっといけそうな。

外部経由を考えると、IFTTTになると思いますが、そうなるとgoogle homeに通知する手段が無いんですね。家のネットワークを解放したくないので、外部経由させるときは、MQTTサーバを外部においてアクセスされば、家のネットワークを解放せずにすみそうです。Wifi外のポストとか。

あと、センサー側にも工夫がしてあるので(ソースが乱れてますが)、説明したいですが、別記事になるかもしれません。


ESP8266のスケッチを載せます。

#include <ESP8266WiFi.h>

#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPClient.h>

/* Set these to your desired credentials. */
const char *ssid = "XXXXXX"; //ENTER YOUR WIFI SETTINGS
const char *password = "XXXXXXX";

//Web/Server address to read/write from
const char *host = "";

const int btn = 12;
const int btn2 = 14;
double avgdR = 0.0;
int initCount = 20;

///=======================================================================
// Power on setup
//=======================================================================

void setup() {
delay(1000);
Serial.begin(115200);
WiFi.mode(WIFI_OFF); //Prevents reconnection issue (taking too long to connect)
delay(1000);
WiFi.mode(WIFI_STA); //This line hides the viewing of ESP as wifi hotspot

WiFi.begin(ssid, password); //Connect to your WiFi router
Serial.println("");

Serial.print("Connecting");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

//If connection successful show IP address in serial monitor
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP()); //IP address assigned to your ESP
}

void sendLetter()
{
//start
HTTPClient http; //Declare object of class HTTPClient
//GET Data
String Link,getData;
getData = "?token=XXXXXXXXXX"; //Note "?" added at front
Link = "http://localhost:7070" + getData;

http.begin(Link); //Specify request destination
Serial.println("button pushed");
int httpCode = http.GET(); //Send the request
String payload = http.getString(); //Get the response payload
Serial.println(httpCode); //Print HTTP return code
Serial.println(payload); //Print request response payload

http.end(); //Close connection
//end
}

//=======================================================================
// Main Program Loop
//=======================================================================
void loop() {

int iValue = analogRead( A0 );
double dV = iValue * 3.3 / 1023;
double dis = 0.0;
double dR = 0.0;

if( 0.005 < (3.3 - dV) )
{
dR = 10 * 1000 * dV / (3.3 - dV);
}
if( 0.0 == dR )
{
Serial.println("Infinity");
}
else
{
if(initCount > 0)
{
dis = dR - avgdR;
avgdR = ( ( dR + avgdR + avgdR) / 3 ) ;
initCount = initCount - 1;
return ;
}
dis = dR - avgdR;
avgdR = ( ( dR + avgdR + avgdR) / 3 ) ; //新規の輝度を取り込んで適応させる。
Serial.print("dR:");
Serial.println(dR);
Serial.print("avgdR:");
Serial.println(avgdR);
Serial.print("dis:");
Serial.println(dis);
}
if(dis > 2000 || dis < -2000){ //平均から外れると何か横切ったと判定する。
Serial.println("ON!!!!!!");
sendLetter();
}else{
Serial.println("off");
}

delay(1000);