#include <Arduino.h>
#include <DHT.h>
#include <PubSubClient.h>
#include <WiFiManager.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <Wire.h>
#include "esp_system.h"
#include "esp_wifi.h"
// Initialize with default values (can be overridden by user configuration)
char mqttServer[40] = "192.168.1.100";
int mqttPort = 1883;
char mqttUsername[40] = "";
char mqttPassword[40] = "";
char mqttClientId[] = "ESP-VTOXI";
// #define BEEPER_PIN D3
// #define DHT1_PIN D4
// #define DHT2_PIN D5
// #define DHT3_PIN D6
// #define DHT4_PIN D7
#define BEEPER_PIN 4 // GPIO4 for the beeper
#define DHT1_PIN 17 // GPIO17 for DHT1
#define DHT2_PIN 18 // GPIO18 for DHT2
#define DHT3_PIN 19 // GPIO19 for DHT3
#define DHT4_PIN 21 // GPIO21 for DHT4
#define DHT_TYPE DHT11
DHT dht1(DHT1_PIN, DHT_TYPE);
DHT dht2(DHT2_PIN, DHT_TYPE);
DHT dht3(DHT3_PIN, DHT_TYPE);
DHT dht4(DHT4_PIN, DHT_TYPE);
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SDA_PIN 21 // I2C SDA pin for ESP32
#define SCL_PIN 22 // I2C SCL pin for ESP32
#define SSD1306_I2C_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
unsigned long previousMillis = 0;
const long interval = 5 * 1000;
WiFiClient espClient;
PubSubClient client(espClient);
uint64_t uniqueId;
// Function forward declarations
void generateMqttClientId();
void initializeHardware();
bool initializeDisplay();
void displayScrollingText(String data);
void connectToWiFi();
void connectToMQTT();
void handleMQTT();
void callback(char *topic, byte *payload, unsigned int length);
void processPingMessage(const char *topic, const char *payload);
void reconnect();
void readAndPublishSensorData();
void publishSensorData(const char *topic, const String &data);
void setup()
{
initializeHardware();
generateMqttClientId();
connectToWiFi();
connectToMQTT();
}
void loop()
{
handleMQTT();
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
readAndPublishSensorData(); // Perform sensor data reading and publishing
}
}
void generateMqttClientId()
{
snprintf(mqttClientId, sizeof(mqttClientId), "ESP-%llu", uniqueId);
}
void initializeHardware()
{
Serial.begin(115200);
uint8_t mac[6];
esp_read_mac(mac, ESP_MAC_WIFI_STA);
uniqueId = ESP.getEfuseMac();
Serial.print("Unique Chip ID: ");
Serial.println(uniqueId);
pinMode(BUILTIN_LED, OUTPUT); // Initialize the LED pin as an output
pinMode(BEEPER_PIN, OUTPUT); // Beeper
if (!initializeDisplay())
{
Serial.println(F("SSD1306 initialization failed"));
}
}
bool initializeDisplay()
{
if (!display.begin(SSD1306_I2C_ADDRESS, SDA_PIN, SCL_PIN))
{
return false; // Return false if display initialization fails
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
displayScrollingText("Pins: D4 - DHT#1, D5 - DHT#2, D6 - DHT#3, D7 - DHT#4, D3: Beeper");
return true;
}
void displayScrollingText(String data)
{
String textToScroll = data;
int textWidth = textToScroll.length() * 6;
for (int x = 0; x > -textWidth; x--)
{
display.clearDisplay();
display.setCursor(x, 0);
display.println(textToScroll);
display.display();
delay(50); // Adjust the scrolling speed by changing the delay value
}
}
void connectToWiFi()
{
WiFiManager wifiManager;
WiFiManagerParameter custom_mqtt_server("mqtt_server", "MQTT Server", mqttServer, 40);
WiFiManagerParameter custom_mqtt_port("mqtt_port", "MQTT Port", String(mqttPort).c_str(), 5);
WiFiManagerParameter custom_mqtt_username("mqtt_username", "MQTT Username", mqttUsername, 40);
WiFiManagerParameter custom_mqtt_password("mqtt_password", "MQTT Password", mqttPassword, 40);
wifiManager.addParameter(&custom_mqtt_server);
wifiManager.addParameter(&custom_mqtt_port);
wifiManager.addParameter(&custom_mqtt_username);
wifiManager.addParameter(&custom_mqtt_password);
wifiManager.autoConnect("ESP-" + uniqueId);
strncpy(mqttServer, custom_mqtt_server.getValue(), sizeof(mqttServer));
mqttPort = atoi(custom_mqtt_port.getValue());
strncpy(mqttUsername, custom_mqtt_username.getValue(), sizeof(mqttUsername));
strncpy(mqttPassword, custom_mqtt_password.getValue(), sizeof(mqttPassword));
}
void connectToMQTT()
{
client.setServer(mqttServer, mqttPort);
client.setCallback(callback);
}
void handleMQTT()
{
if (!client.connected())
{
reconnect();
}
client.loop();
}
void reconnect()
{
while (!client.connected())
{
Serial.println("Connecting to MQTT...");
displayScrollingText("Connecting to MQTT...");
if (client.connect(mqttClientId, mqttUsername, mqttPassword))
{
Serial.println("Connected to MQTT");
displayScrollingText("Connected to MQTT");
char pingTopic[64];
snprintf(pingTopic, sizeof(pingTopic), "%llu/ping", uniqueId);
client.subscribe(pingTopic);
}
else
{
Serial.print("Failed, rc=");
Serial.print(client.state());
Serial.println(" Retrying in 5 seconds...");
displayScrollingText("MQTT connection Failed, Retry in 5 seconds...");
delay(5000);
}
}
}
void callback(char *topic, byte *payload, unsigned int length)
{
// Handle MQTT messages here
char pingTopic[64];
snprintf(pingTopic, sizeof(pingTopic), "%llu/ping", uniqueId);
if (strcmp(topic, pingTopic) == 0) // 0 means both strings are equal
{
processPingMessage(topic, (const char *)payload);
}
}
void processPingMessage(const char *topic, const char *payload)
{
if (strcmp(payload, "1") == 0)
{
// If the payload is "1", blink the LED
digitalWrite(BUILTIN_LED, HIGH); // Turn the LED on
tone(BEEPER_PIN, 1000);
delay(100);
digitalWrite(BUILTIN_LED, LOW); // Turn the LED off
noTone(BEEPER_PIN); // Turn off the beep
}
}
void readAndPublishSensorData()
{
char statusTopic[64];
char temperatureTopic[64];
char humidityTopic[64];
float temperature1 = dht1.readTemperature();
float humidity1 = dht1.readHumidity();
float temperature2 = dht2.readTemperature();
float humidity2 = dht2.readHumidity();
float temperature3 = dht3.readTemperature();
float humidity3 = dht3.readHumidity();
float temperature4 = dht4.readTemperature();
float humidity4 = dht4.readHumidity();
if (!isnan(temperature1) && !isnan(humidity1))
{
snprintf(temperatureTopic, sizeof(temperatureTopic), "%llu/temperature/1", uniqueId);
snprintf(humidityTopic, sizeof(humidityTopic), "%llu/humidity/1", uniqueId);
String temperatureString = String(temperature1, 1);
String humidityString = String(humidity1, 1);
publishSensorData(temperatureTopic, temperatureString);
publishSensorData(humidityTopic, humidityString);
}
else
{
snprintf(statusTopic, sizeof(statusTopic), "%llu/status/1", uniqueId);
publishSensorData(statusTopic, "Failed to read DHT1 sensor data.");
Serial.println("Failed to read DHT1 sensor data.");
}
if (!isnan(temperature2) && !isnan(humidity2))
{
snprintf(temperatureTopic, sizeof(temperatureTopic), "%llu/temperature/2", uniqueId);
snprintf(humidityTopic, sizeof(humidityTopic), "%llu/humidity/2", uniqueId);
String temperatureString = String(temperature2, 1);
String humidityString = String(humidity2, 1);
publishSensorData(temperatureTopic, temperatureString);
publishSensorData(humidityTopic, humidityString);
}
else
{
snprintf(statusTopic, sizeof(statusTopic), "%llu/status/2", uniqueId);
publishSensorData(statusTopic, "Failed to read DHT2 sensor data.");
Serial.println("Failed to read DHT2 sensor data.");
}
if (!isnan(temperature3) && !isnan(humidity3))
{
snprintf(temperatureTopic, sizeof(temperatureTopic), "%llu/temperature/3", uniqueId);
snprintf(humidityTopic, sizeof(humidityTopic), "%llu/humidity/3", uniqueId);
String temperatureString = String(temperature3, 1);
String humidityString = String(humidity3, 1);
publishSensorData(temperatureTopic, temperatureString);
publishSensorData(humidityTopic, humidityString);
}
else
{
snprintf(statusTopic, sizeof(statusTopic), "%llu/status/3", uniqueId);
publishSensorData(statusTopic, "Failed to read DHT3 sensor data.");
Serial.println("Failed to read DHT3 sensor data.");
}
if (!isnan(temperature4) && !isnan(humidity4))
{
snprintf(temperatureTopic, sizeof(temperatureTopic), "%llu/temperature/4", uniqueId);
snprintf(humidityTopic, sizeof(humidityTopic), "%llu/humidity/4", uniqueId);
String temperatureString = String(temperature4, 1);
String humidityString = String(humidity4, 1);
publishSensorData(temperatureTopic, temperatureString);
publishSensorData(humidityTopic, humidityString);
}
else
{
snprintf(statusTopic, sizeof(statusTopic), "%llu/status/4", uniqueId);
publishSensorData(statusTopic, "Failed to read DHT4 sensor data.");
Serial.println("Failed to read DHT4 sensor data.");
}
}
void publishSensorData(const char *topic, const String &data)
{
if (client.publish(topic, data.c_str()))
{
Serial.println("Data published successfully on topic: " + String(topic));
}
else
{
Serial.println("Failed to publish data on topic: " + String(topic));
}
}