PowerMeter fixes (#342)
* PowerMeter: gracefully handle non-float MQTT values * PowerMeter: update _lastPowerMeterUpdate conservatively update the timestampt only if the topic actually matched any subscription and if the value could be parsed as a float. * PowerMeter: unsubscribe before subscribing * PowerMeter: organize subscriptions in a map this allows for a slightly more elegant code and reduced amount of code overall. * PowerMeter: clean up header * move private methods to private section of class declaration. * remove unused member variable.
This commit is contained in:
parent
9bc334e368
commit
6b425d96b0
@ -4,8 +4,8 @@
|
|||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include <espMqttClient.h>
|
#include <espMqttClient.h>
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Hoymiles.h>
|
#include <map>
|
||||||
#include <memory>
|
#include <list>
|
||||||
#include "SDM.h"
|
#include "SDM.h"
|
||||||
#include "sml.h"
|
#include "sml.h"
|
||||||
|
|
||||||
@ -37,15 +37,17 @@ public:
|
|||||||
SOURCE_SML = 4
|
SOURCE_SML = 4
|
||||||
};
|
};
|
||||||
void init();
|
void init();
|
||||||
void mqtt();
|
|
||||||
void loop();
|
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);
|
float getPowerTotal(bool forceUpdate = true);
|
||||||
uint32_t getLastPowerMeterUpdate();
|
uint32_t getLastPowerMeterUpdate();
|
||||||
|
|
||||||
private:
|
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;
|
bool _verboseLogging = true;
|
||||||
uint32_t _interval;
|
|
||||||
uint32_t _lastPowerMeterCheck;
|
uint32_t _lastPowerMeterCheck;
|
||||||
// Used in Power limiter for safety check
|
// Used in Power limiter for safety check
|
||||||
uint32_t _lastPowerMeterUpdate;
|
uint32_t _lastPowerMeterUpdate;
|
||||||
@ -59,7 +61,7 @@ private:
|
|||||||
float _powerMeterImport = 0.0;
|
float _powerMeterImport = 0.0;
|
||||||
float _powerMeterExport = 0.0;
|
float _powerMeterExport = 0.0;
|
||||||
|
|
||||||
bool mqttInitDone = false;
|
std::map<String, float*> _mqttSubscriptions;
|
||||||
|
|
||||||
void readPowerMeter();
|
void readPowerMeter();
|
||||||
|
|
||||||
|
|||||||
@ -20,80 +20,78 @@ SoftwareSerial inputSerial;
|
|||||||
|
|
||||||
void PowerMeterClass::init()
|
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;
|
_lastPowerMeterCheck = 0;
|
||||||
_lastPowerMeterUpdate = 0;
|
_lastPowerMeterUpdate = 0;
|
||||||
|
|
||||||
|
for (auto const& s: _mqttSubscriptions) { MqttSettings.unsubscribe(s.first); }
|
||||||
|
_mqttSubscriptions.clear();
|
||||||
|
|
||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
if (!config.PowerMeter_Enabled) {
|
if (!config.PowerMeter_Enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.PowerMeter_Source == SOURCE_MQTT) {
|
switch(config.PowerMeter_Source) {
|
||||||
if (strlen(config.PowerMeter_MqttTopicPowerMeter1) > 0) {
|
case SOURCE_MQTT: {
|
||||||
MqttSettings.subscribe(config.PowerMeter_MqttTopicPowerMeter1, 0, std::bind(&PowerMeterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
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) {
|
subscribe(config.PowerMeter_MqttTopicPowerMeter1, &_powerMeter1Power);
|
||||||
MqttSettings.subscribe(config.PowerMeter_MqttTopicPowerMeter2, 0, std::bind(&PowerMeterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
subscribe(config.PowerMeter_MqttTopicPowerMeter2, &_powerMeter2Power);
|
||||||
}
|
subscribe(config.PowerMeter_MqttTopicPowerMeter3, &_powerMeter3Power);
|
||||||
|
break;
|
||||||
if (strlen(config.PowerMeter_MqttTopicPowerMeter3) > 0) {
|
|
||||||
MqttSettings.subscribe(config.PowerMeter_MqttTopicPowerMeter3, 0, std::bind(&PowerMeterClass::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(config.PowerMeter_Source == SOURCE_SDM1PH || config.PowerMeter_Source == SOURCE_SDM3PH) {
|
case SOURCE_SDM1PH:
|
||||||
|
case SOURCE_SDM3PH:
|
||||||
sdm.begin();
|
sdm.begin();
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (config.PowerMeter_Source == SOURCE_HTTP) {
|
case SOURCE_HTTP:
|
||||||
HttpPowerMeter.init();
|
HttpPowerMeter.init();
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (config.PowerMeter_Source == SOURCE_SML) {
|
case SOURCE_SML:
|
||||||
pinMode(SML_RX_PIN, INPUT);
|
pinMode(SML_RX_PIN, INPUT);
|
||||||
inputSerial.begin(9600, SWSERIAL_8N1, SML_RX_PIN, -1, false, 128, 95);
|
inputSerial.begin(9600, SWSERIAL_8N1, SML_RX_PIN, -1, false, 128, 95);
|
||||||
inputSerial.enableRx(true);
|
inputSerial.enableRx(true);
|
||||||
inputSerial.enableTx(false);
|
inputSerial.enableTx(false);
|
||||||
inputSerial.flush();
|
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)
|
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) {
|
std::string value(reinterpret_cast<const char*>(payload), len);
|
||||||
return;
|
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<const char*>(payload), (unsigned int)len));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(topic, config.PowerMeter_MqttTopicPowerMeter2) == 0) {
|
|
||||||
_powerMeter2Power = std::stof(std::string(reinterpret_cast<const char*>(payload), (unsigned int)len));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(topic, config.PowerMeter_MqttTopicPowerMeter3) == 0) {
|
|
||||||
_powerMeter3Power = std::stof(std::string(reinterpret_cast<const char*>(payload), (unsigned int)len));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_verboseLogging) {
|
|
||||||
MessageOutput.printf("PowerMeterClass: TotalPower: %5.2f\r\n", getPowerTotal());
|
|
||||||
}
|
|
||||||
|
|
||||||
_lastPowerMeterUpdate = millis();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float PowerMeterClass::getPowerTotal(bool forceUpdate)
|
float PowerMeterClass::getPowerTotal(bool forceUpdate)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user