From 99cdcfdc7a886c1356990ea637ddda386eaa9353 Mon Sep 17 00:00:00 2001 From: sjors van mierlo Date: Fri, 6 Aug 2021 21:19:03 +0200 Subject: [PATCH 1/4] Adjusted readme mqtt port to be the same as the configuration example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5481b01..6fff287 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ Copy `Settings.example.h` to `Settings.h` and fill in the correct data. | WIFI_SSID | - | Wifi name to connect to | | WIFI_PASSWORD | - | Wifi password | | MQTT_HOST_NAME | - | MQTT broker address | -| MQTT_PORT | 1833 | MQTT broker port | +| MQTT_PORT | 1883 | MQTT broker port | | MQTT_USER_NAME| - | MQTT user name | | MQTT_PASSWORD | - | MQTT password | | MQTT_HOSTNAME| ESP-DSMR | MQTT name | From 22789f3258f0f350b8ec3ad6e3e417f9b7e9ffc3 Mon Sep 17 00:00:00 2001 From: sjors van mierlo Date: Sat, 7 Aug 2021 15:04:41 +0200 Subject: [PATCH 2/4] fixed typo in consumption --- esp8266-dsmr.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esp8266-dsmr.ino b/esp8266-dsmr.ino index 2b146ff..41c9cea 100644 --- a/esp8266-dsmr.ino +++ b/esp8266-dsmr.ino @@ -29,10 +29,10 @@ const Measurement measurements[] = { {"version", "1-3:0.2.8", 10, 12, Measurement::STRING}, {"power/timestamp", "0-0:1.0.0", 10, 23, Measurement::STRING}, {"power/device_id", "0-0:96.1.1", 11, 45, Measurement::STRING}, - {"power/consuption", "1-0:1.7.0", 10, 16, Measurement::FLOAT}, + {"power/consumption", "1-0:1.7.0", 10, 16, Measurement::FLOAT}, {"power/production", "1-0:2.7.0", 10, 16, Measurement::FLOAT}, - {"power/total_consuption_tariff_1", "1-0:1.8.1", 10, 20, Measurement::FLOAT}, - {"power/total_consuption_tariff_2", "1-0:1.8.2", 10, 20, Measurement::FLOAT}, + {"power/total_consumption_tariff_1", "1-0:1.8.1", 10, 20, Measurement::FLOAT}, + {"power/total_consumption_tariff_2", "1-0:1.8.2", 10, 20, Measurement::FLOAT}, {"power/total_production_tariff_1", "1-0:2.8.1", 10, 20, Measurement::FLOAT}, {"power/total_production_tariff_2", "1-0:2.8.2", 10, 20, Measurement::FLOAT}, {"power/power_tariff", "0-0:96.14.0", 12, 16, Measurement::INT}, From b8e8bbe7b9ccb8d10a192f4b55dd5a6df055a8fd Mon Sep 17 00:00:00 2001 From: Bram van Deventer Date: Fri, 13 Aug 2021 19:47:13 +0200 Subject: [PATCH 3/4] (WIP) Adding HA Mqtt Auto discover - Add autoconfig file - Remove MQTT topic prefix config - Remove MQTT topc userclient - Always use ESP chip ID as prefix - Enlarge MQTT buffer size - Set MQTT retained to false on all msgs --- AutoConfig.h | 65 ++++++++++++++++++++++++++++++ MQTTPublisher.cpp | 52 ++++++++++++------------ MQTTPublisher.h | 10 ++--- Settings.example.h | 6 --- WifiConnector.cpp | 1 - esp8266-dsmr.ino | 98 +++++++++++++++++++++++++--------------------- 6 files changed, 149 insertions(+), 83 deletions(-) create mode 100644 AutoConfig.h diff --git a/AutoConfig.h b/AutoConfig.h new file mode 100644 index 0000000..f133824 --- /dev/null +++ b/AutoConfig.h @@ -0,0 +1,65 @@ +#include "MQTTPublisher.h" +#include "Settings.h" +#include "Logger.h" + +#pragma once + +namespace AutoConfig +{ +Logger logger; + +void SendConfig(MQTTPublisher mqttPublisher, char identifier[24]) +{ + logger = Logger("AutoConfig"); + logger.info("Start auto config"); + + char mqttPayload[2048]; + DynamicJsonDocument device(256); + DynamicJsonDocument autoconfPayload(1024); + StaticJsonDocument<64> identifiersDoc; + JsonArray identifiers = identifiersDoc.to(); + + // Set device properties + identifiers.add(identifier); + device["identifiers"] = identifiers; + device["manufacturer"] = "Bram2202"; + device["model"] = "ESP - DSMR"; + device["name"] = identifier; + device["sw_version"] = "v1.3.0"; + + // Set sensor properties + mqttPublisher.publish("test", "test", true); + + // power_consumption + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = String(identifier) + "/power/consumption/status"; + autoconfPayload["state_topic"] = String(identifier) + "/power/consumption"; + autoconfPayload["name"] = String(identifier) + "_power_consumption"; + autoconfPayload["unit_of_measurement"] = "kW"; + autoconfPayload["unique_id"] = "power_consumption"; + autoconfPayload["icon"] = "mdi:flash"; + autoconfPayload["device_class"] = "power"; + autoconfPayload["state_class"] = "measurement"; + serializeJson(autoconfPayload, mqttPayload); + mqttPublisher.publish("homeassistant/sensor/" + String(identifier) + "/power_consumption/config", &mqttPayload[0], false); + + autoconfPayload.clear(); + logger.info("1st send"); + + // power_production + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = String(identifier) + "/power/production/status"; + autoconfPayload["state_topic"] = String(identifier) + "/power/production"; + autoconfPayload["name"] = String(identifier) + "_power_production"; + autoconfPayload["unit_of_measurement"] = "kW"; + autoconfPayload["unique_id"] = "power_production"; + autoconfPayload["icon"] = "mdi:flash"; + autoconfPayload["device_class"] = "power"; + autoconfPayload["state_class"] = "measurement"; + serializeJson(autoconfPayload, mqttPayload); + mqttPublisher.publish("homeassistant/sensor/" + String(identifier) + "/power_production/config", &mqttPayload[0], false); + + autoconfPayload.clear(); + logger.info("2nd send"); +} +} diff --git a/MQTTPublisher.cpp b/MQTTPublisher.cpp index fc7cd55..376929b 100644 --- a/MQTTPublisher.cpp +++ b/MQTTPublisher.cpp @@ -1,34 +1,19 @@ #include "MQTTPublisher.h" #include "Settings.h" +#pragma once + WiFiClient espClient; PubSubClient client(espClient); -MQTTPublisher::MQTTPublisher(String clientId) +MQTTPublisher::MQTTPublisher(String identifier) { + _identifier = identifier; randomSeed(micros()); - _clientId = clientId; logger = Logger("MQTTPublisher"); - logger.debug("ClientId:" + _clientId); } -MQTTPublisher::~MQTTPublisher() -{ - client.publish(getTopic("status").c_str(), "offline"); - client.disconnect(); -} - -String MQTTPublisher::getTopic(String name) -{ - if (USE_CLIENT_ID) - { - return String(MQTT_PREFIX) + '/' + _clientId + '/' + name; - } - else - { - return String(MQTT_PREFIX) + '/' + name; - } -} +MQTTPublisher::MQTTPublisher() {} bool MQTTPublisher::reconnect() { @@ -41,12 +26,12 @@ bool MQTTPublisher::reconnect() if (String(MQTT_USER_NAME).length()) { logger.info("Connecting with credientials"); - clientConnected = client.connect(_clientId.c_str(), MQTT_USER_NAME, MQTT_PASSWORD); + clientConnected = client.connect(_identifier.c_str(), MQTT_USER_NAME, MQTT_PASSWORD); } else { logger.info("Connecting without credentials"); - clientConnected = client.connect(_clientId.c_str()); + clientConnected = client.connect(_identifier.c_str()); } if (clientConnected) @@ -56,8 +41,8 @@ bool MQTTPublisher::reconnect() hasMQTT = true; // Once connected, publish an announcement... - client.publish(getTopic("status").c_str(), "online"); + client.publish(String(_identifier + "/status").c_str(), String("online").c_str()); return true; } else @@ -70,6 +55,7 @@ bool MQTTPublisher::reconnect() void MQTTPublisher::start() { + if (String(MQTT_HOST_NAME).length() == 0 || MQTT_PORT == 0) { logger.warn("disabled. No hostname or port set."); @@ -79,6 +65,9 @@ void MQTTPublisher::start() logger.debug("enabled. Connecting."); client.setServer(MQTT_HOST_NAME, MQTT_PORT); + client.setKeepAlive(10); + client.setBufferSize(2048); + reconnect(); isStarted = true; } @@ -101,11 +90,20 @@ void MQTTPublisher::handle() } } -bool MQTTPublisher::publishOnMQTT(String topicSuffix, String msg) +bool MQTTPublisher::publish(String topic, String msg, bool addIdentifier) { - String topic = getTopic(topicSuffix); - logger.debug("Publish to '" + topic + "':" + msg); - auto retVal = client.publish(topic.c_str(), msg.c_str()); + if (addIdentifier) + topic = _identifier + "/" + topic; + logger.debug("Publish to: " + topic + ": " + msg); + + //int henk = sizeof(msg.c_str()); + //logger.debug("size : " + String(henk)); + + auto retVal = client.publish(topic.c_str(), msg.c_str(), false); + yield(); + if (!retVal) + logger.debug("!error : " + String(client.state())); + return retVal; } diff --git a/MQTTPublisher.h b/MQTTPublisher.h index 7e95d1c..3e85e82 100644 --- a/MQTTPublisher.h +++ b/MQTTPublisher.h @@ -17,7 +17,7 @@ class MQTTPublisher private: Logger logger; bool _debugMode; - String _clientId; + String _identifier; bool isStarted; uint32_t lastConnectionAttempt = 0; // last reconnect @@ -26,12 +26,12 @@ class MQTTPublisher bool reconnect(); String getTopic(String name); public: - MQTTPublisher(String clientId = String(ESP.getChipId(), HEX)); - ~MQTTPublisher(); + MQTTPublisher(String identifier); + MQTTPublisher(); + void start(); void stop(); - void handle(); - bool publishOnMQTT(String topic, String msg); + bool publish(String topic, String msg, bool addIdentifier); }; diff --git a/Settings.example.h b/Settings.example.h index b62e9c8..1f647fd 100644 --- a/Settings.example.h +++ b/Settings.example.h @@ -22,11 +22,5 @@ //publish online status name #define MQTT_HOSTNAME "ESP-DSMR" -//default MQTT prefix -#define MQTT_PREFIX "dsmr" - -// Use Client ID in MQTT prefix -#define USE_CLIENT_ID false - //for debugging, print info on serial (DEBUG, INFO, WARN) #define LOG_LEVEL INFO diff --git a/WifiConnector.cpp b/WifiConnector.cpp index aa256cb..faae42a 100644 --- a/WifiConnector.cpp +++ b/WifiConnector.cpp @@ -16,7 +16,6 @@ WifiConnector::WifiConnector() // Set params and try to connect void WifiConnector::start() { - logger.info("Start"); // Setup Wifi diff --git a/esp8266-dsmr.ino b/esp8266-dsmr.ino index 41c9cea..226b9d2 100644 --- a/esp8266-dsmr.ino +++ b/esp8266-dsmr.ino @@ -2,12 +2,15 @@ #include #include #include -#include "MQTTPublisher.h" #include -#include "WifiConnector.h" +#include #include "ESP8266mDNS.h" + +#include "MQTTPublisher.h" +#include "WifiConnector.h" #include "Settings.h" #include "Logger.h" +#include "AutoConfig.h" typedef struct { @@ -26,36 +29,36 @@ typedef struct } Measurement; const Measurement measurements[] = { - {"version", "1-3:0.2.8", 10, 12, Measurement::STRING}, - {"power/timestamp", "0-0:1.0.0", 10, 23, Measurement::STRING}, - {"power/device_id", "0-0:96.1.1", 11, 45, Measurement::STRING}, - {"power/consumption", "1-0:1.7.0", 10, 16, Measurement::FLOAT}, - {"power/production", "1-0:2.7.0", 10, 16, Measurement::FLOAT}, - {"power/total_consumption_tariff_1", "1-0:1.8.1", 10, 20, Measurement::FLOAT}, - {"power/total_consumption_tariff_2", "1-0:1.8.2", 10, 20, Measurement::FLOAT}, - {"power/total_production_tariff_1", "1-0:2.8.1", 10, 20, Measurement::FLOAT}, - {"power/total_production_tariff_2", "1-0:2.8.2", 10, 20, Measurement::FLOAT}, - {"power/power_tariff", "0-0:96.14.0", 12, 16, Measurement::INT}, - {"power/short_power_outages", "0-0:96.7.21", 12, 17, Measurement::INT}, - {"power/long_power_outages", "0-0:96.7.9", 11, 16, Measurement::INT}, - {"power/phase_1/short_power_drops", "1-0:32.32.0", 12, 17, Measurement::INT}, - {"power/phase_2/short_power_drops", "1-0:52.32.0", 12, 17, Measurement::INT}, - {"power/phase_3/short_power_drops", "1-0:72.32.0", 12, 17, Measurement::INT}, - {"power/phase_1/short_power_peaks", "1-0:32.36.0", 12, 17, Measurement::INT}, - {"power/phase_2/short_power_peaks", "1-0:52.36.0", 12, 17, Measurement::INT}, - {"power/phase_3/short_power_peaks", "1-0:72.36.0", 12, 17, Measurement::INT}, - {"power/phase_1/current", "1-0:31.7.0", 11, 14, Measurement::INT}, - {"power/phase_2/current", "1-0:51.7.0", 11, 14, Measurement::INT}, - {"power/phase_3/current", "1-0:71.7.0", 11, 14, Measurement::INT}, - {"power/phase_1/usage", "1-0:21.7.0", 11, 17, Measurement::FLOAT}, - {"power/phase_2/usage", "1-0:41.7.0", 11, 17, Measurement::FLOAT}, - {"power/phase_3/usage", "1-0:61.7.0", 11, 17, Measurement::FLOAT}, - {"power/phase_1/delivery", "1-0:22.7.0", 11, 17, Measurement::FLOAT}, - {"power/phase_2/delivery", "1-0:42.7.0", 11, 17, Measurement::FLOAT}, - {"power/phase_3/delivery", "1-0:62.7.0", 11, 17, Measurement::FLOAT}, - {"gas/total", "0-1:24.2.1", 26, 35, Measurement::FLOAT}, - {"gas/device_id", "0-1:96.1.0", 11, 45, Measurement::STRING}, - {"gas/timestamp", "0-1:24.2.1", 11, 24, Measurement::STRING}, + {"version", "1-3:0.2.8", 10, 12, Measurement::STRING}, + {"power/timestamp", "0-0:1.0.0", 10, 23, Measurement::STRING}, + {"power/device_id", "0-0:96.1.1", 11, 45, Measurement::STRING}, + {"power/consumption", "1-0:1.7.0", 10, 16, Measurement::FLOAT}, + {"power/production", "1-0:2.7.0", 10, 16, Measurement::FLOAT}, + {"power/total_consumption_tariff_1", "1-0:1.8.1", 10, 20, Measurement::FLOAT}, + {"power/total_consumption_tariff_2", "1-0:1.8.2", 10, 20, Measurement::FLOAT}, + {"power/total_production_tariff_1", "1-0:2.8.1", 10, 20, Measurement::FLOAT}, + {"power/total_production_tariff_2", "1-0:2.8.2", 10, 20, Measurement::FLOAT}, + {"power/power_tariff", "0-0:96.14.0", 12, 16, Measurement::INT}, + {"power/short_power_outages", "0-0:96.7.21", 12, 17, Measurement::INT}, + {"power/long_power_outages", "0-0:96.7.9", 11, 16, Measurement::INT}, + {"power/phase_1/short_power_drops", "1-0:32.32.0", 12, 17, Measurement::INT}, + {"power/phase_2/short_power_drops", "1-0:52.32.0", 12, 17, Measurement::INT}, + {"power/phase_3/short_power_drops", "1-0:72.32.0", 12, 17, Measurement::INT}, + {"power/phase_1/short_power_peaks", "1-0:32.36.0", 12, 17, Measurement::INT}, + {"power/phase_2/short_power_peaks", "1-0:52.36.0", 12, 17, Measurement::INT}, + {"power/phase_3/short_power_peaks", "1-0:72.36.0", 12, 17, Measurement::INT}, + {"power/phase_1/current", "1-0:31.7.0", 11, 14, Measurement::INT}, + {"power/phase_2/current", "1-0:51.7.0", 11, 14, Measurement::INT}, + {"power/phase_3/current", "1-0:71.7.0", 11, 14, Measurement::INT}, + {"power/phase_1/usage", "1-0:21.7.0", 11, 17, Measurement::FLOAT}, + {"power/phase_2/usage", "1-0:41.7.0", 11, 17, Measurement::FLOAT}, + {"power/phase_3/usage", "1-0:61.7.0", 11, 17, Measurement::FLOAT}, + {"power/phase_1/delivery", "1-0:22.7.0", 11, 17, Measurement::FLOAT}, + {"power/phase_2/delivery", "1-0:42.7.0", 11, 17, Measurement::FLOAT}, + {"power/phase_3/delivery", "1-0:62.7.0", 11, 17, Measurement::FLOAT}, + {"gas/total", "0-1:24.2.1", 26, 35, Measurement::FLOAT}, + {"gas/device_id", "0-1:96.1.0", 11, 45, Measurement::STRING}, + {"gas/timestamp", "0-1:24.2.1", 11, 24, Measurement::STRING}, }; MQTTPublisher mqttPublisher; @@ -65,6 +68,7 @@ String incomingString = ""; bool hasMQTT = false; bool hasWIFI = false; Logger logger = Logger("App"); +char identifier[24]; int rxPin = 3; int lvlPin = 5; @@ -77,21 +81,27 @@ void setup() logger.info("Start setup"); - pinMode(lvlPin, OUTPUT); // D1 + // Set pin modes + pinMode(lvlPin, OUTPUT); // D1 digitalWrite(lvlPin, HIGH); // Turn on RX Trans - + + snprintf(identifier, sizeof(identifier), "ESP_DSMR_%X", ESP.getChipId()); + // Setup Wifi wifiConnector = WifiConnector(); wifiConnector.start(); // Setup MQTT - mqttPublisher = MQTTPublisher(); + mqttPublisher = MQTTPublisher(identifier); mqttPublisher.start(); // Setup OTA ArduinoOTA.setHostname(WIFI_HOSTNAME); ArduinoOTA.begin(); + // Sent HA config + AutoConfig::SendConfig(mqttPublisher, identifier); + logger.info("Setup complete"); } @@ -133,17 +143,17 @@ void handleString(String incomingString) switch (measurement.valueType) { - case Measurement::FLOAT: - value = String(value.toFloat(), 3); - break; - case Measurement::INT: - value = String(value.toInt()); - break; - default: - break; + case Measurement::FLOAT: + value = String(value.toFloat(), 3); + break; + case Measurement::INT: + value = String(value.toInt()); + break; + default: + break; } - mqttPublisher.publishOnMQTT(measurement.name, value); + mqttPublisher.publish(measurement.name, value, true); } } } From 775f45ec56a6df130b496f3c7a63e2e16e570a08 Mon Sep 17 00:00:00 2001 From: Bram van Deventer Date: Mon, 16 Aug 2021 14:45:08 +0200 Subject: [PATCH 4/4] Adding AutoConfig for HA - Adding HA auto config. - Update some entities. - Send online state. - Update README to include HA MQTT auto discovery - Remove MQTT topic config - Add retain flag to publish --- AutoConfig.cpp | 402 ++++++++++++++++++++++++++++++++++++++++++++++ AutoConfig.h | 74 ++------- MQTTPublisher.cpp | 5 +- MQTTPublisher.h | 3 +- README.md | 29 ++-- esp8266-dsmr.ino | 77 +++++---- 6 files changed, 482 insertions(+), 108 deletions(-) create mode 100644 AutoConfig.cpp diff --git a/AutoConfig.cpp b/AutoConfig.cpp new file mode 100644 index 0000000..f03ae6e --- /dev/null +++ b/AutoConfig.cpp @@ -0,0 +1,402 @@ +#include +#include "MQTTPublisher.h" +#include "AutoConfig.h" +#include "Settings.h" +#include "Logger.h" + +#pragma once + +/** + * instantiate AutoConfig class. + * * + * @param mqttPublisher Publisher for sending msgs + * @param identifier ESP identifier + */ +AutoConfig::AutoConfig(MQTTPublisher &mqttPublisher, String identifier) +{ + _mqttPublisher = mqttPublisher; + _identifier = identifier; + logger = Logger("AutoConfig"); +} + +AutoConfig::AutoConfig() {} + +/** + * Send sensor config for Home Assistant + */ +void AutoConfig::SendConfig() +{ + logger = Logger("AutoConfig"); + logger.info("Start auto config"); + + char mqttPayload[2048]; + DynamicJsonDocument device(256); + DynamicJsonDocument autoconfPayload(1024); + StaticJsonDocument<64> identifiersDoc; + JsonArray identifiers = identifiersDoc.to(); + + // Set device properties + identifiers.add(_identifier); + device["identifiers"] = identifiers; + device["manufacturer"] = "Bram2202"; + device["model"] = "ESP-DSMR"; + device["name"] = _identifier; + device["sw_version"] = "v1.3.0"; + + // power_consumption + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/consumption/status"; + autoconfPayload["state_topic"] = _identifier + "/power/consumption"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/consumption"; + autoconfPayload["name"] = _identifier + "_power_consumption"; + autoconfPayload["unit_of_measurement"] = "kW"; + autoconfPayload["unique_id"] = "power_consumption"; + autoconfPayload["icon"] = "mdi:flash"; + autoconfPayload["device_class"] = "power"; + autoconfPayload["state_class"] = "measurement"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/power_consumption/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // power_production + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/production/status"; + autoconfPayload["state_topic"] = _identifier + "/power/production"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/production"; + autoconfPayload["name"] = _identifier + "_power_production"; + autoconfPayload["unit_of_measurement"] = "kW"; + autoconfPayload["unique_id"] = "power_production"; + autoconfPayload["icon"] = "mdi:flash"; + autoconfPayload["device_class"] = "power"; + autoconfPayload["state_class"] = "measurement"; + autoconfPayload["last_reset_value_template"] = "1970-01-01T00:00:00+00:00"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/power_production/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // total_consumption_tariff_1 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/total_consumption_tariff_1/status"; + autoconfPayload["state_topic"] = _identifier + "/power/total_consumption_tariff_1"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/total_consumption_tariff_1"; + autoconfPayload["name"] = _identifier + "_total_consumption_tariff_1"; + autoconfPayload["unit_of_measurement"] = "kWh"; + autoconfPayload["unique_id"] = "total_consumption_tariff_1"; + autoconfPayload["icon"] = "mdi:counter"; + autoconfPayload["device_class"] = "energy"; + autoconfPayload["state_class"] = "measurement"; + autoconfPayload["last_reset_value_template"] = "1970-01-01T00:00:00+00:00"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/total_consumption_tariff_1/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // total_consumption_tariff_2 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/total_consumption_tariff_2/status"; + autoconfPayload["state_topic"] = _identifier + "/power/total_consumption_tariff_2"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/total_consumption_tariff_2"; + autoconfPayload["name"] = _identifier + "_total_consumption_tariff_2"; + autoconfPayload["unit_of_measurement"] = "kWh"; + autoconfPayload["unique_id"] = "total_consumption_tariff_2"; + autoconfPayload["icon"] = "mdi:counter"; + autoconfPayload["device_class"] = "energy"; + autoconfPayload["state_class"] = "measurement"; + autoconfPayload["last_reset_value_template"] = "1970-01-01T00:00:00+00:00"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/total_consumption_tariff_2/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // total_production_tariff_1 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/total_production_tariff_1/status"; + autoconfPayload["state_topic"] = _identifier + "/power/total_production_tariff_1"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/total_production_tariff_1"; + autoconfPayload["name"] = _identifier + "_total_production_tariff_1"; + autoconfPayload["unit_of_measurement"] = "kWh"; + autoconfPayload["unique_id"] = "total_production_tariff_1"; + autoconfPayload["icon"] = "mdi:counter"; + autoconfPayload["device_class"] = "energy"; + autoconfPayload["state_class"] = "measurement"; + autoconfPayload["last_reset_value_template"] = "1970-01-01T00:00:00+00:00"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/total_production_tariff_1/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // total_production_tariff_2 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/total_production_tariff_2/status"; + autoconfPayload["state_topic"] = _identifier + "/power/total_production_tariff_2"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/total_production_tariff_2"; + autoconfPayload["name"] = _identifier + "_total_production_tariff_2"; + autoconfPayload["unit_of_measurement"] = "kWh"; + autoconfPayload["unique_id"] = "total_production_tariff_2"; + autoconfPayload["icon"] = "mdi:counter"; + autoconfPayload["device_class"] = "energy"; + autoconfPayload["state_class"] = "measurement"; + autoconfPayload["last_reset_value_template"] = "1970-01-01T00:00:00+00:00"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/total_production_tariff_2/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // power_tariff + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/power_tariff/status"; + autoconfPayload["state_topic"] = _identifier + "/power/power_tariff"; + autoconfPayload["name"] = _identifier + "_power_tariff"; + autoconfPayload["unique_id"] = "power_tariff"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/power_tariff/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // Extra stuff here + if (AUTOCONFIG_POWER_EXTENDED) + { + // short power outages + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/short_power_outages/status"; + autoconfPayload["state_topic"] = _identifier + "/power/short_power_outages"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/short_power_outages"; + autoconfPayload["name"] = _identifier + "_short_power_outages"; + autoconfPayload["unique_id"] = "short_power_outages"; + autoconfPayload["icon"] = "mdi:flash-off"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/short_power_outages/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // long power outages + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/long_power_outages/status"; + autoconfPayload["state_topic"] = _identifier + "/power/long_power_outages"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/long_power_outages"; + autoconfPayload["name"] = _identifier + "_long_power_outages"; + autoconfPayload["unique_id"] = "long_power_outages"; + autoconfPayload["icon"] = "mdi:flash-off"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/long_power_outages/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // instant current phase 1 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_1/current/status"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_1/current"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_1/current"; + autoconfPayload["name"] = _identifier + "_phase_1_current"; + autoconfPayload["unit_of_measurement"] = "A"; + autoconfPayload["unique_id"] = "phase_1_current"; + autoconfPayload["icon"] = "mdi:flash"; + autoconfPayload["device_class"] = "current"; + autoconfPayload["state_class"] = "measurement"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_1_current/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // instant current phase 2 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_2/current/status"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_2/current"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_2/current"; + autoconfPayload["name"] = _identifier + "_phase_2_current"; + autoconfPayload["unit_of_measurement"] = "A"; + autoconfPayload["unique_id"] = "phase_2_current"; + autoconfPayload["icon"] = "mdi:flash"; + autoconfPayload["device_class"] = "current"; + autoconfPayload["state_class"] = "measurement"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_2_current/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // instant current phase 3 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_3/current/status"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_3/current"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_3/current"; + autoconfPayload["name"] = _identifier + "_phase_3_current"; + autoconfPayload["unit_of_measurement"] = "A"; + autoconfPayload["unique_id"] = "phase_3_current"; + autoconfPayload["icon"] = "mdi:flash"; + autoconfPayload["device_class"] = "current"; + autoconfPayload["state_class"] = "measurement"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_3_current/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // instant consumption phase 1 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_1/consumption/status"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_1/consumption"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_1/consumption"; + autoconfPayload["name"] = _identifier + "_phase_1_consumption"; + autoconfPayload["unit_of_measurement"] = "kW"; + autoconfPayload["unique_id"] = "phase_1_consumption"; + autoconfPayload["icon"] = "mdi:flash"; + autoconfPayload["device_class"] = "power"; + autoconfPayload["state_class"] = "measurement"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_1_consumption/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // instant consumption phase 2 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_2/consumption/status"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_2/consumption"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_2/consumption"; + autoconfPayload["name"] = _identifier + "_phase_2_consumption"; + autoconfPayload["unit_of_measurement"] = "kW"; + autoconfPayload["unique_id"] = "phase_2_consumption"; + autoconfPayload["icon"] = "mdi:flash"; + autoconfPayload["device_class"] = "power"; + autoconfPayload["state_class"] = "measurement"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_2_consumption/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // instant consumption phase 3 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_3/consumption/status"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_3/consumption"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_3/consumption"; + autoconfPayload["name"] = _identifier + "_phase_3_consumption"; + autoconfPayload["unit_of_measurement"] = "kW"; + autoconfPayload["unique_id"] = "phase_3_consumption"; + autoconfPayload["icon"] = "mdi:flash"; + autoconfPayload["device_class"] = "power"; + autoconfPayload["state_class"] = "measurement"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_3_consumption/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // instant production phase 1 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_1/production/status"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_1/production"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_1/production"; + autoconfPayload["name"] = _identifier + "_phase_1_production"; + autoconfPayload["unit_of_measurement"] = "kW"; + autoconfPayload["unique_id"] = "phase_1_production"; + autoconfPayload["icon"] = "mdi:flash"; + autoconfPayload["device_class"] = "power"; + autoconfPayload["state_class"] = "measurement"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_1_production/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // instant production phase 2 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_2/production/status"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_2/production"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_2/production"; + autoconfPayload["name"] = _identifier + "_phase_2_production"; + autoconfPayload["unit_of_measurement"] = "kW"; + autoconfPayload["unique_id"] = "phase_2_production"; + autoconfPayload["icon"] = "mdi:flash"; + autoconfPayload["device_class"] = "power"; + autoconfPayload["state_class"] = "measurement"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_2_production/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // instant production phase 1 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_3/production/status"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_3/production"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_3/production"; + autoconfPayload["name"] = _identifier + "_phase_3_production"; + autoconfPayload["unit_of_measurement"] = "kW"; + autoconfPayload["unique_id"] = "phase_3_production"; + autoconfPayload["icon"] = "mdi:flash"; + autoconfPayload["device_class"] = "power"; + autoconfPayload["state_class"] = "measurement"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_3_production/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // short drops phase 1 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_1/drops/status"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_1/drops"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_1/drops"; + autoconfPayload["name"] = _identifier + "_phase_1_drops"; + autoconfPayload["unique_id"] = "phase_1_drops"; + autoconfPayload["icon"] = "mdi:chart-sankey"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_1_drops/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // short drops phase 2 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_2/drops/status"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_2/drops"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_2/drops"; + autoconfPayload["name"] = _identifier + "_phase_2_drops"; + autoconfPayload["unique_id"] = "phase_2_drops"; + autoconfPayload["icon"] = "mdi:chart-sankey"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_2_drops/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // short drops phase 3 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_3/drops/status"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_3/drops"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_3/drops"; + autoconfPayload["name"] = _identifier + "_phase_3_drops"; + autoconfPayload["unique_id"] = "phase_3_drops"; + autoconfPayload["icon"] = "mdi:chart-sankey"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_3_drops/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // short peaks phase 1 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_1/drops/peaks"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_1/peaks"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_1/peaks"; + autoconfPayload["name"] = _identifier + "_phase_1_peaks"; + autoconfPayload["unique_id"] = "phase_1_peaks"; + autoconfPayload["icon"] = "mdi:chart-bell-curve"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_1_peaks/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // short peaks phase 2 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_2/drops/peaks"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_2/peaks"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_2/peaks"; + autoconfPayload["name"] = _identifier + "_phase_2_peaks"; + autoconfPayload["unique_id"] = "phase_2_peaks"; + autoconfPayload["icon"] = "mdi:chart-bell-curve"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_2_peaks/config", &mqttPayload[0], false); + autoconfPayload.clear(); + + // short peaks phase 3 + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "/power/phase_3/drops/peaks"; + autoconfPayload["state_topic"] = _identifier + "/power/phase_3/peaks"; + autoconfPayload["last_reset_topic"] = _identifier + "/power/phase_3/peaks"; + autoconfPayload["name"] = _identifier + "_phase_3_peaks"; + autoconfPayload["unique_id"] = "phase_3_peaks"; + autoconfPayload["icon"] = "mdi:chart-bell-curve"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/phase_3_peaks/config", &mqttPayload[0], false); + autoconfPayload.clear(); + } + + if (AUTOCONFIG_GAS) + { + // Gas + autoconfPayload["device"] = device.as(); + autoconfPayload["availability_topic"] = _identifier + "gas/total/status"; + autoconfPayload["state_topic"] = _identifier + "gas/total"; + autoconfPayload["last_reset_topic"] = _identifier + "gas/total"; + autoconfPayload["name"] = _identifier + "_total_gas"; + autoconfPayload["unit_of_measurement"] = "kWh"; + autoconfPayload["unique_id"] = "gas/total"; + autoconfPayload["icon"] = "mdi:counter"; + autoconfPayload["last_reset_value_template"] = "1970-01-01T00:00:00+00:00"; + serializeJson(autoconfPayload, mqttPayload); + _mqttPublisher.publish("homeassistant/sensor/" + _identifier + "/gas_total/config", &mqttPayload[0], false); + autoconfPayload.clear(); + } +} diff --git a/AutoConfig.h b/AutoConfig.h index f133824..8ce658f 100644 --- a/AutoConfig.h +++ b/AutoConfig.h @@ -1,65 +1,19 @@ +#pragma once +#include #include "MQTTPublisher.h" #include "Settings.h" #include "Logger.h" -#pragma once - -namespace AutoConfig +class AutoConfig { -Logger logger; - -void SendConfig(MQTTPublisher mqttPublisher, char identifier[24]) -{ - logger = Logger("AutoConfig"); - logger.info("Start auto config"); - - char mqttPayload[2048]; - DynamicJsonDocument device(256); - DynamicJsonDocument autoconfPayload(1024); - StaticJsonDocument<64> identifiersDoc; - JsonArray identifiers = identifiersDoc.to(); - - // Set device properties - identifiers.add(identifier); - device["identifiers"] = identifiers; - device["manufacturer"] = "Bram2202"; - device["model"] = "ESP - DSMR"; - device["name"] = identifier; - device["sw_version"] = "v1.3.0"; - - // Set sensor properties - mqttPublisher.publish("test", "test", true); - - // power_consumption - autoconfPayload["device"] = device.as(); - autoconfPayload["availability_topic"] = String(identifier) + "/power/consumption/status"; - autoconfPayload["state_topic"] = String(identifier) + "/power/consumption"; - autoconfPayload["name"] = String(identifier) + "_power_consumption"; - autoconfPayload["unit_of_measurement"] = "kW"; - autoconfPayload["unique_id"] = "power_consumption"; - autoconfPayload["icon"] = "mdi:flash"; - autoconfPayload["device_class"] = "power"; - autoconfPayload["state_class"] = "measurement"; - serializeJson(autoconfPayload, mqttPayload); - mqttPublisher.publish("homeassistant/sensor/" + String(identifier) + "/power_consumption/config", &mqttPayload[0], false); - - autoconfPayload.clear(); - logger.info("1st send"); - - // power_production - autoconfPayload["device"] = device.as(); - autoconfPayload["availability_topic"] = String(identifier) + "/power/production/status"; - autoconfPayload["state_topic"] = String(identifier) + "/power/production"; - autoconfPayload["name"] = String(identifier) + "_power_production"; - autoconfPayload["unit_of_measurement"] = "kW"; - autoconfPayload["unique_id"] = "power_production"; - autoconfPayload["icon"] = "mdi:flash"; - autoconfPayload["device_class"] = "power"; - autoconfPayload["state_class"] = "measurement"; - serializeJson(autoconfPayload, mqttPayload); - mqttPublisher.publish("homeassistant/sensor/" + String(identifier) + "/power_production/config", &mqttPayload[0], false); - - autoconfPayload.clear(); - logger.info("2nd send"); -} -} +private: + Logger logger; + MQTTPublisher _mqttPublisher; + String _identifier; + +public: + AutoConfig(MQTTPublisher& mqttPublisher, String identifier); + AutoConfig(); + + void SendConfig(); +}; \ No newline at end of file diff --git a/MQTTPublisher.cpp b/MQTTPublisher.cpp index 376929b..decc29a 100644 --- a/MQTTPublisher.cpp +++ b/MQTTPublisher.cpp @@ -96,10 +96,7 @@ bool MQTTPublisher::publish(String topic, String msg, bool addIdentifier) topic = _identifier + "/" + topic; logger.debug("Publish to: " + topic + ": " + msg); - //int henk = sizeof(msg.c_str()); - //logger.debug("size : " + String(henk)); - - auto retVal = client.publish(topic.c_str(), msg.c_str(), false); + auto retVal = client.publish(topic.c_str(), msg.c_str(), true); yield(); if (!retVal) diff --git a/MQTTPublisher.h b/MQTTPublisher.h index 3e85e82..9ed4275 100644 --- a/MQTTPublisher.h +++ b/MQTTPublisher.h @@ -19,17 +19,16 @@ class MQTTPublisher bool _debugMode; String _identifier; bool isStarted; - uint32_t lastConnectionAttempt = 0; // last reconnect uint32_t lastUpdateMqtt; // last data send bool reconnect(); String getTopic(String name); + public: MQTTPublisher(String identifier); MQTTPublisher(); - void start(); void stop(); void handle(); diff --git a/README.md b/README.md index 6fff287..e04fbf8 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ Can be powered directly from the meter itself, no external power supply needed*. The code should work on DSRM v2.2 and higher, only tested on V4.2.
Supports Dutch and Belgian smart meters.
+Can be used with Home Assistant (mqtt auto discover) + ## Board in action ![esp8266-dsmr](/docs/PCB_IRL.png "esp8266-dsmr") @@ -22,8 +24,17 @@ Supports Dutch and Belgian smart meters.
- [PubSubClient](https://pubsubclient.knolleary.net) - MQTT client - [Core for ESP8266](https://github.com/esp8266/Arduino) - Arduino core for ESP8266 WiFi chip +## Home Assistant + +If MQTT Discovery is enabled in Home Assistant [INFO](https://www.home-assistant.io/docs/mqtt/discovery/),
+the majority of the entities are auto-created and can be found on the integration page.
+Its posible to disale the gas and phase entities in the settings, [See Settings](#Settings). + ## Messages +The `MQTT_TOPIC` consists of "ESP_DSMR_" + ESP chip ID.
+For example: `ESP_DSMR_C491F3` + ### Info | Name | unit | DSMR code | MQTT topic | |:---- |:-------|:------ |:------| @@ -45,12 +56,12 @@ Supports Dutch and Belgian smart meters.
| instant current phase 1 | A | 1-0:31.7.0 |/power/phase_1/current | | instant current phase 2 | A | 1-0:51.7.0 |/power/phase_2/current | | instant current phase 3 | A | 1-0:71.7.0 |/power/phase_3/current | -| instant usage phase 1 | kW | 1-0:21.7.0 |/power/phase_1/usage | -| instant usage phase 2 | kW | 1-0:41.7.0 |/power/phase_2/usage | -| instant usage phase 3 | kW | 1-0:61.7.0 |/power/phase_3/usage | -| instant delivery phase 1 | kW | 1-0:22.7.0 |/power/phase_1/delivery | -| instant delivery phase 2 | kW | 1-0:42.7.0 |/power/phase_2/delivery | -| instant delivery phase 3 | kW | 1-0:62.7.0 |/power/phase_3/delivery | +| instant consumption phase 1 | kW | 1-0:21.7.0 |/power/phase_1/consumption | +| instant consumption phase 2 | kW | 1-0:41.7.0 |/power/phase_2/consumption | +| instant consumption phase 3 | kW | 1-0:61.7.0 |/power/phase_3/consumption | +| instant production phase 1 | kW | 1-0:22.7.0 |/power/phase_1/production | +| instant production phase 2 | kW | 1-0:42.7.0 |/power/phase_2/production | +| instant production phase 3 | kW | 1-0:62.7.0 |/power/phase_3/production | | short drops phase 1 | - | 1-0:32.32.0 | /power/phase_1/drops | | short drops phase 2 | - | 1-0:52.32.0 | /power/phase_2/drops | | short drops phase 3 | - | 1-0:72.32.0 | /power/phase_3/drops | @@ -81,7 +92,7 @@ The values for the day and night tariffs are different in the Netherlands compar Copy `Settings.example.h` to `Settings.h` and fill in the correct data. | Setting | default | Description| -|:------------- |:----- |:-------------:| +|:------------- |:----- |:-------------| | WIFI_HOSTNAME | ESP-DSMR | device name on network | | WIFI_SSID | - | Wifi name to connect to | | WIFI_PASSWORD | - | Wifi password | @@ -90,8 +101,8 @@ Copy `Settings.example.h` to `Settings.h` and fill in the correct data. | MQTT_USER_NAME| - | MQTT user name | | MQTT_PASSWORD | - | MQTT password | | MQTT_HOSTNAME| ESP-DSMR | MQTT name | -| MQTT_PREFIX | dsmr | MQTT prefix | -| USE_CLIENT_ID | FALSE | Use clientId in prefix | +| AUTOCONFIG_GAS | true | setup gas entity in HA | +| AUTOCONFIG_POWER_EXTENDED | true | setup all power entities in HA | | LOG_LEVEL | INFO | ( DEBUG / INFO / WARN ) | diff --git a/esp8266-dsmr.ino b/esp8266-dsmr.ino index 226b9d2..bc7afd4 100644 --- a/esp8266-dsmr.ino +++ b/esp8266-dsmr.ino @@ -18,6 +18,7 @@ typedef struct String key; // OBIS property key int start; // start of value in string int end; // end of value in string + bool online; enum { @@ -29,46 +30,47 @@ typedef struct } Measurement; const Measurement measurements[] = { - {"version", "1-3:0.2.8", 10, 12, Measurement::STRING}, - {"power/timestamp", "0-0:1.0.0", 10, 23, Measurement::STRING}, - {"power/device_id", "0-0:96.1.1", 11, 45, Measurement::STRING}, - {"power/consumption", "1-0:1.7.0", 10, 16, Measurement::FLOAT}, - {"power/production", "1-0:2.7.0", 10, 16, Measurement::FLOAT}, - {"power/total_consumption_tariff_1", "1-0:1.8.1", 10, 20, Measurement::FLOAT}, - {"power/total_consumption_tariff_2", "1-0:1.8.2", 10, 20, Measurement::FLOAT}, - {"power/total_production_tariff_1", "1-0:2.8.1", 10, 20, Measurement::FLOAT}, - {"power/total_production_tariff_2", "1-0:2.8.2", 10, 20, Measurement::FLOAT}, - {"power/power_tariff", "0-0:96.14.0", 12, 16, Measurement::INT}, - {"power/short_power_outages", "0-0:96.7.21", 12, 17, Measurement::INT}, - {"power/long_power_outages", "0-0:96.7.9", 11, 16, Measurement::INT}, - {"power/phase_1/short_power_drops", "1-0:32.32.0", 12, 17, Measurement::INT}, - {"power/phase_2/short_power_drops", "1-0:52.32.0", 12, 17, Measurement::INT}, - {"power/phase_3/short_power_drops", "1-0:72.32.0", 12, 17, Measurement::INT}, - {"power/phase_1/short_power_peaks", "1-0:32.36.0", 12, 17, Measurement::INT}, - {"power/phase_2/short_power_peaks", "1-0:52.36.0", 12, 17, Measurement::INT}, - {"power/phase_3/short_power_peaks", "1-0:72.36.0", 12, 17, Measurement::INT}, - {"power/phase_1/current", "1-0:31.7.0", 11, 14, Measurement::INT}, - {"power/phase_2/current", "1-0:51.7.0", 11, 14, Measurement::INT}, - {"power/phase_3/current", "1-0:71.7.0", 11, 14, Measurement::INT}, - {"power/phase_1/usage", "1-0:21.7.0", 11, 17, Measurement::FLOAT}, - {"power/phase_2/usage", "1-0:41.7.0", 11, 17, Measurement::FLOAT}, - {"power/phase_3/usage", "1-0:61.7.0", 11, 17, Measurement::FLOAT}, - {"power/phase_1/delivery", "1-0:22.7.0", 11, 17, Measurement::FLOAT}, - {"power/phase_2/delivery", "1-0:42.7.0", 11, 17, Measurement::FLOAT}, - {"power/phase_3/delivery", "1-0:62.7.0", 11, 17, Measurement::FLOAT}, - {"gas/total", "0-1:24.2.1", 26, 35, Measurement::FLOAT}, - {"gas/device_id", "0-1:96.1.0", 11, 45, Measurement::STRING}, - {"gas/timestamp", "0-1:24.2.1", 11, 24, Measurement::STRING}, -}; + {"version", "1-3:0.2.8", 10, 12, false, Measurement::STRING}, + {"power/timestamp", "0-0:1.0.0", 10, 23, false, Measurement::STRING}, + {"power/device_id", "0-0:96.1.1", 11, 45, false, Measurement::STRING}, + {"power/consumption", "1-0:1.7.0", 10, 16, false, Measurement::FLOAT}, + {"power/production", "1-0:2.7.0", 10, 16, false, Measurement::FLOAT}, + {"power/total_consumption_tariff_1", "1-0:1.8.1", 10, 20, false, Measurement::FLOAT}, + {"power/total_consumption_tariff_2", "1-0:1.8.2", 10, 20, false, Measurement::FLOAT}, + {"power/total_production_tariff_1", "1-0:2.8.1", 10, 20, false, Measurement::FLOAT}, + {"power/total_production_tariff_2", "1-0:2.8.2", 10, 20, false, Measurement::FLOAT}, + {"power/power_tariff", "0-0:96.14.0", 12, 16, false, Measurement::INT}, + {"power/short_power_outages", "0-0:96.7.21", 12, 17, false, Measurement::INT}, + {"power/long_power_outages", "0-0:96.7.9", 11, 16, false, Measurement::INT}, + {"power/phase_1/short_power_drops", "1-0:32.32.0", 12, 17, false, Measurement::INT}, + {"power/phase_2/short_power_drops", "1-0:52.32.0", 12, 17, false, Measurement::INT}, + {"power/phase_3/short_power_drops", "1-0:72.32.0", 12, 17, false, Measurement::INT}, + {"power/phase_1/short_power_peaks", "1-0:32.36.0", 12, 17, false, Measurement::INT}, + {"power/phase_2/short_power_peaks", "1-0:52.36.0", 12, 17, false, Measurement::INT}, + {"power/phase_3/short_power_peaks", "1-0:72.36.0", 12, 17, false, Measurement::INT}, + {"power/phase_1/current", "1-0:31.7.0", 11, 14, false, Measurement::INT}, + {"power/phase_2/current", "1-0:51.7.0", 11, 14, false, Measurement::INT}, + {"power/phase_3/current", "1-0:71.7.0", 11, 14, false, Measurement::INT}, + {"power/phase_1/consumption", "1-0:21.7.0", 11, 17, false, Measurement::FLOAT}, + {"power/phase_2/consumption", "1-0:41.7.0", 11, 17, false, Measurement::FLOAT}, + {"power/phase_3/consumption", "1-0:61.7.0", 11, 17, false, Measurement::FLOAT}, + {"power/phase_1/production", "1-0:22.7.0", 11, 17, false, Measurement::FLOAT}, + {"power/phase_2/production", "1-0:42.7.0", 11, 17, false, Measurement::FLOAT}, + {"power/phase_3/production", "1-0:62.7.0", 11, 17, false, Measurement::FLOAT}, + {"gas/total", "0-1:24.2.1", 26, 35, false, Measurement::FLOAT}, + {"gas/device_id", "0-1:96.1.0", 11, 45, false, Measurement::STRING}, + {"gas/timestamp", "0-1:24.2.1", 11, 24, false, Measurement::STRING}}; MQTTPublisher mqttPublisher; WifiConnector wifiConnector; +AutoConfig autoConfig; WiFiUDP ntpUDP; String incomingString = ""; bool hasMQTT = false; bool hasWIFI = false; Logger logger = Logger("App"); char identifier[24]; +int valueState[29]; int rxPin = 3; int lvlPin = 5; @@ -100,7 +102,8 @@ void setup() ArduinoOTA.begin(); // Sent HA config - AutoConfig::SendConfig(mqttPublisher, identifier); + autoConfig = AutoConfig(mqttPublisher, identifier); + autoConfig.SendConfig(); logger.info("Setup complete"); } @@ -153,7 +156,15 @@ void handleString(String incomingString) break; } + // Check if measurement state is offline, if so publish online state + if (!measurement.online) + { + measurement.online = true; + mqttPublisher.publish(measurement.name + "/status", "online", true); + } + + // Publish measurement mqttPublisher.publish(measurement.name, value, true); } } -} +} \ No newline at end of file