#include <WiFi.h>
#include <PubSubClient.h>
#include <ModbusRTUSlave.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <ESPAsyncWiFiManager.h>
#include <AsyncElegantOTA.h> // Include the AsyncElegantOTA library
#include "private.h"
// Constants
const uint8_t rxPin = 10;
const uint8_t txPin = 11;
const uint8_t SLAVE_ID = 1;
const int numInputRegisters = 380;
// Modbus
ModbusRTUSlave mb(Serial2, NO_DE_PIN);
uint16_t inputRegisters[numInputRegisters];
// MQTT
WiFiClient espClient;
PubSubClient client(espClient);
// Web Server
AsyncWebServer server(80);
// WiFiManager
DNSServer dnsServer;
AsyncWiFiManager wifiManager(&server, &dnsServer);
long lastMsg = 0;
char msg[50];
int value = 0;
union FloatToModbus {
float floatValue;
uint16_t intValues[2];
};
void setup_wifi() {
// Initialize Wi-Fi using ESPAsyncWiFiManager
wifiManager.autoConnect("ESP32-Config"); // Create an AP with this SSID for configuration
// The rest of your setup remains the same
// ...
}
// void setup_wifi() {
// delay(10);
// // We start by connecting to a WiFi network
// Serial.println();
// Serial.print("Connecting to ");
// Serial.println(ssid);
// WiFi.begin(ssid, password);
// while (WiFi.status() != WL_CONNECTED) {
// delay(500);
// Serial.print(".");
// }
// Serial.println("");
// Serial.println("WiFi connected");
// Serial.println("IP address: ");
// Serial.println(WiFi.localIP());
// }
// Function to convert a string to a float
float to_float(String messageTemp) {
return atof(messageTemp.c_str());
}
void updateModbusRegisters(const char* topic, float value, int highRegister, int lowRegister) {
inputRegisters[highRegister] = FloatToModbus{value}.intValues[1];
inputRegisters[lowRegister] = FloatToModbus{value}.intValues[0];
}
// Callback function for MQTT messages
void callback(char* topic, byte* message, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(": ");
String messageTemp;
for (int i = 0; i < length; i++) {
messageTemp += (char)message[i];
}
Serial.println(messageTemp);
if (strcmp(topic, "smarthome/meters/grid/sdm630/l1_power_active") == 0) {
float temp = to_float(messageTemp);
updateModbusRegisters(topic, temp, 12, 13);
} else if (strcmp(topic, "smarthome/meters/grid/sdm630/l2_power_active") == 0) {
float temp = to_float(messageTemp);
updateModbusRegisters(topic, temp, 14, 15);
} else if (strcmp(topic, "smarthome/meters/grid/sdm630/l3_power_active") == 0) {
float temp = to_float(messageTemp);
updateModbusRegisters(topic, temp, 16, 17);
} else if (strcmp(topic, "smarthome/meters/grid/sdm630/import_energy_active") == 0) {
float temp = to_float(messageTemp);
updateModbusRegisters(topic, temp, 72, 73);
} else if (strcmp(topic, "smarthome/meters/grid/sdm630/export_energy_active") == 0) {
float temp = to_float(messageTemp);
updateModbusRegisters(topic, temp, 74, 75);
}
}
void setup_webserver() {
// Route to display register values
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
String response = "<html><body>";
response += "<h1>Modbus Register Values</h1>";
for (int i = 0; i < numInputRegisters; i++) {
response += "Register " + String(i) + ": " + String(inputRegisters[i]) + "<br>";
}
response += "</body></html>";
request->send(200, "text/html", response);
});
}
void setup_ota() {
AsyncElegantOTA.begin(&server); // Initialize ElegantOTA with the web server
}
// **************************************************
void setup() {
Serial.begin(115200);
setup_wifi();
setup_webserver(); // Initialize the web server
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
// Serial2.begin(9600, SERIAL_8N1, 16, 17); // software serial attached to the MAX485 module
// add a series of Input registers
mb.configureInputRegisters(inputRegisters, numInputRegisters);
// set Input register values
inputRegisters[12] = 2500; // l1 Active power Watts (integer part)
inputRegisters[13] = 76; // l1 Active power Watts (fractional part)
inputRegisters[14] = 2500; // l2 Active power Watts (integer part)
inputRegisters[15] = 76; // l2 Active power Watts (fractional part)
inputRegisters[16] = 2500; // l3 Active power Watts (integer part)
inputRegisters[17] = 76; // l3 Active power Watts (fractional part)
inputRegisters[72] = 4000; // import_energy_active (integer part)
inputRegisters[73] = 0; // import_energy_active (fractional part)
inputRegisters[74] = 3500; // export_energy_active (integer part)
inputRegisters[75] = 0; // export_energy_active (fractional part)
mb.begin(SLAVE_ID, 9600); // Set your appropriate RE/DE pin configuration here
}
// **************************************************
// **************************************************
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(clientID, mqtt_username, mqtt_password)) {
Serial.println("Connected to MQTT Broker!");
// Subscribe
client.subscribe("smarthome/meters/grid/sdm630/l1_power_active");
client.subscribe("smarthome/meters/grid/sdm630/l2_power_active");
client.subscribe("smarthome/meters/grid/sdm630/l3_power_active");
client.subscribe("smarthome/meters/grid/sdm630/import_energy_active");
client.subscribe("smarthome/meters/grid/sdm630/export_energy_active");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
// **************************************************
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
mb.poll();
yield();
}