[goecharger] Add API V2 support (#12400)
* add API V2 support * handle InterrupedException explicitly Signed-off-by: Reinhard Plaim <reinhardplaim@gmail.com>
This commit is contained in:
parent
378a037df9
commit
ba03fef082
|
@ -2,10 +2,12 @@
|
||||||
|
|
||||||
This Binding controls and reads data from the [Go-eCharger](https://go-e.co/).
|
This Binding controls and reads data from the [Go-eCharger](https://go-e.co/).
|
||||||
It is a mobile wallbox for charging EVs and has an open REST API for reading data and configuration.
|
It is a mobile wallbox for charging EVs and has an open REST API for reading data and configuration.
|
||||||
|
The API must be activated in the Go-eCharger app.
|
||||||
|
|
||||||
## Supported Things
|
## Supported Things
|
||||||
|
|
||||||
This binding supports Go-eCharger HOME+ with 7.4kW or 22kW.
|
This binding supports Go-eCharger HOME+ with 7.4kW, 11kW or 22kW.
|
||||||
|
The Go-eCharger HOMEfix with 11kW and 22kW is supported too.
|
||||||
|
|
||||||
## Thing Configuration
|
## Thing Configuration
|
||||||
|
|
||||||
|
@ -14,34 +16,41 @@ The thing has two configuration parameters:
|
||||||
| Parameter | Description | Required |
|
| Parameter | Description | Required |
|
||||||
|-----------------|-----------------------------------------------|----------|
|
|-----------------|-----------------------------------------------|----------|
|
||||||
| ip | The IP-address of your Go-eCharger | yes |
|
| ip | The IP-address of your Go-eCharger | yes |
|
||||||
|
| apiVersion | The API version to use (1=default or 2) | no |
|
||||||
| refreshInterval | Interval to read data, default 5 (in seconds) | no |
|
| refreshInterval | Interval to read data, default 5 (in seconds) | no |
|
||||||
|
|
||||||
|
The apiVersion 2 is only available for Go-eCharger with new hardware revision (CM-03).
|
||||||
|
|
||||||
## Channels
|
## Channels
|
||||||
|
|
||||||
Currently available channels are
|
Currently available channels are
|
||||||
| Channel ID | Item Type | Description |
|
| Channel ID | Item Type | Description | API version |
|
||||||
|--------------------------|--------------------------|---------------------------------------------------------------|
|
|--------------------------|--------------------------|---------------------------------------------------------------|-------------------|
|
||||||
| maxCurrent | Number:ElectricCurrent | Maximum current allowed to use for charging |
|
| maxCurrent | Number:ElectricCurrent | Maximum current allowed to use for charging | 1 (r/w), 2 (r/w) |
|
||||||
| pwmSignal | String | Signal status for PWM signal |
|
| maxCurrentTemp | Number:ElectricCurrent | Maximum current temporary (not written to EEPROM) | 1 (r) |
|
||||||
| error | String | Error code of charger |
|
| pwmSignal | String | Signal status for PWM signal | 1 (r), 2 (r) |
|
||||||
| voltageL1 | Number:ElectricPotential | Voltage on L1 |
|
| error | String | Error code of charger | 1 (r), 2 (r) |
|
||||||
| voltageL2 | Number:ElectricPotential | Voltage on L2 |
|
| voltageL1 | Number:ElectricPotential | Voltage on L1 | 1 (r), 2 (r) |
|
||||||
| voltageL3 | Number:ElectricPotential | Voltage on L3 |
|
| voltageL2 | Number:ElectricPotential | Voltage on L2 | 1 (r), 2 (r) |
|
||||||
| currentL1 | Number:ElectricCurrent | Current on L1 |
|
| voltageL3 | Number:ElectricPotential | Voltage on L3 | 1 (r), 2 (r) |
|
||||||
| currentL2 | Number:ElectricCurrent | Current on L2 |
|
| currentL1 | Number:ElectricCurrent | Current on L1 | 1 (r), 2 (r) |
|
||||||
| currentL3 | Number:ElectricCurrent | Current on L3 |
|
| currentL2 | Number:ElectricCurrent | Current on L2 | 1 (r), 2 (r) |
|
||||||
| powerL1 | Number:Power | Power on L1 |
|
| currentL3 | Number:ElectricCurrent | Current on L3 | 1 (r), 2 (r) |
|
||||||
| powerL2 | Number:Power | Power on L2 |
|
| powerL1 | Number:Power | Power on L1 | 1 (r), 2 (r) |
|
||||||
| powerL3 | Number:Power | Power on L2 |
|
| powerL2 | Number:Power | Power on L2 | 1 (r), 2 (r) |
|
||||||
| phases | Number | Amount of phases currently used for charging |
|
| powerL3 | Number:Power | Power on L2 | 1 (r), 2 (r) |
|
||||||
| sessionChargeEnergyLimit | Number:Energy | Wallbox stops charging after defined value, disable with 0 |
|
| powerAll | Number:Power | Power over all three phases | 1 (r), 2 (r) |
|
||||||
| sessionChargedEnergy | Number:Energy | Amount of energy that has been charged in this session |
|
| phases | Number | Amount of phases currently used for charging | 1 (r), 2 (r/w) |
|
||||||
| totalChargedEnergy | Number:Energy | Amount of energy that has been charged since installation |
|
| sessionChargeEnergyLimit | Number:Energy | Wallbox stops charging after defined value, disable with 0 | 1 (r/w), 2 (r/w) |
|
||||||
| allowCharging | Switch | If `ON` charging is allowed |
|
| sessionChargedEnergy | Number:Energy | Amount of energy that has been charged in this session | 1 (r), 2 (r) |
|
||||||
| cableCurrent | Number:ElectricCurrent | Specifies the max current that can be charged with that cable |
|
| totalChargedEnergy | Number:Energy | Amount of energy that has been charged since installation | 1 (r), 2 (r) |
|
||||||
| temperature | Number:Temperature | Temperature of the Go-eCharger |
|
| allowCharging | Switch | If `ON` charging is allowed | 1 (r/w), 2 (r) |
|
||||||
| firmware | String | Firmware Version |
|
| cableCurrent | Number:ElectricCurrent | Specifies the max current that can be charged with that cable | 1 (r), 2 (r) |
|
||||||
| accessConfiguration | String | Access configuration, for example OPEN, RFID ... |
|
| temperature | Number:Temperature | Temperature of the curciuit board of the Go-eCharger | 1 (r), 2 (r) |
|
||||||
|
| temperatureType2Port | Number:Temperature | Temperature of the type 2 port of the Go-eCharger | 2 (r) |
|
||||||
|
| firmware | String | Firmware Version | 1 (r), 2 (r) |
|
||||||
|
| accessConfiguration | String | Access configuration, for example OPEN, RFID ... | 1 (r/w) |
|
||||||
|
| forceState | Number | Force state (Neutral=0, Off=1, On=2) | 2 (r/w) |
|
||||||
|
|
||||||
## Full Example
|
## Full Example
|
||||||
|
|
||||||
|
@ -55,6 +64,9 @@ demo.items
|
||||||
|
|
||||||
```
|
```
|
||||||
Number:ElectricCurrent GoEChargerMaxCurrent "Maximum current" {channel="goecharger:goe:garage:maxCurrent"}
|
Number:ElectricCurrent GoEChargerMaxCurrent "Maximum current" {channel="goecharger:goe:garage:maxCurrent"}
|
||||||
|
Number:ElectricCurrent GoEChargerMaxCurrentTemp "Maximum current temporary" {channel="goecharger:goe:garage:maxCurrentTemp"}
|
||||||
|
Number GoEChargerForceState "Force state" {channel="goecharger:goe:garage:forceState"}
|
||||||
|
Number GoEChargerPhases "Phases" {channel="goecharger:goe:garage:phases"}
|
||||||
String GoEChargerPwmSignal "Pwm signal status" {channel="goecharger:goe:garage:pwmSignal"}
|
String GoEChargerPwmSignal "Pwm signal status" {channel="goecharger:goe:garage:pwmSignal"}
|
||||||
String GoEChargerError "Error code" {channel="goecharger:goe:garage:error"}
|
String GoEChargerError "Error code" {channel="goecharger:goe:garage:error"}
|
||||||
Number:ElectricPotential GoEChargerVoltageL1 "Voltage l1" {channel="goecharger:goe:garage:voltageL1"}
|
Number:ElectricPotential GoEChargerVoltageL1 "Voltage l1" {channel="goecharger:goe:garage:voltageL1"}
|
||||||
|
@ -66,13 +78,14 @@ Number:ElectricCurrent GoEChargerCurrentL3 "Current l3"
|
||||||
Number:Power GoEChargerPowerL1 "Power l1" {channel="goecharger:goe:garage:powerL1"}
|
Number:Power GoEChargerPowerL1 "Power l1" {channel="goecharger:goe:garage:powerL1"}
|
||||||
Number:Power GoEChargerPowerL2 "Power l2" {channel="goecharger:goe:garage:powerL2"}
|
Number:Power GoEChargerPowerL2 "Power l2" {channel="goecharger:goe:garage:powerL2"}
|
||||||
Number:Power GoEChargerPowerL3 "Power l3" {channel="goecharger:goe:garage:powerL3"}
|
Number:Power GoEChargerPowerL3 "Power l3" {channel="goecharger:goe:garage:powerL3"}
|
||||||
Number GoEChargerPhases "Phases" {channel="goecharger:goe:garage:phases"}
|
Number:Power GoEChargerPowerAll "Power over All" {channel="goecharger:goe:garage:powerAll"}
|
||||||
Number:Energy GoEChargerSessionChargeEnergyLimit "Current session charge energy limit" {channel="goecharger:goe:garage:sessionChargeEnergyLimit"}
|
Number:Energy GoEChargerSessionChargeEnergyLimit "Current session charge energy limit" {channel="goecharger:goe:garage:sessionChargeEnergyLimit"}
|
||||||
Number:Energy GoEChargerSessionChargedEnergy "Current session charged energy" {channel="goecharger:goe:garage:sessionChargedEnergy"}
|
Number:Energy GoEChargerSessionChargedEnergy "Current session charged energy" {channel="goecharger:goe:garage:sessionChargedEnergy"}
|
||||||
Number:Energy GoEChargerTotalChargedEnergy "Total charged energy" {channel="goecharger:goe:garage:totalChargedEnergy"}
|
Number:Energy GoEChargerTotalChargedEnergy "Total charged energy" {channel="goecharger:goe:garage:totalChargedEnergy"}
|
||||||
Switch GoEChargerAllowCharging "Allow charging" {channel="goecharger:goe:garage:allowCharging"}
|
Switch GoEChargerAllowCharging "Allow charging" {channel="goecharger:goe:garage:allowCharging"}
|
||||||
Number:ElectricCurrent GoEChargerCableCurrent "Cable encoding" {channel="goecharger:goe:garage:cableCurrent"}
|
Number:ElectricCurrent GoEChargerCableCurrent "Cable encoding" {channel="goecharger:goe:garage:cableCurrent"}
|
||||||
Number:Temperature GoEChargerTemperature "Temperature" {channel="goecharger:goe:garage:temperature"}
|
Number:Temperature GoEChargerTemperatureType2Port "Temperature type 2 port" {channel="goecharger:goe:garage:temperatureType2Port"}
|
||||||
|
Number:Temperature GoEChargerTemperatureCircuitBoard "Temperature circuit board" {channel="goecharger:goe:garage:temperature"}
|
||||||
String GoEChargerFirmware "Firmware" {channel="goecharger:goe:garage:firmware"}
|
String GoEChargerFirmware "Firmware" {channel="goecharger:goe:garage:firmware"}
|
||||||
String GoEChargerAccessConfiguration "Access configuration" {channel="goecharger:goe:garage:accessConfiguration"}
|
String GoEChargerAccessConfiguration "Access configuration" {channel="goecharger:goe:garage:accessConfiguration"}
|
||||||
```
|
```
|
||||||
|
@ -88,9 +101,86 @@ when
|
||||||
Item availablePVCurrent received update
|
Item availablePVCurrent received update
|
||||||
then
|
then
|
||||||
logInfo("Amps available: ", receivedCommand.state)
|
logInfo("Amps available: ", receivedCommand.state)
|
||||||
GoEChargerMaxCurrent.sendCommand(receivedCommand.state)
|
GoEChargerMaxCurrentTemp.sendCommand(receivedCommand.state)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Advanced example:
|
||||||
|
```
|
||||||
|
rule "Set charging limit for go-eCharger"
|
||||||
|
when
|
||||||
|
Time cron "*/10 * * ? * *" // Trigger every 10 seconds
|
||||||
|
then
|
||||||
|
if (GoEChargerExcessCharge.state == ON) {
|
||||||
|
var totalPowerOutputInWatt = Total_power_fast.state as DecimalType * 1000
|
||||||
|
if (totalPowerOutputInWatt > 0) {
|
||||||
|
totalPowerOutputInWatt = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
totalPowerOutputInWatt = totalPowerOutputInWatt * -1
|
||||||
|
|
||||||
|
var maxAmp3Phases = (totalPowerOutputInWatt / 3) / 230
|
||||||
|
if (maxAmp3Phases > 16.0) {
|
||||||
|
maxAmp3Phases = 16.0
|
||||||
|
}
|
||||||
|
var maxAmp1Phase = totalPowerOutputInWatt / 230;
|
||||||
|
|
||||||
|
if (maxAmp3Phases.intValue >= 6) {
|
||||||
|
// set force state to neutral (Neutral=0, Off=1, On=2)
|
||||||
|
if (GoEChargerForceState.state != 0) {
|
||||||
|
GoEChargerForceState.sendCommand(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3 phases
|
||||||
|
if ((GoEChargerPhases.state as Number) != 3) {
|
||||||
|
GoEChargerPhases.sendCommand(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((GoEChargerMaxCurrent.state as Number).intValue != maxAmp3Phases.intValue) {
|
||||||
|
GoEChargerMaxCurrent.sendCommand(maxAmp3Phases.intValue)
|
||||||
|
// logInfo("eCharger", "Set charging limit 3 Phases: " + maxAmp3Phases.intValue + " A")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (maxAmp1Phase.intValue >= 6 ) {
|
||||||
|
// set force state to neutral (Neutral=0, Off=1, On=2)
|
||||||
|
if (GoEChargerForceState.state != 0) {
|
||||||
|
GoEChargerForceState.sendCommand(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch to 1 phase -> check if this is useful
|
||||||
|
if ((GoEChargerPhases.state as Number) != 1) {
|
||||||
|
GoEChargerPhases.sendCommand(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((GoEChargerMaxCurrent.state as Number).intValue != maxAmp1Phase.intValue) {
|
||||||
|
GoEChargerMaxCurrent.sendCommand(maxAmp1Phase.intValue)
|
||||||
|
// logInfo("eCharger", "Set charging limit 1 Phase: " + maxAmp1Phase.intValue + " A")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// switch off
|
||||||
|
if (GoEChargerForceState.state != 1) {
|
||||||
|
GoEChargerForceState.sendCommand(1);
|
||||||
|
// logInfo("eCharger", "Switch charging off")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// set force state to neutral (Neutral=0, Off=1, On=2)
|
||||||
|
if (GoEChargerForceState.state != 0) {
|
||||||
|
GoEChargerForceState.sendCommand(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((GoEChargerPhases.state as Number) != 3) {
|
||||||
|
GoEChargerPhases.sendCommand(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((GoEChargerMaxCurrent.state as Number).intValue != 16) {
|
||||||
|
GoEChargerMaxCurrent.sendCommand(16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
You can also define more advanced rules if you have multiple cars that charge with a different amount of phases.
|
You can also define more advanced rules if you have multiple cars that charge with a different amount of phases.
|
||||||
For example if your car charges on one phase only, you can set maxAmps to output of PV power, if your car charges on two phases you can set maxAmps to `pv output / 2`, and for 3 phases `pv output / 3`.
|
For example if your car charges on one phase only, you can set maxAmps to output of PV power, if your car charges on two phases you can set maxAmps to `pv output / 2`, and for 3 phases `pv output / 3`.
|
||||||
In general the calculation would be ´maxAmps = pvOutput / phases`.
|
In general the calculation would be ´maxAmps = pvOutput / phases`.
|
||||||
|
|
|
@ -31,6 +31,7 @@ public class GoEChargerBindingConstants {
|
||||||
|
|
||||||
// List of all Channel ids
|
// List of all Channel ids
|
||||||
public static final String MAX_CURRENT = "maxCurrent";
|
public static final String MAX_CURRENT = "maxCurrent";
|
||||||
|
public static final String MAX_CURRENT_TEMPORARY = "maxCurrentTemporary";
|
||||||
public static final String ACCESS_CONFIGURATION = "accessConfiguration";
|
public static final String ACCESS_CONFIGURATION = "accessConfiguration";
|
||||||
public static final String PWM_SIGNAL = "pwmSignal";
|
public static final String PWM_SIGNAL = "pwmSignal";
|
||||||
public static final String ERROR = "error";
|
public static final String ERROR = "error";
|
||||||
|
@ -43,10 +44,12 @@ public class GoEChargerBindingConstants {
|
||||||
public static final String POWER_L1 = "powerL1";
|
public static final String POWER_L1 = "powerL1";
|
||||||
public static final String POWER_L2 = "powerL2";
|
public static final String POWER_L2 = "powerL2";
|
||||||
public static final String POWER_L3 = "powerL3";
|
public static final String POWER_L3 = "powerL3";
|
||||||
|
public static final String POWER_ALL = "powerAll";
|
||||||
public static final String ALLOW_CHARGING = "allowCharging";
|
public static final String ALLOW_CHARGING = "allowCharging";
|
||||||
public static final String CABLE_ENCODING = "cableCurrent";
|
public static final String CABLE_ENCODING = "cableCurrent";
|
||||||
public static final String PHASES = "phases";
|
public static final String PHASES = "phases";
|
||||||
public static final String TEMPERATURE = "temperature";
|
public static final String TEMPERATURE_TYPE2_PORT = "temperatureType2Port";
|
||||||
|
public static final String TEMPERATURE_CIRCUIT_BOARD = "temperature";
|
||||||
public static final String SESSION_CHARGE_CONSUMPTION = "sessionChargedEnergy";
|
public static final String SESSION_CHARGE_CONSUMPTION = "sessionChargedEnergy";
|
||||||
public static final String SESSION_CHARGE_CONSUMPTION_LIMIT = "sessionChargeEnergyLimit";
|
public static final String SESSION_CHARGE_CONSUMPTION_LIMIT = "sessionChargeEnergyLimit";
|
||||||
public static final String TOTAL_CONSUMPTION = "totalChargedEnergy";
|
public static final String TOTAL_CONSUMPTION = "totalChargedEnergy";
|
||||||
|
@ -54,4 +57,10 @@ public class GoEChargerBindingConstants {
|
||||||
|
|
||||||
public static final String API_URL = "http://%IP%/status";
|
public static final String API_URL = "http://%IP%/status";
|
||||||
public static final String MQTT_URL = "http://%IP%/mqtt?payload=%KEY%=%VALUE%";
|
public static final String MQTT_URL = "http://%IP%/mqtt?payload=%KEY%=%VALUE%";
|
||||||
|
|
||||||
|
// API v2 only
|
||||||
|
public static final String FORCE_STATE = "forceState";
|
||||||
|
|
||||||
|
public static final String API_URL_V2 = "http://%IP%/api/status";
|
||||||
|
public static final String SET_URL_V2 = "http://%IP%/api/set?%KEY%=%VALUE%";
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,12 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||||
* The {@link GoEChargerConfiguration} class contains fields mapping thing configuration parameters.
|
* The {@link GoEChargerConfiguration} class contains fields mapping thing configuration parameters.
|
||||||
*
|
*
|
||||||
* @author Samuel Brucksch - Initial contribution
|
* @author Samuel Brucksch - Initial contribution
|
||||||
|
* @author Reinhard Plaim - Add apiVersion
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class GoEChargerConfiguration {
|
public class GoEChargerConfiguration {
|
||||||
|
|
||||||
public @Nullable String ip;
|
public @Nullable String ip;
|
||||||
public Integer refreshInterval = 5;
|
public Integer refreshInterval = 5;
|
||||||
|
public Integer apiVersion = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.eclipse.jetty.client.HttpClient;
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
import org.openhab.binding.goecharger.internal.handler.GoEChargerHandler;
|
import org.openhab.binding.goecharger.internal.handler.GoEChargerHandler;
|
||||||
|
import org.openhab.binding.goecharger.internal.handler.GoEChargerV2Handler;
|
||||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
|
@ -40,7 +41,6 @@ import org.osgi.service.component.annotations.Reference;
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
@Component(configurationPid = "binding.goecharger", service = ThingHandlerFactory.class)
|
@Component(configurationPid = "binding.goecharger", service = ThingHandlerFactory.class)
|
||||||
public class GoEChargerHandlerFactory extends BaseThingHandlerFactory {
|
public class GoEChargerHandlerFactory extends BaseThingHandlerFactory {
|
||||||
|
|
||||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_GOE);
|
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_GOE);
|
||||||
private final HttpClient httpClient;
|
private final HttpClient httpClient;
|
||||||
|
|
||||||
|
@ -57,10 +57,16 @@ public class GoEChargerHandlerFactory extends BaseThingHandlerFactory {
|
||||||
@Override
|
@Override
|
||||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||||
|
var apiVersion = thing.getConfiguration().as(GoEChargerConfiguration.class).apiVersion;
|
||||||
|
|
||||||
if (THING_TYPE_GOE.equals(thingTypeUID)) {
|
if (THING_TYPE_GOE.equals(thingTypeUID)) {
|
||||||
|
if (apiVersion == 1) {
|
||||||
return new GoEChargerHandler(thing, httpClient);
|
return new GoEChargerHandler(thing, httpClient);
|
||||||
}
|
}
|
||||||
|
if (apiVersion == 2) {
|
||||||
|
return new GoEChargerV2Handler(thing, httpClient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.goecharger.internal.api;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link GoEStatusResponseBaseDTO} class represents a json response from the
|
||||||
|
* charger.
|
||||||
|
*
|
||||||
|
* @author Reinhard Plaim - Initial contribution
|
||||||
|
*/
|
||||||
|
public class GoEStatusResponseBaseDTO {
|
||||||
|
@SerializedName("car")
|
||||||
|
public Integer pwmSignal;
|
||||||
|
|
||||||
|
@SerializedName("amp")
|
||||||
|
public Integer maxCurrent;
|
||||||
|
|
||||||
|
@SerializedName("nrg")
|
||||||
|
public Integer[] energy;
|
||||||
|
|
||||||
|
@SerializedName("err")
|
||||||
|
public Integer errorCode;
|
||||||
|
|
||||||
|
@SerializedName("cbl")
|
||||||
|
public Integer cableEncoding;
|
||||||
|
|
||||||
|
@SerializedName("eto")
|
||||||
|
public Long totalChargeConsumption;
|
||||||
|
|
||||||
|
@SerializedName("fwv")
|
||||||
|
public String firmware;
|
||||||
|
}
|
|
@ -19,47 +19,30 @@ import com.google.gson.annotations.SerializedName;
|
||||||
* charger.
|
* charger.
|
||||||
*
|
*
|
||||||
* @author Samuel Brucksch - Initial contribution
|
* @author Samuel Brucksch - Initial contribution
|
||||||
|
* @author Reinhard Plaim - move some properties to base DTO
|
||||||
*/
|
*/
|
||||||
public class GoEStatusResponseDTO {
|
public class GoEStatusResponseDTO extends GoEStatusResponseBaseDTO {
|
||||||
@SerializedName("version")
|
@SerializedName("version")
|
||||||
public String version;
|
public String version;
|
||||||
|
|
||||||
@SerializedName("car")
|
|
||||||
public Integer pwmSignal;
|
|
||||||
|
|
||||||
@SerializedName("ast")
|
|
||||||
public Integer accessConfiguration;
|
|
||||||
|
|
||||||
@SerializedName("amp")
|
|
||||||
public Integer maxCurrent;
|
|
||||||
|
|
||||||
@SerializedName("nrg")
|
|
||||||
public Integer[] energy;
|
|
||||||
|
|
||||||
@SerializedName("err")
|
|
||||||
public Integer errorCode;
|
|
||||||
|
|
||||||
@SerializedName("alw")
|
|
||||||
public Integer allowCharging;
|
|
||||||
|
|
||||||
@SerializedName("cbl")
|
|
||||||
public Integer cableEncoding;
|
|
||||||
|
|
||||||
@SerializedName("pha")
|
@SerializedName("pha")
|
||||||
public Integer phases;
|
public Integer phases;
|
||||||
|
|
||||||
|
@SerializedName("ast")
|
||||||
|
public Integer accessConfiguration;
|
||||||
|
|
||||||
|
@SerializedName("alw")
|
||||||
|
public Integer allowCharging;
|
||||||
|
|
||||||
@SerializedName("tmp")
|
@SerializedName("tmp")
|
||||||
public Integer temperature;
|
public Integer temperature;
|
||||||
|
|
||||||
@SerializedName("dws")
|
|
||||||
public Long sessionChargeConsumption;
|
|
||||||
|
|
||||||
@SerializedName("dwo")
|
@SerializedName("dwo")
|
||||||
public Integer sessionChargeConsumptionLimit;
|
public Integer sessionChargeConsumptionLimit;
|
||||||
|
|
||||||
@SerializedName("eto")
|
@SerializedName("dws")
|
||||||
public Long totalChargeConsumption;
|
public Long sessionChargeConsumption;
|
||||||
|
|
||||||
@SerializedName("fwv")
|
@SerializedName("amx")
|
||||||
public String firmware;
|
public Integer maxCurrentTemporary;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.goecharger.internal.api;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link GoEStatusResponseV2DTO} class represents a json response from the
|
||||||
|
* charger.
|
||||||
|
*
|
||||||
|
* @author Reinhard Plaim - Initial contribution
|
||||||
|
*/
|
||||||
|
public class GoEStatusResponseV2DTO extends GoEStatusResponseBaseDTO {
|
||||||
|
@SerializedName("mod")
|
||||||
|
public String version;
|
||||||
|
|
||||||
|
@SerializedName("psm")
|
||||||
|
public Integer phases;
|
||||||
|
|
||||||
|
@SerializedName("alw")
|
||||||
|
public Boolean allowCharging;
|
||||||
|
|
||||||
|
@SerializedName("tma")
|
||||||
|
public Double[] temperatures;
|
||||||
|
|
||||||
|
@SerializedName("wh")
|
||||||
|
public Long sessionChargeConsumption;
|
||||||
|
|
||||||
|
@SerializedName("dwo")
|
||||||
|
public Double sessionChargeConsumptionLimit;
|
||||||
|
|
||||||
|
@SerializedName("frc")
|
||||||
|
public Integer forceState;
|
||||||
|
}
|
|
@ -0,0 +1,172 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.goecharger.internal.handler;
|
||||||
|
|
||||||
|
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
import org.openhab.binding.goecharger.internal.GoEChargerConfiguration;
|
||||||
|
import org.openhab.binding.goecharger.internal.api.GoEStatusResponseBaseDTO;
|
||||||
|
import org.openhab.core.library.types.QuantityType;
|
||||||
|
import org.openhab.core.library.types.StringType;
|
||||||
|
import org.openhab.core.library.unit.Units;
|
||||||
|
import org.openhab.core.thing.ChannelUID;
|
||||||
|
import org.openhab.core.thing.Thing;
|
||||||
|
import org.openhab.core.thing.ThingStatus;
|
||||||
|
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||||
|
import org.openhab.core.types.Command;
|
||||||
|
import org.openhab.core.types.State;
|
||||||
|
import org.openhab.core.types.UnDefType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link GoEChargerBaseHandler} is responsible for handling commands, which are
|
||||||
|
* sent to one of the channels.
|
||||||
|
*
|
||||||
|
* @author Samuel Brucksch - Initial contribution
|
||||||
|
* @author Reinhard Plaim - Adapt to use API version 2
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public abstract class GoEChargerBaseHandler extends BaseThingHandler {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(GoEChargerBaseHandler.class);
|
||||||
|
|
||||||
|
protected @Nullable GoEChargerConfiguration config;
|
||||||
|
|
||||||
|
protected List<String> allChannels = new ArrayList<>();
|
||||||
|
|
||||||
|
protected final Gson gson = new Gson();
|
||||||
|
|
||||||
|
private @Nullable ScheduledFuture<?> refreshJob;
|
||||||
|
|
||||||
|
protected final HttpClient httpClient;
|
||||||
|
|
||||||
|
public GoEChargerBaseHandler(Thing thing, HttpClient httpClient) {
|
||||||
|
super(thing);
|
||||||
|
this.httpClient = httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected State getValue(String channelId, GoEStatusResponseBaseDTO goeResponseBase) {
|
||||||
|
switch (channelId) {
|
||||||
|
case MAX_CURRENT:
|
||||||
|
if (goeResponseBase.maxCurrent == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>(goeResponseBase.maxCurrent, Units.AMPERE);
|
||||||
|
case CABLE_ENCODING:
|
||||||
|
if (goeResponseBase.cableEncoding == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>(goeResponseBase.cableEncoding, Units.AMPERE);
|
||||||
|
case FIRMWARE:
|
||||||
|
if (goeResponseBase.firmware == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new StringType(goeResponseBase.firmware);
|
||||||
|
case VOLTAGE_L1:
|
||||||
|
if (goeResponseBase.energy == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>(goeResponseBase.energy[0], Units.VOLT);
|
||||||
|
case VOLTAGE_L2:
|
||||||
|
if (goeResponseBase.energy == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>(goeResponseBase.energy[1], Units.VOLT);
|
||||||
|
case VOLTAGE_L3:
|
||||||
|
if (goeResponseBase.energy == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>(goeResponseBase.energy[2], Units.VOLT);
|
||||||
|
}
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
config = getConfigAs(GoEChargerConfiguration.class);
|
||||||
|
allChannels = getThing().getChannels().stream().map(channel -> channel.getUID().getId())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
logger.debug("Number of channels found: {}", allChannels.size());
|
||||||
|
|
||||||
|
updateStatus(ThingStatus.UNKNOWN);
|
||||||
|
|
||||||
|
startAutomaticRefresh();
|
||||||
|
logger.debug("Finished initializing!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected GoEStatusResponseBaseDTO getGoEData()
|
||||||
|
throws InterruptedException, TimeoutException, ExecutionException, JsonSyntaxException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateChannelsAndStatus(@Nullable GoEStatusResponseBaseDTO goeResponse, @Nullable String message) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refresh() {
|
||||||
|
synchronized (this) {
|
||||||
|
// Request new GoE data
|
||||||
|
try {
|
||||||
|
GoEStatusResponseBaseDTO goeResponse = getGoEData();
|
||||||
|
updateChannelsAndStatus(goeResponse, null);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
updateChannelsAndStatus(null, ie.getMessage());
|
||||||
|
} catch (TimeoutException | ExecutionException e) {
|
||||||
|
updateChannelsAndStatus(null, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startAutomaticRefresh() {
|
||||||
|
synchronized (this) {
|
||||||
|
if (refreshJob == null || refreshJob.isCancelled()) {
|
||||||
|
GoEChargerConfiguration config = getConfigAs(GoEChargerConfiguration.class);
|
||||||
|
int delay = config.refreshInterval.intValue();
|
||||||
|
logger.debug("Running refresh job with delay {} s", delay);
|
||||||
|
refreshJob = scheduler.scheduleWithFixedDelay(this::refresh, 0, delay, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
logger.debug("Disposing the Go-eCharger handler.");
|
||||||
|
|
||||||
|
final ScheduledFuture<?> refreshJob = this.refreshJob;
|
||||||
|
if (refreshJob != null && !refreshJob.isCancelled()) {
|
||||||
|
refreshJob.cancel(true);
|
||||||
|
this.refreshJob = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,48 +12,24 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.goecharger.internal.handler;
|
package org.openhab.binding.goecharger.internal.handler;
|
||||||
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.ACCESS_CONFIGURATION;
|
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.*;
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.ALLOW_CHARGING;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.CABLE_ENCODING;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.CURRENT_L1;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.CURRENT_L2;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.CURRENT_L3;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.ERROR;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.FIRMWARE;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.MAX_CURRENT;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.PHASES;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.POWER_L1;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.POWER_L2;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.POWER_L3;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.PWM_SIGNAL;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.SESSION_CHARGE_CONSUMPTION;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.SESSION_CHARGE_CONSUMPTION_LIMIT;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.TEMPERATURE;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.TOTAL_CONSUMPTION;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.VOLTAGE_L1;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.VOLTAGE_L2;
|
|
||||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.VOLTAGE_L3;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javax.measure.quantity.ElectricCurrent;
|
import javax.measure.quantity.ElectricCurrent;
|
||||||
import javax.measure.quantity.Energy;
|
import javax.measure.quantity.Energy;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.eclipse.jetty.client.HttpClient;
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
import org.eclipse.jetty.client.api.ContentResponse;
|
import org.eclipse.jetty.client.api.ContentResponse;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
import org.openhab.binding.goecharger.internal.GoEChargerBindingConstants;
|
import org.openhab.binding.goecharger.internal.GoEChargerBindingConstants;
|
||||||
import org.openhab.binding.goecharger.internal.GoEChargerConfiguration;
|
import org.openhab.binding.goecharger.internal.api.GoEStatusResponseBaseDTO;
|
||||||
import org.openhab.binding.goecharger.internal.api.GoEStatusResponseDTO;
|
import org.openhab.binding.goecharger.internal.api.GoEStatusResponseDTO;
|
||||||
|
import org.openhab.binding.goecharger.internal.api.GoEStatusResponseV2DTO;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
import org.openhab.core.library.types.QuantityType;
|
import org.openhab.core.library.types.QuantityType;
|
||||||
|
@ -64,7 +40,6 @@ import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingStatus;
|
import org.openhab.core.thing.ThingStatus;
|
||||||
import org.openhab.core.thing.ThingStatusDetail;
|
import org.openhab.core.thing.ThingStatusDetail;
|
||||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
import org.openhab.core.types.RefreshType;
|
import org.openhab.core.types.RefreshType;
|
||||||
import org.openhab.core.types.State;
|
import org.openhab.core.types.State;
|
||||||
|
@ -72,7 +47,6 @@ import org.openhab.core.types.UnDefType;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.JsonSyntaxException;
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,34 +54,31 @@ import com.google.gson.JsonSyntaxException;
|
||||||
* sent to one of the channels.
|
* sent to one of the channels.
|
||||||
*
|
*
|
||||||
* @author Samuel Brucksch - Initial contribution
|
* @author Samuel Brucksch - Initial contribution
|
||||||
|
* @author Reinhard Plaim - Adapt to use API version 2
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class GoEChargerHandler extends BaseThingHandler {
|
public class GoEChargerHandler extends GoEChargerBaseHandler {
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(GoEChargerHandler.class);
|
private final Logger logger = LoggerFactory.getLogger(GoEChargerHandler.class);
|
||||||
|
|
||||||
private @Nullable GoEChargerConfiguration config;
|
|
||||||
|
|
||||||
private List<String> allChannels = new ArrayList<>();
|
|
||||||
|
|
||||||
private final Gson gson = new Gson();
|
|
||||||
|
|
||||||
private @Nullable ScheduledFuture<?> refreshJob;
|
|
||||||
|
|
||||||
private final HttpClient httpClient;
|
|
||||||
|
|
||||||
public GoEChargerHandler(Thing thing, HttpClient httpClient) {
|
public GoEChargerHandler(Thing thing, HttpClient httpClient) {
|
||||||
super(thing);
|
super(thing, httpClient);
|
||||||
this.httpClient = httpClient;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private State getValue(String channelId, GoEStatusResponseDTO goeResponse) {
|
@Override
|
||||||
|
protected State getValue(String channelId, GoEStatusResponseBaseDTO goeResponseBase) {
|
||||||
|
var state = super.getValue(channelId, goeResponseBase);
|
||||||
|
if (state != UnDefType.UNDEF) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
var goeResponse = (GoEStatusResponseDTO) goeResponseBase;
|
||||||
switch (channelId) {
|
switch (channelId) {
|
||||||
case MAX_CURRENT:
|
case MAX_CURRENT_TEMPORARY:
|
||||||
if (goeResponse.maxCurrent == null) {
|
if (goeResponse.maxCurrentTemporary == null) {
|
||||||
return UnDefType.UNDEF;
|
return UnDefType.UNDEF;
|
||||||
}
|
}
|
||||||
return new QuantityType<>(goeResponse.maxCurrent, Units.AMPERE);
|
return new QuantityType<>(goeResponse.maxCurrentTemporary, Units.AMPERE);
|
||||||
case PWM_SIGNAL:
|
case PWM_SIGNAL:
|
||||||
if (goeResponse.pwmSignal == null) {
|
if (goeResponse.pwmSignal == null) {
|
||||||
return UnDefType.UNDEF;
|
return UnDefType.UNDEF;
|
||||||
|
@ -178,11 +149,6 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||||
return UnDefType.UNDEF;
|
return UnDefType.UNDEF;
|
||||||
}
|
}
|
||||||
return goeResponse.allowCharging == 1 ? OnOffType.ON : OnOffType.OFF;
|
return goeResponse.allowCharging == 1 ? OnOffType.ON : OnOffType.OFF;
|
||||||
case CABLE_ENCODING:
|
|
||||||
if (goeResponse.cableEncoding == null) {
|
|
||||||
return UnDefType.UNDEF;
|
|
||||||
}
|
|
||||||
return new QuantityType<>(goeResponse.cableEncoding, Units.AMPERE);
|
|
||||||
case PHASES:
|
case PHASES:
|
||||||
if (goeResponse.energy == null) {
|
if (goeResponse.energy == null) {
|
||||||
return UnDefType.UNDEF;
|
return UnDefType.UNDEF;
|
||||||
|
@ -198,7 +164,7 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
return new DecimalType(count);
|
return new DecimalType(count);
|
||||||
case TEMPERATURE:
|
case TEMPERATURE_CIRCUIT_BOARD:
|
||||||
if (goeResponse.temperature == null) {
|
if (goeResponse.temperature == null) {
|
||||||
return UnDefType.UNDEF;
|
return UnDefType.UNDEF;
|
||||||
}
|
}
|
||||||
|
@ -220,26 +186,6 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||||
return UnDefType.UNDEF;
|
return UnDefType.UNDEF;
|
||||||
}
|
}
|
||||||
return new QuantityType<>((Double) (goeResponse.totalChargeConsumption / 10d), Units.KILOWATT_HOUR);
|
return new QuantityType<>((Double) (goeResponse.totalChargeConsumption / 10d), Units.KILOWATT_HOUR);
|
||||||
case FIRMWARE:
|
|
||||||
if (goeResponse.firmware == null) {
|
|
||||||
return UnDefType.UNDEF;
|
|
||||||
}
|
|
||||||
return new StringType(goeResponse.firmware);
|
|
||||||
case VOLTAGE_L1:
|
|
||||||
if (goeResponse.energy == null) {
|
|
||||||
return UnDefType.UNDEF;
|
|
||||||
}
|
|
||||||
return new QuantityType<>(goeResponse.energy[0], Units.VOLT);
|
|
||||||
case VOLTAGE_L2:
|
|
||||||
if (goeResponse.energy == null) {
|
|
||||||
return UnDefType.UNDEF;
|
|
||||||
}
|
|
||||||
return new QuantityType<>(goeResponse.energy[1], Units.VOLT);
|
|
||||||
case VOLTAGE_L3:
|
|
||||||
if (goeResponse.energy == null) {
|
|
||||||
return UnDefType.UNDEF;
|
|
||||||
}
|
|
||||||
return new QuantityType<>(goeResponse.energy[2], Units.VOLT);
|
|
||||||
case CURRENT_L1:
|
case CURRENT_L1:
|
||||||
if (goeResponse.energy == null) {
|
if (goeResponse.energy == null) {
|
||||||
return UnDefType.UNDEF;
|
return UnDefType.UNDEF;
|
||||||
|
@ -272,6 +218,11 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||||
return UnDefType.UNDEF;
|
return UnDefType.UNDEF;
|
||||||
}
|
}
|
||||||
return new QuantityType<>(goeResponse.energy[9] * 100, Units.WATT);
|
return new QuantityType<>(goeResponse.energy[9] * 100, Units.WATT);
|
||||||
|
case POWER_ALL:
|
||||||
|
if (goeResponseBase.energy == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>(goeResponseBase.energy[11] * 10, Units.WATT);
|
||||||
}
|
}
|
||||||
return UnDefType.UNDEF;
|
return UnDefType.UNDEF;
|
||||||
}
|
}
|
||||||
|
@ -286,6 +237,7 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||||
|
|
||||||
String key = null;
|
String key = null;
|
||||||
String value = null;
|
String value = null;
|
||||||
|
|
||||||
switch (channelUID.getId()) {
|
switch (channelUID.getId()) {
|
||||||
case MAX_CURRENT:
|
case MAX_CURRENT:
|
||||||
key = "amp";
|
key = "amp";
|
||||||
|
@ -295,13 +247,22 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||||
value = String.valueOf(((QuantityType<ElectricCurrent>) command).toUnit(Units.AMPERE).intValue());
|
value = String.valueOf(((QuantityType<ElectricCurrent>) command).toUnit(Units.AMPERE).intValue());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case MAX_CURRENT_TEMPORARY:
|
||||||
|
key = "amx";
|
||||||
|
if (command instanceof DecimalType) {
|
||||||
|
value = String.valueOf(((DecimalType) command).intValue());
|
||||||
|
} else if (command instanceof QuantityType<?>) {
|
||||||
|
value = String.valueOf(((QuantityType<ElectricCurrent>) command).toUnit(Units.AMPERE).intValue());
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SESSION_CHARGE_CONSUMPTION_LIMIT:
|
case SESSION_CHARGE_CONSUMPTION_LIMIT:
|
||||||
key = "dwo";
|
key = "dwo";
|
||||||
|
var multiplier = 10;
|
||||||
if (command instanceof DecimalType) {
|
if (command instanceof DecimalType) {
|
||||||
value = String.valueOf(((DecimalType) command).intValue() * 10);
|
value = String.valueOf(((DecimalType) command).intValue() * multiplier);
|
||||||
} else if (command instanceof QuantityType<?>) {
|
} else if (command instanceof QuantityType<?>) {
|
||||||
value = String
|
value = String.valueOf(
|
||||||
.valueOf(((QuantityType<Energy>) command).toUnit(Units.KILOWATT_HOUR).intValue() * 10);
|
((QuantityType<Energy>) command).toUnit(Units.KILOWATT_HOUR).intValue() * multiplier);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ALLOW_CHARGING:
|
case ALLOW_CHARGING:
|
||||||
|
@ -330,8 +291,8 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key != null && value != null) {
|
if (key != null && value != null) {
|
||||||
sendData(key, value);
|
sendData(key, value);
|
||||||
} else {
|
} else {
|
||||||
|
@ -341,96 +302,82 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
config = getConfigAs(GoEChargerConfiguration.class);
|
super.initialize();
|
||||||
allChannels = getThing().getChannels().stream().map(channel -> channel.getUID().getId())
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
updateStatus(ThingStatus.UNKNOWN);
|
|
||||||
|
|
||||||
startAutomaticRefresh();
|
|
||||||
logger.debug("Finished initializing!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getUrl(String type) {
|
private String getReadUrl() {
|
||||||
return type.replace("%IP%", StringUtils.trimToEmpty(config.ip));
|
return GoEChargerBindingConstants.API_URL.replace("%IP%", config.ip.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getWriteUrl(String key, String value) {
|
||||||
|
return GoEChargerBindingConstants.MQTT_URL.replace("%IP%", config.ip.toString()).replace("%KEY%", key)
|
||||||
|
.replace("%VALUE%", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendData(String key, String value) {
|
private void sendData(String key, String value) {
|
||||||
String urlStr = getUrl(GoEChargerBindingConstants.MQTT_URL).replace("%KEY%", key).replace("%VALUE%", value);
|
String urlStr = getWriteUrl(key, value);
|
||||||
logger.debug("POST URL = {}", urlStr);
|
logger.trace("GET URL = {}", urlStr);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ContentResponse contentResponse = httpClient.newRequest(urlStr).method(HttpMethod.POST)
|
HttpMethod httpMethod = HttpMethod.GET;
|
||||||
|
ContentResponse contentResponse = httpClient.newRequest(urlStr).method(httpMethod)
|
||||||
.timeout(5, TimeUnit.SECONDS).send();
|
.timeout(5, TimeUnit.SECONDS).send();
|
||||||
String response = contentResponse.getContentAsString();
|
String response = contentResponse.getContentAsString();
|
||||||
logger.debug("POST Response: {}", response);
|
|
||||||
GoEStatusResponseDTO result = gson.fromJson(response, GoEStatusResponseDTO.class);
|
logger.trace("{} Response: {}", httpMethod.toString(), response);
|
||||||
updateChannelsAndStatus(result, null);
|
|
||||||
} catch (InterruptedException | TimeoutException | ExecutionException | JsonSyntaxException e) {
|
var statusCode = contentResponse.getStatus();
|
||||||
updateChannelsAndStatus(null, e.getMessage());
|
if (!(statusCode == 200 || statusCode == 204)) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
|
"@text/unsuccessful.communication-error");
|
||||||
|
logger.debug("Could not send data, Response {}, StatusCode: {}", response, statusCode);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ie.toString());
|
||||||
|
logger.debug("Could not send data: {}, {}", urlStr, ie.toString());
|
||||||
|
} catch (TimeoutException | ExecutionException | JsonSyntaxException e) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.toString());
|
||||||
|
logger.debug("Could not send data: {}, {}", urlStr, e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request new data from Go-E charger
|
* Request new data from Go-eCharger
|
||||||
*
|
*
|
||||||
* @return the Go-E charger object mapping the JSON response or null in case of
|
* @return the Go-eCharger object mapping the JSON response or null in case of
|
||||||
* error
|
* error
|
||||||
* @throws ExecutionException
|
* @throws ExecutionException
|
||||||
* @throws TimeoutException
|
* @throws TimeoutException
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private GoEStatusResponseDTO getGoEData()
|
@Override
|
||||||
|
protected GoEStatusResponseBaseDTO getGoEData()
|
||||||
throws InterruptedException, TimeoutException, ExecutionException, JsonSyntaxException {
|
throws InterruptedException, TimeoutException, ExecutionException, JsonSyntaxException {
|
||||||
String urlStr = getUrl(GoEChargerBindingConstants.API_URL);
|
String urlStr = getReadUrl();
|
||||||
logger.debug("GET URL = {}", urlStr);
|
logger.trace("GET URL = {}", urlStr);
|
||||||
|
|
||||||
ContentResponse contentResponse = httpClient.newRequest(urlStr).method(HttpMethod.GET)
|
ContentResponse contentResponse = httpClient.newRequest(urlStr).method(HttpMethod.GET)
|
||||||
.timeout(5, TimeUnit.SECONDS).send();
|
.timeout(5, TimeUnit.SECONDS).send();
|
||||||
|
|
||||||
String response = contentResponse.getContentAsString();
|
String response = contentResponse.getContentAsString();
|
||||||
logger.debug("GET Response: {}", response);
|
logger.trace("GET Response: {}", response);
|
||||||
|
|
||||||
|
if (config.apiVersion == 1) {
|
||||||
return gson.fromJson(response, GoEStatusResponseDTO.class);
|
return gson.fromJson(response, GoEStatusResponseDTO.class);
|
||||||
}
|
}
|
||||||
|
return gson.fromJson(response, GoEStatusResponseV2DTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
private void updateChannelsAndStatus(@Nullable GoEStatusResponseDTO goeResponse, @Nullable String message) {
|
@Override
|
||||||
|
protected void updateChannelsAndStatus(@Nullable GoEStatusResponseBaseDTO goeResponse, @Nullable String message) {
|
||||||
if (goeResponse == null) {
|
if (goeResponse == null) {
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, message);
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, message);
|
||||||
allChannels.forEach(channel -> updateState(channel, UnDefType.UNDEF));
|
allChannels.forEach(channel -> updateState(channel, UnDefType.UNDEF));
|
||||||
} else {
|
} else {
|
||||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
|
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
|
||||||
allChannels.forEach(channel -> updateState(channel, getValue(channel, goeResponse)));
|
allChannels.forEach(channel -> updateState(channel, getValue(channel, (GoEStatusResponseDTO) goeResponse)));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refresh() {
|
|
||||||
// Request new GoE data
|
|
||||||
try {
|
|
||||||
GoEStatusResponseDTO goeResponse = getGoEData();
|
|
||||||
updateChannelsAndStatus(goeResponse, null);
|
|
||||||
} catch (InterruptedException | TimeoutException | ExecutionException e) {
|
|
||||||
updateChannelsAndStatus(null, e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startAutomaticRefresh() {
|
|
||||||
if (refreshJob == null || refreshJob.isCancelled()) {
|
|
||||||
GoEChargerConfiguration config = getConfigAs(GoEChargerConfiguration.class);
|
|
||||||
int delay = config.refreshInterval.intValue();
|
|
||||||
logger.debug("Running refresh job with delay {} s", delay);
|
|
||||||
refreshJob = scheduler.scheduleWithFixedDelay(this::refresh, 0, delay, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
logger.debug("Disposing the Go-E Charger handler.");
|
|
||||||
|
|
||||||
final ScheduledFuture<?> refreshJob = this.refreshJob;
|
|
||||||
if (refreshJob != null && !refreshJob.isCancelled()) {
|
|
||||||
refreshJob.cancel(true);
|
|
||||||
this.refreshJob = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,360 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.goecharger.internal.handler;
|
||||||
|
|
||||||
|
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.*;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import javax.measure.quantity.ElectricCurrent;
|
||||||
|
import javax.measure.quantity.Energy;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
import org.eclipse.jetty.client.api.ContentResponse;
|
||||||
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
|
import org.openhab.binding.goecharger.internal.GoEChargerBindingConstants;
|
||||||
|
import org.openhab.binding.goecharger.internal.api.GoEStatusResponseBaseDTO;
|
||||||
|
import org.openhab.binding.goecharger.internal.api.GoEStatusResponseDTO;
|
||||||
|
import org.openhab.binding.goecharger.internal.api.GoEStatusResponseV2DTO;
|
||||||
|
import org.openhab.core.library.types.DecimalType;
|
||||||
|
import org.openhab.core.library.types.OnOffType;
|
||||||
|
import org.openhab.core.library.types.QuantityType;
|
||||||
|
import org.openhab.core.library.types.StringType;
|
||||||
|
import org.openhab.core.library.unit.SIUnits;
|
||||||
|
import org.openhab.core.library.unit.Units;
|
||||||
|
import org.openhab.core.thing.ChannelUID;
|
||||||
|
import org.openhab.core.thing.Thing;
|
||||||
|
import org.openhab.core.thing.ThingStatus;
|
||||||
|
import org.openhab.core.thing.ThingStatusDetail;
|
||||||
|
import org.openhab.core.types.Command;
|
||||||
|
import org.openhab.core.types.RefreshType;
|
||||||
|
import org.openhab.core.types.State;
|
||||||
|
import org.openhab.core.types.UnDefType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link GoEChargerV2Handler} is responsible for handling commands, which are
|
||||||
|
* sent to one of the channels.
|
||||||
|
*
|
||||||
|
* @author Samuel Brucksch - Initial contribution
|
||||||
|
* @author Reinhard Plaim - Adapt to use API version 2
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class GoEChargerV2Handler extends GoEChargerBaseHandler {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(GoEChargerV2Handler.class);
|
||||||
|
|
||||||
|
private String filter = "";
|
||||||
|
|
||||||
|
public GoEChargerV2Handler(Thing thing, HttpClient httpClient) {
|
||||||
|
super(thing, httpClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected State getValue(String channelId, GoEStatusResponseBaseDTO goeResponseBase) {
|
||||||
|
var state = super.getValue(channelId, goeResponseBase);
|
||||||
|
if (state != UnDefType.UNDEF) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
var goeResponse = (GoEStatusResponseV2DTO) goeResponseBase;
|
||||||
|
switch (channelId) {
|
||||||
|
case PHASES:
|
||||||
|
if (goeResponse.phases == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
var phases = "1";
|
||||||
|
if (goeResponse.phases == 2) {
|
||||||
|
phases = "3";
|
||||||
|
}
|
||||||
|
return new DecimalType(phases);
|
||||||
|
case PWM_SIGNAL:
|
||||||
|
if (goeResponse.pwmSignal == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
String pwmSignal = null;
|
||||||
|
switch (goeResponse.pwmSignal) {
|
||||||
|
case 0:
|
||||||
|
pwmSignal = "UNKNOWN/ERROR";
|
||||||
|
case 1:
|
||||||
|
pwmSignal = "IDLE";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pwmSignal = "CHARGING";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
pwmSignal = "WAITING_FOR_CAR";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
pwmSignal = "COMPLETE";
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
pwmSignal = "ERROR";
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return new StringType(pwmSignal);
|
||||||
|
case ERROR:
|
||||||
|
if (goeResponse.errorCode == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
String error = null;
|
||||||
|
switch (goeResponse.errorCode) {
|
||||||
|
case 0:
|
||||||
|
error = "UNKNOWN/ERROR";
|
||||||
|
case 1:
|
||||||
|
error = "IDLE";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
error = "CHARGING";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
error = "WAITING_FOR_CAR";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
error = "COMPLETE";
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
error = "ERROR";
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return new StringType(error);
|
||||||
|
case ALLOW_CHARGING:
|
||||||
|
return goeResponse.allowCharging == true ? OnOffType.ON : OnOffType.OFF;
|
||||||
|
case TEMPERATURE_TYPE2_PORT:
|
||||||
|
if (goeResponse.temperatures == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>(goeResponse.temperatures[0], SIUnits.CELSIUS);
|
||||||
|
case TEMPERATURE_CIRCUIT_BOARD:
|
||||||
|
if (goeResponse.temperatures == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>(goeResponse.temperatures[1], SIUnits.CELSIUS);
|
||||||
|
case SESSION_CHARGE_CONSUMPTION:
|
||||||
|
if (goeResponse.sessionChargeConsumption == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>((Double) (goeResponse.sessionChargeConsumption / 1000d), Units.KILOWATT_HOUR);
|
||||||
|
case SESSION_CHARGE_CONSUMPTION_LIMIT:
|
||||||
|
if (goeResponse.sessionChargeConsumptionLimit == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>((Double) (goeResponse.sessionChargeConsumptionLimit / 1000d),
|
||||||
|
Units.KILOWATT_HOUR);
|
||||||
|
case TOTAL_CONSUMPTION:
|
||||||
|
if (goeResponse.totalChargeConsumption == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>((Double) (goeResponse.totalChargeConsumption / 1000d), Units.KILOWATT_HOUR);
|
||||||
|
case CURRENT_L1:
|
||||||
|
if (goeResponse.energy == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>((Double) (goeResponse.energy[4] / 1000d), Units.AMPERE);
|
||||||
|
case CURRENT_L2:
|
||||||
|
if (goeResponse.energy == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>((Double) (goeResponse.energy[5] / 1000d), Units.AMPERE);
|
||||||
|
case CURRENT_L3:
|
||||||
|
if (goeResponse.energy == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>((Double) (goeResponse.energy[6] / 1000d), Units.AMPERE);
|
||||||
|
case POWER_L1:
|
||||||
|
if (goeResponse.energy == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>(goeResponse.energy[7] * 1000, Units.WATT);
|
||||||
|
case POWER_L2:
|
||||||
|
if (goeResponse.energy == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>(goeResponse.energy[8] * 1000, Units.WATT);
|
||||||
|
case POWER_L3:
|
||||||
|
if (goeResponse.energy == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>(goeResponse.energy[9] * 1000, Units.WATT);
|
||||||
|
case POWER_ALL:
|
||||||
|
if (goeResponse.energy == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new QuantityType<>(goeResponse.energy[11] * 1000, Units.WATT);
|
||||||
|
case FORCE_STATE:
|
||||||
|
if (goeResponse.forceState == null) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
return new DecimalType(goeResponse.forceState.toString());
|
||||||
|
}
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||||
|
if (command instanceof RefreshType) {
|
||||||
|
// we can not update single channels and refresh is triggered automatically
|
||||||
|
// anyways
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String key = null;
|
||||||
|
String value = null;
|
||||||
|
|
||||||
|
switch (channelUID.getId()) {
|
||||||
|
case MAX_CURRENT:
|
||||||
|
key = "amp";
|
||||||
|
if (command instanceof DecimalType) {
|
||||||
|
value = String.valueOf(((DecimalType) command).intValue());
|
||||||
|
} else if (command instanceof QuantityType<?>) {
|
||||||
|
value = String.valueOf(((QuantityType<ElectricCurrent>) command).toUnit(Units.AMPERE).intValue());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SESSION_CHARGE_CONSUMPTION_LIMIT:
|
||||||
|
key = "dwo";
|
||||||
|
var multiplier = 1000;
|
||||||
|
if (command instanceof DecimalType) {
|
||||||
|
value = String.valueOf(((DecimalType) command).intValue() * multiplier);
|
||||||
|
} else if (command instanceof QuantityType<?>) {
|
||||||
|
value = String.valueOf(
|
||||||
|
((QuantityType<Energy>) command).toUnit(Units.KILOWATT_HOUR).intValue() * multiplier);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PHASES:
|
||||||
|
key = "psm";
|
||||||
|
if (command instanceof DecimalType) {
|
||||||
|
var phases = 1;
|
||||||
|
var help = (DecimalType) command;
|
||||||
|
if (help.intValue() == 3) {
|
||||||
|
// set value 2 for 3 phases
|
||||||
|
phases = 2;
|
||||||
|
}
|
||||||
|
value = String.valueOf(phases);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FORCE_STATE:
|
||||||
|
key = "frc";
|
||||||
|
if (command instanceof DecimalType) {
|
||||||
|
value = String.valueOf(((DecimalType) command).intValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key != null && value != null) {
|
||||||
|
sendData(key, value);
|
||||||
|
} else {
|
||||||
|
logger.warn("Could not update channel {} with key {} and value {}", channelUID.getId(), key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
// only read needed parameters
|
||||||
|
filter = "?filter=";
|
||||||
|
var declaredFields = GoEStatusResponseV2DTO.class.getDeclaredFields();
|
||||||
|
var declaredFieldsBase = GoEStatusResponseV2DTO.class.getSuperclass().getDeclaredFields();
|
||||||
|
|
||||||
|
for (var field : declaredFields) {
|
||||||
|
filter += field.getAnnotation(SerializedName.class).value() + ",";
|
||||||
|
}
|
||||||
|
for (var field : declaredFieldsBase) {
|
||||||
|
filter += field.getAnnotation(SerializedName.class).value() + ",";
|
||||||
|
}
|
||||||
|
filter = filter.substring(0, filter.length() - 1);
|
||||||
|
|
||||||
|
super.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getReadUrl() {
|
||||||
|
return GoEChargerBindingConstants.API_URL_V2.replace("%IP%", config.ip.toString()) + filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getWriteUrl(String key, String value) {
|
||||||
|
return GoEChargerBindingConstants.SET_URL_V2.replace("%IP%", config.ip.toString()).replace("%KEY%", key)
|
||||||
|
.replace("%VALUE%", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendData(String key, String value) {
|
||||||
|
String urlStr = getWriteUrl(key, value);
|
||||||
|
logger.trace("POST URL = {}", urlStr);
|
||||||
|
|
||||||
|
try {
|
||||||
|
HttpMethod httpMethod = HttpMethod.GET;
|
||||||
|
ContentResponse contentResponse = httpClient.newRequest(urlStr).method(httpMethod)
|
||||||
|
.timeout(5, TimeUnit.SECONDS).send();
|
||||||
|
String response = contentResponse.getContentAsString();
|
||||||
|
|
||||||
|
logger.trace("{} Response: {}", httpMethod.toString(), response);
|
||||||
|
|
||||||
|
var statusCode = contentResponse.getStatus();
|
||||||
|
if (!(statusCode == 200 || statusCode == 204)) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
|
"@text/unsuccessful.communication-error");
|
||||||
|
logger.debug("Could not send data, Response {}, StatusCode: {}", response, statusCode);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ie.toString());
|
||||||
|
logger.debug("Could not send data: {}, {}", urlStr, ie.toString());
|
||||||
|
} catch (TimeoutException | ExecutionException | JsonSyntaxException e) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.toString());
|
||||||
|
logger.debug("Could not send data: {}, {}", urlStr, e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request new data from Go-eCharger
|
||||||
|
*
|
||||||
|
* @return the Go-eCharger object mapping the JSON response or null in case of
|
||||||
|
* error
|
||||||
|
* @throws ExecutionException
|
||||||
|
* @throws TimeoutException
|
||||||
|
* @throws InterruptedException
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected GoEStatusResponseBaseDTO getGoEData()
|
||||||
|
throws InterruptedException, TimeoutException, ExecutionException, JsonSyntaxException {
|
||||||
|
String urlStr = getReadUrl();
|
||||||
|
logger.trace("GET URL = {}", urlStr);
|
||||||
|
|
||||||
|
ContentResponse contentResponse = httpClient.newRequest(urlStr).method(HttpMethod.GET)
|
||||||
|
.timeout(5, TimeUnit.SECONDS).send();
|
||||||
|
|
||||||
|
String response = contentResponse.getContentAsString();
|
||||||
|
logger.trace("GET Response: {}", response);
|
||||||
|
|
||||||
|
if (config.apiVersion == 1) {
|
||||||
|
return gson.fromJson(response, GoEStatusResponseDTO.class);
|
||||||
|
}
|
||||||
|
return gson.fromJson(response, GoEStatusResponseV2DTO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateChannelsAndStatus(@Nullable GoEStatusResponseBaseDTO goeResponse, @Nullable String message) {
|
||||||
|
if (goeResponse == null) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, message);
|
||||||
|
allChannels.forEach(channel -> updateState(channel, UnDefType.UNDEF));
|
||||||
|
} else {
|
||||||
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
allChannels
|
||||||
|
.forEach(channel -> updateState(channel, getValue(channel, (GoEStatusResponseV2DTO) goeResponse)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,11 +12,21 @@ thing-type.goecharger.goe.description = Go-eCharger thing that represents the wa
|
||||||
|
|
||||||
thing-type.config.goecharger.goe.ip.label = IP Address
|
thing-type.config.goecharger.goe.ip.label = IP Address
|
||||||
thing-type.config.goecharger.goe.ip.description = The IP address of the Go-eCharger
|
thing-type.config.goecharger.goe.ip.description = The IP address of the Go-eCharger
|
||||||
|
thing-type.config.goecharger.goe.apiVersion.label = API version
|
||||||
|
thing-type.config.goecharger.goe.apiVersion.description = The API version of the Go-eCharger
|
||||||
thing-type.config.goecharger.goe.refreshInterval.label = Refresh Interval
|
thing-type.config.goecharger.goe.refreshInterval.label = Refresh Interval
|
||||||
thing-type.config.goecharger.goe.refreshInterval.description = Refresh interval for acquiring data from Go-eCharger in seconds
|
thing-type.config.goecharger.goe.refreshInterval.description = Refresh interval for acquiring data from Go-eCharger in seconds
|
||||||
|
|
||||||
# channel types
|
# channel types
|
||||||
|
|
||||||
|
channel-type.goecharger.current.label = Maximum Current
|
||||||
|
channel-type.goecharger.current.description = Maximum current per phase allowed to use for charging
|
||||||
|
channel-type.goecharger.maxCurrTmp.label = Maximum Current Temporary
|
||||||
|
channel-type.goecharger.maxCurrTmp.description = Maximum current temporary (not written to EEPROM)
|
||||||
|
channel-type.goecharger.phs.label = Phases
|
||||||
|
channel-type.goecharger.phs.description = Amount of phases currently used for charging
|
||||||
|
channel-type.goecharger.fs.label = Force State
|
||||||
|
channel-type.goecharger.fs.description = Force state (Neutral=0, Off=1, On=2)
|
||||||
channel-type.goecharger.alw.label = Allow Charging
|
channel-type.goecharger.alw.label = Allow Charging
|
||||||
channel-type.goecharger.alw.description = If true charging is allowed
|
channel-type.goecharger.alw.description = If true charging is allowed
|
||||||
channel-type.goecharger.ast.label = Access Configuration
|
channel-type.goecharger.ast.label = Access Configuration
|
||||||
|
@ -33,20 +43,16 @@ channel-type.goecharger.cl2.label = Current L2
|
||||||
channel-type.goecharger.cl2.description = Current on L2
|
channel-type.goecharger.cl2.description = Current on L2
|
||||||
channel-type.goecharger.cl3.label = Current L3
|
channel-type.goecharger.cl3.label = Current L3
|
||||||
channel-type.goecharger.cl3.description = Current on L3
|
channel-type.goecharger.cl3.description = Current on L3
|
||||||
channel-type.goecharger.current.label = Maximum Current
|
|
||||||
channel-type.goecharger.current.description = Maximum current per phase allowed to use for charging
|
|
||||||
channel-type.goecharger.err.label = Error Code
|
channel-type.goecharger.err.label = Error Code
|
||||||
channel-type.goecharger.err.description = Error code of Go-eCharger
|
channel-type.goecharger.err.description = Error code of Go-eCharger
|
||||||
channel-type.goecharger.err.state.option.NONE = None
|
|
||||||
channel-type.goecharger.err.state.option.RCCB = RCCB
|
|
||||||
channel-type.goecharger.err.state.option.NO_GROUND = No ground
|
|
||||||
channel-type.goecharger.err.state.option.INTERNAL = Internal
|
|
||||||
channel-type.goecharger.eto.label = Total Charged Energy
|
channel-type.goecharger.eto.label = Total Charged Energy
|
||||||
channel-type.goecharger.eto.description = Amount of energy that has been charged since installation
|
channel-type.goecharger.eto.description = Amount of energy that has been charged since installation
|
||||||
channel-type.goecharger.fmw.label = Firmware
|
channel-type.goecharger.fmw.label = Firmware
|
||||||
channel-type.goecharger.fmw.description = Firmware Version
|
channel-type.goecharger.fmw.description = Firmware Version
|
||||||
channel-type.goecharger.pha.label = Phases
|
channel-type.goecharger.scl.label = Current Session Charge Energy Limit
|
||||||
channel-type.goecharger.pha.description = Amount of phases currently used for charging
|
channel-type.goecharger.scl.description = Wallbox stops charging after defined value, deactivate with value 0
|
||||||
|
channel-type.goecharger.scs.label = Current Session Charged Energy
|
||||||
|
channel-type.goecharger.scs.description = Amount of energy that has been charged in this session
|
||||||
channel-type.goecharger.pl1.label = Power L1
|
channel-type.goecharger.pl1.label = Power L1
|
||||||
channel-type.goecharger.pl1.description = Power on L1
|
channel-type.goecharger.pl1.description = Power on L1
|
||||||
channel-type.goecharger.pl2.label = Power L2
|
channel-type.goecharger.pl2.label = Power L2
|
||||||
|
@ -55,19 +61,16 @@ channel-type.goecharger.pl3.label = Power L3
|
||||||
channel-type.goecharger.pl3.description = Power on L3
|
channel-type.goecharger.pl3.description = Power on L3
|
||||||
channel-type.goecharger.pwm.label = PWM signal status
|
channel-type.goecharger.pwm.label = PWM signal status
|
||||||
channel-type.goecharger.pwm.description = Pulse-width modulation signal status
|
channel-type.goecharger.pwm.description = Pulse-width modulation signal status
|
||||||
channel-type.goecharger.pwm.state.option.READY_NO_CAR = Ready (no car)
|
channel-type.goecharger.tmpT2p.label = Temperature type 2 port
|
||||||
channel-type.goecharger.pwm.state.option.CHARGING = Charging
|
channel-type.goecharger.tmpT2p.description = Temperature on the type 2 port of the Go-eCharger
|
||||||
channel-type.goecharger.pwm.state.option.WAITING_FOR_CAR = Waiting for car
|
channel-type.goecharger.tmp.label = Temperature circuit board
|
||||||
channel-type.goecharger.pwm.state.option.CHARGING_DONE_CAR_CONNECTED = Charging done (car connected)
|
channel-type.goecharger.tmp.description = Temperature on the circuit board of the Go-eCharger
|
||||||
channel-type.goecharger.scl.label = Current Session Charge Energy Limit
|
|
||||||
channel-type.goecharger.scl.description = Wallbox stops charging after defined value, deactivate with value 0
|
|
||||||
channel-type.goecharger.scs.label = Current Session Charged Energy
|
|
||||||
channel-type.goecharger.scs.description = Amount of energy that has been charged in this session
|
|
||||||
channel-type.goecharger.tmp.label = Temperature
|
|
||||||
channel-type.goecharger.tmp.description = Temperature of the Go-eCharger
|
|
||||||
channel-type.goecharger.vl1.label = Voltage L1
|
channel-type.goecharger.vl1.label = Voltage L1
|
||||||
channel-type.goecharger.vl1.description = Voltage on L1
|
channel-type.goecharger.vl1.description = Voltage on L1
|
||||||
channel-type.goecharger.vl2.label = Voltage L2
|
channel-type.goecharger.vl2.label = Voltage L2
|
||||||
channel-type.goecharger.vl2.description = Voltage on L2
|
channel-type.goecharger.vl2.description = Voltage on L2
|
||||||
channel-type.goecharger.vl3.label = Voltage L3
|
channel-type.goecharger.vl3.label = Voltage L3
|
||||||
channel-type.goecharger.vl3.description = Voltage on L3
|
channel-type.goecharger.vl3.description = Voltage on L3
|
||||||
|
|
||||||
|
# Others
|
||||||
|
unsuccessful.communication-error=Request response was unsuccessful
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
<channels>
|
<channels>
|
||||||
<channel id="maxCurrent" typeId="current"/>
|
<channel id="maxCurrent" typeId="current"/>
|
||||||
|
<channel id="maxCurrentTemp" typeId="maxCurrTmp"/>
|
||||||
<channel id="pwmSignal" typeId="pwm"/>
|
<channel id="pwmSignal" typeId="pwm"/>
|
||||||
<channel id="error" typeId="err"/>
|
<channel id="error" typeId="err"/>
|
||||||
<channel id="voltageL1" typeId="vl1"/>
|
<channel id="voltageL1" typeId="vl1"/>
|
||||||
|
@ -21,15 +22,17 @@
|
||||||
<channel id="powerL1" typeId="pl1"/>
|
<channel id="powerL1" typeId="pl1"/>
|
||||||
<channel id="powerL2" typeId="pl2"/>
|
<channel id="powerL2" typeId="pl2"/>
|
||||||
<channel id="powerL3" typeId="pl3"/>
|
<channel id="powerL3" typeId="pl3"/>
|
||||||
<channel id="phases" typeId="pha"/>
|
|
||||||
<channel id="sessionChargeEnergyLimit" typeId="scl"/>
|
|
||||||
<channel id="sessionChargedEnergy" typeId="scs"/>
|
|
||||||
<channel id="totalChargedEnergy" typeId="eto"/>
|
|
||||||
<channel id="allowCharging" typeId="alw"/>
|
<channel id="allowCharging" typeId="alw"/>
|
||||||
<channel id="cableCurrent" typeId="cbl"/>
|
<channel id="cableCurrent" typeId="cbl"/>
|
||||||
<channel id="temperature" typeId="tmp"/>
|
|
||||||
<channel id="firmware" typeId="fmw"/>
|
<channel id="firmware" typeId="fmw"/>
|
||||||
<channel id="accessConfiguration" typeId="ast"/>
|
<channel id="accessConfiguration" typeId="ast"/>
|
||||||
|
<channel id="phases" typeId="pha"/>
|
||||||
|
<channel id="forceState" typeId="fs"/>
|
||||||
|
<channel id="sessionChargedEnergy" typeId="scs"/>
|
||||||
|
<channel id="sessionChargeEnergyLimit" typeId="scl"/>
|
||||||
|
<channel id="totalChargedEnergy" typeId="eto"/>
|
||||||
|
<channel id="temperatureType2Port" typeId="tmpT2p"/>
|
||||||
|
<channel id="temperature" typeId="tmp"/>
|
||||||
</channels>
|
</channels>
|
||||||
|
|
||||||
<config-description>
|
<config-description>
|
||||||
|
@ -38,6 +41,10 @@
|
||||||
<description>The IP address of the Go-eCharger</description>
|
<description>The IP address of the Go-eCharger</description>
|
||||||
<context>network-address</context>
|
<context>network-address</context>
|
||||||
</parameter>
|
</parameter>
|
||||||
|
<parameter name="apiVersion" type="integer" required="false" min="1" max="2">
|
||||||
|
<label>API version</label>
|
||||||
|
<description>The API version of the Go-eCharger</description>
|
||||||
|
</parameter>
|
||||||
<parameter name="refreshInterval" type="integer" required="false" unit="s">
|
<parameter name="refreshInterval" type="integer" required="false" unit="s">
|
||||||
<label>Refresh Interval</label>
|
<label>Refresh Interval</label>
|
||||||
<description>Refresh interval for acquiring data from Go-eCharger in seconds</description>
|
<description>Refresh interval for acquiring data from Go-eCharger in seconds</description>
|
||||||
|
@ -65,6 +72,12 @@
|
||||||
<description>Maximum current per phase allowed to use for charging</description>
|
<description>Maximum current per phase allowed to use for charging</description>
|
||||||
<state pattern="%d %unit%" readOnly="false"/>
|
<state pattern="%d %unit%" readOnly="false"/>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
<channel-type id="maxCurrTmp">
|
||||||
|
<item-type>Number:ElectricCurrent</item-type>
|
||||||
|
<label>Maximum Current Temporary</label>
|
||||||
|
<description>Maximum current temporary (not written to EEPROM)</description>
|
||||||
|
<state pattern="%d %unit%" readOnly="false"/>
|
||||||
|
</channel-type>
|
||||||
<channel-type id="pwm">
|
<channel-type id="pwm">
|
||||||
<item-type>String</item-type>
|
<item-type>String</item-type>
|
||||||
<label>PWM signal status</label>
|
<label>PWM signal status</label>
|
||||||
|
@ -149,6 +162,12 @@
|
||||||
<item-type>Number</item-type>
|
<item-type>Number</item-type>
|
||||||
<label>Phases</label>
|
<label>Phases</label>
|
||||||
<description>Amount of phases currently used for charging</description>
|
<description>Amount of phases currently used for charging</description>
|
||||||
|
<state readOnly="false"/>
|
||||||
|
</channel-type>
|
||||||
|
<channel-type id="fs">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Force state</label>
|
||||||
|
<description>Force state (Neutral=0, Off=1, On=2)</description>
|
||||||
<state readOnly="true"/>
|
<state readOnly="true"/>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
<channel-type id="scl">
|
<channel-type id="scl">
|
||||||
|
@ -181,11 +200,19 @@
|
||||||
<description>Specifies the max amps that can be charged with that cable</description>
|
<description>Specifies the max amps that can be charged with that cable</description>
|
||||||
<state pattern="%d %unit%" readOnly="true"/>
|
<state pattern="%d %unit%" readOnly="true"/>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
<channel-type id="tmpT2p">
|
||||||
|
<item-type>Number:Temperature</item-type>
|
||||||
|
<label>Temperature type 2 port</label>
|
||||||
|
<description>Temperature of the Go-eCharger on the type 2 port</description>
|
||||||
|
<state pattern="%d %unit%" readOnly="true"/>
|
||||||
|
<category>Temperature</category>
|
||||||
|
</channel-type>
|
||||||
<channel-type id="tmp">
|
<channel-type id="tmp">
|
||||||
<item-type>Number:Temperature</item-type>
|
<item-type>Number:Temperature</item-type>
|
||||||
<label>Temperature</label>
|
<label>Temperature circuit board</label>
|
||||||
<description>Temperature of the Go-eCharger</description>
|
<description>Temperature of the Go-eCharger on circuit board</description>
|
||||||
<state pattern="%d %unit%" readOnly="true"/>
|
<state pattern="%d %unit%" readOnly="true"/>
|
||||||
|
<category>Temperature</category>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
<channel-type id="fmw">
|
<channel-type id="fmw">
|
||||||
<item-type>String</item-type>
|
<item-type>String</item-type>
|
||||||
|
|
Loading…
Reference in New Issue