[evcc] fixed channels vehicle/capacity and vehicle/vehicleName, added channels for current Vehicle/HeatingDevice per Loadpoint (#16428)

* removed loadpoint/vehicleCapacity, added vehicle/capacity (bugfix)
implemented currentVehicle / currentHeating per loadpoint (enhancement)
fixed update of channeld vehicleTitle (bugfix)

Signed-off-by: Michael Weger <weger.michael@gmx.net>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
MikeTheTux 2024-03-08 08:44:45 +01:00 committed by Ciprian Pascu
parent 349d34663b
commit d647ce3e3c
7 changed files with 364 additions and 130 deletions

View File

@ -79,7 +79,6 @@ Please note that you have to replace _\<N\>_ with your loadpoint id/number.
| loadpoint\<N\>#title | String | R | Title of loadpoint |
| loadpoint\<N\>#vehicleConnected | Switch | R | Whether vehicle is connected to loadpoint |
| loadpoint\<N\>#vehicleConnectedDuration | Number:Time | R | Duration the vehicle is connected to loadpoint |
| loadpoint\<N\>#vehicleCapacity | Number:Energy | R | Capacity of EV battery |
| loadpoint\<N\>#vehicleOdometer | Number:Length | R | Total distance travelled by EV |
| loadpoint\<N\>#vehiclePresent | Switch | R | Whether evcc is able to get data from vehicle |
| loadpoint\<N\>#vehicleRange | Number:Length | R | Battery range for EV |
@ -105,31 +104,43 @@ Please note that you have to replace _\<N\>_ with your loadpoint id/number.
### Vehicle Channels
Those channels exist per configured vehicle.
Please note that you have to replace _\<ID\>_ with your vehicle id/name.
Those channels exist:
| Channel | Type | Read/Write | Description |
|----------------------------------|----------------------|------------|--------------------------------------------------------------------------|
| vehicle\<ID\>#vehicleTitle | String | R | Title of vehicle |
| vehicle\<ID\>#vehicleMinSoC | Number:Dimensionless | RW | Minimum state of charge (SoC) a vehicle should have |
| vehicle\<ID\>#vehicleLimitSoC | Number:Dimensionless | RW | Until which state of charge (SoC) should the specific vehicle be charged |
| vehicle\<ID\>#vehiclePlanEnabled | Switch | RW | Plan for charging enabled |
| vehicle\<ID\>#vehiclePlanSoC | Number:Dimensionless | RW | Until which state of charge (SoC) should vehicle be charged in plan |
| vehicle\<ID\>#vehiclePlanTime | DateTime | RW | When the plan SoC should be reached |
* 1 per configured loadpoint with `chargerFeatureHeating = false`:
* These channels point to the heating device that is currently active/connected at/to the loadpoint
* Please note that you have to replace _\<N\>_ with your loadpoint id/number
* 1 per configured vehicle:
* Please note that you have to replace _\<ID\>_ with your vehicle id/name
| Channel | Type | Read/Write | Description |
|----------------------------------------------------|----------------------|------------|--------------------------------------------------------------------------|
| [loadpoint\<N\>\|vehicle\<ID\]>#vehicleTitle | String | R | Title of vehicle |
| [loadpoint\<N\>\|vehicle\<ID\]>#vehicleMinSoC | Number:Dimensionless | RW | Minimum state of charge (SoC) a vehicle should have |
| [loadpoint\<N\>\|vehicle\<ID\]>#vehicleLimitSoC | Number:Dimensionless | RW | Until which state of charge (SoC) should the specific vehicle be charged |
| [loadpoint\<N\>\|vehicle\<ID\]>#vehicleCapacity | Number:Energy | R | Capacity of EV battery |
| [loadpoint\<N\>\|vehicle\<ID\]>#vehiclePlanEnabled | Switch | RW | Plan for charging enabled |
| [loadpoint\<N\>\|vehicle\<ID\]>#vehiclePlanSoC | Number:Dimensionless | RW | Until which state of charge (SoC) should vehicle be charged in plan |
| [loadpoint\<N\>\|vehicle\<ID\]>#vehiclePlanTime | DateTime | RW | When the plan SoC should be reached |
### Heating Channels
Those channels exist per configured heating device.
Please note that you have to replace _\<ID\>_ with your heating device id/name.
Those channels exist:
| Channel | Type | Read/Write | Description |
|---------------------------------------|--------------------|------------|-----------------------------------------------------------------------|
| heating\<ID\>#heatingTitle | String | R | Title of heating device |
| heating\<ID\>#heatingMinTemperature | Number:Temperature | RW | Minimum Temperature a heating device should have |
| heating\<ID\>#heatingLimitTemperature | Number:Temperature | RW | Until which Temperature should the specific heating device be charged |
| heating\<ID\>#heatingPlanEnabled | Switch | RW | Plan for charging enabled |
| heating\<ID\>#heatingPlanTemperature | Number:Temperature | RW | Until which Temperature should heating device be charged in plan |
| heating\<ID\>#heatingPlanTime | DateTime | RW | When the plan Temperature should be reached |
* 1 per configured loadpoint with `chargerFeatureHeating = true`:
* These channels point to the heating device that is currently active/connected at/to the loadpoint
* Please note that you have to replace _\<N\>_ with your loadpoint id/number
* 1 per configured heating device:
* Please note that you have to replace _\<ID\>_ with your heating device id/name
| Channel | Type | Read/Write | Description |
|---------------------------------------------------------|--------------------|------------|-----------------------------------------------------------------------|
| [loadpoint\<N\>\|heating\<ID\]>#heatingTitle | String | R | Title of heating device |
| [loadpoint\<N\>\|heating\<ID\]>#heatingMinTemperature | Number:Temperature | RW | Minimum Temperature a heating device should have |
| [loadpoint\<N\>\|heating\<ID\]>#heatingLimitTemperature | Number:Temperature | RW | Until which Temperature should the specific heating device be charged |
| [loadpoint\<N\>\|heating\<ID\]>#heatingCapacity | Number:Energy | R | Capacity of heating device |
| [loadpoint\<N\>\|heating\<ID\]>#heatingPlanEnabled | Switch | RW | Plan for charging enabled |
| [loadpoint\<N\>\|heating\<ID\]>#heatingPlanTemperature | Number:Temperature | RW | Until which Temperature should heating device be charged in plan |
| [loadpoint\<N\>\|heating\<ID\]>#heatingPlanTime | DateTime | RW | When the plan Temperature should be reached |
## Full Example
@ -179,23 +190,23 @@ String evcc_loadpoint0_title "Loadpoint
Switch evcc_loadpoint0_chargerFeatureHeating "Feature: Heating [%s]" <switch> {channel="evcc:device:demo:loadpoint0#chargerFeatureHeating"}
Switch evcc_loadpoint0_chargerFeatureIntegratedDevice "Feature: Integrated Device [%s]" <switch> {channel="evcc:device:demo:loadpoint0#chargerFeatureIntegratedDevice"}
// Vehicle on loadpoint
// Loadpoint vehicle channels
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: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"}
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: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#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:vehicle0#vehiclePlanTime"}
// Vehicle on loadpoint
String evcc_loadpoint0current_vehicleTitle "Vehicle title [%s]" <text> {channel="evcc:device:demo:loadpoint0current#vehicleTitle"}
Number:Dimensionless evcc_loadpoint0current_vehicleMinSoC "Vehicle minimum SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:loadpoint0current#vehicleMinSoC"}
Number:Dimensionless evcc_loadpoint0current_vehicleLimitSoC "Vehicle limit SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:loadpoint0current#vehicleLimitSoC"}
Number:Energy evcc_loadpoint0current_vehicleCapacity "Vehicle capacity [%.0f kWh]" <batterylevel> {channel="evcc:device:demo:loadpoint0current#vehicleCapacity"}
Switch evcc_loadpoint0current_vehiclePlanEnabled "Vehicle plan enabled [%s]" <switch> {channel="evcc:device:demo:loadpoint0current#vehiclePlanEnabled"}
Number:Dimensionless evcc_loadpoint0current_vehiclePlanSoC "Vehicle plan SoC [%d %%]" <batterylevel> {channel="evcc:device:demo:loadpoint0current#vehiclePlanSoC"}
DateTime evcc_loadpoint0current_vehiclePlanTime "Vehicle plan time [%1$td.%1$tm.%1$tY, %1$tH:%1$tM]" <time> {channel="evcc:device:demo:loadpoint0current#vehiclePlanTime"}
```
### Sitemap
@ -230,16 +241,16 @@ sitemap evcc label="evcc Demo" {
Setpoint item=evcc_loadpoint0_phases minValue=1 maxValue=3 step=2
}
Text item=evcc_loadpoint0_vehicleName label="Vehicle" {
Text item=evcc_loadpoint0_vehicleCapacity
Text item=evcc_loadpoint0current_vehicleCapacity
Text item=evcc_loadpoint0_vehicleOdometer
Text item=evcc_loadpoint0_vehicleRange
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
Text item=evcc_loadpoint0current_vehicleTitle
Setpoint item=evcc_loadpoint0current_vehicleMinSoC minValue=0 maxValue=100 step=5
Setpoint item=evcc_loadpoint0current_vehicleLimitSoC minValue=5 maxValue=100 step=5
Switch item=evcc_loadpoint0current_vehiclePlanEnabled
Setpoint item=evcc_loadpoint0current_vehiclePlanSoC minValue=5 maxValue=100 step=5
Input item=evcc_loadpoint0current_vehiclePlanTime
}
}
}

View File

@ -32,6 +32,7 @@ public class EvccBindingConstants {
public static final String CHANNEL_GROUP_ID_LOADPOINT = "loadpoint";
public static final String CHANNEL_GROUP_ID_VEHICLE = "vehicle";
public static final String CHANNEL_GROUP_ID_HEATING = "heating";
public static final String CHANNEL_GROUP_ID_CURRENT = "current";
// List of all Channel ids
public static final String CHANNEL_BATTERY_CAPACITY = "batteryCapacity";
@ -70,7 +71,6 @@ public class EvccBindingConstants {
public static final String CHANNEL_LOADPOINT_EFFECTIVE_LIMIT_SOC = "effectiveLimitSoC";
public static final String CHANNEL_LOADPOINT_EFFECTIVE_LIMIT_TEMPERATURE = "effectiveLimitTemperature";
public static final String CHANNEL_LOADPOINT_TITLE = "title";
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_PRESENT = "vehiclePresent";
public static final String CHANNEL_LOADPOINT_VEHICLE_RANGE = "vehicleRange";
@ -86,6 +86,8 @@ public class EvccBindingConstants {
public static final String CHANNEL_HEATING_MIN_TEMPERATURE = "heatingMinTemperature";
public static final String CHANNEL_VEHICLE_LIMIT_SOC = "vehicleLimitSoC";
public static final String CHANNEL_HEATING_LIMIT_TEMPERATURE = "heatingLimitTemperature";
public static final String CHANNEL_VEHICLE_CAPACITY = "vehicleCapacity";
public static final String CHANNEL_HEATING_CAPACITY = "heatingCapacity";
public static final String CHANNEL_VEHICLE_PLAN_ENABLED = "vehiclePlanEnabled";
public static final String CHANNEL_HEATING_PLAN_ENABLED = "heatingPlanEnabled";
public static final String CHANNEL_VEHICLE_PLAN_SOC = "vehiclePlanSoC";
@ -163,8 +165,6 @@ public class EvccBindingConstants {
BINDING_ID, CHANNEL_LOADPOINT_EFFECTIVE_LIMIT_TEMPERATURE);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_TITLE = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_TITLE);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_CAPACITY = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_VEHICLE_CAPACITY);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_ODOMETER = new ChannelTypeUID(BINDING_ID,
CHANNEL_LOADPOINT_VEHICLE_ODOMETER);
public static final ChannelTypeUID CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_PRESENT = new ChannelTypeUID(BINDING_ID,
@ -194,6 +194,10 @@ public class EvccBindingConstants {
CHANNEL_VEHICLE_LIMIT_SOC);
public static final ChannelTypeUID CHANNEL_TYPE_UID_HEATING_LIMIT_TEMPERATURE = new ChannelTypeUID(BINDING_ID,
CHANNEL_HEATING_LIMIT_TEMPERATURE);
public static final ChannelTypeUID CHANNEL_TYPE_UID_VEHICLE_CAPACITY = new ChannelTypeUID(BINDING_ID,
CHANNEL_VEHICLE_CAPACITY);
public static final ChannelTypeUID CHANNEL_TYPE_UID_HEATING_CAPACITY = new ChannelTypeUID(BINDING_ID,
CHANNEL_HEATING_CAPACITY);
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_HEATING_PLAN_ENABLED = new ChannelTypeUID(BINDING_ID,

View File

@ -50,6 +50,7 @@ import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -72,6 +73,8 @@ public class EvccHandler extends BaseThingHandler {
private boolean gridConfigured = false;
private boolean pvConfigured = false;
private Set<String> vehicleFeatureHeating = new HashSet<String>();
private Set<String> loadpointFeatureHeating = new HashSet<String>();
Map<String, Triple<Boolean, Float, ZonedDateTime>> vehiclePlans = new HashMap<>();
public EvccHandler(Thing thing) {
@ -145,7 +148,8 @@ public class EvccHandler extends BaseThingHandler {
return;
}
}
} else if (groupId.startsWith(CHANNEL_GROUP_ID_LOADPOINT)) {
} else if (groupId.startsWith(CHANNEL_GROUP_ID_LOADPOINT)
&& !groupId.endsWith(CHANNEL_GROUP_ID_CURRENT)) {
int loadpoint = Integer.parseInt(groupId.substring(CHANNEL_GROUP_ID_LOADPOINT.length())) + 1;
switch (channelIdWithoutGroup) {
case CHANNEL_LOADPOINT_MODE -> {
@ -212,13 +216,31 @@ public class EvccHandler extends BaseThingHandler {
return;
}
}
} else if (groupId.startsWith(CHANNEL_GROUP_ID_VEHICLE)
|| groupId.startsWith(CHANNEL_GROUP_ID_HEATING)) {
String vehicleName;
if (groupId.startsWith(CHANNEL_GROUP_ID_VEHICLE)) {
vehicleName = groupId.substring(CHANNEL_GROUP_ID_VEHICLE.length());
} else {
vehicleName = groupId.substring(CHANNEL_GROUP_ID_HEATING.length());
} else if (groupId.startsWith(CHANNEL_GROUP_ID_VEHICLE) || groupId.startsWith(CHANNEL_GROUP_ID_HEATING)
|| (groupId.startsWith(CHANNEL_GROUP_ID_LOADPOINT)
&& groupId.endsWith(CHANNEL_GROUP_ID_CURRENT))) {
String vehicleName = null;
if (groupId.startsWith(CHANNEL_GROUP_ID_VEHICLE) || groupId.startsWith(CHANNEL_GROUP_ID_HEATING)) {
if (groupId.startsWith(CHANNEL_GROUP_ID_VEHICLE)) {
vehicleName = groupId.substring(CHANNEL_GROUP_ID_VEHICLE.length());
} else {
vehicleName = groupId.substring(CHANNEL_GROUP_ID_HEATING.length());
}
} else if (groupId.startsWith(CHANNEL_GROUP_ID_LOADPOINT)
&& groupId.endsWith(CHANNEL_GROUP_ID_CURRENT)) {
final Result result = this.result;
if (result == null) {
return;
}
int loadpointId = Integer.parseInt(groupId.substring(CHANNEL_GROUP_ID_LOADPOINT.length(),
groupId.length() - CHANNEL_GROUP_ID_CURRENT.length()));
Loadpoint loadpoint = result.getLoadpoints()[loadpointId];
vehicleName = loadpoint.getVehicleName();
}
if (vehicleName == null) {
return;
}
switch (channelIdWithoutGroup) {
case CHANNEL_VEHICLE_MIN_SOC -> {
@ -457,10 +479,11 @@ public class EvccHandler extends BaseThingHandler {
if (result == null) {
return;
}
final String channelGroup = CHANNEL_GROUP_ID_LOADPOINT + loadpointId;
final String channelGroup = CHANNEL_GROUP_ID_LOADPOINT + String.valueOf(loadpointId);
Loadpoint loadpoint = result.getLoadpoints()[loadpointId];
boolean chargerFeatureHeating = loadpoint.getChargerFeatureHeating();
String vehicleName = loadpoint.getVehicleName();
createChannel(CHANNEL_LOADPOINT_ACTIVE_PHASES, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_ACTIVE_PHASES,
CoreItemFactory.NUMBER);
@ -494,6 +517,11 @@ public class EvccHandler extends BaseThingHandler {
createChannel(CHANNEL_LOADPOINT_LIMIT_ENERGY, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_LIMIT_ENERGY,
"Number:Energy");
if (chargerFeatureHeating) {
if ((vehicleName != null) && !vehicleName.isBlank()) {
this.vehicleFeatureHeating.add(vehicleName);
}
this.loadpointFeatureHeating.add(channelGroup);
createChannel(CHANNEL_LOADPOINT_LIMIT_TEMPERATURE, channelGroup,
CHANNEL_TYPE_UID_LOADPOINT_LIMIT_TEMPERATURE, "Number:Temperature");
createChannel(CHANNEL_LOADPOINT_EFFECTIVE_LIMIT_TEMPERATURE, channelGroup,
@ -505,6 +533,11 @@ public class EvccHandler extends BaseThingHandler {
removeChannel(CHANNEL_LOADPOINT_EFFECTIVE_LIMIT_SOC, channelGroup);
removeChannel(CHANNEL_LOADPOINT_VEHICLE_SOC, channelGroup);
} else {
if ((vehicleName != null) && !vehicleName.isBlank()) {
this.vehicleFeatureHeating.remove(vehicleName);
}
this.loadpointFeatureHeating.remove(channelGroup);
createChannel(CHANNEL_LOADPOINT_LIMIT_SOC, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_LIMIT_SOC,
"Number:Dimensionless");
createChannel(CHANNEL_LOADPOINT_EFFECTIVE_LIMIT_SOC, channelGroup,
@ -518,8 +551,6 @@ public class EvccHandler extends BaseThingHandler {
}
createChannel(CHANNEL_LOADPOINT_TITLE, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_TITLE, CoreItemFactory.STRING);
createChannel(CHANNEL_LOADPOINT_VEHICLE_CAPACITY, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_CAPACITY,
"Number:Energy");
createChannel(CHANNEL_LOADPOINT_VEHICLE_ODOMETER, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_ODOMETER,
"Number:Length");
createChannel(CHANNEL_LOADPOINT_VEHICLE_PRESENT, channelGroup, CHANNEL_TYPE_UID_LOADPOINT_VEHICLE_PRESENT,
@ -539,12 +570,33 @@ public class EvccHandler extends BaseThingHandler {
removeChannel("targetSoC", channelGroup);
removeChannel("targetTime", channelGroup);
removeChannel("targetTimeEnabled", channelGroup);
removeChannel("vehicleCapacity", channelGroup);
if (vehicleName != null) {
createChannelsVehicle(vehicleName, channelGroup);
}
}
private void createChannelsVehicle(String vehicleName) {
String channelGroup;
if (vehicleFeatureHeating.contains(vehicleName)) {
channelGroup = CHANNEL_GROUP_ID_HEATING + vehicleName;
createChannelsVehicle(vehicleName, null);
}
private void createChannelsVehicle(String vehicleName, @Nullable String loadpointName) {
boolean isHeating;
if (loadpointName == null) {
isHeating = this.vehicleFeatureHeating.contains(vehicleName);
} else {
isHeating = this.loadpointFeatureHeating.contains(loadpointName);
}
if (isHeating) {
String channelGroup;
if (loadpointName == null) {
channelGroup = CHANNEL_GROUP_ID_HEATING + vehicleName;
} else {
channelGroup = loadpointName + CHANNEL_GROUP_ID_CURRENT;
}
createChannel(CHANNEL_HEATING_MIN_TEMPERATURE, channelGroup, CHANNEL_TYPE_UID_HEATING_MIN_TEMPERATURE,
"Number:Temperature");
createChannel(CHANNEL_HEATING_LIMIT_TEMPERATURE, channelGroup, CHANNEL_TYPE_UID_HEATING_LIMIT_TEMPERATURE,
@ -552,6 +604,7 @@ public class EvccHandler extends BaseThingHandler {
createChannel(CHANNEL_HEATING_PLAN_TEMPERATURE, channelGroup, CHANNEL_TYPE_UID_HEATING_PLAN_TEMPERATURE,
"Number:Temperature");
createChannel(CHANNEL_HEATING_TITLE, channelGroup, CHANNEL_TYPE_UID_HEATING_TITLE, CoreItemFactory.STRING);
createChannel(CHANNEL_HEATING_CAPACITY, channelGroup, CHANNEL_TYPE_UID_HEATING_CAPACITY, "Number:Energy");
createChannel(CHANNEL_HEATING_PLAN_TIME, channelGroup, CHANNEL_TYPE_UID_HEATING_PLAN_TIME,
CoreItemFactory.DATETIME);
createChannel(CHANNEL_HEATING_PLAN_ENABLED, channelGroup, CHANNEL_TYPE_UID_HEATING_PLAN_ENABLED,
@ -567,8 +620,15 @@ public class EvccHandler extends BaseThingHandler {
removeChannel(CHANNEL_VEHICLE_PLAN_TIME, channelGroup);
removeChannel(CHANNEL_VEHICLE_PLAN_ENABLED, channelGroup);
removeChannel(CHANNEL_VEHICLE_PLAN_TIME, channelGroup);
removeChannel(CHANNEL_VEHICLE_CAPACITY, channelGroup);
} else {
channelGroup = CHANNEL_GROUP_ID_VEHICLE + vehicleName;
String channelGroup;
if (loadpointName == null) {
channelGroup = CHANNEL_GROUP_ID_VEHICLE + vehicleName;
} else {
channelGroup = loadpointName + CHANNEL_GROUP_ID_CURRENT;
}
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,
@ -576,6 +636,7 @@ public class EvccHandler extends BaseThingHandler {
createChannel(CHANNEL_VEHICLE_PLAN_SOC, channelGroup, CHANNEL_TYPE_UID_VEHICLE_PLAN_SOC,
"Number:Dimensionless");
createChannel(CHANNEL_VEHICLE_TITLE, channelGroup, CHANNEL_TYPE_UID_VEHICLE_TITLE, CoreItemFactory.STRING);
createChannel(CHANNEL_VEHICLE_CAPACITY, channelGroup, CHANNEL_TYPE_UID_VEHICLE_CAPACITY, "Number:Energy");
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,
@ -591,6 +652,7 @@ public class EvccHandler extends BaseThingHandler {
removeChannel(CHANNEL_HEATING_PLAN_TIME, channelGroup);
removeChannel(CHANNEL_HEATING_PLAN_ENABLED, channelGroup);
removeChannel(CHANNEL_HEATING_PLAN_TIME, channelGroup);
removeChannel(CHANNEL_HEATING_CAPACITY, channelGroup);
}
}
@ -752,8 +814,6 @@ public class EvccHandler extends BaseThingHandler {
updateState(channel, new StringType(vehicleName));
if (chargerFeatureHeating) {
vehicleFeatureHeating.add(vehicleName);
float limitSoC = loadpoint.getLimitSoC();
channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_LIMIT_TEMPERATURE);
updateState(channel, new QuantityType<>(limitSoC, SIUnits.CELSIUS));
@ -766,8 +826,6 @@ public class EvccHandler extends BaseThingHandler {
channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_VEHICLE_TEMPERATURE);
updateState(channel, new QuantityType<>(vehicleSoC, SIUnits.CELSIUS));
} else {
vehicleFeatureHeating.remove(vehicleName);
float limitSoC = loadpoint.getLimitSoC();
channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_LIMIT_SOC);
updateState(channel, new QuantityType<>(limitSoC, Units.PERCENT));
@ -785,10 +843,6 @@ public class EvccHandler extends BaseThingHandler {
channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_TITLE);
updateState(channel, new StringType(title));
float vehicleCapacity = loadpoint.getVehicleCapacity();
channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_VEHICLE_CAPACITY);
updateState(channel, new QuantityType<>(vehicleCapacity, Units.KILOWATT_HOUR));
float vehicleOdometer = loadpoint.getVehicleOdometer();
channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_VEHICLE_ODOMETER);
updateState(channel, new QuantityType<>(vehicleOdometer, MetricPrefix.KILO(SIUnits.METRE)));
@ -800,62 +854,124 @@ public class EvccHandler extends BaseThingHandler {
float vehicleRange = loadpoint.getVehicleRange();
channel = new ChannelUID(uid, channelGroup, CHANNEL_LOADPOINT_VEHICLE_RANGE);
updateState(channel, new QuantityType<>(vehicleRange, MetricPrefix.KILO(SIUnits.METRE)));
if (vehicleName != null) {
updateChannelsVehicle(vehicleName, channelGroup);
}
}
private void updateChannelsVehicle(String vehicleName) {
updateChannelsVehicle(vehicleName, null);
}
private void updateChannelsVehicle(String vehicleName, @Nullable String loadpointName) {
final Result result = this.result;
if (result == null) {
return;
}
final ThingUID uid = getThing().getUID();
Vehicle vehicle = result.getVehicles().get(vehicleName);
final String channelGroup;
boolean vehicleFeatureHeating = this.vehicleFeatureHeating.contains(vehicleName);
if (vehicleFeatureHeating) {
channelGroup = CHANNEL_GROUP_ID_HEATING + vehicleName;
float minSoC = vehicle.getMinSoC();
ChannelUID channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_MIN_TEMPERATURE);
updateState(channel, new QuantityType<>(minSoC, SIUnits.CELSIUS));
float limitSoC = vehicle.getLimitSoC();
channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_LIMIT_TEMPERATURE);
updateState(channel, new QuantityType<>(limitSoC, SIUnits.CELSIUS));
String title = vehicle.getTitle();
channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_TITLE);
updateState(channel, new StringType(title));
boolean isHeating;
if (loadpointName == null) {
isHeating = this.vehicleFeatureHeating.contains(vehicleName);
} else {
channelGroup = CHANNEL_GROUP_ID_VEHICLE + vehicleName;
float minSoC = vehicle.getMinSoC();
ChannelUID 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));
String title = vehicle.getTitle();
channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_TITLE);
updateState(channel, new StringType(title));
isHeating = this.loadpointFeatureHeating.contains(loadpointName);
}
Vehicle vehicle = null;
if (!vehicleName.isBlank()) {
vehicle = result.getVehicles().get(vehicleName);
}
Plan plan = vehicle.getPlan();
String channelGroup;
if (isHeating) {
if (loadpointName == null) {
channelGroup = CHANNEL_GROUP_ID_HEATING + vehicleName;
} else {
channelGroup = loadpointName + CHANNEL_GROUP_ID_CURRENT;
}
if (vehicle == null) {
ChannelUID channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_MIN_TEMPERATURE);
updateState(channel, UnDefType.UNDEF);
channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_LIMIT_TEMPERATURE);
updateState(channel, UnDefType.UNDEF);
channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_TITLE);
updateState(channel, UnDefType.UNDEF);
channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_CAPACITY);
updateState(channel, UnDefType.UNDEF);
} else {
float minSoC = vehicle.getMinSoC();
ChannelUID channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_MIN_TEMPERATURE);
updateState(channel, new QuantityType<>(minSoC, SIUnits.CELSIUS));
float limitSoC = vehicle.getLimitSoC();
channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_LIMIT_TEMPERATURE);
updateState(channel, new QuantityType<>(limitSoC, SIUnits.CELSIUS));
String title = vehicle.getTitle();
channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_TITLE);
updateState(channel, new StringType(title));
float capacity = vehicle.getCapacity();
channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_CAPACITY);
updateState(channel, new QuantityType<>(capacity, Units.KILOWATT_HOUR));
}
} else {
if (loadpointName == null) {
channelGroup = CHANNEL_GROUP_ID_VEHICLE + vehicleName;
} else {
channelGroup = loadpointName + CHANNEL_GROUP_ID_CURRENT;
}
if (vehicle == null) {
ChannelUID channel = new ChannelUID(uid, channelGroup, CHANNEL_VEHICLE_MIN_SOC);
updateState(channel, UnDefType.UNDEF);
channel = new ChannelUID(uid, channelGroup, CHANNEL_VEHICLE_LIMIT_SOC);
updateState(channel, UnDefType.UNDEF);
channel = new ChannelUID(uid, channelGroup, CHANNEL_VEHICLE_TITLE);
updateState(channel, UnDefType.UNDEF);
channel = new ChannelUID(uid, channelGroup, CHANNEL_VEHICLE_CAPACITY);
updateState(channel, UnDefType.UNDEF);
} else {
float minSoC = vehicle.getMinSoC();
ChannelUID 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));
String title = vehicle.getTitle();
channel = new ChannelUID(uid, channelGroup, CHANNEL_VEHICLE_TITLE);
updateState(channel, new StringType(title));
float capacity = vehicle.getCapacity();
channel = new ChannelUID(uid, channelGroup, CHANNEL_VEHICLE_CAPACITY);
updateState(channel, new QuantityType<>(capacity, Units.KILOWATT_HOUR));
}
}
Plan plan = null;
if (vehicle != null) {
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, vehicleFeatureHeating);
updateVehiclePlanChannel(uid, vehicleName, channelGroup, isHeating);
}
private void updateVehiclePlanChannel(String vehicleName, ThingUID uid, String channelGroup,
boolean vehicleFeatureHeating) {
private void updateVehiclePlanChannel(ThingUID uid, String vehicleName, String channelGroup, boolean isHeating) {
Triple<Boolean, Float, ZonedDateTime> planValues = vehiclePlans.get(vehicleName);
if (vehicleFeatureHeating) {
if (isHeating) {
ChannelUID channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_PLAN_ENABLED);
updateState(channel, planValues.getLeft() ? OnOffType.ON : OnOffType.OFF);
channel = new ChannelUID(uid, channelGroup, CHANNEL_HEATING_PLAN_TEMPERATURE);

View File

@ -82,9 +82,6 @@ public class Loadpoint {
@SerializedName("title")
private String title;
@SerializedName("vehicleCapacity")
private float vehicleCapacity;
@SerializedName("vehicleOdometer")
private float vehicleOdometer;
@ -242,13 +239,6 @@ public class Loadpoint {
return title;
}
/**
* @return vehicle's capacity
*/
public float getVehicleCapacity() {
return vehicleCapacity;
}
/**
* @return vehicle's odometer
*/

View File

@ -33,6 +33,9 @@ public class Vehicle {
@SerializedName("limitSoc")
private float limitSoC;
@SerializedName("capacity")
private float capacity;
@SerializedName("plans")
private Plan[] plans;
@ -57,6 +60,13 @@ public class Vehicle {
return limitSoC;
}
/**
* @return vehicle's capacity
*/
public float getCapacity() {
return capacity;
}
/**
* @return current plan for vehicle
*/

View File

@ -18,12 +18,33 @@ 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.loadpoint.label = Loadpoint
channel-group-type.evcc.loadpoint0.label = Loadpoint 0
channel-group-type.evcc.loadpoint0current.label = Loadpoint 0: Current
channel-group-type.evcc.loadpoint1.label = Loadpoint 1
channel-group-type.evcc.loadpoint1current.label = Loadpoint 1: Current
channel-group-type.evcc.loadpoint2.label = Loadpoint 2
channel-group-type.evcc.loadpoint2current.label = Loadpoint 2: Current
channel-group-type.evcc.loadpoint3.label = Loadpoint 3
channel-group-type.evcc.loadpoint3current.label = Loadpoint 3: Current
channel-group-type.evcc.loadpoint4.label = Loadpoint 4
channel-group-type.evcc.loadpoint4current.label = Loadpoint 4: Current
channel-group-type.evcc.loadpoint5.label = Loadpoint 5
channel-group-type.evcc.loadpoint5current.label = Loadpoint 5: Current
channel-group-type.evcc.loadpoint6.label = Loadpoint 6
channel-group-type.evcc.loadpoint6current.label = Loadpoint 6: Current
channel-group-type.evcc.loadpoint7.label = Loadpoint 7
channel-group-type.evcc.loadpoint7current.label = Loadpoint 7: Current
channel-group-type.evcc.loadpoint8.label = Loadpoint 8
channel-group-type.evcc.loadpoint8current.label = Loadpoint 8: Current
channel-group-type.evcc.loadpoint9.label = Loadpoint 9
channel-group-type.evcc.loadpoint9current.label = Loadpoint 9: Current
# channel types
channel-type.evcc.activePhases.label = Charging Active Phases
channel-type.evcc.activePhases.description = Current number of active phases while charging
channel-type.evcc.availableVersion.label = Available Version
channel-type.evcc.availableVersion.description = Available evcc update version
channel-type.evcc.batteryCapacity.label = Battery Capacity
channel-type.evcc.batteryCapacity.description = Capacity of (home) battery
channel-type.evcc.batteryDischargeControl.label = Battery Discharge Control
@ -64,7 +85,7 @@ 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.effectiveLimitSoC.label = Effective Charging Limit SoC
channel-type.evcc.effectiveLimitSoC.label = Effective Charging Limit
channel-type.evcc.effectiveLimitSoC.description = Effective state of charge (SoC) until which the vehicle will be charged
channel-type.evcc.effectiveLimitTemperature.label = Effective Charging Limit Temperature
channel-type.evcc.effectiveLimitTemperature.description = Effective Temperature until which the heating device will be charged
@ -74,7 +95,9 @@ 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.heatingLimitTemperature.label = Heating Charging Limit Temperature
channel-type.evcc.heatingCapacity.label = Heating Capacity
channel-type.evcc.heatingCapacity.description = Capacity of heating device
channel-type.evcc.heatingLimitTemperature.label = Charging Temperature Limit
channel-type.evcc.heatingLimitTemperature.description = Until which Temperature should the specific heating device be charged
channel-type.evcc.heatingMinTemperature.label = Heating Min Temperature
channel-type.evcc.heatingMinTemperature.description = Minimum Temperature a heating device should have
@ -152,6 +175,12 @@ channel-type.evcc.vehicleTemperature.label = Temperature
channel-type.evcc.vehicleTemperature.description = Current Temperature of the heating device
channel-type.evcc.vehicleTitle.label = Vehicle Title
channel-type.evcc.vehicleTitle.description = Title of vehicle
channel-type.evcc.version.label = Version
channel-type.evcc.version.description = Current evcc version
# channel group types
channel-group-type.evcc.loadpoint.label = Loadpoint
# channel types

View File

@ -11,16 +11,26 @@
<channel-groups>
<channel-group id="general" typeId="general"/>
<channel-group id="loadpoint0" typeId="loadpoint"/>
<channel-group id="loadpoint1" typeId="loadpoint"/>
<channel-group id="loadpoint2" typeId="loadpoint"/>
<channel-group id="loadpoint3" typeId="loadpoint"/>
<channel-group id="loadpoint4" typeId="loadpoint"/>
<channel-group id="loadpoint5" typeId="loadpoint"/>
<channel-group id="loadpoint6" typeId="loadpoint"/>
<channel-group id="loadpoint7" typeId="loadpoint"/>
<channel-group id="loadpoint8" typeId="loadpoint"/>
<channel-group id="loadpoint9" typeId="loadpoint"/>
<channel-group id="loadpoint0" typeId="loadpoint0"/>
<channel-group id="loadpoint1" typeId="loadpoint1"/>
<channel-group id="loadpoint2" typeId="loadpoint2"/>
<channel-group id="loadpoint3" typeId="loadpoint3"/>
<channel-group id="loadpoint4" typeId="loadpoint4"/>
<channel-group id="loadpoint5" typeId="loadpoint5"/>
<channel-group id="loadpoint6" typeId="loadpoint6"/>
<channel-group id="loadpoint7" typeId="loadpoint7"/>
<channel-group id="loadpoint8" typeId="loadpoint8"/>
<channel-group id="loadpoint9" typeId="loadpoint9"/>
<channel-group id="loadpoint0current" typeId="loadpoint0current"/>
<channel-group id="loadpoint1current" typeId="loadpoint1current"/>
<channel-group id="loadpoint2current" typeId="loadpoint2current"/>
<channel-group id="loadpoint3current" typeId="loadpoint3current"/>
<channel-group id="loadpoint4current" typeId="loadpoint4current"/>
<channel-group id="loadpoint5current" typeId="loadpoint5current"/>
<channel-group id="loadpoint6current" typeId="loadpoint6current"/>
<channel-group id="loadpoint7current" typeId="loadpoint7current"/>
<channel-group id="loadpoint8current" typeId="loadpoint8current"/>
<channel-group id="loadpoint9current" typeId="loadpoint9current"/>
</channel-groups>
<config-description>
@ -41,8 +51,65 @@
<channel-group-type id="general">
<label>General Data</label>
</channel-group-type>
<channel-group-type id="loadpoint">
<label>Loadpoint</label>
<channel-group-type id="loadpoint0">
<label>Loadpoint 0</label>
</channel-group-type>
<channel-group-type id="loadpoint1">
<label>Loadpoint 1</label>
</channel-group-type>
<channel-group-type id="loadpoint2">
<label>Loadpoint 2</label>
</channel-group-type>
<channel-group-type id="loadpoint3">
<label>Loadpoint 3</label>
</channel-group-type>
<channel-group-type id="loadpoint4">
<label>Loadpoint 4</label>
</channel-group-type>
<channel-group-type id="loadpoint5">
<label>Loadpoint 5</label>
</channel-group-type>
<channel-group-type id="loadpoint6">
<label>Loadpoint 6</label>
</channel-group-type>
<channel-group-type id="loadpoint7">
<label>Loadpoint 7</label>
</channel-group-type>
<channel-group-type id="loadpoint8">
<label>Loadpoint 8</label>
</channel-group-type>
<channel-group-type id="loadpoint9">
<label>Loadpoint 9</label>
</channel-group-type>
<channel-group-type id="loadpoint0current">
<label>Loadpoint 0: Current</label>
</channel-group-type>
<channel-group-type id="loadpoint1current">
<label>Loadpoint 1: Current</label>
</channel-group-type>
<channel-group-type id="loadpoint2current">
<label>Loadpoint 2: Current</label>
</channel-group-type>
<channel-group-type id="loadpoint3current">
<label>Loadpoint 3: Current</label>
</channel-group-type>
<channel-group-type id="loadpoint4current">
<label>Loadpoint 4: Current</label>
</channel-group-type>
<channel-group-type id="loadpoint5current">
<label>Loadpoint 5: Current</label>
</channel-group-type>
<channel-group-type id="loadpoint6current">
<label>Loadpoint 6: Current</label>
</channel-group-type>
<channel-group-type id="loadpoint7current">
<label>Loadpoint 7: Current</label>
</channel-group-type>
<channel-group-type id="loadpoint8current">
<label>Loadpoint 8: Current</label>
</channel-group-type>
<channel-group-type id="loadpoint9current">
<label>Loadpoint 9: Current</label>
</channel-group-type>
<!-- Units and description on: https://docs.evcc.io/docs/reference/configuration/messaging/#msg -->
@ -332,13 +399,6 @@
<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>
<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>
@ -459,6 +519,20 @@
<state min="0" step="1" max="100" pattern="%.0f %unit%" readOnly="false"/>
<autoUpdatePolicy>veto</autoUpdatePolicy>
</channel-type>
<channel-type id="vehicleCapacity">
<item-type>Number:Energy</item-type>
<label>Vehicle Capacity</label>
<description>Capacity of EV battery</description>
<category>Energy</category>
<state pattern="%.0f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="heatingCapacity">
<item-type>Number:Energy</item-type>
<label>Heating Capacity</label>
<description>Capacity of heating device</description>
<category>Energy</category>
<state pattern="%.0f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="vehiclePlanEnabled">
<item-type>Switch</item-type>
<label>Vehicle Plan Enabled</label>