[daikin] Fix communication errors by retrying failed http requests (#12239)

* [daikin] Fix communication errors by retrying failed http requests

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
This commit is contained in:
jimtng 2022-02-16 16:35:19 +10:00 committed by GitHub
parent 85866c63c0
commit f18ee99b08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 155 additions and 159 deletions

View File

@ -12,13 +12,12 @@
*/
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;
@ -37,7 +36,6 @@ import org.openhab.binding.daikin.internal.api.airbase.AirbaseBasicInfo;
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;
@ -47,11 +45,12 @@ 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;
@ -183,73 +182,73 @@ public class DaikinWebTargets {
}
private String invoke(String uri) throws DaikinCommunicationException {
return invoke(uri, new HashMap<>());
return invoke(uri, null);
}
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);
}
} 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;
}
}
if (response == null) {
throw new DaikinCommunicationException("Daikin controller returned error while invoking " + uriWithParams);
}
return response;
}
private String executeUrl(String url) throws DaikinCommunicationException {
private synchronized String invoke(String url, @Nullable Map<String, String> params)
throws DaikinCommunicationException {
int attemptCount = 1;
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);
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++;
}
}
ContentResponse response = request.send();
if (response.getStatus() == HttpStatus.FORBIDDEN_403) {
throw new DaikinCommunicationForbiddenException("Daikin controller access denied. Check uuid/key.");
}
if (response.getStatus() != HttpStatus.OK_200) {
logger.debug("Daikin controller HTTP status: {} - {}", response.getStatus(), response.getReason());
}
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);
throw new DaikinCommunicationException("Execution interrupted");
}
}
private String paramsToQueryString(Map<String, String> params) {
if (params.isEmpty()) {
return "";
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());
ContentResponse response = request.send();
if (response.getStatus() != HttpStatus.OK_200) {
logger.debug("Daikin controller HTTP status: {} - {} {}", response.getStatus(), response.getReason(), url);
}
return "?" + params.entrySet().stream().map(param -> param.getKey() + "=" + param.getValue())
.collect(Collectors.joining("&"));
if (response.getStatus() == HttpStatus.FORBIDDEN_403) {
throw new DaikinCommunicationForbiddenException("Daikin controller access denied. Check uuid/key.");
}
return response.getContentAsString();
}
private Throwable getRootCause(Throwable exception) {
Throwable cause = exception.getCause();
while (cause != null) {
exception = cause;
cause = cause.getCause();
}
return exception;
}
}

View File

@ -23,7 +23,7 @@ import org.slf4j.LoggerFactory;
/**
* Holds information from the basic_info call.
*
* @author Jimy Tanagra - Initial contribution
* @author Jimmy Tanagra - Initial contribution
*
*/
@NonNullByDefault
@ -38,7 +38,7 @@ public class BasicInfo {
}
public static BasicInfo parse(String response) {
LOGGER.debug("Parsing string: \"{}\"", response);
LOGGER.trace("Parsing string: \"{}\"", response);
Map<String, String> responseMap = InfoParser.parse(response);

View File

@ -50,7 +50,7 @@ public class ControlInfo {
}
public static ControlInfo parse(String response) {
LOGGER.debug("Parsing string: \"{}\"", response);
LOGGER.trace("Parsing string: \"{}\"", response);
Map<String, String> responseMap = InfoParser.parse(response);

View File

@ -12,10 +12,8 @@
*/
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;
@ -42,22 +40,14 @@ public class EnergyInfoDayAndWeek {
}
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));
@ -94,7 +84,7 @@ public class EnergyInfoDayAndWeek {
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;
}

View File

@ -43,10 +43,10 @@ public class EnergyInfoYear {
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;
}

View File

@ -12,21 +12,29 @@
*/
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() {
}
@ -34,7 +42,7 @@ public class 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]));
}
@ -61,7 +69,7 @@ public class InfoParser {
}
}
public static Optional<Integer[]> parseArrayofInt(String value) {
public static Optional<Integer[]> parseArrayOfInt(String value) {
if ("-".equals(value)) {
return Optional.empty();
}
@ -72,11 +80,20 @@ public class InfoParser {
}
}
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;
}
}
}

View File

@ -38,7 +38,7 @@ public class SensorInfo {
}
public static SensorInfo parse(String response) {
LOGGER.debug("Parsing string: \"{}\"", response);
LOGGER.trace("Parsing string: \"{}\"", response);
Map<String, String> responseMap = InfoParser.parse(response);

View File

@ -39,7 +39,7 @@ public class AirbaseBasicInfo {
}
public static AirbaseBasicInfo parse(String response) {
LOGGER.debug("Parsing string: \"{}\"", response);
LOGGER.trace("Parsing string: \"{}\"", response);
Map<String, String> responseMap = InfoParser.parse(response);

View File

@ -49,7 +49,7 @@ public class AirbaseControlInfo {
}
public static AirbaseControlInfo parse(String response) {
LOGGER.debug("Parsing string: \"{}\"", response);
LOGGER.trace("Parsing string: \"{}\"", response);
Map<String, String> responseMap = InfoParser.parse(response);

View File

@ -43,7 +43,7 @@ public class AirbaseModelInfo {
}
public static AirbaseModelInfo parse(String response) {
LOGGER.debug("Parsing string: \"{}\"", response);
LOGGER.trace("Parsing string: \"{}\"", response);
Map<String, String> responseMap = InfoParser.parse(response);

View File

@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory;
* Holds information from the basic_info call.
*
* @author Paul Smedley - Initial contribution
* @author Jimmy Tanagra - Refactor zone array to 0-based
*
*/
@NonNullByDefault
@ -34,13 +35,13 @@ public class AirbaseZoneInfo {
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);
@ -48,18 +49,19 @@ public class AirbaseZoneInfo {
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);

View File

@ -77,7 +77,7 @@ public class DaikinACUnitDiscoveryService extends AbstractDiscoveryService {
@Override
protected void startBackgroundDiscovery() {
logger.debug("Starting background discovery");
logger.trace("Starting background discovery");
if (backgroundFuture != null && !backgroundFuture.isDone()) {
backgroundFuture.cancel(true);
@ -100,7 +100,7 @@ public class DaikinACUnitDiscoveryService extends AbstractDiscoveryService {
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);
@ -133,7 +133,7 @@ public class DaikinACUnitDiscoveryService extends AbstractDiscoveryService {
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"));
@ -165,7 +165,7 @@ public class DaikinACUnitDiscoveryService extends AbstractDiscoveryService {
}
DiscoveryResult result = resultBuilder.build();
logger.debug("Successfully discovered host {}", host);
logger.trace("Successfully discovered host {}", host);
thingDiscovered(result);
return true;
}
@ -176,7 +176,7 @@ public class DaikinACUnitDiscoveryService extends AbstractDiscoveryService {
.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;
}

View File

@ -12,7 +12,6 @@
*/
package org.openhab.binding.daikin.internal.handler;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Optional;
import java.util.stream.IntStream;
@ -40,7 +39,6 @@ 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.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
@ -66,12 +64,11 @@ public class DaikinAcUnitHandler extends DaikinBaseHandler {
}
@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);
@ -152,7 +149,6 @@ public class DaikinAcUnitHandler extends DaikinBaseHandler {
// Suppress any error if energy info is not supported.
logger.debug("getEnergyInfoDayAndWeek() error: {}", e.getMessage());
}
updateStatus(ThingStatus.ONLINE);
}
@Override

View File

@ -12,7 +12,6 @@
*/
package org.openhab.binding.daikin.internal.handler;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
@ -37,7 +36,6 @@ import org.openhab.core.library.types.OnOffType;
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;
@ -75,46 +73,40 @@ public class DaikinAirbaseUnitHandler extends DaikinBaseHandler {
}
@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()));
AirbaseControlInfo controlInfo = webTargets.getAirbaseControlInfo();
if (!"OK".equals(controlInfo.ret)) {
throw new DaikinCommunicationException("Invalid response from host");
}
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()));
}
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()));
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();
if (sensorInfo != null) {
updateTemperatureChannel(DaikinBindingConstants.CHANNEL_INDOOR_TEMP, sensorInfo.indoortemp);
updateTemperatureChannel(DaikinBindingConstants.CHANNEL_OUTDOOR_TEMP, sensorInfo.outdoortemp);
}
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
@ -177,14 +169,21 @@ public class DaikinAirbaseUnitHandler extends DaikinBaseHandler {
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 ({})",
@ -192,14 +191,8 @@ public class DaikinAirbaseUnitHandler extends DaikinBaseHandler {
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

View File

@ -12,7 +12,6 @@
*/
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;
@ -68,7 +67,7 @@ public abstract class DaikinBaseHandler extends BaseThingHandler {
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;
@ -131,8 +130,8 @@ public abstract class DaikinBaseHandler extends BaseThingHandler {
}
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());
}
}
@ -148,7 +147,6 @@ public abstract class DaikinBaseHandler extends BaseThingHandler {
}
webTargets = new DaikinWebTargets(httpClient, config.host, config.secure, config.uuid);
refreshInterval = config.refresh;
schedulePoll();
}
}
@ -182,8 +180,11 @@ public abstract class DaikinBaseHandler extends BaseThingHandler {
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);
@ -194,9 +195,7 @@ public abstract class DaikinBaseHandler extends BaseThingHandler {
"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());
}
}