diff --git a/include/PowerMeterSml.h b/include/PowerMeterSml.h index 2e180c574..a0d614201 100644 --- a/include/PowerMeterSml.h +++ b/include/PowerMeterSml.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -25,38 +26,43 @@ class PowerMeterSml : public PowerMeterProvider { std::string _user; mutable std::mutex _mutex; - float _activePowerTotal = 0.0; - float _activePowerL1 = 0.0; - float _activePowerL2 = 0.0; - float _activePowerL3 = 0.0; - float _voltageL1 = 0.0; - float _voltageL2 = 0.0; - float _voltageL3 = 0.0; - float _currentL1 = 0.0; - float _currentL2 = 0.0; - float _currentL3 = 0.0; - float _energyImport = 0.0; - float _energyExport = 0.0; - - typedef struct { + using values_t = struct { + std::optional activePowerTotal = std::nullopt; + std::optional activePowerL1 = std::nullopt; + std::optional activePowerL2 = std::nullopt; + std::optional activePowerL3 = std::nullopt; + std::optional voltageL1 = std::nullopt; + std::optional voltageL2 = std::nullopt; + std::optional voltageL3 = std::nullopt; + std::optional currentL1 = std::nullopt; + std::optional currentL2 = std::nullopt; + std::optional currentL3 = std::nullopt; + std::optional energyImport = std::nullopt; + std::optional energyExport = std::nullopt; + }; + + values_t _values; + values_t _cache; + + using OBISHandler = struct { uint8_t const OBIS[6]; void (*decoder)(float&); - float* target; + std::optional* target; char const* name; - } OBISHandler; + }; const std::list smlHandlerList{ - {{0x01, 0x00, 0x10, 0x07, 0x00, 0xff}, &smlOBISW, &_activePowerTotal, "active power total"}, - {{0x01, 0x00, 0x24, 0x07, 0x00, 0xff}, &smlOBISW, &_activePowerL1, "active power L1"}, - {{0x01, 0x00, 0x38, 0x07, 0x00, 0xff}, &smlOBISW, &_activePowerL2, "active power L2"}, - {{0x01, 0x00, 0x4c, 0x07, 0x00, 0xff}, &smlOBISW, &_activePowerL3, "active power L3"}, - {{0x01, 0x00, 0x20, 0x07, 0x00, 0xff}, &smlOBISVolt, &_voltageL1, "voltage L1"}, - {{0x01, 0x00, 0x34, 0x07, 0x00, 0xff}, &smlOBISVolt, &_voltageL2, "voltage L2"}, - {{0x01, 0x00, 0x48, 0x07, 0x00, 0xff}, &smlOBISVolt, &_voltageL3, "voltage L3"}, - {{0x01, 0x00, 0x1f, 0x07, 0x00, 0xff}, &smlOBISAmpere, &_currentL1, "current L1"}, - {{0x01, 0x00, 0x33, 0x07, 0x00, 0xff}, &smlOBISAmpere, &_currentL2, "current L2"}, - {{0x01, 0x00, 0x47, 0x07, 0x00, 0xff}, &smlOBISAmpere, &_currentL3, "current L3"}, - {{0x01, 0x00, 0x01, 0x08, 0x00, 0xff}, &smlOBISWh, &_energyImport, "energy import"}, - {{0x01, 0x00, 0x02, 0x08, 0x00, 0xff}, &smlOBISWh, &_energyExport, "energy export"} + {{0x01, 0x00, 0x10, 0x07, 0x00, 0xff}, &smlOBISW, &_cache.activePowerTotal, "active power total"}, + {{0x01, 0x00, 0x24, 0x07, 0x00, 0xff}, &smlOBISW, &_cache.activePowerL1, "active power L1"}, + {{0x01, 0x00, 0x38, 0x07, 0x00, 0xff}, &smlOBISW, &_cache.activePowerL2, "active power L2"}, + {{0x01, 0x00, 0x4c, 0x07, 0x00, 0xff}, &smlOBISW, &_cache.activePowerL3, "active power L3"}, + {{0x01, 0x00, 0x20, 0x07, 0x00, 0xff}, &smlOBISVolt, &_cache.voltageL1, "voltage L1"}, + {{0x01, 0x00, 0x34, 0x07, 0x00, 0xff}, &smlOBISVolt, &_cache.voltageL2, "voltage L2"}, + {{0x01, 0x00, 0x48, 0x07, 0x00, 0xff}, &smlOBISVolt, &_cache.voltageL3, "voltage L3"}, + {{0x01, 0x00, 0x1f, 0x07, 0x00, 0xff}, &smlOBISAmpere, &_cache.currentL1, "current L1"}, + {{0x01, 0x00, 0x33, 0x07, 0x00, 0xff}, &smlOBISAmpere, &_cache.currentL2, "current L2"}, + {{0x01, 0x00, 0x47, 0x07, 0x00, 0xff}, &smlOBISAmpere, &_cache.currentL3, "current L3"}, + {{0x01, 0x00, 0x01, 0x08, 0x00, 0xff}, &smlOBISWh, &_cache.energyImport, "energy import"}, + {{0x01, 0x00, 0x02, 0x08, 0x00, 0xff}, &smlOBISWh, &_cache.energyExport, "energy export"} }; }; diff --git a/src/PowerMeterSml.cpp b/src/PowerMeterSml.cpp index 105d20f9d..021b48cd6 100644 --- a/src/PowerMeterSml.cpp +++ b/src/PowerMeterSml.cpp @@ -5,23 +5,29 @@ float PowerMeterSml::getPowerTotal() const { std::lock_guard l(_mutex); - return _activePowerTotal; + if (_values.activePowerTotal.has_value()) { return *_values.activePowerTotal; } + return 0; } void PowerMeterSml::doMqttPublish() const { +#define PUB(t, m) \ + if (_values.m.has_value()) { mqttPublish(t, *_values.m); } + std::lock_guard l(_mutex); - mqttPublish("power1", _activePowerL1); - mqttPublish("power2", _activePowerL2); - mqttPublish("power3", _activePowerL3); - mqttPublish("voltage1", _voltageL1); - mqttPublish("voltage2", _voltageL2); - mqttPublish("voltage3", _voltageL3); - mqttPublish("current1", _currentL1); - mqttPublish("current2", _currentL2); - mqttPublish("current3", _currentL3); - mqttPublish("import", _energyImport); - mqttPublish("export", _energyExport); + PUB("power1", activePowerL1); + PUB("power2", activePowerL2); + PUB("power3", activePowerL3); + PUB("voltage1", voltageL1); + PUB("voltage2", voltageL2); + PUB("voltage3", voltageL3); + PUB("current1", currentL1); + PUB("current2", currentL2); + PUB("current3", currentL3); + PUB("import", energyImport); + PUB("export", energyExport); + +#undef PUB } void PowerMeterSml::processSmlByte(uint8_t byte) @@ -31,22 +37,27 @@ void PowerMeterSml::processSmlByte(uint8_t byte) for (auto& handler: smlHandlerList) { if (!smlOBISCheck(handler.OBIS)) { continue; } - gotUpdate(); - - std::lock_guard l(_mutex); - handler.decoder(*handler.target); + float helper = 0.0; + handler.decoder(helper); if (_verboseLogging) { MessageOutput.printf("[%s] decoded %s to %.2f\r\n", - _user.c_str(), handler.name, *handler.target); + _user.c_str(), handler.name, helper); } + + std::lock_guard l(_mutex); + *handler.target = helper; } break; case SML_FINAL: + gotUpdate(); + _values = _cache; + _cache = { std::nullopt }; MessageOutput.printf("[%s] TotalPower: %5.2f\r\n", _user.c_str(), getPowerTotal()); break; case SML_CHECKSUM_ERROR: + _cache = { std::nullopt }; MessageOutput.printf("[%s] checksum verification failed\r\n", _user.c_str()); break;