OpenDTU-old/src/MqttHandleVedirect.cpp
Bernhard Kirchen 3c8b8d4427
use frozen::string and frozen::map where reasonable (#593)
this change utilizes some of the features from library "frozen", which
was included upstream for the grid profile parser. to improve code
maintainability, a couple of std::maps mapping strings to values or the
other way around were introduced in OpenDTU-OnBattery-specific code at
the expense of some flash and computing overhead.

library "frozen" offers constexpr versions of map and string, which
saves initialization code and offers slightly faster lookups. this
brings the binary size down by ~25kB and should provide a small
performance improvement at runtime.
2024-01-04 23:28:34 +01:00

168 lines
6.4 KiB
C++

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2022 Helge Erbe and others
*/
#include "VictronMppt.h"
#include "MqttHandleVedirect.h"
#include "MqttSettings.h"
#include "MessageOutput.h"
MqttHandleVedirectClass MqttHandleVedirect;
// #define MQTTHANDLEVEDIRECT_DEBUG
void MqttHandleVedirectClass::init(Scheduler& scheduler)
{
scheduler.addTask(_loopTask);
_loopTask.setCallback(std::bind(&MqttHandleVedirectClass::loop, this));
_loopTask.setIterations(TASK_FOREVER);
_loopTask.enable();
// initially force a full publish
this->forceUpdate();
}
void MqttHandleVedirectClass::forceUpdate()
{
// initially force a full publish
_nextPublishUpdatesOnly = 0;
_nextPublishFull = 1;
}
void MqttHandleVedirectClass::loop()
{
CONFIG_T& config = Configuration.get();
if (!MqttSettings.getConnected() || !config.Vedirect.Enabled) {
return;
}
if (!VictronMppt.isDataValid()) {
return;
}
if ((millis() >= _nextPublishFull) || (millis() >= _nextPublishUpdatesOnly)) {
// determine if this cycle should publish full values or updates only
if (_nextPublishFull <= _nextPublishUpdatesOnly) {
_PublishFull = true;
} else {
_PublishFull = !config.Vedirect.UpdatesOnly;
}
#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
auto spMpptData = VictronMppt.getData();
String value;
String topic = "victron/";
topic.concat(spMpptData->SER);
topic.concat("/");
if (_PublishFull || spMpptData->PID != _kvFrame.PID)
MqttSettings.publish(topic + "PID", spMpptData->getPidAsString().data());
if (_PublishFull || strcmp(spMpptData->SER, _kvFrame.SER) != 0)
MqttSettings.publish(topic + "SER", spMpptData->SER );
if (_PublishFull || strcmp(spMpptData->FW, _kvFrame.FW) != 0)
MqttSettings.publish(topic + "FW", spMpptData->FW);
if (_PublishFull || spMpptData->LOAD != _kvFrame.LOAD)
MqttSettings.publish(topic + "LOAD", spMpptData->LOAD == true ? "ON": "OFF");
if (_PublishFull || spMpptData->CS != _kvFrame.CS)
MqttSettings.publish(topic + "CS", spMpptData->getCsAsString().data());
if (_PublishFull || spMpptData->ERR != _kvFrame.ERR)
MqttSettings.publish(topic + "ERR", spMpptData->getErrAsString().data());
if (_PublishFull || spMpptData->OR != _kvFrame.OR)
MqttSettings.publish(topic + "OR", spMpptData->getOrAsString().data());
if (_PublishFull || spMpptData->MPPT != _kvFrame.MPPT)
MqttSettings.publish(topic + "MPPT", spMpptData->getMpptAsString().data());
if (_PublishFull || spMpptData->HSDS != _kvFrame.HSDS) {
value = spMpptData->HSDS;
MqttSettings.publish(topic + "HSDS", value);
}
if (_PublishFull || spMpptData->V != _kvFrame.V) {
value = spMpptData->V;
MqttSettings.publish(topic + "V", value);
}
if (_PublishFull || spMpptData->I != _kvFrame.I) {
value = spMpptData->I;
MqttSettings.publish(topic + "I", value);
}
if (_PublishFull || spMpptData->P != _kvFrame.P) {
value = spMpptData->P;
MqttSettings.publish(topic + "P", value);
}
if (_PublishFull || spMpptData->VPV != _kvFrame.VPV) {
value = spMpptData->VPV;
MqttSettings.publish(topic + "VPV", value);
}
if (_PublishFull || spMpptData->IPV != _kvFrame.IPV) {
value = spMpptData->IPV;
MqttSettings.publish(topic + "IPV", value);
}
if (_PublishFull || spMpptData->PPV != _kvFrame.PPV) {
value = spMpptData->PPV;
MqttSettings.publish(topic + "PPV", value);
}
if (_PublishFull || spMpptData->E != _kvFrame.E) {
value = spMpptData->E;
MqttSettings.publish(topic + "E", value);
}
if (_PublishFull || spMpptData->H19 != _kvFrame.H19) {
value = spMpptData->H19;
MqttSettings.publish(topic + "H19", value);
}
if (_PublishFull || spMpptData->H20 != _kvFrame.H20) {
value = spMpptData->H20;
MqttSettings.publish(topic + "H20", value);
}
if (_PublishFull || spMpptData->H21 != _kvFrame.H21) {
value = spMpptData->H21;
MqttSettings.publish(topic + "H21", value);
}
if (_PublishFull || spMpptData->H22 != _kvFrame.H22) {
value = spMpptData->H22;
MqttSettings.publish(topic + "H22", value);
}
if (_PublishFull || spMpptData->H23 != _kvFrame.H23) {
value = spMpptData->H23;
MqttSettings.publish(topic + "H23", value);
}
if (!_PublishFull) {
_kvFrame = *spMpptData;
}
// now calculate next points of time to publish
_nextPublishUpdatesOnly = millis() + (config.Mqtt.PublishInterval * 1000);
if (_PublishFull) {
// when Home Assistant MQTT-Auto-Discovery is active,
// and "enable expiration" is active, all values must be published at
// least once before the announced expiry interval is reached
if ((config.Vedirect.UpdatesOnly) && (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
}
}