Skip to content

Commit

Permalink
Merge pull request #125 from helgeerbe/powerlimiter
Browse files Browse the repository at this point in the history
Translations for powerlimiter admin; Pylontech CAN Pins in Device manager; other fixes & enhancements
  • Loading branch information
helgeerbe committed Mar 7, 2023
2 parents b70407d + 44a770b commit 6dd34a8
Show file tree
Hide file tree
Showing 15 changed files with 79 additions and 26 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,9 @@ This can be achieved by copying one of the [env:....] sections from 'platformio.
-DHOYMILES_PIN_CE=4
-DHOYMILES_PIN_CS=5
-DVICTRON_PIN_TX=21
-DVICTRON_PIN_RX=22
-DVICTRON_PIN_RX=22
-DPYLONTECH_PIN_RX=27
-DPYLONTECH_PIN_TX=14
```
It is recommended to make all changes only in the 'platformio_override.ini', this is your personal copy.
You can also change the pins by creating a custom [device profile](docs/DeviceProfiles.md).
Expand Down
5 changes: 4 additions & 1 deletion include/PinMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ struct PinMapping_t {
uint8_t display_reset;
uint8_t victron_tx;
uint8_t victron_rx;
uint8_t battery_rx;
uint8_t battery_tx;
};

class PinMappingClass {
Expand All @@ -42,9 +44,10 @@ class PinMappingClass {
bool isValidNrf24Config();
bool isValidEthConfig();
bool isValidVictronConfig();
bool isValidBatteryConfig();

private:
PinMapping_t _pinMapping;
};

extern PinMappingClass PinMapping;
extern PinMappingClass PinMapping;
3 changes: 2 additions & 1 deletion include/PylontechCanReceiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@

class PylontechCanReceiverClass {
public:
void init();
void init(int8_t rx, int8_t tx);
void enable();
void loop();
void parseCanPackets();
void mqtt();
Expand Down
2 changes: 2 additions & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ build_flags = ${env.build_flags}
-DHOYMILES_PIN_CS=5
-DVICTRON_PIN_TX=21
-DVICTRON_PIN_RX=22
-DPYLONTECH_PIN_RX=27
-DPYLONTECH_PIN_TX=14


[env:olimex_esp32_poe]
Expand Down
13 changes: 12 additions & 1 deletion src/PinMapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ PinMappingClass::PinMappingClass()
_pinMapping.victron_tx = VICTRON_PIN_TX;
_pinMapping.victron_rx = VICTRON_PIN_RX;

_pinMapping.battery_rx = PYLONTECH_PIN_RX;
_pinMapping.battery_tx = PYLONTECH_PIN_TX;
}

PinMapping_t& PinMappingClass::get()
Expand Down Expand Up @@ -119,6 +121,9 @@ bool PinMappingClass::init(const String& deviceMapping)
_pinMapping.victron_rx = doc[i]["victron"]["rx"] | VICTRON_PIN_RX;
_pinMapping.victron_tx = doc[i]["victron"]["tx"] | VICTRON_PIN_TX;

_pinMapping.battery_rx = doc[i]["battery"]["rx"] | PYLONTECH_PIN_RX;
_pinMapping.battery_tx = doc[i]["battery"]["tx"] | PYLONTECH_PIN_TX;

return true;
}
}
Expand All @@ -145,4 +150,10 @@ bool PinMappingClass::isValidVictronConfig()
{
return _pinMapping.victron_rx > 0
&& _pinMapping.victron_tx > 0;
}
}

bool PinMappingClass::isValidBatteryConfig()
{
return _pinMapping.battery_rx > 0
&& _pinMapping.battery_tx > 0;
}
15 changes: 6 additions & 9 deletions src/PowerLimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,14 @@ void PowerLimiterClass::init()
}

_consumeSolarPowerOnly = true;
_lastCommandSent = 0;
_lastCommandSent = 0;
_lastLoop = 0;
_lastPowerMeterUpdate = 0;
_lastRequestedPowerLimit = 0;
}

void PowerLimiterClass::onMqttMessage(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total)
{
MessageOutput.printf("PowerLimiterClass: Received MQTT message on topic: %s\r\n", topic);

CONFIG_T& config = Configuration.get();

if (strcmp(topic, config.PowerLimiter_MqttTopicPowerMeter1) == 0) {
Expand Down Expand Up @@ -109,11 +107,10 @@ void PowerLimiterClass::loop()
float acPower = inverter->Statistics()->getChannelFieldValue(TYPE_AC, (ChannelNum_t) config.PowerLimiter_InverterChannelId, FLD_PAC);
float correctedDcVoltage = dcVoltage + (acPower * config.PowerLimiter_VoltageLoadCorrectionFactor);

if ((_consumeSolarPowerOnly && isStartThresholdReached(inverter))
|| !canUseDirectSolarPower()) {
if ((_consumeSolarPowerOnly && isStartThresholdReached(inverter))) {
// The battery is full enough again, use the full battery power from now on.
_consumeSolarPowerOnly = false;
} else if (!_consumeSolarPowerOnly && !isStopThresholdReached(inverter) && canUseDirectSolarPower()) {
} else if (!_consumeSolarPowerOnly && isStopThresholdReached(inverter) && canUseDirectSolarPower()) {
// The battery voltage dropped too low
_consumeSolarPowerOnly = true;
}
Expand Down Expand Up @@ -224,7 +221,7 @@ bool PowerLimiterClass::canUseDirectSolarPower()

uint16_t PowerLimiterClass::getDirectSolarPower()
{
if (!this->canUseDirectSolarPower()) {
if (!canUseDirectSolarPower()) {
return 0;
}

Expand All @@ -249,7 +246,7 @@ bool PowerLimiterClass::isStartThresholdReached(std::shared_ptr<InverterAbstract
{
CONFIG_T& config = Configuration.get();

// If the Battery interface is enabled, use the SOC value
// Check if the Battery interface is enabled and the SOC start threshold is reached
if (config.Battery_Enabled
&& config.PowerLimiter_BatterySocStartThreshold > 0.0
&& (millis() - Battery.stateOfChargeLastUpdate) < 60000
Expand All @@ -270,7 +267,7 @@ bool PowerLimiterClass::isStopThresholdReached(std::shared_ptr<InverterAbstract>
{
CONFIG_T& config = Configuration.get();

// If the Battery interface is enabled, use the SOC value
// Check if the Battery interface is enabled and the SOC stop threshold is reached
if (config.Battery_Enabled
&& config.PowerLimiter_BatterySocStopThreshold > 0.0
&& (millis() - Battery.stateOfChargeLastUpdate) < 60000
Expand Down
11 changes: 8 additions & 3 deletions src/PylontechCanReceiver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,21 @@

PylontechCanReceiverClass PylontechCanReceiver;

void PylontechCanReceiverClass::init()
void PylontechCanReceiverClass::init(int8_t rx, int8_t tx)
{
CAN.setPins(rx, tx);

CONFIG_T& config = Configuration.get();

if (!config.Battery_Enabled) {
return;
}

CAN.setPins(PYLONTECH_PIN_RX, PYLONTECH_PIN_TX);

enable();
}

void PylontechCanReceiverClass::enable()
{
if (!CAN.begin(500E3)) {
Hoymiles.getMessageOutput()->println("Starting CAN failed!");
}
Expand Down
2 changes: 1 addition & 1 deletion src/WebApi_battery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,6 @@ void WebApiBatteryClass::onAdminPost(AsyncWebServerRequest* request)
request->send(response);

if (config.Battery_Enabled) {
PylontechCanReceiver.init();
PylontechCanReceiver.enable();
}
}
4 changes: 4 additions & 0 deletions src/WebApi_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
victronPinObj[F("rx")] = pin.victron_rx;
victronPinObj[F("tx")] = pin.victron_tx;

JsonObject batteryPinObj = curPin.createNestedObject("battery");
batteryPinObj[F("rx")] = pin.battery_rx;
batteryPinObj[F("tx")] = pin.battery_tx;

response->setLength();
request->send(response);
}
Expand Down
13 changes: 10 additions & 3 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "InverterSettings.h"
#include "MessageOutput.h"
#include "VeDirectFrameHandler.h"
#include "PylontechCanReceiver.h"
#include "MqttHandleDtu.h"
#include "MqttHandleHass.h"
#include "MqttHandleVedirectHass.h"
Expand All @@ -20,7 +21,6 @@
#include "Utils.h"
#include "WebApi.h"
#include "PowerLimiter.h"
#include "PylontechCanReceiver.h"
#include "defaults.h"
#include <Arduino.h>
#include <LittleFS.h>
Expand Down Expand Up @@ -149,8 +149,15 @@ void setup()
// Dynamic power limiter
PowerLimiter.init();

// Pylontech / CAN bus
PylontechCanReceiver.init();
// Initialize Pylontech Battery / CAN bus
MessageOutput.println(F("Initialize Pylontech battery interface... "));
if (PinMapping.isValidBatteryConfig()) {
MessageOutput.printf("Pylontech Battery rx = %d, tx = %d\r\n", pin.battery_rx, pin.battery_tx);
PylontechCanReceiver.init(pin.battery_rx, pin.battery_tx);
MessageOutput.println(F("done"));
} else {
MessageOutput.println(F("Invalid pin config"));
}
}

void loop()
Expand Down
25 changes: 23 additions & 2 deletions webapp/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -447,15 +447,36 @@
"Save": "@:dtuadmin.Save"
},
"powerlimiteradmin": {
"PowerLimiterSettings": "Power Limiter Einstellungen",
"PowerLimiterConfiguration": "Power Limiter Konfiguration",
"General": "Allgemein",
"Enable": "Aktiviert",
"EnableSolarPasstrough": "Aktiviere Solar Pass-trough",
"SolarpasstroughInfo": "Diese Einstellung aktiviert die direkte Weitergabe der aktuell vom Laderegler gemeldeten Solarleistung an den Wechselrichter um eine unnötige Speicherung zu vermeiden und die Energieverluste zu minimieren.",
"InverterId": "Wechselrichter ID",
"InverterIdHint": "Wähle den Wechselrichter an dem die Batterie hängt.",
"InverterChannelId": "Kanal ID",
"InverterChannelIdHint": "Wähle den Kanal an dem die Batterie hängt.",
"TargetPowerConsumption": "Erlaubter Stromverbrauch",
"TargetPowerConsumptionHint": "Angestrebter erlaubter Stromverbrauch.",
"TargetPowerConsumptionHysteresis": "Hysterese für den Zielstromverbrauch",
"TargetPowerConsumptionHysteresisHint": "Wert um den der Zielstromverbrauch schwanken darf, ohne dass nachgeregelt wird."

"TargetPowerConsumptionHysteresisHint": "Wert um den der Zielstromverbrauch schwanken darf, ohne dass nachgeregelt wird.",
"LowerPowerLimit": "Unteres Leistungslimit",
"UpperPowerLimit": "Oberes Leistungslimit",
"PowerMeters": "Leistungsmesser - MQTT",
"MqttTopicPowerMeter1": "MQTT topic - Power meter #1",
"MqttTopicPowerMeter2": "MQTT topic - Power meter #2 (Optional)",
"MqttTopicPowerMeter3": "MQTT topic - Power meter #3 (Optional)",
"BatterySocStartThreshold": "Akku SOC - Start",
"BatterySocStopThreshold": "Akku SOC - Stop",
"VoltageStartThreshold": "DC Spannung - Start",
"VoltageStopThreshold": "DC Spannung - Stop",
"VoltageLoadCorrectionFactor": "DC Spannung - Lastkorrekturfaktor",
"BatterySocInfo": "<b>Hinweis:</b> Der Battery SOC (State of charge) -Wert kann nur benutzt werden wenn das Battery CAN Bus Interface aktiviert ist. Wenn die Batterie innerhalb der letzten Minute keine Werte geschickt hat, werden als Fallback-Option die Spannungseinstellungen verwendet.",
"InverterIsBehindPowerMeter": "Welchselrichter ist hinter Leistungsmesser",
"Battery": "DC / Akku",
"VoltageLoadCorrectionInfo": "<b>Hinweis:</b> Wenn Leistung von der Batterie abgegeben wird, bricht normalerweise die Spannung etwas ein. Damit nicht vorzeitig der Wechelrichter ausgeschaltet wird sobald der \"Stop\"-Schwellenwert erreicht wird, wird der hier angegebene Korrekturfaktor mit einberechnet. Korrigierte Spannung = DC Spannung + (Aktuelle Leistung (W) + Korrekturfaktor).",
"Save": "@:dtuadmin.Save"
},
"batteryadmin": {
"BatterySettings": "Batterie Einstellungen",
Expand Down
8 changes: 4 additions & 4 deletions webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@
"PowerLimiterConfiguration": "Power Limiter Configuration",
"General": "General",
"Enable": "Enable",
"EnableSolarPasstrough": "Enable Solar Passtrough",
"EnableSolarPasstrough": "Enable Solar-Passtrough",
"SolarpasstroughInfo": "When the sun is shining, this setting enables the sychronization of the inverter limit with the current solar power of the Victron MPPT charger. This optimizes battery degradation and loses.",
"InverterId": "Inverter ID",
"InverterIdHint": "Select proper inverter ID where battery is connected to.",
Expand All @@ -461,12 +461,12 @@
"TargetPowerConsumptionHint": "Set the grid power consumption the limiter tries to achieve.",
"TargetPowerConsumptionHysteresis": "Hysteresis for power consumption",
"TargetPowerConsumptionHysteresisHint": "Value around which the target power consumption fluctuates without readjustment.",
"LowerPowerLimit": "Lower power limit / continuous feed",
"LowerPowerLimit": "Lower power limit",
"UpperPowerLimit": "Upper power limit",
"PowerMeters": "Power meters - MQTT",
"MqttTopicPowerMeter1": "MQTT topic - Power meter #1",
"MqttTopicPowerMeter2": "MQTT topic - Power meter #2",
"MqttTopicPowerMeter3": "MQTT topic - Power meter #3",
"MqttTopicPowerMeter2": "MQTT topic - Power meter #2 (optional)",
"MqttTopicPowerMeter3": "MQTT topic - Power meter #3 (optional)",
"BatterySocStartThreshold": "Battery SOC - Start threshold",
"BatterySocStopThreshold": "Battery SOC - Stop threshold",
"VoltageStartThreshold": "DC Voltage - Start threshold",
Expand Down
Binary file modified webapp_dist/index.html.gz
Binary file not shown.
Binary file modified webapp_dist/js/app.js.gz
Binary file not shown.
Binary file modified webapp_dist/zones.json.gz
Binary file not shown.

0 comments on commit 6dd34a8

Please sign in to comment.