[fronius] Add actions to force battery discharging (#19254)

Signed-off-by: Florian Hotze <dev@florianhotze.com>
This commit is contained in:
Florian Hotze
2025-08-27 20:23:34 +02:00
committed by GitHub
parent 4da0fee5b3
commit b28715570f
4 changed files with 129 additions and 27 deletions
@@ -189,6 +189,9 @@ Once the actions instance has been retrieved, you can invoke the following metho
- `preventBatteryCharging()`: Prevent the battery from charging (removes all battery control schedules first and applies all the time).
- `addPreventBatteryChargingSchedule(LocalTime from, LocalTime until)`: Add a schedule to prevent the battery from charging in the specified time range.
- `addPreventBatteryChargingSchedule(ZonedDateTime from, ZonedDateTime until)`: Add a schedule to prevent the battery from charging in the specified time range.
- `forceBatteryDischarging(QuantityType<Power> power)`: Force the battery to discharge with the specified power (removes all battery control schedules first and applies all the time).
- `addForcedBatteryDischargingSchedule(LocalTime from, LocalTime until, QuantityType<Power> power)`: Add a schedule to force the battery to discharge with the specified power in the specified time range.
- `addForcedBatteryDischargingSchedule(ZonedDateTime from, ZonedDateTime until, QuantityType<Power> power)`: Add a schedule to force the battery to discharge with the specified power in the specified time range.
- `setBackupReservedBatteryCapacity(int percent)`: Set the reserved battery capacity for backup power.
- `setBackupReservedBatteryCapacity(PercentType percent)`: Set the reserved battery capacity for backup power.
@@ -207,6 +210,7 @@ froniusInverterActions.resetBatteryControl();
froniusInverterActions.addHoldBatteryChargeSchedule(time.toZDT('18:00'), time.toZDT('22:00'));
froniusInverterActions.addForcedBatteryChargingSchedule(time.toZDT('22:00'), time.toZDT('23:59'), Quantity('5 kW'));
froniusInverterActions.addForcedBatteryChargingSchedule(time.toZDT('00:00'), time.toZDT('06:00'), Quantity('5 kW'));
froniusInverterActions.addForcesBatteryDischargingSchedule(time.toZDT('07:00'), time.toZDT('09:00'));
froniusInverterActions.addPreventBatteryChargingSchedule(time.toZDT('09:00'), time.toZDT('12:00'));
froniusInverterActions.setBackupReservedBatteryCapacity(50);
@@ -132,6 +132,35 @@ public class FroniusSymoInverterActions implements ThingActions {
}
}
public static boolean forceBatteryDischarging(ThingActions actions, QuantityType<Power> power) {
if (actions instanceof FroniusSymoInverterActions froniusSymoInverterActions) {
return froniusSymoInverterActions.forceBatteryDischarging(power);
} else {
throw new IllegalArgumentException(
"The 'actions' argument is not an instance of FroniusSymoInverterActions");
}
}
public static boolean addForcedBatteryDischargingSchedule(ThingActions actions, LocalTime from, LocalTime until,
QuantityType<Power> power) {
if (actions instanceof FroniusSymoInverterActions froniusSymoInverterActions) {
return froniusSymoInverterActions.addForcedBatteryDischargingSchedule(from, until, power);
} else {
throw new IllegalArgumentException(
"The 'actions' argument is not an instance of FroniusSymoInverterActions");
}
}
public static boolean addForcedBatteryDischargingSchedule(ThingActions actions, ZonedDateTime from,
ZonedDateTime until, QuantityType<Power> power) {
if (actions instanceof FroniusSymoInverterActions froniusSymoInverterActions) {
return froniusSymoInverterActions.addForcedBatteryDischargingSchedule(from, until, power);
} else {
throw new IllegalArgumentException(
"The 'actions' argument is not an instance of FroniusSymoInverterActions");
}
}
public static boolean setBackupReservedBatteryCapacity(ThingActions actions, int percent) {
if (actions instanceof FroniusSymoInverterActions froniusSymoInverterActions) {
return froniusSymoInverterActions.setBackupReservedBatteryCapacity(percent);
@@ -265,6 +294,39 @@ public class FroniusSymoInverterActions implements ThingActions {
return addPreventBatteryChargingSchedule(from.toLocalTime(), until.toLocalTime());
}
@RuleAction(label = "@text/actions.force-battery-discharging.label", description = "@text/actions.force-battery-discharging.description")
public @ActionOutput(type = "boolean", label = "Success") boolean forceBatteryDischarging(
@ActionInput(name = "power", label = "@text/actions.power.label", description = "@text/actions.power.label", type = "QuantityType<Power>", required = true) QuantityType<Power> power) {
FroniusBatteryControl batteryControl = getBatteryControl();
if (batteryControl != null) {
return executeBatteryControlAction(() -> {
batteryControl.forceBatteryDischarging(power);
return true;
});
}
return false;
}
@RuleAction(label = "@text/actions.add-forced-battery-discharging-schedule.label", description = "@text/actions.add-forced-battery-discharging-schedule.description")
public @ActionOutput(type = "boolean", label = "Success") boolean addForcedBatteryDischargingSchedule(
@ActionInput(name = "from", label = "@text/actions.from.label", description = "@text/actions.from.description", required = true) LocalTime from,
@ActionInput(name = "until", label = "@text/actions.until.label", description = "@text/actions.until.description", required = true) LocalTime until,
@ActionInput(name = "power", label = "@text/actions.power.label", description = "@text/actions.power.label", type = "QuantityType<Power>", required = true) QuantityType<Power> power) {
FroniusBatteryControl batteryControl = getBatteryControl();
if (batteryControl != null) {
return executeBatteryControlAction(() -> {
batteryControl.addForcedBatteryDischargingSchedule(from, until, power);
return true;
});
}
return false;
}
public boolean addForcedBatteryDischargingSchedule(ZonedDateTime from, ZonedDateTime until,
QuantityType<Power> power) {
return addForcedBatteryDischargingSchedule(from.toLocalTime(), until.toLocalTime(), power);
}
@RuleAction(label = "@text/actions.backup-reserved-battery-capacity.label", description = "@text/actions.backup-reserved-battery-capacity.description")
public @ActionOutput(type = "boolean", label = "Success") boolean setBackupReservedBatteryCapacity(
@ActionInput(name = "percent", label = "@text/actions.soc.label", description = "@text/actions.soc.description", required = true) int percent) {
@@ -146,6 +146,35 @@ public class FroniusBatteryControl {
logger.trace("Time of Use settings set successfully");
}
/**
* Adds a schedule to the time of use settings of the Fronius hybrid inverter.
*
* @param from start time of the forced charge period
* @param until end time of the forced charge period
* @param scheduleType the type of the schedule
* @param power the power value for the schedule
* @throws FroniusCommunicationException when an error occurs during communication with the inverter
* @throws FroniusUnauthorizedException when the login fails due to invalid credentials
*/
private void addSchedule(LocalTime from, LocalTime until, ScheduleType scheduleType, QuantityType<Power> power)
throws FroniusCommunicationException, FroniusUnauthorizedException {
TimeOfUseRecords currentTimeOfUse = getTimeOfUse();
TimeOfUseRecord[] timeOfUse = new TimeOfUseRecord[currentTimeOfUse.records().length + 1];
System.arraycopy(currentTimeOfUse.records(), 0, timeOfUse, 0, currentTimeOfUse.records().length);
QuantityType<Power> powerInWatts = power.toUnit(Units.WATT);
if (powerInWatts == null) {
throw new IllegalArgumentException("power must be convertible to Watt unit");
}
if (powerInWatts.intValue() < 0) {
throw new IllegalArgumentException("power must be non-negative");
}
TimeOfUseRecord holdCharge = new TimeOfUseRecord(true, powerInWatts.intValue(), scheduleType,
new TimeTableRecord(from.format(TIME_FORMATTER), until.format(TIME_FORMATTER)), ALL_WEEKDAYS_RECORD);
timeOfUse[timeOfUse.length - 1] = holdCharge;
setTimeOfUse(new TimeOfUseRecords(timeOfUse));
}
/**
* Resets the time of use settings (i.e. removes all time-dependent battery control settings) of the Fronius hybrid
* inverter.
@@ -179,14 +208,7 @@ public class FroniusBatteryControl {
*/
public void addHoldBatteryChargeSchedule(LocalTime from, LocalTime until)
throws FroniusCommunicationException, FroniusUnauthorizedException {
TimeOfUseRecord[] currentTimeOfUse = getTimeOfUse().records();
TimeOfUseRecord[] timeOfUse = new TimeOfUseRecord[currentTimeOfUse.length + 1];
System.arraycopy(currentTimeOfUse, 0, timeOfUse, 0, currentTimeOfUse.length);
TimeOfUseRecord holdCharge = new TimeOfUseRecord(true, 0, ScheduleType.DISCHARGE_MAX,
new TimeTableRecord(from.format(TIME_FORMATTER), until.format(TIME_FORMATTER)), ALL_WEEKDAYS_RECORD);
timeOfUse[timeOfUse.length - 1] = holdCharge;
setTimeOfUse(new TimeOfUseRecords(timeOfUse));
addSchedule(from, until, ScheduleType.DISCHARGE_MAX, new QuantityType<>(0, Units.WATT));
}
/**
@@ -213,18 +235,7 @@ public class FroniusBatteryControl {
*/
public void addForcedBatteryChargingSchedule(LocalTime from, LocalTime until, QuantityType<Power> power)
throws FroniusCommunicationException, FroniusUnauthorizedException {
TimeOfUseRecords currentTimeOfUse = getTimeOfUse();
TimeOfUseRecord[] timeOfUse = new TimeOfUseRecord[currentTimeOfUse.records().length + 1];
System.arraycopy(currentTimeOfUse.records(), 0, timeOfUse, 0, currentTimeOfUse.records().length);
QuantityType<Power> powerInWatts = power.toUnit(Units.WATT);
if (powerInWatts == null) {
throw new IllegalArgumentException("power must be convertible to Watt unit");
}
TimeOfUseRecord holdCharge = new TimeOfUseRecord(true, powerInWatts.intValue(), ScheduleType.CHARGE_MIN,
new TimeTableRecord(from.format(TIME_FORMATTER), until.format(TIME_FORMATTER)), ALL_WEEKDAYS_RECORD);
timeOfUse[timeOfUse.length - 1] = holdCharge;
setTimeOfUse(new TimeOfUseRecords(timeOfUse));
addSchedule(from, until, ScheduleType.CHARGE_MIN, power);
}
/**
@@ -248,14 +259,34 @@ public class FroniusBatteryControl {
*/
public void addPreventBatteryChargingSchedule(LocalTime from, LocalTime until)
throws FroniusCommunicationException, FroniusUnauthorizedException {
TimeOfUseRecords currentTimeOfUse = getTimeOfUse();
TimeOfUseRecord[] timeOfUse = new TimeOfUseRecord[currentTimeOfUse.records().length + 1];
System.arraycopy(currentTimeOfUse.records(), 0, timeOfUse, 0, currentTimeOfUse.records().length);
addSchedule(from, until, ScheduleType.CHARGE_MAX, new QuantityType<>(0, Units.WATT));
}
TimeOfUseRecord preventCharging = new TimeOfUseRecord(true, 0, ScheduleType.CHARGE_MAX,
new TimeTableRecord(from.format(TIME_FORMATTER), until.format(TIME_FORMATTER)), ALL_WEEKDAYS_RECORD);
timeOfUse[timeOfUse.length - 1] = preventCharging;
setTimeOfUse(new TimeOfUseRecords(timeOfUse));
/**
* Forces the battery to discharge right now with the specified power.
*
* @param power the power to discharge the battery with
* @throws FroniusCommunicationException when an error occurs during communication with the inverter
* @throws FroniusUnauthorizedException when the login fails due to invalid credentials
*/
public void forceBatteryDischarging(QuantityType<Power> power)
throws FroniusCommunicationException, FroniusUnauthorizedException {
reset();
addForcedBatteryDischargingSchedule(BEGIN_OF_DAY, END_OF_DAY, power);
}
/**
* Forces the battery to discharge during a specific time period with the specified power.
*
* @param from start time of the prevented charging period
* @param until end time of the prevented charging period
* @param power the power to discharge the battery with
* @throws FroniusCommunicationException when an error occurs during communication with the inverter
* @throws FroniusUnauthorizedException when the login fails due to invalid credentials
*/
public void addForcedBatteryDischargingSchedule(LocalTime from, LocalTime until, QuantityType<Power> power)
throws FroniusCommunicationException, FroniusUnauthorizedException {
addSchedule(from, until, ScheduleType.DISCHARGE_MIN, power);
}
/**
@@ -136,6 +136,11 @@ actions.prevent-battery-charging.label = Prevent Battery Charging
actions.prevent-battery-charging.description = Prevent the battery from charging
actions.add-prevent-battery-charging-schedule.label = Add Prevent Battery Charging Schedule
actions.add-prevent-battery-charging-schedule.description = Add a schedule to prevent the battery from charging in the specified time range
actions.force-battery-discharging.label = Force Battery Discharging
actions.force-battery-discharging.description = Force the battery to discharge with the specified power
actions.add-forced-battery-discharging-schedule.label = Add Forced Battery Discharging Schedule
actions.add-forced-battery-discharging-schedule.description = Add a schedule to force the battery to discharge with the specified power in the specified time range
actions.backup-reserved-battery-capacity.label = Backup Power Reserved Battery Capacity
actions.backup-reserved-battery-capacity.description = Set the reserved battery capacity for backup power supply
actions.from.label = Begin Timestamp