diff --git a/include/MqttHandleVedirect.h b/include/MqttHandleVedirect.h deleted file mode 100644 index 7e00df2cb..000000000 --- a/include/MqttHandleVedirect.h +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -#pragma once - -#include "VeDirectMpptController.h" -#include "Configuration.h" -#include -#include -#include - -class MqttHandleVedirectClass { -public: - void init(Scheduler& scheduler); - void forceUpdate(); -private: - void loop(); - std::map _kvFrames; - - Task _loopTask; - - // point of time in millis() when updated values will be published - uint32_t _nextPublishUpdatesOnly = 0; - - // point of time in millis() when all values will be published - uint32_t _nextPublishFull = 1; - - bool _PublishFull; - - void publish_mppt_data(const VeDirectMpptController::data_t &mpptData, - const VeDirectMpptController::data_t &frame) const; -}; - -extern MqttHandleVedirectClass MqttHandleVedirect; diff --git a/include/solarcharger/Provider.h b/include/solarcharger/Provider.h index 3bbbf25a1..9143bb6c4 100644 --- a/include/solarcharger/Provider.h +++ b/include/solarcharger/Provider.h @@ -5,6 +5,7 @@ namespace SolarChargers { +class Stats; class HassIntegration; class Provider { @@ -13,6 +14,7 @@ class Provider { virtual bool init(bool verboseLogging) = 0; virtual void deinit() = 0; virtual void loop() = 0; + virtual std::shared_ptr getStats() const = 0; virtual HassIntegration const& getHassIntegration() const = 0; // TODO(andreasboehm): below methods are taken from VictronMppt to start abstracting diff --git a/include/solarcharger/Stats.h b/include/solarcharger/Stats.h new file mode 100644 index 000000000..124af3bc8 --- /dev/null +++ b/include/solarcharger/Stats.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#include + +namespace SolarChargers { + +class Stats { +public: + void mqttLoop(); + + // the interval at which all data will be re-published, even + // if they did not change. used to calculate Home Assistent expiration. + virtual uint32_t getMqttFullPublishIntervalMs() const; + +protected: + virtual void mqttPublish() const; + +private: + uint32_t _lastMqttPublish = 0; +}; + +} // namespace SolarChargers diff --git a/include/solarcharger/victron/Provider.h b/include/solarcharger/victron/Provider.h index 72e6756ff..b7ea3774f 100644 --- a/include/solarcharger/victron/Provider.h +++ b/include/solarcharger/victron/Provider.h @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace SolarChargers::Victron { @@ -20,6 +21,7 @@ class Provider : public ::SolarChargers::Provider { bool init(bool verboseLogging) final; void deinit() final; void loop() final; + std::shared_ptr<::SolarChargers::Stats> getStats() const final { return _stats; } ::SolarChargers::HassIntegration const& getHassIntegration() const final { return _hassIntegration; } bool isDataValid() const final; @@ -68,6 +70,7 @@ class Provider : public ::SolarChargers::Provider { using controller_t = std::unique_ptr; std::vector _controllers; std::vector _serialPortOwners; + std::shared_ptr _stats = std::make_shared(); HassIntegration _hassIntegration; bool initController(int8_t rx, int8_t tx, bool logging, diff --git a/include/solarcharger/victron/Stats.h b/include/solarcharger/victron/Stats.h new file mode 100644 index 000000000..8ef6b1e07 --- /dev/null +++ b/include/solarcharger/victron/Stats.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#include +#include +#include + +namespace SolarChargers::Victron { + +class Stats : public ::SolarChargers::Stats { +public: + void mqttPublish() const final; + +private: + mutable std::map _kvFrames; + + // point of time in millis() when updated values will be published + mutable uint32_t _nextPublishUpdatesOnly = 0; + + // point of time in millis() when all values will be published + mutable uint32_t _nextPublishFull = 1; + + mutable bool _PublishFull; + + void publish_mppt_data(const VeDirectMpptController::data_t &mpptData, + const VeDirectMpptController::data_t &frame) const; +}; + +} // namespace SolarChargers::Victron diff --git a/src/WebApi_mqtt.cpp b/src/WebApi_mqtt.cpp index 658f4e821..79008fc54 100644 --- a/src/WebApi_mqtt.cpp +++ b/src/WebApi_mqtt.cpp @@ -10,7 +10,6 @@ #include "MqttHandleInverter.h" #include "MqttHandleHuawei.h" #include "MqttHandlePowerLimiter.h" -#include "MqttHandleVedirect.h" #include "MqttSettings.h" #include "WebApi.h" #include "WebApi_errors.h" @@ -339,7 +338,6 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) MqttHandlePowerLimiter.forceUpdate(); SolarCharger.updateSettings(); - MqttHandleVedirect.forceUpdate(); } String WebApiMqttClass::getTlsCertInfo(const char* cert) diff --git a/src/main.cpp b/src/main.cpp index 5833ff7e1..c4c438415 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,7 +17,6 @@ #include "MqttHandleBatteryHass.h" #include "MqttHandleInverter.h" #include "MqttHandleInverterTotal.h" -#include "MqttHandleVedirect.h" #include "MqttHandleHuawei.h" #include "MqttHandlePowerLimiter.h" #include "MqttHandlePowerLimiterHass.h" @@ -135,7 +134,6 @@ void setup() MqttHandleDtu.init(scheduler); MqttHandleInverter.init(scheduler); MqttHandleInverterTotal.init(scheduler); - MqttHandleVedirect.init(scheduler); MqttHandleHass.init(scheduler); MqttHandleBatteryHass.init(scheduler); MqttHandleHuawei.init(scheduler); diff --git a/src/solarcharger/Controller.cpp b/src/solarcharger/Controller.cpp index f1b580434..73ba65ff3 100644 --- a/src/solarcharger/Controller.cpp +++ b/src/solarcharger/Controller.cpp @@ -51,9 +51,11 @@ void Controller::loop() { std::lock_guard lock(_mutex); - if (_upProvider) { - _upProvider->loop(); - } + if (!_upProvider) { return; } + + _upProvider->loop(); + + _upProvider->getStats()->mqttLoop(); auto const& config = Configuration.get(); if (!config.Mqtt.Hass.Enabled) { return; } diff --git a/src/solarcharger/Stats.cpp b/src/solarcharger/Stats.cpp new file mode 100644 index 000000000..5033b1621 --- /dev/null +++ b/src/solarcharger/Stats.cpp @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include + +namespace SolarChargers { + +void Stats::mqttLoop() +{ + auto& config = Configuration.get(); + + if (!MqttSettings.getConnected() + || (millis() - _lastMqttPublish) < (config.Mqtt.PublishInterval * 1000)) { + return; + } + + mqttPublish(); + + _lastMqttPublish = millis(); +} + +uint32_t Stats::getMqttFullPublishIntervalMs() const +{ + auto& config = Configuration.get(); + + // this is the default interval, see mqttLoop(). mqttPublish() + // implementations in derived classes may choose to publish some values + // with a lower frequency and hence implement this method with a different + // return value. + return config.Mqtt.PublishInterval * 1000; +} + +} // namespace SolarChargers diff --git a/src/MqttHandleVedirect.cpp b/src/solarcharger/victron/Stats.cpp similarity index 71% rename from src/MqttHandleVedirect.cpp rename to src/solarcharger/victron/Stats.cpp index 383634d32..57d8211b0 100644 --- a/src/MqttHandleVedirect.cpp +++ b/src/solarcharger/victron/Stats.cpp @@ -1,45 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2022 Helge Erbe and others - */ -#include "MqttHandleVedirect.h" -#include "MqttSettings.h" -#include "MessageOutput.h" +#include +#include +#include #include +#include -MqttHandleVedirectClass MqttHandleVedirect; +namespace SolarChargers::Victron { -// #define MQTTHANDLEVEDIRECT_DEBUG - -void MqttHandleVedirectClass::init(Scheduler& scheduler) -{ - scheduler.addTask(_loopTask); - _loopTask.setCallback([this] { loop(); }); - _loopTask.setIterations(TASK_FOREVER); - _loopTask.enable(); - - // initially force a full publish - this->forceUpdate(); -} - -void MqttHandleVedirectClass::forceUpdate() +void Stats::mqttPublish() const { - // initially force a full publish - _nextPublishUpdatesOnly = 0; - _nextPublishFull = 1; -} - - -void MqttHandleVedirectClass::loop() -{ - auto const& config = Configuration.get(); - if (!MqttSettings.getConnected() - || !config.SolarCharger.Enabled - || config.SolarCharger.Provider != SolarChargerProviderType::VEDIRECT) { - return; - } - if ((millis() >= _nextPublishFull) || (millis() >= _nextPublishUpdatesOnly)) { + auto const& config = Configuration.get(); + // determine if this cycle should publish full values or updates only if (_nextPublishFull <= _nextPublishUpdatesOnly) { _PublishFull = true; @@ -47,15 +19,6 @@ void MqttHandleVedirectClass::loop() _PublishFull = !config.SolarCharger.PublishUpdatesOnly; } - #ifdef MQTTHANDLEVEDIRECT_DEBUG - MessageOutput.printf("\r\n\r\nMqttHandleVedirectClass::loop millis %lu _nextPublishUpdatesOnly %u _nextPublishFull %u\r\n", millis(), _nextPublishUpdatesOnly, _nextPublishFull); - if (_PublishFull) { - MessageOutput.println("MqttHandleVedirectClass::loop publish full"); - } else { - MessageOutput.println("MqttHandleVedirectClass::loop publish updates only"); - } - #endif - for (int idx = 0; idx < SolarCharger.controllerAmount(); ++idx) { std::optional optMpptData = SolarCharger.getData(idx); if (!optMpptData.has_value()) { continue; } @@ -68,7 +31,7 @@ void MqttHandleVedirectClass::loop() } // now calculate next points of time to publish - _nextPublishUpdatesOnly = millis() + (config.Mqtt.PublishInterval * 1000); + _nextPublishUpdatesOnly = millis() + ::SolarChargers::Stats::getMqttFullPublishIntervalMs(); if (_PublishFull) { // when Home Assistant MQTT-Auto-Discovery is active, @@ -77,24 +40,15 @@ void MqttHandleVedirectClass::loop() if ((config.SolarCharger.PublishUpdatesOnly) && (config.Mqtt.Hass.Enabled) && (config.Mqtt.Hass.Expire)) { _nextPublishFull = millis() + (((config.Mqtt.PublishInterval * 3) - 1) * 1000); - #ifdef MQTTHANDLEVEDIRECT_DEBUG - uint32_t _tmpNextFullSeconds = (config.Mqtt_PublishInterval * 3) - 1; - MessageOutput.printf("MqttHandleVedirectClass::loop _tmpNextFullSeconds %u - _nextPublishFull %u \r\n", _tmpNextFullSeconds, _nextPublishFull); - #endif - } else { // no future publish full needed _nextPublishFull = UINT32_MAX; } } - - #ifdef MQTTHANDLEVEDIRECT_DEBUG - MessageOutput.printf("MqttHandleVedirectClass::loop _nextPublishUpdatesOnly %u _nextPublishFull %u\r\n", _nextPublishUpdatesOnly, _nextPublishFull); - #endif } } -void MqttHandleVedirectClass::publish_mppt_data(const VeDirectMpptController::data_t ¤tData, +void Stats::publish_mppt_data(const VeDirectMpptController::data_t ¤tData, const VeDirectMpptController::data_t &previousData) const { String value; String topic = "victron/"; @@ -146,3 +100,5 @@ void MqttHandleVedirectClass::publish_mppt_data(const VeDirectMpptController::da PUBLISH_OPT(SmartBatterySenseTemperatureMilliCelsius, "SmartBatterySenseTemperature", currentData.SmartBatterySenseTemperatureMilliCelsius.second / 1000.0); #undef PUBLILSH_OPT } + +}; // namespace SolarChargers::Victron