Skip to content

Commit 76e4db2

Browse files
authored
[fronius] Support setting backup reserved battery capacity (openhab#18080)
* [fronius] Add action to set reserve battery capacity Signed-off-by: Florian Hotze <[email protected]>
1 parent c8330a7 commit 76e4db2

File tree

5 files changed

+95
-0
lines changed

5 files changed

+95
-0
lines changed

bundles/org.openhab.binding.fronius/README.md

+4
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ Once the actions instance has been retrieved, you can invoke the following metho
185185
- `forceBatteryCharging(QuantityType<Power> power)`: Force the battery to charge with the specified power (removes all battery control schedules first and applies all the time).
186186
- `addForcedBatteryChargingSchedule(LocalTime from, LocalTime until, QuantityType<Power> power)`: Add a schedule to force the battery to charge with the specified power in the specified time range.
187187
- `addForcedBatteryChargingSchedule(ZonedDateTime from, ZonedDateTime until, QuantityType<Power> power)`: Add a schedule to force the battery to charge with the specified power in the specified time range.
188+
- `setBackupReservedBatteryCapacity(int percent)`: Set the reserved battery capacity for backup power.
189+
- `setBackupReservedBatteryCapacity(PercentType percent)`: Set the reserved battery capacity for backup power.
188190

189191
All methods return a boolean value indicating whether the action was successful.
190192

@@ -201,6 +203,8 @@ froniusInverterActions.resetBatteryControl();
201203
froniusInverterActions.addHoldBatteryChargeSchedule(time.toZDT('18:00'), time.toZDT('22:00'));
202204
froniusInverterActions.addForcedBatteryChargingSchedule(time.toZDT('22:00'), time.toZDT('23:59'), Quantity('5 kW'));
203205
froniusInverterActions.addForcedBatteryChargingSchedule(time.toZDT('00:00'), time.toZDT('06:00'), Quantity('5 kW'));
206+
207+
froniusInverterActions.setBackupReservedBatteryCapacity(50);
204208
```
205209

206210
## Full Example

bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/action/FroniusSymoInverterActions.java

+33
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.openhab.core.automation.annotation.ActionInput;
2424
import org.openhab.core.automation.annotation.ActionOutput;
2525
import org.openhab.core.automation.annotation.RuleAction;
26+
import org.openhab.core.library.types.PercentType;
2627
import org.openhab.core.library.types.QuantityType;
2728
import org.openhab.core.thing.binding.ThingActions;
2829
import org.openhab.core.thing.binding.ThingActionsScope;
@@ -97,6 +98,24 @@ public static boolean addForcedBatteryChargingSchedule(ThingActions actions, Zon
9798
return addForcedBatteryChargingSchedule(actions, from.toLocalTime(), until.toLocalTime(), power);
9899
}
99100

101+
public static boolean setBackupReservedBatteryCapacity(ThingActions actions, int percent) {
102+
if (actions instanceof FroniusSymoInverterActions froniusSymoInverterActions) {
103+
return froniusSymoInverterActions.setBackupReservedBatteryCapacity(percent);
104+
} else {
105+
throw new IllegalArgumentException(
106+
"The 'actions' argument is not an instance of FroniusSymoInverterActions");
107+
}
108+
}
109+
110+
public static boolean setBackupReservedBatteryCapacity(ThingActions actions, PercentType percent) {
111+
if (actions instanceof FroniusSymoInverterActions froniusSymoInverterActions) {
112+
return froniusSymoInverterActions.setBackupReservedBatteryCapacity(percent);
113+
} else {
114+
throw new IllegalArgumentException(
115+
"The 'actions' argument is not an instance of FroniusSymoInverterActions");
116+
}
117+
}
118+
100119
@Override
101120
public void setThingHandler(@Nullable ThingHandler handler) {
102121
this.handler = (FroniusSymoInverterHandler) handler;
@@ -166,4 +185,18 @@ public boolean addForcedBatteryChargingSchedule(ZonedDateTime from, ZonedDateTim
166185
QuantityType<Power> power) {
167186
return addForcedBatteryChargingSchedule(from.toLocalTime(), until.toLocalTime(), power);
168187
}
188+
189+
@RuleAction(label = "@text/actions.backup-reserved-battery-capacity.label", description = "@text/actions.backup-reserved-battery-capacity.description")
190+
public @ActionOutput(type = "boolean", label = "Success") boolean setBackupReservedBatteryCapacity(
191+
@ActionInput(name = "percent", label = "@text/actions.soc.label", description = "@text/actions.soc.description", required = true) int percent) {
192+
FroniusSymoInverterHandler handler = this.handler;
193+
if (handler != null) {
194+
return handler.setBackupReservedBatteryCapacity(percent);
195+
}
196+
return false;
197+
}
198+
199+
public boolean setBackupReservedBatteryCapacity(PercentType percent) {
200+
return setBackupReservedBatteryCapacity(percent.intValue());
201+
}
169202
}

bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/api/FroniusBatteryControl.java

+37
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.net.URI;
1919
import java.time.LocalTime;
2020
import java.time.format.DateTimeFormatter;
21+
import java.util.Map;
2122
import java.util.Properties;
2223

2324
import javax.measure.quantity.Power;
@@ -49,6 +50,8 @@
4950
@NonNullByDefault
5051
public class FroniusBatteryControl {
5152
private static final String TIME_OF_USE_ENDPOINT = "/config/timeofuse";
53+
private static final String BATTERIES_ENDPOINT = "/config/batteries";
54+
private static final String BACKUP_RESERVED_CAPACITY_PARAMETER = "HYB_BACKUP_RESERVED";
5255

5356
private static final Logger LOGGER = LoggerFactory.getLogger(FroniusBatteryControl.class);
5457
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
@@ -64,13 +67,15 @@ public class FroniusBatteryControl {
6467
private final String username;
6568
private final String password;
6669
private final URI timeOfUseUri;
70+
private final URI batteriesUri;
6771

6872
public FroniusBatteryControl(HttpClient httpClient, URI baseUri, String username, String password) {
6973
this.httpClient = httpClient;
7074
this.baseUri = baseUri;
7175
this.username = username;
7276
this.password = password;
7377
this.timeOfUseUri = baseUri.resolve(URI.create(TIME_OF_USE_ENDPOINT));
78+
this.batteriesUri = baseUri.resolve(URI.create(BATTERIES_ENDPOINT));
7479
}
7580

7681
/**
@@ -208,4 +213,36 @@ ScheduleType.CHARGE_MIN, new TimeTableRecord(from.format(TIME_FORMATTER), until.
208213
timeOfUse[timeOfUse.length - 1] = holdCharge;
209214
setTimeOfUse(new TimeOfUseRecords(timeOfUse));
210215
}
216+
217+
/**
218+
* Sets the reserved battery capacity for backup power.
219+
*
220+
* @param percent the reserved battery capacity for backup power
221+
* @throws FroniusCommunicationException when an error occurs during communication with the inverter
222+
* @throws IllegalArgumentException when percent is not in [10,95]
223+
* @throws FroniusUnauthorizedException when login failed due to invalid credentials
224+
*/
225+
public void setBackupReservedCapacity(int percent)
226+
throws FroniusCommunicationException, FroniusUnauthorizedException {
227+
if (percent < 10 || percent > 95) {
228+
throw new IllegalArgumentException("invalid percent value: " + percent + " (must be in [10,95])");
229+
}
230+
231+
// Login and get the auth header for the next request
232+
String authHeader = FroniusConfigAuthUtil.login(httpClient, baseUri, username, password, HttpMethod.POST,
233+
batteriesUri.getPath(), API_TIMEOUT);
234+
Properties headers = new Properties();
235+
headers.put(HttpHeader.AUTHORIZATION.asString(), authHeader);
236+
237+
// Set the setting
238+
String json = gson.toJson(Map.of(BACKUP_RESERVED_CAPACITY_PARAMETER, percent));
239+
String responseString = FroniusHttpUtil.executeUrl(HttpMethod.POST, batteriesUri.toString(), headers,
240+
new ByteArrayInputStream(json.getBytes()), "application/json", API_TIMEOUT);
241+
PostConfigResponse response = gson.fromJson(responseString, PostConfigResponse.class);
242+
if (!response.writeSuccess().contains(BACKUP_RESERVED_CAPACITY_PARAMETER)) {
243+
LOGGER.debug("{}", responseString);
244+
throw new FroniusCommunicationException("Failed to write configuration to inverter");
245+
}
246+
LOGGER.trace("Backup Reserved Capacity setting set successfully");
247+
}
211248
}

bundles/org.openhab.binding.fronius/src/main/java/org/openhab/binding/fronius/internal/handler/FroniusSymoInverterHandler.java

+17
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,23 @@ public boolean addForcedBatteryChargingSchedule(LocalTime from, LocalTime until,
185185
return false;
186186
}
187187

188+
public boolean setBackupReservedBatteryCapacity(int percent) {
189+
FroniusBatteryControl batteryControl = getBatteryControl();
190+
if (batteryControl != null) {
191+
try {
192+
batteryControl.setBackupReservedCapacity(percent);
193+
return true;
194+
} catch (IllegalArgumentException e) {
195+
logger.warn("Failed to set backup reserved battery capacity: {}", e.getMessage());
196+
} catch (FroniusCommunicationException e) {
197+
logger.warn("Failed to set backup reserved battery capacity", e);
198+
} catch (FroniusUnauthorizedException e) {
199+
logger.warn("Failed to set backup reserved battery capacity: Invalid username or password");
200+
}
201+
}
202+
return false;
203+
}
204+
188205
/**
189206
* Update the channel from the last data retrieved
190207
*

bundles/org.openhab.binding.fronius/src/main/resources/OH-INF/i18n/fronius.properties

+4
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,13 @@ actions.force-battery-charging.label = Force Battery Charging
128128
actions.force-battery-charging.description = Force the battery to charge with the specified power
129129
actions.add-forced-battery-charging-schedule.label = Add Forced Battery Charging Schedule
130130
actions.add-forced-battery-charging-schedule.description = Add a schedule to force the battery to charge with the specified power in the specified time range
131+
actions.backup-reserved-battery-capacity.label = Backup Power Reserved Battery Capacity
132+
actions.backup-reserved-battery-capacity.description = Set the reserved battery capacity for backup power supply
131133
actions.from.label = Begin Timestamp
132134
actions.from.description = The beginning of the time range
133135
actions.until.label = End Timestamp
134136
actions.until.description = The (inclusive) end of the time range
135137
actions.power.label = Power
136138
actions.power.description = The power to charge the battery with
139+
actions.soc.label = State of Charge
140+
actions.soc.description = Battery State of Charge (in percent)

0 commit comments

Comments
 (0)