[evcc] Adjust to evcc version 0.123.1 (#16114)

* updated url of setTargetEnergy and setTargetSoC to match evcc version 0.123.1
* removed minSoc from Loadpoint (since evcc 0.123.0 part of vehicle)
* renamed from targetEnergy to limitEnergy to match new evcc version
* renamed from targetSoC to limitSoC to match new evcc version
* plementation of vehicle object to match new evcc version 0.123.1 -> new implementation of minSoC and plans (served by new api)

Signed-off-by: Luca Arnecke <luca@arnecke.name>
Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
Signed-off-by: Michael Weger <weger.michael@gmx.net>
Co-authored-by: Florian Hotze <florianh_dev@icloud.com>
Co-authored-by: Michael Weger <weger.michael@gmx.net>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
lucaarn 2024-02-05 20:49:57 +01:00 committed by Ciprian Pascu
parent bd97a633f9
commit 1521e25ab9
10 changed files with 847 additions and 334 deletions

View File

@ -1,7 +1,7 @@
# evcc Binding # evcc Binding
This binding integrates [evcc - electric vehicle charging control](https://evcc.io), a project that provides a control center for electric vehicle charging. This binding integrates [evcc - electric vehicle charging control](https://evcc.io), a project that provides a control center for electric vehicle charging.
The binding requires evcc [version 0.117.0](https://github.com/evcc-io/evcc/releases/tag/0.117.0) or newer and is tested with this version. The binding requires evcc [version 0.123.1](https://github.com/evcc-io/evcc/releases/tag/0.123.1) or newer and is tested with this version.
You can easily install and upgrade evcc on openHABian using `sudo openhabian-config`. You can easily install and upgrade evcc on openHABian using `sudo openhabian-config`.
@ -38,50 +38,66 @@ Default value for _refreshInterval_ is 60 seconds.
Those channels exist only once. Those channels exist only once.
Please note that some of them are only available when evcc is properly configured. Please note that some of them are only available when evcc is properly configured.
| Channel | Type | Read/Write | Description | | Channel | Type | Read/Write | Description |
|----------------------------|----------------------|------------|--------------------------------------------------------------------------------------------------------------| |---------------------------------|----------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| general#batteryCapacity | Number:Energy | R | Capacity of (home) battery. | | general#batteryCapacity | Number:Energy | R | Capacity of (home) battery |
| general#batteryPower | Number:Power | R | Current power from battery. | | general#batteryPower | Number:Power | R | Current power from battery |
| general#batterySoC | Number:Dimensionless | R | Current State of Charge of battery. | | general#batterySoC | Number:Dimensionless | R | Current State of Charge of battery |
| general#batteryPrioritySoC | Number:Dimensionless | RW | State of State of Charge for which the battery has priority over charging the ev when charging mode is "pv". | | general#batteryDischargeControl | Switch | RW | Enable or disable battery discharge control |
| general#gridPower | Number:Power | R | Current power from grid (negative means feed-in) | | general#batteryMode | String | R | Current battery mode |
| general#homePower | Number:Power | R | Current power taken by home. | | general#prioritySoC | Number:Dimensionless | RW | State of State of Charge for which the battery has priority over charging the ev when charging mode is "pv" |
| general#pvPower | Number:Power | R | Current power from photovoltaik. | | general#bufferSoC | Number:Dimensionless | RW | Until this State of Charge the discharging of a house battery is allowed in "pv" mode, when there is insufficient solar surplus (below the minimum charging power) |
| general#bufferStartSoC | Number:Dimensionless | RW | State of Charge for which a charging session in "pv" mode is started, even if there is insufficient solar surplus |
| general#residualPower | Number:Power | RW | Target operating point of the surplus regulation at the grid connection (grid meter) |
| general#gridPower | Number:Power | R | Current power from grid (negative means feed-in) |
| general#homePower | Number:Power | R | Current power taken by home |
| general#pvPower | Number:Power | R | Current power from photovoltaik |
### Loadpoint channels ### Loadpoint channels
Those channels exist per configured loadpoint. Those channels exist per configured loadpoint.
Please note that you have to replace _N_ with your loadpoint number. Please note that you have to replace _N_ with your loadpoint number.
| Channel | Type | Read/Write | Description | | Channel | Type | Read/Write | Description |
|-------------------------------------|------------------------|------------|-----------------------------------------------------------------------------------------------------| |-------------------------------------|------------------------|------------|-------------------------------------------------------------------------------------------------------------------|
| loadpointN#activePhases | Number | R | Current number of active phases while charging | | loadpointN#activePhases | Number | R | Current number of active phases while charging |
| loadpointN#chargeCurrent | Number:ElectricCurrent | R | Current amperage per connected phase while charging | | loadpointN#chargeCurrent | Number:ElectricCurrent | R | Current amperage per connected phase while charging |
| loadpointN#chargeDuration | Number:Time | R | Charging duration | | loadpointN#chargeDuration | Number:Time | R | Charging duration |
| loadpointN#chargeRemainingDuration | Number:Time | R | Remaining duration until target SoC is reached | | loadpointN#chargeRemainingDuration | Number:Time | R | Remaining duration until limit SoC is reached |
| loadpointN#chargeRemainingEnergy | Number:Energy | R | Remaining energy until target SoC is reached | | loadpointN#chargeRemainingEnergy | Number:Energy | R | Remaining energy until limit SoC is reached |
| loadpointN#chargePower | Number:Power | R | Current power of charging | | loadpointN#chargePower | Number:Power | R | Current power of charging |
| loadpointN#chargedEnergy | Number:Energy | R | Energy charged since plugged-in | | loadpointN#chargedEnergy | Number:Energy | R | Energy charged since plugged-in |
| loadpointN#charging | Switch | R | Loadpoint is currently charging | | loadpointN#charging | Switch | R | Loadpoint is currently charging |
| loadpointN#enabled | Switch | R | Charging enabled (mode is not "off") | | loadpointN#enabled | Switch | R | Charging enabled (mode is not "off") |
| loadpointN#maxCurrent | Number:ElectricCurrent | RW | Maximum amperage per connected phase with which the car should be charged | | loadpointN#maxCurrent | Number:ElectricCurrent | RW | Maximum amperage per connected phase with which the car should be charged |
| loadpointN#minCurrent | Number:ElectricCurrent | RW | Minimum amperage per connected phase with which the car should be charged | | loadpointN#minCurrent | Number:ElectricCurrent | RW | Minimum amperage per connected phase with which the car should be charged |
| loadpointN#minSoC | Number:Dimensionless | RW | Charge immediately with maximum power up to the defined SoC, if the charge mode is not set to "off" | | loadpointN#mode | String | RW | Charging mode: "off", "now", "minpv", "pv" |
| loadpointN#mode | String | RW | Charging mode: "off", "now", "minpv", "pv" | | loadpointN#phases | Number | RW | The maximum number of phases which can be used |
| loadpointN#phases | Number | RW | The maximum number of phases which can be used | | loadpointN#limitEnergy | Number:Energy | RW | Amount of energy to charge the vehicle with |
| loadpointN#targetEnergy | Number:Energy | RW | Amount of energy to charge the vehicle with | | loadpointN#limitSoC | Number:Dimensionless | RW | Until which state of charge (SoC) should the vehicle be charged |
| loadpointN#targetSoC | Number:Dimensionless | RW | Until which state of charge (SoC) should the vehicle be charged | | loadpointN#title | String | R | Title of loadpoint |
| loadpointN#targetTime | DateTime | RW | When the target SoC should be reached | | loadpointN#vehicleConnected | Switch | R | Whether vehicle is connected to loadpoint |
| loadpointN#targetTimeEnabled | Switch | RW | Target time for charging enabled | | loadpointN#vehicleConnectedDuration | Number:Time | R | Duration the vehicle is connected to loadpoint |
| loadpointN#title | String | R | Title of loadpoint | | loadpointN#vehicleCapacity | Number:Energy | R | Capacity of EV battery |
| loadpointN#vehicleConnected | Switch | R | Whether vehicle is connected to loadpoint | | loadpointN#vehicleOdometer | Number:Length | R | Total distance travelled by EV |
| loadpointN#vehicleConnectedDuration | Number:Time | R | Duration the vehicle is connected to loadpoint | | loadpointN#vehiclePresent | Switch | R | Whether evcc is able to get data from vehicle |
| loadpointN#vehicleCapacity | Number:Energy | R | Capacity of EV battery | | loadpointN#vehicleRange | Number:Length | R | Battery range for EV |
| loadpointN#vehicleOdometer | Number:Length | R | Total distance travelled by EV | | loadpointN#vehicleSoC | Number:Dimensionless | R | Current State of Charge of EV |
| loadpointN#vehiclePresent | Switch | R | Whether evcc is able to get data from vehicle | | loadpointN#vehicleName | String | R | The unique identifier of the EV used in the evcc configuration (containing no whitespaces nor special characters) |
| loadpointN#vehicleRange | Number:Length | R | Battery range for EV |
| loadpointN#vehicleSoC | Number:Dimensionless | R | Current State of Charge of EV | ### Vehicle channels
| loadpointN#vehicleTitle | String | R | Name of EV |
Those channels exist per configured vehicle.
Please note that you have to replace _ID_ with your vehicle id/name.
| Channel | Type | Read/Write | Description |
|------------------------------|----------------------|------------|--------------------------------------------------------------------------|
| vehicleID#vehicleTitle | String | R | Title of vehicle |
| vehicleID#vehicleMinSoC | Number:Dimensionless | RW | Minimum state of charge (SoC) a vehicle should have |
| vehicleID#vehicleLimitSoC | Number:Dimensionless | RW | Until which state of charge (SoC) should the specific vehicle be charged |
| vehicleID#vehiclePlanEnabled | Switch | RW | Plan for charging enabled |
| vehicleID#vehiclePlanSoC | Number:Dimensionless | RW | Until which state of charge (SoC) should vehicle be charged in plan |
| vehicleID#vehiclePlanTime | DateTime | RW | When the plan SoC should be reached |
## Full Example ## Full Example
@ -95,43 +111,53 @@ Thing evcc:device:demo "evcc Demo" [url="https://demo.evcc.io", refreshInterval=
```java ```java
// General // General
Number:General evcc_batteryCapacity "Battery Capacity [%.0f kWH]" <energy> {channel="evcc:device:demo:general#batteryCapacity"} Number:Energy evcc_batteryCapacity "Battery Capacity [%.0f kWh]" <energy> {channel="evcc:device:demo:general#batteryCapacity"}
Number:Power evcc_batteryPower "Battery Power [%.1f kW]" <energy> {channel="evcc:device:demo:general#batteryPower"} Number:Power evcc_batteryPower "Battery Power [%.1f kW]" <energy> {channel="evcc:device:demo:general#batteryPower"}
Number:Dimensionless evcc_batterySoC "Battery SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:general#batterySoC"} Number:Dimensionless evcc_batterySoC "Battery SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:general#batterySoC"}
Number:Dimensionless evcc_batteryPrioritySoC "Battery Priority SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:general#batteryPrioritySoC"} Switch evcc_batteryDischargeControl "Battery Discharge Control [%s]" <switch> {channel="evcc:device:demo:general#batteryDischargeControl"}
Number:Power evcc_gridPower "Grid Power [%.1f kW]" <energy> {channel="evcc:device:demo:general#gridPower"} String evcc_batteryMode "Battery Mode [%s]" <battery> {channel="evcc:device:demo:general#batteryMode"}
Number:Power evcc_homePower "Home Power [%.1f kW]" <energy> {channel="evcc:device:demo:general#homePower"} Number:Dimensionless evcc_prioritySoC "Battery Priority SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:general#prioritySoC"}
Number:Power evcc_pvPower "PV Power [%.1f kW]" <energy> {channel="evcc:device:demo:general#pvPower"} Number:Dimensionless evcc_bufferSoC "Battery Buffer SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:general#bufferSoC"}
Number:Dimensionless evcc_bufferStartSoC "Battery Buffer Start SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:general#bufferStartSoC"}
Number:Power evcc_residualPower "Grid Residual Power [%.1f kW]" <energy> {channel="evcc:device:demo:general#residualPower"}
Number:Power evcc_gridPower "Grid Power [%.1f kW]" <energy> {channel="evcc:device:demo:general#gridPower"}
Number:Power evcc_homePower "Home Power [%.1f kW]" <energy> {channel="evcc:device:demo:general#homePower"}
Number:Power evcc_pvPower "PV Power [%.1f kW]" <energy> {channel="evcc:device:demo:general#pvPower"}
// Loadpoint // Loadpoint
Number evcc_loadpoint0_activePhases "Active Phases [%d]" {channel="evcc:device:demo:loadpoint0#activePhases"} Number evcc_loadpoint0_activePhases "Active Phases [%d]" {channel="evcc:device:demo:loadpoint0#activePhases"}
Number:ElectricCurrent evcc_loadpoint0_chargeCurrent "Charging current [%.0f A]" <energy> {channel="evcc:device:demo:loadpoint0#chargeCurrent"} Number:ElectricCurrent evcc_loadpoint0_chargeCurrent "Charging current [%.0f A]" <energy> {channel="evcc:device:demo:loadpoint0#chargeCurrent"}
Number:Time evcc_loadpoint0_chargeDuration "Charging duration [%1$tH:%1$tM]" <time> {channel="evcc:device:demo:loadpoint0#chargeDuration"} Number:Time evcc_loadpoint0_chargeDuration "Charging duration [%1$tH:%1$tM]" <time> {channel="evcc:device:demo:loadpoint0#chargeDuration"}
Number:Time evcc_loadpoint0_chargeRemainingDuration "Charging remaining duration [%1$tH:%1$tM]" <time> {channel="evcc:device:demo:loadpoint0#chargeRemainingDuration"} Number:Time evcc_loadpoint0_chargeRemainingDuration "Charging remaining duration [%1$tH:%1$tM]" <time> {channel="evcc:device:demo:loadpoint0#chargeRemainingDuration"}
Number:Energy evcc_loadpoint0_chargeRemainingEnergy "Charging remaining energy [%.1f kWh]" <energy> {channel="evcc:device:demo:loadpoint0#chargeRemainingEnergy"} Number:Energy evcc_loadpoint0_chargeRemainingEnergy "Charging remaining energy [%.1f kWh]" <energy> {channel="evcc:device:demo:loadpoint0#chargeRemainingEnergy"}
Number:Power evcc_loadpoint0_chargePower "Charging power [%.1f kW]" <energy> {channel="evcc:device:demo:loadpoint0#chargePower"} Number:Power evcc_loadpoint0_chargePower "Charging power [%.1f kW]" <energy> {channel="evcc:device:demo:loadpoint0#chargePower"}
Number:Energy evcc_loadpoint0_chargedEnergy "Charged energy [%.1f kWh]" <energy> {channel="evcc:device:demo:loadpoint0#chargedEnergy"} Number:Energy evcc_loadpoint0_chargedEnergy "Charged energy [%.1f kWh]" <energy> {channel="evcc:device:demo:loadpoint0#chargedEnergy"}
Switch evcc_loadpoint0_charging "Currently charging [%s]" <battery> {channel="evcc:device:demo:loadpoint0#charging"} Switch evcc_loadpoint0_charging "Currently charging [%s]" <battery> {channel="evcc:device:demo:loadpoint0#charging"}
Switch evcc_loadpoint0_enabled "Charging enabled [%s]" <switch> {channel="evcc:device:demo:loadpoint0#enabled"} Switch evcc_loadpoint0_enabled "Charging enabled [%s]" <switch> {channel="evcc:device:demo:loadpoint0#enabled"}
Number:ElectricCurrent evcc_loadpoint0_maxCurrent "Maximum current [%.0f A]" <energy> {channel="evcc:device:demo:loadpoint0#maxCurrent"} Number:ElectricCurrent evcc_loadpoint0_maxCurrent "Maximum current [%.0f A]" <energy> {channel="evcc:device:demo:loadpoint0#maxCurrent"}
Number:ElectricCurrent evcc_loadpoint0_minCurrent "Minimum current [%.0f A]" <energy> {channel="evcc:device:demo:loadpoint0#minCurrent"} Number:ElectricCurrent evcc_loadpoint0_minCurrent "Minimum current [%.0f A]" <energy> {channel="evcc:device:demo:loadpoint0#minCurrent"}
Number:Dimensionless evcc_loadpoint0_minSoC "Minimum SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:loadpoint0#minSoC"} String evcc_loadpoint0_mode "Mode [%s]" {channel="evcc:device:demo:loadpoint0#mode"}
String evcc_loadpoint0_mode "Mode [%s]" {channel="evcc:device:demo:loadpoint0#mode"} Number evcc_loadpoint0_phases "Enabled phases [%d]" {channel="evcc:device:demo:loadpoint0#phases"}
Number evcc_loadpoint0_phases "Enabled phases [%d]" {channel="evcc:device:demo:loadpoint0#phases"} Number:Energy evcc_loadpoint0_limitEnergy "Limit energy [%.1f kWh]" <batterylevel> {channel="evcc:device:demo:loadpoint0#limitEnergy"}
Number:Energy evcc_loadpoint0_targetEnergy "Target energy [%.1f kWh]" <batterylevel> {channel="evcc:device:demo:loadpoint0#targetEnergy"} Number:Dimensionless evcc_loadpoint0_limitSoC "Limit SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:loadpoint0#limitSoC"}
Number:Dimensionless evcc_loadpoint0_targetSoC "Target SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:loadpoint0#targetSoC"} String evcc_loadpoint0_title "Loadpoint title [%s]" <text> {channel="evcc:device:demo:loadpoint0#title"}
DateTime evcc_loadpoint0_targetTime "Target time [%1$td.%1$tm.%1$tY, %1$tH:%1$tM]" <time> {channel="evcc:device:demo:loadpoint0#targetTime"}
Switch evcc_loadpoint0_targetTimeEnabled "Target time enabled [%s]" <switch> {channel="evcc:device:demo:loadpoint0#targetTimeEnabled"}
String evcc_loadpoint0_title "Loadpoint title [%s]" <text> {channel="evcc:device:demo:loadpoint0#title"}
// Vehicle on loadpoint // Vehicle on loadpoint
Switch evcc_loadpoint0_vehicleConnected "Vehicle connected [%s]" <switch> {channel="evcc:device:demo:loadpoint0#vehicleConnected"} Switch evcc_loadpoint0_vehicleConnected "Vehicle connected [%s]" <switch> {channel="evcc:device:demo:loadpoint0#vehicleConnected"}
Number:Time evcc_loadpoint0_vehicleConnectedDuration "Vehicle connected duration [%.1f h]" <time> {channel="evcc:device:demo:loadpoint0#vehicleConnectedDuration"} Number:Time evcc_loadpoint0_vehicleConnectedDuration "Vehicle connected duration [%.1f h]" <time> {channel="evcc:device:demo:loadpoint0#vehicleConnectedDuration"}
Number:Energy evcc_loadpoint0_vehicleCapacity "Vehicle capacity [%.0f kWH]" <batterylevel> {channel="evcc:device:demo:loadpoint0#vehicleCapacity"} Number:Energy evcc_loadpoint0_vehicleCapacity "Vehicle capacity [%.0f kWh]" <batterylevel> {channel="evcc:device:demo:loadpoint0#vehicleCapacity"}
Number:Length evcc_loadpoint0_vehicleOdometer "Vehicle odometer [%.1f km]" {channel="evcc:device:demo:loadpoint0#vehicleOdometer"} Number:Length evcc_loadpoint0_vehicleOdometer "Vehicle odometer [%.1f km]" {channel="evcc:device:demo:loadpoint0#vehicleOdometer"}
Switch evcc_loadpoint0_vehiclePresent "Vehicle present [%s]" <switch> {channel="evcc:device:demo:loadpoint0#vehiclePresent"} Switch evcc_loadpoint0_vehiclePresent "Vehicle present [%s]" <switch> {channel="evcc:device:demo:loadpoint0#vehiclePresent"}
Number:Length evcc_loadpoint0_vehicleRange "Vehicle Range [%.0f km]" {channel="evcc:device:demo:loadpoint0#vehicleRange"} Number:Length evcc_loadpoint0_vehicleRange "Vehicle Range [%.0f km]" {channel="evcc:device:demo:loadpoint0#vehicleRange"}
Number:Dimensionless evcc_loadpoint0_vehicleSoC "Vehicle SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:loadpoint0#vehicleSoC"} Number:Dimensionless evcc_loadpoint0_vehicleSoC "Vehicle SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:loadpoint0#vehicleSoC"}
String evcc_loadpoint0_vehicleName "Vehicle name [%s]" <text> {channel="evcc:device:demo:loadpoint0#vehicleTitle"} String evcc_loadpoint0_VehicleName "Vehicle name [%s]" <text> {channel="evcc:device:demo:loadpoint0#vehicleName"}
// Vehicle
String evcc_vehicle0_vehicleTitle "Vehicle title [%s]" <text> {channel="evcc:device:demo:vehicle0#vehicleTitle"}
Number:Dimensionless evcc_vehicle0_vehicleMinSoC "Vehicle minimum SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:vehicle0#vehicleMinSoC"}
Number:Dimensionless evcc_vehicle0_vehicleLimitSoC "Vehicle limit SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:vehicle0#vehicleLimitSoC"}
Switch evcc_vehicle0_vehiclePlanEnabled "Vehicle plan enabled [%s]" <switch> {channel="evcc:device:demo:vehicle0#vehiclePlanEnabled"}
Number:Dimensionless evcc_vehicle0_vehiclePlanSoC "Vehicle plan SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:vehicle0#vehiclePlanSoC"}
DateTime evcc_vehicle0_vehiclePlanTime "Vehicle plan time [%1$td.%1$tm.%1$tY, %1$tH:%1$tM]" <time> {channel="evcc:device:demo:loadpoint0#targetTime"}
``` ```
### Sitemap ### Sitemap
@ -158,8 +184,8 @@ sitemap evcc label="evcc Demo" {
} }
Switch item=evcc_loadpoint0_mode mappings=["off"="Stop","now"="Now","minpv"="Min + PV", "pv"="Only PV"] Switch item=evcc_loadpoint0_mode mappings=["off"="Stop","now"="Now","minpv"="Min + PV", "pv"="Only PV"]
Text label="Charging settings" icon="settings" { Text label="Charging settings" icon="settings" {
Setpoint item=evcc_loadpoint0_targetEnergy minValue=5 maxValue=100 step=5 Setpoint item=evcc_loadpoint0_limitEnergy minValue=5 maxValue=100 step=5
Setpoint item=evcc_loadpoint0_targetSoC minValue=5 maxValue=100 step=5 Setpoint item=evcc_loadpoint0_limitSoC minValue=5 maxValue=100 step=5
Setpoint item=evcc_loadpoint0_minCurrent minValue=6 maxValue=96 step=2 Setpoint item=evcc_loadpoint0_minCurrent minValue=6 maxValue=96 step=2
Setpoint item=evcc_loadpoint0_maxCurrent minValue=6 maxValue=96 step=2 Setpoint item=evcc_loadpoint0_maxCurrent minValue=6 maxValue=96 step=2
Setpoint item=evcc_loadpoint0_minSoC minValue=0 maxValue=100 step=5 Setpoint item=evcc_loadpoint0_minSoC minValue=0 maxValue=100 step=5
@ -170,6 +196,12 @@ sitemap evcc label="evcc Demo" {
Text item=evcc_loadpoint0_vehicleOdometer Text item=evcc_loadpoint0_vehicleOdometer
Text item=evcc_loadpoint0_vehicleRange Text item=evcc_loadpoint0_vehicleRange
Text item=evcc_loadpoint0_vehicleSoC Text item=evcc_loadpoint0_vehicleSoC
Text item=evcc_vehicle0_vehicleTitle
Setpoint item=evcc_vehicle0_vehicleMinSoC minValue=0 maxValue=100 step=5
Setpoint item=evcc_vehicle0_vehicleLimitSoC minValue=5 maxValue=100 step=5
Switch item=evcc_vehicle0_vehiclePlanEnabled
Setpoint item=evcc_vehicle0_vehiclePlanSoC minValue=5 maxValue=100 step=5
Input item=evcc_vehicle0_vehiclePlanTime
} }
} }
} }

View File

@ -21,6 +21,7 @@ import org.openhab.core.thing.type.ChannelTypeUID;
* used across the whole binding. * used across the whole binding.
* *
* @author Florian Hotze - Initial contribution * @author Florian Hotze - Initial contribution
* @author Luca Arnecke - Update to evcc version 0.123.1
*/ */
@NonNullByDefault @NonNullByDefault
public class EvccBindingConstants { public class EvccBindingConstants {
@ -28,12 +29,19 @@ public class EvccBindingConstants {
private static final String BINDING_ID = "evcc"; private static final String BINDING_ID = "evcc";
public static final String CHANNEL_GROUP_ID_GENERAL = "general"; public static final String CHANNEL_GROUP_ID_GENERAL = "general";
public static final String CHANNEL_GROUP_ID_LOADPOINT = "loadpoint";
public static final String CHANNEL_GROUP_ID_VEHICLE = "vehicle";
// List of all Channel ids // List of all Channel ids
public static final String CHANNEL_BATTERY_CAPACITY = "batteryCapacity"; public static final String CHANNEL_BATTERY_CAPACITY = "batteryCapacity";
public static final String CHANNEL_BATTERY_POWER = "batteryPower"; public static final String CHANNEL_BATTERY_POWER = "batteryPower";
public static final String CHANNEL_BATTERY_SOC = "batterySoC"; public static final String CHANNEL_BATTERY_SOC = "batterySoC";
public static final String CHANNEL_BATTERY_PRIORITY_SOC = "batteryPrioritySoC"; public static final String CHANNEL_BATTERY_DISCHARGE_CONTROL = "batteryDischargeControl";
public static final String CHANNEL_BATTERY_MODE = "batteryMode";
public static final String CHANNEL_PRIORITY_SOC = "prioritySoC";
public static final String CHANNEL_BUFFER_SOC = "bufferSoC";
public static final String CHANNEL_BUFFER_START_SOC = "bufferStartSoC";
public static final String CHANNEL_RESIDUAL_POWER = "residualPower";
public static final String CHANNEL_GRID_POWER = "gridPower"; public static final String CHANNEL_GRID_POWER = "gridPower";
public static final String CHANNEL_HOME_POWER = "homePower"; public static final String CHANNEL_HOME_POWER = "homePower";
public static final String CHANNEL_PV_POWER = "pvPower"; public static final String CHANNEL_PV_POWER = "pvPower";
@ -47,27 +55,26 @@ public class EvccBindingConstants {
public static final String CHANNEL_LOADPOINT_CHARGING = "charging"; public static final String CHANNEL_LOADPOINT_CHARGING = "charging";
public static final String CHANNEL_LOADPOINT_CONNECTED = "vehicleConnected"; public static final String CHANNEL_LOADPOINT_CONNECTED = "vehicleConnected";
public static final String CHANNEL_LOADPOINT_CONNECTED_DURATION = "vehicleConnectedDuration"; public static final String CHANNEL_LOADPOINT_CONNECTED_DURATION = "vehicleConnectedDuration";
public static final String CHANNEL_LOADPOINT_HAS_VEHICLE = "hasVehicle";
public static final String CHANNEL_LOADPOINT_ENABLED = "enabled"; public static final String CHANNEL_LOADPOINT_ENABLED = "enabled";
public static final String CHANNEL_LOADPOINT_MAX_CURRENT = "maxCurrent"; public static final String CHANNEL_LOADPOINT_MAX_CURRENT = "maxCurrent";
public static final String CHANNEL_LOADPOINT_MIN_CURRENT = "minCurrent"; public static final String CHANNEL_LOADPOINT_MIN_CURRENT = "minCurrent";
public static final String CHANNEL_LOADPOINT_MIN_SOC = "minSoC";
public static final String CHANNEL_LOADPOINT_MODE = "mode"; public static final String CHANNEL_LOADPOINT_MODE = "mode";
public static final String CHANNEL_LOADPOINT_PHASES = "phases"; public static final String CHANNEL_LOADPOINT_PHASES = "phases";
public static final String CHANNEL_LOADPOINT_TARGET_ENERGY = "targetEnergy"; public static final String CHANNEL_LOADPOINT_LIMIT_ENERGY = "limitEnergy";
public static final String CHANNEL_LOADPOINT_TARGET_SOC = "targetSoC"; public static final String CHANNEL_LOADPOINT_LIMIT_SOC = "limitSoC";
public static final String CHANNEL_LOADPOINT_TARGET_TIME = "targetTime";
/**
* Whether a target time is set on loadpoint.
*/
public static final String CHANNEL_LOADPOINT_TARGET_TIME_ENABLED = "targetTimeEnabled";
public static final String CHANNEL_LOADPOINT_TITLE = "title"; public static final String CHANNEL_LOADPOINT_TITLE = "title";
public static final String CHANNEL_LOADPOINT_VEHICLE_CAPACITY = "vehicleCapacity"; public static final String CHANNEL_LOADPOINT_VEHICLE_CAPACITY = "vehicleCapacity";
public static final String CHANNEL_LOADPOINT_VEHICLE_ODOMETER = "vehicleOdometer"; public static final String CHANNEL_LOADPOINT_VEHICLE_ODOMETER = "vehicleOdometer";
public static final String CHANNEL_LOADPOINT_VEHICLE_PRESENT = "vehiclePresent"; public static final String CHANNEL_LOADPOINT_VEHICLE_PRESENT = "vehiclePresent";
public static final String CHANNEL_LOADPOINT_VEHICLE_RANGE = "vehicleRange"; public static final String CHANNEL_LOADPOINT_VEHICLE_RANGE = "vehicleRange";
public static final String CHANNEL_LOADPOINT_VEHICLE_SOC = "vehicleSoC"; public static final String CHANNEL_LOADPOINT_VEHICLE_SOC = "vehicleSoC";
public static final String CHANNEL_LOADPOINT_VEHICLE_TITLE = "vehicleTitle"; public static final String CHANNEL_LOADPOINT_VEHICLE_NAME = "vehicleName";
public static final String CHANNEL_VEHICLE_TITLE = "vehicleTitle";
public static final String CHANNEL_VEHICLE_MIN_SOC = "vehicleMinSoC";
public static final String CHANNEL_VEHICLE_LIMIT_SOC = "vehicleLimitSoC";
public static final String CHANNEL_VEHICLE_PLAN_ENABLED = "vehiclePlanEnabled";
public static final String CHANNEL_VEHICLE_PLAN_SOC = "vehiclePlanSoC";
public static final String CHANNEL_VEHICLE_PLAN_TIME = "vehiclePlanTime";
// List of all Thing Type UIDs // List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_DEVICE = new ThingTypeUID(BINDING_ID, "device"); public static final ThingTypeUID THING_TYPE_DEVICE = new ThingTypeUID(BINDING_ID, "device");
@ -79,8 +86,17 @@ public class EvccBindingConstants {
CHANNEL_BATTERY_POWER); CHANNEL_BATTERY_POWER);
public static final ChannelTypeUID CHANNEL_TYPE_UID_BATTERY_SOC = new ChannelTypeUID(BINDING_ID, public static final ChannelTypeUID CHANNEL_TYPE_UID_BATTERY_SOC = new ChannelTypeUID(BINDING_ID,
CHANNEL_BATTERY_SOC); CHANNEL_BATTERY_SOC);
public static final ChannelTypeUID CHANNEL_TYPE_UID_BATTERY_PRIORITY_SOC = new ChannelTypeUID(BINDING_ID, public static final ChannelTypeUID CHANNEL_TYPE_UID_BATTERY_DISCHARGE_CONTROL = new ChannelTypeUID(BINDING_ID,
CHANNEL_BATTERY_PRIORITY_SOC); CHANNEL_BATTERY_DISCHARGE_CONTROL);
public static final ChannelTypeUID CHANNEL_TYPE_UID_BATTERY_MODE = new ChannelTypeUID(BINDING_ID,
CHANNEL_BATTERY_MODE);
public static final ChannelTypeUID CHANNEL_TYPE_UID_PRIORITY_SOC = new ChannelTypeUID(BINDING_ID,
CHANNEL_PRIORITY_SOC);
public static final ChannelTypeUID CHANNEL_TYPE_UID_BUFFER_SOC = new ChannelTypeUID(BINDING_ID, CHANNEL_BUFFER_SOC);
public static final ChannelTypeUID CHANNEL_TYPE_UID_BUFFER_START_SOC = new ChannelTypeUID(BINDING_ID,
CHANNEL_BUFFER_START_SOC);
public static final ChannelTypeUID CHANNEL_TYPE_UID_RESIDUAL_POWER = new ChannelTypeUID(BINDING_ID,
CHANNEL_RESIDUAL_POWER);
public static final ChannelTypeUID CHANNEL_TYPE_UID_GRID_POWER = new ChannelTypeUID(BINDING_ID, CHANNEL_GRID_POWER); public static final ChannelTypeUID CHANNEL_TYPE_UID_GRID_POWER = new ChannelTypeUID(BINDING_ID, CHANNEL_GRID_POWER);
public static final ChannelTypeUID CHANNEL_TYPE_UID_HOME_POWER = new ChannelTypeUID(BINDING_ID, CHANNEL_HOME_POWER); public static final ChannelTypeUID CHANNEL_TYPE_UID_HOME_POWER = new ChannelTypeUID(BINDING_ID, CHANNEL_HOME_POWER);
public static final ChannelTypeUID CHANNEL_TYPE_UID_PV_POWER = new ChannelTypeUID(BINDING_ID, CHANNEL_PV_POWER); public static final ChannelTypeUID CHANNEL_TYPE_UID_PV_POWER = new ChannelTypeUID(BINDING_ID, CHANNEL_PV_POWER);
@ -110,20 +126,14 @@ public class EvccBindingConstants {
CHANNEL_LOADPOINT_MAX_CURRENT); CHANNEL_LOADPOINT_MAX_CURRENT);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_MIN_CURRENT = new ChannelTypeUID(BINDING_ID, public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_MIN_CURRENT = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_MIN_CURRENT); CHANNEL_LOADPOINT_MIN_CURRENT);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_MIN_SOC = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_MIN_SOC);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_MODE = new ChannelTypeUID(BINDING_ID, public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_MODE = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_MODE); CHANNEL_LOADPOINT_MODE);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_PHASES = new ChannelTypeUID(BINDING_ID, public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_PHASES = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_PHASES); CHANNEL_LOADPOINT_PHASES);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_TARGET_ENERGY = new ChannelTypeUID(BINDING_ID, public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_LIMIT_ENERGY = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_TARGET_ENERGY); CHANNEL_LOADPOINT_LIMIT_ENERGY);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_TARGET_SOC = new ChannelTypeUID(BINDING_ID, public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_LIMIT_SOC = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_TARGET_SOC); CHANNEL_LOADPOINT_LIMIT_SOC);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_TARGET_TIME = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_TARGET_TIME);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_TARGET_TIME_ENABLED = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_TARGET_TIME_ENABLED);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_TITLE = new ChannelTypeUID(BINDING_ID, public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_TITLE = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_TITLE); CHANNEL_LOADPOINT_TITLE);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_CAPACITY = new ChannelTypeUID(BINDING_ID, public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_CAPACITY = new ChannelTypeUID(BINDING_ID,
@ -136,8 +146,20 @@ public class EvccBindingConstants {
CHANNEL_LOADPOINT_VEHICLE_RANGE); CHANNEL_LOADPOINT_VEHICLE_RANGE);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_SOC = new ChannelTypeUID(BINDING_ID, public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_SOC = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_VEHICLE_SOC); CHANNEL_LOADPOINT_VEHICLE_SOC);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_TITLE = new ChannelTypeUID(BINDING_ID, public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_NAME = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_VEHICLE_TITLE); CHANNEL_LOADPOINT_VEHICLE_NAME);
public static final ChannelTypeUID CHANNEL_TYPE_UID_VEHICLE_TITLE = new ChannelTypeUID(BINDING_ID,
CHANNEL_VEHICLE_TITLE);
public static final ChannelTypeUID CHANNEL_TYPE_UID_VEHICLE_MIN_SOC = new ChannelTypeUID(BINDING_ID,
CHANNEL_VEHICLE_MIN_SOC);
public static final ChannelTypeUID CHANNEL_TYPE_UID_VEHICLE_LIMIT_SOC = new ChannelTypeUID(BINDING_ID,
CHANNEL_VEHICLE_LIMIT_SOC);
public static final ChannelTypeUID CHANNEL_TYPE_UID_VEHICLE_PLAN_ENABLED = new ChannelTypeUID(BINDING_ID,
CHANNEL_VEHICLE_PLAN_ENABLED);
public static final ChannelTypeUID CHANNEL_TYPE_UID_VEHICLE_PLAN_SOC = new ChannelTypeUID(BINDING_ID,
CHANNEL_VEHICLE_PLAN_SOC);
public static final ChannelTypeUID CHANNEL_TYPE_UID_VEHICLE_PLAN_TIME = new ChannelTypeUID(BINDING_ID,
CHANNEL_VEHICLE_PLAN_TIME);
public static final int CONNECTION_TIMEOUT_MILLISEC = 5000; public static final int CONNECTION_TIMEOUT_MILLISEC = 5000;
public static final int LONG_CONNECTION_TIMEOUT_MILLISEC = 60000; public static final int LONG_CONNECTION_TIMEOUT_MILLISEC = 60000;

View File

@ -16,6 +16,8 @@ import static org.openhab.binding.evcc.internal.EvccBindingConstants.*;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException; import java.time.format.DateTimeParseException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -24,7 +26,9 @@ import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.evcc.internal.api.EvccAPI; import org.openhab.binding.evcc.internal.api.EvccAPI;
import org.openhab.binding.evcc.internal.api.EvccApiException; import org.openhab.binding.evcc.internal.api.EvccApiException;
import org.openhab.binding.evcc.internal.api.dto.Loadpoint; import org.openhab.binding.evcc.internal.api.dto.Loadpoint;
import org.openhab.binding.evcc.internal.api.dto.Plan;
import org.openhab.binding.evcc.internal.api.dto.Result; import org.openhab.binding.evcc.internal.api.dto.Result;
import org.openhab.binding.evcc.internal.api.dto.Vehicle;
import org.openhab.core.library.CoreItemFactory; import org.openhab.core.library.CoreItemFactory;
import org.openhab.core.library.types.DateTimeType; import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.DecimalType;
@ -52,6 +56,7 @@ import org.slf4j.LoggerFactory;
* sent to one of the channels. * sent to one of the channels.
* *
* @author Florian Hotze - Initial contribution * @author Florian Hotze - Initial contribution
* @author Luca Arnecke - Update to evcc version 0.123.1
*/ */
@NonNullByDefault @NonNullByDefault
public class EvccHandler extends BaseThingHandler { public class EvccHandler extends BaseThingHandler {
@ -64,9 +69,7 @@ public class EvccHandler extends BaseThingHandler {
private boolean batteryConfigured = false; private boolean batteryConfigured = false;
private boolean gridConfigured = false; private boolean gridConfigured = false;
private boolean pvConfigured = false; private boolean pvConfigured = false;
Map<String, Triple<Boolean, Float, ZonedDateTime>> vehiclePlans = new HashMap<>();
private boolean targetTimeEnabled = false;
private ZonedDateTime targetTimeZDT = ZonedDateTime.now().plusHours(12);
public EvccHandler(Thing thing) { public EvccHandler(Thing thing) {
super(thing); super(thing);
@ -82,25 +85,64 @@ public class EvccHandler extends BaseThingHandler {
if (groupId == null) { if (groupId == null) {
return; return;
} }
String channelGroupId = channelUID.getGroupId();
String channelIdWithoutGroup = channelUID.getIdWithoutGroup(); String channelIdWithoutGroup = channelUID.getIdWithoutGroup();
EvccAPI evccAPI = this.evccAPI; EvccAPI evccAPI = this.evccAPI;
if (evccAPI == null) { if (evccAPI == null) {
return; return;
} }
try { try {
if (channelGroupId.equals(CHANNEL_GROUP_ID_GENERAL)) { if (groupId.equals(CHANNEL_GROUP_ID_GENERAL)) {
if (!channelIdWithoutGroup.equals(CHANNEL_BATTERY_PRIORITY_SOC)) { switch (channelIdWithoutGroup) {
return; case CHANNEL_PRIORITY_SOC -> {
if (command instanceof QuantityType<?> qt) {
evccAPI.setPrioritySoC(qt.toUnit(Units.PERCENT).intValue());
} else if (command instanceof DecimalType dt) {
evccAPI.setPrioritySoC(dt.intValue());
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
}
case CHANNEL_BUFFER_SOC -> {
if (command instanceof QuantityType<?> qt) {
evccAPI.setBufferSoC(qt.toUnit(Units.PERCENT).intValue());
} else if (command instanceof DecimalType dt) {
evccAPI.setBufferSoC(dt.intValue());
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
}
case CHANNEL_BUFFER_START_SOC -> {
if (command instanceof QuantityType<?> qt) {
evccAPI.setBufferStartSoC(qt.toUnit(Units.PERCENT).intValue());
} else if (command instanceof DecimalType dt) {
evccAPI.setBufferStartSoC(dt.intValue());
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
}
case CHANNEL_RESIDUAL_POWER -> {
if (command instanceof QuantityType<?> qt) {
evccAPI.setResidualPower(qt.toUnit(Units.WATT).intValue());
} else if (command instanceof DecimalType dt) {
evccAPI.setResidualPower(dt.intValue());
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
}
case CHANNEL_BATTERY_DISCHARGE_CONTROL -> {
if (command == OnOffType.ON) {
evccAPI.setBatteryDischargeControl(true);
} else if (command == OnOffType.OFF) {
evccAPI.setBatteryDischargeControl(false);
} else {
logger.debug("Command has wrong type, OnOffType required!");
}
}
default -> {
return;
}
} }
if (command instanceof QuantityType<?> qt) { } else if (groupId.startsWith(CHANNEL_GROUP_ID_LOADPOINT)) {
evccAPI.setBatteryPrioritySoC(qt.toUnit(Units.PERCENT).intValue());
} else if (command instanceof DecimalType dt) {
evccAPI.setBatteryPrioritySoC(dt.intValue());
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
} else {
int loadpoint = Integer.parseInt(groupId.substring(9)) + 1; int loadpoint = Integer.parseInt(groupId.substring(9)) + 1;
switch (channelIdWithoutGroup) { switch (channelIdWithoutGroup) {
case CHANNEL_LOADPOINT_MODE -> { case CHANNEL_LOADPOINT_MODE -> {
@ -110,59 +152,25 @@ public class EvccHandler extends BaseThingHandler {
logger.debug("Command has wrong type, StringType required!"); logger.debug("Command has wrong type, StringType required!");
} }
} }
case CHANNEL_LOADPOINT_MIN_SOC -> { case CHANNEL_LOADPOINT_LIMIT_ENERGY -> {
if (command instanceof QuantityType<?> qt) { if (command instanceof QuantityType<?> qt) {
evccAPI.setMinSoC(loadpoint, qt.toUnit(Units.PERCENT).intValue()); evccAPI.setLimitEnergy(loadpoint, qt.toUnit(Units.WATT_HOUR).floatValue());
} else if (command instanceof DecimalType dt) { } else if (command instanceof DecimalType dt) {
evccAPI.setMinSoC(loadpoint, dt.intValue()); // DecimalType commands are interpreted as 'kWh'
} else { evccAPI.setLimitEnergy(loadpoint, dt.intValue() * 1000);
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
}
case CHANNEL_LOADPOINT_TARGET_ENERGY -> {
if (command instanceof QuantityType<?> qt) {
evccAPI.setTargetEnergy(loadpoint, qt.toUnit(Units.WATT_HOUR).floatValue());
} else { } else {
logger.debug("Command has wrong type, QuantityType required!"); logger.debug("Command has wrong type, QuantityType required!");
} }
} }
case CHANNEL_LOADPOINT_TARGET_SOC -> { case CHANNEL_LOADPOINT_LIMIT_SOC -> {
if (command instanceof QuantityType<?> qt) { if (command instanceof QuantityType<?> qt) {
evccAPI.setTargetSoC(loadpoint, qt.toUnit(Units.PERCENT).intValue()); evccAPI.setLimitSoC(loadpoint, qt.toUnit(Units.PERCENT).intValue());
} else if (command instanceof DecimalType dt) { } else if (command instanceof DecimalType dt) {
evccAPI.setTargetSoC(loadpoint, dt.intValue()); evccAPI.setLimitSoC(loadpoint, dt.intValue());
} else { } else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!"); logger.debug("Command has wrong type, QuantityType or DecimalType required!");
} }
} }
case CHANNEL_LOADPOINT_TARGET_TIME -> {
if (command instanceof DateTimeType dtt) {
targetTimeZDT = dtt.getZonedDateTime();
ChannelUID channel = new ChannelUID(getThing().getUID(), "loadpoint" + loadpoint,
CHANNEL_LOADPOINT_TARGET_TIME);
updateState(channel, new DateTimeType(targetTimeZDT));
if (targetTimeEnabled) {
try {
evccAPI.setTargetTime(loadpoint, targetTimeZDT);
} catch (DateTimeParseException e) {
logger.debug("Failed to set target charge: ", e);
}
}
} else {
logger.debug("Command has wrong type, DateTimeType required!");
}
}
case CHANNEL_LOADPOINT_TARGET_TIME_ENABLED -> {
if (command == OnOffType.ON) {
evccAPI.setTargetTime(loadpoint, targetTimeZDT);
targetTimeEnabled = true;
} else if (command == OnOffType.OFF) {
evccAPI.removeTargetTime(loadpoint);
targetTimeEnabled = false;
} else {
logger.debug("Command has wrong type, OnOffType required!");
}
}
case CHANNEL_LOADPOINT_PHASES -> { case CHANNEL_LOADPOINT_PHASES -> {
if (command instanceof DecimalType dt) { if (command instanceof DecimalType dt) {
evccAPI.setPhases(loadpoint, dt.intValue()); evccAPI.setPhases(loadpoint, dt.intValue());
@ -192,6 +200,82 @@ public class EvccHandler extends BaseThingHandler {
return; return;
} }
} }
} else if (groupId.startsWith(CHANNEL_GROUP_ID_VEHICLE)) {
String vehicleName = groupId.substring(7);
switch (channelIdWithoutGroup) {
case CHANNEL_VEHICLE_MIN_SOC -> {
if (command instanceof QuantityType<?> qt) {
evccAPI.setVehicleMinSoC(vehicleName, qt.toUnit(Units.PERCENT).intValue());
} else if (command instanceof DecimalType dt) {
evccAPI.setVehicleMinSoC(vehicleName, dt.intValue());
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
}
case CHANNEL_VEHICLE_LIMIT_SOC -> {
if (command instanceof QuantityType<?> qt) {
evccAPI.setVehicleLimitSoC(vehicleName, qt.toUnit(Units.PERCENT).intValue());
} else if (command instanceof DecimalType dt) {
evccAPI.setVehicleLimitSoC(vehicleName, dt.intValue());
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
}
case CHANNEL_VEHICLE_PLAN_ENABLED -> {
Triple<Boolean, Float, ZonedDateTime> planValues = vehiclePlans.get(vehicleName);
if (command == OnOffType.ON) {
evccAPI.setVehiclePlan(vehicleName, planValues.getMiddle().intValue(),
planValues.getRight());
vehiclePlans.put(vehicleName,
new Triple<>(true, planValues.getMiddle(), planValues.getRight()));
} else if (command == OnOffType.OFF) {
evccAPI.removeVehiclePlan(vehicleName);
vehiclePlans.put(vehicleName,
new Triple<>(false, planValues.getMiddle(), planValues.getRight()));
} else {
logger.debug("Command has wrong type, OnOffType required!");
}
}
case CHANNEL_VEHICLE_PLAN_SOC -> {
Triple<Boolean, Float, ZonedDateTime> planValues = vehiclePlans.get(vehicleName);
if (command instanceof QuantityType<?> qt) {
vehiclePlans.put(vehicleName, new Triple<>(planValues.getLeft(),
qt.toUnit(Units.PERCENT).floatValue(), planValues.getRight()));
if (planValues.getLeft()) {
evccAPI.setVehiclePlan(vehicleName, qt.toUnit(Units.PERCENT).intValue(),
planValues.getRight());
}
} else if (command instanceof DecimalType dt) {
vehiclePlans.put(vehicleName,
new Triple<>(planValues.getLeft(), dt.floatValue(), planValues.getRight()));
if (planValues.getLeft()) {
evccAPI.setVehiclePlan(vehicleName, dt.intValue(), planValues.getRight());
}
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
}
case CHANNEL_VEHICLE_PLAN_TIME -> {
Triple<Boolean, Float, ZonedDateTime> planValues = vehiclePlans.get(vehicleName);
if (command instanceof DateTimeType dtt) {
vehiclePlans.put(vehicleName, new Triple<>(planValues.getLeft(), planValues.getMiddle(),
dtt.getZonedDateTime()));
if (planValues.getLeft()) {
try {
evccAPI.setVehiclePlan(vehicleName, planValues.getMiddle().intValue(),
dtt.getZonedDateTime());
} catch (DateTimeParseException e) {
logger.debug("Failed to set vehicle plan time: ", e);
}
}
} else {
logger.debug("Command has wrong type, DateTimeType required!");
}
}
default -> {
return;
}
}
} }
} catch (EvccApiException e) { } catch (EvccApiException e) {
Throwable cause = e.getCause(); Throwable cause = e.getCause();
@ -248,6 +332,8 @@ public class EvccHandler extends BaseThingHandler {
String sitename = result.getSiteTitle(); String sitename = result.getSiteTitle();
int numberOfLoadpoints = result.getLoadpoints().length; int numberOfLoadpoints = result.getLoadpoints().length;
logger.debug("Found {} loadpoints on site {}.", numberOfLoadpoints, sitename); logger.debug("Found {} loadpoints on site {}.", numberOfLoadpoints, sitename);
Map<String, Vehicle> vehicles = result.getVehicles();
logger.debug("Found {} vehicles on site {}.", vehicles.size(), sitename);
updateStatus(ThingStatus.ONLINE); updateStatus(ThingStatus.ONLINE);
batteryConfigured = result.getBatteryConfigured(); batteryConfigured = result.getBatteryConfigured();
gridConfigured = result.getGridConfigured(); gridConfigured = result.getGridConfigured();
@ -258,6 +344,10 @@ public class EvccHandler extends BaseThingHandler {
createChannelsLoadpoint(i); createChannelsLoadpoint(i);
updateChannelsLoadpoint(i); updateChannelsLoadpoint(i);
} }
for (String vehicleName : vehicles.keySet()) {
createChannelsVehicle(vehicleName);
updateChannelsVehicle(vehicleName);
}
} }
} }
@ -279,8 +369,17 @@ public class EvccHandler extends BaseThingHandler {
"Number:Power"); "Number:Power");
createChannel(CHANNEL_BATTERY_SOC, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_BATTERY_SOC, createChannel(CHANNEL_BATTERY_SOC, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_BATTERY_SOC,
"Number:Dimensionless"); "Number:Dimensionless");
createChannel(CHANNEL_BATTERY_PRIORITY_SOC, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_BATTERY_PRIORITY_SOC, createChannel(CHANNEL_BATTERY_DISCHARGE_CONTROL, CHANNEL_GROUP_ID_GENERAL,
CHANNEL_TYPE_UID_BATTERY_DISCHARGE_CONTROL, "Switch");
createChannel(CHANNEL_BATTERY_MODE, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_BATTERY_MODE, "String");
createChannel(CHANNEL_PRIORITY_SOC, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_PRIORITY_SOC,
"Number:Dimensionless"); "Number:Dimensionless");
createChannel(CHANNEL_BUFFER_SOC, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_BUFFER_SOC,
"Number:Dimensionless");
createChannel(CHANNEL_BUFFER_START_SOC, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_BUFFER_START_SOC,
"Number:Dimensionless");
createChannel(CHANNEL_RESIDUAL_POWER, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_RESIDUAL_POWER,
"Number:Power");
} }
if (gridConfigured) { if (gridConfigured) {
createChannel(CHANNEL_GRID_POWER, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_GRID_POWER, "Number:Power"); createChannel(CHANNEL_GRID_POWER, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_GRID_POWER, "Number:Power");
@ -289,10 +388,11 @@ public class EvccHandler extends BaseThingHandler {
if (pvConfigured) { if (pvConfigured) {
createChannel(CHANNEL_PV_POWER, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_PV_POWER, "Number:Power"); createChannel(CHANNEL_PV_POWER, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_PV_POWER, "Number:Power");
} }
removeChannel("batteryPrioritySoC", CHANNEL_GROUP_ID_GENERAL);
} }
private void createChannelsLoadpoint(int loadpointId) { private void createChannelsLoadpoint(int loadpointId) {
final String channelGroup = "loadpoint" + loadpointId; final String channelGroup = CHANNEL_GROUP_ID_LOADPOINT + loadpointId;
createChannel(CHANNEL_LOADPOINT_ACTIVE_PHASES, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_ACTIVE_PHASES, createChannel(CHANNEL_LOADPOINT_ACTIVE_PHASES, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_ACTIVE_PHASES,
CoreItemFactory.NUMBER); CoreItemFactory.NUMBER);
createChannel(CHANNEL_LOADPOINT_CHARGE_CURRENT, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_CHARGE_CURRENT, createChannel(CHANNEL_LOADPOINT_CHARGE_CURRENT, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_CHARGE_CURRENT,
@ -319,19 +419,13 @@ public class EvccHandler extends BaseThingHandler {
"Number:ElectricCurrent"); "Number:ElectricCurrent");
createChannel(CHANNEL_LOADPOINT_MIN_CURRENT, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_MIN_CURRENT, createChannel(CHANNEL_LOADPOINT_MIN_CURRENT, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_MIN_CURRENT,
"Number:ElectricCurrent"); "Number:ElectricCurrent");
createChannel(CHANNEL_LOADPOINT_MIN_SOC, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_MIN_SOC,
"Number:Dimensionless");
createChannel(CHANNEL_LOADPOINT_MODE, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_MODE, CoreItemFactory.STRING); createChannel(CHANNEL_LOADPOINT_MODE, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_MODE, CoreItemFactory.STRING);
createChannel(CHANNEL_LOADPOINT_PHASES, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_PHASES, createChannel(CHANNEL_LOADPOINT_PHASES, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_PHASES,
CoreItemFactory.NUMBER); CoreItemFactory.NUMBER);
createChannel(CHANNEL_LOADPOINT_TARGET_ENERGY, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_TARGET_ENERGY, createChannel(CHANNEL_LOADPOINT_LIMIT_ENERGY, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_LIMIT_ENERGY,
"Number:Energy"); "Number:Energy");
createChannel(CHANNEL_LOADPOINT_TARGET_SOC, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_TARGET_SOC, createChannel(CHANNEL_LOADPOINT_LIMIT_SOC, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_LIMIT_SOC,
"Number:Dimensionless"); "Number:Dimensionless");
createChannel(CHANNEL_LOADPOINT_TARGET_TIME, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_TARGET_TIME,
CoreItemFactory.DATETIME);
createChannel(CHANNEL_LOADPOINT_TARGET_TIME_ENABLED, channelGroup,
CHANNEL_TYPE_UID_LOADPOINT_TARGET_TIME_ENABLED, CoreItemFactory.SWITCH);
createChannel(CHANNEL_LOADPOINT_TITLE, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_TITLE, CoreItemFactory.STRING); createChannel(CHANNEL_LOADPOINT_TITLE, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_TITLE, CoreItemFactory.STRING);
createChannel(CHANNEL_LOADPOINT_VEHICLE_CAPACITY, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_CAPACITY, createChannel(CHANNEL_LOADPOINT_VEHICLE_CAPACITY, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_CAPACITY,
"Number:Energy"); "Number:Energy");
@ -343,10 +437,33 @@ public class EvccHandler extends BaseThingHandler {
"Number:Length"); "Number:Length");
createChannel(CHANNEL_LOADPOINT_VEHICLE_SOC, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_SOC, createChannel(CHANNEL_LOADPOINT_VEHICLE_SOC, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_SOC,
"Number:Dimensionless"); "Number:Dimensionless");
createChannel(CHANNEL_LOADPOINT_VEHICLE_TITLE, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_TITLE, createChannel(CHANNEL_LOADPOINT_VEHICLE_NAME, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_NAME,
CoreItemFactory.STRING); CoreItemFactory.STRING);
removeChannel(CHANNEL_LOADPOINT_HAS_VEHICLE, channelGroup); removeChannel("hasVehicle", channelGroup);
removeChannel("minSoC", channelGroup);
removeChannel("targetEnergy", channelGroup);
removeChannel("targetSoC", channelGroup);
removeChannel("targetTime", channelGroup);
removeChannel("targetTimeEnabled", channelGroup);
}
private void createChannelsVehicle(String vehicleName) {
final String channelGroup = CHANNEL_GROUP_ID_VEHICLE + vehicleName;
createChannel(CHANNEL_VEHICLE_TITLE, channelGroup, CHANNEL_TYPE_UID_VEHICLE_TITLE, CoreItemFactory.STRING);
createChannel(CHANNEL_VEHICLE_MIN_SOC, channelGroup, CHANNEL_TYPE_UID_VEHICLE_MIN_SOC, "Number:Dimensionless");
createChannel(CHANNEL_VEHICLE_LIMIT_SOC, channelGroup, CHANNEL_TYPE_UID_VEHICLE_LIMIT_SOC,
"Number:Dimensionless");
createChannel(CHANNEL_VEHICLE_PLAN_SOC, channelGroup, CHANNEL_TYPE_UID_VEHICLE_PLAN_SOC,
"Number:Dimensionless");
createChannel(CHANNEL_VEHICLE_PLAN_TIME, channelGroup, CHANNEL_TYPE_UID_VEHICLE_PLAN_TIME,
CoreItemFactory.DATETIME);
createChannel(CHANNEL_VEHICLE_PLAN_ENABLED, channelGroup, CHANNEL_TYPE_UID_VEHICLE_PLAN_ENABLED,
CoreItemFactory.SWITCH);
createChannel(CHANNEL_VEHICLE_PLAN_SOC, channelGroup, CHANNEL_TYPE_UID_VEHICLE_PLAN_SOC,
"Number:Dimensionless");
createChannel(CHANNEL_VEHICLE_PLAN_TIME, channelGroup, CHANNEL_TYPE_UID_VEHICLE_PLAN_TIME,
CoreItemFactory.DATETIME);
} }
// Units and description for vars: https://docs.evcc.io/docs/reference/configuration/messaging/#msg // Units and description for vars: https://docs.evcc.io/docs/reference/configuration/messaging/#msg
@ -371,9 +488,29 @@ public class EvccHandler extends BaseThingHandler {
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_BATTERY_SOC); channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_BATTERY_SOC);
updateState(channel, new QuantityType<>(batterySoC, Units.PERCENT)); updateState(channel, new QuantityType<>(batterySoC, Units.PERCENT));
float batteryPrioritySoC = result.getBatteryPrioritySoC(); boolean batteryDischargeControl = result.getBatteryDischargeControl();
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_BATTERY_PRIORITY_SOC); channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_BATTERY_DISCHARGE_CONTROL);
updateState(channel, new QuantityType<>(batteryPrioritySoC, Units.PERCENT)); updateState(channel, OnOffType.from(batteryDischargeControl));
String batteryMode = result.getBatteryMode();
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_BATTERY_MODE);
updateState(channel, new StringType(batteryMode));
float prioritySoC = result.getPrioritySoC();
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_PRIORITY_SOC);
updateState(channel, new QuantityType<>(prioritySoC, Units.PERCENT));
float bufferSoC = result.getBufferSoC();
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_BUFFER_SOC);
updateState(channel, new QuantityType<>(bufferSoC, Units.PERCENT));
float bufferStartSoC = result.getBufferStartSoC();
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_BUFFER_START_SOC);
updateState(channel, new QuantityType<>(bufferStartSoC, Units.PERCENT));
float residualPower = result.getResidualPower();
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_RESIDUAL_POWER);
updateState(channel, new QuantityType<>(residualPower, Units.WATT));
} }
boolean gridConfigured = this.gridConfigured; boolean gridConfigured = this.gridConfigured;
if (gridConfigured) { if (gridConfigured) {
@ -398,123 +535,147 @@ public class EvccHandler extends BaseThingHandler {
return; return;
} }
final ThingUID uid = getThing().getUID(); final ThingUID uid = getThing().getUID();
final String loadpointName = "loadpoint" + loadpointId; final String channelGroup = CHANNEL_GROUP_ID_LOADPOINT + loadpointId;
ChannelUID channel; ChannelUID channel;
Loadpoint loadpoint = result.getLoadpoints()[loadpointId]; Loadpoint loadpoint = result.getLoadpoints()[loadpointId];
int activePhases = loadpoint.getActivePhases(); int activePhases = loadpoint.getActivePhases();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_ACTIVE_PHASES); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_ACTIVE_PHASES);
updateState(channel, new DecimalType(activePhases)); updateState(channel, new DecimalType(activePhases));
float chargeCurrent = loadpoint.getChargeCurrent(); float chargeCurrent = loadpoint.getChargeCurrent();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_CHARGE_CURRENT); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_CHARGE_CURRENT);
updateState(channel, new QuantityType<>(chargeCurrent, Units.AMPERE)); updateState(channel, new QuantityType<>(chargeCurrent, Units.AMPERE));
long chargeDuration = loadpoint.getChargeDuration(); long chargeDuration = loadpoint.getChargeDuration();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_CHARGE_DURATION); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_CHARGE_DURATION);
updateState(channel, new QuantityType<>(chargeDuration, MetricPrefix.NANO(Units.SECOND))); updateState(channel, new QuantityType<>(chargeDuration, MetricPrefix.NANO(Units.SECOND)));
float chargePower = loadpoint.getChargePower(); float chargePower = loadpoint.getChargePower();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_CHARGE_POWER); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_CHARGE_POWER);
updateState(channel, new QuantityType<>(chargePower, Units.WATT)); updateState(channel, new QuantityType<>(chargePower, Units.WATT));
long chargeRemainingDuration = loadpoint.getChargeRemainingDuration(); long chargeRemainingDuration = loadpoint.getChargeRemainingDuration();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_CHARGE_REMAINING_DURATION); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_CHARGE_REMAINING_DURATION);
updateState(channel, new QuantityType<>(chargeRemainingDuration, MetricPrefix.NANO(Units.SECOND))); updateState(channel, new QuantityType<>(chargeRemainingDuration, MetricPrefix.NANO(Units.SECOND)));
float chargeRemainingEnergy = loadpoint.getChargeRemainingEnergy(); float chargeRemainingEnergy = loadpoint.getChargeRemainingEnergy();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_CHARGE_REMAINING_ENERGY); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_CHARGE_REMAINING_ENERGY);
updateState(channel, new QuantityType<>(chargeRemainingEnergy, Units.WATT_HOUR)); updateState(channel, new QuantityType<>(chargeRemainingEnergy, Units.WATT_HOUR));
float chargedEnergy = loadpoint.getChargedEnergy(); float chargedEnergy = loadpoint.getChargedEnergy();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_CHARGED_ENERGY); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_CHARGED_ENERGY);
updateState(channel, new QuantityType<>(chargedEnergy, Units.WATT_HOUR)); updateState(channel, new QuantityType<>(chargedEnergy, Units.WATT_HOUR));
boolean charging = loadpoint.getCharging(); boolean charging = loadpoint.getCharging();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_CHARGING); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_CHARGING);
updateState(channel, OnOffType.from(charging)); updateState(channel, OnOffType.from(charging));
boolean connected = loadpoint.getConnected(); boolean connected = loadpoint.getConnected();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_CONNECTED); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_CONNECTED);
updateState(channel, OnOffType.from(connected)); updateState(channel, OnOffType.from(connected));
long connectedDuration = loadpoint.getConnectedDuration(); long connectedDuration = loadpoint.getConnectedDuration();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_CONNECTED_DURATION); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_CONNECTED_DURATION);
updateState(channel, new QuantityType<>(connectedDuration, MetricPrefix.NANO(Units.SECOND))); updateState(channel, new QuantityType<>(connectedDuration, MetricPrefix.NANO(Units.SECOND)));
boolean enabled = loadpoint.getEnabled(); boolean enabled = loadpoint.getEnabled();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_ENABLED); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_ENABLED);
updateState(channel, OnOffType.from(enabled)); updateState(channel, OnOffType.from(enabled));
float maxCurrent = loadpoint.getMaxCurrent(); float maxCurrent = loadpoint.getMaxCurrent();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_MAX_CURRENT); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_MAX_CURRENT);
updateState(channel, new QuantityType<>(maxCurrent, Units.AMPERE)); updateState(channel, new QuantityType<>(maxCurrent, Units.AMPERE));
float minCurrent = loadpoint.getMinCurrent(); float minCurrent = loadpoint.getMinCurrent();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_MIN_CURRENT); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_MIN_CURRENT);
updateState(channel, new QuantityType<>(minCurrent, Units.AMPERE)); updateState(channel, new QuantityType<>(minCurrent, Units.AMPERE));
float minSoC = loadpoint.getMinSoC();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_MIN_SOC);
updateState(channel, new QuantityType<>(minSoC, Units.PERCENT));
String mode = loadpoint.getMode(); String mode = loadpoint.getMode();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_MODE); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_MODE);
updateState(channel, new StringType(mode)); updateState(channel, new StringType(mode));
int phases = loadpoint.getPhases(); int phases = loadpoint.getPhases();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_PHASES); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_PHASES);
updateState(channel, new DecimalType(phases)); updateState(channel, new DecimalType(phases));
float targetEnergy = loadpoint.getTargetEnergy(); float limitEnergy = loadpoint.getLimitEnergy();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_TARGET_ENERGY); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_LIMIT_ENERGY);
updateState(channel, new QuantityType<>(targetEnergy, Units.WATT_HOUR)); updateState(channel, new QuantityType<>(limitEnergy, Units.WATT_HOUR));
float targetSoC = loadpoint.getTargetSoC(); float limitSoC = loadpoint.getLimitSoC();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_TARGET_SOC); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_LIMIT_SOC);
updateState(channel, new QuantityType<>(targetSoC, Units.PERCENT)); updateState(channel, new QuantityType<>(limitSoC, Units.PERCENT));
String targetTime = loadpoint.getTargetTime();
if (targetTime == null || "0001-01-01T00:00:00Z".equals(targetTime)) {
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_TARGET_TIME_ENABLED);
updateState(channel, OnOffType.OFF);
targetTimeEnabled = false;
} else {
this.targetTimeZDT = ZonedDateTime.parse(targetTime);
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_TARGET_TIME);
updateState(channel, new DateTimeType(targetTimeZDT));
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_TARGET_TIME_ENABLED);
updateState(channel, OnOffType.ON);
targetTimeEnabled = true;
}
String title = loadpoint.getTitle(); String title = loadpoint.getTitle();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_TITLE); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_TITLE);
updateState(channel, new StringType(title)); updateState(channel, new StringType(title));
float vehicleCapacity = loadpoint.getVehicleCapacity(); float vehicleCapacity = loadpoint.getVehicleCapacity();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_VEHICLE_CAPACITY); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_VEHICLE_CAPACITY);
updateState(channel, new QuantityType<>(vehicleCapacity, Units.KILOWATT_HOUR)); updateState(channel, new QuantityType<>(vehicleCapacity, Units.KILOWATT_HOUR));
float vehicleOdometer = loadpoint.getVehicleOdometer(); float vehicleOdometer = loadpoint.getVehicleOdometer();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_VEHICLE_ODOMETER); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_VEHICLE_ODOMETER);
updateState(channel, new QuantityType<>(vehicleOdometer, MetricPrefix.KILO(SIUnits.METRE))); updateState(channel, new QuantityType<>(vehicleOdometer, MetricPrefix.KILO(SIUnits.METRE)));
boolean vehiclePresent = loadpoint.getVehiclePresent(); boolean vehiclePresent = loadpoint.getVehiclePresent();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_VEHICLE_PRESENT); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_VEHICLE_PRESENT);
updateState(channel, OnOffType.from(vehiclePresent)); updateState(channel, OnOffType.from(vehiclePresent));
float vehicleRange = loadpoint.getVehicleRange(); float vehicleRange = loadpoint.getVehicleRange();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_VEHICLE_RANGE); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_VEHICLE_RANGE);
updateState(channel, new QuantityType<>(vehicleRange, MetricPrefix.KILO(SIUnits.METRE))); updateState(channel, new QuantityType<>(vehicleRange, MetricPrefix.KILO(SIUnits.METRE)));
float vehicleSoC = loadpoint.getVehicleSoC(); float vehicleSoC = loadpoint.getVehicleSoC();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_VEHICLE_SOC); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_VEHICLE_SOC);
updateState(channel, new QuantityType<>(vehicleSoC, Units.PERCENT)); updateState(channel, new QuantityType<>(vehicleSoC, Units.PERCENT));
String vehicleTitle = loadpoint.getVehicleTitle(); String vehicleName = loadpoint.getVehicleName();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_VEHICLE_TITLE); channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_VEHICLE_NAME);
updateState(channel, new StringType(vehicleTitle)); updateState(channel, new StringType(vehicleName));
}
private void updateChannelsVehicle(String vehicleName) {
final Result result = this.result;
if (result == null) {
return;
}
final ThingUID uid = getThing().getUID();
final String channelGroup = CHANNEL_GROUP_ID_VEHICLE + vehicleName;
ChannelUID channel;
Vehicle vehicle = result.getVehicles().get(vehicleName);
String title = vehicle.getTitle();
channel = new ChannelUID(uid, channelGroup, CHANNEL_VEHICLE_TITLE);
updateState(channel, new StringType(title));
float minSoC = vehicle.getMinSoC();
channel = new ChannelUID(uid, channelGroup, CHANNEL_VEHICLE_MIN_SOC);
updateState(channel, new QuantityType<>(minSoC, Units.PERCENT));
float limitSoC = vehicle.getLimitSoC();
channel = new ChannelUID(uid, channelGroup, CHANNEL_VEHICLE_LIMIT_SOC);
updateState(channel, new QuantityType<>(limitSoC, Units.PERCENT));
Plan plan = vehicle.getPlan();
if (plan == null && vehiclePlans.get(vehicleName) == null) {
vehiclePlans.put(vehicleName, new Triple<>(false, 100f, ZonedDateTime.now().plusHours(12)));
} else if (plan != null) {
vehiclePlans.put(vehicleName, new Triple<>(true, plan.getSoC(), ZonedDateTime.parse(plan.getTime())));
}
updateVehiclePlanChannel(vehicleName, uid, channelGroup);
}
private void updateVehiclePlanChannel(String vehicleName, ThingUID uid, String channelGroup) {
Triple<Boolean, Float, ZonedDateTime> planValues = vehiclePlans.get(vehicleName);
ChannelUID channel = new ChannelUID(uid, channelGroup, CHANNEL_VEHICLE_PLAN_ENABLED);
updateState(channel, planValues.getLeft() ? OnOffType.ON : OnOffType.OFF);
channel = new ChannelUID(uid, channelGroup, CHANNEL_VEHICLE_PLAN_SOC);
updateState(channel, new QuantityType<>(planValues.getMiddle(), Units.PERCENT));
channel = new ChannelUID(uid, channelGroup, CHANNEL_VEHICLE_PLAN_TIME);
updateState(channel, new DateTimeType(planValues.getRight()));
} }
private void createChannel(String channel, String channelGroupId, ChannelTypeUID channelTypeUID, String itemType) { private void createChannel(String channel, String channelGroupId, ChannelTypeUID channelTypeUID, String itemType) {
@ -531,4 +692,28 @@ public class EvccHandler extends BaseThingHandler {
updateThing(editThing().withoutChannel(channelUid).build()); updateThing(editThing().withoutChannel(channelUid).build());
} }
} }
private class Triple<L, M, R> {
private final L left;
private final M middle;
private final R right;
private Triple(L left, M middle, R right) {
this.left = left;
this.middle = middle;
this.right = right;
}
private L getLeft() {
return left;
}
private M getMiddle() {
return middle;
}
private R getRight() {
return right;
}
}
} }

View File

@ -31,9 +31,10 @@ import com.google.gson.JsonSyntaxException;
/** /**
* The {@link EvccAPI} is responsible for API calls to evcc. * The {@link EvccAPI} is responsible for API calls to evcc.
* API requests were written for evcc version 0.117.0 * API requests were written for evcc version 0.123.1
* *
* @author Florian Hotze - Initial contribution * @author Florian Hotze - Initial contribution
* @author Luca Arnecke - Update to evcc version 0.123.1
*/ */
@NonNullByDefault @NonNullByDefault
public class EvccAPI { public class EvccAPI {
@ -86,26 +87,38 @@ public class EvccAPI {
} }
// Site API calls. // Site API calls.
public String setBatteryPrioritySoC(int prioritySoc) throws EvccApiException { public String setPrioritySoC(int prioritySoc) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "prioritysoc/" + prioritySoc, "POST"); return httpRequest(this.host + EVCC_REST_API + "prioritysoc/" + prioritySoc, "POST");
} }
public String setBufferSoC(int bufferSoC) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "buffersoc/" + bufferSoC, "POST");
}
public String setBufferStartSoC(int bufferStartSoC) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "bufferstartsoc/" + bufferStartSoC, "POST");
}
public String setResidualPower(int residualPower) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "residualpower/" + residualPower, "POST");
}
public String setBatteryDischargeControl(boolean batteryDischargeControl) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "batterydischargecontrol/" + batteryDischargeControl, "POST");
}
// Loadpoint specific API calls. // Loadpoint specific API calls.
public String setMode(int loadpoint, String mode) throws EvccApiException { public String setMode(int loadpoint, String mode) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/mode/" + mode, "POST"); return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/mode/" + mode, "POST");
} }
public String setMinSoC(int loadpoint, int minSoC) throws EvccApiException { public String setLimitEnergy(int loadpoint, float limitEnergy) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/minsoc/" + minSoC, "POST"); return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/limitenergy/" + limitEnergy,
}
public String setTargetEnergy(int loadpoint, float targetEnergy) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/target/energy/" + targetEnergy,
"POST"); "POST");
} }
public String setTargetSoC(int loadpoint, int targetSoC) throws EvccApiException { public String setLimitSoC(int loadpoint, int limitSoC) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/target/soc/" + targetSoC, "POST"); return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/limitsoc/" + limitSoC, "POST");
} }
public String setPhases(int loadpoint, int phases) throws EvccApiException { public String setPhases(int loadpoint, int phases) throws EvccApiException {
@ -120,12 +133,21 @@ public class EvccAPI {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/maxcurrent/" + maxCurrent, "POST"); return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/maxcurrent/" + maxCurrent, "POST");
} }
public String setTargetTime(int loadpoint, ZonedDateTime targetTime) throws EvccApiException { // Vehicle specific API calls.
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/target/time/" public String setVehicleMinSoC(String vehicleName, int minSoC) throws EvccApiException {
+ targetTime.toLocalDateTime().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + "Z", "POST"); return httpRequest(this.host + EVCC_REST_API + "vehicles/" + vehicleName + "/minsoc/" + minSoC, "POST");
} }
public String removeTargetTime(int loadpoint) throws EvccApiException { public String setVehicleLimitSoC(String vehicleName, int limitSoC) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/target/time", "DELETE"); return httpRequest(this.host + EVCC_REST_API + "vehicles/" + vehicleName + "/limitsoc/" + limitSoC, "POST");
}
public String setVehiclePlan(String vehicleName, int planSoC, ZonedDateTime planTime) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "vehicles/" + vehicleName + "/plan/soc/" + planSoC + "/"
+ planTime.toLocalDateTime().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + "Z", "POST");
}
public String removeVehiclePlan(String vehicleName) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "vehicles/" + vehicleName + "/plan/soc", "DELETE");
} }
} }

View File

@ -16,9 +16,10 @@ import com.google.gson.annotations.SerializedName;
/** /**
* This class represents a loadpoint object of the status response (/api/state). * This class represents a loadpoint object of the status response (/api/state).
* This DTO was written for evcc version 0.117.0 * This DTO was written for evcc version 0.123.1
* *
* @author Florian Hotze - Initial contribution * @author Florian Hotze - Initial contribution
* @author Luca Arnecke - Update to evcc version 0.123.1
*/ */
public class Loadpoint { public class Loadpoint {
// Data types from https://github.com/evcc-io/evcc/blob/master/api/api.go // Data types from https://github.com/evcc-io/evcc/blob/master/api/api.go
@ -63,23 +64,17 @@ public class Loadpoint {
@SerializedName("minCurrent") @SerializedName("minCurrent")
private float minCurrent; private float minCurrent;
@SerializedName("minSoc")
private float minSoC;
@SerializedName("mode") @SerializedName("mode")
private String mode; private String mode;
@SerializedName("phasesEnabled") @SerializedName("phasesEnabled")
private int phases; private int phases;
@SerializedName("planActive") @SerializedName("limitEnergy")
private boolean planActive; private float limitEnergy;
@SerializedName("targetEnergy") @SerializedName("limitSoc")
private float targetEnergy; private float limitSoC;
@SerializedName("targetSoc")
private float targetSoC;
@SerializedName("targetTime") @SerializedName("targetTime")
private String targetTime; private String targetTime;
@ -102,8 +97,8 @@ public class Loadpoint {
@SerializedName("vehicleSoc") @SerializedName("vehicleSoc")
private float vehicleSoC; private float vehicleSoC;
@SerializedName("vehicleTitle") @SerializedName("vehicleName")
private String vehicleTitle; private String vehicleName;
/** /**
* @return number of active phases * @return number of active phases
@ -196,13 +191,6 @@ public class Loadpoint {
return minCurrent; return minCurrent;
} }
/**
* @return minimum state of charge
*/
public float getMinSoC() {
return minSoC;
}
/** /**
* @return charging mode: off, now, minpv, pv * @return charging mode: off, now, minpv, pv
*/ */
@ -218,24 +206,17 @@ public class Loadpoint {
} }
/** /**
* @return whether charging plan is active * @return limit energy
*/ */
public boolean getPlanActive() { public float getLimitEnergy() {
return planActive; return limitEnergy;
} }
/** /**
* @return target energy * @return limit state of charge (SoC)
*/ */
public float getTargetEnergy() { public float getLimitSoC() {
return targetEnergy; return limitSoC;
}
/**
* @return target state of charge (SoC)
*/
public float getTargetSoC() {
return targetSoC;
} }
/** /**
@ -290,7 +271,7 @@ public class Loadpoint {
/** /**
* @return vehicle's title/name * @return vehicle's title/name
*/ */
public String getVehicleTitle() { public String getVehicleName() {
return vehicleTitle; return vehicleName;
} }
} }

View File

@ -0,0 +1,46 @@
/**
* Copyright (c) 2010-2024 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.evcc.internal.api.dto;
import com.google.gson.annotations.SerializedName;
/**
* This class represents a plan object of the status response (/api/state).
* This DTO was written for evcc version 0.123.1
*
* @author Luca Arnecke - Initial contribution
*/
public class Plan {
// Data types from https://github.com/evcc-io/evcc/blob/master/api/api.go
// and from https://docs.evcc.io/docs/reference/configuration/messaging/#msg
@SerializedName("soc")
private float soc;
@SerializedName("time")
private String time;
/**
* @return state of charge
*/
public float getSoC() {
return soc;
}
/**
* @return time
*/
public String getTime() {
return time;
}
}

View File

@ -12,13 +12,16 @@
*/ */
package org.openhab.binding.evcc.internal.api.dto; package org.openhab.binding.evcc.internal.api.dto;
import java.util.Map;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
/** /**
* This class represents the result object of the status response (/api/state). * This class represents the result object of the status response (/api/state).
* This DTO was written for evcc version 0.117.0 * This DTO was written for evcc version 0.123.1
* *
* @author Florian Hotze - Initial contribution * @author Florian Hotze - Initial contribution
* @author Luca Arnecke - update to evcc version 0.123.1
*/ */
public class Result { public class Result {
// Data types from https://github.com/evcc-io/evcc/blob/master/api/api.go // Data types from https://github.com/evcc-io/evcc/blob/master/api/api.go
@ -38,6 +41,12 @@ public class Result {
@SerializedName("batterySoc") @SerializedName("batterySoc")
private float batterySoC; private float batterySoC;
@SerializedName("batteryDischargeControl")
private boolean batteryDischargeControl;
@SerializedName("batteryMode")
private String batteryMode;
@SerializedName("gridConfigured") @SerializedName("gridConfigured")
private boolean gridConfigured; private boolean gridConfigured;
@ -51,7 +60,16 @@ public class Result {
private Loadpoint[] loadpoints; private Loadpoint[] loadpoints;
@SerializedName("prioritySoc") @SerializedName("prioritySoc")
private float batteryPrioritySoC; private float prioritySoC;
@SerializedName("bufferSoc")
private float bufferSoC;
@SerializedName("bufferStartSoc")
private float bufferStartSoC;
@SerializedName("residualPower")
private float residualPower;
@SerializedName("pvConfigured") @SerializedName("pvConfigured")
private boolean pvConfigured; private boolean pvConfigured;
@ -62,6 +80,9 @@ public class Result {
@SerializedName("siteTitle") @SerializedName("siteTitle")
private String siteTitle; private String siteTitle;
@SerializedName("vehicles")
private Map<String, Vehicle> vehicles;
/** /**
* @return battery's capacity * @return battery's capacity
*/ */
@ -86,8 +107,29 @@ public class Result {
/** /**
* @return battery's priority state of charge * @return battery's priority state of charge
*/ */
public float getBatteryPrioritySoC() { public float getPrioritySoC() {
return batteryPrioritySoC; return prioritySoC;
}
/**
* @return Battery Buffer SoC
*/
public float getBufferSoC() {
return bufferSoC;
}
/**
* @return Battery Buffer Start SoC
*/
public float getBufferStartSoC() {
return bufferStartSoC;
}
/**
* @return Grid Residual Power
*/
public float getResidualPower() {
return residualPower;
} }
/** /**
@ -97,6 +139,20 @@ public class Result {
return batterySoC; return batterySoC;
} }
/**
* @return battery discharge control
*/
public boolean getBatteryDischargeControl() {
return batteryDischargeControl;
}
/**
* @return battery mode
*/
public String getBatteryMode() {
return batteryMode;
}
/** /**
* @return whether grid is configured * @return whether grid is configured
*/ */
@ -145,4 +201,8 @@ public class Result {
public String getSiteTitle() { public String getSiteTitle() {
return siteTitle; return siteTitle;
} }
public Map<String, Vehicle> getVehicles() {
return vehicles;
}
} }

View File

@ -0,0 +1,70 @@
/**
* Copyright (c) 2010-2024 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.evcc.internal.api.dto;
import com.google.gson.annotations.SerializedName;
/**
* This class represents a vehicle object of the status response (/api/state).
* This DTO was written for evcc version 0.123.1
*
* @author Luca Arnecke - Initial contribution
*/
public class Vehicle {
// Data types from https://github.com/evcc-io/evcc/blob/master/api/api.go
// and from https://docs.evcc.io/docs/reference/configuration/messaging/#msg
@SerializedName("title")
private String title;
@SerializedName("minSoc")
private float minSoC;
@SerializedName("limitSoc")
private float limitSoC;
@SerializedName("plans")
private Plan[] plans;
/**
* @return vehicle name
*/
public String getTitle() {
return title;
}
/**
* @return minimum state of charge
*/
public float getMinSoC() {
return minSoC;
}
/**
* @return limit state of charge
*/
public float getLimitSoC() {
return limitSoC;
}
/**
* @return current plan for vehicle
*/
public Plan getPlan() {
if (plans != null) {
return plans[0];
} else {
return null;
}
}
}

View File

@ -26,12 +26,20 @@ channel-type.evcc.activePhases.label = Charging Active Phases
channel-type.evcc.activePhases.description = Current number of active phases while charging channel-type.evcc.activePhases.description = Current number of active phases while charging
channel-type.evcc.batteryCapacity.label = Battery Capacity channel-type.evcc.batteryCapacity.label = Battery Capacity
channel-type.evcc.batteryCapacity.description = Capacity of (home) battery channel-type.evcc.batteryCapacity.description = Capacity of (home) battery
channel-type.evcc.batteryDischargeControl.label = Battery Discharge Control
channel-type.evcc.batteryDischargeControl.description = Enable or disable battery discharge control
channel-type.evcc.batteryDischargeControl.state.option.ON = Enabled
channel-type.evcc.batteryDischargeControl.state.option.OFF = Disabled
channel-type.evcc.batteryMode.label = Battery Mode
channel-type.evcc.batteryMode.description = Current Battery Mode
channel-type.evcc.batteryPower.label = Battery Power channel-type.evcc.batteryPower.label = Battery Power
channel-type.evcc.batteryPower.description = Current power from battery channel-type.evcc.batteryPower.description = Current power from battery
channel-type.evcc.batteryPrioritySoC.label = Battery Priority SoC
channel-type.evcc.batteryPrioritySoC.description = State of Charge for which the battery has priority over charging the ev when charging mode is "pv".
channel-type.evcc.batterySoC.label = Battery SoC channel-type.evcc.batterySoC.label = Battery SoC
channel-type.evcc.batterySoC.description = Current State of Charge of battery channel-type.evcc.batterySoC.description = Current State of Charge of battery
channel-type.evcc.bufferSoC.label = Battery Buffer SoC
channel-type.evcc.bufferSoC.description = Until this State of Charge the discharging of a house battery is allowed in "pv" mode, when there is insufficient solar surplus (below the minimum charging power)
channel-type.evcc.bufferStartSoC.label = Battery Buffer Start SoC
channel-type.evcc.bufferStartSoC.description = State of Charge for which a charging session in "pv" mode is started, even if there is insufficient solar surplus
channel-type.evcc.chargeCurrent.label = Charging Current channel-type.evcc.chargeCurrent.label = Charging Current
channel-type.evcc.chargeCurrent.description = Current amperage per connected phase while charging channel-type.evcc.chargeCurrent.description = Current amperage per connected phase while charging
channel-type.evcc.chargeDuration.label = Charging Duration channel-type.evcc.chargeDuration.label = Charging Duration
@ -39,9 +47,9 @@ channel-type.evcc.chargeDuration.description = Charging duration
channel-type.evcc.chargePower.label = Charging Power channel-type.evcc.chargePower.label = Charging Power
channel-type.evcc.chargePower.description = Current power of charging channel-type.evcc.chargePower.description = Current power of charging
channel-type.evcc.chargeRemainingDuration.label = Charging Remaining Duration channel-type.evcc.chargeRemainingDuration.label = Charging Remaining Duration
channel-type.evcc.chargeRemainingDuration.description = Remaining duration until target SoC is reached channel-type.evcc.chargeRemainingDuration.description = Remaining duration until limit SoC is reached
channel-type.evcc.chargeRemainingEnergy.label = Charging Remaining Energy channel-type.evcc.chargeRemainingEnergy.label = Charging Remaining Energy
channel-type.evcc.chargeRemainingEnergy.description = Remaining energy until target SoC is reached channel-type.evcc.chargeRemainingEnergy.description = Remaining energy until limit SoC is reached
channel-type.evcc.chargedEnergy.label = Charged Energy channel-type.evcc.chargedEnergy.label = Charged Energy
channel-type.evcc.chargedEnergy.description = Energy charged since plugged-in channel-type.evcc.chargedEnergy.description = Energy charged since plugged-in
channel-type.evcc.charging.label = Charging State channel-type.evcc.charging.label = Charging State
@ -56,12 +64,14 @@ channel-type.evcc.gridPower.label = Grid Power
channel-type.evcc.gridPower.description = Current power from grid (negative means feed-in) channel-type.evcc.gridPower.description = Current power from grid (negative means feed-in)
channel-type.evcc.homePower.label = Home Power channel-type.evcc.homePower.label = Home Power
channel-type.evcc.homePower.description = Current power taken by home channel-type.evcc.homePower.description = Current power taken by home
channel-type.evcc.limitEnergy.label = Charging Limit Energy
channel-type.evcc.limitEnergy.description = Amount of energy to charge the vehicle with
channel-type.evcc.limitSoC.label = Charging Limit SoC
channel-type.evcc.limitSoC.description = Until which state of charge (SoC) should the vehicle be charged
channel-type.evcc.maxCurrent.label = Charging max Current channel-type.evcc.maxCurrent.label = Charging max Current
channel-type.evcc.maxCurrent.description = Maximum amperage per connected phase with which the car should be charged channel-type.evcc.maxCurrent.description = Maximum amperage per connected phase with which the car should be charged
channel-type.evcc.minCurrent.label = Charging min Current channel-type.evcc.minCurrent.label = Charging min Current
channel-type.evcc.minCurrent.description = Minimum amperage per connected phase with which the car should be charged channel-type.evcc.minCurrent.description = Minimum amperage per connected phase with which the car should be charged
channel-type.evcc.minSoC.label = Charging min SoC
channel-type.evcc.minSoC.description = Charge immediately with maximum power up to the defined SoC, if the charge mode is not set to "off"
channel-type.evcc.mode.label = Charging Mode channel-type.evcc.mode.label = Charging Mode
channel-type.evcc.mode.description = Charging mode: "off", "now", "minpv", "pv" channel-type.evcc.mode.description = Charging mode: "off", "now", "minpv", "pv"
channel-type.evcc.mode.state.option.off = Off channel-type.evcc.mode.state.option.off = Off
@ -70,18 +80,12 @@ channel-type.evcc.mode.state.option.minpv = Min + PV
channel-type.evcc.mode.state.option.pv = Only PV channel-type.evcc.mode.state.option.pv = Only PV
channel-type.evcc.phases.label = Charging Enabled Phases channel-type.evcc.phases.label = Charging Enabled Phases
channel-type.evcc.phases.description = The maximum number of phases which can be used channel-type.evcc.phases.description = The maximum number of phases which can be used
channel-type.evcc.prioritySoC.label = Battery Priority SoC
channel-type.evcc.prioritySoC.description = State of Charge for which the battery has priority over charging the EV when charging mode is "pv"
channel-type.evcc.pvPower.label = PV Power channel-type.evcc.pvPower.label = PV Power
channel-type.evcc.pvPower.description = Current power from photovoltaik channel-type.evcc.pvPower.description = Current power from photovoltaik
channel-type.evcc.targetEnergy.label = Charging Target Energy channel-type.evcc.residualPower.label = Grid Residual Power
channel-type.evcc.targetEnergy.description = Amount of energy to charge the vehicle with channel-type.evcc.residualPower.description = Target operating point of the surplus regulation at the grid connection (grid meter)
channel-type.evcc.targetSoC.label = Charging Target SoC
channel-type.evcc.targetSoC.description = Until which state of charge (SoC) should the vehicle be charged
channel-type.evcc.targetTime.label = Charging Target Time
channel-type.evcc.targetTime.description = When the target SoC should be reached
channel-type.evcc.targetTimeEnabled.label = Charging Target Time Enabled
channel-type.evcc.targetTimeEnabled.description = Target time for charging enabled
channel-type.evcc.targetTimeEnabled.state.option.ON = Enabled
channel-type.evcc.targetTimeEnabled.state.option.OFF = Disabled
channel-type.evcc.title.label = Loadpoint Title channel-type.evcc.title.label = Loadpoint Title
channel-type.evcc.title.description = Title of loadpoint channel-type.evcc.title.description = Title of loadpoint
channel-type.evcc.vehicleCapacity.label = Vehicle Capacity channel-type.evcc.vehicleCapacity.label = Vehicle Capacity
@ -92,8 +96,22 @@ channel-type.evcc.vehicleConnected.state.option.ON = Connected
channel-type.evcc.vehicleConnected.state.option.OFF = Not connected channel-type.evcc.vehicleConnected.state.option.OFF = Not connected
channel-type.evcc.vehicleConnectedDuration.label = Vehicle Connected Duration channel-type.evcc.vehicleConnectedDuration.label = Vehicle Connected Duration
channel-type.evcc.vehicleConnectedDuration.description = Duration the vehicle is connected to loadpoint channel-type.evcc.vehicleConnectedDuration.description = Duration the vehicle is connected to loadpoint
channel-type.evcc.vehicleLimitSoC.label = Vehicle Charging Limit SoC
channel-type.evcc.vehicleLimitSoC.description = Until which state of charge (SoC) should the specific vehicle be charged
channel-type.evcc.vehicleMinSoC.label = Vehicle Min SoC
channel-type.evcc.vehicleMinSoC.description = Minimum state of charge (SoC) a vehicle should have
channel-type.evcc.vehicleName.label = Vehicle Name
channel-type.evcc.vehicleName.description = The unique identifier of the EV used in the evcc configuration (containing no whitespaces nor special characters)
channel-type.evcc.vehicleOdometer.label = Vehicle Odometer channel-type.evcc.vehicleOdometer.label = Vehicle Odometer
channel-type.evcc.vehicleOdometer.description = Total distance travelled by EV channel-type.evcc.vehicleOdometer.description = Total distance travelled by EV
channel-type.evcc.vehiclePlanEnabled.label = Vehicle Plan Enabled
channel-type.evcc.vehiclePlanEnabled.description = Plan for charging enabled
channel-type.evcc.vehiclePlanEnabled.state.option.ON = Enabled
channel-type.evcc.vehiclePlanEnabled.state.option.OFF = Disabled
channel-type.evcc.vehiclePlanSoC.label = Vehicle Plan SoC
channel-type.evcc.vehiclePlanSoC.description = Until which state of charge (SoC) should vehicle be charged in plan
channel-type.evcc.vehiclePlanTime.label = Vehicle Plan Time
channel-type.evcc.vehiclePlanTime.description = When the plan SoC should be reached
channel-type.evcc.vehiclePresent.label = Vehicle Data Access channel-type.evcc.vehiclePresent.label = Vehicle Data Access
channel-type.evcc.vehiclePresent.description = Whether evcc is able to get data from vehicle channel-type.evcc.vehiclePresent.description = Whether evcc is able to get data from vehicle
channel-type.evcc.vehiclePresent.state.option.ON = Data access channel-type.evcc.vehiclePresent.state.option.ON = Data access
@ -103,7 +121,12 @@ channel-type.evcc.vehicleRange.description = Battery range for EV
channel-type.evcc.vehicleSoC.label = Vehicle SoC channel-type.evcc.vehicleSoC.label = Vehicle SoC
channel-type.evcc.vehicleSoC.description = Current State of Charge of EV channel-type.evcc.vehicleSoC.description = Current State of Charge of EV
channel-type.evcc.vehicleTitle.label = Vehicle Title channel-type.evcc.vehicleTitle.label = Vehicle Title
channel-type.evcc.vehicleTitle.description = Name of EV channel-type.evcc.vehicleTitle.description = Title of vehicle
# channel types
channel-type.evcc.batteryPrioritySoC.label = Battery Priority SoC
channel-type.evcc.batteryPrioritySoC.description = State of Charge for which the battery has priority over charging the ev when charging mode is "pv".
# thing status description # thing status description

View File

@ -67,13 +67,59 @@
<category>BatteryLevel</category> <category>BatteryLevel</category>
<state pattern="%.0f %unit%" readOnly="true"/> <state pattern="%.0f %unit%" readOnly="true"/>
</channel-type> </channel-type>
<channel-type id="batteryPrioritySoC"> <channel-type id="batteryDischargeControl">
<item-type>Switch</item-type>
<label>Battery Discharge Control</label>
<description>Enable or disable battery discharge control</description>
<category>Switch</category>
<state readOnly="false">
<options>
<option value="ON">Enabled</option>
<option value="OFF">Disabled</option>
</options>
</state>
</channel-type>
<channel-type id="batteryMode">
<item-type>String</item-type>
<label>Battery Mode</label>
<description>Current Battery Mode</description>
<category>Battery</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="prioritySoC">
<item-type>Number:Dimensionless</item-type> <item-type>Number:Dimensionless</item-type>
<label>Battery Priority SoC</label> <label>Battery Priority SoC</label>
<description>State of Charge for which the battery has priority over charging the ev when charging mode is "pv".</description> <description>State of Charge for which the battery has priority over charging the EV when charging mode is "pv"
</description>
<category>BatteryLevel</category> <category>BatteryLevel</category>
<state min="0" step="0.1" max="100" pattern="%.0f %unit%" readOnly="false"/> <state min="0" step="0.1" max="100" pattern="%.0f %unit%" readOnly="false"/>
</channel-type> </channel-type>
<channel-type id="bufferSoC">
<item-type>Number:Dimensionless</item-type>
<label>Battery Buffer SoC</label>
<description>Until this State of Charge the discharging of a house battery is allowed in "pv" mode, when there is
insufficient solar surplus (below the minimum charging power)
</description>
<category>BatteryLevel</category>
<state min="0" step="0.1" max="100" pattern="%.0f %unit%" readOnly="false"/>
</channel-type>
<channel-type id="bufferStartSoC">
<item-type>Number:Dimensionless</item-type>
<label>Battery Buffer Start SoC</label>
<description>State of Charge for which a charging session in "pv" mode is started, even if there is insufficient solar
surplus
</description>
<category>BatteryLevel</category>
<state min="0" step="0.1" max="100" pattern="%.0f %unit%" readOnly="false"/>
</channel-type>
<channel-type id="residualPower">
<item-type>Number:Power</item-type>
<label>Grid Residual Power</label>
<description>Target operating point of the surplus regulation at the grid connection (grid meter)
</description>
<category>Energy</category>
<state min="0" step="1" pattern="%.0f %unit%" readOnly="false"/>
</channel-type>
<channel-type id="gridPower"> <channel-type id="gridPower">
<item-type>Number:Power</item-type> <item-type>Number:Power</item-type>
<label>Grid Power</label> <label>Grid Power</label>
@ -96,7 +142,7 @@
<state pattern="%.1f %unit%" readOnly="true"/> <state pattern="%.1f %unit%" readOnly="true"/>
</channel-type> </channel-type>
<!-- Channels for loadpoints --> <!-- Channel Types for loadpoints -->
<channel-type id="activePhases"> <channel-type id="activePhases">
<item-type>Number</item-type> <item-type>Number</item-type>
<label>Charging Active Phases</label> <label>Charging Active Phases</label>
@ -128,14 +174,14 @@
<channel-type id="chargeRemainingDuration"> <channel-type id="chargeRemainingDuration">
<item-type>Number:Time</item-type> <item-type>Number:Time</item-type>
<label>Charging Remaining Duration</label> <label>Charging Remaining Duration</label>
<description>Remaining duration until target SoC is reached</description> <description>Remaining duration until limit SoC is reached</description>
<category>Time</category> <category>Time</category>
<state pattern="%.1f min" readOnly="true"/> <state pattern="%.1f min" readOnly="true"/>
</channel-type> </channel-type>
<channel-type id="chargeRemainingEnergy"> <channel-type id="chargeRemainingEnergy">
<item-type>Number:Energy</item-type> <item-type>Number:Energy</item-type>
<label>Charging Remaining Energy</label> <label>Charging Remaining Energy</label>
<description>Remaining energy until target SoC is reached</description> <description>Remaining energy until limit SoC is reached</description>
<category>Energy</category> <category>Energy</category>
<state pattern="%.1f %unit%" readOnly="true"/> <state pattern="%.1f %unit%" readOnly="true"/>
</channel-type> </channel-type>
@ -186,19 +232,11 @@
<state min="0" step="1" pattern="%.0f %unit%" readOnly="false"/> <state min="0" step="1" pattern="%.0f %unit%" readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy> <autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type> </channel-type>
<channel-type id="minSoC">
<item-type>Number:Dimensionless</item-type>
<label>Charging min SoC</label>
<description>Charge immediately with maximum power up to the defined SoC, if the charge mode is not set to "off"</description>
<category>BatteryLevel</category>
<state min="0" step="1" max="100" pattern="%.0f %unit%" readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="mode"> <channel-type id="mode">
<item-type>String</item-type> <item-type>String</item-type>
<label>Charging Mode</label> <label>Charging Mode</label>
<description>Charging mode: "off", "now", "minpv", "pv"</description> <description>Charging mode: "off", "now", "minpv", "pv"</description>
<category>String</category> <category>Heating</category>
<state readOnly="false"> <state readOnly="false">
<options> <options>
<option value="off">Off</option> <option value="off">Off</option>
@ -217,48 +255,27 @@
<state min="0" step="1" max="3" pattern="%d" readOnly="false"/> <state min="0" step="1" max="3" pattern="%d" readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy> <autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type> </channel-type>
<channel-type id="targetEnergy"> <channel-type id="limitEnergy">
<item-type>Number:Energy</item-type> <item-type>Number:Energy</item-type>
<label>Charging Target Energy</label> <label>Charging Limit Energy</label>
<description>Amount of energy to charge the vehicle with</description> <description>Amount of energy to charge the vehicle with</description>
<category>BatteryLevel</category> <category>BatteryLevel</category>
<state min="0" pattern="%.0f %unit%" readOnly="false"/> <state min="0" pattern="%.0f %unit%" readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy> <autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type> </channel-type>
<channel-type id="targetSoC"> <channel-type id="limitSoC">
<item-type>Number:Dimensionless</item-type> <item-type>Number:Dimensionless</item-type>
<label>Charging Target SoC</label> <label>Charging Limit SoC</label>
<description>Until which state of charge (SoC) should the vehicle be charged</description> <description>Until which state of charge (SoC) should the vehicle be charged</description>
<category>BatteryLevel</category> <category>BatteryLevel</category>
<state min="0" step="1" max="100" pattern="%.0f %unit%" readOnly="false"/> <state min="0" step="1" max="100" pattern="%.0f %unit%" readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy> <autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type> </channel-type>
<channel-type id="targetTime">
<item-type>DateTime</item-type>
<label>Charging Target Time</label>
<description>When the target SoC should be reached</description>
<category>Time</category>
<state readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="targetTimeEnabled">
<item-type>Switch</item-type>
<label>Charging Target Time Enabled</label>
<description>Target time for charging enabled</description>
<category>Switch</category>
<state readOnly="false">
<options>
<option value="ON">Enabled</option>
<option value="OFF">Disabled</option>
</options>
</state>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="title"> <channel-type id="title">
<item-type>String</item-type> <item-type>String</item-type>
<label>Loadpoint Title</label> <label>Loadpoint Title</label>
<description>Title of loadpoint</description> <description>Title of loadpoint</description>
<category>Text</category> <category>PowerOutlet</category>
<state readOnly="true"/> <state readOnly="true"/>
</channel-type> </channel-type>
<channel-type id="vehicleConnected"> <channel-type id="vehicleConnected">
@ -291,7 +308,7 @@
<item-type>Number:Length</item-type> <item-type>Number:Length</item-type>
<label>Vehicle Odometer</label> <label>Vehicle Odometer</label>
<description>Total distance travelled by EV</description> <description>Total distance travelled by EV</description>
<category></category> <category>MoveControl</category>
<state pattern="%.1f %unit%" readOnly="true"/> <state pattern="%.1f %unit%" readOnly="true"/>
</channel-type> </channel-type>
<channel-type id="vehiclePresent"> <channel-type id="vehiclePresent">
@ -320,11 +337,66 @@
<category>BatteryLevel</category> <category>BatteryLevel</category>
<state pattern="%.0f %unit%" readOnly="true"/> <state pattern="%.0f %unit%" readOnly="true"/>
</channel-type> </channel-type>
<channel-type id="vehicleName">
<item-type>String</item-type>
<label>Vehicle Name</label>
<description>The unique identifier of the EV used in the evcc configuration (containing no whitespaces nor special
characters)</description>
<category>Settings</category>
<state readOnly="true"/>
</channel-type>
<!-- Channel Types for vehicles -->
<channel-type id="vehicleTitle"> <channel-type id="vehicleTitle">
<item-type>String</item-type> <item-type>String</item-type>
<label>Vehicle Title</label> <label>Vehicle Title</label>
<description>Name of EV</description> <description>Title of vehicle</description>
<category>Text</category> <category>GarageDoor</category>
<state readOnly="true"/> <state readOnly="true"/>
</channel-type> </channel-type>
<channel-type id="vehicleMinSoC">
<item-type>Number:Dimensionless</item-type>
<label>Vehicle Min SoC</label>
<description>Minimum state of charge (SoC) a vehicle should have</description>
<category>BatteryLevel</category>
<state min="0" step="1" max="100" pattern="%.0f %unit%" readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="vehicleLimitSoC">
<item-type>Number:Dimensionless</item-type>
<label>Vehicle Charging Limit SoC</label>
<description>Until which state of charge (SoC) should the specific vehicle be charged</description>
<category>BatteryLevel</category>
<state min="0" step="1" max="100" pattern="%.0f %unit%" readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="vehiclePlanEnabled">
<item-type>Switch</item-type>
<label>Vehicle Plan Enabled</label>
<description>Plan for charging enabled</description>
<category>Switch</category>
<state readOnly="false">
<options>
<option value="ON">Enabled</option>
<option value="OFF">Disabled</option>
</options>
</state>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="vehiclePlanSoC">
<item-type>Number:Dimensionless</item-type>
<label>Vehicle Plan SoC</label>
<description>Until which state of charge (SoC) should vehicle be charged in plan</description>
<category>BatteryLevel</category>
<state min="0" step="1" max="100" pattern="%.0f %unit%" readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="vehiclePlanTime">
<item-type>DateTime</item-type>
<label>Vehicle Plan Time</label>
<description>When the plan SoC should be reached</description>
<category>Time</category>
<state readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
</thing:thing-descriptions> </thing:thing-descriptions>