From caed5438b037cc02f124353b6f8a36f4a85d0853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Bo=CC=88hm?= Date: Sun, 22 Dec 2024 15:46:50 +0100 Subject: [PATCH] Feature: Detect if inverter supports 'Power Distribution Logic' The detection of 'Power Distribution Logic' is based on the firmware version for specific models and is needed to disable any means of overscaling, as it simply does not work when 'Power Distrbution Logic' is available. --- include/PowerLimiterSolarInverter.h | 1 + lib/Hoymiles/src/inverters/HMS_4CH.cpp | 7 +++++ lib/Hoymiles/src/inverters/HMS_4CH.h | 1 + lib/Hoymiles/src/inverters/HM_Abstract.h | 3 ++- lib/Hoymiles/src/inverters/InverterAbstract.h | 3 +++ src/PowerLimiterSolarInverter.cpp | 24 +++++++++++++++-- src/WebApi_devinfo.cpp | 1 + src/WebApi_powerlimiter.cpp | 1 + webapp/src/components/DevInfo.vue | 5 ++++ webapp/src/locales/de.json | 6 +++-- webapp/src/locales/en.json | 6 +++-- webapp/src/locales/fr.json | 6 +++-- webapp/src/types/DevInfoStatus.ts | 1 + webapp/src/types/PowerLimiterConfig.ts | 1 + webapp/src/views/PowerLimiterAdminView.vue | 26 +++++++++++++------ 15 files changed, 75 insertions(+), 17 deletions(-) diff --git a/include/PowerLimiterSolarInverter.h b/include/PowerLimiterSolarInverter.h index 72023211c..392615b36 100644 --- a/include/PowerLimiterSolarInverter.h +++ b/include/PowerLimiterSolarInverter.h @@ -17,4 +17,5 @@ class PowerLimiterSolarInverter : public PowerLimiterInverter { private: uint16_t scaleLimit(uint16_t expectedOutputWatts); void setAcOutput(uint16_t expectedOutputWatts) final; + static char mpptName(MpptNum_t mppt); }; diff --git a/lib/Hoymiles/src/inverters/HMS_4CH.cpp b/lib/Hoymiles/src/inverters/HMS_4CH.cpp index 1616d013e..0d8d16702 100644 --- a/lib/Hoymiles/src/inverters/HMS_4CH.cpp +++ b/lib/Hoymiles/src/inverters/HMS_4CH.cpp @@ -90,3 +90,10 @@ uint8_t HMS_4CH::getChannelMetaDataSize() const { return sizeof(channelMetaData) / sizeof(channelMetaData[0]); } + +bool HMS_4CH::supportsPowerDistributionLogic() +{ + // This feature was added in inverter firmware version 01.01.12 and + // will limit the AC output instead of limiting the DC inputs. + return DevInfo()->getFwBuildVersion() >= 10112U; +}; diff --git a/lib/Hoymiles/src/inverters/HMS_4CH.h b/lib/Hoymiles/src/inverters/HMS_4CH.h index cb7573390..fb2d1662f 100644 --- a/lib/Hoymiles/src/inverters/HMS_4CH.h +++ b/lib/Hoymiles/src/inverters/HMS_4CH.h @@ -12,4 +12,5 @@ class HMS_4CH : public HMS_Abstract { uint8_t getByteAssignmentSize() const; const channelMetaData_t* getChannelMetaData() const; uint8_t getChannelMetaDataSize() const; + bool supportsPowerDistributionLogic() final; }; diff --git a/lib/Hoymiles/src/inverters/HM_Abstract.h b/lib/Hoymiles/src/inverters/HM_Abstract.h index 491149dc2..1088403ba 100644 --- a/lib/Hoymiles/src/inverters/HM_Abstract.h +++ b/lib/Hoymiles/src/inverters/HM_Abstract.h @@ -16,6 +16,7 @@ class HM_Abstract : public InverterAbstract { bool sendRestartControlRequest(); bool resendPowerControlRequest(); bool sendGridOnProFileParaRequest(); + bool supportsPowerDistributionLogic() override { return false; }; private: uint8_t _lastAlarmLogCnt = 0; @@ -23,4 +24,4 @@ class HM_Abstract : public InverterAbstract { PowerLimitControlType _activePowerControlType = PowerLimitControlType::AbsolutNonPersistent; uint8_t _powerState = 1; -}; \ No newline at end of file +}; diff --git a/lib/Hoymiles/src/inverters/InverterAbstract.h b/lib/Hoymiles/src/inverters/InverterAbstract.h index db2ed2556..53822b498 100644 --- a/lib/Hoymiles/src/inverters/InverterAbstract.h +++ b/lib/Hoymiles/src/inverters/InverterAbstract.h @@ -120,6 +120,9 @@ class InverterAbstract { virtual bool sendChangeChannelRequest(); virtual bool sendGridOnProFileParaRequest() = 0; + // This feature will limit the AC output instead of limiting the DC inputs. + virtual bool supportsPowerDistributionLogic() = 0; + HoymilesRadio* getRadio(); AlarmLogParser* EventLog(); diff --git a/src/PowerLimiterSolarInverter.cpp b/src/PowerLimiterSolarInverter.cpp index 55f88d868..7dbd088a3 100644 --- a/src/PowerLimiterSolarInverter.cpp +++ b/src/PowerLimiterSolarInverter.cpp @@ -123,7 +123,7 @@ uint16_t PowerLimiterSolarInverter::scaleLimit(uint16_t expectedOutputWatts) // as the inverter will take care of the power distribution across the MPPTs itself. // (added in inverter firmware 01.01.12 on supported models (HMS-1600/1800/2000)) // When disabled we return the expected output. - if (!_config.UseOverscaling) { return expectedOutputWatts; } + if (!_config.UseOverscaling || _spInverter->supportsPowerDistributionLogic()) { return expectedOutputWatts; } // prevent scaling if inverter is not producing, as input channels are not // producing energy and hence are detected as not-producing, causing @@ -178,7 +178,7 @@ uint16_t PowerLimiterSolarInverter::scaleLimit(uint16_t expectedOutputWatts) if (_verboseLogging) { MessageOutput.printf("%s MPPT-%c AC power %.0f W\r\n", - _logPrefix, m + 'a', mpptPowerAC); + _logPrefix, mpptName(m), mpptPowerAC); } } @@ -227,3 +227,23 @@ void PowerLimiterSolarInverter::setAcOutput(uint16_t expectedOutputWatts) setTargetPowerLimitWatts(scaleLimit(expectedOutputWatts)); setTargetPowerState(true); } + +char PowerLimiterSolarInverter::mpptName(MpptNum_t mppt) +{ + switch (mppt) { + case MpptNum_t::MPPT_A: + return 'a'; + + case MpptNum_t::MPPT_B: + return 'b'; + + case MpptNum_t::MPPT_C: + return 'c'; + + case MpptNum_t::MPPT_D: + return 'd'; + + default: + return '?'; + } +} diff --git a/src/WebApi_devinfo.cpp b/src/WebApi_devinfo.cpp index 449cd1772..45078ffef 100644 --- a/src/WebApi_devinfo.cpp +++ b/src/WebApi_devinfo.cpp @@ -35,6 +35,7 @@ void WebApiDevInfoClass::onDevInfoStatus(AsyncWebServerRequest* request) root["hw_model_name"] = inv->DevInfo()->getHwModelName(); root["max_power"] = inv->DevInfo()->getMaxPower(); root["fw_build_datetime"] = inv->DevInfo()->getFwBuildDateTimeStr(); + root["pdl_supported"] = inv->supportsPowerDistributionLogic(); } WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); diff --git a/src/WebApi_powerlimiter.cpp b/src/WebApi_powerlimiter.cpp index 8301c738b..196bc5be0 100644 --- a/src/WebApi_powerlimiter.cpp +++ b/src/WebApi_powerlimiter.cpp @@ -70,6 +70,7 @@ void WebApiPowerLimiterClass::onMetaData(AsyncWebServerRequest* request) obj["type"] = inv->typeName(); auto channels = inv->Statistics()->getChannelsByType(TYPE_DC); obj["channels"] = channels.size(); + obj["pdl_supported"] = inv->supportsPowerDistributionLogic(); } WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); diff --git a/webapp/src/components/DevInfo.vue b/webapp/src/components/DevInfo.vue index 7a998e1c0..a56f8ce64 100644 --- a/webapp/src/components/DevInfo.vue +++ b/webapp/src/components/DevInfo.vue @@ -46,6 +46,11 @@ {{ $t('devinfo.HardwareVersion') }} {{ devInfoList.hw_version }} + + {{ $t('devinfo.SupportsPowerDistributionLogic') }} + {{ $t('devinfo.yes') }} + {{ $t('devinfo.no') }} + diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index 30354ec2f..bc9565253 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -233,7 +233,10 @@ "FirmwareVersion": "Firmware-Version", "FirmwareBuildDate": "Firmware-Erstellungsdatum", "HardwarePartNumber": "Hardware-Teilenummer", - "HardwareVersion": "Hardware-Version" + "HardwareVersion": "Hardware-Version", + "SupportsPowerDistributionLogic": "'Power Distribution Logic' unterstützt", + "yes": "@:base.Yes", + "no": "@:base.No" }, "gridprofile": { "NoInfo": "@:devinfo.NoInfo", @@ -711,7 +714,6 @@ "InverterIsSolarPowered": "Wechselrichter wird von Solarmodulen gespeist", "UseOverscaling": "Verschattetet/Ungenutzte Eingänge ausgleichen", "UseOverscalingHint": "Erlaubt das Überskalieren des Wechselrichter-Limits, um ungenutzte Eingänge oder Verschattung eines oder mehrerer Eingänge auszugleichen.", - "UseOverscalingInfo": "Hint: Aktiviere das Ausgleichen von Verschatteten oder ungenutzten Eingängen NICHT, wenn dein Wechselrichter Hoymiles 'Power Distribution Logic' unterstützt, da hiermit der AC-Ausgang limitiert wird und nicht die DC-Eingänge (Verfügbar seit Wechselrichter Firmware Version 01.01.12 auf unterstützten Modellen).", "VoltageThresholds": "Batterie Spannungs-Schwellwerte ", "VoltageLoadCorrectionInfo": "Hinweis: Wenn Leistung von der Batterie abgegeben wird, bricht ihre Spannung etwas ein. Der Spannungseinbruch skaliert mit dem Entladestrom. Damit Wechselrichter nicht vorzeitig ausgeschaltet werden sobald der Stop-Schwellenwert unterschritten wurde, wird der hier angegebene Korrekturfaktor mit einberechnet, um die Spannung zu errechnen, die der Akku in Ruhe hätte. Korrigierte Spannung = DC Spannung + (Aktuelle Leistung (W) * Korrekturfaktor).", "InverterRestartHour": "Uhrzeit für automatischen Wechselrichterneustart", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index f422815d3..1aba6a997 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -233,7 +233,10 @@ "FirmwareVersion": "Firmware Version", "FirmwareBuildDate": "Firmware Build Date", "HardwarePartNumber": "Hardware Part Number", - "HardwareVersion": "Hardware Version" + "HardwareVersion": "Hardware Version", + "SupportsPowerDistributionLogic": "'Power Distribution Logic' supported", + "yes": "@:base.Yes", + "no": "@:base.No" }, "gridprofile": { "NoInfo": "@:devinfo.NoInfo", @@ -713,7 +716,6 @@ "InverterIsSolarPowered": "Inverter is powered by solar modules", "UseOverscaling": "Compensate shaded or unused inputs", "UseOverscalingHint": "Allow to overscale the inverter limit to compensate for unused inputs or shading of one or multiple inputs.", - "UseOverscalingInfo": "Hint: Only enable compensation of shaded or unused inputs if your inverter does NOT support hoymiles 'Power Distribution Logic' which will limit the AC output instead of limiting the DC inputs (added in inverter firmware version 01.01.12 on supported models).", "VoltageThresholds": "Battery Voltage Thresholds", "VoltageLoadCorrectionInfo": "Hint: When the battery is discharged, its voltage drops. The voltage drop scales with the discharge current. In order to not stop inverters too early (stop threshold), this load correction factor can be specified to calculate the battery voltage if it was idle. Corrected voltage = DC Voltage + (Current power * correction factor).", "InverterRestartHour": "Automatic Inverter Restart Time", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index af33a515a..62aaa1389 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -268,7 +268,10 @@ "FirmwareVersion": "Version du firmware", "FirmwareBuildDate": "Date de création du firmware", "HardwarePartNumber": "Numéro d'article matériel", - "HardwareVersion": "Version du matériel" + "HardwareVersion": "Version du matériel", + "SupportsPowerDistributionLogic": "'Power Distribution Logic' supported", + "yes": "@:base.Yes", + "no": "@:base.No" }, "gridprofile": { "NoInfo": "@:devinfo.NoInfo", @@ -779,7 +782,6 @@ "InverterIsSolarPowered": "Inverter is powered by solar modules", "UseOverscaling": "Compensate shaded or unused inputs", "UseOverscalingHint": "Allow to overscale the inverter limit to compensate for unused inputs or shading of one or multiple inputs.", - "UseOverscalingInfo": "Hint: Only enable compensation of shaded or unused inputs if your inverter does NOT support hoymiles 'Power Distribution Logic' which will limit the AC output instead of limiting the DC inputs (added in inverter firmware version 01.01.12 on supported models).", "VoltageThresholds": "Battery Voltage Thresholds", "VoltageLoadCorrectionInfo": "Hint: When the battery is discharged, its voltage drops. The voltage drop scales with the discharge current. In order to not stop inverters too early (stop threshold), this load correction factor can be specified to calculate the battery voltage if it was idle. Corrected voltage = DC Voltage + (Current power * correction factor).", "InverterRestartHour": "Automatic Inverter Restart Time", diff --git a/webapp/src/types/DevInfoStatus.ts b/webapp/src/types/DevInfoStatus.ts index 7c37a5673..452524c9c 100644 --- a/webapp/src/types/DevInfoStatus.ts +++ b/webapp/src/types/DevInfoStatus.ts @@ -8,4 +8,5 @@ export interface DevInfoStatus { hw_version: number; hw_model_name: string; max_power: number; + pdl_supported: boolean; } diff --git a/webapp/src/types/PowerLimiterConfig.ts b/webapp/src/types/PowerLimiterConfig.ts index 99d5d67f9..8bdf3a80e 100644 --- a/webapp/src/types/PowerLimiterConfig.ts +++ b/webapp/src/types/PowerLimiterConfig.ts @@ -10,6 +10,7 @@ export interface PowerLimiterInverterInfo { max_power: number; type: string; channels: number; + pdl_supported: boolean; } // meta-data not directly part of the DPL settings, diff --git a/webapp/src/views/PowerLimiterAdminView.vue b/webapp/src/views/PowerLimiterAdminView.vue index b43c8e1ca..840bcb4be 100644 --- a/webapp/src/views/PowerLimiterAdminView.vue +++ b/webapp/src/views/PowerLimiterAdminView.vue @@ -129,7 +129,10 @@ /> - -