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 {
public:
explicit PowerMeterHttpJson(PowerMeterHttpJsonConfig const& cfg)
: _cfg(cfg) { }
bool init() final;
void loop() final;
float getPowerTotal() const final;
@ -24,6 +27,8 @@ public:
poll_result_t poll();
private:
PowerMeterHttpJsonConfig const _cfg;
uint32_t _lastPoll;
power_values_t _powerValues;

View File

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

View File

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

View File

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

View File

@ -26,20 +26,24 @@ void PowerMeterClass::updateSettings()
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:
_upProvider = std::make_unique<PowerMeterMqtt>();
_upProvider = std::make_unique<PowerMeterMqtt>(pmcfg.Mqtt);
break;
case PowerMeterProvider::Type::SDM1PH:
_upProvider = std::make_unique<PowerMeterSerialSdm>(
PowerMeterSerialSdm::Phases::One, pmcfg.SerialSdm);
break;
case PowerMeterProvider::Type::SDM3PH:
_upProvider = std::make_unique<PowerMeterSerialSdm>();
_upProvider = std::make_unique<PowerMeterSerialSdm>(
PowerMeterSerialSdm::Phases::Three, pmcfg.SerialSdm);
break;
case PowerMeterProvider::Type::HTTP_JSON:
_upProvider = std::make_unique<PowerMeterHttpJson>();
_upProvider = std::make_unique<PowerMeterHttpJson>(pmcfg.HttpJson);
break;
case PowerMeterProvider::Type::SERIAL_SML:
_upProvider = std::make_unique<PowerMeterSerialSml>();
@ -48,7 +52,7 @@ void PowerMeterClass::updateSettings()
_upProvider = std::make_unique<PowerMeterUdpSmaHomeManager>();
break;
case PowerMeterProvider::Type::HTTP_SML:
_upProvider = std::make_unique<PowerMeterHttpSml>();
_upProvider = std::make_unique<PowerMeterHttpSml>(pmcfg.HttpSml);
break;
}

View File

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

View File

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

View File

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

View File

@ -1,6 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "PowerMeterSerialSdm.h"
#include "Configuration.h"
#include "PinMapping.h"
#include "MessageOutput.h"
#include "SerialPortManager.h"
@ -61,13 +60,11 @@ void PowerMeterSerialSdm::loop()
{
if (!_upSdm) { return; }
auto const& config = Configuration.get();
if ((millis() - _lastPoll) < (config.PowerMeter.SerialSdm.PollingInterval * 1000)) {
if ((millis() - _lastPoll) < (_cfg.PollingInterval * 1000)) {
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
// 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 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);
phase3Power = _upSdm->readVal(SDM_PHASE_3_POWER, addr);
phase2Voltage = _upSdm->readVal(SDM_PHASE_2_VOLTAGE, addr);

View File

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