[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:
@@ -31,6 +31,7 @@ public class GoEChargerBindingConstants {
|
||||
|
||||
// List of all Channel ids
|
||||
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 PWM_SIGNAL = "pwmSignal";
|
||||
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_L2 = "powerL2";
|
||||
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 CABLE_ENCODING = "cableCurrent";
|
||||
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_LIMIT = "sessionChargeEnergyLimit";
|
||||
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 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.
|
||||
*
|
||||
* @author Samuel Brucksch - Initial contribution
|
||||
* @author Reinhard Plaim - Add apiVersion
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GoEChargerConfiguration {
|
||||
|
||||
public @Nullable String ip;
|
||||
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.jetty.client.HttpClient;
|
||||
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.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
@@ -40,7 +41,6 @@ import org.osgi.service.component.annotations.Reference;
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.goecharger", service = ThingHandlerFactory.class)
|
||||
public class GoEChargerHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_GOE);
|
||||
private final HttpClient httpClient;
|
||||
|
||||
@@ -57,9 +57,15 @@ public class GoEChargerHandlerFactory extends BaseThingHandlerFactory {
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
var apiVersion = thing.getConfiguration().as(GoEChargerConfiguration.class).apiVersion;
|
||||
|
||||
if (THING_TYPE_GOE.equals(thingTypeUID)) {
|
||||
return new GoEChargerHandler(thing, httpClient);
|
||||
if (apiVersion == 1) {
|
||||
return new GoEChargerHandler(thing, httpClient);
|
||||
}
|
||||
if (apiVersion == 2) {
|
||||
return new GoEChargerV2Handler(thing, httpClient);
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
* @author Samuel Brucksch - Initial contribution
|
||||
* @author Reinhard Plaim - move some properties to base DTO
|
||||
*/
|
||||
public class GoEStatusResponseDTO {
|
||||
public class GoEStatusResponseDTO extends GoEStatusResponseBaseDTO {
|
||||
@SerializedName("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")
|
||||
public Integer phases;
|
||||
|
||||
@SerializedName("ast")
|
||||
public Integer accessConfiguration;
|
||||
|
||||
@SerializedName("alw")
|
||||
public Integer allowCharging;
|
||||
|
||||
@SerializedName("tmp")
|
||||
public Integer temperature;
|
||||
|
||||
@SerializedName("dws")
|
||||
public Long sessionChargeConsumption;
|
||||
|
||||
@SerializedName("dwo")
|
||||
public Integer sessionChargeConsumptionLimit;
|
||||
|
||||
@SerializedName("eto")
|
||||
public Long totalChargeConsumption;
|
||||
@SerializedName("dws")
|
||||
public Long sessionChargeConsumption;
|
||||
|
||||
@SerializedName("fwv")
|
||||
public String firmware;
|
||||
@SerializedName("amx")
|
||||
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;
|
||||
|
||||
import static org.openhab.binding.goecharger.internal.GoEChargerBindingConstants.ACCESS_CONFIGURATION;
|
||||
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 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 javax.measure.quantity.ElectricCurrent;
|
||||
import javax.measure.quantity.Energy;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
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.GoEChargerConfiguration;
|
||||
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;
|
||||
@@ -64,7 +40,6 @@ 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.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
@@ -72,7 +47,6 @@ import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
@@ -80,34 +54,31 @@ import com.google.gson.JsonSyntaxException;
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Samuel Brucksch - Initial contribution
|
||||
* @author Reinhard Plaim - Adapt to use API version 2
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GoEChargerHandler extends BaseThingHandler {
|
||||
public class GoEChargerHandler extends GoEChargerBaseHandler {
|
||||
|
||||
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) {
|
||||
super(thing);
|
||||
this.httpClient = httpClient;
|
||||
super(thing, 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) {
|
||||
case MAX_CURRENT:
|
||||
if (goeResponse.maxCurrent == null) {
|
||||
case MAX_CURRENT_TEMPORARY:
|
||||
if (goeResponse.maxCurrentTemporary == null) {
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
return new QuantityType<>(goeResponse.maxCurrent, Units.AMPERE);
|
||||
return new QuantityType<>(goeResponse.maxCurrentTemporary, Units.AMPERE);
|
||||
case PWM_SIGNAL:
|
||||
if (goeResponse.pwmSignal == null) {
|
||||
return UnDefType.UNDEF;
|
||||
@@ -178,11 +149,6 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
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:
|
||||
if (goeResponse.energy == null) {
|
||||
return UnDefType.UNDEF;
|
||||
@@ -198,7 +164,7 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||
count++;
|
||||
}
|
||||
return new DecimalType(count);
|
||||
case TEMPERATURE:
|
||||
case TEMPERATURE_CIRCUIT_BOARD:
|
||||
if (goeResponse.temperature == null) {
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
@@ -220,26 +186,6 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
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:
|
||||
if (goeResponse.energy == null) {
|
||||
return UnDefType.UNDEF;
|
||||
@@ -272,6 +218,11 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||
return UnDefType.UNDEF;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -286,6 +237,7 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||
|
||||
String key = null;
|
||||
String value = null;
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case MAX_CURRENT:
|
||||
key = "amp";
|
||||
@@ -295,13 +247,22 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||
value = String.valueOf(((QuantityType<ElectricCurrent>) command).toUnit(Units.AMPERE).intValue());
|
||||
}
|
||||
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:
|
||||
key = "dwo";
|
||||
var multiplier = 10;
|
||||
if (command instanceof DecimalType) {
|
||||
value = String.valueOf(((DecimalType) command).intValue() * 10);
|
||||
value = String.valueOf(((DecimalType) command).intValue() * multiplier);
|
||||
} else if (command instanceof QuantityType<?>) {
|
||||
value = String
|
||||
.valueOf(((QuantityType<Energy>) command).toUnit(Units.KILOWATT_HOUR).intValue() * 10);
|
||||
value = String.valueOf(
|
||||
((QuantityType<Energy>) command).toUnit(Units.KILOWATT_HOUR).intValue() * multiplier);
|
||||
}
|
||||
break;
|
||||
case ALLOW_CHARGING:
|
||||
@@ -330,8 +291,8 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
if (key != null && value != null) {
|
||||
sendData(key, value);
|
||||
} else {
|
||||
@@ -341,96 +302,82 @@ public class GoEChargerHandler extends BaseThingHandler {
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
config = getConfigAs(GoEChargerConfiguration.class);
|
||||
allChannels = getThing().getChannels().stream().map(channel -> channel.getUID().getId())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
startAutomaticRefresh();
|
||||
logger.debug("Finished initializing!");
|
||||
super.initialize();
|
||||
}
|
||||
|
||||
private String getUrl(String type) {
|
||||
return type.replace("%IP%", StringUtils.trimToEmpty(config.ip));
|
||||
private String getReadUrl() {
|
||||
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) {
|
||||
String urlStr = getUrl(GoEChargerBindingConstants.MQTT_URL).replace("%KEY%", key).replace("%VALUE%", value);
|
||||
logger.debug("POST URL = {}", urlStr);
|
||||
String urlStr = getWriteUrl(key, value);
|
||||
logger.trace("GET URL = {}", urlStr);
|
||||
|
||||
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();
|
||||
String response = contentResponse.getContentAsString();
|
||||
logger.debug("POST Response: {}", response);
|
||||
GoEStatusResponseDTO result = gson.fromJson(response, GoEStatusResponseDTO.class);
|
||||
updateChannelsAndStatus(result, null);
|
||||
} catch (InterruptedException | TimeoutException | ExecutionException | JsonSyntaxException e) {
|
||||
updateChannelsAndStatus(null, e.getMessage());
|
||||
|
||||
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-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
|
||||
* @throws ExecutionException
|
||||
* @throws TimeoutException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Nullable
|
||||
private GoEStatusResponseDTO getGoEData()
|
||||
@Override
|
||||
protected GoEStatusResponseBaseDTO getGoEData()
|
||||
throws InterruptedException, TimeoutException, ExecutionException, JsonSyntaxException {
|
||||
String urlStr = getUrl(GoEChargerBindingConstants.API_URL);
|
||||
logger.debug("GET URL = {}", urlStr);
|
||||
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.debug("GET Response: {}", response);
|
||||
return gson.fromJson(response, GoEStatusResponseDTO.class);
|
||||
logger.trace("GET Response: {}", response);
|
||||
|
||||
if (config.apiVersion == 1) {
|
||||
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) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, message);
|
||||
allChannels.forEach(channel -> updateState(channel, UnDefType.UNDEF));
|
||||
} else {
|
||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
|
||||
allChannels.forEach(channel -> updateState(channel, getValue(channel, 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;
|
||||
allChannels.forEach(channel -> updateState(channel, getValue(channel, (GoEStatusResponseDTO) goeResponse)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.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.description = Refresh interval for acquiring data from Go-eCharger in seconds
|
||||
|
||||
# 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.description = If true charging is allowed
|
||||
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.cl3.label = Current 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.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.description = Amount of energy that has been charged since installation
|
||||
channel-type.goecharger.fmw.label = Firmware
|
||||
channel-type.goecharger.fmw.description = Firmware Version
|
||||
channel-type.goecharger.pha.label = Phases
|
||||
channel-type.goecharger.pha.description = Amount of phases currently used for charging
|
||||
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.pl1.label = Power L1
|
||||
channel-type.goecharger.pl1.description = Power on L1
|
||||
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.pwm.label = PWM 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.pwm.state.option.CHARGING = Charging
|
||||
channel-type.goecharger.pwm.state.option.WAITING_FOR_CAR = Waiting for car
|
||||
channel-type.goecharger.pwm.state.option.CHARGING_DONE_CAR_CONNECTED = Charging done (car connected)
|
||||
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.tmpT2p.label = Temperature type 2 port
|
||||
channel-type.goecharger.tmpT2p.description = Temperature on the type 2 port of the Go-eCharger
|
||||
channel-type.goecharger.tmp.label = Temperature circuit board
|
||||
channel-type.goecharger.tmp.description = Temperature on the circuit board of the Go-eCharger
|
||||
channel-type.goecharger.vl1.label = Voltage L1
|
||||
channel-type.goecharger.vl1.description = Voltage on L1
|
||||
channel-type.goecharger.vl2.label = Voltage L2
|
||||
channel-type.goecharger.vl2.description = Voltage on L2
|
||||
channel-type.goecharger.vl3.label = Voltage L3
|
||||
channel-type.goecharger.vl3.description = Voltage on L3
|
||||
|
||||
# Others
|
||||
unsuccessful.communication-error=Request response was unsuccessful
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
<channels>
|
||||
<channel id="maxCurrent" typeId="current"/>
|
||||
<channel id="maxCurrentTemp" typeId="maxCurrTmp"/>
|
||||
<channel id="pwmSignal" typeId="pwm"/>
|
||||
<channel id="error" typeId="err"/>
|
||||
<channel id="voltageL1" typeId="vl1"/>
|
||||
@@ -21,15 +22,17 @@
|
||||
<channel id="powerL1" typeId="pl1"/>
|
||||
<channel id="powerL2" typeId="pl2"/>
|
||||
<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="cableCurrent" typeId="cbl"/>
|
||||
<channel id="temperature" typeId="tmp"/>
|
||||
<channel id="firmware" typeId="fmw"/>
|
||||
<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>
|
||||
|
||||
<config-description>
|
||||
@@ -38,6 +41,10 @@
|
||||
<description>The IP address of the Go-eCharger</description>
|
||||
<context>network-address</context>
|
||||
</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">
|
||||
<label>Refresh Interval</label>
|
||||
<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>
|
||||
<state pattern="%d %unit%" readOnly="false"/>
|
||||
</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">
|
||||
<item-type>String</item-type>
|
||||
<label>PWM signal status</label>
|
||||
@@ -149,6 +162,12 @@
|
||||
<item-type>Number</item-type>
|
||||
<label>Phases</label>
|
||||
<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"/>
|
||||
</channel-type>
|
||||
<channel-type id="scl">
|
||||
@@ -181,11 +200,19 @@
|
||||
<description>Specifies the max amps that can be charged with that cable</description>
|
||||
<state pattern="%d %unit%" readOnly="true"/>
|
||||
</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">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>Temperature of the Go-eCharger</description>
|
||||
<label>Temperature circuit board</label>
|
||||
<description>Temperature of the Go-eCharger on circuit board</description>
|
||||
<state pattern="%d %unit%" readOnly="true"/>
|
||||
<category>Temperature</category>
|
||||
</channel-type>
|
||||
<channel-type id="fmw">
|
||||
<item-type>String</item-type>
|
||||
|
||||
Reference in New Issue
Block a user