#include "DHT.h"
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <time.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <ESP32Servo.h>
const char *WIFI_SSID = "Wokwi-GUEST";
const char *WIFI_PASSWORD = "";
const char *TAGOIO_SERVER = "api.us-e1.tago.io/data";
const char *TAGOIO_TOKEN = "8ed05452-c90e-433f-bc04-9e2779f403a4";
const char *MQTT_BROKER = "c156df48019b4a9ea5e3f6e0a9f612bd.s1.eu.hivemq.cloud";
const char *MQTT_CLIENT_ID = "ESP32_Industrial_Monitor";
const char *MQTT_USER = "lucifer_esp32";
const char *MQTT_PASSWORD = "Admin123";
const char *MQTT_TOPIC_DATA = "industrial/warehouse/data";
const char *MQTT_TOPIC_COMMAND = "industrial/warehouse/command";
const char *NTP_SERVER = "pool.ntp.org";
const long GMT_OFFSET_SEC = 0;
const int DAYLIGHT_OFFSET_SEC = 0;
const int DHT_PIN = 15;
const int BUZZER_PIN = 26;
const int BUTTON_TEST = 25;
const int BUTTON_MANUAL = 27;
const int LED_GREEN = 2;
const int LED_RED = 13;
const int SERVO_PIN = 18;
const float TEMPERATURE_THRESHOLD = 37.0;
const float HUMIDITY_THRESHOLD = 70.0;
const int SENSOR_READ_INTERVAL = 7000;
const int MQTT_PUBLISH_INTERVAL = 7000;
const int SERIAL_BAUD_RATE = 115200;
const int MQTT_PORT = 8883;
const int SERVO_NORMAL_POSITION = 0;
const int SERVO_COOLING_POSITION = 180;
const int BUZZER_FREQUENCY = 1000;
const int ALERT_DURATION = 10000;
const int DEBOUNCE_DELAY = 50;
const int SERVO_MOVE_DELAY = 2500;
const int BUZZER_ON_TIME = 500;
const int BUZZER_OFF_TIME = 1000;
const unsigned long MQTT_CHECK_INTERVAL = 60000;
const float TEST_TEMPERATURE = 45.0;
const float TEST_HUMIDITY = 85.0;
const unsigned long TEST_MODE_DURATION = 60000;
#define DHT_TYPE DHT22
const char* hivemq_root_ca = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" \
"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" \
"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" \
"WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" \
"ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" \
"MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n" \
"h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n" \
"0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n" \
"A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n" \
"T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n" \
"B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n" \
"B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n" \
"KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n" \
"OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n" \
"jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n" \
"qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n" \
"rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" \
"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n" \
"hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" \
"ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n" \
"3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n" \
"NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n" \
"ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n" \
"TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n" \
"jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n" \
"oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n" \
"4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n" \
"mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n" \
"emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" \
"-----END CERTIFICATE-----\n" ;
DHT temperatureSensor(DHT_PIN, DHT_TYPE);
WiFiClientSecure secureWifiClient;
PubSubClient mqttClient(secureWifiClient);
Servo coolingServo;
bool alertActive = false;
bool coolingMode = false;
bool systemOK = true;
bool testModeActive = false;
bool manualModeActive = false;
unsigned long lastSensorRead = 0;
unsigned long lastMqttCheck = 0;
unsigned long lastMqttPublish = 0;
unsigned long lastTagoSend = 0;
unsigned long lastServoMove = 0;
unsigned long testModeStartTime = 0;
bool buzzerState = false;
unsigned long lastBuzzerToggle = 0;
bool servoNeedsMove = false;
int desiredServoPosition = SERVO_NORMAL_POSITION;
unsigned long servoForceTime = 0;
bool buttonTestPressed = false;
bool buttonManualPressed = false;
int currentServoPosition = SERVO_NORMAL_POSITION;
int targetServoPosition = SERVO_NORMAL_POSITION;
bool servoMoving = false;
void setup() {
initializeSerial();
initializePins();
initializeServos();
temperatureSensor.begin();
debugSystemStatus();
connectToWiFi();
configureSecureConnection();
mqttClient.setServer(MQTT_BROKER, MQTT_PORT);
mqttClient.setBufferSize(1024);
mqttClient.setCallback(onMqttMessage);
configTime(GMT_OFFSET_SEC, DAYLIGHT_OFFSET_SEC, NTP_SERVER);
Serial.println("Industrial Temperature Monitoring System Initialized");
delay(2000);
Serial.println("DHT22 Sensor initialized and ready");
testServo();
updateSystemStatusLEDs();
}
void loop() {
handleButtonInput();
unsigned long currentTime = millis();
if (currentTime - lastMqttCheck >= MQTT_CHECK_INTERVAL) {
if (!mqttClient.connected()) {
Serial.println("MQTT disconnected, attempting reconnection...");
connectToMqttBroker();
}
lastMqttCheck = currentTime;
}
mqttClient.loop();
handleServoMovement(currentTime);
handleIntermittentBuzzer(currentTime);
if (testModeActive && (currentTime - testModeStartTime >= TEST_MODE_DURATION)) {
exitTestMode();
}
if (currentTime - lastSensorRead >= SENSOR_READ_INTERVAL) {
processSensorReading();
debugServoPosition();
lastSensorRead = currentTime;
}
if (currentTime - lastMqttPublish >= MQTT_PUBLISH_INTERVAL) {
if (mqttClient.connected()) {
publishDataToMqtt();
}
lastMqttPublish = currentTime;
}
delay(50);
}
void onMqttMessage(char* topic, byte* payload, unsigned int length) {
String message = "";
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.print("MQTT message received on topic: ");
Serial.println(topic);
Serial.print("Message: ");
Serial.println(message);
if (String(topic) == MQTT_TOPIC_COMMAND) {
handleMqttCommand(message);
}
}
void handleMqttCommand(String message) {
DynamicJsonDocument doc(256);
DeserializationError error = deserializeJson(doc, message);
if (error) {
Serial.print("JSON parsing failed: ");
Serial.println(error.c_str());
return;
}
if (doc.containsKey("command")) {
String command = doc["command"];
Serial.print("Command received: ");
Serial.println(command);
if (command == "open") {
Serial.println("Remote command: Opening servo to 180 degrees");
forceServoPosition(SERVO_COOLING_POSITION);
coolingMode = true;
manualModeActive = true;
} else if (command == "close") {
Serial.println("Remote command: Closing servo to 0 degrees");
forceServoPosition(SERVO_NORMAL_POSITION);
coolingMode = false;
manualModeActive = false;
} else {
Serial.println("Unknown command received");
}
}
}
void handleServoMovement(unsigned long currentTime) {
if (servoNeedsMove && (currentTime - servoForceTime >= 100)) {
Serial.println("FORCING SERVO MOVEMENT - AGGRESSIVE MODE!");
coolingServo.detach();
delay(10);
coolingServo.attach(SERVO_PIN);
delay(10);
for (int i = 0; i < 5; i++) {
coolingServo.write(desiredServoPosition);
delay(20);
}
currentServoPosition = desiredServoPosition;
servoNeedsMove = false;
Serial.print("SERVO FORCED TO POSITION: ");
Serial.println(desiredServoPosition);
}
}
void handleIntermittentBuzzer(unsigned long currentTime) {
if (alertActive && !manualModeActive) {
if (buzzerState) {
if (currentTime - lastBuzzerToggle >= BUZZER_ON_TIME) {
noTone(BUZZER_PIN);
buzzerState = false;
lastBuzzerToggle = currentTime;
Serial.println("Buzzer OFF (intermittent)");
}
} else {
if (currentTime - lastBuzzerToggle >= BUZZER_OFF_TIME) {
tone(BUZZER_PIN, BUZZER_FREQUENCY);
buzzerState = true;
lastBuzzerToggle = currentTime;
Serial.println("Buzzer ON (intermittent)");
}
}
} else {
if (buzzerState) {
noTone(BUZZER_PIN);
buzzerState = false;
Serial.println("Buzzer OFF (alert cleared or manual mode)");
}
}
}
void initializeSerial() {
Serial.begin(SERIAL_BAUD_RATE);
Serial.println();
Serial.println("===============================");
Serial.println("Industrial Temperature & Humidity Monitor");
Serial.print("Temperature Threshold: ");
Serial.println(TEMPERATURE_THRESHOLD);
Serial.print("Humidity Threshold: ");
Serial.println(HUMIDITY_THRESHOLD);
Serial.println("Test Mode: Press button to simulate alert conditions");
Serial.println("Manual Mode: Press manual button to toggle servo position");
Serial.println("Servo Alert Position: 180 degrees (cooling activated)");
Serial.println("Servo Normal Position: 0 degrees (normal operation)");
Serial.println("===============================");
}
void initializePins() {
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_RED, OUTPUT);
pinMode(BUTTON_TEST, INPUT_PULLUP);
pinMode(BUTTON_MANUAL, INPUT_PULLUP);
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_RED, LOW);
Serial.println("Pins initialized successfully (using internal pull-ups)");
Serial.println("LED System: Green (Pin 2) - System OK, Red (Pin 13) - Alert/Error");
Serial.println("Button Test: Pin 25 - Test Mode (simulates alert conditions)");
Serial.println("Button Manual: Pin 27 - Manual servo control");
delay(100);
Serial.print("Test Button (Pin 25) state: ");
Serial.println(digitalRead(BUTTON_TEST) ? "HIGH (not pressed)" : "LOW (pressed)");
Serial.print("Manual Button (Pin 27) state: ");
Serial.println(digitalRead(BUTTON_MANUAL) ? "HIGH (not pressed)" : "LOW (pressed)");
}
void updateSystemStatusLEDs() {
if (systemOK && !alertActive && !manualModeActive) {
digitalWrite(LED_GREEN, HIGH);
digitalWrite(LED_RED, LOW);
Serial.println("LED Status: GREEN ON (System Normal)");
} else {
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_RED, HIGH);
Serial.println("LED Status: RED ON (Alert/Error/Manual Active)");
}
}
void forceServoPosition(int angle) {
if (angle < 0) angle = 0;
if (angle > 180) angle = 180;
Serial.print("AGGRESSIVE SERVO MOVE from ");
Serial.print(currentServoPosition);
Serial.print(" to ");
Serial.print(angle);
Serial.println(" degrees");
desiredServoPosition = angle;
servoNeedsMove = true;
servoForceTime = millis();
coolingServo.write(angle);
currentServoPosition = angle;
Serial.print("Servo movement SCHEDULED and ATTEMPTED: ");
Serial.println(angle);
}
void setServoPosition(int angle) {
if (angle < 0) angle = 0;
if (angle > 180) angle = 180;
Serial.print("Moving servo from ");
Serial.print(currentServoPosition);
Serial.print(" to ");
Serial.print(angle);
Serial.println(" degrees");
coolingServo.write(angle);
currentServoPosition = angle;
lastServoMove = millis();
Serial.print("Servo position set to: ");
Serial.println(angle);
}
void initializeServos() {
Serial.println("Initializing servo...");
coolingServo.attach(SERVO_PIN);
delay(1000);
setServoPosition(SERVO_NORMAL_POSITION);
delay(SERVO_MOVE_DELAY);
Serial.println("Servo initialized successfully at pin 18");
Serial.print("Initial servo position: ");
Serial.println(SERVO_NORMAL_POSITION);
}
void testServo() {
Serial.println("Testing servo movement and LED system...");
digitalWrite(LED_RED, HIGH);
digitalWrite(LED_GREEN, LOW);
Serial.println("Test 1: Moving to ALERT position (180 degrees) - RED LED ON");
setServoPosition(SERVO_COOLING_POSITION);
delay(SERVO_MOVE_DELAY);
digitalWrite(LED_RED, LOW);
digitalWrite(LED_GREEN, HIGH);
Serial.println("Test 2: Moving to NORMAL position (0 degrees) - GREEN LED ON");
setServoPosition(SERVO_NORMAL_POSITION);
delay(SERVO_MOVE_DELAY);
Serial.println("Test 3: Moving to MIDDLE position (90 degrees)");
setServoPosition(90);
delay(SERVO_MOVE_DELAY);
Serial.println("Test 4: Returning to NORMAL position (0 degrees)");
setServoPosition(SERVO_NORMAL_POSITION);
delay(SERVO_MOVE_DELAY);
systemOK = true;
updateSystemStatusLEDs();
Serial.println("Servo test completed successfully!");
delay(1000);
}
void connectToWiFi() {
Serial.print("Connecting to WiFi: ");
Serial.println(WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected successfully!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
}
void configureSecureConnection() {
Serial.println("Configuring secure TLS connection...");
secureWifiClient.setCACert(hivemq_root_ca);
Serial.println("TLS configuration completed");
}
void ensureMqttConnection() {
while (!mqttClient.connected()) {
connectToMqttBroker();
}
}
bool connectToMqttBroker() {
Serial.print("Connecting to MQTT broker...");
if (mqttClient.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {
Serial.println(" SUCCESS!");
Serial.println("Connected to HiveMQ Cloud with TLS");
if (mqttClient.subscribe(MQTT_TOPIC_COMMAND)) {
Serial.print("Subscribed to command topic: ");
Serial.println(MQTT_TOPIC_COMMAND);
} else {
Serial.println("Failed to subscribe to command topic");
}
return true;
}
Serial.print(" FAILED! Error code: ");
Serial.println(mqttClient.state());
return false;
}
void handleButtonInput() {
handleTestButton();
handleManualButton();
}
void handleTestButton() {
static unsigned long lastButtonChange = 0;
static bool lastButtonState = HIGH;
unsigned long currentTime = millis();
bool currentButtonState = digitalRead(BUTTON_TEST);
if (currentButtonState != lastButtonState) {
lastButtonChange = currentTime;
}
if ((currentTime - lastButtonChange) > DEBOUNCE_DELAY) {
if (currentButtonState == LOW && !buttonTestPressed) {
buttonTestPressed = true;
Serial.println("=== TEST BUTTON PRESSED ===");
toggleTestMode();
}
else if (currentButtonState == HIGH && buttonTestPressed) {
buttonTestPressed = false;
Serial.println("Test button released");
}
}
lastButtonState = currentButtonState;
}
void handleManualButton() {
static unsigned long lastManualButtonChange = 0;
static bool lastManualButtonState = HIGH;
unsigned long currentTime = millis();
bool currentManualButtonState = digitalRead(BUTTON_MANUAL);
if (currentManualButtonState != lastManualButtonState) {
lastManualButtonChange = currentTime;
}
if ((currentTime - lastManualButtonChange) > DEBOUNCE_DELAY) {
if (currentManualButtonState == LOW && !buttonManualPressed) {
buttonManualPressed = true;
Serial.println("=== MANUAL BUTTON PRESSED ===");
toggleManualServoControl();
}
else if (currentManualButtonState == HIGH && buttonManualPressed) {
buttonManualPressed = false;
Serial.println("Manual button released");
}
}
lastManualButtonState = currentManualButtonState;
}
void toggleManualServoControl() {
manualModeActive = true;
if (currentServoPosition == SERVO_NORMAL_POSITION) {
Serial.println("Manual servo control: Opening to 180 degrees");
forceServoPosition(SERVO_COOLING_POSITION);
coolingMode = true;
} else {
Serial.println("Manual servo control: Closing to 0 degrees");
forceServoPosition(SERVO_NORMAL_POSITION);
coolingMode = false;
manualModeActive = false;
}
updateSystemStatusLEDs();
Serial.print("Manual Mode Active: ");
Serial.println(manualModeActive ? "YES" : "NO");
Serial.print("Servo Position: ");
Serial.println(currentServoPosition);
}
void toggleTestMode() {
if (testModeActive) {
exitTestMode();
} else {
enterTestMode();
}
}
void enterTestMode() {
testModeActive = true;
testModeStartTime = millis();
Serial.println("ENTERING TEST MODE");
Serial.println("Simulating alert conditions for 30 seconds...");
Serial.print("Test Temperature: ");
Serial.print(TEST_TEMPERATURE);
Serial.println(" C");
Serial.print("Test Humidity: ");
Serial.print(TEST_HUMIDITY);
Serial.println("%");
Serial.println("This will trigger the alert system automatically");
Serial.println("Expected: Servo should move to 180 degrees and LED should turn RED");
}
void exitTestMode() {
testModeActive = false;
Serial.println("EXITING TEST MODE");
Serial.println("Returning to normal sensor readings...");
processSensorReading();
}
void processSensorReading() {
if (manualModeActive) {
Serial.println("Manual mode active - skipping automatic sensor processing");
return;
}
float temperature, humidity;
if (testModeActive) {
temperature = TEST_TEMPERATURE;
humidity = TEST_HUMIDITY;
Serial.println("Using TEST VALUES (simulated alert conditions)");
} else {
temperature = temperatureSensor.readTemperature();
humidity = temperatureSensor.readHumidity();
if (isnan(temperature) || isnan(humidity)) {
Serial.println("Error reading DHT22 sensor - Check connections!");
Serial.println("Expected: DHT22 VCC->3.3V, GND->GND, SDA->Pin 15");
systemOK = false;
updateSystemStatusLEDs();
return;
}
}
displaySensorData(temperature, humidity);
bool shouldAlert = (temperature > TEMPERATURE_THRESHOLD) || (humidity > HUMIDITY_THRESHOLD);
if (shouldAlert) {
handleEnvironmentalAlert(temperature, humidity);
} else {
deactivateAlert();
}
sendDataToTagoIO(temperature, humidity);
}
void displaySensorData(float temperature, float humidity) {
Serial.print(testModeActive ? "TEST MODE - " : "NORMAL - ");
Serial.print("Temp: ");
Serial.print(temperature);
Serial.print("C | Hum: ");
Serial.print(humidity);
Serial.print("% | Alert: ");
Serial.print(alertActive ? "ACTIVE" : "INACTIVE");
Serial.print(" | Cooling: ");
Serial.print(coolingMode ? "ON" : "OFF");
Serial.print(" | Manual: ");
Serial.print(manualModeActive ? "ACTIVE" : "INACTIVE");
Serial.print(" | Servo: ");
Serial.print(currentServoPosition);
Serial.print(" degrees | LEDs: ");
Serial.print(digitalRead(LED_GREEN) ? "GREEN " : "");
Serial.print(digitalRead(LED_RED) ? "RED" : "");
if (testModeActive) {
unsigned long timeLeft = TEST_MODE_DURATION - (millis() - testModeStartTime);
Serial.print(" | Test Time Left: ");
Serial.print(timeLeft / 1000);
Serial.print("s");
}
Serial.println();
}
void handleEnvironmentalAlert(float temperature, float humidity) {
if (!alertActive) {
alertActive = true;
systemOK = false;
Serial.println("ALERT: Environmental conditions exceeded!");
if (testModeActive) {
Serial.println("This is a TEST ALERT - simulated conditions");
}
if (temperature > TEMPERATURE_THRESHOLD) {
Serial.print("Temperature alert: ");
Serial.print(temperature);
Serial.print("C (threshold: ");
Serial.print(TEMPERATURE_THRESHOLD);
Serial.println("C)");
}
if (humidity > HUMIDITY_THRESHOLD) {
Serial.print("Humidity alert: ");
Serial.print(humidity);
Serial.print("% (threshold: ");
Serial.print(HUMIDITY_THRESHOLD);
Serial.println("%)");
}
activateAlertSystems();
if (!manualModeActive) {
activateAutomaticCooling();
}
}
}
void activateAlertSystems() {
updateSystemStatusLEDs();
if (!manualModeActive) {
Serial.println("Intermittent buzzer system activated");
lastBuzzerToggle = millis();
buzzerState = false;
} else {
Serial.println("Manual mode active - buzzer suppressed");
}
}
void activateAutomaticCooling() {
if (!coolingMode || currentServoPosition != SERVO_COOLING_POSITION) {
Serial.println("ACTIVATING AUTOMATIC COOLING SYSTEM - AGGRESSIVE MODE");
Serial.print("Moving servo from ");
Serial.print(currentServoPosition);
Serial.print(" to ");
Serial.print(SERVO_COOLING_POSITION);
Serial.println(" degrees (COOLING POSITION)");
forceServoPosition(SERVO_COOLING_POSITION);
coolingMode = true;
delay(SERVO_MOVE_DELAY);
Serial.println("Cooling system activated - Servo FORCED to 180 degrees");
}
}
void deactivateAlert() {
if (alertActive) {
alertActive = false;
systemOK = true;
Serial.println("ALERT CLEARED - Environmental conditions normalized");
if (testModeActive) {
Serial.println("Test alert cleared - conditions normalized in test mode");
} else {
Serial.println("Real environmental conditions normalized - System OK");
}
updateSystemStatusLEDs();
noTone(BUZZER_PIN);
buzzerState = false;
if (!manualModeActive && (coolingMode || currentServoPosition != SERVO_NORMAL_POSITION)) {
Serial.println("DEACTIVATING COOLING SYSTEM - AGGRESSIVE MODE");
Serial.print("Returning servo from ");
Serial.print(currentServoPosition);
Serial.print(" to ");
Serial.print(SERVO_NORMAL_POSITION);
Serial.println(" degrees (NORMAL POSITION)");
forceServoPosition(SERVO_NORMAL_POSITION);
coolingMode = false;
delay(SERVO_MOVE_DELAY);
Serial.println("Cooling system deactivated - Servo FORCED to 0 degrees");
} else if (manualModeActive) {
Serial.println("Manual mode active - servo position maintained by user");
}
}
}
void publishDataToMqtt() {
float temperature, humidity;
if (testModeActive) {
temperature = TEST_TEMPERATURE;
humidity = TEST_HUMIDITY;
} else {
temperature = temperatureSensor.readTemperature();
humidity = temperatureSensor.readHumidity();
}
if (!isnan(temperature) && !isnan(humidity)) {
String payload = createMqttJsonPayload(temperature, humidity);
Serial.print("MQTT Payload size: ");
Serial.print(payload.length());
Serial.println(" bytes");
if (mqttClient.publish(MQTT_TOPIC_DATA, payload.c_str())) {
Serial.print("Data published to MQTT: ");
Serial.println(payload);
if (testModeActive) Serial.println(" (TEST MODE DATA)");
} else {
Serial.print("Failed to publish data to MQTT - Payload size: ");
Serial.print(payload.length());
Serial.println(" bytes");
}
}
}
String createMqttJsonPayload(float temperature, float humidity) {
DynamicJsonDocument doc(512);
doc["temp"] = temperature;
doc["hum"] = humidity;
doc["alert"] = alertActive ? 1 : 0;
doc["cooling"] = coolingMode ? 1 : 0;
doc["system"] = systemOK ? 1 : 0;
doc["test"] = testModeActive ? 1 : 0;
doc["manual"] = manualModeActive ? 1 : 0;
doc["servo"] = currentServoPosition;
doc["time"] = getUnixTime();
if (temperature > TEMPERATURE_THRESHOLD && humidity > HUMIDITY_THRESHOLD) {
doc["reason"] = "TH";
} else if (temperature > TEMPERATURE_THRESHOLD) {
doc["reason"] = "T";
} else if (humidity > HUMIDITY_THRESHOLD) {
doc["reason"] = "H";
} else {
doc["reason"] = "OK";
}
String jsonPayload;
serializeJson(doc, jsonPayload);
return jsonPayload;
}
void sendDataToTagoIO(float temperature, float humidity) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi connection lost. Reconnecting...");
connectToWiFi();
return;
}
String payload = createTagoPayload(temperature, humidity);
postToTagoIO(payload);
}
String createTagoPayload(float temperature, float humidity) {
DynamicJsonDocument doc(1024);
JsonArray array = doc.to<JsonArray>();
JsonObject tempObj = array.createNestedObject();
tempObj["variable"] = "temperature";
tempObj["value"] = temperature;
tempObj["unit"] = "C";
tempObj["time"] = getISO8601Time();
JsonObject humObj = array.createNestedObject();
humObj["variable"] = "humidity";
humObj["value"] = humidity;
humObj["unit"] = "%";
humObj["time"] = getISO8601Time();
JsonObject alertObj = array.createNestedObject();
alertObj["variable"] = "alert_status";
alertObj["value"] = alertActive ? 1 : 0;
alertObj["time"] = getISO8601Time();
JsonObject alertReasonObj = array.createNestedObject();
alertReasonObj["variable"] = "alert_reason";
if (temperature > TEMPERATURE_THRESHOLD && humidity > HUMIDITY_THRESHOLD) {
alertReasonObj["value"] = "TEMP_HUM";
} else if (temperature > TEMPERATURE_THRESHOLD) {
alertReasonObj["value"] = "TEMP";
} else if (humidity > HUMIDITY_THRESHOLD) {
alertReasonObj["value"] = "HUM";
} else {
alertReasonObj["value"] = "NONE";
}
alertReasonObj["time"] = getISO8601Time();
JsonObject coolingObj = array.createNestedObject();
coolingObj["variable"] = "cooling_active";
coolingObj["value"] = coolingMode ? 1 : 0;
coolingObj["time"] = getISO8601Time();
JsonObject testModeObj = array.createNestedObject();
testModeObj["variable"] = "test_mode";
testModeObj["value"] = testModeActive ? 1 : 0;
testModeObj["time"] = getISO8601Time();
JsonObject manualModeObj = array.createNestedObject();
manualModeObj["variable"] = "manual_mode";
manualModeObj["value"] = manualModeActive ? 1 : 0;
manualModeObj["time"] = getISO8601Time();
JsonObject systemStatusObj = array.createNestedObject();
systemStatusObj["variable"] = "system_status";
systemStatusObj["value"] = systemOK ? 1 : 0;
systemStatusObj["time"] = getISO8601Time();
String jsonPayload;
serializeJson(doc, jsonPayload);
return jsonPayload;
}
void postToTagoIO(const String &payload) {
HTTPClient http;
String url = String("https://") + TAGOIO_SERVER;
http.begin(url);
http.addHeader("device-token", TAGOIO_TOKEN);
http.addHeader("Content-Type", "application/json");
Serial.println("Sending data to TagoIO...");
int httpResponseCode = http.POST(payload);
if (httpResponseCode > 0) {
String response = http.getString();
Serial.print("TagoIO Response Code: ");
Serial.println(httpResponseCode);
} else {
Serial.print("TagoIO HTTP Error: ");
Serial.println(httpResponseCode);
}
http.end();
}
String getISO8601Time() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return "";
}
char buffer[30];
strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", &timeinfo);
return String(buffer);
}
unsigned long getUnixTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
return millis() / 1000;
}
return mktime(&timeinfo);
}
void debugServoPosition() {
Serial.println("=== SYSTEM DEBUG ===");
Serial.print("System OK: ");
Serial.println(systemOK ? "YES" : "NO");
Serial.print("Alert Active: ");
Serial.println(alertActive ? "YES" : "NO");
Serial.print("Cooling Mode: ");
Serial.println(coolingMode ? "ON" : "OFF");
Serial.print("Test Mode: ");
Serial.println(testModeActive ? "ACTIVE" : "INACTIVE");
Serial.print("Current Position: ");
Serial.println(currentServoPosition);
Serial.print("Green LED: ");
Serial.println(digitalRead(LED_GREEN) ? "ON" : "OFF");
Serial.print("Red LED: ");
Serial.println(digitalRead(LED_RED) ? "ON" : "OFF");
Serial.print("Buzzer State: ");
Serial.println(buzzerState ? "ON" : "OFF");
Serial.print("Servo Needs Move: ");
Serial.println(servoNeedsMove ? "YES" : "NO");
Serial.println("====================");
}
void debugSystemStatus() {
Serial.println("=== SYSTEM STATUS DEBUG ===");
Serial.print("Test Button pin: ");
Serial.println(digitalRead(BUTTON_TEST) ? "HIGH" : "LOW");
Serial.print("System OK: ");
Serial.println(systemOK ? "YES" : "NO");
Serial.print("Alert Active: ");
Serial.println(alertActive ? "YES" : "NO");
Serial.print("Cooling Mode: ");
Serial.println(coolingMode ? "ON" : "OFF");
Serial.print("Test Mode: ");
Serial.println(testModeActive ? "ACTIVE" : "INACTIVE");
Serial.print("Green LED: ");
Serial.println(digitalRead(LED_GREEN) ? "ON" : "OFF");
Serial.print("Red LED: ");
Serial.println(digitalRead(LED_RED) ? "ON" : "OFF");
Serial.print("Servo Position: ");
Serial.println(currentServoPosition);
Serial.println("============================");
}