Skip to content

Commit

Permalink
refactor MQTT interface and extend with autodiscovery + preparing tls…
Browse files Browse the repository at this point in the history
… support
  • Loading branch information
ohAnd committed Jun 6, 2024
1 parent 8905302 commit 61aeb30
Show file tree
Hide file tree
Showing 8 changed files with 296 additions and 89 deletions.
2 changes: 1 addition & 1 deletion include/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct UserConfig
char mqttBrokerUser[64] = "dtuuser";
char mqttBrokerPassword[64] = "dtupass";
char mqttBrokerMainTopic[32] = "dtu1";
boolean mqttHAautoDiscovery = false;
boolean mqttHAutoDiscoveryON = false;
boolean mqttActive = false;

uint8_t displayConnected = 0; // OLED default
Expand Down
32 changes: 32 additions & 0 deletions include/mqttHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef MQTTHANDLER_H
#define MQTTHANDLER_H

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClientSecure.h>

class MQTTHandler {
public:
MQTTHandler(const char* broker, int port, const char* user, const char* password, bool useTLS, const char* sensorUniqueName);
void setup(bool autoDiscovery);
void loop(bool autoDiscovery);
void publishDiscoveryMessage(const char* sensor_type, const char* location, const char* unit);
void publishSensorData(String typeName, String value);
void publishStandardData(String topicPath, String value);

private:
const char* mqtt_broker;
int mqtt_port;
const char* mqtt_user;
const char* mqtt_password;
bool useTLS;
const char* sensor_uniqeName;

WiFiClient wifiClient;
WiFiClientSecure wifiClientSecure;
PubSubClient client;

void reconnect(bool autoDiscovery);
};

#endif // MQTTHANDLER_H
4 changes: 2 additions & 2 deletions include/version.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#define VERSION "1.6.0_localDev"
#define BUILDTIME "06.06.2024 - 00:11:48"
#define BUILDTIMESTAMP "1717625508"
#define BUILDTIME "06.06.2024 - 22:00:02"
#define BUILDTIMESTAMP "1717704002"
2 changes: 1 addition & 1 deletion include/version.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "1.6.0_localDev",
"versiondate": "06.06.2024 - 00:11:48",
"versiondate": "06.06.2024 - 22:00:02",
"linksnapshot": "https://github.com/ohAnd/dtuGateway/releases/download/snapshot/dtuGateway_snapshot_1.6.0_localDev.bin",
"link": "https://github.com/ohAnd/dtuGateway//releases/latest/download/dtuGateway_release_1.6.0_localDev.bin"
}
4 changes: 3 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,11 @@ So I decided to put this abstraction in an **ESP8266** to have a stable abstract

#### connections to the environment
- serving the readed data per /api/data
- binding configuration with seperate activation and login data setting
- configuration of bindings with seperate activation and login data setting
- binding: updating openHab instance with readed data and pulling set data from the instance
- binding: updating to a MQTT broker with readed data [OPEN: pulling set power data from the mqtt instance]
- 2 ways to configure - simple mqtt publishing with base topic or HA MQTT AutoDiscovery based
- for all publishing retain flag is set (keeping last seen data in broker)

#### display support
- selectable (and storable) over advanced web config[^2] or per serial com and at directly at start up coming from factory mode ( [see first-setup-with-access-point](#first-setup-with-access-point) )
Expand Down
6 changes: 3 additions & 3 deletions src/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ void UserConfigManager::printConfigdata()
Serial.print(F("mqtt binding active: \t"));
Serial.println(userConfig.mqttActive);
Serial.print(F("mqtt HA autoDiscovery: \t"));
Serial.println(userConfig.mqttHAautoDiscovery);
Serial.println(userConfig.mqttHAutoDiscoveryON);

Serial.print(F("dtu update time: \t"));
Serial.println(userConfig.dtuUpdateTime);
Expand Down Expand Up @@ -169,7 +169,7 @@ JsonDocument UserConfigManager::mappingStructToJson()
doc["mqtt"]["user"] = userConfig.mqttBrokerUser;
doc["mqtt"]["pass"] = userConfig.mqttBrokerPassword;
doc["mqtt"]["mainTopic"] = userConfig.mqttBrokerMainTopic;
doc["mqtt"]["HAautoDiscovery"] = userConfig.mqttHAautoDiscovery;
doc["mqtt"]["HAutoDiscoveryON"] = userConfig.mqttHAutoDiscoveryON;

doc["display"]["type"] = userConfig.displayConnected;

Expand Down Expand Up @@ -202,7 +202,7 @@ void UserConfigManager::mappingJsonToStruct(JsonDocument doc)
String(doc["mqtt"]["user"]).toCharArray(userConfig.mqttBrokerUser, sizeof(userConfig.mqttBrokerUser));
String(doc["mqtt"]["pass"]).toCharArray(userConfig.mqttBrokerPassword, sizeof(userConfig.mqttBrokerPassword));
String(doc["mqtt"]["mainTopic"]).toCharArray(userConfig.mqttBrokerMainTopic, sizeof(userConfig.mqttBrokerMainTopic));
userConfig.mqttHAautoDiscovery = doc["mqtt"]["HAautoDiscovery"];
userConfig.mqttHAutoDiscoveryON = doc["mqtt"]["HAutoDiscoveryON"];

userConfig.displayConnected = doc["display"]["type"];

Expand Down
220 changes: 139 additions & 81 deletions src/dtuGateway.ino
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
#include <display.h>
#include <displayTFT.h>

#include "dtuInterface.h"
#include <dtuInterface.h>

#include <mqttHandler.h>

#include "index_html.h"
#include "jquery_min_js.h"
Expand Down Expand Up @@ -986,73 +988,127 @@ boolean postMessageToMQTTbroker(String topic, String value)
{
const char *charTopic = topic.c_str();
const char *charValue = value.c_str();
mqttClient.publish(charTopic, charValue);

mqttClient.publish(charTopic, charValue, true);

// Serial.println("\npostMessageToMQTTbroker - send '" + value + "' to topic: " + topic);
return true;
}

boolean updateValuesToMqtt()
// boolean updateValuesToMqtt()
// {
// connectCheckMqttClient();
// if (mqttClient.connected())
// {
// boolean sendOk = postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/timestamp", (String)timeStampInSecondsDtuSynced);
// if (sendOk)
// {
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/grid/U", (String)globalData.grid.voltage);
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/grid/I", (String)globalData.grid.current);
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/grid/P", (String)globalData.grid.power);
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/grid/dailyEnergy", String(globalData.grid.dailyEnergy, 3));
// if (globalData.grid.totalEnergy != 0)
// {
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/grid/totalEnergy", String(globalData.grid.totalEnergy, 3));
// }

// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv0/U", (String)globalData.pv0.voltage);
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv0/I", (String)globalData.pv0.current);
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv0/P", (String)globalData.pv0.power);
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv0/dailyEnergy", String(globalData.pv0.dailyEnergy, 3));
// if (globalData.pv0.totalEnergy != 0)
// {
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv0/totalEnergy", String(globalData.pv0.totalEnergy, 3));
// }

// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv1/U", (String)globalData.pv1.voltage);
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv1/I", (String)globalData.pv1.current);
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv1/P", (String)globalData.pv1.power);
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv1/dailyEnergy", String(globalData.pv1.dailyEnergy, 3));
// if (globalData.pv1.totalEnergy != 0)
// {
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv1/totalEnergy", String(globalData.pv1.totalEnergy, 3));
// }

// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/inverter/Temp", (String)globalData.inverterTemp);
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/inverter/PowerLimit", (String)globalData.powerLimit);
// postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/inverter/WifiRSSI", (String)globalData.dtuRssi);
// Serial.println("\nsent values to mqtt broker");
// }
// else
// {
// Serial.println("\nerror during sent values to mqtt broker");
// }
// }
// else
// {
// Serial.println("\ncould not send to mqtt broker - mqtt not connected");
// return false;
// }
// return true;
// }

bool useTLS = String(userConfig.mqttBrokerIpDomain).startsWith("mqtts://");

MQTTHandler mqttHandler(userConfig.mqttBrokerIpDomain, userConfig.mqttBrokerPort, userConfig.mqttBrokerUser, userConfig.mqttBrokerPassword, useTLS, espUniqueName.c_str());

// publishing data in standard or HA mqtt auto discovery format
void updateValuesToMqtt(boolean haAutoDiscovery = false)
{
connectCheckMqttClient();
if (mqttClient.connected())
Serial.println("\npublish data to MQTT (HA autoDiscovery = " + String(haAutoDiscovery) + ")");
std::map<std::string, std::string> keyValueStore;

keyValueStore["timestamp"] = String(timeStampInSecondsDtuSynced).c_str();

keyValueStore["grid_U"] = String(globalData.grid.voltage).c_str();
keyValueStore["grid_I"] = String(globalData.grid.current).c_str();
keyValueStore["grid_P"] = String(globalData.grid.power).c_str();
keyValueStore["grid_dailyEnergy"] = String(globalData.grid.dailyEnergy, 3).c_str();
if (globalData.grid.totalEnergy != 0)
keyValueStore["grid_totalEnergy"] = String(globalData.grid.totalEnergy, 3).c_str();

keyValueStore["pv0_U"] = String(globalData.pv0.voltage).c_str();
keyValueStore["pv0_I"] = String(globalData.pv0.current).c_str();
keyValueStore["pv0_P"] = String(globalData.pv0.power).c_str();
keyValueStore["pv0_dailyEnergy"] = String(globalData.pv0.dailyEnergy, 3).c_str();
if (globalData.pv0.totalEnergy != 0)
keyValueStore["pv0_totalEnergy"] = String(globalData.pv0.totalEnergy, 3).c_str();

keyValueStore["pv1_U"] = String(globalData.pv1.voltage).c_str();
keyValueStore["pv1_I"] = String(globalData.pv1.current).c_str();
keyValueStore["pv1_P"] = String(globalData.pv1.power).c_str();
keyValueStore["pv1_dailyEnergy"] = String(globalData.pv1.dailyEnergy, 3).c_str();
if (globalData.pv0.totalEnergy != 0)
keyValueStore["pv1_totalEnergy"] = String(globalData.pv1.totalEnergy, 3).c_str();

keyValueStore["inverter_Temp"] = String(globalData.inverterTemp).c_str();
keyValueStore["inverter_PowerLimit"] = String(globalData.powerLimit).c_str();
keyValueStore["inverter_WifiRSSI"] = String(globalData.dtuRssi).c_str();

for (const auto &pair : keyValueStore)
{
boolean sendOk = postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/timestamp", (String)timeStampInSecondsDtuSynced);
if (sendOk)
if (haAutoDiscovery)
{
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/grid/U", (String)globalData.grid.voltage);
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/grid/I", (String)globalData.grid.current);
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/grid/P", (String)globalData.grid.power);
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/grid/dailyEnergy", String(globalData.grid.dailyEnergy, 3));
if (globalData.grid.totalEnergy != 0)
{
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/grid/totalEnergy", String(globalData.grid.totalEnergy, 3));
}

postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv0/U", (String)globalData.pv0.voltage);
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv0/I", (String)globalData.pv0.current);
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv0/P", (String)globalData.pv0.power);
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv0/dailyEnergy", String(globalData.pv0.dailyEnergy, 3));
if (globalData.pv0.totalEnergy != 0)
{
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv0/totalEnergy", String(globalData.pv0.totalEnergy, 3));
}

postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv1/U", (String)globalData.pv1.voltage);
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv1/I", (String)globalData.pv1.current);
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv1/P", (String)globalData.pv1.power);
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv1/dailyEnergy", String(globalData.pv1.dailyEnergy, 3));
if (globalData.pv1.totalEnergy != 0)
{
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/pv1/totalEnergy", String(globalData.pv1.totalEnergy, 3));
}

postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/inverter/Temp", (String)globalData.inverterTemp);
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/inverter/PowerLimit", (String)globalData.powerLimit);
postMessageToMQTTbroker(String(userConfig.mqttBrokerMainTopic) + "/inverter/WifiRSSI", (String)globalData.dtuRssi);
Serial.println("\nsent values to mqtt broker");
mqttHandler.publishSensorData((pair.first).c_str(), (pair.second).c_str());
}
else
{
Serial.println("\nerror during sent values to mqtt broker");
String subtopic = (pair.first).c_str();
subtopic.replace("_", "/");
mqttHandler.publishStandardData(String(userConfig.mqttBrokerMainTopic) + "/" + subtopic, (pair.second).c_str());
}
}
else
{
Serial.println("\ncould not send to mqtt broker - mqtt not connected");
return false;
}
return true;
}

boolean sendHAautoDiscovery()
{
JsonDocument doc;
String haTopicPath = "homeassistant/sensor/" + String(espUniqueName) + "/config";
String haConfigTopicPath = "homeassistant/sensor/" + String(espUniqueName) + "/config";
String haStateTopicPath = "homeassistant/sensor/" + String(espUniqueName) + "/config";

doc["name"] = "HM_Gateway_total-energy";
doc["unique_id"] = espUniqueName;
doc["state_topic"] = haTopicPath;
doc["state_topic"] = haStateTopicPath;
doc["unit_of_measurement"] = "kWh";
doc["icon"] = "mdi:sine-wave";
doc["device"]["name"] = "HoymilesGateway";
Expand All @@ -1064,27 +1120,29 @@ boolean sendHAautoDiscovery()
doc["device"]["configuration_url"] = "http://" + dtuGatewayIP.toString();

// serializeJsonPretty(doc, Serial);
// serializeJson(doc, Serial);

char mqttPayload[1024];
size_t len = serializeJson(doc, mqttPayload);

connectCheckMqttClient();
if (mqttClient.connected())
{
if (userConfig.mqttHAautoDiscovery)
{
mqttClient.beginPublish(haTopicPath.c_str(), len, true);
mqttClient.print(mqttPayload);
mqttClient.endPublish();
Serial.println("\nHA autoDiscovery - send JSON to broker at " + haTopicPath);
}
else
{
postMessageToMQTTbroker(haTopicPath, "");
Serial.println("\nHA autoDiscovery - send empty payload to broker at " + haTopicPath);
}
}
serializeJson(doc, Serial);

// char mqttPayload[1024];
// size_t len = serializeJson(doc, mqttPayload);

// connectCheckMqttClient();
// if (mqttClient.connected())
// {
// if (userConfig.mqttHAutoDiscoveryON)
// {
// mqttClient.beginPublish(haConfigTopicPath.c_str(), len, true);
// mqttClient.print(mqttPayload);
// mqttClient.endPublish();
// Serial.println("\nHA autoDiscovery - send JSON to broker at " + haConfigTopicPath);
// haAutoDiscoveryLastOff = true;
// }
// else if (!userConfig.mqttHAutoDiscoveryON && !haAutoDiscoveryLastOff)
// {
// mqttClient.publish(haConfigTopicPath.c_str(), 0);
// Serial.println("\nHA autoDiscovery - ONE TIME send empty payload to broker at " + haConfigTopicPath);
// haAutoDiscoveryLastOff = true;
// }
// }

return true;
}
Expand Down Expand Up @@ -1217,7 +1275,8 @@ void startServices()
WiFi.scanNetworks(true);

initializeWebServer();
initMqttClient();
Serial.println(F("setup mqtt:"));
mqttHandler.setup(userConfig.mqttHAutoDiscoveryON);
}
else
{
Expand Down Expand Up @@ -1477,15 +1536,16 @@ void loop()
if (updateRunning)
return;

// web server runner
server.handleClient();
// serving domain name
MDNS.update();

// runner for mqttClient to hold a already etablished connection
if (userConfig.mqttActive && mqttClient.connected())
if (WiFi.status() == WL_CONNECTED)
{
mqttClient.loop();
// web server runner
server.handleClient();
// serving domain name
MDNS.update();

// runner for mqttClient to hold a already etablished connection
if (userConfig.mqttActive)
mqttHandler.loop(userConfig.mqttHAutoDiscoveryON);
}

unsigned long currentMillis = millis();
Expand Down Expand Up @@ -1602,8 +1662,6 @@ void loop()
if (userConfig.openhabActive)
getPowerSetDataFromOpenHab();
}
// if (userConfig.mqttActive && userConfig.mqttHAautoDiscovery)
sendHAautoDiscovery();
}

// mid task
Expand All @@ -1628,7 +1686,7 @@ void loop()
if (userConfig.openhabActive)
updateValueToOpenhab();
if (userConfig.mqttActive)
updateValuesToMqtt();
updateValuesToMqtt(userConfig.mqttHAutoDiscoveryON);

if (globalControls.dataFormatJSON)
{
Expand Down Expand Up @@ -1660,7 +1718,7 @@ void loop()
if (userConfig.openhabActive)
updateValueToOpenhab();
if (userConfig.mqttActive)
updateValuesToMqtt();
updateValuesToMqtt(userConfig.mqttHAutoDiscoveryON);
dtuConnection.dtuErrorState = DTU_ERROR_LAST_SEND;
Serial.print(F("\n>>>>> TIMEOUT 5 min for DTU -> NIGHT - send zero values\n"));
}
Expand Down
Loading

0 comments on commit 61aeb30

Please sign in to comment.