Skip to content

Commit

Permalink
Feature: Detect if inverter supports 'Power Distribution Logic'
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
AndreasBoehm authored and schlimmchen committed Dec 23, 2024
1 parent 2fa550e commit caed543
Show file tree
Hide file tree
Showing 15 changed files with 75 additions and 17 deletions.
1 change: 1 addition & 0 deletions include/PowerLimiterSolarInverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
7 changes: 7 additions & 0 deletions lib/Hoymiles/src/inverters/HMS_4CH.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
1 change: 1 addition & 0 deletions lib/Hoymiles/src/inverters/HMS_4CH.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
3 changes: 2 additions & 1 deletion lib/Hoymiles/src/inverters/HM_Abstract.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ class HM_Abstract : public InverterAbstract {
bool sendRestartControlRequest();
bool resendPowerControlRequest();
bool sendGridOnProFileParaRequest();
bool supportsPowerDistributionLogic() override { return false; };

private:
uint8_t _lastAlarmLogCnt = 0;
float _activePowerControlLimit = 0;
PowerLimitControlType _activePowerControlType = PowerLimitControlType::AbsolutNonPersistent;

uint8_t _powerState = 1;
};
};
3 changes: 3 additions & 0 deletions lib/Hoymiles/src/inverters/InverterAbstract.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
24 changes: 22 additions & 2 deletions src/PowerLimiterSolarInverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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 '?';
}
}
1 change: 1 addition & 0 deletions src/WebApi_devinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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__);
Expand Down
1 change: 1 addition & 0 deletions src/WebApi_powerlimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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__);
Expand Down
5 changes: 5 additions & 0 deletions webapp/src/components/DevInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
<td>{{ $t('devinfo.HardwareVersion') }}</td>
<td>{{ devInfoList.hw_version }}</td>
</tr>
<tr>
<td>{{ $t('devinfo.SupportsPowerDistributionLogic') }}</td>
<td v-if="devInfoList.pdl_supported">{{ $t('devinfo.yes') }}</td>
<td v-else>{{ $t('devinfo.no') }}</td>
</tr>
</tbody>
</table>
</template>
Expand Down
6 changes: 4 additions & 2 deletions webapp/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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": "<b>Hint:</b> 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": "<b>Hinweis:</b> 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",
Expand Down
6 changes: 4 additions & 2 deletions webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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": "<b>Hint:</b> 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": "<b>Hint:</b> 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",
Expand Down
6 changes: 4 additions & 2 deletions webapp/src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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": "<b>Hint:</b> 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": "<b>Hint:</b> 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",
Expand Down
1 change: 1 addition & 0 deletions webapp/src/types/DevInfoStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export interface DevInfoStatus {
hw_version: number;
hw_model_name: string;
max_power: number;
pdl_supported: boolean;
}
1 change: 1 addition & 0 deletions webapp/src/types/PowerLimiterConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
26 changes: 18 additions & 8 deletions webapp/src/views/PowerLimiterAdminView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -129,21 +129,17 @@
/>

<InputElement
v-if="powerLimiterConfigList.inverters[idx].is_solar_powered"
v-if="
powerLimiterConfigList.inverters[idx].is_solar_powered &&
inverterSupportsOverscaling(inv.serial)
"
:label="$t('powerlimiteradmin.UseOverscaling')"
:tooltip="$t('powerlimiteradmin.UseOverscalingHint')"
v-model="powerLimiterConfigList.inverters[idx].use_overscaling_to_compensate_shading"
type="checkbox"
wide
/>

<div
v-if="powerLimiterConfigList.inverters[idx].use_overscaling_to_compensate_shading"
class="alert alert-secondary"
role="alert"
v-html="$t('powerlimiteradmin.UseOverscalingInfo')"
></div>

<InputElement
:label="$t('powerlimiteradmin.LowerPowerLimit')"
:tooltip="$t('powerlimiteradmin.LowerPowerLimitHint')"
Expand Down Expand Up @@ -597,6 +593,20 @@ export default defineComponent({
}
return inv.name + ' (' + inv.type + ')';
},
inverterSupportsOverscaling(serial: string) {
if (serial === undefined) {
return false;
}
const meta = this.powerLimiterMetaData;
if (meta === undefined) {
return false;
}
const inv = this.getInverterInfo(serial);
if (inv === undefined) {
return false;
}
return inv.pdl_supported === false;
},
needsChannelSelection() {
const cfg = this.powerLimiterConfigList;
Expand Down

0 comments on commit caed543

Please sign in to comment.