I am not C++ coder.
I have this complex code that reads MAX3485 output and should foward it with help of MQTT. I was hoping to get it work with ESP board, first with ESP8266 and then, deciding that maybe the board recourses are not enough I did try switch to ESP32. Every time the result was same. I could have some MQTT connectivity or I could read sensors output in serial monitor. When I try to forward any actual data to mqtt everything broke immediately. Finally I was so desperate that I did try it several days with help of AI . It turns out that AI I was able to talk is really stupid so no point doing that.
Maybe someone knows about ESP boards and MQTT or has access to smarter AI then I. I put here ESP8266 version I tested unsuccessfully.
Thanks
#include <ESP8266WiFi.h> // Library to handle Wi-Fi connections
#include <PubSubClient.h> // Library for MQTT communication
#include <Ticker.h> // Library for non-blocking delays and watchdog timer
// Wi-Fi credentials
const char* ssid = ""; // Replace with your Wi-Fi SSID
const char* password = ""; // Replace with your Wi-Fi password
// MQTT broker information
const char* mqtt_server = ""; // Replace with your MQTT broker IP
const int mqtt_port = 1883; // Default MQTT port
const char* mqtt_user = ""; // Replace with your MQTT broker username
const char* mqtt_password = ""; // Replace with your MQTT broker password
// User setting for date format
enum DateFormat {
DDMMYYYY, // Date in DD.MM.YYYY format
YYYYMMDD // Date in YYYY-MM-DD format
};
DateFormat dateFormat = DDMMYYYY; // Default format is DD.MM.YYYY
// Device and MQTT settings
const char* device_name = "Hewalex_Solar";
const char* mqtt_topic_base = "homeassistant/sensor/hewalex_solar";
const char* node_id = "hewalex_solar"; // Node ID for MQTT discovery
WiFiClient espClient;
PubSubClient client(espClient); // Declare the client as a global variable
// Watchdog timer settings
Ticker hardwareWatchdog; // Define a Ticker object for the hardware watchdog
const int watchdogTimeout = 5000; // Watchdog timeout in milliseconds
// Array to store sensor readings
float Temp[4]; // Using 4 elements for Temp array
float Flow = 0.0; // Flow rate in liters per minute
float TotalEnergy = 0.0; // Total energy in kWh
float CollectorPower = 0.0; // Collector Power in watts
float Consumption = 0.0; // Consumption in watts
int CollectorPumpSpeed = 0; // Collector Pump Speed (0-15)
bool CollectorActive = false; // Collector Active status
// Strings to store controller date and time
String ControllerDate = "";
String ControllerTime = "";
// Wi-Fi Setup
void setup_wifi() {
delay(10);
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());
}
// MQTT Callback (not used here)
void mqttCallback(char* topic, byte* payload, unsigned int length) {
// Handle incoming MQTT messages
}
// Reconnect to MQTT broker
void reconnect() {
// Loop until reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(device_name, mqtt_user, mqtt_password)) {
Serial.println("connected");
// Publish MQTT discovery messages for Home Assistant
publishDiscoveryMessages();
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
// Publish discovery messages for Home Assistant
void publishDiscoveryMessages() {
// Device information for grouping
String deviceInfo =
"{\"identifiers\": [\"hewalex_solar_device\"],"
"\"name\": \"Hewalex Solar System\","
"\"model\": \"Hewalex Model X\","
"\"manufacturer\": \"Hewalex\","
"\"sw_version\": \"1.0\","
"\"support_url\": \"https://hewalex.com/support\"}";
// Discovery topics for each sensor
String discoveryTopics[] = {
String("homeassistant/sensor/") + node_id + "/collector_temp/config", // Collector Temp
String("homeassistant/sensor/") + node_id + "/buffer_temp/config", // Buffer Temp
String("homeassistant/sensor/") + node_id + "/backflow_temp/config", // T3 Backflow Temp
String("homeassistant/sensor/") + node_id + "/flow/config", // Flow
String("homeassistant/sensor/") + node_id + "/total_energy/config", // Total Energy
String("homeassistant/sensor/") + node_id + "/controller_date/config", // Controller Date
String("homeassistant/sensor/") + node_id + "/controller_time/config", // Controller Time
String("homeassistant/sensor/") + node_id + "/collector_power/config", // Collector Power
String("homeassistant/sensor/") + node_id + "/consumption/config", // Consumption
String("homeassistant/sensor/") + node_id + "/collector_pump_speed/config", // Collector Pump Speed
String("homeassistant/sensor/") + node_id + "/collector_active/config" // Collector Active
};
// Sensor names
String sensorNames[] = {
"Hewalex Solar Collector Temp", // Collector Temp
"Hewalex Solar Buffer Temp", // Buffer Temp
"Hewalex Solar T3 Backflow Temp", // T3 Backflow Temp
"Hewalex Solar Flow", // Flow
"Hewalex Total Energy", // Total Energy
"Hewalex Controller Date", // Controller Date
"Hewalex Controller Time", // Controller Time
"Hewalex Solar Collector Power",// Collector Power
"Hewalex Solar Consumption", // Consumption
"Hewalex Solar Collector Pump Speed", // Collector Pump Speed
"Hewalex Solar Collector Active" // Collector Active
};
// Units of measurement
String units[] = {
"°C", "°C", "°C", "L/min", "kWh", "", "", "W", "W", "", ""
};
// JSON keys
String jsonKeys[] = {
"collector", "buffer", "backflow", "flow",
"total_energy", "controller_date", "controller_time", "collector_power",
"consumption", "collector_pump_speed", "collector_active"
};
// Unique IDs
String uniqueIds[] = {
"hewalex_collector_temp", // Unique ID for Collector Temp
"hewalex_buffer_temp", // Unique ID for Buffer Temp
"hewalex_backflow_temp", // Unique ID for T3 Backflow Temp
"hewalex_flow", // Unique ID for Flow
"hewalex_total_energy", // Unique ID for Total Energy
"hewalex_controller_date", // Unique ID for Controller Date
"hewalex_controller_time", // Unique ID for Controller Time
"hewalex_collector_power", // Unique ID for Collector Power
"hewalex_consumption", // Unique ID for Consumption
"hewalex_collector_pump_speed", // Unique ID for Collector Pump Speed
"hewalex_collector_active" // Unique ID for Collector Active
};
// Publish discovery messages
for (int i = 0; i < 11; i++) {
String discoveryPayload = String("{") +
"\"disc\": true," + // Add disc flag
"\"name\": \"" + sensorNames[i] + "\"," +
"\"state_topic\": \"" + mqtt_topic_base + "\"," +
"\"unit_of_measurement\": \"" + units[i] + "\"," +
"\"value_template\": \"{{ value_json." + jsonKeys[i] + " }}\"," +
"\"device\": " + deviceInfo + "," +
"\"unique_id\": \"" + uniqueIds[i] + "\"" +
"}";
client.publish(discoveryTopics[i].c_str(), discoveryPayload.c_str(), true); // Set retain flag
Serial.print("Published discovery message for ");
Serial.println(sensorNames[i]);
}
}
// Function to reset the hardware watchdog
void resetWatchdog() {
ESP.wdtFeed(); // Reset the hardware watchdog timer
}
void setup() {
// Initialize Serial Monitor for debugging
Serial.begin(38400); // Set the baud rate for Serial Monitor and RS485
// Initialize Wi-Fi
setup_wifi();
// Initialize MQTT client
client.setServer(mqtt_server, mqtt_port); // Set MQTT broker with port
client.setCallback(mqttCallback);
client.setKeepAlive(120); // Increase keep-alive to 120 seconds
// Initialize the hardware watchdog
hardwareWatchdog.attach_ms(watchdogTimeout, resetWatchdog);
// Print a startup message
Serial.println("ESP8266 Initialized with Watchdog Timer");
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// Reset the watchdog periodically
resetWatchdog(); // Feed the watchdog timer to prevent reset
char messageread[1000]; // Buffer to store incoming data
int pos = 0; // Position index for message buffer
// Define the message to be sent via RS485
byte message[] = {0x69, 0x02, 0x01, 0x84, 0x00, 0x00, 0x0C, 0xF6, 0x02, 0x00, 0x01, 0x00, 0x40, 0x80, 0x00, 0x32, 0x64, 0x00, 0xBD, 0xB2};
// Send the message via RS485
Serial.write(message, sizeof(message)); // Send the message via RS485
// Delay to allow message transmission
delay(10);
// Read the data coming in from RS485
while (Serial.available() > 0) {
messageread[pos] = Serial.read();
pos++;
}
// Check the first byte to ensure the correct message was received
if (messageread[0] == 0x69) {
int fncID = messageread[12]; // Extract function ID
// Process message if function ID matches expected value
if (fncID == 0x50) {
int startReg = messageread[16]; // Extract starting register
for (int i = 0; i < messageread[15]; i++) {
if (i % 2 == 0) {
int iReg = i + startReg; // Calculate register index
// Process readings based on register index (ascending order)
if (iReg == 120) { // Controller Date
// Extract raw values
byte yearByte = messageread[18 + i];
byte monthByte = messageread[19 + i];
byte dayByte = messageread[20 + i]; // Using 20th index for day
Serial.print("Raw Year: ");
Serial.println(yearByte, HEX); // Print as hexadecimal
Serial.print("Raw Month: ");
Serial.println(monthByte, HEX); // Print as hexadecimal
Serial.print("Raw Day: ");
Serial.println(dayByte, HEX); // Print as hexadecimal
// Format date based on selected date format
int year = 2000 + yearByte; // Extract year
int month = monthByte; // Extract month
int day = dayByte; // Extract day
if (dateFormat == DDMMYYYY) {
// Format as DD.MM.YYYY
ControllerDate = (day < 10 ? "0" : "") + String(day) + "." +
(month < 10 ? "0" : "") + String(month) + "." +
String(year);
} else {
// Format as YYYY-MM-DD
ControllerDate = String(year) + "-" +
(month < 10 ? "0" : "") + String(month) + "-" +
(day < 10 ? "0" : "") + String(day);
}
Serial.print("Formatted Date: ");
Serial.println(ControllerDate);
}
if (iReg == 124) { // Controller Time
// Extract raw values
byte rawHour = messageread[18 + i];
byte rawMinute = messageread[19 + i];
// Print unformatted raw values
Serial.print("Raw Hour: ");
Serial.println(rawHour); // Print as integer
Serial.print("Raw Minute: ");
Serial.println(rawMinute); // Print as integer
// Show formatted time as HH:MM with leading zeros
ControllerTime = (rawHour < 10 ? "0" : "") + String(rawHour) + ":" + (rawMinute < 10 ? "0" : "") + String(rawMinute);
Serial.print("Formatted Time: ");
Serial.println(ControllerTime);
}
if (iReg == 128) { // Collector Temp
byte hexstr[] = {messageread[19 + i], messageread[18 + i]};
int w = hexstr[0] << 8 | hexstr[1];
if (w & 0x8000) {
w = w - 0x10000;
}
Temp[0] = (w / 10.0) * 10.0; // Convert to °C
}
if (iReg == 130) { // Buffer Temp
byte hexstr[] = {messageread[19 + i], messageread[18 + i]};
int w = hexstr[0] << 8 | hexstr[1];
if (w & 0x8000) {
w = w - 0x10000;
}
Temp[1] = (w / 10.0) * 10.0; // Convert to °C
}
if (iReg == 132) { // T3 Backflow Temp
byte hexstr[] = {messageread[19 + i], messageread[18 + i]};
int w = hexstr[0] << 8 | hexstr[1];
if (w & 0x8000) {
w = w - 0x10000;
}
Temp[2] = (w / 10.0) * 10.0; // Convert to °C
}
if (iReg == 144) { // Collector Power
byte hexstr[] = {messageread[19 + i], messageread[18 + i]};
int w = hexstr[0] << 8 | hexstr[1];
if (w & 0x8000) {
w = w - 0x10000;
}
CollectorPower = w; // Use Collector Power directly in watts
}
if (iReg == 148) { // Consumption
byte hexstr[] = {messageread[19 + i], messageread[18 + i]};
int w = hexstr[0] << 8 | hexstr[1];
if (w & 0x8000) {
w = w - 0x10000;
}
Consumption = w; // Use Consumption directly in watts
}
if (iReg == 150) { // Collector Active
byte hexstr[] = {messageread[19 + i], messageread[18 + i]};
int w = hexstr[0] << 8 | hexstr[1];
CollectorActive = (w != 0); // Set Collector Active status
}
if (iReg == 152) { // Flow
byte hexstr[] = {messageread[19 + i], messageread[18 + i]};
int w = hexstr[0] << 8 | hexstr[1];
if (w & 0x8000) {
w = w - 0x10000;
}
Flow = w / 10.0; // Convert to liters per minute
}
if (iReg == 156) { // Collector Pump Speed
byte hexstr[] = {messageread[19 + i], messageread[18 + i]};
int w = hexstr[0] << 8 | hexstr[1];
CollectorPumpSpeed = w; // Values are 0-15
}
if (iReg == 166) { // Total Energy
byte hexstr[] = {messageread[19 + i], messageread[18 + i]};
int w = hexstr[0] << 8 | hexstr[1];
if (w & 0x8000) {
w = w - 0x10000;
}
TotalEnergy = w / 100.0; // Convert to kWh
}
}
}
}
}
// Send temperature data and other metrics to MQTT
char mqttPayload[512]; // Increased buffer size to accommodate new parameters
snprintf(mqttPayload, sizeof(mqttPayload),
"{\"collector\": %.1f, \"buffer\": %.1f, \"backflow\": %.1f, \"collector_power\": %.0f, \"consumption\": %.0f, \"collector_pump_speed\": %d, \"collector_active\": %s, \"flow\": %.1f, \"total_energy\": %.1f, \"controller_date\": \"%s\", \"controller_time\": \"%s\"}",
Temp[0], Temp[1], Temp[2], CollectorPower, Consumption, CollectorPumpSpeed, CollectorActive ? "true" : "false", Flow, TotalEnergy, ControllerDate.c_str(), ControllerTime.c_str());
client.publish(mqtt_topic_base, mqttPayload, true); // Set QoS to 2 for reliable message delivery
// Print readings to Serial Monitor
Serial.print("Collector Temp = ");
Serial.print(Temp[0]);
Serial.println(" °C");
Serial.print("Buffer Temp = ");
Serial.print(Temp[1]);
Serial.println(" °C");
Serial.print("T3 Backflow Temp = ");
Serial.print(Temp[2]);
Serial.println(" °C");
Serial.print("Collector Power = ");
Serial.print(CollectorPower);
Serial.println(" W");
Serial.print("Consumption = ");
Serial.print(Consumption);
Serial.println(" W");
Serial.print("Collector Pump Speed = ");
Serial.print(CollectorPumpSpeed);
Serial.println("");
Serial.print("Collector Active = ");
Serial.println(CollectorActive ? "true" : "false");
Serial.print("Flow = ");
Serial.print(Flow);
Serial.println(" L/min");
Serial.print("Total Energy = ");
Serial.print(TotalEnergy);
Serial.println(" kWh");
Serial.print("Controller Date = ");
Serial.println(ControllerDate);
Serial.print("Controller Time = ");
Serial.println(ControllerTime);
// Wait for 2 seconds before repeating
delay(2000);
}