#include <WiFi.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
#include "time.h"
// Adafruit IO credentials
#define IO_USERNAME "BenSmiling"
#define IO_KEY "aio_ZdwN60vmbTT3QaYyHt6VRdxzuB5F"
// Wi-Fi credentials
#define WLAN_SSID "Wokwi-GUEST"
#define WLAN_PASS ""
// Pins for sensors and relays
const int currentSensor1Pin = 34;
const int currentSensor2Pin = 35;
const int relay1Pin = 26;
const int relay2Pin = 27;
bool connected = true;
WiFiClient client;
Adafruit_MQTT_Client mqtt(&client, "io.adafruit.com", 1883, IO_USERNAME, IO_KEY);
// MQTT Subscriptions
Adafruit_MQTT_Subscribe relay1Control = Adafruit_MQTT_Subscribe(&mqtt, IO_USERNAME "/feeds/room1_control");
Adafruit_MQTT_Subscribe relay2Control = Adafruit_MQTT_Subscribe(&mqtt, IO_USERNAME "/feeds/room2_control");
Adafruit_MQTT_Subscribe powerLimit = Adafruit_MQTT_Subscribe(&mqtt, IO_USERNAME "/feeds/power_limit");
// MQTT Publications
Adafruit_MQTT_Publish powerRoom1Feed = Adafruit_MQTT_Publish(&mqtt, IO_USERNAME "/feeds/room1_power");
Adafruit_MQTT_Publish powerRoom2Feed = Adafruit_MQTT_Publish(&mqtt, IO_USERNAME "/feeds/room2_power");
Adafruit_MQTT_Publish timestampRoom1Feed = Adafruit_MQTT_Publish(&mqtt, IO_USERNAME "/feeds/room1_timestamp");
Adafruit_MQTT_Publish timestampRoom2Feed = Adafruit_MQTT_Publish(&mqtt, IO_USERNAME "/feeds/room2_timestamp");
Adafruit_MQTT_Publish statusRoom1Feed = Adafruit_MQTT_Publish(&mqtt, IO_USERNAME "/feeds/room1_status");
Adafruit_MQTT_Publish statusRoom2Feed = Adafruit_MQTT_Publish(&mqtt, IO_USERNAME "/feeds/room2_status");
const float ACS712_5A_SENSITIVITY = 0.185;
const float VOLTAGE_SUPPLY = 3.3;
const int ADC_MAX = 4095;
const float AC_VOLTAGE_RMS = 230.0;
float POWER_THRESHOLD = 300.0;
float POWER_SENSITIVITY = 200.0;
bool relay1ManualOff = false;
bool relay2ManualOff = false;
bool relay1State = true;
bool relay2State = true;
bool relay1Auto = true;
bool relay2Auto = true;
bool room1CrossedThreshold = false;
bool room2CrossedThreshold = false;
float lastPublishedPowerRoom1 = -1;
float lastPublishedPowerRoom2 = -1;
// Time setup
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 3600; // Adjust for your timezone
const int daylightOffset_sec = 0;
void setupTime() {
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
Serial.print("Waiting for NTP time sync");
time_t now = time(nullptr);
while (now < 8 * 3600 * 2) {
delay(500);
Serial.print(".");
now = time(nullptr);
}
Serial.println("\nTime synchronized.");
}
String getCurrentTimeString() {
time_t now = time(nullptr);
struct tm timeinfo;
localtime_r(&now, &timeinfo);
char buffer[25];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &timeinfo);
return String(buffer);
}
void blinkPin(int pin, int blinks) {
pinMode(pin, OUTPUT);
for (int i = 0; i < blinks; i++) {
digitalWrite(pin, HIGH);
delay(400);
digitalWrite(pin, LOW);
delay(200);
}
if (pin == 2) {
digitalWrite(pin, HIGH);
}
}
void setup() {
Serial.begin(115200);
pinMode(relay1Pin, OUTPUT);
pinMode(relay2Pin, OUTPUT);
digitalWrite(relay1Pin, LOW);
digitalWrite(relay2Pin, LOW);
Serial.println("Connecting to WiFi...");
WiFi.begin(WLAN_SSID, WLAN_PASS);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 7) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi connected.");
blinkPin(2, 5);
} else {
Serial.println("\nWiFi connection failed.");
}
setupTime();
mqtt.subscribe(&relay1Control);
mqtt.subscribe(&relay2Control);
mqtt.subscribe(&powerLimit);
Serial.println("Subscribed to control feeds.");
attempts = 0;
while (!mqtt.connected() && attempts < 7) {
Serial.print("Connecting to Adafruit IO...");
if (mqtt.connect()) {
Serial.println("connected!");
connected = true;
blinkPin(2, 5);
} else {
Serial.println("failed. Retrying...");
delay(3000);
}
attempts++;
}
if (!mqtt.connected()) {
Serial.println("Unable to connect to Adafruit IO.");
connected = false;
}
blinkPin(2, 5);
relay1State = true;
relay2State = true;
digitalWrite(relay1Pin, HIGH);
digitalWrite(relay2Pin, HIGH);
}
float readACCurrentRMS(int pin) {
const int sampleCount = 1000;
float sumOfSquares = 0;
float voltageOffset = 2.0;
for (int i = 0; i < sampleCount; i++) {
int raw = analogRead(pin);
float voltage = (raw * VOLTAGE_SUPPLY) / ADC_MAX;
float centered = voltage - voltageOffset;
float current = centered / ACS712_5A_SENSITIVITY;
sumOfSquares += current * current;
delayMicroseconds(100);
if (i < 10){
Serial.print(raw);
Serial.print(" ");
}
}
Serial.println("");
float meanSquare = sumOfSquares / sampleCount;
if (sqrt(meanSquare) < 0.3){
meanSquare = 0.0;
}
return sqrt(meanSquare);
}
float calculatePower(float current) {
float power = AC_VOLTAGE_RMS * current * 3.5;
/*if (power > 290){
POWER_SENSITIVITY = 400;
} */
return power;
}
void loop() {
mqtt.processPackets(1000);
mqtt.ping();
mqtt.readSubscription(100);
if (!mqtt.connected()) {
Serial.print("Connecting to Adafruit IO...");
if (mqtt.connect()) {
Serial.println("connected!");
connected = true;
blinkPin(2, 5);
} else {
Serial.println("failed. Retrying...");
// delay(3000);
}
}
if (relay1Control.lastread != NULL) {
String cmd = (char *)relay1Control.lastread;
if (cmd == "0" || cmd == "OFF") {
relay1ManualOff = true;
relay1State = false;
relay1Auto = false;
digitalWrite(relay1Pin, LOW);
statusRoom1Feed.publish("OFF");
} else if (cmd == "1" || cmd == "ON") {
relay1ManualOff = false;
relay1State = true;
relay1Auto = false;
digitalWrite(relay1Pin, HIGH);
statusRoom1Feed.publish("ON");
} else if (cmd == "2" || cmd == "AUTO") {
relay1ManualOff = false;
relay1Auto = true;
}
Serial.print("Received relay command ");
Serial.println(cmd);
}
if (relay2Control.lastread != NULL) {
String cmd = (char *)relay2Control.lastread;
if (cmd == "0" || cmd == "OFF") {
relay2ManualOff = true;
relay2State = false;
relay2Auto = false;
digitalWrite(relay2Pin, LOW);
statusRoom2Feed.publish("OFF");
} else if (cmd == "1" || cmd == "ON") {
relay2ManualOff = false;
relay2State = true;
relay2Auto = false;
digitalWrite(relay2Pin, HIGH);
statusRoom2Feed.publish("ON");
} else if (cmd == "2" || cmd == "AUTO") {
relay2ManualOff = false;
relay2Auto = true;
}
Serial.print("Received relay command ");
Serial.println(cmd);
}
if (powerLimit.lastread != NULL) {
POWER_THRESHOLD = atof((char *)powerLimit.lastread);
if (POWER_THRESHOLD == 0) {
POWER_THRESHOLD = 300;
Serial.println("Power Threshold set to 300W");
} else {
Serial.print("Power Threshold set to ");
Serial.print(POWER_THRESHOLD);
Serial.println("W");
}
}
Serial.print("Room1 Raw values :");
float currentRoom1 = readACCurrentRMS(currentSensor1Pin);
Serial.print("Room 1 current: ");
Serial.println(currentRoom1);
Serial.print("Room2 Raw values :");
float currentRoom2 = readACCurrentRMS(currentSensor2Pin);
Serial.print("Room 2 current: ");
Serial.println(currentRoom2);
float powerRoom1 = calculatePower(currentRoom1);
float powerRoom2 = calculatePower(currentRoom2);
if (powerRoom1 >= 300.0) {
room1CrossedThreshold = true;
}
if (!room1CrossedThreshold) {
powerRoom1 = 0.0;
} else if (powerRoom1 < 300.0) {
powerRoom1 = 300.0;
}
// Room 2 logic
if (powerRoom2 >= 700.0) {
room2CrossedThreshold = true;
}
if (!room2CrossedThreshold) {
powerRoom2 = 0.0;
} else if (powerRoom2 < 700.0) {
powerRoom2 = 700.0;
}
Serial.printf("Power Room1: %.2f W | Room2: %.2f W\n", powerRoom1, powerRoom2);
if (!relay1ManualOff && relay1Auto) {
if (powerRoom1 >= POWER_THRESHOLD && relay1State) {
relay1State = false;
relay1ManualOff = true;
digitalWrite(relay1Pin, LOW);
statusRoom1Feed.publish("OFF");
String timestamp = getCurrentTimeString();
timestampRoom1Feed.publish(timestamp.c_str());
Serial.println("[Auto] Relay1 OFF due to power threshold.");
} /*else if (powerRoom1 < POWER_THRESHOLD && !relay1State) {
relay1State = true;
digitalWrite(relay1Pin, HIGH);
statusRoom1Feed.publish("ON");
Serial.println("[Auto] Relay1 ON, power back to normal.");
}*/
}
if (!relay2ManualOff && relay2Auto) {
if (powerRoom2 >= POWER_THRESHOLD && relay2State) {
relay2State = false;
relay2ManualOff = true;
digitalWrite(relay2Pin, LOW);
statusRoom2Feed.publish("OFF");
String timestamp = getCurrentTimeString();
timestampRoom2Feed.publish(timestamp.c_str());
Serial.println("[Auto] Relay2 OFF due to power threshold.");
} /*else if (powerRoom2 < POWER_THRESHOLD && !relay2State) {
relay2State = true;
digitalWrite(relay2Pin, HIGH);
statusRoom2Feed.publish("ON");
Serial.println("[Auto] Relay2 ON, power back to normal.");
}*/
}
if (abs(powerRoom1 - lastPublishedPowerRoom1) >= POWER_SENSITIVITY) {
powerRoom1Feed.publish(String(powerRoom1).c_str());
lastPublishedPowerRoom1 = powerRoom1;
}
if (abs(powerRoom2 - lastPublishedPowerRoom2) >= POWER_SENSITIVITY) {
powerRoom2Feed.publish(String(powerRoom2).c_str());
lastPublishedPowerRoom2 = powerRoom2;
}
delay(1000);
}