Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New PowerMeter Class for PowerLimiter #102

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7e6dec7
First version of Power limiter
Nov 25, 2022
49ae2a8
Second version of PowerLimiter
Dec 29, 2022
91b4e01
Fix typo in Configuration class
Jan 3, 2023
d057640
Fix rebase conflicts; Rewrite powerlimiter MQTT topic handling; Renam…
Jan 3, 2023
b58c0d3
Rebuild webapp
Jan 3, 2023
ad8d4ee
Use new Hoymiles.getMessageOutput() instead of Serial
Jan 3, 2023
6f905b8
Fix re-initialization of PowerLimiter after saving admin configuration
Jan 3, 2023
da48714
Fix wrong config name
Jan 6, 2023
53a3dd5
PowerLimiter: Add missing newline
Jan 6, 2023
a1a96bc
Increase JSON_BUFFER_SIZE to 8192
Jan 6, 2023
0a2497c
Remove annoying platformio_override.ini from GIT index
Jan 15, 2023
e327866
Implement voltage load correction factor and lots of bugfixes/enhance…
Jan 15, 2023
8a0bed0
Change access point password back to default one (openDTU42)
Jan 21, 2023
eac6ef8
Implement new feature "Direct solar power" (battery bypass)
Jan 22, 2023
5364c49
Fix producing not being stopped when Victron MPPT power < 10
Jan 23, 2023
2847846
Fix victronChargePower not being respected
Jan 29, 2023
790758b
Remove obsolete solarPower if condition
Jan 29, 2023
8ca2a30
README.md: Add some useful info about this project
berni2288 Feb 3, 2023
0b22cff
Implement Pylontech Battery CAN receiver with MQTT publishing
Feb 12, 2023
a703334
README.md: Pylontech battery support is no longer WIP
Feb 12, 2023
a1e579a
Powerlimiter.cpp: Fix newPowerLimit not being signed
berni2288 Feb 13, 2023
fd297d2
Fix some cpplint linting errors in Powerlimiter files
Feb 13, 2023
8323c21
Fix some cpplint linting errors in Powerlimiter files #2
Feb 13, 2023
1a89692
New PowerMeter Class for PowerLimiter
Adminius Feb 13, 2023
28c32ff
Fix some cpplint linting errors in PowerMeter files
Adminius Feb 14, 2023
c40b0c4
Fix cpplint linting error in Powerlimiter file
Adminius Feb 14, 2023
c588cdf
PowerMeter first UI attempt
Adminius Feb 14, 2023
ab2cb35
UI fixes
Adminius Feb 15, 2023
819691d
UI fix typos
Adminius Feb 15, 2023
1a59c23
Fix for wrong error message
Adminius Feb 15, 2023
185e1a0
working state
Adminius Feb 16, 2023
e83a2f4
additinal parameter
Adminius Feb 20, 2023
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
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
# OpenDTU_VeDirect
# OpenDTU_PowerLimiter

This is a fork from the project OpenDTU_VeDirect which is a fork from the Hoymiles project OpenDTU.

This project is still under development and adds following features:

* Dynamically sets the Hoymiles power limited according to the currently used energy in the household (needs an MQTT based power meter like Shelly 3EM)
* Battery support: Read the voltage from Victron MPPT charge controller or from the Hoymiles DC inputs and starts/stops the power producing based on configurable voltage thresholds
* Voltage correction that takes the voltage drop because of the current output load into account (not 100% reliable calculation)
* Can read the current solar panel power from the Victron MPPT and adjust the limiter accordingly to not save energy in the battery (for increased system efficiency). Increases the battery lifespan and reduces energy loses.
* Settings can be configured in the UI
* Pylontech Battery support (via CAN bus interface). Use the SOC for starting/stopping the power output and provide the battery data via MQTT

[![OpenDTU Build](https://github.com/tbnobody/OpenDTU/actions/workflows/build.yml/badge.svg)](https://github.com/tbnobody/OpenDTU/actions/workflows/build.yml)
[![cpplint](https://github.com/tbnobody/OpenDTU/actions/workflows/cpplint.yml/badge.svg)](https://github.com/tbnobody/OpenDTU/actions/workflows/cpplint.yml)
Expand Down
43 changes: 43 additions & 0 deletions include/Battery.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <stdint.h>

class BatteryClass {
public:
float chargeVoltage;
float chargeCurrentLimitation;
float dischargeCurrentLimitation;
uint16_t stateOfCharge;
uint32_t stateOfChargeLastUpdate;
uint16_t stateOfHealth;
float voltage;
float current;
float temperature;
bool alarmOverCurrentDischarge;
bool alarmUnderTemperature;
bool alarmOverTemperature;
bool alarmUnderVoltage;
bool alarmOverVoltage;

bool alarmBmsInternal;
bool alarmOverCurrentCharge;


bool warningHighCurrentDischarge;
bool warningLowTemperature;
bool warningHighTemperature;
bool warningLowVoltage;
bool warningHighVoltage;

bool warningBmsInternal;
bool warningHighCurrentCharge;
char manufacturer[9];
bool chargeEnabled;
bool dischargeEnabled;
bool chargeImmediately;

private:
};

extern BatteryClass Battery;
28 changes: 26 additions & 2 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#define MQTT_MAX_HOSTNAME_STRLEN 128
#define MQTT_MAX_USERNAME_STRLEN 64
#define MQTT_MAX_PASSWORD_STRLEN 64
#define MQTT_MAX_TOPIC_STRLEN 32
#define MQTT_MAX_TOPIC_STRLEN 256
#define MQTT_MAX_LWTVALUE_STRLEN 20
#define MQTT_MAX_ROOT_CA_CERT_STRLEN 2048

Expand All @@ -27,7 +27,7 @@

#define CHAN_MAX_NAME_STRLEN 31

#define JSON_BUFFER_SIZE 6144
#define JSON_BUFFER_SIZE 8192

struct CHANNEL_CONFIG_T {
uint16_t MaxChannelPower;
Expand Down Expand Up @@ -90,6 +90,30 @@ struct CONFIG_T {

bool Mqtt_Hass_Expire;


bool PowerMeter_Enabled;
uint32_t PowerMeter_Interval;
uint32_t PowerMeter_Source;
char PowerMeter_MqttTopicPowerMeter1[MQTT_MAX_TOPIC_STRLEN + 1];
char PowerMeter_MqttTopicPowerMeter2[MQTT_MAX_TOPIC_STRLEN + 1];
char PowerMeter_MqttTopicPowerMeter3[MQTT_MAX_TOPIC_STRLEN + 1];
uint32_t PowerMeter_SdmBaudrate;
uint32_t PowerMeter_SdmAddress;

bool PowerLimiter_Enabled;
bool PowerLimiter_SolarPassTroughEnabled;
uint32_t PowerLimiter_Interval;
bool PowerLimiter_IsInverterBehindPowerMeter;
uint32_t PowerLimiter_LowerPowerLimit;
uint32_t PowerLimiter_UpperPowerLimit;
uint32_t PowerLimiter_BatterySocStartThreshold;
uint32_t PowerLimiter_BatterySocStopThreshold;
float PowerLimiter_VoltageStartThreshold;
float PowerLimiter_VoltageStopThreshold;
float PowerLimiter_VoltageLoadCorrectionFactor;

bool Battery_Enabled;

char Security_Password[WIFI_MAX_PASSWORD_STRLEN + 1];
bool Security_AllowReadonly;
};
Expand Down
34 changes: 34 additions & 0 deletions include/PowerLimiter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include "Configuration.h"
#include <espMqttClient.h>
#include <Arduino.h>
#include <Hoymiles.h>
#include <memory>

class PowerLimiterClass {
public:
void init();
void loop();
void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total);

private:
uint32_t _lastCommandSent;
uint32_t _lastLoop;
uint32_t _lastPowerMeterUpdate;
uint16_t _lastRequestedPowerLimit;
bool _consumeSolarPowerOnly;

float _powerMeter1Power;
float _powerMeter2Power;
float _powerMeter3Power;

bool canUseDirectSolarPower();
uint32_t getDirectSolarPower();
float getLoadCorrectedVoltage(std::shared_ptr<InverterAbstract> inverter);
bool isStartThresholdReached(std::shared_ptr<InverterAbstract> inverter);
bool isStopThresholdReached(std::shared_ptr<InverterAbstract> inverter);
};

extern PowerLimiterClass PowerLimiter;
37 changes: 37 additions & 0 deletions include/PowerMeter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include "Configuration.h"
#include <espMqttClient.h>
#include <Arduino.h>
#include <Hoymiles.h>
#include <memory>
#include "SDM.h"

#ifndef SDM_RX_PIN
#define SDM_RX_PIN 13
#endif

#ifndef SDM_TX_PIN
#define SDM_TX_PIN 32
#endif

class PowerMeterClass {
public:
void init();
void loop();
void onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total);
float getPowerTotal();

private:
uint32_t _interval;
uint32_t _lastPowerMeterUpdate;

float _powerMeter1Power;
float _powerMeter2Power;
float _powerMeter3Power;
float _powerMeterTotalPower;

};

extern PowerMeterClass PowerMeter;
37 changes: 37 additions & 0 deletions include/PylontechCanReceiver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include "Configuration.h"
#include <espMqttClient.h>
#include <Arduino.h>
#include <Hoymiles.h>
#include <memory>

#ifndef PYLONTECH_PIN_RX
#define PYLONTECH_PIN_RX 27
#endif

#ifndef PYLONTECH_PIN_TX
#define PYLONTECH_PIN_TX 26
#endif

class PylontechCanReceiverClass {
public:
void init();
void loop();
void parseCanPackets();
void mqtt();

private:
uint8_t readUnsignedInt8();
uint16_t readUnsignedInt16();
int16_t readSignedInt16();
void readString(char* str, uint8_t numBytes);
void readBooleanBits8(bool* b, uint8_t numBits);
float scaleValue(int16_t value, float factor);
bool getBit(uint8_t value, uint8_t bit);

uint32_t _lastPublish;
};

extern PylontechCanReceiverClass PylontechCanReceiver;
6 changes: 6 additions & 0 deletions include/WebApi.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include "WebApi_battery.h"
#include "WebApi_config.h"
#include "WebApi_devinfo.h"
#include "WebApi_dtu.h"
Expand All @@ -13,6 +14,8 @@
#include "WebApi_network.h"
#include "WebApi_ntp.h"
#include "WebApi_power.h"
#include "WebApi_powermeter.h"
#include "WebApi_powerlimiter.h"
#include "WebApi_prometheus.h"
#include "WebApi_security.h"
#include "WebApi_sysstatus.h"
Expand All @@ -36,6 +39,7 @@ class WebApiClass {
AsyncWebServer _server;
AsyncEventSource _events;

WebApiBatteryClass _webApiBattery;
WebApiConfigClass _webApiConfig;
WebApiDevInfoClass _webApiDevInfo;
WebApiDtuClass _webApiDtu;
Expand All @@ -48,6 +52,8 @@ class WebApiClass {
WebApiNetworkClass _webApiNetwork;
WebApiNtpClass _webApiNtp;
WebApiPowerClass _webApiPower;
WebApiPowerMeterClass _webApiPowerMeter;
WebApiPowerLimiterClass _webApiPowerLimiter;
WebApiPrometheusClass _webApiPrometheus;
WebApiSecurityClass _webApiSecurity;
WebApiSysstatusClass _webApiSysstatus;
Expand Down
18 changes: 18 additions & 0 deletions include/WebApi_battery.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <ESPAsyncWebServer.h>


class WebApiBatteryClass {
public:
void init(AsyncWebServer* server);
void loop();

private:
void onStatus(AsyncWebServerRequest* request);
void onAdminGet(AsyncWebServerRequest* request);
void onAdminPost(AsyncWebServerRequest* request);

AsyncWebServer* _server;
};
18 changes: 18 additions & 0 deletions include/WebApi_powerlimiter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <ESPAsyncWebServer.h>


class WebApiPowerLimiterClass {
public:
void init(AsyncWebServer* server);
void loop();

private:
void onStatus(AsyncWebServerRequest* request);
void onAdminGet(AsyncWebServerRequest* request);
void onAdminPost(AsyncWebServerRequest* request);

AsyncWebServer* _server;
};
18 changes: 18 additions & 0 deletions include/WebApi_powermeter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <ESPAsyncWebServer.h>


class WebApiPowerMeterClass {
public:
void init(AsyncWebServer* server);
void loop();

private:
void onStatus(AsyncWebServerRequest* request);
void onAdminGet(AsyncWebServerRequest* request);
void onAdminPost(AsyncWebServerRequest* request);

AsyncWebServer* _server;
};
22 changes: 21 additions & 1 deletion include/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,24 @@

#define VEDIRECT_ENABLED false
#define VEDIRECT_UPDATESONLY true
#define VEDIRECT_POLL_INTERVAL 5
#define VEDIRECT_POLL_INTERVAL 5

#define POWERMETER_ENABLED false
#define POWERMETER_INTERVAL 10
#define POWERMETER_SOURCE 2
#define POWERMETER_SDMBAUDRATE 9600
#define POWERMETER_SDMADDRESS 1

#define POWERLIMITER_ENABLED false
#define POWERLIMITER_SOLAR_PASSTROUGH_ENABLED true
#define POWERLIMITER_INTERVAL 10
#define POWERLIMITER_IS_INVERTER_BEHIND_POWER_METER true
#define POWERLIMITER_LOWER_POWER_LIMIT 10
#define POWERLIMITER_UPPER_POWER_LIMIT 800
#define POWERLIMITER_BATTERY_SOC_START_THRESHOLD 80
#define POWERLIMITER_BATTERY_SOC_STOP_THRESHOLD 20
#define POWERLIMITER_VOLTAGE_START_THRESHOLD 50.0
#define POWERLIMITER_VOLTAGE_STOP_THRESHOLD 49.0
#define POWERLIMITER_VOLTAGE_LOAD_CORRECTION_FACTOR 0.001

#define BATTERY_ENABLED false
Loading