From 76800fdda124f47419bf57809e1b8d924d3c3fdd Mon Sep 17 00:00:00 2001 From: Joost den Boer Date: Thu, 15 Apr 2021 22:02:44 +0200 Subject: [PATCH 1/8] Reworking parsing of OBIS properties by using a array of measurement structs containing a name (used for topic), OBIS keys, etc. Adding additional properties for Kaifa 304 meter. Added a Logger component for more concise logging. Changed topic structure : TOPIC_PREFIX / / . E.g. "esp-dsmr/b18206/power/total_consumption_low" --- Logger.cpp | 29 ++++++ Logger.h | 14 +++ MQTTPublisher.cpp | 210 +++++++++++++++++++++---------------------- MQTTPublisher.h | 10 ++- Settings.example.h | 5 +- WifiConnector.cpp | 37 +++----- WifiConnector.h | 7 +- esp8266-dsmr.ino | 218 +++++++++++++++++++++++++++------------------ 8 files changed, 298 insertions(+), 232 deletions(-) create mode 100644 Logger.cpp create mode 100644 Logger.h diff --git a/Logger.cpp b/Logger.cpp new file mode 100644 index 0000000..c3a6250 --- /dev/null +++ b/Logger.cpp @@ -0,0 +1,29 @@ +#include "Logger.h" +#include "Settings.h" + +// Create Wifi Connector +Logger::Logger(String name) +{ + _name = name; +} + +void Logger::debug(String msg) +{ + if (LOG_LEVEL <= DEBUG) { + Serial.println("DEBUG - " + _name + ":" + msg); + } +} + +void Logger::info(String msg) +{ + if (LOG_LEVEL <= INFO) { + Serial.println("INFO - " + _name + ":" + msg); + } +} + +void Logger::warn(String msg) +{ + if (LOG_LEVEL <= WARN) { + Serial.println("WARN - " + _name + ":" + msg); + } +} diff --git a/Logger.h b/Logger.h new file mode 100644 index 0000000..1628704 --- /dev/null +++ b/Logger.h @@ -0,0 +1,14 @@ +#pragma once +#include + +class Logger +{ + private: + String _name; + + public: + Logger(String name = "Logger"); + void info(String msg); + void debug(String msg); + void warn(String msg); +}; diff --git a/MQTTPublisher.cpp b/MQTTPublisher.cpp index 681f431..c28b28c 100644 --- a/MQTTPublisher.cpp +++ b/MQTTPublisher.cpp @@ -1,109 +1,101 @@ -#include "MQTTPublisher.h" -#include "Settings.h" - -WiFiClient espClient; -PubSubClient client(espClient); - -MQTTPublisher::MQTTPublisher(bool inDebugMode) -{ - randomSeed(micros()); - debugMode = inDebugMode; -} - -MQTTPublisher::~MQTTPublisher() -{ - client.publish(MQTT_HOSTNAME, "offline"); - client.disconnect(); -} - -bool MQTTPublisher::reconnect() -{ - lastConnectionAttempt = millis(); - - if (debugMode) - { - Serial.println("MQTT) Attempt connection to server: " + String(MQTT_HOST_NAME)); - } - - // Create a random client ID - String clientId = String(MQTT_HOSTNAME) + "-"; - clientId += String(random(0xffff), HEX); - - // Attempt to connect - bool clientConnected; - if (String(MQTT_USER_NAME).length()) - { - Serial.println("MQTT) Connecting with credientials"); - clientConnected = client.connect(clientId.c_str(), MQTT_USER_NAME, MQTT_PASSWORD); - } - else - { - Serial.println("MQTT) Connecting without credentials"); - clientConnected = client.connect(clientId.c_str()); - } - - if (clientConnected) - { - if (debugMode) { - Serial.println("MQTT) connected"); - } - - hasMQTT = true; - - // Once connected, publish an announcement... - client.publish(MQTT_HOSTNAME, "online"); - - return true; - } else { - - if (debugMode) - { - Serial.println("MQTT) failed, rc="); - Serial.println(client.state()); - } - - } - - return false; -} - - -void MQTTPublisher::start() -{ - if (String(MQTT_HOST_NAME).length() == 0 || MQTT_PORT == 0) - { - Serial.println("MQTT) disabled. No hostname or port set."); - return; //not configured - } - - if (debugMode){ - Serial.println("MQTT) enabled. Connecting."); - } - - client.setServer(MQTT_HOST_NAME, MQTT_PORT); - reconnect(); - isStarted = true; -} - -void MQTTPublisher::stop() -{ - isStarted = false; -} - -void MQTTPublisher::handle() -{ - if (!isStarted) - return; - - if (!client.connected() && millis() - lastConnectionAttempt > RECONNECT_TIMEOUT) { - hasMQTT = false; - if (!reconnect()) return; - } -} - -bool MQTTPublisher::publishOnMQTT(String prepend, String topic, String value) -{ - auto retVal = client.publish((prepend.c_str() + topic).c_str(), value.c_str()); - yield(); - return retVal; -} +#include "MQTTPublisher.h" +#include "Settings.h" + +WiFiClient espClient; +PubSubClient client(espClient); + +MQTTPublisher::MQTTPublisher(String clientId) +{ + 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) +{ + return String(MQTT_PREFIX) + '/' + _clientId + '/' + name; +} + +bool MQTTPublisher::reconnect() +{ + lastConnectionAttempt = millis(); + + logger.debug("Attempt connection to server: " + String(MQTT_HOST_NAME)); + + // Attempt to connect + bool clientConnected; + if (String(MQTT_USER_NAME).length()) + { + logger.info("Connecting with credientials"); + clientConnected = client.connect(_clientId.c_str(), MQTT_USER_NAME, MQTT_PASSWORD); + } + else + { + logger.info("Connecting without credentials"); + clientConnected = client.connect(_clientId.c_str()); + } + + if (clientConnected) + { + logger.debug("connected"); + + hasMQTT = true; + + // Once connected, publish an announcement... + client.publish(getTopic("status").c_str(), "online"); + + return true; + } else { + logger.warn("failed, rc=" + client.state()); + } + + return false; +} + + +void MQTTPublisher::start() +{ + if (String(MQTT_HOST_NAME).length() == 0 || MQTT_PORT == 0) + { + logger.warn("disabled. No hostname or port set."); + return; //not configured + } + + logger.debug("enabled. Connecting."); + + client.setServer(MQTT_HOST_NAME, MQTT_PORT); + reconnect(); + isStarted = true; +} + +void MQTTPublisher::stop() +{ + isStarted = false; +} + +void MQTTPublisher::handle() +{ + if (!isStarted) + return; + + if (!client.connected() && millis() - lastConnectionAttempt > RECONNECT_TIMEOUT) { + hasMQTT = false; + if (!reconnect()) return; + } +} + +bool MQTTPublisher::publishOnMQTT(String topicSuffix, String msg) +{ + String topic = getTopic(topicSuffix); + logger.debug("Publish to '" + topic + "':" + msg); + auto retVal = client.publish(topic.c_str(), msg.c_str()); + yield(); + return retVal; +} diff --git a/MQTTPublisher.h b/MQTTPublisher.h index 3fd8494..7e95d1c 100644 --- a/MQTTPublisher.h +++ b/MQTTPublisher.h @@ -5,6 +5,7 @@ #include #include "PubSubClient.h" #include "WiFiClient.h" +#include "Logger.h" #define RECONNECT_TIMEOUT 15000 @@ -14,20 +15,23 @@ extern bool hasWIFI; class MQTTPublisher { private: - bool debugMode; + Logger logger; + bool _debugMode; + String _clientId; bool isStarted; uint32_t lastConnectionAttempt = 0; // last reconnect uint32_t lastUpdateMqtt; // last data send bool reconnect(); + String getTopic(String name); public: - MQTTPublisher(bool inDebugMode = false); + MQTTPublisher(String clientId = String(ESP.getChipId(), HEX)); ~MQTTPublisher(); void start(); void stop(); void handle(); - bool publishOnMQTT(String prepend, String topic, String value); + bool publishOnMQTT(String topic, String msg); }; diff --git a/Settings.example.h b/Settings.example.h index 962cc71..7966a6d 100644 --- a/Settings.example.h +++ b/Settings.example.h @@ -26,4 +26,7 @@ #define MQTT_TOPIC "dsmr" //for debugging, print info on serial -#define DEBUGE_MODE true \ No newline at end of file +#define DEBUG 1 +#define INFO 2 +#define WARN 3 +#define LOG_LEVEL DEBUG diff --git a/WifiConnector.cpp b/WifiConnector.cpp index 3644efd..0f8e693 100644 --- a/WifiConnector.cpp +++ b/WifiConnector.cpp @@ -7,9 +7,9 @@ #include "ESP8266mDNS.h" // Create Wifi Connector -WifiConnector::WifiConnector(bool inDebugMode) +WifiConnector::WifiConnector() { - debugMode = inDebugMode; + logger = Logger("WifiConnector"); tryingReconnect = false; } @@ -17,9 +17,7 @@ WifiConnector::WifiConnector(bool inDebugMode) void WifiConnector::start() { - if (debugMode){ - Serial.println("Wifi) Start "); - } + logger.info("Start"); // Setup Wifi WiFi.mode(WIFI_STA); @@ -30,30 +28,21 @@ void WifiConnector::start() // Wait until unit has wifi before continuing while (WiFi.status() != WL_CONNECTED) { delay(500); - if (debugMode){ - Serial.print("."); - } + logger.debug("."); } // Set wifi bool hasWIFI = true; - if (debugMode) - { - Serial.println("Wifi) Connected!"); - Serial.println("Wifi) IP: "); - Serial.println(WiFi.localIP()); - } - + logger.info("Connected!"); + logger.debug("IP: " + WiFi.localIP()); } // If wifi connection is lost, try to reconnect void WifiConnector::reconnect() { - if (debugMode){ - Serial.println("Wifi) Try to reconnect!"); - } + logger.debug("Try to reconnect!"); // First hit, try to reconnect. if(!tryingReconnect) @@ -71,9 +60,7 @@ void WifiConnector::handle() // Check if WIfi is Connected if(!WiFi.isConnected() && !tryingReconnect){ - if (debugMode){ - Serial.println("Wifi) Disconnected!"); - } + logger.info("Disconnected!"); // Set bool false and try to reconnect hasWIFI = false; @@ -81,13 +68,9 @@ void WifiConnector::handle() }else if (WiFi.isConnected() && !hasWIFI){ // Wifi is Reconnected - if (debugMode){ - Serial.println("Wifi) Reconnected!"); - } + logger.info("Reconnected!"); hasWIFI = true; tryingReconnect = false; - } - -} \ No newline at end of file +} diff --git a/WifiConnector.h b/WifiConnector.h index 88bd0b2..6fa6463 100644 --- a/WifiConnector.h +++ b/WifiConnector.h @@ -1,16 +1,17 @@ #pragma once +#include "Logger.h" extern bool hasWIFI; class WifiConnector { private: - bool debugMode; + Logger logger; bool tryingReconnect; public: - WifiConnector(bool inDebugMode = false); + WifiConnector(); void start(); void handle(); void reconnect(); -}; \ No newline at end of file +}; diff --git a/esp8266-dsmr.ino b/esp8266-dsmr.ino index 59425b9..f3c909f 100644 --- a/esp8266-dsmr.ino +++ b/esp8266-dsmr.ino @@ -6,13 +6,105 @@ #include "WifiConnector.h" #include "ESP8266mDNS.h" #include "Settings.h" +#include "Logger.h" -MQTTPublisher mqqtPublisher(DEBUGE_MODE); -WifiConnector wifiConnector(DEBUGE_MODE); +//enum ValueType { STRING, FLOAT } + +typedef struct { + String name; + String key; // OBIS property key + int start; // start of value in string + int end; // end of value in string + + enum { + STRING, + FLOAT, + INT + } valueType; + +} 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/power_consuption" , "1-0:1.7.0" , 10, 16, Measurement::FLOAT }, + { "power/power_production" , "1-0:2.7.0" , 10, 16, Measurement::FLOAT }, + { "power/total_consuption_low" , "1-0:1.8.1" , 10, 20, Measurement::FLOAT }, + { "power/total_consuption_high" , "1-0:1.8.2" , 10, 20, Measurement::FLOAT }, + { "power/total_production_low" , "1-0:2.8.1" , 10, 20, Measurement::FLOAT }, + { "power/total_production_high" , "1-0:2.8.2" , 10, 20, Measurement::FLOAT }, + { "gas/total" , "0-1:24.2.1" , 26, 35, Measurement::FLOAT }, + { "power/power_tariff" , "0-0:96.14.0", 12, 16, Measurement::INT}, + // Additional properties as available on Kaifa 304 + // specs: https://www.netbeheernederland.nl/_upload/Files/Slimme_meter_15_a727fce1f1.pdf + // Kaifa: https://www.liander.nl/sites/default/files/Meters-Handleidingen-elektriciteit-Kaifa-uitgebreid.pdf + { "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/instant_current" , "1-0:31.7.0" , 11, 14, Measurement::INT }, + { "power/phase_2/instant_current" , "1-0:51.7.0" , 11, 14, Measurement::INT }, + { "power/phase_3/instant_current" , "1-0:71.7.0" , 11, 14, Measurement::INT }, + { "power/phase_1/instant_usage" , "1-0:21.7.0" , 11, 17, Measurement::FLOAT }, + { "power/phase_2/instant_usage" , "1-0:41.7.0" , 11, 17, Measurement::FLOAT }, + { "power/phase_3/instant_usage" , "1-0:61.7.0" , 11, 17, Measurement::FLOAT }, + { "power/phase_1/instant_delivery" , "1-0:22.7.0" , 11, 17, Measurement::FLOAT }, + { "power/phase_2/instant_delivery" , "1-0:42.7.0" , 11, 17, Measurement::FLOAT }, + { "power/phase_3/instant_delivery" , "1-0:62.7.0" , 11, 17, 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; +WifiConnector wifiConnector; WiFiUDP ntpUDP; String incomingString = ""; bool hasMQTT = false; bool hasWIFI = false; +Logger logger = Logger("App"); + +void test() { + handleString("/KFM5KAIFA-METER"); + handleString("1-3:0.2.8(42)"); + handleString("0-0:1.0.0(210413140243S)"); + handleString("0-0:96.1.1(4530303033303030303036343035333134)"); + handleString("1-0:1.8.1(019867.385*kWh)"); + handleString("1-0:1.8.2(010090.200*kWh)"); + handleString("1-0:2.8.1(003899.380*kWh)"); + handleString("1-0:2.8.2(009033.210*kWh)"); + handleString("0-0:96.14.0(0002)"); + handleString("1-0:1.7.0(00.708*kW)"); + handleString("1-0:2.7.0(00.001*kW)"); + handleString("0-0:96.7.21(00012)"); + handleString("0-0:96.7.9(00006)"); + handleString("1-0:99.97.0(5)(0-0:96.7.19)(181227144100W)(0000020430*s)(181219144343W)(0000021625*s)(161123070756W)(0000001349*s)(151126025422W)(0000004263*s)(000101000001W)(2147483647*s)"); + handleString("1-0:32.32.0(00001)"); + handleString("1-0:52.32.0(00002)"); + handleString("1-0:72.32.0(00003)"); + handleString("1-0:32.36.0(00004)"); + handleString("1-0:52.36.0(00005)"); + handleString("1-0:72.36.0(00006)"); + handleString("0-0:96.13.1()"); + handleString("0-0:96.13.0()"); + handleString("1-0:31.7.0(003*A)"); + handleString("1-0:51.7.0(006*A)"); + handleString("1-0:71.7.0(009*A)"); + handleString("1-0:21.7.0(00.596*kW)"); + handleString("1-0:22.7.0(00.091*kW)"); + handleString("1-0:41.7.0(00.112*kW)"); + handleString("1-0:42.7.0(00.092*kW)"); + handleString("1-0:61.7.0(00.002*kW)"); + handleString("1-0:62.7.0(00.093*kW)"); + handleString("0-1:24.1.0(003)"); + handleString("0-1:96.1.0(4730303233353631323233373631313134)"); + handleString("0-1:24.2.1(210413140000S)(04981.523*m3)"); + handleString("!ECD2"); +} void setup() { @@ -20,113 +112,61 @@ void setup() { Serial.begin(115200); pinMode(3, FUNCTION_0); - if (DEBUGE_MODE) { - Serial.println("Booting"); - } + logger.info("Booting"); // Setup Wifi + wifiConnector = WifiConnector(); wifiConnector.start(); // Setup MQTT - mqqtPublisher.start(); + mqttPublisher = MQTTPublisher(); + mqttPublisher.start(); + +// test(); } void loop() { wifiConnector.handle(); yield(); - mqqtPublisher.handle(); + mqttPublisher.handle(); yield(); // If serial received, read until newline if (Serial.available() > 0) { incomingString = Serial.readStringUntil('\n'); - handelString(incomingString); + handleString(incomingString); } } // Regex are not supported, so use indexOf and substring -void handelString(String incomingString) { - - // DSMR version - int found1 = incomingString.indexOf("1-3:0.2.8"); - if (found1 > -1) { - String value1 = incomingString.substring(10, 12); - if (DEBUGE_MODE) - Serial.println("0.2.8= " + value1); - mqqtPublisher.publishOnMQTT(MQTT_TOPIC, "/version", value1); - } - - // Power consuption - int found2 = incomingString.indexOf("1-0:1.7.0"); - if (found2 > -1) { - String value2 = String(incomingString.substring(10, 16).toFloat(), 3); - if (DEBUGE_MODE) - Serial.println("1.7.0= " + value2); - mqqtPublisher.publishOnMQTT(MQTT_TOPIC, "/power_consuption", value2); - } +void handleString(String incomingString) { - // Power production - int found3 = incomingString.indexOf("1-0:2.7.0"); - if (found3 > -1) { - String value3 = String(incomingString.substring(10, 16).toFloat(), 3); - if (DEBUGE_MODE) - Serial.println("2.7.0= " + value3); - mqqtPublisher.publishOnMQTT(MQTT_TOPIC, "/power_production", value3); - } - - // Total consuption low - int found4 = incomingString.indexOf("1-0:1.8.1"); - if (found4 > -1) { - String value4 = String(incomingString.substring(10, 20).toFloat(), 3); - if (DEBUGE_MODE) - Serial.println("1.8.1= " + value4); - mqqtPublisher.publishOnMQTT(MQTT_TOPIC, "/total_consuption_low", value4); - } - - // Total consuption high - int found5 = incomingString.indexOf("1-0:1.8.2"); - if (found5 > -1) { - String value5 = String(incomingString.substring(10, 20).toFloat(), 3); - if (DEBUGE_MODE) - Serial.println("1.8.2= " + value5); - mqqtPublisher.publishOnMQTT(MQTT_TOPIC, "/total_consuption_high", value5); - } - - // Total production low - int found6 = incomingString.indexOf("1-0:2.8.1"); - if (found6 > -1) { - String value6 = String(incomingString.substring(10, 20).toFloat(), 3); - if (DEBUGE_MODE) - Serial.println("2.8.1= " + value6); - mqqtPublisher.publishOnMQTT(MQTT_TOPIC, "/total_production_low", value6); - } - - // Total production high - int found7 = incomingString.indexOf("1-0:2.8.2"); - if (found7 > -1) { - String value7 = String(incomingString.substring(10, 20).toFloat(), 3); - if (DEBUGE_MODE) - Serial.println("2.8.2= " + value7); - mqqtPublisher.publishOnMQTT(MQTT_TOPIC, "/total_production_high", value7); - } - - // Total gas - int found8 = incomingString.indexOf("0-1:24.2.1"); - if (found8 > -1) { - String value8 = String(incomingString.substring(26, 35).toFloat(), 3); - if (DEBUGE_MODE) - Serial.println("24.2.1= " + value8); - mqqtPublisher.publishOnMQTT(MQTT_TOPIC, "/total_gas", value8); - } - - // Power tariff (1 low, 2 high) - int found9 = incomingString.indexOf("0-0:96.14.0"); - if (found9 > -1) { - String value9 = String(incomingString.substring(12, 16).toInt()); - if (DEBUGE_MODE) - Serial.println("96.14.0= " + value9); - mqqtPublisher.publishOnMQTT(MQTT_TOPIC, "/power_tariff", value9); + int i; + int arraySize = sizeof(measurements)/sizeof(measurements[0]); + + for (i = 0; i < arraySize; i++) { + Measurement measurement = measurements[i]; + String obisKey = measurement.key; + + if(incomingString.indexOf(obisKey) > -1) { + // found + String value = incomingString.substring(measurement.start, measurement.end); + logger.debug("DEBUG_1 " + obisKey + "=" + value); + + switch (measurement.valueType) { + case Measurement::FLOAT: + value = String(value.toFloat(), 3); + break; + case Measurement::INT: + value = String(value.toInt()); + break; + default: + break; + } + + mqttPublisher.publishOnMQTT(measurement.name, value); + //break; // incoming string has been handled. No need to continue. (for now) + } } - } From 0fc9dee9e699863782ac879fce2710987d5c358a Mon Sep 17 00:00:00 2001 From: Joost den Boer Date: Fri, 16 Apr 2021 08:50:13 +0200 Subject: [PATCH 2/8] Updated readme --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 1faa802..e50fb35 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,12 @@ # esp8266-dsmr + +> 16-04-2020: Based on Bram2202's [esp8266-dsmr](https://github.com/bram2202/esp8266-dsmr). +> - Extended number of supported properties to include all property values send by a [Kaifa 304](https://www.liander.nl/sites/default/files/Meters-Handleidingen-elektriciteit-Kaifa-uitgebreid.pdf) smart meter. Now in a simple structure and easy to extend. +> - Changed MQTT structure to `esp-dsmr//`. The property name can include additional `/`. E.g. for `1-0:31.7.0` (L1 instant usage), the MQTT topic is `esp-dsmr//power/phase_1/instant_usage`. +> +> See [code](https://github.com/diversit/esp8266-dsmr/blob/master/esp8266-dsmr.ino#L28) for all supported properties. + + A ESP8266 based DSMR reader, posting onto MQTT, powered directly from the meter itself, no external power supply needed.. All units (except power tariff and version) are rounded to 3 decimals. From c7b5a079d44ee4879d652ea0b51cf8ba8db87ec6 Mon Sep 17 00:00:00 2001 From: Joost den Boer Date: Fri, 16 Apr 2021 09:07:31 +0200 Subject: [PATCH 3/8] Fix date --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e50fb35..f0c86a2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # esp8266-dsmr -> 16-04-2020: Based on Bram2202's [esp8266-dsmr](https://github.com/bram2202/esp8266-dsmr). +> 16-04-2021: Based on Bram2202's [esp8266-dsmr](https://github.com/bram2202/esp8266-dsmr). > - Extended number of supported properties to include all property values send by a [Kaifa 304](https://www.liander.nl/sites/default/files/Meters-Handleidingen-elektriciteit-Kaifa-uitgebreid.pdf) smart meter. Now in a simple structure and easy to extend. > - Changed MQTT structure to `esp-dsmr//`. The property name can include additional `/`. E.g. for `1-0:31.7.0` (L1 instant usage), the MQTT topic is `esp-dsmr//power/phase_1/instant_usage`. > @@ -91,4 +91,4 @@ Connecting to the DSMR witn a RJ11 in Port 1 (P1), found on most smart meters. - If the level shifter inverter is connected, it's impossible to flash the firmware.
Pin RX is used, disconnect the pin to flash new firmware. - Some DSMR cannot deliver enough power to run the Wemos stably.
-Connect a 5V usb supply to fix this. \ No newline at end of file +Connect a 5V usb supply to fix this. From 49e7a08c99a9a670f42e929a713fed673f54f845 Mon Sep 17 00:00:00 2001 From: Joost den Boer Date: Fri, 16 Apr 2021 09:54:13 +0200 Subject: [PATCH 4/8] Update README --- README.md | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index f0c86a2..252aeb1 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ The code should work on DSRM v2.2 and higher, only tested on V4.2. ![esp8266-dsmr](https://github.com/bram2202/esp8266-dsmr/blob/master/docs/esp8266-dsmr.jpg "esp8266-dsmr") ## Requirements -* ESP8266 (Wemos/LOLIN D1 mini) +* ESP8266 (Wemos/LOLIN D1 mini/ESP01/NodeMCU) * Basic soldering and wiring skills * (For Wemos d1 mini) CH340G driver [[link]](https://wiki.wemos.cc/downloads) * Arduino IDE @@ -25,17 +25,11 @@ The code should work on DSRM v2.2 and higher, only tested on V4.2. ## Supported messages -| Name | unit | DSMR code | MQTT topic | -|:---- |:-------|:------ |:------| -| DSMR version | - | 0.2.8 | dsmr/power_consuption | -| power consuption | kW | 1.7.0 | dsmr/power_consuption | -| power prduction | kW | 2.7.0| dsmr/power_production | -| total consuption low | kWh | 1.8.1 | dsmr/total_consuption_low | -| total consuption high | kWh | 1.8.2 | dsmr/total_consuption_high | -| total production low | kWh | 2.8.1 | dsmr/total_production_low | -| total production high | kWh | 2.8.2 | dsmr/total_production_high | -| total gas | m3 | 24.2.1 | dsmr/total_gas | -| power tariff | 1 = low, 2 = high | 96.14.0 | dsmr/power_tariff | +See [code](https://github.com/diversit/esp8266-dsmr/blob/master/esp8266-dsmr.ino#L28) + +## Library dependencies +- [PubSubClient](https://pubsubclient.knolleary.net) - MQTT client +- [WifiManager](https://github.com/tzapu/WiFiManager) - Wifi client ## Settings Copy `Settings.example.h` to `Settings.h` and fill in the correct data. From 8b742f5738855fdc622db9568193136cbe26d404 Mon Sep 17 00:00:00 2001 From: Joost den Boer Date: Fri, 16 Apr 2021 10:55:12 +0200 Subject: [PATCH 5/8] Document Telegraf setup to capture all smart meter values in InfluxDB --- README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/README.md b/README.md index 252aeb1..3d89a4a 100644 --- a/README.md +++ b/README.md @@ -86,3 +86,40 @@ Connecting to the DSMR witn a RJ11 in Port 1 (P1), found on most smart meters. Pin RX is used, disconnect the pin to flash new firmware. - Some DSMR cannot deliver enough power to run the Wemos stably.
Connect a 5V usb supply to fix this. + +## Capture MQTT values with Telegraf into InfluxDB + +Since MQTT only contains the last value of a metric, when the consumer is temporary offline, all values in between are lost. +This can be solved by having Telegraf also monitoring your MQTT topics and store the values into an InfluxDB from which values can easily be displayed in graphs using Grafana. + +In `telegram.conf` the MQTT consumer input needs to be enabled. +Since the topic values created by ESP8266-DSMR are both Strings, Integers and Float, the data_format `value` is used with data_type `string` which supports all types. +All data seems to be put in Influx properly and Grafana can display graphs using those values. + +Data is stored in measurement 'mqtt_consumer' and have the 'topic' as tag. +Example query: +``` +SELECT "value" FROM "mqtt_consumer" WHERE ("topic" = 'esp-dsmr/fdc4f6/power/power_production') AND $timeFilter +``` + +Telegraf config: +``` +[[inputs.mqtt_consumer]] + servers = ["tcp://:1883"] + topics = [ + "esp-dsmr/fdc4f6/#" + ] + client_id = "telegraf" +# +# ## Username and password to connect MQTT server. +# # username = "telegraf" +# # password = "metricsmetricsmetricsmetrics" +# ## Data format to consume. +# ## Each data format has its own unique set of configuration options, read +# ## more about them here: +# ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md + data_format = "value" + data_type = "string" +``` + +Unfortunately with the used PubSub client, it is not possible to set the QoS and therefore it is not possible to use the persistent session feature, which would cache all values on the broker when Telegraf would be temporary offline. \ No newline at end of file From 4470fa89490951f3d73b6ba2a50d8db4112c52fa Mon Sep 17 00:00:00 2001 From: Bram van Deventer Date: Mon, 26 Apr 2021 16:09:11 +0200 Subject: [PATCH 6/8] Fix Readme (WIP) - Remove text - add back msg table - fix code styling --- README.md | 99 ++++++++++++++++++----------------- esp8266-dsmr.ino | 131 ++++++++++++++++++++++++----------------------- 2 files changed, 116 insertions(+), 114 deletions(-) diff --git a/README.md b/README.md index 3d89a4a..76c8ac0 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,5 @@ # esp8266-dsmr -> 16-04-2021: Based on Bram2202's [esp8266-dsmr](https://github.com/bram2202/esp8266-dsmr). -> - Extended number of supported properties to include all property values send by a [Kaifa 304](https://www.liander.nl/sites/default/files/Meters-Handleidingen-elektriciteit-Kaifa-uitgebreid.pdf) smart meter. Now in a simple structure and easy to extend. -> - Changed MQTT structure to `esp-dsmr//`. The property name can include additional `/`. E.g. for `1-0:31.7.0` (L1 instant usage), the MQTT topic is `esp-dsmr//power/phase_1/instant_usage`. -> -> See [code](https://github.com/diversit/esp8266-dsmr/blob/master/esp8266-dsmr.ino#L28) for all supported properties. - - A ESP8266 based DSMR reader, posting onto MQTT, powered directly from the meter itself, no external power supply needed.. All units (except power tariff and version) are rounded to 3 decimals. @@ -21,15 +14,58 @@ The code should work on DSRM v2.2 and higher, only tested on V4.2. * (For Wemos d1 mini) CH340G driver [[link]](https://wiki.wemos.cc/downloads) * Arduino IDE * Hardware package for arduino [[LINK]](https://github.com/esp8266/Arduino) -* MQTT lib. for Arduino [[LINK]](https://pubsubclient.knolleary.net/) +## Library dependencies +- [PubSubClient](https://pubsubclient.knolleary.net) - MQTT client +- [WifiManager](https://github.com/esp8266/Arduino) - Wifi client ## Supported messages -See [code](https://github.com/diversit/esp8266-dsmr/blob/master/esp8266-dsmr.ino#L28) -## Library dependencies -- [PubSubClient](https://pubsubclient.knolleary.net) - MQTT client -- [WifiManager](https://github.com/tzapu/WiFiManager) - Wifi client +### Info +| Name | unit | DSMR code | MQTT topic | +|:---- |:-------|:------ |:------| +| DSMR version | - | 1-3:0.2.8 | /version | + +### Power +| Name | unit | DSMR code | MQTT topic | +|:---- |:-------|:------ |:------| +| current power consumption | kW | 1-0:1.7.0 | /power/consumption | +| current power production | kW | 1-0:2.7.0| /power/production | +| total consumption low | kWh | 1-0:1.8.1 | /power/total_consumption_low | +| total consumption high | kWh | 1-0:1.8.2 | /power/total_consumption_high | +| total production low | kWh | 1-0:2.8.1 | /power/total_production_low | +| total production high | kWh | 1-0:2.8.2 | /power/total_production_high | +| power tariff | 1 = low, 2 = high | 0-0:96.14.0 | /power/power_tariff | +| timestamp| - | 0-0:1.0.0 | /power/timestamp | +| device id | - | 0-0:96.1.1 | /power/device | +| short power outages | - | 0-0:96.7.21 |/power/short_power_outages | +| long power outages | - | 0-0:96.7.9 |/power/long_power_outages | +| 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 | +| 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 | +| short peaks phase 1 | - | 1-0:32.36.0 | /power/phase_1/peaks | +| short peaks phase 2 | - | 1-0:52.36.0 | /power/phase_2/peaks | +| short peaks phase 3 | - | 1-0:72.36.0 | /power/phase_3/peaks | + + +### Gas +| Name | unit | DSMR code | MQTT topic | +|:---- |:-------|:------ |:------| +| total gas | m3 | 0-1:24.2.1 | /gas/total | +| timestamp| - | 0-1:24.2.1| /gas/timestamp | +| device id | - | 0-1:96.1.0 | /gas/device | + + + ## Settings Copy `Settings.example.h` to `Settings.h` and fill in the correct data. @@ -85,41 +121,4 @@ Connecting to the DSMR witn a RJ11 in Port 1 (P1), found on most smart meters. - If the level shifter inverter is connected, it's impossible to flash the firmware.
Pin RX is used, disconnect the pin to flash new firmware. - Some DSMR cannot deliver enough power to run the Wemos stably.
-Connect a 5V usb supply to fix this. - -## Capture MQTT values with Telegraf into InfluxDB - -Since MQTT only contains the last value of a metric, when the consumer is temporary offline, all values in between are lost. -This can be solved by having Telegraf also monitoring your MQTT topics and store the values into an InfluxDB from which values can easily be displayed in graphs using Grafana. - -In `telegram.conf` the MQTT consumer input needs to be enabled. -Since the topic values created by ESP8266-DSMR are both Strings, Integers and Float, the data_format `value` is used with data_type `string` which supports all types. -All data seems to be put in Influx properly and Grafana can display graphs using those values. - -Data is stored in measurement 'mqtt_consumer' and have the 'topic' as tag. -Example query: -``` -SELECT "value" FROM "mqtt_consumer" WHERE ("topic" = 'esp-dsmr/fdc4f6/power/power_production') AND $timeFilter -``` - -Telegraf config: -``` -[[inputs.mqtt_consumer]] - servers = ["tcp://:1883"] - topics = [ - "esp-dsmr/fdc4f6/#" - ] - client_id = "telegraf" -# -# ## Username and password to connect MQTT server. -# # username = "telegraf" -# # password = "metricsmetricsmetricsmetrics" -# ## Data format to consume. -# ## Each data format has its own unique set of configuration options, read -# ## more about them here: -# ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md - data_format = "value" - data_type = "string" -``` - -Unfortunately with the used PubSub client, it is not possible to set the QoS and therefore it is not possible to use the persistent session feature, which would cache all values on the broker when Telegraf would be temporary offline. \ No newline at end of file +Connect a 5V usb supply to fix this. \ No newline at end of file diff --git a/esp8266-dsmr.ino b/esp8266-dsmr.ino index f3c909f..52f1ecd 100644 --- a/esp8266-dsmr.ino +++ b/esp8266-dsmr.ino @@ -8,56 +8,53 @@ #include "Settings.h" #include "Logger.h" -//enum ValueType { STRING, FLOAT } - -typedef struct { +typedef struct +{ String name; String key; // OBIS property key - int start; // start of value in string - int end; // end of value in string + int start; // start of value in string + int end; // end of value in string - enum { + enum + { STRING, FLOAT, INT } valueType; - + } 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/power_consuption" , "1-0:1.7.0" , 10, 16, Measurement::FLOAT }, - { "power/power_production" , "1-0:2.7.0" , 10, 16, Measurement::FLOAT }, - { "power/total_consuption_low" , "1-0:1.8.1" , 10, 20, Measurement::FLOAT }, - { "power/total_consuption_high" , "1-0:1.8.2" , 10, 20, Measurement::FLOAT }, - { "power/total_production_low" , "1-0:2.8.1" , 10, 20, Measurement::FLOAT }, - { "power/total_production_high" , "1-0:2.8.2" , 10, 20, Measurement::FLOAT }, - { "gas/total" , "0-1:24.2.1" , 26, 35, Measurement::FLOAT }, - { "power/power_tariff" , "0-0:96.14.0", 12, 16, Measurement::INT}, - // Additional properties as available on Kaifa 304 - // specs: https://www.netbeheernederland.nl/_upload/Files/Slimme_meter_15_a727fce1f1.pdf - // Kaifa: https://www.liander.nl/sites/default/files/Meters-Handleidingen-elektriciteit-Kaifa-uitgebreid.pdf - { "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/instant_current" , "1-0:31.7.0" , 11, 14, Measurement::INT }, - { "power/phase_2/instant_current" , "1-0:51.7.0" , 11, 14, Measurement::INT }, - { "power/phase_3/instant_current" , "1-0:71.7.0" , 11, 14, Measurement::INT }, - { "power/phase_1/instant_usage" , "1-0:21.7.0" , 11, 17, Measurement::FLOAT }, - { "power/phase_2/instant_usage" , "1-0:41.7.0" , 11, 17, Measurement::FLOAT }, - { "power/phase_3/instant_usage" , "1-0:61.7.0" , 11, 17, Measurement::FLOAT }, - { "power/phase_1/instant_delivery" , "1-0:22.7.0" , 11, 17, Measurement::FLOAT }, - { "power/phase_2/instant_delivery" , "1-0:42.7.0" , 11, 17, Measurement::FLOAT }, - { "power/phase_3/instant_delivery" , "1-0:62.7.0" , 11, 17, 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/consuption", "1-0:1.7.0", 10, 16, Measurement::FLOAT}, + {"power/production", "1-0:2.7.0", 10, 16, Measurement::FLOAT}, + {"power/total_consuption_low", "1-0:1.8.1", 10, 20, Measurement::FLOAT}, + {"power/total_consuption_high", "1-0:1.8.2", 10, 20, Measurement::FLOAT}, + {"power/total_production_low", "1-0:2.8.1", 10, 20, Measurement::FLOAT}, + {"power/total_production_high", "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; @@ -68,7 +65,8 @@ bool hasMQTT = false; bool hasWIFI = false; Logger logger = Logger("App"); -void test() { +void test() +{ handleString("/KFM5KAIFA-METER"); handleString("1-3:0.2.8(42)"); handleString("0-0:1.0.0(210413140243S)"); @@ -103,10 +101,11 @@ void test() { handleString("0-1:24.1.0(003)"); handleString("0-1:96.1.0(4730303233353631323233373631313134)"); handleString("0-1:24.2.1(210413140000S)(04981.523*m3)"); - handleString("!ECD2"); + handleString("!ECD2"); } -void setup() { +void setup() +{ // Start serial ESP8266 RX port (pin 3) Serial.begin(115200); @@ -121,50 +120,54 @@ void setup() { // Setup MQTT mqttPublisher = MQTTPublisher(); mqttPublisher.start(); - -// test(); } -void loop() { - +void loop() +{ + wifiConnector.handle(); yield(); mqttPublisher.handle(); yield(); // If serial received, read until newline - if (Serial.available() > 0) { + if (Serial.available() > 0) + { incomingString = Serial.readStringUntil('\n'); handleString(incomingString); } } // Regex are not supported, so use indexOf and substring -void handleString(String incomingString) { +void handleString(String incomingString) +{ int i; - int arraySize = sizeof(measurements)/sizeof(measurements[0]); - - for (i = 0; i < arraySize; i++) { + int arraySize = sizeof(measurements) / sizeof(measurements[0]); + + for (i = 0; i < arraySize; i++) + { Measurement measurement = measurements[i]; String obisKey = measurement.key; - if(incomingString.indexOf(obisKey) > -1) { + if (incomingString.indexOf(obisKey) > -1) + { // found String value = incomingString.substring(measurement.start, measurement.end); logger.debug("DEBUG_1 " + obisKey + "=" + value); - - switch (measurement.valueType) { - case Measurement::FLOAT: - value = String(value.toFloat(), 3); - break; - case Measurement::INT: - value = String(value.toInt()); - break; - default: - break; + + switch (measurement.valueType) + { + case Measurement::FLOAT: + value = String(value.toFloat(), 3); + break; + case Measurement::INT: + value = String(value.toInt()); + break; + default: + break; } - + mqttPublisher.publishOnMQTT(measurement.name, value); //break; // incoming string has been handled. No need to continue. (for now) } From 4f337f776168ef5fc58aab4d41d34a53a286e685 Mon Sep 17 00:00:00 2001 From: Bram van Deventer Date: Mon, 26 Apr 2021 20:04:19 +0200 Subject: [PATCH 7/8] Fix logger level - Update settings - Add logger level enum - Change topic to prefix --- Logger.cpp | 16 +++++++++++++--- Logger.h | 14 +++++++------- MQTTPublisher.cpp | 15 +++++++++------ Settings.example.h | 15 ++++++--------- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/Logger.cpp b/Logger.cpp index c3a6250..af0f957 100644 --- a/Logger.cpp +++ b/Logger.cpp @@ -1,6 +1,13 @@ #include "Logger.h" #include "Settings.h" +enum LEVEL +{ + DEBUG = 1, + INFO = 2, + WARN = 3 +}; + // Create Wifi Connector Logger::Logger(String name) { @@ -9,21 +16,24 @@ Logger::Logger(String name) void Logger::debug(String msg) { - if (LOG_LEVEL <= DEBUG) { + if (LOG_LEVEL <= DEBUG) + { Serial.println("DEBUG - " + _name + ":" + msg); } } void Logger::info(String msg) { - if (LOG_LEVEL <= INFO) { + if (LOG_LEVEL <= INFO) + { Serial.println("INFO - " + _name + ":" + msg); } } void Logger::warn(String msg) { - if (LOG_LEVEL <= WARN) { + if (LOG_LEVEL <= WARN) + { Serial.println("WARN - " + _name + ":" + msg); } } diff --git a/Logger.h b/Logger.h index 1628704..3e368f1 100644 --- a/Logger.h +++ b/Logger.h @@ -3,12 +3,12 @@ class Logger { - private: - String _name; +private: + String _name; - public: - Logger(String name = "Logger"); - void info(String msg); - void debug(String msg); - void warn(String msg); +public: + Logger(String name = "Logger"); + void info(String msg); + void debug(String msg); + void warn(String msg); }; diff --git a/MQTTPublisher.cpp b/MQTTPublisher.cpp index c28b28c..7676de3 100644 --- a/MQTTPublisher.cpp +++ b/MQTTPublisher.cpp @@ -26,7 +26,7 @@ String MQTTPublisher::getTopic(String name) bool MQTTPublisher::reconnect() { lastConnectionAttempt = millis(); - + logger.debug("Attempt connection to server: " + String(MQTT_HOST_NAME)); // Attempt to connect @@ -52,14 +52,15 @@ bool MQTTPublisher::reconnect() client.publish(getTopic("status").c_str(), "online"); return true; - } else { + } + else + { logger.warn("failed, rc=" + client.state()); } return false; } - void MQTTPublisher::start() { if (String(MQTT_HOST_NAME).length() == 0 || MQTT_PORT == 0) @@ -85,9 +86,11 @@ void MQTTPublisher::handle() if (!isStarted) return; - if (!client.connected() && millis() - lastConnectionAttempt > RECONNECT_TIMEOUT) { + if (!client.connected() && millis() - lastConnectionAttempt > RECONNECT_TIMEOUT) + { hasMQTT = false; - if (!reconnect()) return; + if (!reconnect()) + return; } } @@ -95,7 +98,7 @@ bool MQTTPublisher::publishOnMQTT(String topicSuffix, String msg) { String topic = getTopic(topicSuffix); logger.debug("Publish to '" + topic + "':" + msg); - auto retVal = client.publish(topic.c_str(), msg.c_str()); + auto retVal = client.publish(topic.c_str(), msg.c_str()); yield(); return retVal; } diff --git a/Settings.example.h b/Settings.example.h index 7966a6d..dcf1c8a 100644 --- a/Settings.example.h +++ b/Settings.example.h @@ -8,25 +8,22 @@ #define WIFI_PASSWORD "" //set the mqqt host name or ip address to your mqqt host. Leave empty to disable mqtt. -#define MQTT_HOST_NAME "" +#define MQTT_HOST_NAME "" //mqtt port for the above host -#define MQTT_PORT 1883 +#define MQTT_PORT 1883 //if authentication is enabled for mqtt, set the username below. Leave empty to disable authentication -#define MQTT_USER_NAME "" +#define MQTT_USER_NAME "" //password for above user -#define MQTT_PASSWORD "" +#define MQTT_PASSWORD "" //publish online status name #define MQTT_HOSTNAME "ESP-DSMR" //default MQTT topic -#define MQTT_TOPIC "dsmr" +#define MQTT_PREFIX "dsmr" -//for debugging, print info on serial -#define DEBUG 1 -#define INFO 2 -#define WARN 3 +//for debugging, print info on serial (DEBUG, INFO, WARN) #define LOG_LEVEL DEBUG From 5c70635f5d3303a56e9225bd8328fe2b371589f0 Mon Sep 17 00:00:00 2001 From: Bram van Deventer Date: Wed, 28 Apr 2021 20:38:58 +0200 Subject: [PATCH 8/8] Add client id settings - Chose to use client id in mqtt prefix - Code styling - Update readme --- MQTTPublisher.cpp | 11 +++++++++-- README.md | 21 ++++++++++----------- Settings.example.h | 7 +++++-- WifiConnector.cpp | 28 +++++++++++++++------------- esp8266-dsmr.ino | 40 ---------------------------------------- 5 files changed, 39 insertions(+), 68 deletions(-) diff --git a/MQTTPublisher.cpp b/MQTTPublisher.cpp index 7676de3..fc7cd55 100644 --- a/MQTTPublisher.cpp +++ b/MQTTPublisher.cpp @@ -12,7 +12,7 @@ MQTTPublisher::MQTTPublisher(String clientId) logger.debug("ClientId:" + _clientId); } -MQTTPublisher::~MQTTPublisher() +MQTTPublisher::~MQTTPublisher() { client.publish(getTopic("status").c_str(), "offline"); client.disconnect(); @@ -20,7 +20,14 @@ MQTTPublisher::~MQTTPublisher() String MQTTPublisher::getTopic(String name) { - return String(MQTT_PREFIX) + '/' + _clientId + '/' + name; + if (USE_CLIENT_ID) + { + return String(MQTT_PREFIX) + '/' + _clientId + '/' + name; + } + else + { + return String(MQTT_PREFIX) + '/' + name; + } } bool MQTTPublisher::reconnect() diff --git a/README.md b/README.md index 76c8ac0..6ba8631 100644 --- a/README.md +++ b/README.md @@ -25,19 +25,18 @@ The code should work on DSRM v2.2 and higher, only tested on V4.2. | Name | unit | DSMR code | MQTT topic | |:---- |:-------|:------ |:------| | DSMR version | - | 1-3:0.2.8 | /version | +| Status | online, offline | - | /status | ### Power | Name | unit | DSMR code | MQTT topic | |:---- |:-------|:------ |:------| | current power consumption | kW | 1-0:1.7.0 | /power/consumption | -| current power production | kW | 1-0:2.7.0| /power/production | +| current power production | kW | 1-0:2.7.0 | /power/production | | total consumption low | kWh | 1-0:1.8.1 | /power/total_consumption_low | | total consumption high | kWh | 1-0:1.8.2 | /power/total_consumption_high | | total production low | kWh | 1-0:2.8.1 | /power/total_production_low | | total production high | kWh | 1-0:2.8.2 | /power/total_production_high | | power tariff | 1 = low, 2 = high | 0-0:96.14.0 | /power/power_tariff | -| timestamp| - | 0-0:1.0.0 | /power/timestamp | -| device id | - | 0-0:96.1.1 | /power/device | | short power outages | - | 0-0:96.7.21 |/power/short_power_outages | | long power outages | - | 0-0:96.7.9 |/power/long_power_outages | | instant current phase 1 | A | 1-0:31.7.0 |/power/phase_1/current | @@ -46,16 +45,17 @@ The code should work on DSRM v2.2 and higher, only tested on V4.2. | 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 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 | | 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 | | short peaks phase 1 | - | 1-0:32.36.0 | /power/phase_1/peaks | | short peaks phase 2 | - | 1-0:52.36.0 | /power/phase_2/peaks | | short peaks phase 3 | - | 1-0:72.36.0 | /power/phase_3/peaks | - +| timestamp| - | 0-0:1.0.0 | /power/timestamp | +| device id | - | 0-0:96.1.1 | /power/device | ### Gas | Name | unit | DSMR code | MQTT topic | @@ -65,8 +65,6 @@ The code should work on DSRM v2.2 and higher, only tested on V4.2. | device id | - | 0-1:96.1.0 | /gas/device | - - ## Settings Copy `Settings.example.h` to `Settings.h` and fill in the correct data. @@ -80,8 +78,9 @@ 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_TOPIC | dsmr | MQTT topic prefix | -| DEBUGE_MODE | true | debug mode | +| MQTT_PREFIX | dsmr | MQTT prefix | +| USE_CLIENT_ID | FALSE | Use clientId in prefix | +| LOG_LEVEL | INFO | ( DEBUG / INFO / WARN ) | ## Circuit diff --git a/Settings.example.h b/Settings.example.h index dcf1c8a..b62e9c8 100644 --- a/Settings.example.h +++ b/Settings.example.h @@ -22,8 +22,11 @@ //publish online status name #define MQTT_HOSTNAME "ESP-DSMR" -//default MQTT topic +//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 DEBUG +#define LOG_LEVEL INFO diff --git a/WifiConnector.cpp b/WifiConnector.cpp index 0f8e693..e787ce0 100644 --- a/WifiConnector.cpp +++ b/WifiConnector.cpp @@ -22,13 +22,14 @@ void WifiConnector::start() // Setup Wifi WiFi.mode(WIFI_STA); WiFi.hostname(WIFI_HOSTNAME); - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); // This funtion is called from main setup function, // Wait until unit has wifi before continuing - while (WiFi.status() != WL_CONNECTED) { - delay(500); - logger.debug("."); + while (WiFi.status() != WL_CONNECTED) + { + delay(500); + logger.debug("."); } // Set wifi bool @@ -43,30 +44,31 @@ void WifiConnector::reconnect() { logger.debug("Try to reconnect!"); - - // First hit, try to reconnect. - if(!tryingReconnect) + + // First hit, try to reconnect. + if (!tryingReconnect) { WiFi.reconnect(); tryingReconnect = true; } - } // handle function called from main loop void WifiConnector::handle() { - + // Check if WIfi is Connected - if(!WiFi.isConnected() && !tryingReconnect){ - + if (!WiFi.isConnected() && !tryingReconnect) + { + logger.info("Disconnected!"); // Set bool false and try to reconnect hasWIFI = false; reconnect(); - - }else if (WiFi.isConnected() && !hasWIFI){ // Wifi is Reconnected + } + else if (WiFi.isConnected() && !hasWIFI) + { // Wifi is Reconnected logger.info("Reconnected!"); diff --git a/esp8266-dsmr.ino b/esp8266-dsmr.ino index 52f1ecd..5cc2151 100644 --- a/esp8266-dsmr.ino +++ b/esp8266-dsmr.ino @@ -65,45 +65,6 @@ bool hasMQTT = false; bool hasWIFI = false; Logger logger = Logger("App"); -void test() -{ - handleString("/KFM5KAIFA-METER"); - handleString("1-3:0.2.8(42)"); - handleString("0-0:1.0.0(210413140243S)"); - handleString("0-0:96.1.1(4530303033303030303036343035333134)"); - handleString("1-0:1.8.1(019867.385*kWh)"); - handleString("1-0:1.8.2(010090.200*kWh)"); - handleString("1-0:2.8.1(003899.380*kWh)"); - handleString("1-0:2.8.2(009033.210*kWh)"); - handleString("0-0:96.14.0(0002)"); - handleString("1-0:1.7.0(00.708*kW)"); - handleString("1-0:2.7.0(00.001*kW)"); - handleString("0-0:96.7.21(00012)"); - handleString("0-0:96.7.9(00006)"); - handleString("1-0:99.97.0(5)(0-0:96.7.19)(181227144100W)(0000020430*s)(181219144343W)(0000021625*s)(161123070756W)(0000001349*s)(151126025422W)(0000004263*s)(000101000001W)(2147483647*s)"); - handleString("1-0:32.32.0(00001)"); - handleString("1-0:52.32.0(00002)"); - handleString("1-0:72.32.0(00003)"); - handleString("1-0:32.36.0(00004)"); - handleString("1-0:52.36.0(00005)"); - handleString("1-0:72.36.0(00006)"); - handleString("0-0:96.13.1()"); - handleString("0-0:96.13.0()"); - handleString("1-0:31.7.0(003*A)"); - handleString("1-0:51.7.0(006*A)"); - handleString("1-0:71.7.0(009*A)"); - handleString("1-0:21.7.0(00.596*kW)"); - handleString("1-0:22.7.0(00.091*kW)"); - handleString("1-0:41.7.0(00.112*kW)"); - handleString("1-0:42.7.0(00.092*kW)"); - handleString("1-0:61.7.0(00.002*kW)"); - handleString("1-0:62.7.0(00.093*kW)"); - handleString("0-1:24.1.0(003)"); - handleString("0-1:96.1.0(4730303233353631323233373631313134)"); - handleString("0-1:24.2.1(210413140000S)(04981.523*m3)"); - handleString("!ECD2"); -} - void setup() { @@ -169,7 +130,6 @@ void handleString(String incomingString) } mqttPublisher.publishOnMQTT(measurement.name, value); - //break; // incoming string has been handled. No need to continue. (for now) } } }