[evcc] Adjust to API changes & Add new channels for evcc 0.117.0 (#14983)

* [evcc] Remove `hasVehicle` channel
* [evcc] Update API for evcc 0.117.0
* [evcc] Fix targetSoC and targetTime not working

Also:
- Use new Java 17 features.

Fixes #14348.

* [evcc] Add `targetEnergy` channel
* [evcc] Make `batteryPrioritySoC` channel writable

Closes #14347.

Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
This commit is contained in:
Florian Hotze 2023-05-21 21:21:38 +02:00 committed by GitHub
parent 0724c3febc
commit 095a5df323
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 253 additions and 242 deletions

View File

@ -1,7 +1,7 @@
# evcc Binding
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.111.0](https://github.com/evcc-io/evcc/releases/tag/0.111.0) or newer and is tested with this version.
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.
You can easily install and upgrade evcc on openHABian using `sudo openhabian-config`.
@ -43,7 +43,7 @@ Please note that some of them are only available when evcc is properly configure
| general#batteryCapacity | Number:Energy | R | Capacity of (home) battery. |
| general#batteryPower | Number:Power | R | Current power from battery. |
| general#batterySoC | Number:Dimensionless | R | Current State of Charge of battery. |
| general#batteryPrioritySoC | Number:Dimensionless | R | State of State of Charge for which the battery has priority over charging the ev when charging mode is "pv". |
| 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#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. |
@ -64,12 +64,12 @@ Please note that you have to replace _N_ with your loadpoint number.
| loadpointN#chargedEnergy | Number:Energy | R | Energy charged since plugged-in |
| loadpointN#charging | Switch | R | Loadpoint is currently charging |
| loadpointN#enabled | Switch | R | Charging enabled (mode is not "off") |
| loadpointN#hasVehicle | Switch | R | Whether vehicle is configured for loadpoint |
| 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#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#phases | Number | RW | The maximum number of phases which can be used |
| loadpointN#targetEnergy | Number:Energy | RW | Amount of energy to charge the vehicle with |
| loadpointN#targetSoC | Number:Dimensionless | RW | Until which state of charge (SoC) should the vehicle be charged |
| loadpointN#targetTime | DateTime | RW | When the target SoC should be reached |
| loadpointN#targetTimeEnabled | Switch | RW | Target time for charging enabled |
@ -113,12 +113,12 @@ Number:Power evcc_loadpoint0_chargePower "Charging
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_enabled "Charging enabled [%s]" <switch> {channel="evcc:device:demo:loadpoint0#enabled"}
Switch evcc_loadpoint0_hasVehicle "Vehicle configured [%s]" <switch> {channel="evcc:device:demo:loadpoint0#hasVehicle"}
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: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"}
Number evcc_loadpoint0_phases "Enabled phases [%d]" {channel="evcc:device:demo:loadpoint0#phases"}
Number:Energy evcc_loadpoint0_targetEnergy "Target energy [%.1f kWh]" <batterylevel> {channel="evcc:device:demo:loadpoint0#targetEnergy"}
Number:Dimensionless evcc_loadpoint0_targetSoC "Target SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:loadpoint0#targetSoC"}
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"}
@ -158,6 +158,7 @@ sitemap evcc label="evcc Demo" {
}
Switch item=evcc_loadpoint0_mode mappings=["off"="Stop","now"="Now","minpv"="Min + PV", "pv"="Only PV"]
Text label="Charging settings" icon="settings" {
Setpoint item=evcc_loadpoint0_targetEnergy minValue=5 maxValue=100 step=5
Setpoint item=evcc_loadpoint0_targetSoC minValue=5 maxValue=100 step=5
Setpoint item=evcc_loadpoint0_minCurrent minValue=6 maxValue=96 step=2
Setpoint item=evcc_loadpoint0_maxCurrent minValue=6 maxValue=96 step=2

View File

@ -27,6 +27,8 @@ public class EvccBindingConstants {
private static final String BINDING_ID = "evcc";
public static final String CHANNEL_GROUP_ID_GENERAL = "general";
// List of all Channel ids
public static final String CHANNEL_BATTERY_CAPACITY = "batteryCapacity";
public static final String CHANNEL_BATTERY_POWER = "batteryPower";
@ -45,13 +47,14 @@ public class EvccBindingConstants {
public static final String CHANNEL_LOADPOINT_CHARGING = "charging";
public static final String CHANNEL_LOADPOINT_CONNECTED = "vehicleConnected";
public static final String CHANNEL_LOADPOINT_CONNECTED_DURATION = "vehicleConnectedDuration";
public static final String CHANNEL_LOADPOINT_ENABLED = "enabled";
public static final String CHANNEL_LOADPOINT_HAS_VEHICLE = "hasVehicle";
public static final String CHANNEL_LOADPOINT_ENABLED = "enabled";
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_SOC = "minSoC";
public static final String CHANNEL_LOADPOINT_MODE = "mode";
public static final String CHANNEL_LOADPOINT_PHASES = "phases";
public static final String CHANNEL_LOADPOINT_TARGET_ENERGY = "targetEnergy";
public static final String CHANNEL_LOADPOINT_TARGET_SOC = "targetSoC";
public static final String CHANNEL_LOADPOINT_TARGET_TIME = "targetTime";
/**
@ -103,8 +106,6 @@ public class EvccBindingConstants {
CHANNEL_LOADPOINT_CONNECTED_DURATION);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_ENABLED = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_ENABLED);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_HAS_VEHICLE = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_HAS_VEHICLE);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_MAX_CURRENT = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_MAX_CURRENT);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_MIN_CURRENT = new ChannelTypeUID(BINDING_ID,
@ -115,6 +116,8 @@ public class EvccBindingConstants {
CHANNEL_LOADPOINT_MODE);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_PHASES = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_PHASES);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_TARGET_ENERGY = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_TARGET_ENERGY);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_TARGET_SOC = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_TARGET_SOC);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_TARGET_TIME = new ChannelTypeUID(BINDING_ID,

View File

@ -34,7 +34,6 @@ import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.MetricPrefix;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
@ -42,7 +41,6 @@ import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
@ -67,7 +65,6 @@ public class EvccHandler extends BaseThingHandler {
private boolean gridConfigured = false;
private boolean pvConfigured = false;
private float targetSoC = 100;
private boolean targetTimeEnabled = false;
private ZonedDateTime targetTimeZDT = ZonedDateTime.now().plusHours(12);
@ -85,97 +82,116 @@ public class EvccHandler extends BaseThingHandler {
if (groupId == null) {
return;
}
String channelGroupId = channelUID.getGroupId();
String channelIdWithoutGroup = channelUID.getIdWithoutGroup();
int loadpoint = Integer.parseInt(groupId.substring(9)) + 1;
EvccAPI evccAPI = this.evccAPI;
if (evccAPI == null) {
return;
}
try {
switch (channelIdWithoutGroup) {
case CHANNEL_LOADPOINT_MODE:
if (command instanceof StringType) {
evccAPI.setMode(loadpoint, command.toString());
} else {
logger.debug("Command has wrong type, StringType required!");
}
break;
case CHANNEL_LOADPOINT_MIN_SOC:
if (command instanceof QuantityType) {
evccAPI.setMinSoC(loadpoint, ((QuantityType<?>) command).toUnit(Units.PERCENT).intValue());
} else if (command instanceof DecimalType) {
evccAPI.setMinSoC(loadpoint, ((DecimalType) command).intValue());
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
break;
case CHANNEL_LOADPOINT_TARGET_SOC:
if (command instanceof QuantityType) {
evccAPI.setTargetSoC(loadpoint,
((QuantityType<?>) command).toUnit(Units.PERCENT).intValue());
} else if (command instanceof DecimalType) {
evccAPI.setTargetSoC(loadpoint, ((DecimalType) command).intValue());
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
break;
case CHANNEL_LOADPOINT_TARGET_TIME:
if (command instanceof DateTimeType) {
targetTimeZDT = ((DateTimeType) command).getZonedDateTime();
ChannelUID channel = new ChannelUID(getThing().getUID(), "loadpoint" + loadpoint,
CHANNEL_LOADPOINT_TARGET_TIME);
updateState(channel, new DateTimeType(targetTimeZDT));
if (targetTimeEnabled) {
try {
evccAPI.setTargetCharge(loadpoint, targetSoC, targetTimeZDT);
} catch (DateTimeParseException e) {
logger.debug("Failed to set target charge: ", e);
}
}
} else {
logger.debug("Command has wrong type, DateTimeType required!");
}
break;
case CHANNEL_LOADPOINT_TARGET_TIME_ENABLED:
if (command == OnOffType.ON) {
evccAPI.setTargetCharge(loadpoint, targetSoC, targetTimeZDT);
targetTimeEnabled = true;
} else if (command == OnOffType.OFF) {
evccAPI.unsetTargetCharge(loadpoint);
targetTimeEnabled = false;
} else {
logger.debug("Command has wrong type, OnOffType required!");
}
break;
case CHANNEL_LOADPOINT_PHASES:
if (command instanceof DecimalType) {
evccAPI.setPhases(loadpoint, ((DecimalType) command).intValue());
} else {
logger.debug("Command has wrong type, DecimalType required!");
}
break;
case CHANNEL_LOADPOINT_MIN_CURRENT:
if (command instanceof QuantityType) {
evccAPI.setMinCurrent(loadpoint,
((QuantityType<?>) command).toUnit(Units.AMPERE).intValue());
} else if (command instanceof DecimalType) {
evccAPI.setMinCurrent(loadpoint, ((DecimalType) command).intValue());
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
break;
case CHANNEL_LOADPOINT_MAX_CURRENT:
if (command instanceof QuantityType) {
evccAPI.setMaxCurrent(loadpoint,
((QuantityType<?>) command).toUnit(Units.AMPERE).intValue());
} else if (command instanceof DecimalType) {
evccAPI.setMaxCurrent(loadpoint, ((DecimalType) command).intValue());
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
break;
default:
if (channelGroupId.equals(CHANNEL_GROUP_ID_GENERAL)) {
if (!channelIdWithoutGroup.equals(CHANNEL_BATTERY_PRIORITY_SOC)) {
return;
}
if (command instanceof QuantityType<?> qt) {
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;
switch (channelIdWithoutGroup) {
case CHANNEL_LOADPOINT_MODE -> {
if (command instanceof StringType) {
evccAPI.setMode(loadpoint, command.toString());
} else {
logger.debug("Command has wrong type, StringType required!");
}
}
case CHANNEL_LOADPOINT_MIN_SOC -> {
if (command instanceof QuantityType<?> qt) {
evccAPI.setMinSoC(loadpoint, qt.toUnit(Units.PERCENT).intValue());
} else if (command instanceof DecimalType dt) {
evccAPI.setMinSoC(loadpoint, dt.intValue());
} else {
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 {
logger.debug("Command has wrong type, QuantityType required!");
}
}
case CHANNEL_LOADPOINT_TARGET_SOC -> {
if (command instanceof QuantityType<?> qt) {
evccAPI.setTargetSoC(loadpoint, qt.toUnit(Units.PERCENT).intValue());
} else if (command instanceof DecimalType dt) {
evccAPI.setTargetSoC(loadpoint, dt.intValue());
} else {
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 -> {
if (command instanceof DecimalType dt) {
evccAPI.setPhases(loadpoint, dt.intValue());
} else {
logger.debug("Command has wrong type, DecimalType required!");
}
}
case CHANNEL_LOADPOINT_MIN_CURRENT -> {
if (command instanceof QuantityType<?> qt) {
evccAPI.setMinCurrent(loadpoint, qt.toUnit(Units.AMPERE).intValue());
} else if (command instanceof DecimalType dt) {
evccAPI.setMinCurrent(loadpoint, dt.intValue());
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
}
case CHANNEL_LOADPOINT_MAX_CURRENT -> {
if (command instanceof QuantityType<?> qt) {
evccAPI.setMaxCurrent(loadpoint, qt.toUnit(Units.AMPERE).intValue());
} else if (command instanceof DecimalType dt) {
evccAPI.setMaxCurrent(loadpoint, dt.intValue());
} else {
logger.debug("Command has wrong type, QuantityType or DecimalType required!");
}
}
default -> {
return;
}
}
}
} catch (EvccApiException e) {
Throwable cause = e.getCause();
@ -256,20 +272,22 @@ public class EvccHandler extends BaseThingHandler {
// Utility functions
private void createChannelsGeneral() {
final String channelGroup = "general";
if (batteryConfigured) {
createChannel(CHANNEL_BATTERY_CAPACITY, channelGroup, CHANNEL_TYPE_UID_BATTERY_CAPACITY, "Number:Energy");
createChannel(CHANNEL_BATTERY_POWER, channelGroup, CHANNEL_TYPE_UID_BATTERY_POWER, "Number:Power");
createChannel(CHANNEL_BATTERY_SOC, channelGroup, CHANNEL_TYPE_UID_BATTERY_SOC, "Number:Dimensionless");
createChannel(CHANNEL_BATTERY_PRIORITY_SOC, channelGroup, CHANNEL_TYPE_UID_BATTERY_PRIORITY_SOC,
createChannel(CHANNEL_BATTERY_CAPACITY, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_BATTERY_CAPACITY,
"Number:Energy");
createChannel(CHANNEL_BATTERY_POWER, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_BATTERY_POWER,
"Number:Power");
createChannel(CHANNEL_BATTERY_SOC, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_BATTERY_SOC,
"Number:Dimensionless");
createChannel(CHANNEL_BATTERY_PRIORITY_SOC, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_BATTERY_PRIORITY_SOC,
"Number:Dimensionless");
}
if (gridConfigured) {
createChannel(CHANNEL_GRID_POWER, channelGroup, CHANNEL_TYPE_UID_GRID_POWER, "Number:Power");
createChannel(CHANNEL_GRID_POWER, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_GRID_POWER, "Number:Power");
}
createChannel(CHANNEL_HOME_POWER, channelGroup, CHANNEL_TYPE_UID_HOME_POWER, "Number:Power");
createChannel(CHANNEL_HOME_POWER, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_HOME_POWER, "Number:Power");
if (pvConfigured) {
createChannel(CHANNEL_PV_POWER, channelGroup, CHANNEL_TYPE_UID_PV_POWER, "Number:Power");
createChannel(CHANNEL_PV_POWER, CHANNEL_GROUP_ID_GENERAL, CHANNEL_TYPE_UID_PV_POWER, "Number:Power");
}
}
@ -297,8 +315,6 @@ public class EvccHandler extends BaseThingHandler {
"Number:Time");
createChannel(CHANNEL_LOADPOINT_ENABLED, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_ENABLED,
CoreItemFactory.SWITCH);
createChannel(CHANNEL_LOADPOINT_HAS_VEHICLE, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_HAS_VEHICLE,
CoreItemFactory.SWITCH);
createChannel(CHANNEL_LOADPOINT_MAX_CURRENT, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_MAX_CURRENT,
"Number:ElectricCurrent");
createChannel(CHANNEL_LOADPOINT_MIN_CURRENT, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_MIN_CURRENT,
@ -308,6 +324,8 @@ public class EvccHandler extends BaseThingHandler {
createChannel(CHANNEL_LOADPOINT_MODE, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_MODE, CoreItemFactory.STRING);
createChannel(CHANNEL_LOADPOINT_PHASES, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_PHASES,
CoreItemFactory.NUMBER);
createChannel(CHANNEL_LOADPOINT_TARGET_ENERGY, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_TARGET_ENERGY,
"Number:Energy");
createChannel(CHANNEL_LOADPOINT_TARGET_SOC, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_TARGET_SOC,
"Number:Dimensionless");
createChannel(CHANNEL_LOADPOINT_TARGET_TIME, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_TARGET_TIME,
@ -327,6 +345,8 @@ public class EvccHandler extends BaseThingHandler {
"Number:Dimensionless");
createChannel(CHANNEL_LOADPOINT_VEHICLE_TITLE, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_TITLE,
CoreItemFactory.STRING);
removeChannel(CHANNEL_LOADPOINT_HAS_VEHICLE, channelGroup);
}
// Units and description for vars: https://docs.evcc.io/docs/reference/configuration/messaging/#msg
@ -340,34 +360,34 @@ public class EvccHandler extends BaseThingHandler {
boolean batteryConfigured = this.batteryConfigured;
if (batteryConfigured) {
float batteryCapacity = result.getBatteryCapacity();
channel = new ChannelUID(uid, "general", CHANNEL_BATTERY_CAPACITY);
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_BATTERY_CAPACITY);
updateState(channel, new QuantityType<>(batteryCapacity, Units.KILOWATT_HOUR));
float batteryPower = result.getBatteryPower();
channel = new ChannelUID(uid, "general", CHANNEL_BATTERY_POWER);
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_BATTERY_POWER);
updateState(channel, new QuantityType<>(batteryPower, Units.WATT));
float batterySoC = result.getBatterySoC();
channel = new ChannelUID(uid, "general", CHANNEL_BATTERY_SOC);
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_BATTERY_SOC);
updateState(channel, new QuantityType<>(batterySoC, Units.PERCENT));
float batteryPrioritySoC = result.getBatteryPrioritySoC();
channel = new ChannelUID(uid, "general", CHANNEL_BATTERY_PRIORITY_SOC);
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_BATTERY_PRIORITY_SOC);
updateState(channel, new QuantityType<>(batteryPrioritySoC, Units.PERCENT));
}
boolean gridConfigured = this.gridConfigured;
if (gridConfigured) {
float gridPower = result.getGridPower();
channel = new ChannelUID(uid, "general", CHANNEL_GRID_POWER);
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_GRID_POWER);
updateState(channel, new QuantityType<>(gridPower, Units.WATT));
}
float homePower = result.getHomePower();
channel = new ChannelUID(uid, "general", CHANNEL_HOME_POWER);
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_HOME_POWER);
updateState(channel, new QuantityType<>(homePower, Units.WATT));
boolean pvConfigured = this.pvConfigured;
if (pvConfigured) {
float pvPower = result.getPvPower();
channel = new ChannelUID(uid, "general", CHANNEL_PV_POWER);
channel = new ChannelUID(uid, CHANNEL_GROUP_ID_GENERAL, CHANNEL_PV_POWER);
updateState(channel, new QuantityType<>(pvPower, Units.WATT));
}
}
@ -426,10 +446,6 @@ public class EvccHandler extends BaseThingHandler {
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_ENABLED);
updateState(channel, OnOffType.from(enabled));
boolean hasVehicle = loadpoint.getHasVehicle();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_HAS_VEHICLE);
updateState(channel, OnOffType.from(hasVehicle));
float maxCurrent = loadpoint.getMaxCurrent();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_MAX_CURRENT);
updateState(channel, new QuantityType<>(maxCurrent, Units.AMPERE));
@ -450,12 +466,16 @@ public class EvccHandler extends BaseThingHandler {
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_PHASES);
updateState(channel, new DecimalType(phases));
targetSoC = loadpoint.getTargetSoC();
float targetEnergy = loadpoint.getTargetEnergy();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_TARGET_ENERGY);
updateState(channel, new QuantityType<>(targetEnergy, Units.WATT_HOUR));
float targetSoC = loadpoint.getTargetSoC();
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_TARGET_SOC);
updateState(channel, new QuantityType<>(targetSoC, Units.PERCENT));
String targetTime = loadpoint.getTargetTime();
if (targetTime == null) {
if (targetTime == null || targetTime.equals("0001-01-01T00:00:00Z")) {
channel = new ChannelUID(uid, loadpointName, CHANNEL_LOADPOINT_TARGET_TIME_ENABLED);
updateState(channel, OnOffType.OFF);
targetTimeEnabled = false;
@ -498,14 +518,17 @@ public class EvccHandler extends BaseThingHandler {
}
private void createChannel(String channel, String channelGroupId, ChannelTypeUID channelTypeUID, String itemType) {
ChannelUID channelToCheck = new ChannelUID(thing.getUID(), channelGroupId, channel);
if (thing.getChannel(channelToCheck) == null) {
ThingBuilder thingBuilder = editThing();
Channel testchannel = ChannelBuilder
.create(new ChannelUID(getThing().getUID(), channelGroupId, channel), itemType)
.withType(channelTypeUID).build();
thingBuilder.withChannel(testchannel);
updateThing(thingBuilder.build());
ChannelUID channelUid = new ChannelUID(thing.getUID(), channelGroupId, channel);
if (thing.getChannel(channelUid) == null) {
updateThing(editThing()
.withChannel(ChannelBuilder.create(channelUid, itemType).withType(channelTypeUID).build()).build());
}
}
private void removeChannel(String channel, String channelGroupId) {
ChannelUID channelUid = new ChannelUID(thing.getUID(), channelGroupId, channel);
if (thing.getChannel(channelUid) != null) {
updateThing(editThing().withoutChannel(channelUid).build());
}
}
}

View File

@ -31,7 +31,8 @@ import com.google.gson.JsonSyntaxException;
/**
* The {@link EvccAPI} is responsible for API calls to evcc.
*
* API requests were written for evcc version 0.117.0
*
* @author Florian Hotze - Initial contribution
*/
@NonNullByDefault
@ -46,7 +47,7 @@ public class EvccAPI {
/**
* Make a HTTP request.
*
*
* @param url full request URL
* @param method request method, e.g. GET, POST
* @return the response body
@ -84,6 +85,11 @@ public class EvccAPI {
}
}
// Site API calls.
public String setBatteryPrioritySoC(int prioritySoc) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "prioritysoc/" + prioritySoc, "POST");
}
// Loadpoint specific API calls.
public String setMode(int loadpoint, String mode) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/mode/" + mode, "POST");
@ -93,8 +99,13 @@ public class EvccAPI {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/minsoc/" + minSoC, "POST");
}
public String setTargetEnergy(int loadpoint, float targetEnergy) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/target/energy/" + targetEnergy,
"POST");
}
public String setTargetSoC(int loadpoint, int targetSoC) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/targetsoc/" + targetSoC, "POST");
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/target/soc/" + targetSoC, "POST");
}
public String setPhases(int loadpoint, int phases) throws EvccApiException {
@ -109,13 +120,12 @@ public class EvccAPI {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/maxcurrent/" + maxCurrent, "POST");
}
public String setTargetCharge(int loadpoint, float targetSoC, ZonedDateTime targetTime) throws EvccApiException {
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/targetcharge/" + targetSoC + "/"
+ targetTime.toLocalDateTime().format(formatter), "POST");
public String setTargetTime(int loadpoint, ZonedDateTime targetTime) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/target/time/"
+ targetTime.toLocalDateTime().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + "Z", "POST");
}
public String unsetTargetCharge(int loadpoint) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/targetcharge", "DELETE");
public String removeTargetTime(int loadpoint) throws EvccApiException {
return httpRequest(this.host + EVCC_REST_API + "loadpoints/" + loadpoint + "/target/time", "DELETE");
}
}

View File

@ -16,7 +16,7 @@ import com.google.gson.annotations.SerializedName;
/**
* This class represents a loadpoint object of the status response (/api/state).
* This DTO was written for evcc version 0.111.1
* This DTO was written for evcc version 0.117.0
*
* @author Florian Hotze - Initial contribution
*/
@ -57,12 +57,6 @@ public class Loadpoint {
@SerializedName("enabled")
private boolean enabled;
@SerializedName("hasVehicle")
private boolean hasVehicle;
@SerializedName("loadpoint")
private int loadpoint;
@SerializedName("maxCurrent")
private float maxCurrent;
@ -75,14 +69,14 @@ public class Loadpoint {
@SerializedName("mode")
private String mode;
@SerializedName("phases")
@SerializedName("phasesEnabled")
private int phases;
@SerializedName("pvAction")
private String pvAction;
@SerializedName("planActive")
private boolean planActive;
@SerializedName("pvRemaining")
private long pvRemaining;
@SerializedName("targetEnergy")
private float targetEnergy;
@SerializedName("targetSoc")
private float targetSoC;
@ -188,20 +182,6 @@ public class Loadpoint {
return enabled;
}
/**
* @return whether vehicle is configured for loadpoint
*/
public boolean getHasVehicle() {
return hasVehicle;
}
/**
* @return loadpoint id
*/
public int getLoadpoint() {
return loadpoint;
}
/**
* @return maximum current
*/
@ -238,17 +218,17 @@ public class Loadpoint {
}
/**
* @return the pv action
* @return whether charging plan is active
*/
public String getPvAction() {
return pvAction;
public boolean getPlanActive() {
return planActive;
}
/**
* @return the pv remaining
* @return target energy
*/
public long getPvRemaining() {
return pvRemaining;
public float getTargetEnergy() {
return targetEnergy;
}
/**

View File

@ -16,7 +16,7 @@ import com.google.gson.annotations.SerializedName;
/**
* This class represents the result object of the status response (/api/state).
* This DTO was written for evcc version 0.111.1
* This DTO was written for evcc version 0.117.0
*
* @author Florian Hotze - Initial contribution
*/

View File

@ -16,7 +16,7 @@ import com.google.gson.annotations.SerializedName;
/**
* This class represents the status response (/api/state).
* This DTO was written for evcc version 0.111.1
* This DTO was written for evcc version 0.117.0
*
* @author Florian Hotze - Initial contribution
*/

View File

@ -17,12 +17,12 @@ thing-type.config.evcc.device.url.description = URL of evcc web UI, e.g. https:/
# channel group types
channel-group-type.evcc.general.label = General data
channel-group-type.evcc.general.label = General Data
channel-group-type.evcc.loadpoint.label = Loadpoint
# channel types
channel-type.evcc.activePhases.label = Charging active phases
channel-type.evcc.activePhases.label = Charging Active Phases
channel-type.evcc.activePhases.description = Current number of active phases while charging
channel-type.evcc.batteryCapacity.label = Battery Capacity
channel-type.evcc.batteryCapacity.description = Capacity of (home) battery
@ -32,79 +32,77 @@ 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.description = Current State of Charge of battery
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.chargeDuration.label = Charging duration
channel-type.evcc.chargeDuration.label = Charging Duration
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.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.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.chargedEnergy.label = Charged energy
channel-type.evcc.chargedEnergy.label = Charged Energy
channel-type.evcc.chargedEnergy.description = Energy charged since plugged-in
channel-type.evcc.charging.label = Charging state
channel-type.evcc.charging.label = Charging State
channel-type.evcc.charging.description = Loadpoint is currently charging
channel-type.evcc.charging.state.option.ON = Charging
channel-type.evcc.charging.state.option.OFF = Not charging
channel-type.evcc.enabled.label = Charging enabled
channel-type.evcc.enabled.label = Charging Enabled
channel-type.evcc.enabled.description = Charging enabled (mode not "off")
channel-type.evcc.enabled.state.option.ON = Enabled
channel-type.evcc.enabled.state.option.OFF = Disabled
channel-type.evcc.gridPower.label = Grid Power
channel-type.evcc.gridPower.description = Current power from grid (negative means feed-in)
channel-type.evcc.hasVehicle.label = Loadpoint has vehicle configuration
channel-type.evcc.hasVehicle.description = Whether vehicle is configured for loadpoint
channel-type.evcc.hasVehicle.state.option.ON = Configured
channel-type.evcc.hasVehicle.state.option.OFF = Not configured
channel-type.evcc.homePower.label = Home Power
channel-type.evcc.homePower.description = Current power taken by home
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.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.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.state.option.off = Off
channel-type.evcc.mode.state.option.now = Now
channel-type.evcc.mode.state.option.now = Fast
channel-type.evcc.mode.state.option.minpv = Min + 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.pvPower.label = PV Power
channel-type.evcc.pvPower.description = Current power from photovoltaik
channel-type.evcc.targetSoC.label = Charging target SoC
channel-type.evcc.targetEnergy.label = Charging Target Energy
channel-type.evcc.targetEnergy.description = Amount of energy to charge the vehicle with
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.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.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.vehicleCapacity.label = Vehicle capacity
channel-type.evcc.vehicleCapacity.label = Vehicle Capacity
channel-type.evcc.vehicleCapacity.description = Capacity of EV battery
channel-type.evcc.vehicleConnected.label = Vehicle connected
channel-type.evcc.vehicleConnected.label = Vehicle Connected
channel-type.evcc.vehicleConnected.description = Whether vehicle is connected to loadpoint
channel-type.evcc.vehicleConnected.state.option.ON = 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.vehicleOdometer.label = Vehicle odometer
channel-type.evcc.vehicleOdometer.label = Vehicle Odometer
channel-type.evcc.vehicleOdometer.description = Total distance travelled by EV
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.state.option.ON = Data access
channel-type.evcc.vehiclePresent.state.option.OFF = No data access
channel-type.evcc.vehicleRange.label = Vehicle range
channel-type.evcc.vehicleRange.label = Vehicle Range
channel-type.evcc.vehicleRange.description = Battery range for EV
channel-type.evcc.vehicleSoC.label = Vehicle SoC
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
# thing status description

View File

@ -39,7 +39,7 @@
</thing-type>
<channel-group-type id="general">
<label>General data</label>
<label>General Data</label>
</channel-group-type>
<channel-group-type id="loadpoint">
<label>Loadpoint</label>
@ -64,15 +64,15 @@
<item-type>Number:Dimensionless</item-type>
<label>Battery SoC</label>
<description>Current State of Charge of battery</description>
<category>batterylevel</category>
<category>BatteryLevel</category>
<state pattern="%.0f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="batteryPrioritySoC">
<item-type>Number:Dimensionless</item-type>
<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>
<category>batterylevel</category>
<state pattern="%.0f %unit%" readOnly="true"/>
<category>BatteryLevel</category>
<state min="0" step="0.1" max="100" pattern="%.0f %unit%" readOnly="false"/>
</channel-type>
<channel-type id="gridPower">
<item-type>Number:Power</item-type>
@ -99,56 +99,56 @@
<!-- Channels for loadpoints -->
<channel-type id="activePhases">
<item-type>Number</item-type>
<label>Charging active phases</label>
<label>Charging Active Phases</label>
<description>Current number of active phases while charging</description>
<category></category>
<state pattern="%d" readOnly="true"/>
</channel-type>
<channel-type id="chargeCurrent">
<item-type>Number:ElectricCurrent</item-type>
<label>Charging current</label>
<label>Charging Current</label>
<description>Current amperage per connected phase while charging</description>
<category>Energy</category>
<state pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="chargeDuration">
<item-type>Number:Time</item-type>
<label>Charging duration</label>
<label>Charging Duration</label>
<description>Charging duration</description>
<category>Time</category>
<state pattern="%.1f min" readOnly="true"/>
</channel-type>
<channel-type id="chargePower">
<item-type>Number:Power</item-type>
<label>Charging power</label>
<label>Charging Power</label>
<description>Current power of charging</description>
<category>Energy</category>
<state pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="chargeRemainingDuration">
<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>
<category>Time</category>
<state pattern="%.1f min" readOnly="true"/>
</channel-type>
<channel-type id="chargeRemainingEnergy">
<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>
<category>Energy</category>
<state pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="chargedEnergy">
<item-type>Number:Energy</item-type>
<label>Charged energy</label>
<label>Charged Energy</label>
<description>Energy charged since plugged-in</description>
<category>Energy</category>
<state pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="charging">
<item-type>Switch</item-type>
<label>Charging state</label>
<label>Charging State</label>
<description>Loadpoint is currently charging</description>
<category>Energy</category>
<state pattern="%f %unit%" readOnly="true">
@ -160,7 +160,7 @@
</channel-type>
<channel-type id="enabled">
<item-type>Switch</item-type>
<label>Charging enabled</label>
<label>Charging Enabled</label>
<description>Charging enabled (mode not "off")</description>
<category>Switch</category>
<state readOnly="true">
@ -170,21 +170,9 @@
</options>
</state>
</channel-type>
<channel-type id="hasVehicle">
<item-type>Switch</item-type>
<label>Loadpoint has vehicle configuration</label>
<description>Whether vehicle is configured for loadpoint</description>
<category>Switch</category>
<state readOnly="true">
<options>
<option value="ON">Configured</option>
<option value="OFF">Not configured</option>
</options>
</state>
</channel-type>
<channel-type id="maxCurrent">
<item-type>Number:ElectricCurrent</item-type>
<label>Charging max current</label>
<label>Charging max Current</label>
<description>Maximum amperage per connected phase with which the car should be charged</description>
<category>Energy</category>
<state min="0" step="1" pattern="%.0f %unit%" readOnly="false"/>
@ -192,7 +180,7 @@
</channel-type>
<channel-type id="minCurrent">
<item-type>Number:ElectricCurrent</item-type>
<label>Charging min current</label>
<label>Charging min Current</label>
<description>Minimum amperage per connected phase with which the car should be charged</description>
<category>Energy</category>
<state min="0" step="1" pattern="%.0f %unit%" readOnly="false"/>
@ -202,19 +190,19 @@
<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>
<category>BatteryLevel</category>
<state min="0" step="1" max="100" pattern="%.0f %unit%" readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="mode">
<item-type>String</item-type>
<label>Charging mode</label>
<label>Charging Mode</label>
<description>Charging mode: "off", "now", "minpv", "pv"</description>
<category>String</category>
<state readOnly="false">
<options>
<option value="off">Off</option>
<option value="now">Now</option>
<option value="now">Fast</option>
<option value="minpv">Min + PV</option>
<option value="pv">Only PV</option>
</options>
@ -223,23 +211,31 @@
</channel-type>
<channel-type id="phases">
<item-type>Number</item-type>
<label>Charging enabled phases</label>
<label>Charging Enabled Phases</label>
<description>The maximum number of phases which can be used</description>
<category>Energy</category>
<state min="0" step="1" max="3" pattern="%d" readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="targetEnergy">
<item-type>Number:Energy</item-type>
<label>Charging Target Energy</label>
<description>Amount of energy to charge the vehicle with</description>
<category>BatteryLevel</category>
<state min="0" pattern="%.0f %unit%" readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="targetSoC">
<item-type>Number:Dimensionless</item-type>
<label>Charging target SoC</label>
<label>Charging Target SoC</label>
<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"/>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="targetTime">
<item-type>DateTime</item-type>
<label>Charging target time</label>
<label>Charging Target Time</label>
<description>When the target SoC should be reached</description>
<category>Time</category>
<state readOnly="false"/>
@ -247,7 +243,7 @@
</channel-type>
<channel-type id="targetTimeEnabled">
<item-type>Switch</item-type>
<label>Charging target time enabled</label>
<label>Charging Target Time Enabled</label>
<description>Target time for charging enabled</description>
<category>Switch</category>
<state readOnly="false">
@ -260,14 +256,14 @@
</channel-type>
<channel-type id="title">
<item-type>String</item-type>
<label>Loadpoint title</label>
<label>Loadpoint Title</label>
<description>Title of loadpoint</description>
<category>Text</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="vehicleConnected">
<item-type>Switch</item-type>
<label>Vehicle connected</label>
<label>Vehicle Connected</label>
<description>Whether vehicle is connected to loadpoint</description>
<category>Switch</category>
<state readOnly="true">
@ -279,28 +275,28 @@
</channel-type>
<channel-type id="vehicleConnectedDuration">
<item-type>Number:Time</item-type>
<label>Vehicle connected duration</label>
<label>Vehicle Connected Duration</label>
<description>Duration the vehicle is connected to loadpoint</description>
<category>Time</category>
<state pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="vehicleCapacity">
<item-type>Number:Energy</item-type>
<label>Vehicle capacity</label>
<label>Vehicle Capacity</label>
<description>Capacity of EV battery</description>
<category>Energy</category>
<state pattern="%.0f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="vehicleOdometer">
<item-type>Number:Length</item-type>
<label>Vehicle odometer</label>
<label>Vehicle Odometer</label>
<description>Total distance travelled by EV</description>
<category></category>
<state pattern="%.1f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="vehiclePresent">
<item-type>Switch</item-type>
<label>Vehicle data access</label>
<label>Vehicle Data Access</label>
<description>Whether evcc is able to get data from vehicle</description>
<category>Switch</category>
<state readOnly="true">
@ -312,7 +308,7 @@
</channel-type>
<channel-type id="vehicleRange">
<item-type>Number:Length</item-type>
<label>Vehicle range</label>
<label>Vehicle Range</label>
<description>Battery range for EV</description>
<category></category>
<state pattern="%.1f %unit%" readOnly="true"/>
@ -321,12 +317,12 @@
<item-type>Number:Dimensionless</item-type>
<label>Vehicle SoC</label>
<description>Current State of Charge of EV</description>
<category>Batterylevel</category>
<category>BatteryLevel</category>
<state pattern="%.0f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="vehicleTitle">
<item-type>String</item-type>
<label>Vehicle title</label>
<label>Vehicle Title</label>
<description>Name of EV</description>
<category>Text</category>
<state readOnly="true"/>