*/
package org.openhab.binding.daikin.internal;
-import java.io.IOException;
+import java.io.EOFException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
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.openhab.binding.daikin.internal.api.airbase.AirbaseControlInfo;
import org.openhab.binding.daikin.internal.api.airbase.AirbaseModelInfo;
import org.openhab.binding.daikin.internal.api.airbase.AirbaseZoneInfo;
-import org.openhab.core.io.net.http.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* @author Tim Waterhouse - Initial Contribution
* @author Paul Smedley <paul@smedley.id.au> - Modifications to support Airbase Controllers
* @author Jimmy Tanagra - Add support for https and Daikin's uuid authentication
+ * Implement connection retry
*
*/
@NonNullByDefault
public class DaikinWebTargets {
- private static final int TIMEOUT_MS = 30000;
+ private static final int TIMEOUT_MS = 5000;
private String getBasicInfoUri;
private String setControlInfoUri;
}
private String invoke(String uri) throws DaikinCommunicationException {
- return invoke(uri, new HashMap<>());
- }
-
- private String invoke(String uri, Map<String, String> params) throws DaikinCommunicationException {
- String uriWithParams = uri + paramsToQueryString(params);
- logger.debug("Calling url: {}", uriWithParams);
- String response;
- synchronized (this) {
- try {
- if (httpClient != null) {
- response = executeUrl(uriWithParams);
- } else {
- // a fall back method
- logger.debug("Using HttpUtil fall scback");
- response = HttpUtil.executeUrl("GET", uriWithParams, TIMEOUT_MS);
+ return invoke(uri, null);
+ }
+
+ private synchronized String invoke(String url, @Nullable Map<String, String> params)
+ throws DaikinCommunicationException {
+ int attemptCount = 1;
+ try {
+ while (true) {
+ try {
+ String result = executeUrl(url, params);
+ if (attemptCount > 1) {
+ logger.debug("HTTP request successful on attempt #{}: {}", attemptCount, url);
+ }
+ return result;
+ } catch (ExecutionException | TimeoutException e) {
+ if (attemptCount >= 3) {
+ logger.debug("HTTP request failed after {} attempts: {}", attemptCount, url, e);
+ Throwable rootCause = getRootCause(e);
+ String message = rootCause.getMessage();
+ // EOFException message is too verbose/gibberish
+ if (message == null || rootCause instanceof EOFException) {
+ message = "Connection error";
+ }
+ throw new DaikinCommunicationException(message);
+ }
+ logger.debug("HTTP request error on attempt #{}: {} {}", attemptCount, url, e.getMessage());
+ Thread.sleep(500 * attemptCount);
+ attemptCount++;
}
- } catch (DaikinCommunicationException ex) {
- throw ex;
- } catch (IOException ex) {
- // Response will also be set to null if parsing in executeUrl fails so we use null here to make the
- // error check below consistent.
- response = null;
}
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new DaikinCommunicationException("Execution interrupted");
}
-
- if (response == null) {
- throw new DaikinCommunicationException("Daikin controller returned error while invoking " + uriWithParams);
- }
-
- return response;
}
- private String executeUrl(String url) throws DaikinCommunicationException {
- try {
- Request request = httpClient.newRequest(url).method(HttpMethod.GET).timeout(TIMEOUT_MS,
- TimeUnit.MILLISECONDS);
- if (uuid != null) {
- request.header("X-Daikin-uuid", uuid);
- logger.debug("Header: X-Daikin-uuid: {}", uuid);
- }
- ContentResponse response = request.send();
+ private String executeUrl(String url, @Nullable Map<String, String> params)
+ throws InterruptedException, TimeoutException, ExecutionException, DaikinCommunicationException {
+ Request request = httpClient.newRequest(url).method(HttpMethod.GET).timeout(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ if (uuid != null) {
+ request.header("X-Daikin-uuid", uuid);
+ logger.trace("Header: X-Daikin-uuid: {}", uuid);
+ }
+ if (params != null) {
+ params.forEach((key, value) -> request.param(key, value));
+ }
+ logger.trace("Calling url: {}", request.getURI());
- if (response.getStatus() == HttpStatus.FORBIDDEN_403) {
- throw new DaikinCommunicationForbiddenException("Daikin controller access denied. Check uuid/key.");
- }
+ ContentResponse response = request.send();
- if (response.getStatus() != HttpStatus.OK_200) {
- logger.debug("Daikin controller HTTP status: {} - {}", response.getStatus(), response.getReason());
- }
+ if (response.getStatus() != HttpStatus.OK_200) {
+ logger.debug("Daikin controller HTTP status: {} - {} {}", response.getStatus(), response.getReason(), url);
+ }
- return response.getContentAsString();
- } catch (DaikinCommunicationException e) {
- throw e;
- } catch (ExecutionException | TimeoutException e) {
- throw new DaikinCommunicationException("Daikin HTTP error", e);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new DaikinCommunicationException("Daikin HTTP interrupted", e);
+ if (response.getStatus() == HttpStatus.FORBIDDEN_403) {
+ throw new DaikinCommunicationForbiddenException("Daikin controller access denied. Check uuid/key.");
}
+
+ return response.getContentAsString();
}
- private String paramsToQueryString(Map<String, String> params) {
- if (params.isEmpty()) {
- return "";
+ private Throwable getRootCause(Throwable exception) {
+ Throwable cause = exception.getCause();
+ while (cause != null) {
+ exception = cause;
+ cause = cause.getCause();
}
-
- return "?" + params.entrySet().stream().map(param -> param.getKey() + "=" + param.getValue())
- .collect(Collectors.joining("&"));
+ return exception;
}
}
/**
* Holds information from the basic_info call.
*
- * @author Jimy Tanagra - Initial contribution
+ * @author Jimmy Tanagra - Initial contribution
*
*/
@NonNullByDefault
}
public static BasicInfo parse(String response) {
- LOGGER.debug("Parsing string: \"{}\"", response);
+ LOGGER.trace("Parsing string: \"{}\"", response);
Map<String, String> responseMap = InfoParser.parse(response);
}
public static ControlInfo parse(String response) {
- LOGGER.debug("Parsing string: \"{}\"", response);
+ LOGGER.trace("Parsing string: \"{}\"", response);
Map<String, String> responseMap = InfoParser.parse(response);
*/
package org.openhab.binding.daikin.internal.api;
-import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
-import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.Logger;
}
public static EnergyInfoDayAndWeek parse(String response) {
- EnergyInfoDayAndWeek info = new EnergyInfoDayAndWeek();
-
LOGGER.trace("Parsing string: \"{}\"", response);
// /aircon/get_week_power_ex
// ret=OK,s_dayw=0,week_heat=1/1/1/1/1/5/2/1/1/1/1/2/1/1,week_cool=0/0/0/0/0/0/0/0/0/0/0/0/0/0
// week_heat=<today>/<today-1>/<today-2>/<today-3>/...
- Map<String, String> responseMap = Arrays.asList(response.split(",")).stream().filter(kv -> kv.contains("="))
- .map(kv -> {
- String[] keyValue = kv.split("=");
- String key = keyValue[0];
- String value = keyValue.length > 1 ? keyValue[1] : "";
- return new String[] { key, value };
- }).collect(Collectors.toMap(x -> x[0], x -> x[1]));
-
- if (responseMap.get("ret") != null && ("OK".equals(responseMap.get("ret")))) {
+ Map<String, String> responseMap = InfoParser.parse(response);
+ EnergyInfoDayAndWeek info = new EnergyInfoDayAndWeek();
+ if ("OK".equals(responseMap.get("ret"))) {
Optional<Integer> dayOfWeek = Optional.ofNullable(responseMap.get("s_dayw"))
.flatMap(value -> InfoParser.parseInt(value));
info.energyCoolingLastWeek = Optional.of(previousWeekEnergy / 10);
}
} else {
- LOGGER.debug("did not receive 'ret=OK' from adapter");
+ LOGGER.debug("EnergyInfoDayAndWeek::parse() did not receive 'ret=OK' from adapter");
}
return info;
}
EnergyInfoYear info = new EnergyInfoYear();
info.energyHeatingThisYear = Optional.ofNullable(responseMap.get("curr_year_heat"))
- .flatMap(value -> InfoParser.parseArrayofInt(value, 12));
+ .flatMap(value -> InfoParser.parseArrayOfInt(value, 12));
info.energyCoolingThisYear = Optional.ofNullable(responseMap.get("curr_year_cool"))
- .flatMap(value -> InfoParser.parseArrayofInt(value, 12));
+ .flatMap(value -> InfoParser.parseArrayOfInt(value, 12));
return info;
}
*/
package org.openhab.binding.daikin.internal.api;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Class for parsing the comma separated values and array values returned by the Daikin Controller.
*
* @author Jimmy Tanagra - Initial Contribution
+ * urldecode the parsed value
*
*/
@NonNullByDefault
public class InfoParser {
+ private static final Logger logger = LoggerFactory.getLogger(InfoParser.class);
+
private InfoParser() {
}
return Stream.of(response.split(",")).filter(kv -> kv.contains("=")).map(kv -> {
String[] keyValue = kv.split("=");
String key = keyValue[0];
- String value = keyValue.length > 1 ? keyValue[1] : "";
+ String value = keyValue.length > 1 ? urldecode(keyValue[1]) : "";
return new String[] { key, value };
}).collect(Collectors.toMap(x -> x[0], x -> x[1]));
}
}
}
- public static Optional<Integer[]> parseArrayofInt(String value) {
+ public static Optional<Integer[]> parseArrayOfInt(String value) {
if ("-".equals(value)) {
return Optional.empty();
}
}
}
- public static Optional<Integer[]> parseArrayofInt(String value, int expectedArraySize) {
- Optional<Integer[]> result = parseArrayofInt(value);
+ public static Optional<Integer[]> parseArrayOfInt(String value, int expectedArraySize) {
+ Optional<Integer[]> result = parseArrayOfInt(value);
if (result.isPresent() && result.get().length == expectedArraySize) {
return result;
}
return Optional.empty();
}
+
+ public static String urldecode(String value) {
+ try {
+ return URLDecoder.decode(value, StandardCharsets.UTF_8.toString());
+ } catch (UnsupportedEncodingException e) {
+ logger.warn("Unsupported encoding error in '{}'", value, e);
+ return value;
+ }
+ }
}
}
public static SensorInfo parse(String response) {
- LOGGER.debug("Parsing string: \"{}\"", response);
+ LOGGER.trace("Parsing string: \"{}\"", response);
Map<String, String> responseMap = InfoParser.parse(response);
}
public static AirbaseBasicInfo parse(String response) {
- LOGGER.debug("Parsing string: \"{}\"", response);
+ LOGGER.trace("Parsing string: \"{}\"", response);
Map<String, String> responseMap = InfoParser.parse(response);
}
public static AirbaseControlInfo parse(String response) {
- LOGGER.debug("Parsing string: \"{}\"", response);
+ LOGGER.trace("Parsing string: \"{}\"", response);
Map<String, String> responseMap = InfoParser.parse(response);
}
public static AirbaseModelInfo parse(String response) {
- LOGGER.debug("Parsing string: \"{}\"", response);
+ LOGGER.trace("Parsing string: \"{}\"", response);
Map<String, String> responseMap = InfoParser.parse(response);
* Holds information from the basic_info call.
*
* @author Paul Smedley - Initial contribution
+ * @author Jimmy Tanagra - Refactor zone array to 0-based
*
*/
@NonNullByDefault
private static final Logger LOGGER = LoggerFactory.getLogger(AirbaseZoneInfo.class);
public String zonenames = "";
- public boolean zone[] = new boolean[9];
+ public boolean zone[] = new boolean[8];
private AirbaseZoneInfo() {
}
public static AirbaseZoneInfo parse(String response) {
- LOGGER.debug("Parsing string: \"{}\"", response);
+ LOGGER.trace("Parsing string: \"{}\"", response);
Map<String, String> responseMap = InfoParser.parse(response);
info.zonenames = Optional.ofNullable(responseMap.get("zone_name")).orElse("");
String zoneinfo = Optional.ofNullable(responseMap.get("zone_onoff")).orElse("");
- String[] zones = zoneinfo.split("%3b");
+ String[] zones = zoneinfo.split(";");
- for (int i = 1; i < 9; i++) {
- info.zone[i] = "1".equals(zones[i - 1]);
+ int count = Math.min(info.zone.length, zones.length);
+ for (int i = 0; i < count; i++) {
+ info.zone[i] = "1".equals(zones[i]);
}
return info;
}
public Map<String, String> getParamString() {
Map<String, String> params = new LinkedHashMap<>();
- String onoffstring = IntStream.range(1, zone.length).mapToObj(idx -> zone[idx] ? "1" : "0")
- .collect(Collectors.joining("%3b"));
+ String onoffstring = IntStream.range(0, zone.length).mapToObj(idx -> zone[idx] ? "1" : "0")
+ .collect(Collectors.joining(";"));
params.put("zone_name", zonenames);
params.put("zone_onoff", onoffstring);
@Override
protected void startBackgroundDiscovery() {
- logger.debug("Starting background discovery");
+ logger.trace("Starting background discovery");
if (backgroundFuture != null && !backgroundFuture.isDone()) {
backgroundFuture.cancel(true);
return () -> {
long timestampOfLastScan = getTimestampOfLastScan();
for (InetAddress broadcastAddress : getBroadcastAddresses()) {
- logger.debug("Starting broadcast for {}", broadcastAddress.toString());
+ logger.trace("Starting broadcast for {}", broadcastAddress.toString());
try (DatagramSocket socket = new DatagramSocket()) {
socket.setBroadcast(true);
String host = incomingPacket.getAddress().toString().substring(1);
String data = new String(incomingPacket.getData(), 0, incomingPacket.getLength(), "US-ASCII");
- logger.debug("Received packet from {}: {}", host, data);
+ logger.trace("Received packet from {}: {}", host, data);
Map<String, String> parsedData = InfoParser.parse(data);
Boolean secure = "1".equals(parsedData.get("en_secure"));
}
DiscoveryResult result = resultBuilder.build();
- logger.debug("Successfully discovered host {}", host);
+ logger.trace("Successfully discovered host {}", host);
thingDiscovered(result);
return true;
}
.withProperty(DaikinConfiguration.HOST, host).withLabel("Daikin Airbase AC Unit (" + host + ")")
.withRepresentationProperty(DaikinConfiguration.HOST).build();
- logger.debug("Successfully discovered host {}", host);
+ logger.trace("Successfully discovered host {}", host);
thingDiscovered(result);
return true;
}
*/
package org.openhab.binding.daikin.internal.handler;
-import java.io.IOException;
import java.math.BigDecimal;
import java.util.Optional;
import java.util.stream.IntStream;
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.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
}
@Override
- protected void pollStatus() throws IOException {
- DaikinWebTargets webTargets = this.webTargets;
- if (webTargets == null) {
- return;
- }
+ protected void pollStatus() throws DaikinCommunicationException {
ControlInfo controlInfo = webTargets.getControlInfo();
+ if (!"OK".equals(controlInfo.ret)) {
+ throw new DaikinCommunicationException("Invalid response from host");
+ }
updateState(DaikinBindingConstants.CHANNEL_AC_POWER, controlInfo.power ? OnOffType.ON : OnOffType.OFF);
updateTemperatureChannel(DaikinBindingConstants.CHANNEL_AC_TEMP, controlInfo.temp);
// Suppress any error if energy info is not supported.
logger.debug("getEnergyInfoDayAndWeek() error: {}", e.getMessage());
}
- updateStatus(ThingStatus.ONLINE);
}
@Override
*/
package org.openhab.binding.daikin.internal.handler;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
-import org.openhab.core.thing.ThingStatus;
import org.openhab.core.types.Command;
import org.openhab.core.types.StateOption;
import org.slf4j.Logger;
}
@Override
- protected void pollStatus() throws IOException {
- AirbaseControlInfo controlInfo = webTargets.getAirbaseControlInfo();
-
+ protected void pollStatus() throws DaikinCommunicationException {
if (airbaseModelInfo == null || !"OK".equals(airbaseModelInfo.ret)) {
airbaseModelInfo = webTargets.getAirbaseModelInfo();
updateChannelStateDescriptions();
}
- if (controlInfo != null) {
- updateState(DaikinBindingConstants.CHANNEL_AC_POWER, controlInfo.power ? OnOffType.ON : OnOffType.OFF);
- updateTemperatureChannel(DaikinBindingConstants.CHANNEL_AC_TEMP, controlInfo.temp);
- updateState(DaikinBindingConstants.CHANNEL_AC_MODE, new StringType(controlInfo.mode.name()));
- updateState(DaikinBindingConstants.CHANNEL_AIRBASE_AC_FAN_SPEED,
- new StringType(controlInfo.fanSpeed.name()));
-
- if (!controlInfo.power) {
- updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.OFF.getValue()));
- } else if (controlInfo.mode == AirbaseMode.COLD) {
- updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.COOL.getValue()));
- } else if (controlInfo.mode == AirbaseMode.HEAT) {
- updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.HEAT.getValue()));
- } else if (controlInfo.mode == AirbaseMode.AUTO) {
- updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.AUTO.getValue()));
- }
+ AirbaseControlInfo controlInfo = webTargets.getAirbaseControlInfo();
+ if (!"OK".equals(controlInfo.ret)) {
+ throw new DaikinCommunicationException("Invalid response from host");
}
- SensorInfo sensorInfo = webTargets.getAirbaseSensorInfo();
- if (sensorInfo != null) {
- updateTemperatureChannel(DaikinBindingConstants.CHANNEL_INDOOR_TEMP, sensorInfo.indoortemp);
+ updateState(DaikinBindingConstants.CHANNEL_AC_POWER, OnOffType.from(controlInfo.power));
+ updateTemperatureChannel(DaikinBindingConstants.CHANNEL_AC_TEMP, controlInfo.temp);
+ updateState(DaikinBindingConstants.CHANNEL_AC_MODE, new StringType(controlInfo.mode.name()));
+ updateState(DaikinBindingConstants.CHANNEL_AIRBASE_AC_FAN_SPEED, new StringType(controlInfo.fanSpeed.name()));
- updateTemperatureChannel(DaikinBindingConstants.CHANNEL_OUTDOOR_TEMP, sensorInfo.outdoortemp);
+ if (!controlInfo.power) {
+ updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.OFF.getValue()));
+ } else if (controlInfo.mode == AirbaseMode.COLD) {
+ updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.COOL.getValue()));
+ } else if (controlInfo.mode == AirbaseMode.HEAT) {
+ updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.HEAT.getValue()));
+ } else if (controlInfo.mode == AirbaseMode.AUTO) {
+ updateState(DaikinBindingConstants.CHANNEL_AC_HOMEKITMODE, new StringType(HomekitMode.AUTO.getValue()));
}
+ SensorInfo sensorInfo = webTargets.getAirbaseSensorInfo();
+ updateTemperatureChannel(DaikinBindingConstants.CHANNEL_INDOOR_TEMP, sensorInfo.indoortemp);
+ updateTemperatureChannel(DaikinBindingConstants.CHANNEL_OUTDOOR_TEMP, sensorInfo.outdoortemp);
+
AirbaseZoneInfo zoneInfo = webTargets.getAirbaseZoneInfo();
- if (zoneInfo != null) {
- IntStream.range(0, zoneInfo.zone.length)
- .forEach(idx -> updateState(DaikinBindingConstants.CHANNEL_AIRBASE_AC_ZONE + idx,
- OnOffType.from(zoneInfo.zone[idx])));
- }
- updateStatus(ThingStatus.ONLINE);
+ IntStream.range(0, zoneInfo.zone.length)
+ .forEach(idx -> updateState(DaikinBindingConstants.CHANNEL_AIRBASE_AC_ZONE + (idx + 1),
+ OnOffType.from(zoneInfo.zone[idx])));
}
@Override
webTargets.setAirbaseControlInfo(info);
}
+ /**
+ *
+ * Turn the zone on/off
+ * The Airbase controller allows turning off all zones, so we allow it here too
+ *
+ * @param zone the zone number starting from 1
+ * @param command true to turn on the zone, false to turn it off
+ *
+ */
protected void changeZone(int zone, boolean command) throws DaikinCommunicationException {
AirbaseZoneInfo zoneInfo = webTargets.getAirbaseZoneInfo();
- long commonZones = 0;
long maxZones = zoneInfo.zone.length;
if (airbaseModelInfo != null) {
- maxZones = Math.min(maxZones - 1, airbaseModelInfo.zonespresent);
- commonZones = airbaseModelInfo.commonzone;
+ maxZones = Math.min(maxZones, airbaseModelInfo.zonespresent);
}
if (zone <= 0 || zone > maxZones) {
logger.warn("The given zone number ({}) is outside the number of zones supported by the controller ({})",
return;
}
- long openZones = IntStream.range(0, zoneInfo.zone.length).filter(idx -> zoneInfo.zone[idx]).count()
- + commonZones;
- logger.debug("Number of open zones: \"{}\"", openZones);
-
- if (openZones >= 1) {
- zoneInfo.zone[zone] = command;
- webTargets.setAirbaseZoneInfo(zoneInfo);
- }
+ zoneInfo.zone[zone - 1] = command;
+ webTargets.setAirbaseZoneInfo(zoneInfo);
}
@Override
*/
package org.openhab.binding.daikin.internal.handler;
-import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
private boolean uuidRegistrationAttempted = false;
// Abstract methods to be overridden by specific Daikin implementation class
- protected abstract void pollStatus() throws IOException;
+ protected abstract void pollStatus() throws DaikinCommunicationException;
protected abstract void changePower(boolean power) throws DaikinCommunicationException;
}
logger.debug("Received command ({}) of wrong type for thing '{}' on channel {}", command,
thing.getUID().getAsString(), channelUID.getId());
- } catch (DaikinCommunicationException ex) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ex.getMessage());
+ } catch (DaikinCommunicationException e) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
}
}
webTargets = new DaikinWebTargets(httpClient, config.host, config.secure, config.uuid);
refreshInterval = config.refresh;
-
schedulePoll();
}
}
private synchronized void poll() {
try {
- logger.debug("Polling for state");
+ logger.trace("Polling for state");
pollStatus();
+ if (getThing().getStatus() != ThingStatus.ONLINE) {
+ updateStatus(ThingStatus.ONLINE);
+ }
} catch (DaikinCommunicationForbiddenException e) {
if (!uuidRegistrationAttempted && config.key != null && config.uuid != null) {
logger.debug("poll: Attempting to register uuid {} with key {}", config.uuid, config.key);
"Access denied. Check uuid/key.");
logger.warn("{} access denied by adapter. Check uuid/key.", thing.getUID());
}
- } catch (IOException e) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
- } catch (RuntimeException e) {
+ } catch (DaikinCommunicationException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
}