#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
/*
========================================================
WIFI + MQTT CONFIG
========================================================
*/
// WiFi router (NOT ESP hotspot anymore)
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASS = "";
// HiveMQ Cloud (from dashboard)
const char* MQTT_SERVER = "YOUR_CLUSTER_URL";
const int MQTT_PORT = 8883;
// Credentials
const char* MQTT_USER = "YOUR_USERNAME";
const char* MQTT_PASS = "YOUR_PASSWORD";
/*
========================================================
TOPICS
========================================================
*/
const char* TOPIC_VOLTAGE = "microgrid/voltage";
const char* TOPIC_CURRENT = "microgrid/current";
const char* TOPIC_POWER = "microgrid/power";
const char* TOPIC_RPM = "microgrid/rpm";
const char* TOPIC_STATE = "microgrid/state";
const char* TOPIC_ALERT = "microgrid/alert";
const char* TOPIC_CMD = "microgrid/cmd";
/*
========================================================
HARDWARE PINS
========================================================
*/
#define VOLTAGE_PIN 34
#define CURRENT_PIN 35
#define RPM_PIN 27
#define RELAY_PIN 26
#define LED_RED 25
#define LED_YELLOW 33
#define LED_GREEN 32
#define PPR 1
/*
========================================================
THRESHOLDS (TUNABLE)
========================================================
*/
float OPT_V_MIN = 5.0;
float OPT_P_MIN = 2.0;
float STRESS_V_MIN = 3.0;
float STRESS_P_MIN = 1.0;
float RPM_MIN = 50;
/*
========================================================
GLOBALS
========================================================
*/
WiFiClientSecure espClient;
PubSubClient client(espClient);
volatile uint32_t pulses = 0;
float voltage, current, power, rpm, efficiency;
enum State {OPTIMAL, STRESSED, FAULT, STOPPED};
State state = STOPPED;
/*
========================================================
RPM ISR
========================================================
*/
void IRAM_ATTR rpmISR() {
pulses++;
}
/*
========================================================
MQTT CALLBACK (REMOTE CONTROL)
========================================================
*/
void callback(char* topic, byte* payload, unsigned int length)
{
String msg;
for (int i = 0; i < length; i++) msg += (char)payload[i];
if (String(topic) == TOPIC_CMD)
{
if (msg == "RELAY_ON") digitalWrite(RELAY_PIN, HIGH);
if (msg == "RELAY_OFF") digitalWrite(RELAY_PIN, LOW);
}
}
/*
========================================================
WIFI CONNECT
========================================================
*/
void connectWiFi()
{
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
}
}
/*
========================================================
MQTT CONNECT
========================================================
*/
void connectMQTT()
{
espClient.setInsecure(); // simplifies TLS for demo
client.setServer(MQTT_SERVER, MQTT_PORT);
client.setCallback(callback);
while (!client.connected())
{
client.connect("microgrid-node", MQTT_USER, MQTT_PASS);
delay(500);
}
client.subscribe(TOPIC_CMD);
}
/*
========================================================
SETUP
========================================================
*/
void setup()
{
Serial.begin(115200);
pinMode(RPM_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(RPM_PIN), rpmISR, FALLING);
pinMode(RELAY_PIN, OUTPUT);
pinMode(LED_RED, OUTPUT);
pinMode(LED_YELLOW, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
connectWiFi();
connectMQTT();
}
/*
========================================================
STATE MACHINE
========================================================
*/
void updateState()
{
efficiency = (rpm > 0) ? power / rpm : 0;
if (rpm < RPM_MIN)
{
state = STOPPED;
}
else if (efficiency < 0.005)
{
state = FAULT;
}
else if (voltage < STRESS_V_MIN || power < STRESS_P_MIN)
{
state = STRESSED;
}
else
{
state = OPTIMAL;
}
}
/*
========================================================
LOOP
========================================================
*/
unsigned long lastSend = 0;
void loop()
{
if (!client.connected()) connectMQTT();
client.loop();
/*
---------------- SENSOR SIMULATION ----------------
*/
voltage = analogRead(VOLTAGE_PIN) * (3.3 / 4095.0) * 4.0;
current = analogRead(CURRENT_PIN) * (3.3 / 4095.0) * 2.0;
power = voltage * current;
/*
---------------- RPM ----------------
*/
rpm = pulses * 60;
pulses = 0;
updateState();
/*
---------------- ACTUATION ----------------
*/
if (state == OPTIMAL)
{
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(LED_GREEN, HIGH);
digitalWrite(LED_YELLOW, LOW);
digitalWrite(LED_RED, LOW);
}
else if (state == STRESSED)
{
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_RED, LOW);
digitalWrite(LED_YELLOW, HIGH);
}
else if (state == FAULT)
{
digitalWrite(RELAY_PIN, LOW);
digitalWrite(LED_RED, HIGH);
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_YELLOW, LOW);
}
/*
---------------- MQTT PUBLISH ----------------
*/
if (millis() - lastSend > 2000)
{
lastSend = millis();
client.publish(TOPIC_VOLTAGE, String(voltage).c_str());
client.publish(TOPIC_CURRENT, String(current).c_str());
client.publish(TOPIC_POWER, String(power).c_str());
client.publish(TOPIC_RPM, String(rpm).c_str());
String s = (state == OPTIMAL) ? "OPTIMAL" :
(state == STRESSED) ? "STRESSED" :
(state == FAULT) ? "FAULT" : "STOPPED";
client.publish(TOPIC_STATE, s.c_str());
}
}