#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoOTA.h>
#include <Wire.h>
//WiFi settings
const char* WiFiHostname = "Gates"; // WiFi Hostname
const char* ssid = "UniFi-HomeKit"; // WiFi name
const char* password = "*********"; // WiFi password
//MQTT settings
const char* mqttID = "Gates";
const char* mqttServer = "10.10.20.10";
const int mqttPort = 1883;
const char* mqttUser = "********";
const char* mqttPassword = "***********";
const char* OTAHostname = "Gates"; //OTA Hostname
// constants
const int ledPin = 2; // the number of the LED pin
const int frontGatePin = 13; //D5 yellow
const int backGatePin = 14; //D7 blue
//time constants
const int oneMinute = (1 * 60 * 1000);
const int twentyMinutes = (20 * 60 * 1000);
const int fiveMinutes = (5 * 60 * 1000);
const int tenSeconds = 10000;
const int oneHour = (1 * 60 * 60 * 1000);
const int thirtyMinutes = (1 * 30 * 60 * 1000);
const int backGateOpenTime = 10000;
const int backGateCloseTime = 10000;
const int backGateTransitTime = 30000;
//MILLIS
unsigned long startMillisBlink;
unsigned long currentMillisBlink;
unsigned long startMillisWait;
unsigned long currentMillisWait;
unsigned long startMillisStatus;
unsigned long currentMillisStatus;
WiFiClient espClient;
PubSubClient client(espClient);
void connectToWiFi()
{
WiFi.hostname(WiFiHostname);
WiFi.mode(WIFI_STA); //access point mode disabled
WiFi.begin(ssid, password);
Serial.println("");
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
ledBlink(100, 1, false);
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
//Serial.printf("RSSI: %d dBm\n", WiFi.RSSI());
long rssi = WiFi.RSSI();
Serial.print("RSSI:");
Serial.println(rssi);
}
void connectToMQTT()
{
client.setKeepAlive(tenSeconds); // setting keep alive to 10 seconds
client.setServer(mqttServer, mqttPort);
client.setCallback(callback);
Serial.println("");
Serial.print("Connecting to MQTT");
wait(200);
Serial.print(".");
wait(200);
Serial.print(".");
wait(200);
Serial.println(".");
while (!client.connected()) {
if (client.connect(mqttID, mqttUser, mqttPassword )) {
Serial.println("Connected to MQTT server");
} else {
ledBlink(300, 2, false);
Serial.println("");
Serial.print("failed with state ");
Serial.print(client.state());
}
}
}
void OTASetup()
{
ArduinoOTA.setHostname(OTAHostname);
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else { // U_FS
type = "filesystem";
}
// NOTE: if updating FS this would be the place to unmount FS using FS.end()
Serial.println("Start updating " + type);
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
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");
}
});
ArduinoOTA.begin();
}
void startConnection()
{
wait(2000);
//WiFi
connectToWiFi();
wait(tenSeconds);
//MQTT
connectToMQTT();
//OTA
OTASetup();
}
void ledBlink (int delayPeriod, int blinks, bool beep)
{
bool timeElapsed = false;
blinks = blinks * 2;
while (blinks >= 1)
{
timeElapsed = false;
while (timeElapsed == false)
{
ArduinoOTA.handle();
yield();
client.loop();
currentMillisBlink = millis(); //get the current "time"
if (currentMillisBlink - startMillisBlink >= delayPeriod) //test whether the period has elapsed
{
digitalWrite(ledPin, !digitalRead(ledPin));//if so, change the state of the LED.
timeElapsed = true;
startMillisBlink = currentMillisBlink; //IMPORTANT to save the start time of the current LED state.
}
}
blinks--;
}
}
void wait (int waitTime)
{
startMillisWait = millis();
bool timeElapsed = false;
while (timeElapsed == false)
{
ArduinoOTA.handle();
client.loop();
yield();
currentMillisWait = millis(); //get the current time
if (currentMillisWait - startMillisWait >= waitTime) //test whether the period has elapsed
{
timeElapsed = true;
startMillisWait = currentMillisWait; //IMPORTANT
}
}
}
void openFrontGate()
{
digitalWrite(ledPin, LOW);
Serial.println("");
Serial.println("Front gate opening");
client.publish("getCurrentDoorState/FRONTGATE", "Opening");
wait(1000);
client.publish("getCurrentDoorState/FRONTGATE", "Open");
digitalWrite(frontGatePin, LOW);
wait(500);
digitalWrite(frontGatePin, HIGH);
wait(30000);
client.publish("getTargetDoorState/FRONTGATE", "C"); Serial.println("Front gate targhet: closed");
client.publish("getCurrentDoorState/FRONTGATE", "Closing"); Serial.println("Front gate closing");
wait(1000);
client.publish("getCurrentDoorState/FRONTGATE", "Closed"); Serial.println("Front gate closed");
digitalWrite(ledPin, HIGH);
}
void openBackGate()
{
digitalWrite(ledPin, LOW);
Serial.println("");
Serial.println("Back gate opening");
client.publish("getCurrentDoorState/BACKGATE", "Opening");
//Open Back Gate
digitalWrite(backGatePin, LOW);
wait(500);
digitalWrite(backGatePin, HIGH);
wait(backGateOpenTime); //Wait until back gate is open
client.publish("getCurrentDoorState/BACKGATE", "Open");
wait(backGateTransitTime); //Wait transit time
client.publish("getTargetDoorState/BACKGATE", "C"); Serial.println("Back Gate targhet: closed");
client.publish("getCurrentDoorState/BACKGATE", "Closing"); Serial.println("Back Gate closing");
wait(backGateCloseTime); //Wait until back gate is close
client.publish("getCurrentDoorState/BACKGATE", "Closed"); Serial.println("Back Gate closed");
digitalWrite(ledPin, HIGH);
}
void setup() {
Serial.begin(115200);
delay(5000);
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the rekay pins as an output:
pinMode(frontGatePin, OUTPUT);
pinMode(backGatePin, OUTPUT);
digitalWrite(ledPin, HIGH); //Set the led off
digitalWrite(frontGatePin, HIGH); //Set the pin off
digitalWrite(backGatePin, HIGH); //Set the pin off
startConnection();
client.subscribe("status/GATES");
client.subscribe("setTargetDoorState/FRONTGATE"); // target state can be OPEN or CLOSED. By default, values of O and C
//client.subscribe("getTargetDoorState/FRONTGATE"); //current door state can be OPEN, CLOSED, OPENING, CLOSING, STOPPED.
//client.subscribe("getCurrentDoorState/FRONTGATE"); //By default, these use values of O, C, o, c and S respectively
client.subscribe("setTargetDoorState/BACKGATE");
client.publish("status/GATES", "Boot completed");
client.publish("getCurrentDoorState/FRONTGATE", "C");
client.publish("getCurrentDoorState/BACKGATE", "C");
startMillisStatus = millis(); //initial start time
}
void callback(char* topic, byte* payload, unsigned int length)
{
//Print message
Serial.print("Message arrived: ");
Serial.print(topic);
Serial.print(", ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
//Reset the device
if (strcmp(topic, "status/GATES") == 0)
{
if (!strncmp((char *)payload, "RESET", length))
{
ESP.restart();
}
}
//Open the front gate
if (strcmp(topic, "setTargetDoorState/FRONTGATE") == 0)
{
if (!strncmp((char *)payload, "O", length))
{
openFrontGate();
}
else
{
client.publish("getTargetDoorState/FRONTGATE", "C"); Serial.println("Back Gate closed");
client.publish("getCurrentDoorState/FRONTGATE", "Closing"); Serial.println("Back Gate closing");
client.publish("getCurrentDoorState/FRONTGATE", "Closed"); Serial.println("Back Gate closed");
}
}
//Open the back gate
if (strcmp(topic, "setTargetDoorState/BACKGATE") == 0)
{
if (!strncmp((char *)payload, "O", length))
{
openBackGate();
}
else
{
client.publish("getTargetDoorState/BACKGATE", "C"); Serial.println("Back Gate closed");
client.publish("getCurrentDoorState/BACKGATE", "Closing"); Serial.println("Back Gate closing");
client.publish("getCurrentDoorState/BACKGATE", "Closed"); Serial.println("Back Gate closed");
}
}
Serial.println("");
}
void loop() {
client.loop();
ArduinoOTA.handle();
//Check connection every FIVE minutes
currentMillisStatus = millis(); //get the current "time"
if (currentMillisStatus - startMillisStatus >= fiveMinutes) //test whether the period has elapsed
{
if ((WiFi.status() == WL_CONNECTION_LOST) || (WiFi.status() == WL_DISCONNECTED))
{
Serial.println("WiFi connection lost, connecting again");
startConnection();
client.publish("status/GATES", "WiFi connection lost, connected again");
}
if (client.connected() == false)
{
Serial.println("MQTT connection lost, connecting again");
connectToMQTT();
client.publish("status/GATES", "MQTT connection lost, connected again");
}
client.publish("getTargetDoorState/FRONTGATE", "C");
client.publish("getTargetDoorState/BACKGATE", "C");
startMillisStatus = currentMillisStatus; //IMPORTANT
}
}
So, this is my code. In basically every project I use the same base, essentially it connects to the WiFi and to a MQTT server and wait for a MQTT message to arrive
The loop function just listens to incoming messages and every five minutes checks the connection, when a message arrive the callback() function get executed and based on the topic and payload it performs some actions.
I created some functions to avoid duplicate code and (hopefully) simplify it.
The wait() function allows me to create a delay without blocking the background functions of the ESP8266 and to stay connected to WiFi and the MQTT server. The ledBlink() function has the same principle and allows me to blink the onboard led without duplicating the code.
This is the basis for all my projects, for this project I have added two functions that allow me to open the two gates from my phone. By calling the functions openFrontGate() and openBackGate(), the contacts of two relays are closed which open the two gates, then a fake closing feedback is sent to my mobile phone.
After about two months of operation, the contacts of the two relays no longer close but I receive the messages that the gates are opening (example: client.publish("getCurrentDoorState/FRONTGATE", "Opening");)
These are the only information on the problem that I have been able to find. I hope I was clear and I apologize if I made any mistakes because English is not my native language.