/**************************************************************************************************************************************************
* File name : ESP32_HA_Discovery.ino
* Compiler :
* Autor : VIGASAN
* Created : 27/01/2023
* Modified :
* Last modified :
* Description : https://github.com/vigasan/HA_MQTT_Discovery/blob/main/ESP32_HA_DiscoveryVid.ino
* Other info : Discovery MQTT Device Example
**************************************************************************************************************************************************/
#include <WiFi.h>
#include "DHT.h"
#include <PubSubClient.h>
#include <ArduinoJson.h>
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
/*------------------------------------Local definitions------------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
#define PERIOD_MILLSEC_1000 1000
#define PERIOD_MILLSEC_500 500
#define PERIOD_MILLSEC_250 250
#define KEEPALIVE 60
#define DHTTYPE DHT22
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
/*------------------------------------I/O Definitions--------------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
const int IN_DETECT = 5;
const int DHTPIN = 22;
const int RELAYPIN = 35;
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
/*------------------------------------ Configuration --------------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
const char* g_ssid = "Wokwi-GUEST";
const char* g_password = "";
const char* g_mqtt_server = "rochasnet.ddns-intelbras.com.br"; // MQTT Server IP, same of Home Assistant
const char* g_mqttUser = "aluno"; // MQTT Server User Name
const char* g_mqttPsw = "teste123"; // MQTT Server password
int g_mqttPort = 1883; // MQTT Server Port
// Variable used for MQTT Discovery
const char* g_deviceModel = "ESP32 Device"; // Hardware Model
const char* g_swVersion = "1.0"; // Firmware Version
const char* g_manufacturer = "Aluizio Rocha"; // Manufacturer Name
String g_deviceName = "AluizioRocha"; // Device Name
String g_mqttStatusTopic = "homeassistant/" + g_deviceName; // MQTT Topic
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
/*------------------------------------Public variables-------------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
WiFiClient g_WiFiClient;
PubSubClient g_mqttPubSub(g_mqtt_server, g_mqttPort, g_WiFiClient);
unsigned long g_Time = 0;
int g_count = 0;
int g_input_Door;
int g_old_input_Door = 0;
String g_strDoorStatus;
int g_mqttCounterConn = 0;
float g_Humidity = 0.0;
float g_Temperature = 0.0;
bool g_InitSystem = true;
String g_UniqueId;
bool g_SendMqttData = false;
DHT g_dht(DHTPIN, DHTTYPE);
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
/*------------------------------------ SETUP ----------------------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
void setup()
{
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input output Pin definitions
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
pinMode(IN_DETECT, INPUT_PULLUP);
pinMode(RELAYPIN, OUTPUT);
g_dht.begin();
Serial.begin(115200);
delay(500);
Serial.println("");
Serial.println("");
Serial.println("----------------------------------------------");
Serial.print("MODEL: ");
Serial.println(g_deviceModel);
Serial.print("DEVICE: ");
Serial.println(g_deviceName);
Serial.print("SW Rev: ");
Serial.println(g_swVersion);
Serial.println("----------------------------------------------");
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Wifi Init
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
byte mac[6];
delay(100);
// We start by connecting to a WiFi network
Serial.print("Connecting to ");
Serial.println(g_ssid);
WiFi.begin(g_ssid, g_password, 6);
WiFi.macAddress(mac);
g_UniqueId = String(mac[0],HEX) +String(mac[1],HEX) +String(mac[2],HEX) +String(mac[3],HEX) + String(mac[4],HEX) + String(mac[5],HEX);
Serial.print("Unique ID: ");
Serial.println(g_UniqueId);
while(WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.print(".");
}
Serial.println("");
if(WiFi.status() == WL_CONNECTED)
{
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MQTT Init
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
g_mqttPubSub.setServer(g_mqtt_server, g_mqttPort);
g_mqttPubSub.setBufferSize(512);
//g_mqttPubSub.setKeepAlive(KEEPALIVE);
//g_mqttPubSub.setCallback(MqttReceiverCallback);
}
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
/*------------------------------------ LOOP -----------------------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
void loop()
{
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MQTT Connection
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(WiFi.status() == WL_CONNECTED)
{
if(!g_mqttPubSub.connected())
MqttReconnect();
else
g_mqttPubSub.loop();
}
if(g_InitSystem)
{
delay(100);
g_InitSystem = false;
Serial.println("INIT SYSTEM...");
MqttHomeAssistantDiscovery(); // Send Discovery Data
}
if(millis() - g_Time > PERIOD_MILLSEC_500) // Every 500 [msec]
{
g_Time = millis();
////////////////////////////////////////////////////////////////
// DIGITAL INPUTS
////////////////////////////////////////////////////////////////
g_input_Door = digitalRead(IN_DETECT);
if(g_input_Door == 0)
g_strDoorStatus = "ON";
else
g_strDoorStatus = "OFF";
if(g_old_input_Door != g_input_Door)
{
g_old_input_Door = g_input_Door;
g_SendMqttData = true;
Serial.print("Door Status: ");
Serial.println(g_strDoorStatus);
}
if(g_count++ == 20 || g_SendMqttData) // Every 10 [sec] or if input status changed
{
g_count = 0;
////////////////////////////////////////////////////////////////
// TEMPERATURE HUMIDITY
////////////////////////////////////////////////////////////////
g_Temperature = g_dht.readTemperature();
g_Humidity = g_dht.readHumidity();
Serial.print("Temperature: ");
Serial.print(g_Temperature);
Serial.println(" °C");
Serial.print("Humidity: ");
Serial.print(g_Humidity);
Serial.println(" %");
g_SendMqttData = true;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SEND MQTT DATA
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(g_SendMqttData == true)
{
StaticJsonDocument<200> payload;
payload["temp"] = g_Temperature;
payload["hum"] = g_Humidity;
payload["inputstatus"] = g_strDoorStatus;
String strPayload;
serializeJson(payload, strPayload);
if(g_mqttPubSub.connected())
{
Serial.print("Publishing on MQTT topic: ");
Serial.println(g_mqttStatusTopic);
Serial.println("Message:");
Serial.println(strPayload);
Serial.println(" ");
if (!g_mqttPubSub.publish(g_mqttStatusTopic.c_str(), strPayload.c_str(), true))
Serial.println("Publish failed!!");
g_SendMqttData = false;
}
}
}
}
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
/*------------------------------------ Public Functions -----------------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------------------------------------------------------------------*/
void MqttReconnect()
{
// Loop until we're reconnected
while (!g_mqttPubSub.connected() && (g_mqttCounterConn++ < 4))
{
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (g_mqttPubSub.connect(g_deviceName.c_str(), g_mqttUser, g_mqttPsw))
{
Serial.println("connected");
// Subscribe
//g_mqttPubSub.subscribe("homeassistant/status");
delay(100);
} else
{
Serial.print("failed, rc=");
Serial.print(g_mqttPubSub.state());
Serial.println(" try again in 1 seconds");
delay(1000);
}
}
g_mqttCounterConn = 0;
}
void MqttPublishMessage(String topic, String payload)
{
if(!g_mqttPubSub.connected())
MqttReconnect();
Serial.print("Publishing on MQTT topic: ");
Serial.println(topic);
Serial.println("Message:");
Serial.println(payload);
if (!g_mqttPubSub.publish(topic.c_str(), payload.c_str(), true))
Serial.println("Publish failed!!");
}
void MqttHomeAssistantDiscovery()
{
String discoveryTopic;
String strPayload;
Serial.println("SEND HOME ASSISTANT DISCOVERY!!!");
StaticJsonDocument<512> payload;
JsonObject device;
JsonArray identifiers;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Temperature
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
discoveryTopic = "homeassistant/sensor/" + g_deviceName + "/temp/config";
payload["name"] = g_deviceName + ".temp";
payload["uniq_id"] = g_UniqueId + "_temp";
payload["stat_t"] = g_mqttStatusTopic;
payload["dev_cla"] = "temperature";
payload["val_tpl"] = "{{ value_json.temp | is_defined }}";
payload["unit_of_meas"] = "°C";
device = payload.createNestedObject("device");
device["name"] = g_deviceName;
device["model"] = g_deviceModel;
device["sw_version"] = g_swVersion;
device["manufacturer"] = g_manufacturer;
identifiers = device.createNestedArray("identifiers");
identifiers.add(g_UniqueId);
serializeJson(payload, strPayload);
MqttPublishMessage(discoveryTopic, strPayload);
delay(1000);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Humidity
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
payload.clear();
device.clear();
identifiers.clear();
strPayload.clear();
discoveryTopic = "homeassistant/sensor/" + g_deviceName + "/hum/config";
payload["name"] = g_deviceName + ".hum";
payload["uniq_id"] = g_UniqueId + "_hum";
payload["stat_t"] = g_mqttStatusTopic;
payload["dev_cla"] = "humidity";
payload["val_tpl"] = "{{ value_json.hum | is_defined }}";
payload["unit_of_meas"] = "%";
device = payload.createNestedObject("device");
device["name"] = g_deviceName;
device["model"] = g_deviceModel;
device["sw_version"] = g_swVersion;
device["manufacturer"] = g_manufacturer;
identifiers = device.createNestedArray("identifiers");
identifiers.add(g_UniqueId);
serializeJson(payload, strPayload);
MqttPublishMessage(discoveryTopic, strPayload);
delay(1000);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Binary Door
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
payload.clear();
device.clear();
identifiers.clear();
strPayload.clear();
discoveryTopic = "homeassistant/binary_sensor/" + g_deviceName + "/door/config";
payload["name"] = g_deviceName + ".door";
payload["uniq_id"] = g_UniqueId + "_door";
payload["stat_t"] = g_mqttStatusTopic;
payload["dev_cla"] = "door";
payload["val_tpl"] = "{{ value_json.inputstatus | is_defined }}";
device = payload.createNestedObject("device");
device["name"] = g_deviceName;
device["model"] = g_deviceModel;
device["sw_version"] = g_swVersion;
device["manufacturer"] = g_manufacturer;
identifiers = device.createNestedArray("identifiers");
identifiers.add(g_UniqueId);
serializeJson(payload, strPayload);
MqttPublishMessage(discoveryTopic, strPayload);
}
void MqttReceiverCallback(char* topic, byte* inFrame, unsigned int length)
{
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
byte state = 0;
String messageTemp;
for (int i = 0; i < length; i++)
{
Serial.print((char)inFrame[i]);
messageTemp += (char)inFrame[i];
}
Serial.println();
if(String(topic) == String("homeassistant/status"))
{
if(messageTemp == "online")
MqttHomeAssistantDiscovery();
}
}