Skip to content

Commit

Permalink
Prepare Release 2024.11.20
Browse files Browse the repository at this point in the history
merge development into master
  • Loading branch information
schlimmchen authored Nov 20, 2024
2 parents 80a84e5 + bfa55a8 commit 81b1e6e
Show file tree
Hide file tree
Showing 173 changed files with 7,870 additions and 2,942 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cpplint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install cpplint==1.6.1
pip install cpplint
- name: Linting
run: |
cpplint --repository=. --recursive \
Expand Down
90 changes: 56 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,49 @@
[![OpenDTU-OnBattery Build](https://github.com/hoylabs/OpenDTU-OnBattery/actions/workflows/build.yml/badge.svg)](https://github.com/hoylabs/OpenDTU-OnBattery/actions/workflows/build.yml)
[![cpplint](https://github.com/hoylabs/OpenDTU-OnBattery/actions/workflows/cpplint.yml/badge.svg)](https://github.com/hoylabs/OpenDTU-OnBattery/actions/workflows/cpplint.yml)
[![Yarn Linting](https://github.com/hoylabs/OpenDTU-OnBattery/actions/workflows/yarnlint.yml/badge.svg)](https://github.com/hoylabs/OpenDTU-OnBattery/actions/workflows/yarnlint.yml)
<!---
disabled while "create release badge" action is broken, see .github/build.yml
![GitHub tag (latest SemVer)](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/helgeerbe/68b47cc8c8994d04ab3a4fa9d8aee5e6/raw/openDTUcoreRelease.json)
--->

- [OpenDTU-OnBattery](#opendtu-onbattery)
- [What is OpenDTU-OnBattery](#what-is-opendtu-onbattery)
- [Getting Started](#getting-started)
- [Important Differences](#important-differences)
- [Documentation](#documentation)
- [State of the project](#state-of-the-project)
- [History of the project](#history-of-the-project)
- [Project State](#project-state)
- [Project History](#project-history)
- [Acknowledgments](#acknowledgments)

# OpenDTU-OnBattery

This is a fork of [OpenDTU](https://github.com/tbnobody/OpenDTU).
OpenDTU-OnBattery is a fork of [OpenDTU](https://github.com/tbnobody/OpenDTU),
which adds support for battery chargers, battery management systems (BMS), and
power meters on a single ESP32. Its Dynamic Power Limiter can adjust the
inverter's power production to the actual houshold consumption. In this way, it
is possible to implement a zero export policy.

<!---
disabled while "create release badge" action is broken, see .github/build.yml
![GitHub tag (latest SemVer)](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/helgeerbe/68b47cc8c8994d04ab3a4fa9d8aee5e6/raw/openDTUcoreRelease.json)
--->
## Getting Started

[![OpenDTU-OnBattery Build](https://github.com/hoylabs/OpenDTU-OnBattery/actions/workflows/build.yml/badge.svg)](https://github.com/hoylabs/OpenDTU-OnBattery/actions/workflows/build.yml)
[![cpplint](https://github.com/hoylabs/OpenDTU-OnBattery/actions/workflows/cpplint.yml/badge.svg)](https://github.com/hoylabs/OpenDTU-OnBattery/actions/workflows/cpplint.yml)
[![Yarn Linting](https://github.com/hoylabs/OpenDTU-OnBattery/actions/workflows/yarnlint.yml/badge.svg)](https://github.com/hoylabs/OpenDTU-OnBattery/actions/workflows/yarnlint.yml)
See the documentation to learn [what hardware](https://opendtu-onbattery.net/hardware/)
to acquire, how to [initialize](https://opendtu-onbattery.net/firmware/) it
with OpenDTU-OnBattery firmware, and how to
[configure](https://opendtu-onbattery.net/firmware/device_profiles/)
OpenDTU-OnBattery for your hardware.

## Important Differences

## What is OpenDTU-OnBattery
Generally speaking, OpenDTU-OnBattery and the upstream project are compatible
with each other, because OpenDTU-OnBattery mostly only extends the upstream
project. However, there are a few notable differences aside from the added functionality:

OpenDTU-OnBattery is an extension of the original OpenDTU to support battery
chargers, battery management systems (BMS) and power meters on a single ESP32.
With the help of a Dynamic Power Limiter, the power production can be adjusted
to the actual consumption. In this way, it is possible to implement a zero
export policy.
* OpenDTU-OnBattery, due to its code footprint, cannot offer support for
over-the-air (OTA) updates on ESP32 with only 4MB of flash memory. Consult
the [documentation](https://opendtu-onbattery.net/firmware/howto/upgrade_8mb/#background)
to learn more.
* Unlike in the upstream project, you **must** compile the web application
yourself when attempting to build your own firmware blob. See the
[documentation](https://opendtu-onbattery.net/firmware/compile_webapp/) for
details.

## Documentation

Expand All @@ -35,37 +54,40 @@ You may find additional helpful information in the project's
community-maintained [Github
Wiki](https://github.com/hoylabs/OpenDTU-OnBattery/wiki).

To find out what's new or improved have a look at the changelog of the
To find out what's new or improved have a look at the
[releases](https://github.com/hoylabs/OpenDTU-OnBattery/releases).

## State of the project
## Project State

OpenDTU-OnBattery is actively maintained. Please note that OpenDTU-OnBattery
may change significantly during its development. Bug reports, comments, feature
requests and pull requests are welcome!

## History of the project
## Project History

The original OpenDTU project was started from [a discussion on
Mikrocontroller.net](https://www.mikrocontroller.net/topic/525778). It was the
goal to replace the original Hoymiles DTU (Telemetry Gateway) to avoid using
Hoymile's cloud. With a lot of reverse engineering the Hoymiles protocol was
decrypted and analyzed.
Mikrocontroller.net](https://www.mikrocontroller.net/topic/525778). The
original ambition was to replace the original Hoymiles DTU (Telemetry Gateway)
to avoid using Hoymile's cloud. With a lot of reverse engineering, the Hoymiles
protocol was decrypted and analyzed.

In the summer of 2022 @helgeerbe bought a Victron MPPT charge cntroller, and
didn't like the idea to set up a separate ESP32 to receive the charger's data.
He decided to fork OpenDTU and extend it with battery charger support and a
Dynamic Power Limiter.
In the summer of 2022 [@helgeerbe](https://github.com/helgeerbe) bought a
Victron MPPT charge controller, and didn't like the idea to set up a separate
ESP32 to receive the charger's data. He decided to fork OpenDTU and extend it
with battery charger support and a Dynamic Power Limiter.

In early October 2024, the project moved to the newly founded GitHub
organisation `hoylabs` and is since maintained by multiple community members.

## Acknowledgments

* Special thanks to Thomas Basler (@tbnobody), the author of the [upstream
project](https://github.com/tbnobody/OpenDTU), for hist continued effort!
* Thanks to @helgeerbe for starting OpenDTU-OnBattery and his dedication to the
project, as well as his trust in the current maintainers of the project,
which act as part of the `hoylabs` GitHub organisation.
* Special thanks to Thomas Basler ([@tbnobody](https://github.com/tbnobody)),
the author of the [upstream project](https://github.com/tbnobody/OpenDTU),
for his continued effort!
* Thanks to [@helgeerbe](https://github.com/helgeerbe) for starting
OpenDTU-OnBattery, for his dedication to the project, as well as for his
trust in the current maintainers of the project, which act as part of the
`hoylabs` GitHub organisation.
* We like to thank all contributors. With your ideas and enhancements, you have
made OpenDTU-OnBattery much more than @helgeerbe originally had in mind.
made OpenDTU-OnBattery much more than
[@helgeerbe](https://github.com/helgeerbe) originally had in mind.
31 changes: 30 additions & 1 deletion include/BatteryStats.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "AsyncJson.h"
#include "Arduino.h"
#include "JkBmsDataPoints.h"
#include "JbdBmsDataPoints.h"
#include "VeDirectShuntController.h"
#include <cfloat>

Expand Down Expand Up @@ -159,7 +160,6 @@ class SBSBatteryStats : public BatteryStats {

float _chargeVoltage;
float _chargeCurrentLimitation;
float _dischargeCurrentLimitation;
uint16_t _stateOfHealth;
float _current;
float _temperature;
Expand Down Expand Up @@ -284,6 +284,35 @@ class JkBmsBatteryStats : public BatteryStats {
uint32_t _cellVoltageTimestamp = 0;
};

class JbdBmsBatteryStats : public BatteryStats {
public:
void getLiveViewData(JsonVariant& root) const final {
getJsonData(root, false);
}

void getInfoViewData(JsonVariant& root) const {
getJsonData(root, true);
}

void mqttPublish() const final;

uint32_t getMqttFullPublishIntervalMs() const final { return 60 * 1000; }

void updateFrom(JbdBms::DataPointContainer const& dp);

private:
void getJsonData(JsonVariant& root, bool verbose) const;

JbdBms::DataPointContainer _dataPoints;
mutable uint32_t _lastMqttPublish = 0;
mutable uint32_t _lastFullMqttPublish = 0;

uint16_t _cellMinMilliVolt = 0;
uint16_t _cellAvgMilliVolt = 0;
uint16_t _cellMaxMilliVolt = 0;
uint32_t _cellVoltageTimestamp = 0;
};

class VictronSmartShuntStats : public BatteryStats {
public:
void getLiveViewData(JsonVariant& root) const final;
Expand Down
99 changes: 67 additions & 32 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
#include "PinMapping.h"
#include <cstdint>
#include <ArduinoJson.h>
#include <TaskSchedulerDeclarations.h>
#include <mutex>
#include <condition_variable>

#define CONFIG_FILENAME "/config.json"
#define CONFIG_VERSION 0x00011c00 // 0.1.28 // make sure to clean all after change
#define CONFIG_VERSION 0x00011d00 // 0.1.29 // make sure to clean all after change

#define WIFI_MAX_SSID_STRLEN 32
#define WIFI_MAX_PASSWORD_STRLEN 64
Expand All @@ -33,6 +36,7 @@
#define CHAN_MAX_NAME_STRLEN 31

#define DEV_MAX_MAPPING_NAME_STRLEN 63
#define LOCALE_STRLEN 2

#define HTTP_REQUEST_MAX_URL_STRLEN 1024
#define HTTP_REQUEST_MAX_USERNAME_STRLEN 64
Expand Down Expand Up @@ -128,6 +132,43 @@ struct POWERMETER_HTTP_SML_CONFIG_T {
};
using PowerMeterHttpSmlConfig = struct POWERMETER_HTTP_SML_CONFIG_T;

struct POWERLIMITER_INVERTER_CONFIG_T {
uint64_t Serial;
bool IsGoverned;
bool IsBehindPowerMeter;
bool IsSolarPowered;
bool UseOverscalingToCompensateShading;
uint16_t LowerPowerLimit;
uint16_t UpperPowerLimit;
};
using PowerLimiterInverterConfig = struct POWERLIMITER_INVERTER_CONFIG_T;

struct POWERLIMITER_CONFIG_T {
bool Enabled;
bool VerboseLogging;
bool SolarPassThroughEnabled;
uint8_t SolarPassThroughLosses;
bool BatteryAlwaysUseAtNight;
int16_t TargetPowerConsumption;
uint16_t TargetPowerConsumptionHysteresis;
uint16_t BaseLoadLimit;
bool IgnoreSoc;
uint16_t BatterySocStartThreshold;
uint16_t BatterySocStopThreshold;
float VoltageStartThreshold;
float VoltageStopThreshold;
float VoltageLoadCorrectionFactor;
uint16_t FullSolarPassThroughSoc;
float FullSolarPassThroughStartVoltage;
float FullSolarPassThroughStopVoltage;
uint64_t InverterSerialForDcVoltage;
uint8_t InverterChannelIdForDcVoltage;
int8_t RestartHour;
uint16_t TotalUpperPowerLimit;
PowerLimiterInverterConfig Inverters[INV_MAX_COUNT];
};
using PowerLimiterConfig = struct POWERLIMITER_CONFIG_T;

enum BatteryVoltageUnit { Volts = 0, DeciVolts = 1, CentiVolts = 2, MilliVolts = 3 };

enum BatteryAmperageUnit { Amps = 0, MilliAmps = 1 };
Expand All @@ -145,6 +186,8 @@ struct BATTERY_CONFIG_T {
BatteryVoltageUnit MqttVoltageUnit;
bool EnableDischargeCurrentLimit;
float DischargeCurrentLimit;
float DischargeCurrentLimitBelowSoc;
float DischargeCurrentLimitBelowVoltage;
bool UseBatteryReportedDischargeCurrentLimit;
char MqttDischargeCurrentTopic[MQTT_MAX_TOPIC_STRLEN + 1];
char MqttDischargeCurrentJsonPath[BATTERY_JSON_MAX_PATH_STRLEN + 1];
Expand Down Expand Up @@ -251,7 +294,7 @@ struct CONFIG_T {
bool ScreenSaver;
uint8_t Rotation;
uint8_t Contrast;
uint8_t Language;
char Locale[LOCALE_STRLEN + 1];
struct {
uint32_t Duration;
uint8_t Mode;
Expand All @@ -278,34 +321,7 @@ struct CONFIG_T {
PowerMeterHttpSmlConfig HttpSml;
} PowerMeter;

struct {
bool Enabled;
bool VerboseLogging;
bool SolarPassThroughEnabled;
uint8_t SolarPassThroughLosses;
bool BatteryAlwaysUseAtNight;
uint32_t Interval;
bool IsInverterBehindPowerMeter;
bool IsInverterSolarPowered;
bool UseOverscalingToCompensateShading;
uint64_t InverterId;
uint8_t InverterChannelId;
int32_t TargetPowerConsumption;
int32_t TargetPowerConsumptionHysteresis;
int32_t LowerPowerLimit;
int32_t BaseLoadLimit;
int32_t UpperPowerLimit;
bool IgnoreSoc;
uint32_t BatterySocStartThreshold;
uint32_t BatterySocStopThreshold;
float VoltageStartThreshold;
float VoltageStopThreshold;
float VoltageLoadCorrectionFactor;
int8_t RestartHour;
uint32_t FullSolarPassThroughSoc;
float FullSolarPassThroughStartVoltage;
float FullSolarPassThroughStopVoltage;
} PowerLimiter;
PowerLimiterConfig PowerLimiter;

BatteryConfig Battery;

Expand All @@ -331,11 +347,23 @@ struct CONFIG_T {

class ConfigurationClass {
public:
void init();
void init(Scheduler& scheduler);
bool read();
bool write();
void migrate();
CONFIG_T& get();
CONFIG_T const& get();

class WriteGuard {
public:
WriteGuard();
CONFIG_T& getConfig();
~WriteGuard();

private:
std::unique_lock<std::mutex> _lock;
};

WriteGuard getWriteGuard();

INVERTER_CONFIG_T* getFreeInverterSlot();
INVERTER_CONFIG_T* getInverterConfig(const uint64_t serial);
Expand All @@ -347,13 +375,20 @@ class ConfigurationClass {
static void serializePowerMeterHttpJsonConfig(PowerMeterHttpJsonConfig const& source, JsonObject& target);
static void serializePowerMeterHttpSmlConfig(PowerMeterHttpSmlConfig const& source, JsonObject& target);
static void serializeBatteryConfig(BatteryConfig const& source, JsonObject& target);
static void serializePowerLimiterConfig(PowerLimiterConfig const& source, JsonObject& target);

static void deserializeHttpRequestConfig(JsonObject const& source, HttpRequestConfig& target);
static void deserializePowerMeterMqttConfig(JsonObject const& source, PowerMeterMqttConfig& target);
static void deserializePowerMeterSerialSdmConfig(JsonObject const& source, PowerMeterSerialSdmConfig& target);
static void deserializePowerMeterHttpJsonConfig(JsonObject const& source, PowerMeterHttpJsonConfig& target);
static void deserializePowerMeterHttpSmlConfig(JsonObject const& source, PowerMeterHttpSmlConfig& target);
static void deserializeBatteryConfig(JsonObject const& source, BatteryConfig& target);
static void deserializePowerLimiterConfig(JsonObject const& source, PowerLimiterConfig& target);

private:
void loop();

Task _loopTask;
};

extern ConfigurationClass Configuration;
Loading

0 comments on commit 81b1e6e

Please sign in to comment.