powermeter refactor: instanciate power meters with config

instead of reading the main config's powermeter struct(s), the
individual power meters now are instanciated using a copy of their
respective config. this allows to instanciate different power meters
with different configs. as a first step, this simplifies instanciating
power meters for test purposes.
This commit is contained in:
Bernhard Kirchen 2024-05-23 20:08:16 +02:00
parent 3f2d9d38fa
commit b891a4c1a3
10 changed files with 62 additions and 51 deletions

View File

@ -14,6 +14,9 @@ using Unit_t = PowerMeterHttpJsonValue::Unit;
class PowerMeterHttpJson : public PowerMeterProvider { class PowerMeterHttpJson : public PowerMeterProvider {
public: public:
explicit PowerMeterHttpJson(PowerMeterHttpJsonConfig const& cfg)
: _cfg(cfg) { }
bool init() final; bool init() final;
void loop() final; void loop() final;
float getPowerTotal() const final; float getPowerTotal() const final;
@ -24,6 +27,8 @@ public:
poll_result_t poll(); poll_result_t poll();
private: private:
PowerMeterHttpJsonConfig const _cfg;
uint32_t _lastPoll; uint32_t _lastPoll;
power_values_t _powerValues; power_values_t _powerValues;

View File

@ -5,10 +5,14 @@
#include <stdint.h> #include <stdint.h>
#include <Arduino.h> #include <Arduino.h>
#include "HttpGetter.h" #include "HttpGetter.h"
#include "Configuration.h"
#include "PowerMeterSml.h" #include "PowerMeterSml.h"
class PowerMeterHttpSml : public PowerMeterSml { class PowerMeterHttpSml : public PowerMeterSml {
public: public:
explicit PowerMeterHttpSml(PowerMeterHttpSmlConfig const& cfg)
: _cfg(cfg) { }
bool init() final; bool init() final;
void loop() final; void loop() final;
@ -17,6 +21,8 @@ public:
String poll(); String poll();
private: private:
PowerMeterHttpSmlConfig const _cfg;
uint32_t _lastPoll = 0; uint32_t _lastPoll = 0;
std::unique_ptr<HttpGetter> _upHttpGetter; std::unique_ptr<HttpGetter> _upHttpGetter;

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include "Configuration.h"
#include "PowerMeterProvider.h" #include "PowerMeterProvider.h"
#include <espMqttClient.h> #include <espMqttClient.h>
#include <vector> #include <vector>
@ -8,6 +9,9 @@
class PowerMeterMqtt : public PowerMeterProvider { class PowerMeterMqtt : public PowerMeterProvider {
public: public:
explicit PowerMeterMqtt(PowerMeterMqttConfig const& cfg)
: _cfg(cfg) { }
~PowerMeterMqtt(); ~PowerMeterMqtt();
bool init() final; bool init() final;
@ -21,6 +25,8 @@ private:
uint8_t const* payload, size_t len, size_t index, uint8_t const* payload, size_t len, size_t index,
size_t total, float* targetVariable); size_t total, float* targetVariable);
PowerMeterMqttConfig const _cfg;
float _powerValueOne = 0; float _powerValueOne = 0;
float _powerValueTwo = 0; float _powerValueTwo = 0;
float _powerValueThree = 0; float _powerValueThree = 0;

View File

@ -2,11 +2,21 @@
#pragma once #pragma once
#include <mutex> #include <mutex>
#include "Configuration.h"
#include "PowerMeterProvider.h" #include "PowerMeterProvider.h"
#include "SDM.h" #include "SDM.h"
class PowerMeterSerialSdm : public PowerMeterProvider { class PowerMeterSerialSdm : public PowerMeterProvider {
public: public:
enum class Phases {
One,
Three
};
PowerMeterSerialSdm(Phases phases, PowerMeterSerialSdmConfig const& cfg)
: _phases(phases)
, _cfg(cfg) { }
~PowerMeterSerialSdm(); ~PowerMeterSerialSdm();
bool init() final; bool init() final;
@ -15,6 +25,9 @@ public:
void doMqttPublish() const final; void doMqttPublish() const final;
private: private:
Phases _phases;
PowerMeterSerialSdmConfig const _cfg;
uint32_t _lastPoll; uint32_t _lastPoll;
float _phase1Power = 0.0; float _phase1Power = 0.0;

View File

@ -26,20 +26,24 @@ void PowerMeterClass::updateSettings()
if (_upProvider) { _upProvider.reset(); } if (_upProvider) { _upProvider.reset(); }
auto const& config = Configuration.get(); auto const& pmcfg = Configuration.get().PowerMeter;
if (!config.PowerMeter.Enabled) { return; } if (!pmcfg.Enabled) { return; }
switch(static_cast<PowerMeterProvider::Type>(config.PowerMeter.Source)) { switch(static_cast<PowerMeterProvider::Type>(pmcfg.Source)) {
case PowerMeterProvider::Type::MQTT: case PowerMeterProvider::Type::MQTT:
_upProvider = std::make_unique<PowerMeterMqtt>(); _upProvider = std::make_unique<PowerMeterMqtt>(pmcfg.Mqtt);
break; break;
case PowerMeterProvider::Type::SDM1PH: case PowerMeterProvider::Type::SDM1PH:
_upProvider = std::make_unique<PowerMeterSerialSdm>(
PowerMeterSerialSdm::Phases::One, pmcfg.SerialSdm);
break;
case PowerMeterProvider::Type::SDM3PH: case PowerMeterProvider::Type::SDM3PH:
_upProvider = std::make_unique<PowerMeterSerialSdm>(); _upProvider = std::make_unique<PowerMeterSerialSdm>(
PowerMeterSerialSdm::Phases::Three, pmcfg.SerialSdm);
break; break;
case PowerMeterProvider::Type::HTTP_JSON: case PowerMeterProvider::Type::HTTP_JSON:
_upProvider = std::make_unique<PowerMeterHttpJson>(); _upProvider = std::make_unique<PowerMeterHttpJson>(pmcfg.HttpJson);
break; break;
case PowerMeterProvider::Type::SERIAL_SML: case PowerMeterProvider::Type::SERIAL_SML:
_upProvider = std::make_unique<PowerMeterSerialSml>(); _upProvider = std::make_unique<PowerMeterSerialSml>();
@ -48,7 +52,7 @@ void PowerMeterClass::updateSettings()
_upProvider = std::make_unique<PowerMeterUdpSmaHomeManager>(); _upProvider = std::make_unique<PowerMeterUdpSmaHomeManager>();
break; break;
case PowerMeterProvider::Type::HTTP_SML: case PowerMeterProvider::Type::HTTP_SML:
_upProvider = std::make_unique<PowerMeterHttpSml>(); _upProvider = std::make_unique<PowerMeterHttpSml>(pmcfg.HttpSml);
break; break;
} }

View File

@ -1,6 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "Utils.h" #include "Utils.h"
#include "Configuration.h"
#include "PowerMeterHttpJson.h" #include "PowerMeterHttpJson.h"
#include "MessageOutput.h" #include "MessageOutput.h"
#include <WiFiClientSecure.h> #include <WiFiClientSecure.h>
@ -11,14 +10,12 @@
bool PowerMeterHttpJson::init() bool PowerMeterHttpJson::init()
{ {
auto const& config = Configuration.get();
for (uint8_t i = 0; i < POWERMETER_HTTP_JSON_MAX_VALUES; i++) { for (uint8_t i = 0; i < POWERMETER_HTTP_JSON_MAX_VALUES; i++) {
auto const& valueConfig = config.PowerMeter.HttpJson.Values[i]; auto const& valueConfig = _cfg.Values[i];
_httpGetters[i] = nullptr; _httpGetters[i] = nullptr;
if (i == 0 || (config.PowerMeter.HttpJson.IndividualRequests && valueConfig.Enabled)) { if (i == 0 || (_cfg.IndividualRequests && valueConfig.Enabled)) {
_httpGetters[i] = std::make_unique<HttpGetter>(valueConfig.HttpRequest); _httpGetters[i] = std::make_unique<HttpGetter>(valueConfig.HttpRequest);
} }
@ -40,8 +37,7 @@ bool PowerMeterHttpJson::init()
void PowerMeterHttpJson::loop() void PowerMeterHttpJson::loop()
{ {
auto const& config = Configuration.get(); if ((millis() - _lastPoll) < (_cfg.PollingInterval * 1000)) {
if ((millis() - _lastPoll) < (config.PowerMeter.HttpJson.PollingInterval * 1000)) {
return; return;
} }
@ -68,7 +64,7 @@ PowerMeterHttpJson::poll_result_t PowerMeterHttpJson::poll()
}; };
for (uint8_t i = 0; i < POWERMETER_HTTP_JSON_MAX_VALUES; i++) { for (uint8_t i = 0; i < POWERMETER_HTTP_JSON_MAX_VALUES; i++) {
auto const& cfg = Configuration.get().PowerMeter.HttpJson.Values[i]; auto const& cfg = _cfg.Values[i];
if (!cfg.Enabled) { if (!cfg.Enabled) {
cache[i] = 0.0; cache[i] = 0.0;

View File

@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "Configuration.h"
#include "PowerMeterHttpSml.h" #include "PowerMeterHttpSml.h"
#include "MessageOutput.h" #include "MessageOutput.h"
#include <WiFiClientSecure.h> #include <WiFiClientSecure.h>
@ -8,9 +7,7 @@
bool PowerMeterHttpSml::init() bool PowerMeterHttpSml::init()
{ {
auto const& config = Configuration.get(); _upHttpGetter = std::make_unique<HttpGetter>(_cfg.HttpRequest);
_upHttpGetter = std::make_unique<HttpGetter>(config.PowerMeter.HttpSml.HttpRequest);
if (_upHttpGetter->init()) { return true; } if (_upHttpGetter->init()) { return true; }
@ -24,8 +21,7 @@ bool PowerMeterHttpSml::init()
void PowerMeterHttpSml::loop() void PowerMeterHttpSml::loop()
{ {
auto const& config = Configuration.get(); if ((millis() - _lastPoll) < (_cfg.PollingInterval * 1000)) {
if ((millis() - _lastPoll) < (config.PowerMeter.HttpSml.PollingInterval * 1000)) {
return; return;
} }

View File

@ -1,6 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "PowerMeterMqtt.h" #include "PowerMeterMqtt.h"
#include "Configuration.h"
#include "MqttSettings.h" #include "MqttSettings.h"
#include "MessageOutput.h" #include "MessageOutput.h"
@ -18,10 +17,9 @@ bool PowerMeterMqtt::init()
_mqttSubscriptions.push_back(topic); _mqttSubscriptions.push_back(topic);
}; };
auto const& config = Configuration.get(); subscribe(_cfg.Values[0].Topic, &_powerValueOne);
subscribe(config.PowerMeter.Mqtt.Values[0].Topic, &_powerValueOne); subscribe(_cfg.Values[1].Topic, &_powerValueTwo);
subscribe(config.PowerMeter.Mqtt.Values[1].Topic, &_powerValueTwo); subscribe(_cfg.Values[2].Topic, &_powerValueThree);
subscribe(config.PowerMeter.Mqtt.Values[2].Topic, &_powerValueThree);
return _mqttSubscriptions.size() > 0; return _mqttSubscriptions.size() > 0;
} }

View File

@ -1,6 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "PowerMeterSerialSdm.h" #include "PowerMeterSerialSdm.h"
#include "Configuration.h"
#include "PinMapping.h" #include "PinMapping.h"
#include "MessageOutput.h" #include "MessageOutput.h"
#include "SerialPortManager.h" #include "SerialPortManager.h"
@ -61,13 +60,11 @@ void PowerMeterSerialSdm::loop()
{ {
if (!_upSdm) { return; } if (!_upSdm) { return; }
auto const& config = Configuration.get(); if ((millis() - _lastPoll) < (_cfg.PollingInterval * 1000)) {
if ((millis() - _lastPoll) < (config.PowerMeter.SerialSdm.PollingInterval * 1000)) {
return; return;
} }
uint8_t addr = config.PowerMeter.SerialSdm.Address; uint8_t addr = _cfg.Address;
// reading takes a "very long" time as each readVal() is a synchronous // reading takes a "very long" time as each readVal() is a synchronous
// exchange of serial messages. cache the values and write later to // exchange of serial messages. cache the values and write later to
@ -81,7 +78,7 @@ void PowerMeterSerialSdm::loop()
float energyImport = _upSdm->readVal(SDM_IMPORT_ACTIVE_ENERGY, addr); float energyImport = _upSdm->readVal(SDM_IMPORT_ACTIVE_ENERGY, addr);
float energyExport = _upSdm->readVal(SDM_EXPORT_ACTIVE_ENERGY, addr); float energyExport = _upSdm->readVal(SDM_EXPORT_ACTIVE_ENERGY, addr);
if (static_cast<PowerMeterProvider::Type>(config.PowerMeter.Source) == PowerMeterProvider::Type::SDM3PH) { if (_phases == Phases::Three) {
phase2Power = _upSdm->readVal(SDM_PHASE_2_POWER, addr); phase2Power = _upSdm->readVal(SDM_PHASE_2_POWER, addr);
phase3Power = _upSdm->readVal(SDM_PHASE_3_POWER, addr); phase3Power = _upSdm->readVal(SDM_PHASE_3_POWER, addr);
phase2Voltage = _upSdm->readVal(SDM_PHASE_2_VOLTAGE, addr); phase2Voltage = _upSdm->readVal(SDM_PHASE_2_VOLTAGE, addr);

View File

@ -188,25 +188,19 @@ void WebApiPowerMeterClass::onTestHttpJsonRequest(AsyncWebServerRequest* request
char response[256]; char response[256];
auto powerMeterConfig = std::make_unique<CONFIG_T::PowerMeterConfig>(); auto powerMeterConfig = std::make_unique<PowerMeterHttpJsonConfig>();
JsonObject httpJson = root["http_json"]; Configuration.deserializePowerMeterHttpJsonConfig(root["http_json"].as<JsonObject>(),
powerMeterConfig->HttpJson.IndividualRequests = httpJson["individual_requests"].as<bool>(); *powerMeterConfig);
powerMeterConfig->VerboseLogging = true; auto upMeter = std::make_unique<PowerMeterHttpJson>(*powerMeterConfig);
Configuration.deserializePowerMeterHttpJsonConfig(httpJson,
powerMeterConfig->HttpJson);
auto backup = std::make_unique<CONFIG_T::PowerMeterConfig>(Configuration.get().PowerMeter);
Configuration.get().PowerMeter = *powerMeterConfig;
auto upMeter = std::make_unique<PowerMeterHttpJson>();
upMeter->init(); upMeter->init();
auto res = upMeter->poll(); auto res = upMeter->poll();
Configuration.get().PowerMeter = *backup;
using values_t = PowerMeterHttpJson::power_values_t; using values_t = PowerMeterHttpJson::power_values_t;
if (std::holds_alternative<values_t>(res)) { if (std::holds_alternative<values_t>(res)) {
retMsg["type"] = "success"; retMsg["type"] = "success";
auto vals = std::get<values_t>(res); auto vals = std::get<values_t>(res);
auto pos = snprintf(response, sizeof(response), "Result: %5.2fW", vals[0]); auto pos = snprintf(response, sizeof(response), "Result: %5.2fW", vals[0]);
for (size_t i = 1; i < POWERMETER_HTTP_JSON_MAX_VALUES; ++i) { for (size_t i = 1; i < vals.size(); ++i) {
if (!powerMeterConfig->HttpJson.Values[i].Enabled) { continue; } if (!powerMeterConfig->Values[i].Enabled) { continue; }
pos += snprintf(response + pos, sizeof(response) - pos, ", %5.2fW", vals[i]); pos += snprintf(response + pos, sizeof(response) - pos, ", %5.2fW", vals[i]);
} }
snprintf(response + pos, sizeof(response) - pos, ", Total: %5.2f", upMeter->getPowerTotal()); snprintf(response + pos, sizeof(response) - pos, ", Total: %5.2f", upMeter->getPowerTotal());
@ -235,16 +229,12 @@ void WebApiPowerMeterClass::onTestHttpSmlRequest(AsyncWebServerRequest* request)
char response[256]; char response[256];
auto powerMeterConfig = std::make_unique<CONFIG_T::PowerMeterConfig>(); auto powerMeterConfig = std::make_unique<PowerMeterHttpSmlConfig>();
Configuration.deserializePowerMeterHttpSmlConfig(root["http_sml"].as<JsonObject>(), Configuration.deserializePowerMeterHttpSmlConfig(root["http_sml"].as<JsonObject>(),
powerMeterConfig->HttpSml); *powerMeterConfig);
powerMeterConfig->VerboseLogging = true; auto upMeter = std::make_unique<PowerMeterHttpSml>(*powerMeterConfig);
auto backup = std::make_unique<CONFIG_T::PowerMeterConfig>(Configuration.get().PowerMeter);
Configuration.get().PowerMeter = *powerMeterConfig;
auto upMeter = std::make_unique<PowerMeterHttpSml>();
upMeter->init(); upMeter->init();
auto res = upMeter->poll(); auto res = upMeter->poll();
Configuration.get().PowerMeter = *backup;
if (res.isEmpty()) { if (res.isEmpty()) {
retMsg["type"] = "success"; retMsg["type"] = "success";
snprintf(response, sizeof(response), "Result: %5.2fW", upMeter->getPowerTotal()); snprintf(response, sizeof(response), "Result: %5.2fW", upMeter->getPowerTotal());