diff --git a/include/PowerMeter.h b/include/PowerMeter.h index dde43c5e..fce5c832 100644 --- a/include/PowerMeter.h +++ b/include/PowerMeter.h @@ -4,8 +4,8 @@ #include "Configuration.h" #include #include -#include -#include +#include +#include #include "SDM.h" #include "sml.h" @@ -37,15 +37,17 @@ public: SOURCE_SML = 4 }; void init(); - void mqtt(); void loop(); - void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total); float getPowerTotal(bool forceUpdate = true); uint32_t getLastPowerMeterUpdate(); private: + void mqtt(); + + void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, + const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total); + bool _verboseLogging = true; - uint32_t _interval; uint32_t _lastPowerMeterCheck; // Used in Power limiter for safety check uint32_t _lastPowerMeterUpdate; @@ -59,7 +61,7 @@ private: float _powerMeterImport = 0.0; float _powerMeterExport = 0.0; - bool mqttInitDone = false; + std::map _mqttSubscriptions; void readPowerMeter(); diff --git a/src/PowerMeter.cpp b/src/PowerMeter.cpp index 613bb97b..4598c85a 100644 --- a/src/PowerMeter.cpp +++ b/src/PowerMeter.cpp @@ -20,80 +20,78 @@ SoftwareSerial inputSerial; void PowerMeterClass::init() { - using std::placeholders::_1; - using std::placeholders::_2; - using std::placeholders::_3; - using std::placeholders::_4; - using std::placeholders::_5; - using std::placeholders::_6; - _lastPowerMeterCheck = 0; _lastPowerMeterUpdate = 0; + for (auto const& s: _mqttSubscriptions) { MqttSettings.unsubscribe(s.first); } + _mqttSubscriptions.clear(); + CONFIG_T& config = Configuration.get(); - + if (!config.PowerMeter_Enabled) { return; } - if (config.PowerMeter_Source == SOURCE_MQTT) { - if (strlen(config.PowerMeter_MqttTopicPowerMeter1) > 0) { - MqttSettings.subscribe(config.PowerMeter_MqttTopicPowerMeter1, 0, std::bind(&PowerMeterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6)); - } + switch(config.PowerMeter_Source) { + case SOURCE_MQTT: { + auto subscribe = [this](char const* topic, float* target) { + if (strlen(topic) == 0) { return; } + MqttSettings.subscribe(topic, 0, + std::bind(&PowerMeterClass::onMqttMessage, + this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3, std::placeholders::_4, + std::placeholders::_5, std::placeholders::_6) + ); + _mqttSubscriptions.try_emplace(topic, target); + }; - if (strlen(config.PowerMeter_MqttTopicPowerMeter2) > 0) { - MqttSettings.subscribe(config.PowerMeter_MqttTopicPowerMeter2, 0, std::bind(&PowerMeterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6)); - } - - if (strlen(config.PowerMeter_MqttTopicPowerMeter3) > 0) { - MqttSettings.subscribe(config.PowerMeter_MqttTopicPowerMeter3, 0, std::bind(&PowerMeterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6)); - } + subscribe(config.PowerMeter_MqttTopicPowerMeter1, &_powerMeter1Power); + subscribe(config.PowerMeter_MqttTopicPowerMeter2, &_powerMeter2Power); + subscribe(config.PowerMeter_MqttTopicPowerMeter3, &_powerMeter3Power); + break; } - if(config.PowerMeter_Source == SOURCE_SDM1PH || config.PowerMeter_Source == SOURCE_SDM3PH) { + case SOURCE_SDM1PH: + case SOURCE_SDM3PH: sdm.begin(); - } + break; - if (config.PowerMeter_Source == SOURCE_HTTP) { + case SOURCE_HTTP: HttpPowerMeter.init(); - } + break; - if (config.PowerMeter_Source == SOURCE_SML) { + case SOURCE_SML: pinMode(SML_RX_PIN, INPUT); inputSerial.begin(9600, SWSERIAL_8N1, SML_RX_PIN, -1, false, 128, 95); inputSerial.enableRx(true); inputSerial.enableTx(false); inputSerial.flush(); + break; } - - mqttInitDone = true; } void PowerMeterClass::onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total) { - CONFIG_T& config = Configuration.get(); + for (auto const& subscription: _mqttSubscriptions) { + if (subscription.first != topic) { continue; } - if (!config.PowerMeter_Enabled || config.PowerMeter_Source != SOURCE_MQTT) { - return; + std::string value(reinterpret_cast(payload), len); + try { + *subscription.second = std::stof(value); + } + catch(std::invalid_argument const& e) { + MessageOutput.printf("PowerMeterClass: cannot parse payload of topic '%s' as float: %s\r\n", + topic, value.c_str()); + return; + } + + if (_verboseLogging) { + MessageOutput.printf("PowerMeterClass: Updated from '%s', TotalPower: %5.2f\r\n", + topic, getPowerTotal()); + } + + _lastPowerMeterUpdate = millis(); } - - if (strcmp(topic, config.PowerMeter_MqttTopicPowerMeter1) == 0) { - _powerMeter1Power = std::stof(std::string(reinterpret_cast(payload), (unsigned int)len)); - } - - if (strcmp(topic, config.PowerMeter_MqttTopicPowerMeter2) == 0) { - _powerMeter2Power = std::stof(std::string(reinterpret_cast(payload), (unsigned int)len)); - } - - if (strcmp(topic, config.PowerMeter_MqttTopicPowerMeter3) == 0) { - _powerMeter3Power = std::stof(std::string(reinterpret_cast(payload), (unsigned int)len)); - } - - if (_verboseLogging) { - MessageOutput.printf("PowerMeterClass: TotalPower: %5.2f\r\n", getPowerTotal()); - } - - _lastPowerMeterUpdate = millis(); } float PowerMeterClass::getPowerTotal(bool forceUpdate)