Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ struct GRID_CHARGER_CONFIG_T {
};
using GridChargerConfig = struct GRID_CHARGER_CONFIG_T;

enum SolarChargerProviderType { VEDIRECT = 0, MQTT = 1 };
enum SolarChargerProviderType { VEDIRECT = 0, MQTT = 1, Integrated = 2 };

struct SOLARCHARGER_MQTT_CONFIG_T {
bool CalculateOutputPower;
Expand Down
110 changes: 110 additions & 0 deletions include/battery/SmartBufferStats.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <battery/Stats.h>
#include <solarcharger/Controller.h>
#include <solarcharger/integrated/Provider.h>
#include <solarcharger/integrated/Stats.h>

namespace Batteries {

// mandatory interface for all kinds of batteries
class SmartBufferStats : public Stats {

public:
using MPPT = SolarChargers::Integrated::MPPT;

virtual std::optional<String> const& getDeviceName() const = 0;
virtual size_t getNumberMppts() const = 0;

inline std::optional<float> getSolarPowerOverall() const {
return _solar_power_sum;
}

inline std::optional<float> getSolarPower(const MPPT mppt) const {
try {
return _solar_power.at(mppt);
}
catch(const std::out_of_range& ex) {;}

return std::nullopt;
}

inline std::optional<float> getSolarVoltage(const MPPT mppt) const {
try {
return _solar_voltage.at(mppt);
}
catch(const std::out_of_range& ex) {;}

return std::nullopt;
}

protected:
inline void setSolarPower(const MPPT mppt, const std::optional<float> &power, const uint32_t timestamp = millis()) {
if (!power.has_value()) { return; }
_solar_power[mppt] = power;

// update sum value
std::optional<float> sum = std::nullopt;
for (const auto& [index, power] : _solar_power) {
if (!power.has_value()) { continue; }
sum = sum.value_or(0) + *power;
}
_solar_power_sum = sum;

// publish value to SolcarCharger integration
auto object = getObject(mppt);
if (object == nullptr ) { return; }
object->setPower(*power, timestamp);
}

inline void setSolarVoltage(const MPPT mppt, const std::optional<float> &voltage, const uint32_t timestamp = millis()) {
if (!voltage.has_value()) { return; }
_solar_voltage[mppt] = voltage;

// publish value to SolcarCharger integration
auto object = getObject(mppt);
if (object == nullptr) { return; }
object->setVoltage(*voltage, timestamp);
}

private:
std::shared_ptr<SolarChargers::Integrated::MpptData> getObject(const MPPT mppt)
{
try {
return getObjects().at(mppt);
}
catch(const std::out_of_range& ex) {;}

return nullptr;
}


std::map<MPPT, std::shared_ptr<SolarChargers::Integrated::MpptData>> getObjects()
{
auto mppt = SolarCharger.getIntegratedStats();
if (mppt == nullptr) { return {}; }

if (mppt->hasDevice(_solarcharger_id)) { return _objects; }

// if device was not found, immediatly clear our cached pointers
_objects.clear();

// amd try to re-add our device
auto result = mppt->addDevice(getManufacturer(), getDeviceName(), getSerial(), getNumberMppts());
if (!result.has_value()) { return {}; }

_solarcharger_id = (*result).first;
_objects = (*result).second->getMppts();

return _objects;
}

std::optional<uint32_t> _solarcharger_id = std::nullopt;
std::optional<float> _solar_power_sum = std::nullopt;
std::map<MPPT, std::shared_ptr<SolarChargers::Integrated::MpptData>> _objects = std::map<MPPT, std::shared_ptr<SolarChargers::Integrated::MpptData>>();
std::map<MPPT, std::optional<float>> _solar_power = std::map<MPPT, std::optional<float>>();
std::map<MPPT, std::optional<float>> _solar_voltage = std::map<MPPT, std::optional<float>>();
};

} // namespace Batteries
4 changes: 3 additions & 1 deletion include/battery/Stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class Stats {
std::optional<String> const& getManufacturer() const { return _oManufacturer; }
virtual std::optional<String> getHassDeviceName() const { return _oManufacturer; }

std::optional<String> const& getSerial() const { return _serial; }

// the last time *any* data was updated
uint32_t getAgeSeconds() const { return (millis() - _lastUpdate) / 1000; }
bool updateAvailable(uint32_t since) const;
Expand Down Expand Up @@ -167,7 +169,7 @@ class Stats {

String _hwversion = "";
String _fwversion = "";
String _serial = "";
std::optional<String> _serial = std::nullopt;
uint32_t _lastUpdate = 0;

private:
Expand Down
9 changes: 5 additions & 4 deletions include/battery/zendure/Constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace Batteries::Zendure {

#define ZENDURE_MAX_PACKS 4U
#define ZENDURE_REMAINING_TIME_OVERFLOW 59940U
#define ZENDURE_NUM_MPPTS 2U

#define ZENDURE_SECONDS_SUNPOSITION 60U
#define ZENDURE_SECONDS_TIMESYNC 3600U
Expand Down Expand Up @@ -52,11 +53,11 @@ namespace Batteries::Zendure {
#define ZENDURE_LOG_OFFSET_PACK_UNKNOWN_3(pack) (30U+(pack)-1U) // ? => always (8449 | 257 | 0 | 0)
#define ZENDURE_LOG_OFFSET_PACK_TEMPERATURE(pack) (34U+(pack)-1U) // [°C]
#define ZENDURE_LOG_OFFSET_PACK_UNKNOWN_5(pack) (38U+(pack)-1U) // ? => always (1340 | 99 | 0 | 0)
#define ZENDURE_LOG_OFFSET_VOLTAGE 42U // [dV]
#define ZENDURE_LOG_OFFSET_INPUT_VOLTAGE 42U // [dV]
#define ZENDURE_LOG_OFFSET_SOLAR_POWER_MPPT_2 43U // [W]
#define ZENDURE_LOG_OFFSET_SOLAR_POWER_MPPT_1 44U // [W]
#define ZENDURE_LOG_OFFSET_OUTPUT_POWER 45U // [W]
#define ZENDURE_LOG_OFFSET_UNKNOWN_05 46U // ? => 1, 413
#define ZENDURE_LOG_OFFSET_OUTPUT_VOLTAGE 46U // [dV]
#define ZENDURE_LOG_OFFSET_DISCHARGE_POWER 47U // [W]
#define ZENDURE_LOG_OFFSET_CHARGE_POWER 48U // [W]
#define ZENDURE_LOG_OFFSET_OUTPUT_POWER_LIMIT 49U // [cA]
Expand All @@ -79,8 +80,8 @@ namespace Batteries::Zendure {
#define ZENDURE_LOG_OFFSET_UNKNOWN_24 66U // ? => always 0
#define ZENDURE_LOG_OFFSET_UNKNOWN_25 67U // ? => always 0
#define ZENDURE_LOG_OFFSET_UNKNOWN_26 68U // ? => always 0
#define ZENDURE_LOG_OFFSET_UNKNOWN_27 69U // ? => always 0
#define ZENDURE_LOG_OFFSET_UNKNOWN_28 70U // ? => always 1
#define ZENDURE_LOG_OFFSET_SOLAR_VOLTAGE_MPPT_1 69U // [dV]
#define ZENDURE_LOG_OFFSET_SOLAR_VOLTAGE_MPPT_2 70U // [dV]
#define ZENDURE_LOG_OFFSET_UNKNOWN_29 71U // ? => always 0
#define ZENDURE_LOG_OFFSET_UNKNOWN_30 72U // ? some counter => 258, 263, 25
#define ZENDURE_LOG_OFFSET_UNKNOWN_31 73U // ? some counter => 309, 293, 23
Expand Down
61 changes: 27 additions & 34 deletions include/battery/zendure/Stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
#pragma once

#include <MqttSettings.h>
#include <battery/Stats.h>
#include <battery/SmartBufferStats.h>
#include <battery/zendure/Constants.h>
#include <solarcharger/Controller.h>
#include <solarcharger/integrated/Provider.h>
#include <solarcharger/integrated/Stats.h>
#include <map>
#include <optional>
#include <Configuration.h>
Expand Down Expand Up @@ -43,7 +47,7 @@ static constexpr frozen::map<ChargeThroughState, const char*, 5> _chargeThroughS

class PackStats;

class Stats : public ::Batteries::Stats {
class Stats : public ::Batteries::SmartBufferStats {
friend class Provider;

static const char* chargeThroughStateToString(std::optional<ChargeThroughState> mode) {
Expand Down Expand Up @@ -127,13 +131,20 @@ class Stats : public ::Batteries::Stats {
void mqttPublish() const final;

std::optional<String> getHassDeviceName() const final {
return String(*getManufacturer() + " " + _device);
return String(*getManufacturer() + " " + *_device);
}

bool supportsAlarmsAndWarnings() const final { return false; }

std::map<size_t, std::shared_ptr<PackStats>> getPackDataList() const { return _packData; }

virtual std::optional<String> const& getDeviceName() const { return _device; }
virtual size_t getNumberMppts() const { return ZENDURE_NUM_MPPTS; };

inline std::optional<float> getInputPower() const {
return getSolarPowerOverall();
}

protected:
std::shared_ptr<PackStats> getPackData(size_t index) const;
std::shared_ptr<PackStats> addPackData(size_t index, String serial);
Expand Down Expand Up @@ -163,10 +174,10 @@ class Stats : public ::Batteries::Stats {
}

void setHwVersion(String&& version) {
_hwversion = _device.value_or("UNKNOWN");

if (!version.isEmpty()) {
_hwversion = _device + " (" + std::move(version) + ")";
}else{
_hwversion = _device;
_hwversion += " (" + std::move(version) + ")";
}
}
void setFwVersion(String&& version) { _fwversion = std::move(version); }
Expand All @@ -175,29 +186,13 @@ class Stats : public ::Batteries::Stats {
_serial = serial;
}
void setSerial(std::optional<String> serial) {
if (serial.has_value()) {
setSerial(*serial);
}
_serial = serial;
}

void setDevice(String&& device) {
_device = std::move(device);
}

inline void updateSolarInputPower() {
_input_power = _solar_power_1 + _solar_power_2;
}

inline void setSolarPower1(const uint16_t power) {
_solar_power_1 = power;
updateSolarInputPower();
}

inline void setSolarPower2(const uint16_t power) {
_solar_power_2 = power;
updateSolarInputPower();
}

void setChargePower(const uint16_t power) {
_charge_power = power;

Expand All @@ -222,6 +217,10 @@ class Stats : public ::Batteries::Stats {
_output_power = power;
}

inline void setOutputVoltage(const float voltage) {
_output_voltage = voltage;
}

inline void setOutputLimit(const uint16_t power) {
_output_limit = power;
}
Expand All @@ -246,17 +245,12 @@ class Stats : public ::Batteries::Stats {
_auto_recover = static_cast<bool>(value);
}

inline void setVoltage(float voltage, uint32_t timestamp) {
if (voltage > 0) {
setDischargeCurrentLimit(static_cast<float>(_inverse_max) / voltage, timestamp);
}
Batteries::Stats::setVoltage(voltage, timestamp);
}

String _device = String("Unknown");
std::optional<String> _device = std::nullopt;

std::map<size_t, std::shared_ptr<PackStats>> _packData = std::map<size_t, std::shared_ptr<PackStats> >();

std::optional<uint32_t> _solarcharger_id = std::nullopt;

int16_t _cellTemperature = 0;
uint16_t _cellMinMilliVolt = 0;
uint16_t _cellMaxMilliVolt = 0;
Expand All @@ -277,9 +271,8 @@ class Stats : public ::Batteries::Stats {
uint16_t _charge_power = 0;
uint16_t _discharge_power = 0;
uint16_t _output_power = 0;
uint16_t _input_power = 0;
uint16_t _solar_power_1 = 0;
uint16_t _solar_power_2 = 0;

float _output_voltage = 0.0;

uint16_t _charge_power_cycle = 0;
uint16_t _discharge_power_cycle = 0;
Expand Down
3 changes: 2 additions & 1 deletion include/solarcharger/Controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include <TaskSchedulerDeclarations.h>
#include <solarcharger/Provider.h>
#include <solarcharger/Stats.h>

#include <solarcharger/integrated/Stats.h>
namespace SolarChargers {

class Controller {
Expand All @@ -15,6 +15,7 @@ class Controller {
void updateSettings();

std::shared_ptr<Stats const> getStats() const;
std::shared_ptr<Integrated::Stats> getIntegratedStats();

private:
void loop();
Expand Down
32 changes: 32 additions & 0 deletions include/solarcharger/integrated/Provider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <mutex>
#include <memory>
#include <TaskSchedulerDeclarations.h>
#include <solarcharger/Provider.h>
#include <solarcharger/integrated/Stats.h>
#include <espMqttClient.h>

namespace SolarChargers::Integrated {

class Provider : public ::SolarChargers::Provider {
public:
Provider() = default;
~Provider() = default;

bool init() final;
void deinit() final { return; };
void loop() final { return; };
std::shared_ptr<::SolarChargers::Stats> getStats() const final { return _stats; }

private:
Provider(Provider const& other) = delete;
Provider(Provider&& other) = delete;
Provider& operator=(Provider const& other) = delete;
Provider& operator=(Provider&& other) = delete;

std::shared_ptr<Stats> _stats = std::make_shared<Stats>();
};

} // namespace SolarChargers::Integrated
Loading