Skip to content

Commit

Permalink
introduce 'SolarChargerStats'
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreasBoehm committed Dec 7, 2024
1 parent a01ccd3 commit 8c0ecbc
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 186 deletions.
28 changes: 3 additions & 25 deletions include/SolarCharger.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,16 @@
#include <memory>
#include <mutex>
#include <TaskSchedulerDeclarations.h>

#include "SolarChargerProvider.h"
#include "VeDirectMpptController.h"
#include "SolarChargerStats.h"

class SolarChargerClass {
public:
void init(Scheduler&);
void updateSettings();

// TODO(andreasboehm): below methods are taken from VictronMppt to start abstracting
// solar chargers without breaking everything.
size_t controllerAmount();
uint32_t getDataAgeMillis();
uint32_t getDataAgeMillis(size_t idx);

// total output of all MPPT charge controllers in Watts
int32_t getOutputPowerWatts();

// total panel input power of all MPPT charge controllers in Watts
int32_t getPanelPowerWatts();

// sum of total yield of all MPPT charge controllers in kWh
float getYieldTotal();

// sum of today's yield of all MPPT charge controllers in kWh
float getYieldDay();

// minimum of all MPPT charge controllers' output voltages in V
float getOutputVoltage();

std::optional<VeDirectMpptController::data_t> getData(size_t idx = 0);

bool isDataValid();
std::shared_ptr<SolarChargerStats const> getStats() const;

SolarChargerProvider* getProvider() const { return _upProvider.get(); }

Expand Down
27 changes: 2 additions & 25 deletions include/SolarChargerProvider.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include "VeDirectMpptController.h"
#include "SolarChargerStats.h"

class SolarChargerProvider {
public:
Expand All @@ -13,28 +13,5 @@ class SolarChargerProvider {
virtual bool init(bool verboseLogging) = 0;
virtual void deinit() = 0;
virtual void loop() = 0;

// TODO(andreasboehm): below methods are taken from VictronMppt to start abstracting
// solar chargers without breaking everything.
virtual size_t controllerAmount() const = 0;
virtual uint32_t getDataAgeMillis() const = 0;
virtual uint32_t getDataAgeMillis(size_t idx) const = 0;
// total output of all MPPT charge controllers in Watts
virtual int32_t getOutputPowerWatts() const = 0;

// total panel input power of all MPPT charge controllers in Watts
virtual int32_t getPanelPowerWatts() const = 0;

// sum of total yield of all MPPT charge controllers in kWh
virtual float getYieldTotal() const = 0;

// sum of today's yield of all MPPT charge controllers in kWh
virtual float getYieldDay() const = 0;

// minimum of all MPPT charge controllers' output voltages in V
virtual float getOutputVoltage() const = 0;

virtual std::optional<VeDirectMpptController::data_t> getData(size_t idx = 0) const = 0;

virtual bool isDataValid() const = 0;
virtual std::shared_ptr<SolarChargerStats> getStats() = 0;
};
107 changes: 107 additions & 0 deletions include/SolarChargerStats.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <cstddef>
#include <cstdint>

class SolarChargerStats {

public:
class SolarChargerControllerStats {
public:
virtual int32_t getDataAgeMillis() const = 0;
virtual int32_t getOutputPowerWatts() const = 0;
virtual int32_t getPanelPowerWatts() const = 0;
virtual float getYieldTotal() const = 0;
virtual float getYieldDay() const = 0;
virtual float getOutputVoltage() const = 0;
};

virtual uint32_t getDataAgeMillis() const = 0;

// minimum of all MPPT charge controllers' output voltages in V
virtual float getOutputVoltage() const = 0;
virtual bool isOuputVoltageValid() const = 0;

// total output of all MPPT charge controllers in Watts
virtual int32_t getOutputPowerWatts() const = 0;
virtual bool isOutputPowerWattsValid() const = 0;

// total panel input power of all MPPT charge controllers in Watts
virtual int32_t getPanelPowerWatts() const = 0;
virtual bool isPanelPowerWattsValid() const = 0;

// sum of total yield of all MPPT charge controllers in kWh
virtual float getYieldTotal() const = 0;

// sum of today's yield of all MPPT charge controllers in kWh
virtual float getYieldDay() const = 0;

virtual size_t controllerAmount() const = 0;

virtual std::vector<std::unique_ptr<SolarChargerControllerStats>> getControllerStats(size_t idx = 0) const = 0;
};

class SolarChargerStatsDummy : public SolarChargerStats {
public:
uint32_t getDataAgeMillis() const final { return INT32_MAX; }
float getOutputVoltage() const final { return 0; }
bool isOuputVoltageValid() const final { return false; }
int32_t getOutputPowerWatts() const final { return 0; }
bool isOutputPowerWattsValid() const final { return false; }
int32_t getPanelPowerWatts() const final { return 0; }
bool isPanelPowerWattsValid() const final { return false; }
float getYieldTotal() const final { return 0; }
float getYieldDay() const final { return 0; }
size_t controllerAmount() const final { return 0; };
};

class VictronMpptStats : public SolarChargerStats {
friend class VictronMppt;

class VictronMpptControllerStats : public SolarChargerControllerStats {
friend class VictronMppt;

public:
int32_t getDataAgeMillis() const final { return _dataAgeMillis; };
int32_t getOutputPowerWatts() const final { return _outputPowerWatts; };
int32_t getPanelPowerWatts() const final { return _panelPowerWatts; };
float getYieldTotal() const final { return _yieldTotal; };
float getYieldDay() const final { return _yieldDay; };
float getOutputVoltage() const final { return _outputVoltage; };

protected:
uint32_t _dataAgeMillis;
float _outputVoltage;
int32_t _outputPowerWatts;
int32_t _panelPowerWatts;
float _yieldTotal;
float _yieldDay;
};

public:
uint32_t getDataAgeMillis() const final { return _dataAgeMillis; };
float getOutputVoltage() const final { return _outputVoltage; };
bool isOuputVoltageValid() const final { return _isOuputVoltageValid; };
int32_t getOutputPowerWatts() const final { return _outputPowerWatts; };
bool isOutputPowerWattsValid() const final { return _isOutputPowerWattsValid; };
int32_t getPanelPowerWatts() const final { return _panelPowerWatts; };
bool isPanelPowerWattsValid() const final { return _isPanelPowerWattsValid; };
float getYieldTotal() const final { return _yieldTotal; };
float getYieldDay() const final { return _yieldDay; };

size_t controllerAmount() const final { return _controllerStats.size(); };

protected:
uint32_t _dataAgeMillis;
float _outputVoltage;
bool _isOuputVoltageValid;
int32_t _outputPowerWatts;
bool _isOutputPowerWattsValid;
int32_t _panelPowerWatts;
bool _isPanelPowerWattsValid;
float _yieldTotal;
float _yieldDay;

std::vector<std::unique_ptr<VictronMpptControllerStats>> _controllerStats;
};
26 changes: 16 additions & 10 deletions include/VictronMppt.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <TaskSchedulerDeclarations.h>

#include "SolarChargerProvider.h"
#include "SolarChargerStats.h"
#include "VeDirectMpptController.h"
#include "Configuration.h"

Expand All @@ -18,30 +19,32 @@ class VictronMppt : public SolarChargerProvider {
void deinit() final;
void loop() final;

bool isDataValid() const final;
std::shared_ptr<SolarChargerStats> getStats() final;

bool isDataValid() const;

// returns the data age of all controllers,
// i.e, the youngest data's age is returned.
uint32_t getDataAgeMillis() const final;
uint32_t getDataAgeMillis(size_t idx) const final;
uint32_t getDataAgeMillis() const;
uint32_t getDataAgeMillis(size_t idx) const;

size_t controllerAmount() const final { return _controllers.size(); }
std::optional<VeDirectMpptController::data_t> getData(size_t idx = 0) const final;
size_t controllerAmount() const { return _controllers.size(); }
std::optional<VeDirectMpptController::data_t> getData(size_t idx = 0) const;

// total output of all MPPT charge controllers in Watts
int32_t getOutputPowerWatts() const final;
int32_t getOutputPowerWatts() const;

// total panel input power of all MPPT charge controllers in Watts
int32_t getPanelPowerWatts() const final;
int32_t getPanelPowerWatts() const;

// sum of total yield of all MPPT charge controllers in kWh
float getYieldTotal() const final;
float getYieldTotal() const;

// sum of today's yield of all MPPT charge controllers in kWh
float getYieldDay() const final;
float getYieldDay() const;

// minimum of all MPPT charge controllers' output voltages in V
float getOutputVoltage() const final;
float getOutputVoltage() const;

// returns the state of operation from the first available controller
std::optional<uint8_t> getStateOfOperation() const;
Expand All @@ -67,4 +70,7 @@ class VictronMppt : public SolarChargerProvider {
std::vector<String> _serialPortOwners;
bool initController(int8_t rx, int8_t tx, bool logging,
uint8_t instance);

std::shared_ptr<VictronMpptStats> _stats =
std::make_shared<VictronMpptStats>();
};
11 changes: 9 additions & 2 deletions src/MqttHandleVedirect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "MessageOutput.h"
#include "SolarChargerProvider.h"
#include "SolarCharger.h"
#include "VictronMppt.h"

MqttHandleVedirectClass MqttHandleVedirect;

Expand Down Expand Up @@ -40,6 +41,12 @@ void MqttHandleVedirectClass::loop()
return;
}

auto victronMppt = static_cast<VictronMppt*>(SolarCharger.getProvider());

if (!victronMppt) {
return;
}

if ((millis() >= _nextPublishFull) || (millis() >= _nextPublishUpdatesOnly)) {
// determine if this cycle should publish full values or updates only
if (_nextPublishFull <= _nextPublishUpdatesOnly) {
Expand All @@ -57,8 +64,8 @@ void MqttHandleVedirectClass::loop()
}
#endif

for (int idx = 0; idx < SolarCharger.controllerAmount(); ++idx) {
std::optional<VeDirectMpptController::data_t> optMpptData = SolarCharger.getData(idx);
for (int idx = 0; idx < victronMppt->controllerAmount(); ++idx) {
std::optional<VeDirectMpptController::data_t> optMpptData = victronMppt->getData(idx);
if (!optMpptData.has_value()) { continue; }

auto const& kvFrame = _kvFrames[optMpptData->serialNr_SER];
Expand Down
11 changes: 9 additions & 2 deletions src/MqttHandleVedirectHass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "Utils.h"
#include "__compiled_constants.h"
#include "SolarCharger.h"
#include "VictronMppt.h"

MqttHandleVedirectHassClass MqttHandleVedirectHass;

Expand Down Expand Up @@ -57,9 +58,15 @@ void MqttHandleVedirectHassClass::publishConfig()
return;
}

auto victronMppt = static_cast<VictronMppt*>(SolarCharger.getProvider());

if (!victronMppt) {
return;
}

// device info
for (int idx = 0; idx < SolarCharger.controllerAmount(); ++idx) {
auto optMpptData = SolarCharger.getData(idx);
for (int idx = 0; idx < victronMppt->controllerAmount(); ++idx) {
auto optMpptData = victronMppt->getData(idx);
if (!optMpptData.has_value()) { continue; }

publishSensor("MPPT serial number", "mdi:counter", "SER", nullptr, nullptr, nullptr, *optMpptData);
Expand Down
12 changes: 6 additions & 6 deletions src/PowerLimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,8 @@ float PowerLimiterClass::getBatteryVoltage(bool log) {
if (inverter.first > 0) { res = inverter.first; }

float chargeControllerVoltage = -1;
if (SolarCharger.isDataValid()) {
res = chargeControllerVoltage = static_cast<float>(SolarCharger.getOutputVoltage());
if (SolarCharger.getStats()->isOuputVoltageValid()) {
res = chargeControllerVoltage = static_cast<float>(SolarCharger.getStats()->getOutputVoltage());
}

float bmsVoltage = -1;
Expand Down Expand Up @@ -425,8 +425,8 @@ void PowerLimiterClass::fullSolarPassthrough(PowerLimiterClass::Status reason)

uint16_t targetOutput = 0;

if (SolarCharger.isDataValid()) {
targetOutput = static_cast<uint16_t>(std::max<int32_t>(0, SolarCharger.getOutputPowerWatts()));
if (SolarCharger.getStats()->isOutputPowerWattsValid()) {
targetOutput = static_cast<uint16_t>(std::max<int32_t>(0, SolarCharger.getStats()->getOutputPowerWatts()));
targetOutput = dcPowerBusToInverterAc(targetOutput);
}

Expand Down Expand Up @@ -678,11 +678,11 @@ uint16_t PowerLimiterClass::getSolarPassthroughPower()

if (!config.PowerLimiter.SolarPassThroughEnabled
|| isBelowStopThreshold()
|| !SolarCharger.isDataValid()) {
|| !SolarCharger.getStats()->isOutputPowerWattsValid()) {
return 0;
}

return SolarCharger.getOutputPowerWatts();
return SolarCharger.getStats()->getOutputPowerWatts();
}

float PowerLimiterClass::getBatteryInvertersOutputAcWatts()
Expand Down
Loading

0 comments on commit 8c0ecbc

Please sign in to comment.