Skip to content

Commit

Permalink
webapp: refactor DPL inverter settings
Browse files Browse the repository at this point in the history
* remove the table of managed inverters with the row element before it,
  breaking the style of the webapp itself.
* ditch the modals: all inverter settings are now visible if the
  respective inverter is selected to be governed.
* solves the issue where changes to the inverter settings are not
  applied when the modal closes, as is expected by the users, but only
  when the whole DPL settings form is submitted. now it is intuitive
  that changed settings only apply once the whole form is submitted.
  • Loading branch information
schlimmchen committed Nov 12, 2024
1 parent eefce0b commit 236c172
Show file tree
Hide file tree
Showing 9 changed files with 414 additions and 521 deletions.
1 change: 1 addition & 0 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ using PowerMeterHttpSmlConfig = struct POWERMETER_HTTP_SML_CONFIG_T;

struct POWERLIMITER_INVERTER_CONFIG_T {
uint64_t Serial;
bool IsGoverned;
bool IsBehindPowerMeter;
bool IsSolarPowered;
bool UseOverscalingToCompensateShading;
Expand Down
5 changes: 4 additions & 1 deletion src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ void ConfigurationClass::serializePowerLimiterConfig(PowerLimiterConfig const& s
};

// we want a representation of our floating-point value in the JSON that
// uses the least amount of decimal digits possble to convey the value that
// uses the least amount of decimal digits possible to convey the value that
// is actually represented by the float. this is no easy task. ArduinoJson
// does this for us, however, it does it as expected only for variables of
// type double. this is probably because it assumes all floating-point
Expand Down Expand Up @@ -156,6 +156,7 @@ void ConfigurationClass::serializePowerLimiterConfig(PowerLimiterConfig const& s
JsonObject t = inverters.add<JsonObject>();

t["serial"] = serialStr(s.Serial);
t["is_governed"] = s.IsGoverned;
t["is_behind_power_meter"] = s.IsBehindPowerMeter;
t["is_solar_powered"] = s.IsSolarPowered;
t["use_overscaling_to_compensate_shading"] = s.UseOverscalingToCompensateShading;
Expand Down Expand Up @@ -470,6 +471,7 @@ void ConfigurationClass::deserializePowerLimiterConfig(JsonObject const& source,
JsonObject s = inverters[i];

inv.Serial = serialBin(s["serial"] | String("0")); // 0 marks inverter slot as unused
inv.IsGoverned = s["is_governed"] | false;
inv.IsBehindPowerMeter = s["is_behind_power_meter"] | POWERLIMITER_IS_INVERTER_BEHIND_POWER_METER;
inv.IsSolarPowered = s["is_solar_powered"] | POWERLIMITER_IS_INVERTER_SOLAR_POWERED;
inv.UseOverscalingToCompensateShading = s["use_overscaling_to_compensate_shading"] | POWERLIMITER_USE_OVERSCALING_TO_COMPENSATE_SHADING;
Expand Down Expand Up @@ -741,6 +743,7 @@ bool ConfigurationClass::read()
}
inv.Serial = previousInverterSerial;
config.PowerLimiter.InverterSerialForDcVoltage = previousInverterSerial;
inv.IsGoverned = true;
inv.IsBehindPowerMeter = powerlimiter["is_inverter_behind_powermeter"] | POWERLIMITER_IS_INVERTER_BEHIND_POWER_METER;
inv.IsSolarPowered = powerlimiter["is_inverter_solar_powered"] | POWERLIMITER_IS_INVERTER_SOLAR_POWERED;
inv.UseOverscalingToCompensateShading = powerlimiter["use_overscaling_to_compensate_shading"] | POWERLIMITER_USE_OVERSCALING_TO_COMPENSATE_SHADING;
Expand Down
4 changes: 3 additions & 1 deletion src/PowerLimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ void PowerLimiterClass::loop()

if (invConfig.Serial == 0ULL) { break; }

if (!invConfig.IsGoverned) { continue; }

auto iter = _inverters.begin();
while (iter != _inverters.end()) {
if ((*iter)->getSerial() == invConfig.Serial) { break; }
Expand All @@ -160,7 +162,7 @@ void PowerLimiterClass::loop()
for (size_t i = 0; i < INV_MAX_COUNT; ++i) {
auto const& inv = config.PowerLimiter.Inverters[i];
if (inv.Serial == 0ULL) { break; }
found = inv.Serial == (*iter)->getSerial();
found = inv.Serial == (*iter)->getSerial() && inv.IsGoverned;
if (found) { break; }
}

Expand Down
9 changes: 4 additions & 5 deletions src/WebApi_powerlimiter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,20 @@ void WebApiPowerLimiterClass::onMetaData(AsyncWebServerRequest* request)
root["battery_enabled"] = config.Battery.Enabled;
root["charge_controller_enabled"] = config.Vedirect.Enabled;

JsonObject inverters = root["inverters"].to<JsonObject>();
JsonArray inverters = root["inverters"].to<JsonArray>();
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
auto inv = Hoymiles.getInverterBySerial(config.Inverter[i].Serial);
if (!inv) { continue; }

JsonObject obj = inverters[inv->serialString()].to<JsonObject>();
JsonObject obj = inverters.add<JsonObject>();
obj["serial"] = inv->serialString();
obj["pos"] = i;
obj["name"] = String(config.Inverter[i].Name);
obj["poll_enable"] = config.Inverter[i].Poll_Enable;
obj["poll_enable_night"] = config.Inverter[i].Poll_Enable_Night;
obj["command_enable"] = config.Inverter[i].Command_Enable;
obj["command_enable_night"] = config.Inverter[i].Command_Enable_Night;

obj["type"] = "Unknown";
obj["channels"] = 1;
obj["max_power"] = inv->DevInfo()->getMaxPower(); // okay if zero/unknown
obj["type"] = inv->typeName();
auto channels = inv->Statistics()->getChannelsByType(TYPE_DC);
obj["channels"] = channels.size();
Expand Down
1 change: 1 addition & 0 deletions webapp/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@
"ConfigHintNoBatteryInterface": "SoC-basierte Schwellwerte können nur mit konfigurierter Batteriekommunikationsschnittstelle genutzt werden.",
"General": "Allgemein",
"Enable": "Aktiviert",
"GovernInverter": "Steuere Wechselrichter \"{name}\"",
"VerboseLogging": "@:base.VerboseLogging",
"SolarPassthrough": "Solar-Passthrough",
"EnableSolarPassthrough": "Aktiviere Solar-Passthrough",
Expand Down
1 change: 1 addition & 0 deletions webapp/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@
"ConfigHintNoBatteryInterface": "SoC-based thresholds can only be used if a battery communication interface is configured.",
"General": "General",
"Enable": "Enable",
"GovernInverter": "Govern Inverter \"{name}\"",
"VerboseLogging": "@:base.VerboseLogging",
"SolarPassthrough": "Solar-Passthrough",
"EnableSolarPassthrough": "Enable Solar-Passthrough",
Expand Down
1 change: 1 addition & 0 deletions webapp/src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,7 @@
"ConfigHintNoBatteryInterface": "SoC-based thresholds can only be used if a battery communication interface is configured.",
"General": "General",
"Enable": "Enable",
"GovernInverter": "Govern Inverter \"{name}\"",
"VerboseLogging": "@:base.VerboseLogging",
"SolarPassthrough": "Solar-Passthrough",
"EnableSolarPassthrough": "Enable Solar-Passthrough",
Expand Down
5 changes: 4 additions & 1 deletion webapp/src/types/PowerLimiterConfig.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
export interface PowerLimiterInverterInfo {
serial: string;
pos: number;
name: string;
poll_enable: boolean;
poll_enable_night: boolean;
command_enable: boolean;
command_enable_night: boolean;
max_power: number;
type: string;
channels: number;
}
Expand All @@ -15,11 +17,12 @@ export interface PowerLimiterMetaData {
power_meter_enabled: boolean;
battery_enabled: boolean;
charge_controller_enabled: boolean;
inverters: { [key: string]: PowerLimiterInverterInfo };
inverters: PowerLimiterInverterInfo[];
}

export interface PowerLimiterInverterConfig {
serial: string;
is_governed: boolean;
is_behind_power_meter: boolean;
is_solar_powered: boolean;
use_overscaling_to_compensate_shading: boolean;
Expand Down
Loading

0 comments on commit 236c172

Please sign in to comment.