-
-
Save tspspi/ed507c38d92f8ef8d796e72c9e8ce5f1 to your computer and use it in GitHub Desktop.
NodeMCU Amica (ESP8266) motion detector signaling via MQTT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Most simple arduino based motion sensor (most likely external | |
PIR module) code that simply signals the pin change (note: Not | |
via interrupt but via polling) to an MQTT server. Can of course | |
monitor any other binary digital signal that's slowly changing. | |
*/ | |
static const char* wlanSSID = "{FILLIN_WIFI_SSID}"; | |
static const char* wlanPSK = "{FILLIN_WIFI_PSK}"; | |
#define MQTT_SERVER "{FILLIN_MQTT_HOST}" | |
#define MQTT_PORT {FILLIN_MQTT_PORT} | |
#define MQTT_USER "{FILLIN_MQTT_USER}" | |
#define MQTT_PASS "{FILLIN_MQTT_PASS}" | |
#define MQTT_TOPIC "{FILLIN_MQTT_TOPIC}" | |
// Topic has the structure "parentA.parentB.topicname" | |
#define OTA_HOSTNAME "{FILLIN_OTA_HOSTNAME}" | |
#define OTA_PASSWORD "{FILLIN_OTA_SECRET}" | |
#include <ESP8266WiFi.h> | |
#include <ESP8266mDNS.h> | |
#include <WiFiUdp.h> | |
#include <ArduinoOTA.h> | |
#include <Adafruit_MQTT.h> | |
#include <Adafruit_MQTT_Client.h> | |
#ifdef WIFI_ENTERPRISE | |
#nclude <wpa2_enterprise.h> | |
#endif | |
#ifndef MQTT_RECONNECT_INTERVAL | |
#define MQTT_RECONNECT_INTERVAL 5 | |
#endif | |
#ifndef MQTT_REPORT_INTERVAL | |
#define MQTT_REPORT_INTERVAL 15 | |
#endif | |
#ifndef MQTT_PROCESS_PACKETS_TIMEOUT | |
#define MQTT_PROCESS_PACKETS_TIMEOUT 150 | |
#endif | |
#ifndef PORT_MOTIONSENSOR | |
#define PORT_MOTIONSENSOR D7 | |
#endif | |
#ifndef PORT_LED | |
#define PORT_LED D0 | |
#endif | |
/* MQTT */ | |
static WiFiClient wclient; | |
static Adafruit_MQTT_Client mqtt(&wclient, MQTT_SERVER, MQTT_PORT, MQTT_USER, MQTT_PASS); | |
static Adafruit_MQTT_Publish mqttTopicOut(&mqtt, MQTT_TOPIC); | |
static unsigned long int dwMQTTLastReport; | |
static unsigned long int dwWiFiCheckTimeout; | |
static unsigned long int dwTimeoutTickLast; | |
static unsigned long int dwMqttLastConnectTry; | |
/* Generic state */ | |
enum stateNetwork { | |
stateNetwork_Disconnected = 0, | |
stateNetwork_ConnectedWiFi = 1, | |
stateNetwork_ConnectedMQTT = 2 | |
}; | |
static enum stateNetwork stateNet; | |
static int stateSensor; | |
static bool requestStatusChange; | |
/* MQTT status broadcast / report */ | |
static void mqttSendStatus(bool bTriggered) { | |
String msg; | |
msg += "{ \"status\" : "; | |
msg += (stateSensor) ? "true" : "false"; | |
msg += ", \"changed\" : "; | |
msg += (bTriggered) ? "true" : "false"; | |
msg += "}"; | |
dwMQTTLastReport = millis(); | |
mqttTopicOut.publish(msg.c_str()); | |
} | |
void setup() { | |
unsigned long int i; | |
// put your setup code here, to run once: | |
byte mac[6]; | |
pinMode(PORT_MOTIONSENSOR, INPUT); | |
pinMode(PORT_LED, OUTPUT); | |
#ifdef DEBUG | |
Serial.begin(115200); | |
#endif | |
delay(1000); | |
for(i = 0; i < 10; i++) { | |
digitalWrite(PORT_LED, HIGH); delay(100); | |
digitalWrite(PORT_LED, LOW); delay(100); | |
} | |
#ifdef DEBUG | |
delay(150); | |
while(!Serial) { delay(1); } | |
Serial.println("Booting"); | |
Serial.setDebugOutput(true); | |
#endif | |
WiFi.macAddress(mac); | |
#ifdef DEBUG | |
Serial.print("MAC: "); | |
Serial.print(mac[0], HEX); | |
Serial.print(":"); | |
Serial.print(mac[1], HEX); | |
Serial.print(":"); | |
Serial.print(mac[2], HEX); | |
Serial.print(":"); | |
Serial.print(mac[3], HEX); | |
Serial.print(":"); | |
Serial.print(mac[4], HEX); | |
Serial.print(":"); | |
Serial.println(mac[5], HEX); | |
#endif | |
#ifdef WIFI_ENTERPRISE | |
wifi_station_set_wpa2_enterprise_auth(0); | |
wifi_station_clear_cert_key(); | |
wifi_station_clear_enterprise_ca_cert(); | |
wifi_station_clear_enterprise_identity(); | |
wifi_station_clear_enterprise_username(); | |
wifi_station_clear_enterprise_password(); | |
wifi_station_clear_enterprise_new_password(); | |
#endif | |
WiFi.persistent(false); | |
WiFi.mode(WIFI_OFF); | |
WiFi.mode(WIFI_STA); | |
WiFi.begin(wlanSSID, wlanPSK); | |
#ifdef OTA_ENABLE | |
// Hostname defaults to esp8266-[ChipID] | |
ArduinoOTA.setHostname(OTA_HOSTNAME); | |
ArduinoOTA.setPassword(OTA_PASSWORD); | |
ArduinoOTA.onStart([]() { | |
#ifdef DEBUG | |
Serial.println("Start updating"); | |
#endif | |
return; | |
}); | |
ArduinoOTA.onEnd([]() { | |
#ifdef DEBUG | |
Serial.println("\nEnd"); | |
#endif | |
return; | |
}); | |
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { | |
#ifdef DEBUG | |
Serial.printf("Progress: %u%%\r", (progress / (total / 100))); | |
#endif | |
return; | |
}); | |
ArduinoOTA.onError([](ota_error_t error) { | |
#ifdef DEBUG | |
Serial.printf("Error[%u]: ", error); | |
if (error == OTA_AUTH_ERROR) { | |
Serial.println("Auth Failed"); | |
} else if (error == OTA_BEGIN_ERROR) { | |
Serial.println("Begin Failed"); | |
} else if (error == OTA_CONNECT_ERROR) { | |
Serial.println("Connect Failed"); | |
} else if (error == OTA_RECEIVE_ERROR) { | |
Serial.println("Receive Failed"); | |
} else if (error == OTA_END_ERROR) { | |
Serial.println("End Failed"); | |
} | |
#endif | |
return; | |
}); | |
ArduinoOTA.begin(); | |
#endif | |
/* | |
We will trigger an MQTT connection immed. | |
Reporting is also set into the past ... | |
*/ | |
dwMqttLastConnectTry = 0; | |
dwMQTTLastReport = millis() - MQTT_REPORT_INTERVAL; | |
} | |
void loop() { | |
unsigned long currentMillis = millis(); | |
unsigned long int dwLastWiFiCheck; | |
if (currentMillis >= dwWiFiCheckTimeout) { | |
dwLastWiFiCheck = currentMillis - dwWiFiCheckTimeout; | |
} else { | |
dwLastWiFiCheck = (~0) - dwWiFiCheckTimeout + currentMillis; | |
} | |
int wifiState = WiFi.status(); | |
if (dwLastWiFiCheck > 5000) { | |
if (wifiState != WL_CONNECTED) { | |
stateNet = stateNetwork_Disconnected; | |
#ifdef DEBUG | |
Serial.println("WiFi connection not available!"); | |
#endif | |
WiFi.mode(WIFI_OFF); | |
WiFi.mode(WIFI_STA); | |
WiFi.begin(wlanSSID, wlanPSK); | |
#ifdef DEBUG | |
Serial.print("Trying to connect to "); Serial.println(wlanSSID); | |
#endif | |
} else { | |
if (stateNet == stateNetwork_Disconnected) { | |
#ifdef DEBUG | |
Serial.println("WiFi connection became available"); | |
#endif | |
Serial.println(WiFi.localIP()); | |
stateNet = stateNetwork_ConnectedWiFi; | |
mqtt.connect(); // Try MQTT connection ... | |
} | |
} | |
dwWiFiCheckTimeout = currentMillis; | |
} | |
if (wifiState == WL_CONNECTED) { | |
yield(); | |
ArduinoOTA.handle(); | |
} | |
yield(); | |
if (wifiState == WL_CONNECTED) { | |
if (mqtt.connected()) { | |
if (stateNet == stateNetwork_ConnectedWiFi) { | |
stateNet = stateNetwork_ConnectedMQTT; | |
} | |
mqtt.processPackets(MQTT_PROCESS_PACKETS_TIMEOUT); | |
} else { | |
stateNet = stateNetwork_ConnectedWiFi; | |
if (dwMqttLastConnectTry == 0) { | |
mqtt.disconnect(); | |
dwMqttLastConnectTry = currentMillis; | |
} else { | |
unsigned long int dwTimeSinceLastTry; | |
if (currentMillis > dwMqttLastConnectTry) { | |
dwTimeSinceLastTry = currentMillis - dwMqttLastConnectTry; | |
} else { | |
dwTimeSinceLastTry = (~0) - dwMqttLastConnectTry + currentMillis; | |
} | |
if (dwTimeSinceLastTry > (MQTT_RECONNECT_INTERVAL*1000)) { | |
mqtt.connect(); | |
dwMqttLastConnectTry = 0; | |
} | |
} | |
} | |
} | |
yield(); | |
unsigned long int dwDurationSinceLastReport; | |
int pinState; | |
pinState = digitalRead(PORT_MOTIONSENSOR); | |
if(pinState != stateSensor) { | |
if(stateSensor) { | |
digitalWrite(PORT_LED, HIGH); | |
} else { | |
digitalWrite(PORT_LED, LOW); | |
} | |
requestStatusChange = true; | |
stateSensor = pinState; | |
} | |
if (currentMillis > dwMQTTLastReport) { | |
dwDurationSinceLastReport = currentMillis - dwMQTTLastReport; | |
} else { | |
dwDurationSinceLastReport = (~0) - dwMQTTLastReport + currentMillis; | |
} | |
if ((dwDurationSinceLastReport > (MQTT_REPORT_INTERVAL*1000)) || requestStatusChange) { | |
// Periodic status report | |
if(stateNet == stateNetwork_ConnectedMQTT) { | |
mqttSendStatus(requestStatusChange); | |
} | |
requestStatusChange = false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment