Skip to content

Commit

Permalink
re-enable hass
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreasBoehm committed Jan 15, 2025
1 parent 28c9de3 commit 5fe9813
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 83 deletions.
2 changes: 1 addition & 1 deletion include/solarcharger/Controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Controller {
Task _loopTask;
mutable std::mutex _mutex;
std::unique_ptr<Provider> _upProvider = nullptr;
bool _publishSensors = false;
bool _forcePublishSensors = false;
};

} // namespace SolarChargers
Expand Down
3 changes: 2 additions & 1 deletion include/solarcharger/DummyStats.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ class DummyStats : public Stats {
int32_t getPanelPowerWatts() const override { return 0; }
float getYieldTotal() const override { return 0; }
float getYieldDay() const override { return 0; }
void getLiveViewData(JsonVariant& root, boolean fullUpdate, uint32_t lastPublish) const override {}
void getLiveViewData(JsonVariant& root, const boolean fullUpdate, const uint32_t lastPublish) const override {}
void mqttPublish() const override {}
void mqttPublishSensors(const boolean forcePublish) const override {}
};

} // namespace SolarChargers
3 changes: 0 additions & 3 deletions include/solarcharger/HassIntegration.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
namespace SolarChargers {

class HassIntegration {
public:
virtual void publishSensors() const;

protected:
void publish(const String& subtopic, const String& payload) const;
};
Expand Down
1 change: 0 additions & 1 deletion include/solarcharger/Provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ class Provider {
virtual void deinit() = 0;
virtual void loop() = 0;
virtual std::shared_ptr<Stats> getStats() const = 0;
virtual HassIntegration const& getHassIntegration() const = 0;
};

} // namespace SolarChargers
4 changes: 3 additions & 1 deletion include/solarcharger/Stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ class Stats {
virtual float getYieldDay() const;

// convert stats to JSON for web application live view
virtual void getLiveViewData(JsonVariant& root, boolean fullUpdate, uint32_t lastPublish) const;
virtual void getLiveViewData(JsonVariant& root, const boolean fullUpdate, const uint32_t lastPublish) const;

void mqttLoop();

virtual void mqttPublishSensors(const boolean forcePublish) const;

// the interval at which all data will be re-published, even
// if they did not change. used to calculate Home Assistent expiration.
uint32_t getMqttFullPublishIntervalMs() const;
Expand Down
5 changes: 3 additions & 2 deletions include/solarcharger/victron/HassIntegration.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,20 @@ namespace SolarChargers::Victron {

class HassIntegration : public ::SolarChargers::HassIntegration {
public:
void publishSensors() const final;
void publishSensors(const VeDirectMpptController::data_t &mpptData) const;

private:
void publishBinarySensor(const char *caption, const char *icon, const char *subTopic,
const char *payload_on, const char *payload_off,
const VeDirectMpptController::data_t &mpptData) const;

void publishSensor(const char *caption, const char *icon, const char *subTopic,
const char *deviceClass, const char *stateClass,
const char *unitOfMeasurement,
const VeDirectMpptController::data_t &mpptData) const;

void createDeviceInfo(JsonObject &object,
const VeDirectMpptController::data_t &mpptData) const;

};

} // namespace SolarChargers::Victron
2 changes: 0 additions & 2 deletions include/solarcharger/victron/Provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ class Provider : public ::SolarChargers::Provider {
void deinit() final;
void loop() final;
std::shared_ptr<::SolarChargers::Stats> getStats() const final { return _stats; }
::SolarChargers::HassIntegration const& getHassIntegration() const final { return _hassIntegration; }

private:
Provider(Provider const& other) = delete;
Expand All @@ -35,7 +34,6 @@ class Provider : public ::SolarChargers::Provider {
std::vector<controller_t> _controllers;
std::vector<String> _serialPortOwners;
std::shared_ptr<Stats> _stats = std::make_shared<Stats>();
HassIntegration _hassIntegration;

bool initController(int8_t rx, int8_t tx, bool logging, uint8_t instance);
};
Expand Down
6 changes: 5 additions & 1 deletion include/solarcharger/victron/Stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#pragma once

#include <solarcharger/Stats.h>
#include <solarcharger/victron/HassIntegration.h>
#include <VeDirectMpptController.h>
#include <map>

Expand All @@ -16,8 +17,9 @@ class Stats : public ::SolarChargers::Stats {
float getYieldTotal() const final;
float getYieldDay() const final;

void getLiveViewData(JsonVariant& root, boolean fullUpdate, uint32_t lastPublish) const final;
void getLiveViewData(JsonVariant& root, const boolean fullUpdate, const uint32_t lastPublish) const final;
void mqttPublish() const final;
void mqttPublishSensors(const boolean forcePublish) const final;

void update(const String serial, const std::optional<VeDirectMpptController::data_t> mpptData, uint32_t lastUpdate) const;

Expand All @@ -36,6 +38,8 @@ class Stats : public ::SolarChargers::Stats {

mutable bool _PublishFull;

HassIntegration _hassIntegration;

void populateJsonWithInstanceStats(const JsonObject &root, const VeDirectMpptController::data_t &mpptData) const;

void publish_mppt_data(const VeDirectMpptController::data_t &mpptData, const VeDirectMpptController::data_t &frame) const;
Expand Down
18 changes: 8 additions & 10 deletions src/solarcharger/Controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void Controller::updateSettings()

if (!_upProvider->init(verboseLogging)) { _upProvider = nullptr; }

_publishSensors = true;
_forcePublishSensors = true;
}

std::shared_ptr<Stats const> Controller::getStats() const
Expand All @@ -68,23 +68,21 @@ void Controller::loop()

_upProvider->loop();

_upProvider->getStats()->mqttLoop();

auto const& config = Configuration.get();
if (!config.Mqtt.Hass.Enabled) { return; }

// TODO(schlimmchen): this cannot make sure that transient
// connection problems are actually always noticed.
if (!MqttSettings.getConnected()) {
_publishSensors = true;
_forcePublishSensors = true;
return;
}

if (!_publishSensors) { return; }
_upProvider->getStats()->mqttLoop();

auto const& config = Configuration.get();
if (!config.Mqtt.Hass.Enabled) { return; }

_upProvider->getHassIntegration().publishSensors();
_upProvider->getStats()->mqttPublishSensors(_forcePublishSensors);

_publishSensors = false;
_forcePublishSensors = false;
}

} // namespace SolarChargers
114 changes: 54 additions & 60 deletions src/solarcharger/victron/HassIntegration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,67 +14,61 @@

namespace SolarChargers::Victron {

void HassIntegration::publishSensors() const
void HassIntegration::publishSensors(const VeDirectMpptController::data_t &mpptData) const
{
// device info
for (int idx = 0; idx < 0; ++idx) {
std::optional<VeDirectMpptController::data_t> optMpptData = std::nullopt;// TODO(andreasboehm): How can i get the data in a nice way? .getData(idx);
if (!optMpptData.has_value()) { continue; }

publishSensor("MPPT serial number", "mdi:counter", "SER", nullptr, nullptr, nullptr, *optMpptData);
publishSensor("MPPT firmware version integer", "mdi:counter", "FWI", nullptr, nullptr, nullptr, *optMpptData);
publishSensor("MPPT firmware version formatted", "mdi:counter", "FWF", nullptr, nullptr, nullptr, *optMpptData);
publishSensor("MPPT firmware version FW", "mdi:counter", "FW", nullptr, nullptr, nullptr, *optMpptData);
publishSensor("MPPT firmware version FWE", "mdi:counter", "FWE", nullptr, nullptr, nullptr, *optMpptData);
publishSensor("MPPT state of operation", "mdi:wrench", "CS", nullptr, nullptr, nullptr, *optMpptData);
publishSensor("MPPT error code", "mdi:bell", "ERR", nullptr, nullptr, nullptr, *optMpptData);
publishSensor("MPPT off reason", "mdi:wrench", "OR", nullptr, nullptr, nullptr, *optMpptData);
publishSensor("MPPT tracker operation mode", "mdi:wrench", "MPPT", nullptr, nullptr, nullptr, *optMpptData);
publishSensor("MPPT Day sequence number (0...364)", "mdi:calendar-month-outline", "HSDS", NULL, "total", "d", *optMpptData);

// battery info
publishSensor("Battery voltage", NULL, "V", "voltage", "measurement", "V", *optMpptData);
publishSensor("Battery current", NULL, "I", "current", "measurement", "A", *optMpptData);
publishSensor("Battery power (calculated)", NULL, "P", "power", "measurement", "W", *optMpptData);
publishSensor("Battery efficiency (calculated)", NULL, "E", NULL, "measurement", "%", *optMpptData);

// panel info
publishSensor("Panel voltage", NULL, "VPV", "voltage", "measurement", "V", *optMpptData);
publishSensor("Panel current (calculated)", NULL, "IPV", "current", "measurement", "A", *optMpptData);
publishSensor("Panel power", NULL, "PPV", "power", "measurement", "W", *optMpptData);
publishSensor("Panel yield total", NULL, "H19", "energy", "total_increasing", "kWh", *optMpptData);
publishSensor("Panel yield today", NULL, "H20", "energy", "total", "kWh", *optMpptData);
publishSensor("Panel maximum power today", NULL, "H21", "power", "measurement", "W", *optMpptData);
publishSensor("Panel yield yesterday", NULL, "H22", "energy", "total", "kWh", *optMpptData);
publishSensor("Panel maximum power yesterday", NULL, "H23", "power", "measurement", "W", *optMpptData);

// optional info, provided only if the charge controller delivers the information
if (optMpptData->relayState_RELAY.first != 0) {
publishBinarySensor("MPPT error relay state", "mdi:electric-switch", "RELAY", "ON", "OFF", *optMpptData);
}
if (optMpptData->loadOutputState_LOAD.first != 0) {
publishBinarySensor("MPPT load output state", "mdi:export", "LOAD", "ON", "OFF", *optMpptData);
}
if (optMpptData->loadCurrent_IL_mA.first != 0) {
publishSensor("MPPT load current", NULL, "IL", "current", "measurement", "A", *optMpptData);
}

// optional info, provided only if TX is connected to charge controller
if (optMpptData->NetworkTotalDcInputPowerMilliWatts.first != 0) {
publishSensor("VE.Smart network total DC input power", "mdi:solar-power", "NetworkTotalDcInputPower", "power", "measurement", "W", *optMpptData);
}
if (optMpptData->MpptTemperatureMilliCelsius.first != 0) {
publishSensor("MPPT temperature", "mdi:temperature-celsius", "MpptTemperature", "temperature", "measurement", "°C", *optMpptData);
}
if (optMpptData->BatteryAbsorptionMilliVolt.first != 0) {
publishSensor("Battery absorption voltage", "mdi:battery-charging-90", "BatteryAbsorption", "voltage", "measurement", "V", *optMpptData);
}
if (optMpptData->BatteryFloatMilliVolt.first != 0) {
publishSensor("Battery float voltage", "mdi:battery-charging-100", "BatteryFloat", "voltage", "measurement", "V", *optMpptData);
}
if (optMpptData->SmartBatterySenseTemperatureMilliCelsius.first != 0) {
publishSensor("Smart Battery Sense temperature", "mdi:temperature-celsius", "SmartBatterySenseTemperature", "temperature", "measurement", "°C", *optMpptData);
}
publishSensor("MPPT serial number", "mdi:counter", "SER", nullptr, nullptr, nullptr, mpptData);
publishSensor("MPPT firmware version integer", "mdi:counter", "FWI", nullptr, nullptr, nullptr, mpptData);
publishSensor("MPPT firmware version formatted", "mdi:counter", "FWF", nullptr, nullptr, nullptr, mpptData);
publishSensor("MPPT firmware version FW", "mdi:counter", "FW", nullptr, nullptr, nullptr, mpptData);
publishSensor("MPPT firmware version FWE", "mdi:counter", "FWE", nullptr, nullptr, nullptr, mpptData);
publishSensor("MPPT state of operation", "mdi:wrench", "CS", nullptr, nullptr, nullptr, mpptData);
publishSensor("MPPT error code", "mdi:bell", "ERR", nullptr, nullptr, nullptr, mpptData);
publishSensor("MPPT off reason", "mdi:wrench", "OR", nullptr, nullptr, nullptr, mpptData);
publishSensor("MPPT tracker operation mode", "mdi:wrench", "MPPT", nullptr, nullptr, nullptr, mpptData);
publishSensor("MPPT Day sequence number (0...364)", "mdi:calendar-month-outline", "HSDS", NULL, "total", "d", mpptData);

// battery info
publishSensor("Battery voltage", NULL, "V", "voltage", "measurement", "V", mpptData);
publishSensor("Battery current", NULL, "I", "current", "measurement", "A", mpptData);
publishSensor("Battery power (calculated)", NULL, "P", "power", "measurement", "W", mpptData);
publishSensor("Battery efficiency (calculated)", NULL, "E", NULL, "measurement", "%", mpptData);

// panel info
publishSensor("Panel voltage", NULL, "VPV", "voltage", "measurement", "V", mpptData);
publishSensor("Panel current (calculated)", NULL, "IPV", "current", "measurement", "A", mpptData);
publishSensor("Panel power", NULL, "PPV", "power", "measurement", "W", mpptData);
publishSensor("Panel yield total", NULL, "H19", "energy", "total_increasing", "kWh", mpptData);
publishSensor("Panel yield today", NULL, "H20", "energy", "total", "kWh", mpptData);
publishSensor("Panel maximum power today", NULL, "H21", "power", "measurement", "W", mpptData);
publishSensor("Panel yield yesterday", NULL, "H22", "energy", "total", "kWh", mpptData);
publishSensor("Panel maximum power yesterday", NULL, "H23", "power", "measurement", "W", mpptData);

// optional info, provided only if the charge controller delivers the information
if (mpptData.relayState_RELAY.first != 0) {
publishBinarySensor("MPPT error relay state", "mdi:electric-switch", "RELAY", "ON", "OFF", mpptData);
}
if (mpptData.loadOutputState_LOAD.first != 0) {
publishBinarySensor("MPPT load output state", "mdi:export", "LOAD", "ON", "OFF", mpptData);
}
if (mpptData.loadCurrent_IL_mA.first != 0) {
publishSensor("MPPT load current", NULL, "IL", "current", "measurement", "A", mpptData);
}

// optional info, provided only if TX is connected to charge controller
if (mpptData.NetworkTotalDcInputPowerMilliWatts.first != 0) {
publishSensor("VE.Smart network total DC input power", "mdi:solar-power", "NetworkTotalDcInputPower", "power", "measurement", "W", mpptData);
}
if (mpptData.MpptTemperatureMilliCelsius.first != 0) {
publishSensor("MPPT temperature", "mdi:temperature-celsius", "MpptTemperature", "temperature", "measurement", "°C", mpptData);
}
if (mpptData.BatteryAbsorptionMilliVolt.first != 0) {
publishSensor("Battery absorption voltage", "mdi:battery-charging-90", "BatteryAbsorption", "voltage", "measurement", "V", mpptData);
}
if (mpptData.BatteryFloatMilliVolt.first != 0) {
publishSensor("Battery float voltage", "mdi:battery-charging-100", "BatteryFloat", "voltage", "measurement", "V", mpptData);
}
if (mpptData.SmartBatterySenseTemperatureMilliCelsius.first != 0) {
publishSensor("Smart Battery Sense temperature", "mdi:temperature-celsius", "SmartBatterySenseTemperature", "temperature", "measurement", "°C", mpptData);
}
}

Expand Down
16 changes: 15 additions & 1 deletion src/solarcharger/victron/Stats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ float Stats::getYieldDay() const
return sum;
}

void Stats::getLiveViewData(JsonVariant& root, boolean fullUpdate, uint32_t lastPublish) const
void Stats::getLiveViewData(JsonVariant& root, const boolean fullUpdate, const uint32_t lastPublish) const
{
::SolarChargers::Stats::getLiveViewData(root, fullUpdate, lastPublish);

Expand Down Expand Up @@ -340,4 +340,18 @@ void Stats::publish_mppt_data(const VeDirectMpptController::data_t &currentData,
#undef PUBLILSH_OPT
}

void Stats::mqttPublishSensors(const boolean forcePublish) const
{
// TODO(andreasboehm): sensors are only published once, and then never again.
// This matches the old implementation, but is not ideal. We should publish
// sensors whenever a new controller is discovered, or when the amount of available
// datapoints for a controller changed.
if (!forcePublish) { return; }

for (auto entry : _data) {
if (!entry.second) { continue; }
_hassIntegration.publishSensors(*entry.second);
}
}

}; // namespace SolarChargers::Victron

0 comments on commit 5fe9813

Please sign in to comment.