Skip to content

Instantly share code, notes, and snippets.

@tspspi
Last active August 22, 2020 14:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tspspi/ed507c38d92f8ef8d796e72c9e8ce5f1 to your computer and use it in GitHub Desktop.
Save tspspi/ed507c38d92f8ef8d796e72c9e8ce5f1 to your computer and use it in GitHub Desktop.
NodeMCU Amica (ESP8266) motion detector signaling via MQTT
/*
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