[tado] Fix AC control bugs; Add null annotations and checks (#12570)
* [tado] add null annotations and checks * [tado] cosmetics * [tado] tweak homeid * [tado] revert int to Integer * [tado] explicit method public declaration * [tado] remove "Bridge not initialized" exception on shutdown * [tado] new state values: error if unsupported; don't force defaults * [tado] adopt reviewer suggestion * [tado] tweaks * [tado] use new,current,default mode for target capabilities; cosmetics * [tado] eliminate dead code * [tado] set or defaults * [tado] change 'nullable Integer' to 'int' * [tado] eliminate warning if handler already disposed * [tado] improve json logging * [tado] fix getTargetTemperature if state is OFF * [tado] add null checks * [tado] log warning instead of throwing exception * [tado] improved json trace logging * [tado] adopt reviewer suggestion * [tado] fix logging to trace * [tado] thread synch, and fix 'this' assignments on futures * [tado] tweak yaml * [tado] fix verticalSwing * [tado] fix fanLevel Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
This commit is contained in:
parent
55beb413bd
commit
3ee741e63b
@ -1050,16 +1050,16 @@ definitions:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/definitions/ACFanLevel"
|
$ref: "#/definitions/ACFanLevel"
|
||||||
horizontalSwing:
|
|
||||||
description: Cooling system horizontal swing modes. (Tado confusingly names this array without an 's')
|
|
||||||
type: array
|
|
||||||
items:
|
|
||||||
$ref: "#/definitions/ACHorizontalSwing"
|
|
||||||
verticalSwing:
|
verticalSwing:
|
||||||
description: Cooling system vertical swing modes. (Tado confusingly names this array without an 's')
|
description: Cooling system vertical swing modes. (Tado confusingly names this array without an 's')
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/definitions/ACVerticalSwing"
|
$ref: "#/definitions/ACVerticalSwing"
|
||||||
|
horizontalSwing:
|
||||||
|
description: Cooling system horizontal swing modes. (Tado confusingly names this array without an 's')
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/definitions/ACHorizontalSwing"
|
||||||
|
|
||||||
HeatingCapabilities:
|
HeatingCapabilities:
|
||||||
x-discriminator-value: HEATING
|
x-discriminator-value: HEATING
|
||||||
|
|||||||
@ -14,6 +14,7 @@ package org.openhab.binding.tado.internal;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.FanLevel;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.FanLevel;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.FanSpeed;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.FanSpeed;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.HorizontalSwing;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.HorizontalSwing;
|
||||||
@ -30,27 +31,30 @@ import org.openhab.binding.tado.internal.builder.ZoneSettingsBuilder;
|
|||||||
import org.openhab.binding.tado.internal.builder.ZoneStateProvider;
|
import org.openhab.binding.tado.internal.builder.ZoneStateProvider;
|
||||||
import org.openhab.binding.tado.internal.handler.TadoZoneHandler;
|
import org.openhab.binding.tado.internal.handler.TadoZoneHandler;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
|
import org.openhab.core.thing.binding.ThingHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder for incremental creation of zone overlays.
|
* Builder for incremental creation of zone overlays.
|
||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class TadoHvacChange {
|
public class TadoHvacChange {
|
||||||
private TadoZoneHandler zoneHandler;
|
|
||||||
|
private final TadoZoneHandler zoneHandler;
|
||||||
|
private final TerminationConditionBuilder terminationConditionBuilder;
|
||||||
|
private final ZoneSettingsBuilder settingsBuilder;
|
||||||
|
|
||||||
private boolean followSchedule = false;
|
private boolean followSchedule = false;
|
||||||
private TerminationConditionBuilder terminationConditionBuilder;
|
|
||||||
private ZoneSettingsBuilder settingsBuilder;
|
|
||||||
|
|
||||||
public TadoHvacChange(Thing zoneThing) {
|
public TadoHvacChange(Thing zoneThing) {
|
||||||
if (!(zoneThing.getHandler() instanceof TadoZoneHandler)) {
|
ThingHandler handler = zoneThing.getHandler();
|
||||||
|
if (!(handler instanceof TadoZoneHandler)) {
|
||||||
throw new IllegalArgumentException("TadoZoneThing expected, but instead got " + zoneThing);
|
throw new IllegalArgumentException("TadoZoneThing expected, but instead got " + zoneThing);
|
||||||
}
|
}
|
||||||
|
zoneHandler = (TadoZoneHandler) handler;
|
||||||
this.zoneHandler = (TadoZoneHandler) zoneThing.getHandler();
|
terminationConditionBuilder = TerminationConditionBuilder.of(zoneHandler);
|
||||||
this.terminationConditionBuilder = TerminationConditionBuilder.of(zoneHandler);
|
settingsBuilder = ZoneSettingsBuilder.of(zoneHandler);
|
||||||
this.settingsBuilder = ZoneSettingsBuilder.of(zoneHandler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TadoHvacChange withOperationMode(OperationMode operationMode) {
|
public TadoHvacChange withOperationMode(OperationMode operationMode) {
|
||||||
@ -60,12 +64,11 @@ public class TadoHvacChange {
|
|||||||
case MANUAL:
|
case MANUAL:
|
||||||
return activeForever();
|
return activeForever();
|
||||||
case TIMER:
|
case TIMER:
|
||||||
return activeFor(null);
|
return activeForMinutes(0);
|
||||||
case UNTIL_CHANGE:
|
case UNTIL_CHANGE:
|
||||||
return activeUntilChange();
|
return activeUntilChange();
|
||||||
default:
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TadoHvacChange followSchedule() {
|
public TadoHvacChange followSchedule() {
|
||||||
@ -83,9 +86,9 @@ public class TadoHvacChange {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TadoHvacChange activeFor(Integer minutes) {
|
public TadoHvacChange activeForMinutes(int minutes) {
|
||||||
terminationConditionBuilder.withTerminationType(OverlayTerminationConditionType.TIMER);
|
terminationConditionBuilder.withTerminationType(OverlayTerminationConditionType.TIMER);
|
||||||
terminationConditionBuilder.withTimerDurationInSeconds(minutes != null ? minutes * 60 : null);
|
terminationConditionBuilder.withTimerDurationInSeconds(minutes * 60);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import java.math.BigDecimal;
|
|||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.HvacMode;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.HvacMode;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.OperationMode;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.OperationMode;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.TemperatureUnit;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.TemperatureUnit;
|
||||||
@ -31,6 +32,7 @@ import org.openhab.binding.tado.internal.api.model.HeatingZoneSetting;
|
|||||||
import org.openhab.binding.tado.internal.api.model.HotWaterZoneSetting;
|
import org.openhab.binding.tado.internal.api.model.HotWaterZoneSetting;
|
||||||
import org.openhab.binding.tado.internal.api.model.Overlay;
|
import org.openhab.binding.tado.internal.api.model.Overlay;
|
||||||
import org.openhab.binding.tado.internal.api.model.OverlayTerminationConditionType;
|
import org.openhab.binding.tado.internal.api.model.OverlayTerminationConditionType;
|
||||||
|
import org.openhab.binding.tado.internal.api.model.PercentageDataPoint;
|
||||||
import org.openhab.binding.tado.internal.api.model.Power;
|
import org.openhab.binding.tado.internal.api.model.Power;
|
||||||
import org.openhab.binding.tado.internal.api.model.SensorDataPoints;
|
import org.openhab.binding.tado.internal.api.model.SensorDataPoints;
|
||||||
import org.openhab.binding.tado.internal.api.model.TadoSystemType;
|
import org.openhab.binding.tado.internal.api.model.TadoSystemType;
|
||||||
@ -55,9 +57,10 @@ import org.openhab.core.types.UnDefType;
|
|||||||
* @author Andrew Fiddian-Green - Added Low Battery Alarm, A/C Power and Open Window channels
|
* @author Andrew Fiddian-Green - Added Low Battery Alarm, A/C Power and Open Window channels
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class TadoZoneStateAdapter {
|
public class TadoZoneStateAdapter {
|
||||||
private ZoneState zoneState;
|
private final ZoneState zoneState;
|
||||||
private TemperatureUnit temperatureUnit;
|
private final TemperatureUnit temperatureUnit;
|
||||||
|
|
||||||
public TadoZoneStateAdapter(ZoneState zoneState, TemperatureUnit temperatureUnit) {
|
public TadoZoneStateAdapter(ZoneState zoneState, TemperatureUnit temperatureUnit) {
|
||||||
this.zoneState = zoneState;
|
this.zoneState = zoneState;
|
||||||
@ -69,10 +72,9 @@ public class TadoZoneStateAdapter {
|
|||||||
return toTemperatureState(sensorDataPoints.getInsideTemperature(), temperatureUnit);
|
return toTemperatureState(sensorDataPoints.getInsideTemperature(), temperatureUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DecimalType getHumidity() {
|
public State getHumidity() {
|
||||||
SensorDataPoints sensorDataPoints = zoneState.getSensorDataPoints();
|
PercentageDataPoint humidity = zoneState.getSensorDataPoints().getHumidity();
|
||||||
return sensorDataPoints.getHumidity() != null ? toDecimalType(sensorDataPoints.getHumidity().getPercentage())
|
return humidity != null ? toDecimalType(humidity.getPercentage()) : UnDefType.UNDEF;
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DecimalType getHeatingPower() {
|
public DecimalType getHeatingPower() {
|
||||||
@ -81,7 +83,7 @@ public class TadoZoneStateAdapter {
|
|||||||
: DecimalType.ZERO;
|
: DecimalType.ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OnOffType getAcPower() {
|
public State getAcPower() {
|
||||||
ActivityDataPoints dataPoints = zoneState.getActivityDataPoints();
|
ActivityDataPoints dataPoints = zoneState.getActivityDataPoints();
|
||||||
AcPowerDataPoint acPower = dataPoints.getAcPower();
|
AcPowerDataPoint acPower = dataPoints.getAcPower();
|
||||||
if (acPower != null) {
|
if (acPower != null) {
|
||||||
@ -90,7 +92,7 @@ public class TadoZoneStateAdapter {
|
|||||||
return OnOffType.from(acPowerValue);
|
return OnOffType.from(acPowerValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return UnDefType.UNDEF;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StringType getMode() {
|
public StringType getMode() {
|
||||||
@ -106,6 +108,9 @@ public class TadoZoneStateAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public State getTargetTemperature() {
|
public State getTargetTemperature() {
|
||||||
|
if (!isPowerOn()) {
|
||||||
|
return UnDefType.UNDEF;
|
||||||
|
}
|
||||||
switch (zoneState.getSetting().getType()) {
|
switch (zoneState.getSetting().getType()) {
|
||||||
case HEATING:
|
case HEATING:
|
||||||
return toTemperatureState(((HeatingZoneSetting) zoneState.getSetting()).getTemperature(),
|
return toTemperatureState(((HeatingZoneSetting) zoneState.getSetting()).getTemperature(),
|
||||||
@ -228,20 +233,12 @@ public class TadoZoneStateAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static State toTemperatureState(TemperatureObject temperature, TemperatureUnit temperatureUnit) {
|
private static State toTemperatureState(TemperatureObject temperature, TemperatureUnit temperatureUnit) {
|
||||||
if (temperature == null) {
|
|
||||||
return UnDefType.NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return temperatureUnit == TemperatureUnit.FAHRENHEIT
|
return temperatureUnit == TemperatureUnit.FAHRENHEIT
|
||||||
? new QuantityType<>(temperature.getFahrenheit(), ImperialUnits.FAHRENHEIT)
|
? new QuantityType<>(temperature.getFahrenheit(), ImperialUnits.FAHRENHEIT)
|
||||||
: new QuantityType<>(temperature.getCelsius(), SIUnits.CELSIUS);
|
: new QuantityType<>(temperature.getCelsius(), SIUnits.CELSIUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static State toTemperatureState(TemperatureDataPoint temperature, TemperatureUnit temperatureUnit) {
|
private static State toTemperatureState(TemperatureDataPoint temperature, TemperatureUnit temperatureUnit) {
|
||||||
if (temperature == null) {
|
|
||||||
return UnDefType.NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return temperatureUnit == TemperatureUnit.FAHRENHEIT
|
return temperatureUnit == TemperatureUnit.FAHRENHEIT
|
||||||
? new QuantityType<>(temperature.getFahrenheit(), ImperialUnits.FAHRENHEIT)
|
? new QuantityType<>(temperature.getFahrenheit(), ImperialUnits.FAHRENHEIT)
|
||||||
: new QuantityType<>(temperature.getCelsius(), SIUnits.CELSIUS);
|
: new QuantityType<>(temperature.getCelsius(), SIUnits.CELSIUS);
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.tado.internal.api;
|
package org.openhab.binding.tado.internal.api;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.tado.internal.api.auth.Authorizer;
|
import org.openhab.binding.tado.internal.api.auth.Authorizer;
|
||||||
import org.openhab.binding.tado.internal.api.auth.OAuthAuthorizer;
|
import org.openhab.binding.tado.internal.api.auth.OAuthAuthorizer;
|
||||||
import org.openhab.binding.tado.internal.api.client.HomeApi;
|
import org.openhab.binding.tado.internal.api.client.HomeApi;
|
||||||
@ -23,6 +24,7 @@ import com.google.gson.Gson;
|
|||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class HomeApiFactory {
|
public class HomeApiFactory {
|
||||||
private static final String OAUTH_SCOPE = "home.user";
|
private static final String OAUTH_SCOPE = "home.user";
|
||||||
private static final String OAUTH_CLIENT_ID = "public-api-preview";
|
private static final String OAUTH_CLIENT_ID = "public-api-preview";
|
||||||
|
|||||||
@ -12,6 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.tado.internal.api;
|
package org.openhab.binding.tado.internal.api;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.FanLevel;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.FanLevel;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.FanSpeed;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.FanSpeed;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.HorizontalSwing;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.HorizontalSwing;
|
||||||
@ -25,6 +27,7 @@ import org.openhab.binding.tado.internal.api.model.AcFanSpeed;
|
|||||||
import org.openhab.binding.tado.internal.api.model.AcMode;
|
import org.openhab.binding.tado.internal.api.model.AcMode;
|
||||||
import org.openhab.binding.tado.internal.api.model.AcModeCapabilities;
|
import org.openhab.binding.tado.internal.api.model.AcModeCapabilities;
|
||||||
import org.openhab.binding.tado.internal.api.model.AirConditioningCapabilities;
|
import org.openhab.binding.tado.internal.api.model.AirConditioningCapabilities;
|
||||||
|
import org.openhab.binding.tado.internal.api.model.GenericZoneCapabilities;
|
||||||
import org.openhab.binding.tado.internal.api.model.ManualTerminationCondition;
|
import org.openhab.binding.tado.internal.api.model.ManualTerminationCondition;
|
||||||
import org.openhab.binding.tado.internal.api.model.OverlayTerminationCondition;
|
import org.openhab.binding.tado.internal.api.model.OverlayTerminationCondition;
|
||||||
import org.openhab.binding.tado.internal.api.model.OverlayTerminationConditionTemplate;
|
import org.openhab.binding.tado.internal.api.model.OverlayTerminationConditionTemplate;
|
||||||
@ -39,9 +42,11 @@ import org.openhab.binding.tado.internal.api.model.TimerTerminationConditionTemp
|
|||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class TadoApiTypeUtils {
|
public class TadoApiTypeUtils {
|
||||||
|
|
||||||
public static OverlayTerminationCondition getTerminationCondition(OverlayTerminationConditionType type,
|
public static OverlayTerminationCondition getTerminationCondition(OverlayTerminationConditionType type,
|
||||||
Integer timerDurationInSeconds) {
|
int timerDurationInSeconds) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TIMER:
|
case TIMER:
|
||||||
return timerTermination(timerDurationInSeconds);
|
return timerTermination(timerDurationInSeconds);
|
||||||
@ -50,26 +55,38 @@ public class TadoApiTypeUtils {
|
|||||||
case TADO_MODE:
|
case TADO_MODE:
|
||||||
return tadoModeTermination();
|
return tadoModeTermination();
|
||||||
default:
|
default:
|
||||||
return null;
|
throw new IllegalArgumentException("Unexpected OverlayTerminationConditionType " + type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OverlayTerminationCondition cleanTerminationCondition(
|
public static OverlayTerminationCondition cleanTerminationCondition(
|
||||||
OverlayTerminationCondition terminationCondition) {
|
OverlayTerminationCondition terminationCondition) {
|
||||||
Integer timerDuration = terminationCondition.getType() == OverlayTerminationConditionType.TIMER
|
OverlayTerminationConditionType conditionType = terminationCondition.getType();
|
||||||
? ((TimerTerminationCondition) terminationCondition).getRemainingTimeInSeconds()
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return getTerminationCondition(terminationCondition.getType(), timerDuration);
|
int timerDuration = 0;
|
||||||
|
if (conditionType == OverlayTerminationConditionType.TIMER) {
|
||||||
|
Integer duration = ((TimerTerminationCondition) terminationCondition).getRemainingTimeInSeconds();
|
||||||
|
if (duration != null) {
|
||||||
|
timerDuration = duration.intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getTerminationCondition(conditionType, timerDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OverlayTerminationCondition terminationConditionTemplateToTerminationCondition(
|
public static OverlayTerminationCondition terminationConditionTemplateToTerminationCondition(
|
||||||
OverlayTerminationConditionTemplate template) {
|
OverlayTerminationConditionTemplate template) {
|
||||||
Integer timerDuration = template.getType() == OverlayTerminationConditionType.TIMER
|
OverlayTerminationConditionType conditionType = template.getType();
|
||||||
? ((TimerTerminationConditionTemplate) template).getDurationInSeconds()
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return getTerminationCondition(template.getType(), timerDuration);
|
int timerDuration = 0;
|
||||||
|
if (conditionType == OverlayTerminationConditionType.TIMER) {
|
||||||
|
Integer duration = ((TimerTerminationConditionTemplate) template).getDurationInSeconds();
|
||||||
|
if (duration != null) {
|
||||||
|
timerDuration = duration.intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getTerminationCondition(conditionType, timerDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TimerTerminationCondition timerTermination(int durationInSeconds) {
|
public static TimerTerminationCondition timerTermination(int durationInSeconds) {
|
||||||
@ -103,18 +120,10 @@ public class TadoApiTypeUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Float getTemperatureInUnit(TemperatureObject temperature, TemperatureUnit temperatureUnit) {
|
public static Float getTemperatureInUnit(TemperatureObject temperature, TemperatureUnit temperatureUnit) {
|
||||||
if (temperature == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return temperatureUnit == TemperatureUnit.FAHRENHEIT ? temperature.getFahrenheit() : temperature.getCelsius();
|
return temperatureUnit == TemperatureUnit.FAHRENHEIT ? temperature.getFahrenheit() : temperature.getCelsius();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AcMode getAcMode(HvacMode mode) {
|
public static AcMode getAcMode(HvacMode mode) {
|
||||||
if (mode == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case HEAT:
|
case HEAT:
|
||||||
return AcMode.HEAT;
|
return AcMode.HEAT;
|
||||||
@ -127,15 +136,11 @@ public class TadoApiTypeUtils {
|
|||||||
case AUTO:
|
case AUTO:
|
||||||
return AcMode.AUTO;
|
return AcMode.AUTO;
|
||||||
default:
|
default:
|
||||||
return null;
|
throw new IllegalArgumentException("Unexpected AcMode " + mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AcFanSpeed getAcFanSpeed(FanSpeed fanSpeed) {
|
public static AcFanSpeed getAcFanSpeed(FanSpeed fanSpeed) {
|
||||||
if (fanSpeed == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (fanSpeed) {
|
switch (fanSpeed) {
|
||||||
case AUTO:
|
case AUTO:
|
||||||
return AcFanSpeed.AUTO;
|
return AcFanSpeed.AUTO;
|
||||||
@ -145,16 +150,12 @@ public class TadoApiTypeUtils {
|
|||||||
return AcFanSpeed.MIDDLE;
|
return AcFanSpeed.MIDDLE;
|
||||||
case LOW:
|
case LOW:
|
||||||
return AcFanSpeed.LOW;
|
return AcFanSpeed.LOW;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unexpected AcFanSpeed " + fanSpeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ACFanLevel getFanLevel(FanLevel fanLevel) {
|
public static ACFanLevel getFanLevel(FanLevel fanLevel) {
|
||||||
if (fanLevel == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (fanLevel) {
|
switch (fanLevel) {
|
||||||
case AUTO:
|
case AUTO:
|
||||||
return ACFanLevel.AUTO;
|
return ACFanLevel.AUTO;
|
||||||
@ -170,16 +171,12 @@ public class TadoApiTypeUtils {
|
|||||||
return ACFanLevel.LEVEL5;
|
return ACFanLevel.LEVEL5;
|
||||||
case SILENT:
|
case SILENT:
|
||||||
return ACFanLevel.SILENT;
|
return ACFanLevel.SILENT;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unexpected FanLevel " + fanLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ACHorizontalSwing getHorizontalSwing(HorizontalSwing horizontalSwing) {
|
public static ACHorizontalSwing getHorizontalSwing(HorizontalSwing horizontalSwing) {
|
||||||
if (horizontalSwing == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (horizontalSwing) {
|
switch (horizontalSwing) {
|
||||||
case LEFT:
|
case LEFT:
|
||||||
return ACHorizontalSwing.LEFT;
|
return ACHorizontalSwing.LEFT;
|
||||||
@ -197,16 +194,12 @@ public class TadoApiTypeUtils {
|
|||||||
return ACHorizontalSwing.OFF;
|
return ACHorizontalSwing.OFF;
|
||||||
case AUTO:
|
case AUTO:
|
||||||
return ACHorizontalSwing.AUTO;
|
return ACHorizontalSwing.AUTO;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unexpected HorizontalSwing " + horizontalSwing);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ACVerticalSwing getVerticalSwing(VerticalSwing verticalSwing) {
|
public static ACVerticalSwing getVerticalSwing(VerticalSwing verticalSwing) {
|
||||||
if (verticalSwing == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (verticalSwing) {
|
switch (verticalSwing) {
|
||||||
case AUTO:
|
case AUTO:
|
||||||
return ACVerticalSwing.AUTO;
|
return ACVerticalSwing.AUTO;
|
||||||
@ -224,34 +217,34 @@ public class TadoApiTypeUtils {
|
|||||||
return ACVerticalSwing.ON;
|
return ACVerticalSwing.ON;
|
||||||
case OFF:
|
case OFF:
|
||||||
return ACVerticalSwing.OFF;
|
return ACVerticalSwing.OFF;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unexpected VerticalSwing " + verticalSwing);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AcModeCapabilities getModeCapabilities(AirConditioningCapabilities capabilities, AcMode mode) {
|
public static AcModeCapabilities getModeCapabilities(AcMode acMode,
|
||||||
AcModeCapabilities modeCapabilities = null;
|
@Nullable GenericZoneCapabilities capabilities) {
|
||||||
|
AirConditioningCapabilities acCapabilities;
|
||||||
|
|
||||||
if (mode != null) {
|
if (capabilities instanceof AirConditioningCapabilities) {
|
||||||
switch (mode) {
|
acCapabilities = (AirConditioningCapabilities) capabilities;
|
||||||
case COOL:
|
} else {
|
||||||
modeCapabilities = capabilities.getCOOL();
|
acCapabilities = new AirConditioningCapabilities();
|
||||||
break;
|
|
||||||
case HEAT:
|
|
||||||
modeCapabilities = capabilities.getHEAT();
|
|
||||||
break;
|
|
||||||
case DRY:
|
|
||||||
modeCapabilities = capabilities.getDRY();
|
|
||||||
break;
|
|
||||||
case AUTO:
|
|
||||||
modeCapabilities = capabilities.getAUTO();
|
|
||||||
break;
|
|
||||||
case FAN:
|
|
||||||
modeCapabilities = capabilities.getFAN();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return modeCapabilities != null ? modeCapabilities : new AcModeCapabilities();
|
switch (acMode) {
|
||||||
|
case COOL:
|
||||||
|
return acCapabilities.getCOOL();
|
||||||
|
case HEAT:
|
||||||
|
return acCapabilities.getHEAT();
|
||||||
|
case DRY:
|
||||||
|
return acCapabilities.getDRY();
|
||||||
|
case AUTO:
|
||||||
|
return acCapabilities.getAUTO();
|
||||||
|
case FAN:
|
||||||
|
return acCapabilities.getFAN();
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unexpected AcMode " + acMode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,16 +17,21 @@ import static org.openhab.binding.tado.internal.api.TadoApiTypeUtils.*;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.binding.tado.internal.TadoBindingConstants.FanLevel;
|
||||||
|
import org.openhab.binding.tado.internal.TadoBindingConstants.FanSpeed;
|
||||||
|
import org.openhab.binding.tado.internal.TadoBindingConstants.HorizontalSwing;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.HvacMode;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.HvacMode;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.TemperatureUnit;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.TemperatureUnit;
|
||||||
|
import org.openhab.binding.tado.internal.TadoBindingConstants.VerticalSwing;
|
||||||
import org.openhab.binding.tado.internal.api.ApiException;
|
import org.openhab.binding.tado.internal.api.ApiException;
|
||||||
|
import org.openhab.binding.tado.internal.api.TadoApiTypeUtils;
|
||||||
import org.openhab.binding.tado.internal.api.model.ACFanLevel;
|
import org.openhab.binding.tado.internal.api.model.ACFanLevel;
|
||||||
import org.openhab.binding.tado.internal.api.model.ACHorizontalSwing;
|
import org.openhab.binding.tado.internal.api.model.ACHorizontalSwing;
|
||||||
import org.openhab.binding.tado.internal.api.model.ACVerticalSwing;
|
import org.openhab.binding.tado.internal.api.model.ACVerticalSwing;
|
||||||
import org.openhab.binding.tado.internal.api.model.AcFanSpeed;
|
import org.openhab.binding.tado.internal.api.model.AcFanSpeed;
|
||||||
import org.openhab.binding.tado.internal.api.model.AcMode;
|
import org.openhab.binding.tado.internal.api.model.AcMode;
|
||||||
import org.openhab.binding.tado.internal.api.model.AcModeCapabilities;
|
import org.openhab.binding.tado.internal.api.model.AcModeCapabilities;
|
||||||
import org.openhab.binding.tado.internal.api.model.AirConditioningCapabilities;
|
|
||||||
import org.openhab.binding.tado.internal.api.model.CoolingZoneSetting;
|
import org.openhab.binding.tado.internal.api.model.CoolingZoneSetting;
|
||||||
import org.openhab.binding.tado.internal.api.model.GenericZoneCapabilities;
|
import org.openhab.binding.tado.internal.api.model.GenericZoneCapabilities;
|
||||||
import org.openhab.binding.tado.internal.api.model.GenericZoneSetting;
|
import org.openhab.binding.tado.internal.api.model.GenericZoneSetting;
|
||||||
@ -35,17 +40,23 @@ import org.openhab.binding.tado.internal.api.model.Power;
|
|||||||
import org.openhab.binding.tado.internal.api.model.TadoSystemType;
|
import org.openhab.binding.tado.internal.api.model.TadoSystemType;
|
||||||
import org.openhab.binding.tado.internal.api.model.TemperatureObject;
|
import org.openhab.binding.tado.internal.api.model.TemperatureObject;
|
||||||
import org.openhab.binding.tado.internal.api.model.TemperatureRange;
|
import org.openhab.binding.tado.internal.api.model.TemperatureRange;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class AirConditioningZoneSettingsBuilder extends ZoneSettingsBuilder {
|
public class AirConditioningZoneSettingsBuilder extends ZoneSettingsBuilder {
|
||||||
private static final AcMode DEFAULT_MODE = AcMode.COOL;
|
private static final AcMode DEFAULT_MODE = AcMode.COOL;
|
||||||
private static final float DEFAULT_TEMPERATURE_C = 20.0f;
|
private static final float DEFAULT_TEMPERATURE_C = 20.0f;
|
||||||
private static final float DEFAULT_TEMPERATURE_F = 68.0f;
|
private static final float DEFAULT_TEMPERATURE_F = 68.0f;
|
||||||
|
|
||||||
|
private static final String STATE_VALUE_NOT_SUPPORTED = "Your a/c unit does not support '{}:{}' when in state '{}:{}', (supported values: [{}]).";
|
||||||
|
private Logger logger = LoggerFactory.getLogger(AirConditioningZoneSettingsBuilder.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GenericZoneSetting build(ZoneStateProvider zoneStateProvider, GenericZoneCapabilities genericCapabilities)
|
public GenericZoneSetting build(ZoneStateProvider zoneStateProvider, GenericZoneCapabilities genericCapabilities)
|
||||||
throws IOException, ApiException {
|
throws IOException, ApiException {
|
||||||
@ -53,95 +64,138 @@ public class AirConditioningZoneSettingsBuilder extends ZoneSettingsBuilder {
|
|||||||
return coolingSetting(false);
|
return coolingSetting(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
CoolingZoneSetting setting = coolingSetting(true);
|
CoolingZoneSetting newSetting = coolingSetting(true);
|
||||||
setting.setMode(getAcMode(mode));
|
|
||||||
|
AcMode targetMode;
|
||||||
|
HvacMode mode = this.mode;
|
||||||
|
if (mode != null) {
|
||||||
|
targetMode = getAcMode(mode);
|
||||||
|
newSetting.setMode(targetMode);
|
||||||
|
} else {
|
||||||
|
// if mode not changing, so the reference is the current (or default) mode
|
||||||
|
targetMode = getCurrentOrDefaultAcMode(zoneStateProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
Float temperature = this.temperature;
|
||||||
if (temperature != null) {
|
if (temperature != null) {
|
||||||
setting.setTemperature(temperature(temperature, temperatureUnit));
|
newSetting.setTemperature(temperature(temperature, temperatureUnit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Boolean swing = this.swing;
|
||||||
if (swing != null) {
|
if (swing != null) {
|
||||||
setting.setSwing(swing ? Power.ON : Power.OFF);
|
newSetting.setSwing(swing.booleanValue() ? Power.ON : Power.OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Boolean light = this.light;
|
||||||
if (light != null) {
|
if (light != null) {
|
||||||
setting.setLight(light ? Power.ON : Power.OFF);
|
newSetting.setLight(light.booleanValue() ? Power.ON : Power.OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FanSpeed fanSpeed = this.fanSpeed;
|
||||||
if (fanSpeed != null) {
|
if (fanSpeed != null) {
|
||||||
setting.setFanSpeed(getAcFanSpeed(fanSpeed));
|
newSetting.setFanSpeed(getAcFanSpeed(fanSpeed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In the latest API release Tado introduced extra AC settings that have an open ended list of possible
|
||||||
|
* supported state values. And for any particular device, its specific list of supported values is available
|
||||||
|
* via its 'capabilities' structure. So before setting a new value, we check if the respective new value is in
|
||||||
|
* the capabilities list that corresponds to the target AC mode. And if not, a warning message is logged.
|
||||||
|
*/
|
||||||
|
AcModeCapabilities targetModeCapabilities = TadoApiTypeUtils.getModeCapabilities(targetMode,
|
||||||
|
genericCapabilities);
|
||||||
|
|
||||||
|
FanLevel fanLevel = this.fanLevel;
|
||||||
if (fanLevel != null) {
|
if (fanLevel != null) {
|
||||||
setting.setFanLevel(getFanLevel(fanLevel));
|
ACFanLevel targetFanLevel = getFanLevel(fanLevel);
|
||||||
|
List<ACFanLevel> targetFanLevels = targetModeCapabilities.getFanLevel();
|
||||||
|
if (targetFanLevels != null && targetFanLevels.contains(targetFanLevel)) {
|
||||||
|
newSetting.setFanLevel(targetFanLevel);
|
||||||
|
} else {
|
||||||
|
logger.warn(STATE_VALUE_NOT_SUPPORTED, targetFanLevel.getClass().getSimpleName(), targetFanLevel,
|
||||||
|
targetMode.getClass().getSimpleName(), targetMode, targetFanLevels);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HorizontalSwing horizontalSwing = this.horizontalSwing;
|
||||||
if (horizontalSwing != null) {
|
if (horizontalSwing != null) {
|
||||||
setting.setHorizontalSwing(getHorizontalSwing(horizontalSwing));
|
ACHorizontalSwing targetHorizontalSwing = getHorizontalSwing(horizontalSwing);
|
||||||
|
List<ACHorizontalSwing> targetHorizontalSwings = targetModeCapabilities.getHorizontalSwing();
|
||||||
|
if (targetHorizontalSwings != null && targetHorizontalSwings.contains(targetHorizontalSwing)) {
|
||||||
|
newSetting.setHorizontalSwing(targetHorizontalSwing);
|
||||||
|
} else {
|
||||||
|
logger.warn(STATE_VALUE_NOT_SUPPORTED, targetHorizontalSwing.getClass().getSimpleName(),
|
||||||
|
targetHorizontalSwing, targetMode.getClass().getSimpleName(), targetMode,
|
||||||
|
targetHorizontalSwings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VerticalSwing verticalSwing = this.verticalSwing;
|
||||||
if (verticalSwing != null) {
|
if (verticalSwing != null) {
|
||||||
setting.setVerticalSwing(getVerticalSwing(verticalSwing));
|
ACVerticalSwing targetVerticalSwing = getVerticalSwing(verticalSwing);
|
||||||
|
List<ACVerticalSwing> targetVerticalSwings = targetModeCapabilities.getVerticalSwing();
|
||||||
|
if (targetVerticalSwings != null && targetVerticalSwings.contains(targetVerticalSwing)) {
|
||||||
|
newSetting.setVerticalSwing(targetVerticalSwing);
|
||||||
|
} else {
|
||||||
|
logger.warn(STATE_VALUE_NOT_SUPPORTED, targetVerticalSwing.getClass().getSimpleName(),
|
||||||
|
targetVerticalSwing, targetMode.getClass().getSimpleName(), targetMode, targetVerticalSwings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addMissingSettingParts(zoneStateProvider, genericCapabilities, setting);
|
addMissingSettingParts(zoneStateProvider, genericCapabilities, newSetting);
|
||||||
|
|
||||||
return setting;
|
return newSetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMissingSettingParts(ZoneStateProvider zoneStateProvider,
|
private void addMissingSettingParts(ZoneStateProvider zoneStateProvider,
|
||||||
GenericZoneCapabilities genericCapabilities, CoolingZoneSetting setting) throws IOException, ApiException {
|
GenericZoneCapabilities genericCapabilities, CoolingZoneSetting newSetting)
|
||||||
if (setting.getMode() == null) {
|
throws IOException, ApiException {
|
||||||
|
if (newSetting.getMode() == null) {
|
||||||
AcMode targetMode = getCurrentOrDefaultAcMode(zoneStateProvider);
|
AcMode targetMode = getCurrentOrDefaultAcMode(zoneStateProvider);
|
||||||
setting.setMode(targetMode);
|
newSetting.setMode(targetMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
AcModeCapabilities capabilities = getModeCapabilities((AirConditioningCapabilities) genericCapabilities,
|
AcModeCapabilities targetCapabilities = getModeCapabilities(newSetting.getMode(), genericCapabilities);
|
||||||
setting.getMode());
|
|
||||||
|
|
||||||
TemperatureRange temperatures = capabilities.getTemperatures();
|
TemperatureRange temperatures = targetCapabilities.getTemperatures();
|
||||||
if (temperatures != null && setting.getTemperature() == null) {
|
if (temperatures != null && newSetting.getTemperature() == null) {
|
||||||
setting.setTemperature(getCurrentOrDefaultTemperature(zoneStateProvider, temperatures));
|
newSetting.setTemperature(getCurrentOrDefaultTemperature(zoneStateProvider, temperatures));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AcFanSpeed> fanSpeeds = capabilities.getFanSpeeds();
|
List<AcFanSpeed> fanSpeeds = targetCapabilities.getFanSpeeds();
|
||||||
if (fanSpeeds != null && !fanSpeeds.isEmpty() && setting.getFanSpeed() == null) {
|
if (fanSpeeds != null && !fanSpeeds.isEmpty() && newSetting.getFanSpeed() == null) {
|
||||||
setting.setFanSpeed(getCurrentOrDefaultFanSpeed(zoneStateProvider, fanSpeeds));
|
newSetting.setFanSpeed(getCurrentOrDefaultFanSpeed(zoneStateProvider, fanSpeeds));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Power> swings = capabilities.getSwings();
|
List<Power> swings = targetCapabilities.getSwings();
|
||||||
if (swings != null && !swings.isEmpty() && setting.getSwing() == null) {
|
if (swings != null && !swings.isEmpty() && newSetting.getSwing() == null) {
|
||||||
setting.setSwing(getCurrentOrDefaultSwing(zoneStateProvider, swings));
|
newSetting.setSwing(getCurrentOrDefaultSwing(zoneStateProvider, swings));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tado confusingly calls the List / getter method 'fanLevel' / 'getFanLevel()' without 's'
|
List<ACFanLevel> fanLevels = targetCapabilities.getFanLevel();
|
||||||
List<ACFanLevel> fanLevels = capabilities.getFanLevel();
|
if (fanLevels != null && !fanLevels.isEmpty() && newSetting.getFanLevel() == null) {
|
||||||
if (fanLevels != null && !fanLevels.isEmpty() && setting.getFanLevel() == null) {
|
newSetting.setFanLevel(getCurrentOrDefaultFanLevel(zoneStateProvider, fanLevels));
|
||||||
setting.setFanLevel(getCurrentOrDefaultFanLevel(zoneStateProvider, fanLevels));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tado confusingly calls the List / getter method 'horizontalSwing' / 'getHorizontalSwing()' without 's'
|
List<ACHorizontalSwing> horizontalSwings = targetCapabilities.getHorizontalSwing();
|
||||||
List<ACHorizontalSwing> horizontalSwings = capabilities.getHorizontalSwing();
|
if (horizontalSwings != null && !horizontalSwings.isEmpty() && newSetting.getHorizontalSwing() == null) {
|
||||||
if (horizontalSwings != null && !horizontalSwings.isEmpty() && setting.getHorizontalSwing() == null) {
|
newSetting.setHorizontalSwing(getCurrentOrDefaultHorizontalSwing(zoneStateProvider, horizontalSwings));
|
||||||
setting.setHorizontalSwing(getCurrentOrDefaultHorizontalSwing(zoneStateProvider, horizontalSwings));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tado confusingly calls the List / getter method 'verticalSwing' / 'getVerticalSwing()' without 's'
|
List<ACVerticalSwing> verticalSwings = targetCapabilities.getVerticalSwing();
|
||||||
List<ACVerticalSwing> verticalSwings = capabilities.getVerticalSwing();
|
if (verticalSwings != null && !verticalSwings.isEmpty() && newSetting.getVerticalSwing() == null) {
|
||||||
if (verticalSwings != null && !verticalSwings.isEmpty() && setting.getVerticalSwing() == null) {
|
newSetting.setVerticalSwing(getCurrentOrDefaultVerticalSwing(zoneStateProvider, verticalSwings));
|
||||||
setting.setVerticalSwing(getCurrentOrDefaultVerticalSwing(zoneStateProvider, verticalSwings));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tado confusingly calls the List / getter method 'light' / 'getLight()' without 's'
|
List<Power> lights = targetCapabilities.getLight();
|
||||||
List<Power> lights = capabilities.getLight();
|
if (lights != null && !lights.isEmpty() && newSetting.getLight() == null) {
|
||||||
if (lights != null && !lights.isEmpty() && setting.getLight() == null) {
|
newSetting.setLight(getCurrentOrDefaultLight(zoneStateProvider, lights));
|
||||||
setting.setLight(getCurrentOrDefaultLight(zoneStateProvider, lights));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AcMode getCurrentOrDefaultAcMode(ZoneStateProvider zoneStateProvider) throws IOException, ApiException {
|
private AcMode getCurrentOrDefaultAcMode(ZoneStateProvider zoneStateProvider) throws IOException, ApiException {
|
||||||
CoolingZoneSetting zoneSetting = (CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting();
|
AcMode acMode = ((CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting()).getMode();
|
||||||
|
return acMode != null ? acMode : DEFAULT_MODE;
|
||||||
return zoneSetting.getMode() != null ? zoneSetting.getMode() : DEFAULT_MODE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TemperatureObject getCurrentOrDefaultTemperature(ZoneStateProvider zoneStateProvider,
|
private TemperatureObject getCurrentOrDefaultTemperature(ZoneStateProvider zoneStateProvider,
|
||||||
@ -165,68 +219,40 @@ public class AirConditioningZoneSettingsBuilder extends ZoneSettingsBuilder {
|
|||||||
|
|
||||||
private AcFanSpeed getCurrentOrDefaultFanSpeed(ZoneStateProvider zoneStateProvider, List<AcFanSpeed> fanSpeeds)
|
private AcFanSpeed getCurrentOrDefaultFanSpeed(ZoneStateProvider zoneStateProvider, List<AcFanSpeed> fanSpeeds)
|
||||||
throws IOException, ApiException {
|
throws IOException, ApiException {
|
||||||
CoolingZoneSetting zoneSetting = (CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting();
|
AcFanSpeed fanSpeed = ((CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting()).getFanSpeed();
|
||||||
|
return (fanSpeed != null) && fanSpeeds.contains(fanSpeed) ? fanSpeed : fanSpeeds.get(0);
|
||||||
if (zoneSetting.getFanSpeed() != null && fanSpeeds.contains(zoneSetting.getFanSpeed())) {
|
|
||||||
return zoneSetting.getFanSpeed();
|
|
||||||
}
|
|
||||||
|
|
||||||
return fanSpeeds.get(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Power getCurrentOrDefaultSwing(ZoneStateProvider zoneStateProvider, List<Power> swings)
|
private Power getCurrentOrDefaultSwing(ZoneStateProvider zoneStateProvider, List<Power> swings)
|
||||||
throws IOException, ApiException {
|
throws IOException, ApiException {
|
||||||
CoolingZoneSetting zoneSetting = (CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting();
|
Power swing = ((CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting()).getSwing();
|
||||||
|
return (swing != null) && swings.contains(swing) ? swing : swings.get(0);
|
||||||
if (zoneSetting.getSwing() != null && swings.contains(zoneSetting.getSwing())) {
|
|
||||||
return zoneSetting.getSwing();
|
|
||||||
}
|
|
||||||
|
|
||||||
return swings.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Power getCurrentOrDefaultLight(ZoneStateProvider zoneStateProvider, List<Power> lights)
|
|
||||||
throws IOException, ApiException {
|
|
||||||
CoolingZoneSetting zoneSetting = (CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting();
|
|
||||||
|
|
||||||
if (zoneSetting.getLight() != null && lights.contains(zoneSetting.getLight())) {
|
|
||||||
return zoneSetting.getLight();
|
|
||||||
}
|
|
||||||
|
|
||||||
return lights.get(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ACFanLevel getCurrentOrDefaultFanLevel(ZoneStateProvider zoneStateProvider, List<ACFanLevel> fanLevels)
|
private ACFanLevel getCurrentOrDefaultFanLevel(ZoneStateProvider zoneStateProvider, List<ACFanLevel> fanLevels)
|
||||||
throws IOException, ApiException {
|
throws IOException, ApiException {
|
||||||
CoolingZoneSetting zoneSetting = (CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting();
|
ACFanLevel fanLevel = ((CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting()).getFanLevel();
|
||||||
|
return (fanLevel != null) && fanLevels.contains(fanLevel) ? fanLevel : fanLevels.get(0);
|
||||||
if (zoneSetting.getFanLevel() != null && fanLevels.contains(zoneSetting.getFanLevel())) {
|
|
||||||
return zoneSetting.getFanLevel();
|
|
||||||
}
|
|
||||||
|
|
||||||
return fanLevels.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ACHorizontalSwing getCurrentOrDefaultHorizontalSwing(ZoneStateProvider zoneStateProvider,
|
|
||||||
List<ACHorizontalSwing> horizontalSwings) throws IOException, ApiException {
|
|
||||||
CoolingZoneSetting zoneSetting = (CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting();
|
|
||||||
|
|
||||||
if (zoneSetting.getHorizontalSwing() != null && horizontalSwings.contains(zoneSetting.getHorizontalSwing())) {
|
|
||||||
return zoneSetting.getHorizontalSwing();
|
|
||||||
}
|
|
||||||
|
|
||||||
return horizontalSwings.get(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ACVerticalSwing getCurrentOrDefaultVerticalSwing(ZoneStateProvider zoneStateProvider,
|
private ACVerticalSwing getCurrentOrDefaultVerticalSwing(ZoneStateProvider zoneStateProvider,
|
||||||
List<ACVerticalSwing> verticalSwings) throws IOException, ApiException {
|
List<ACVerticalSwing> vertSwings) throws IOException, ApiException {
|
||||||
CoolingZoneSetting zoneSetting = (CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting();
|
ACVerticalSwing vertSwing = ((CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting())
|
||||||
|
.getVerticalSwing();
|
||||||
|
return (vertSwing != null) && vertSwings.contains(vertSwing) ? vertSwing : vertSwings.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (zoneSetting.getVerticalSwing() != null && verticalSwings.contains(zoneSetting.getVerticalSwing())) {
|
private ACHorizontalSwing getCurrentOrDefaultHorizontalSwing(ZoneStateProvider zoneStateProvider,
|
||||||
return zoneSetting.getVerticalSwing();
|
List<ACHorizontalSwing> horzSwings) throws IOException, ApiException {
|
||||||
}
|
ACHorizontalSwing horzSwing = ((CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting())
|
||||||
|
.getHorizontalSwing();
|
||||||
|
return (horzSwing != null) && horzSwings.contains(horzSwing) ? horzSwing : horzSwings.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
return verticalSwings.get(0);
|
private Power getCurrentOrDefaultLight(ZoneStateProvider zoneStateProvider, List<Power> lights)
|
||||||
|
throws IOException, ApiException {
|
||||||
|
Power light = ((CoolingZoneSetting) zoneStateProvider.getZoneState().getSetting()).getLight();
|
||||||
|
return (light != null) && lights.contains(light) ? light : lights.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CoolingZoneSetting coolingSetting(boolean powerOn) {
|
private CoolingZoneSetting coolingSetting(boolean powerOn) {
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import static org.openhab.binding.tado.internal.api.TadoApiTypeUtils.temperature
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.FanLevel;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.FanLevel;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.FanSpeed;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.FanSpeed;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.HorizontalSwing;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.HorizontalSwing;
|
||||||
@ -34,6 +35,7 @@ import org.openhab.binding.tado.internal.api.model.TemperatureObject;
|
|||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class HeatingZoneSettingsBuilder extends ZoneSettingsBuilder {
|
public class HeatingZoneSettingsBuilder extends ZoneSettingsBuilder {
|
||||||
private static final float DEFAULT_TEMPERATURE_C = 22.0f;
|
private static final float DEFAULT_TEMPERATURE_C = 22.0f;
|
||||||
private static final float DEFAULT_TEMPERATURE_F = 72.0f;
|
private static final float DEFAULT_TEMPERATURE_F = 72.0f;
|
||||||
@ -77,6 +79,7 @@ public class HeatingZoneSettingsBuilder extends ZoneSettingsBuilder {
|
|||||||
|
|
||||||
HeatingZoneSetting setting = heatingSetting(true);
|
HeatingZoneSetting setting = heatingSetting(true);
|
||||||
|
|
||||||
|
Float temperature = this.temperature;
|
||||||
if (temperature != null) {
|
if (temperature != null) {
|
||||||
setting.setTemperature(temperature(temperature, temperatureUnit));
|
setting.setTemperature(temperature(temperature, temperatureUnit));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import static org.openhab.binding.tado.internal.api.TadoApiTypeUtils.temperature
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.FanLevel;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.FanLevel;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.FanSpeed;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.FanSpeed;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.HorizontalSwing;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.HorizontalSwing;
|
||||||
@ -35,6 +36,7 @@ import org.openhab.binding.tado.internal.api.model.TemperatureObject;
|
|||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class HotWaterZoneSettingsBuilder extends ZoneSettingsBuilder {
|
public class HotWaterZoneSettingsBuilder extends ZoneSettingsBuilder {
|
||||||
private static final float DEFAULT_TEMPERATURE_C = 50.0f;
|
private static final float DEFAULT_TEMPERATURE_C = 50.0f;
|
||||||
private static final float DEFAULT_TEMPERATURE_F = 122.0f;
|
private static final float DEFAULT_TEMPERATURE_F = 122.0f;
|
||||||
@ -78,6 +80,7 @@ public class HotWaterZoneSettingsBuilder extends ZoneSettingsBuilder {
|
|||||||
|
|
||||||
HotWaterZoneSetting setting = hotWaterSetting(true);
|
HotWaterZoneSetting setting = hotWaterSetting(true);
|
||||||
|
|
||||||
|
Float temperature = this.temperature;
|
||||||
if (temperature != null) {
|
if (temperature != null) {
|
||||||
setting.setTemperature(temperature(temperature, temperatureUnit));
|
setting.setTemperature(temperature(temperature, temperatureUnit));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,8 @@ import static org.openhab.binding.tado.internal.api.TadoApiTypeUtils.*;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.tado.internal.api.ApiException;
|
import org.openhab.binding.tado.internal.api.ApiException;
|
||||||
import org.openhab.binding.tado.internal.api.model.OverlayTerminationCondition;
|
import org.openhab.binding.tado.internal.api.model.OverlayTerminationCondition;
|
||||||
import org.openhab.binding.tado.internal.api.model.OverlayTerminationConditionType;
|
import org.openhab.binding.tado.internal.api.model.OverlayTerminationConditionType;
|
||||||
@ -28,11 +30,13 @@ import org.openhab.binding.tado.internal.handler.TadoZoneHandler;
|
|||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class TerminationConditionBuilder {
|
public class TerminationConditionBuilder {
|
||||||
private TadoZoneHandler zoneHandler;
|
|
||||||
|
|
||||||
private OverlayTerminationConditionType terminationType = null;
|
private final TadoZoneHandler zoneHandler;
|
||||||
private Integer timerDurationInSeconds = null;
|
|
||||||
|
private @Nullable OverlayTerminationConditionType terminationType;
|
||||||
|
private int timerDurationInSeconds = 0;
|
||||||
|
|
||||||
protected TerminationConditionBuilder(TadoZoneHandler zoneHandler) {
|
protected TerminationConditionBuilder(TadoZoneHandler zoneHandler) {
|
||||||
this.zoneHandler = zoneHandler;
|
this.zoneHandler = zoneHandler;
|
||||||
@ -45,23 +49,23 @@ public class TerminationConditionBuilder {
|
|||||||
public TerminationConditionBuilder withTerminationType(OverlayTerminationConditionType terminationType) {
|
public TerminationConditionBuilder withTerminationType(OverlayTerminationConditionType terminationType) {
|
||||||
this.terminationType = terminationType;
|
this.terminationType = terminationType;
|
||||||
if (terminationType != OverlayTerminationConditionType.TIMER) {
|
if (terminationType != OverlayTerminationConditionType.TIMER) {
|
||||||
timerDurationInSeconds = null;
|
timerDurationInSeconds = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TerminationConditionBuilder withTimerDurationInSeconds(Integer timerDurationInSeconds) {
|
public TerminationConditionBuilder withTimerDurationInSeconds(int timerDurationInSeconds) {
|
||||||
this.terminationType = OverlayTerminationConditionType.TIMER;
|
this.terminationType = OverlayTerminationConditionType.TIMER;
|
||||||
this.timerDurationInSeconds = timerDurationInSeconds;
|
this.timerDurationInSeconds = timerDurationInSeconds;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OverlayTerminationCondition build(ZoneStateProvider zoneStateProvider) throws IOException, ApiException {
|
public OverlayTerminationCondition build(ZoneStateProvider zoneStateProvider) throws IOException, ApiException {
|
||||||
OverlayTerminationCondition terminationCondition = null;
|
OverlayTerminationCondition terminationCondition;
|
||||||
|
|
||||||
|
OverlayTerminationConditionType terminationType = this.terminationType;
|
||||||
if (terminationType != null) {
|
if (terminationType != null) {
|
||||||
if (terminationType != OverlayTerminationConditionType.TIMER || timerDurationInSeconds != null) {
|
if (terminationType != OverlayTerminationConditionType.TIMER || timerDurationInSeconds > 0) {
|
||||||
terminationCondition = getTerminationCondition(terminationType, timerDurationInSeconds);
|
terminationCondition = getTerminationCondition(terminationType, timerDurationInSeconds);
|
||||||
} else {
|
} else {
|
||||||
terminationCondition = getCurrentOrDefaultTimerTermination(zoneStateProvider);
|
terminationCondition = getCurrentOrDefaultTimerTermination(zoneStateProvider);
|
||||||
@ -75,18 +79,19 @@ public class TerminationConditionBuilder {
|
|||||||
terminationCondition = getDefaultTerminationCondition();
|
terminationCondition = getDefaultTerminationCondition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return terminationCondition;
|
return terminationCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OverlayTerminationCondition getDefaultTerminationCondition() throws IOException, ApiException {
|
private OverlayTerminationCondition getDefaultTerminationCondition() throws IOException, ApiException {
|
||||||
OverlayTerminationCondition defaultTerminationCondition = zoneHandler.getDefaultTerminationCondition();
|
OverlayTerminationCondition defaultTerminationCondition = zoneHandler.getDefaultTerminationCondition();
|
||||||
return defaultTerminationCondition != null ? defaultTerminationCondition : manualTermination();
|
return defaultTerminationCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimerTerminationCondition getCurrentOrDefaultTimerTermination(ZoneStateProvider zoneStateProvider)
|
private TimerTerminationCondition getCurrentOrDefaultTimerTermination(ZoneStateProvider zoneStateProvider)
|
||||||
throws IOException, ApiException {
|
throws IOException, ApiException {
|
||||||
// Timer without duration
|
// Timer without duration
|
||||||
int duration = zoneHandler.getFallbackTimerDuration() * 60;
|
Integer duration = zoneHandler.getFallbackTimerDuration() * 60;
|
||||||
|
|
||||||
ZoneState zoneState = zoneStateProvider.getZoneState();
|
ZoneState zoneState = zoneStateProvider.getZoneState();
|
||||||
|
|
||||||
|
|||||||
@ -14,13 +14,15 @@ package org.openhab.binding.tado.internal.builder;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.FanLevel;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.FanLevel;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.FanSpeed;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.FanSpeed;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.HorizontalSwing;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.HorizontalSwing;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.HvacMode;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.HvacMode;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.TemperatureUnit;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.TemperatureUnit;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.VerticalSwing;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.VerticalSwing;
|
||||||
|
import org.openhab.binding.tado.internal.TadoBindingConstants.ZoneType;
|
||||||
import org.openhab.binding.tado.internal.api.ApiException;
|
import org.openhab.binding.tado.internal.api.ApiException;
|
||||||
import org.openhab.binding.tado.internal.api.model.GenericZoneCapabilities;
|
import org.openhab.binding.tado.internal.api.model.GenericZoneCapabilities;
|
||||||
import org.openhab.binding.tado.internal.api.model.GenericZoneSetting;
|
import org.openhab.binding.tado.internal.api.model.GenericZoneSetting;
|
||||||
@ -32,12 +34,12 @@ import org.openhab.binding.tado.internal.handler.TadoZoneHandler;
|
|||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public abstract class ZoneSettingsBuilder {
|
public abstract class ZoneSettingsBuilder {
|
||||||
|
|
||||||
public static ZoneSettingsBuilder of(TadoZoneHandler zoneHandler) {
|
public static ZoneSettingsBuilder of(TadoZoneHandler zoneHandler) {
|
||||||
TadoBindingConstants.ZoneType zoneType = zoneHandler.getZoneType();
|
ZoneType zoneType = zoneHandler.getZoneType();
|
||||||
if (zoneType == null) {
|
|
||||||
throw new IllegalArgumentException("Zone type is null");
|
|
||||||
}
|
|
||||||
switch (zoneType) {
|
switch (zoneType) {
|
||||||
case HEATING:
|
case HEATING:
|
||||||
return new HeatingZoneSettingsBuilder();
|
return new HeatingZoneSettingsBuilder();
|
||||||
@ -46,19 +48,19 @@ public abstract class ZoneSettingsBuilder {
|
|||||||
case HOT_WATER:
|
case HOT_WATER:
|
||||||
return new HotWaterZoneSettingsBuilder();
|
return new HotWaterZoneSettingsBuilder();
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Zone type " + zoneHandler.getZoneType() + " unknown");
|
throw new IllegalArgumentException("Zone type " + zoneType + " unknown");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HvacMode mode = null;
|
|
||||||
protected Float temperature = null;
|
|
||||||
protected TemperatureUnit temperatureUnit = TemperatureUnit.CELSIUS;
|
protected TemperatureUnit temperatureUnit = TemperatureUnit.CELSIUS;
|
||||||
protected Boolean swing = null;
|
protected @Nullable Float temperature;
|
||||||
protected Boolean light = null;
|
protected @Nullable HvacMode mode;
|
||||||
protected FanSpeed fanSpeed = null;
|
protected @Nullable Boolean swing;
|
||||||
protected FanLevel fanLevel = null;
|
protected @Nullable Boolean light;
|
||||||
protected HorizontalSwing horizontalSwing = null;
|
protected @Nullable FanSpeed fanSpeed;
|
||||||
protected VerticalSwing verticalSwing = null;
|
protected @Nullable FanLevel fanLevel;
|
||||||
|
protected @Nullable HorizontalSwing horizontalSwing;
|
||||||
|
protected @Nullable VerticalSwing verticalSwing;
|
||||||
|
|
||||||
public ZoneSettingsBuilder withMode(HvacMode mode) {
|
public ZoneSettingsBuilder withMode(HvacMode mode) {
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
@ -100,10 +102,6 @@ public abstract class ZoneSettingsBuilder {
|
|||||||
throws IOException, ApiException;
|
throws IOException, ApiException;
|
||||||
|
|
||||||
protected TemperatureObject truncateTemperature(TemperatureObject temperature) {
|
protected TemperatureObject truncateTemperature(TemperatureObject temperature) {
|
||||||
if (temperature == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
TemperatureObject temperatureObject = new TemperatureObject();
|
TemperatureObject temperatureObject = new TemperatureObject();
|
||||||
if (temperatureUnit == TemperatureUnit.FAHRENHEIT) {
|
if (temperatureUnit == TemperatureUnit.FAHRENHEIT) {
|
||||||
temperatureObject.setFahrenheit(temperature.getFahrenheit());
|
temperatureObject.setFahrenheit(temperature.getFahrenheit());
|
||||||
|
|||||||
@ -14,6 +14,8 @@ package org.openhab.binding.tado.internal.builder;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.tado.internal.api.ApiException;
|
import org.openhab.binding.tado.internal.api.ApiException;
|
||||||
import org.openhab.binding.tado.internal.api.model.ZoneState;
|
import org.openhab.binding.tado.internal.api.model.ZoneState;
|
||||||
import org.openhab.binding.tado.internal.handler.TadoZoneHandler;
|
import org.openhab.binding.tado.internal.handler.TadoZoneHandler;
|
||||||
@ -23,21 +25,20 @@ import org.openhab.binding.tado.internal.handler.TadoZoneHandler;
|
|||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class ZoneStateProvider {
|
public class ZoneStateProvider {
|
||||||
private TadoZoneHandler zoneHandler;
|
private final TadoZoneHandler zoneHandler;
|
||||||
private ZoneState zoneState;
|
private @Nullable ZoneState zoneState;
|
||||||
|
|
||||||
public ZoneStateProvider(TadoZoneHandler zoneHandler) {
|
public ZoneStateProvider(TadoZoneHandler zoneHandler) {
|
||||||
this.zoneHandler = zoneHandler;
|
this.zoneHandler = zoneHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneState getZoneState() throws IOException, ApiException {
|
public synchronized ZoneState getZoneState() throws IOException, ApiException {
|
||||||
if (this.zoneState == null) {
|
ZoneState zoneState = this.zoneState;
|
||||||
ZoneState retrievedZoneState = zoneHandler.getZoneState();
|
if (zoneState == null) {
|
||||||
// empty zone state behaves like a NULL object
|
zoneState = this.zoneState = zoneHandler.getZoneState();
|
||||||
this.zoneState = retrievedZoneState != null ? retrievedZoneState : new ZoneState();
|
|
||||||
}
|
}
|
||||||
|
return zoneState;
|
||||||
return this.zoneState;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,12 +12,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.tado.internal.config;
|
package org.openhab.binding.tado.internal.config;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holder-object for home configuration
|
* Holder-object for home configuration
|
||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class TadoHomeConfig {
|
public class TadoHomeConfig {
|
||||||
public String username;
|
public String username = "";
|
||||||
public String password;
|
public String password = "";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,11 +12,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.tado.internal.config;
|
package org.openhab.binding.tado.internal.config;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holder-object for mobile device configuration
|
* Holder-object for mobile device configuration
|
||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class TadoMobileDeviceConfig {
|
public class TadoMobileDeviceConfig {
|
||||||
public int id;
|
public int id;
|
||||||
public int refreshInterval;
|
public int refreshInterval;
|
||||||
|
|||||||
@ -12,11 +12,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.tado.internal.config;
|
package org.openhab.binding.tado.internal.config;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holder-object for zone configuration
|
* Holder-object for zone configuration
|
||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class TadoZoneConfig {
|
public class TadoZoneConfig {
|
||||||
public long id;
|
public long id;
|
||||||
public int refreshInterval;
|
public int refreshInterval;
|
||||||
|
|||||||
@ -25,6 +25,8 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants;
|
import org.openhab.binding.tado.internal.TadoBindingConstants;
|
||||||
import org.openhab.binding.tado.internal.api.ApiException;
|
import org.openhab.binding.tado.internal.api.ApiException;
|
||||||
import org.openhab.binding.tado.internal.api.model.MobileDevice;
|
import org.openhab.binding.tado.internal.api.model.MobileDevice;
|
||||||
@ -43,13 +45,14 @@ import org.slf4j.LoggerFactory;
|
|||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class TadoDiscoveryService extends AbstractDiscoveryService {
|
public class TadoDiscoveryService extends AbstractDiscoveryService {
|
||||||
private static final int TIMEOUT = 5;
|
private static final int TIMEOUT = 5;
|
||||||
private static final long REFRESH = 600;
|
private static final long REFRESH = 600;
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(TadoDiscoveryService.class);
|
private final Logger logger = LoggerFactory.getLogger(TadoDiscoveryService.class);
|
||||||
|
|
||||||
private ScheduledFuture<?> discoveryFuture;
|
private @Nullable ScheduledFuture<?> discoveryFuture;
|
||||||
|
|
||||||
public static final Set<ThingTypeUID> DISCOVERABLE_THING_TYPES_UIDS = Collections
|
public static final Set<ThingTypeUID> DISCOVERABLE_THING_TYPES_UIDS = Collections
|
||||||
.unmodifiableSet(Stream.of(THING_TYPE_ZONE, THING_TYPE_MOBILE_DEVICE).collect(Collectors.toSet()));
|
.unmodifiableSet(Stream.of(THING_TYPE_ZONE, THING_TYPE_MOBILE_DEVICE).collect(Collectors.toSet()));
|
||||||
@ -83,23 +86,30 @@ public class TadoDiscoveryService extends AbstractDiscoveryService {
|
|||||||
@Override
|
@Override
|
||||||
protected void startBackgroundDiscovery() {
|
protected void startBackgroundDiscovery() {
|
||||||
logger.debug("Start Tado background discovery");
|
logger.debug("Start Tado background discovery");
|
||||||
|
ScheduledFuture<?> discoveryFuture = this.discoveryFuture;
|
||||||
if (discoveryFuture == null || discoveryFuture.isCancelled()) {
|
if (discoveryFuture == null || discoveryFuture.isCancelled()) {
|
||||||
logger.debug("Start Scan");
|
logger.debug("Start Scan");
|
||||||
discoveryFuture = scheduler.scheduleWithFixedDelay(this::startScan, 30, REFRESH, TimeUnit.SECONDS);
|
this.discoveryFuture = scheduler.scheduleWithFixedDelay(this::startScan, 30, REFRESH, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void stopBackgroundDiscovery() {
|
protected void stopBackgroundDiscovery() {
|
||||||
logger.debug("Stop Tado background discovery");
|
logger.debug("Stop Tado background discovery");
|
||||||
|
ScheduledFuture<?> discoveryFuture = this.discoveryFuture;
|
||||||
if (discoveryFuture != null && !discoveryFuture.isCancelled()) {
|
if (discoveryFuture != null && !discoveryFuture.isCancelled()) {
|
||||||
discoveryFuture.cancel(true);
|
discoveryFuture.cancel(true);
|
||||||
discoveryFuture = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void discoverZones() {
|
private void discoverZones() {
|
||||||
Long homeId = homeHandler.getHomeId();
|
Long homeId = homeHandler.getHomeId();
|
||||||
|
|
||||||
|
if (homeId == null) {
|
||||||
|
logger.debug("Could not discover tado zones: Missing home id");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<Zone> zoneList = homeHandler.getApi().listZones(homeId);
|
List<Zone> zoneList = homeHandler.getApi().listZones(homeId);
|
||||||
|
|
||||||
@ -132,6 +142,12 @@ public class TadoDiscoveryService extends AbstractDiscoveryService {
|
|||||||
|
|
||||||
private void discoverMobileDevices() {
|
private void discoverMobileDevices() {
|
||||||
Long homeId = homeHandler.getHomeId();
|
Long homeId = homeHandler.getHomeId();
|
||||||
|
|
||||||
|
if (homeId == null) {
|
||||||
|
logger.debug("Could not discover mobile devices: Missing home id");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<MobileDevice> mobileDeviceList = homeHandler.getApi().listMobileDevices(homeId);
|
List<MobileDevice> mobileDeviceList = homeHandler.getApi().listMobileDevices(homeId);
|
||||||
|
|
||||||
@ -143,7 +159,7 @@ public class TadoDiscoveryService extends AbstractDiscoveryService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException | ApiException e) {
|
} catch (IOException | ApiException e) {
|
||||||
logger.debug("Could not discover tado zones: {}", e.getMessage(), e);
|
logger.debug("Could not discover mobile devices: {}", e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,36 +12,47 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.tado.internal.handler;
|
package org.openhab.binding.tado.internal.handler;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.tado.internal.api.client.HomeApi;
|
import org.openhab.binding.tado.internal.api.client.HomeApi;
|
||||||
import org.openhab.core.thing.Bridge;
|
import org.openhab.core.thing.Bridge;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingStatus;
|
import org.openhab.core.thing.ThingStatus;
|
||||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||||
|
import org.openhab.core.thing.binding.BridgeHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common base class for home-based thing-handler.
|
* Common base class for home-based thing-handler.
|
||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public abstract class BaseHomeThingHandler extends BaseThingHandler {
|
public abstract class BaseHomeThingHandler extends BaseThingHandler {
|
||||||
|
|
||||||
public BaseHomeThingHandler(Thing thing) {
|
public BaseHomeThingHandler(Thing thing) {
|
||||||
super(thing);
|
super(thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getHomeId() {
|
public @Nullable Long getHomeId() {
|
||||||
TadoHomeHandler handler = getHomeHandler();
|
TadoHomeHandler handler = getHomeHandler();
|
||||||
return handler != null ? handler.getHomeId() : Long.valueOf(0);
|
return handler.getHomeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TadoHomeHandler getHomeHandler() {
|
protected TadoHomeHandler getHomeHandler() {
|
||||||
Bridge bridge = getBridge();
|
Bridge bridge = getBridge();
|
||||||
return bridge != null ? (TadoHomeHandler) bridge.getHandler() : null;
|
if (bridge == null) {
|
||||||
|
throw new IllegalStateException("Bridge not initialized");
|
||||||
|
}
|
||||||
|
BridgeHandler handler = bridge.getHandler();
|
||||||
|
if (!(handler instanceof TadoHomeHandler)) {
|
||||||
|
throw new IllegalStateException("Handler not initialized");
|
||||||
|
}
|
||||||
|
return (TadoHomeHandler) handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HomeApi getApi() {
|
protected HomeApi getApi() {
|
||||||
TadoHomeHandler handler = getHomeHandler();
|
TadoHomeHandler handler = getHomeHandler();
|
||||||
return handler != null ? handler.getApi() : null;
|
return handler.getApi();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onSuccessfulOperation() {
|
protected void onSuccessfulOperation() {
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.tado.internal.api.ApiException;
|
import org.openhab.binding.tado.internal.api.ApiException;
|
||||||
import org.openhab.binding.tado.internal.api.model.ControlDevice;
|
import org.openhab.binding.tado.internal.api.model.ControlDevice;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
@ -32,14 +33,16 @@ import org.slf4j.LoggerFactory;
|
|||||||
* devices.
|
* devices.
|
||||||
*
|
*
|
||||||
* @author Andrew Fiddian-Green - Initial contribution
|
* @author Andrew Fiddian-Green - Initial contribution
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class TadoBatteryChecker {
|
public class TadoBatteryChecker {
|
||||||
private final Logger logger = LoggerFactory.getLogger(TadoBatteryChecker.class);
|
private final Logger logger = LoggerFactory.getLogger(TadoBatteryChecker.class);
|
||||||
|
|
||||||
private Map<Long, State> zoneList = new HashMap<>();
|
private final Map<Long, State> zoneList = new HashMap<>();
|
||||||
|
private final TadoHomeHandler homeHandler;
|
||||||
|
|
||||||
private Date refreshTime = new Date();
|
private Date refreshTime = new Date();
|
||||||
private TadoHomeHandler homeHandler;
|
|
||||||
|
|
||||||
public TadoBatteryChecker(TadoHomeHandler homeHandler) {
|
public TadoBatteryChecker(TadoHomeHandler homeHandler) {
|
||||||
this.homeHandler = homeHandler;
|
this.homeHandler = homeHandler;
|
||||||
@ -47,7 +50,7 @@ public class TadoBatteryChecker {
|
|||||||
|
|
||||||
private synchronized void refreshZoneList() {
|
private synchronized void refreshZoneList() {
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
if (homeHandler != null && (now.after(refreshTime) || zoneList.isEmpty())) {
|
if (now.after(refreshTime) || zoneList.isEmpty()) {
|
||||||
// be frugal, we only need to refresh the battery state hourly
|
// be frugal, we only need to refresh the battery state hourly
|
||||||
Calendar calendar = Calendar.getInstance();
|
Calendar calendar = Calendar.getInstance();
|
||||||
calendar.setTime(now);
|
calendar.setTime(now);
|
||||||
|
|||||||
@ -22,6 +22,8 @@ import java.util.Hashtable;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.tado.internal.discovery.TadoDiscoveryService;
|
import org.openhab.binding.tado.internal.discovery.TadoDiscoveryService;
|
||||||
import org.openhab.core.config.discovery.DiscoveryService;
|
import org.openhab.core.config.discovery.DiscoveryService;
|
||||||
import org.openhab.core.thing.Bridge;
|
import org.openhab.core.thing.Bridge;
|
||||||
@ -42,6 +44,7 @@ import org.osgi.service.component.annotations.Reference;
|
|||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
@Component(configurationPid = "binding.tado", service = ThingHandlerFactory.class)
|
@Component(configurationPid = "binding.tado", service = ThingHandlerFactory.class)
|
||||||
public class TadoHandlerFactory extends BaseThingHandlerFactory {
|
public class TadoHandlerFactory extends BaseThingHandlerFactory {
|
||||||
|
|
||||||
@ -63,7 +66,7 @@ public class TadoHandlerFactory extends BaseThingHandlerFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ThingHandler createHandler(Thing thing) {
|
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||||
|
|
||||||
if (thingTypeUID.equals(THING_TYPE_HOME)) {
|
if (thingTypeUID.equals(THING_TYPE_HOME)) {
|
||||||
|
|||||||
@ -13,9 +13,12 @@
|
|||||||
package org.openhab.binding.tado.internal.handler;
|
package org.openhab.binding.tado.internal.handler;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants;
|
import org.openhab.binding.tado.internal.TadoBindingConstants;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.TemperatureUnit;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.TemperatureUnit;
|
||||||
import org.openhab.binding.tado.internal.api.ApiException;
|
import org.openhab.binding.tado.internal.api.ApiException;
|
||||||
@ -26,6 +29,7 @@ import org.openhab.binding.tado.internal.api.model.HomePresence;
|
|||||||
import org.openhab.binding.tado.internal.api.model.HomeState;
|
import org.openhab.binding.tado.internal.api.model.HomeState;
|
||||||
import org.openhab.binding.tado.internal.api.model.PresenceState;
|
import org.openhab.binding.tado.internal.api.model.PresenceState;
|
||||||
import org.openhab.binding.tado.internal.api.model.User;
|
import org.openhab.binding.tado.internal.api.model.User;
|
||||||
|
import org.openhab.binding.tado.internal.api.model.UserHomes;
|
||||||
import org.openhab.binding.tado.internal.config.TadoHomeConfig;
|
import org.openhab.binding.tado.internal.config.TadoHomeConfig;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
import org.openhab.core.thing.Bridge;
|
import org.openhab.core.thing.Bridge;
|
||||||
@ -36,6 +40,7 @@ import org.openhab.core.thing.binding.BaseBridgeHandler;
|
|||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
import org.openhab.core.types.RefreshType;
|
import org.openhab.core.types.RefreshType;
|
||||||
import org.openhab.core.types.State;
|
import org.openhab.core.types.State;
|
||||||
|
import org.openhab.core.types.UnDefType;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -44,21 +49,23 @@ import org.slf4j.LoggerFactory;
|
|||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class TadoHomeHandler extends BaseBridgeHandler {
|
public class TadoHomeHandler extends BaseBridgeHandler {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(TadoHomeHandler.class);
|
private Logger logger = LoggerFactory.getLogger(TadoHomeHandler.class);
|
||||||
|
|
||||||
private TadoHomeConfig configuration;
|
private TadoHomeConfig configuration;
|
||||||
private HomeApi api;
|
private final HomeApi api;
|
||||||
private Long homeId;
|
|
||||||
|
|
||||||
private TadoBatteryChecker batteryChecker;
|
private @Nullable Long homeId;
|
||||||
|
private @Nullable TadoBatteryChecker batteryChecker;
|
||||||
private ScheduledFuture<?> initializationFuture;
|
private @Nullable ScheduledFuture<?> initializationFuture;
|
||||||
|
|
||||||
public TadoHomeHandler(Bridge bridge) {
|
public TadoHomeHandler(Bridge bridge) {
|
||||||
super(bridge);
|
super(bridge);
|
||||||
batteryChecker = new TadoBatteryChecker(this);
|
batteryChecker = new TadoBatteryChecker(this);
|
||||||
|
configuration = getConfigAs(TadoHomeConfig.class);
|
||||||
|
api = new HomeApiFactory().create(configuration.username, configuration.password);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TemperatureUnit getTemperatureUnit() {
|
public TemperatureUnit getTemperatureUnit() {
|
||||||
@ -70,11 +77,10 @@ public class TadoHomeHandler extends BaseBridgeHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
configuration = getConfigAs(TadoHomeConfig.class);
|
configuration = getConfigAs(TadoHomeConfig.class);
|
||||||
api = new HomeApiFactory().create(configuration.username, configuration.password);
|
ScheduledFuture<?> initializationFuture = this.initializationFuture;
|
||||||
|
if (initializationFuture == null || initializationFuture.isDone()) {
|
||||||
if (this.initializationFuture == null || this.initializationFuture.isDone()) {
|
this.initializationFuture = scheduler.scheduleWithFixedDelay(
|
||||||
initializationFuture = scheduler.scheduleWithFixedDelay(this::initializeBridgeStatusAndPropertiesIfOffline,
|
this::initializeBridgeStatusAndPropertiesIfOffline, 0, 300, TimeUnit.SECONDS);
|
||||||
0, 300, TimeUnit.SECONDS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,13 +99,20 @@ public class TadoHomeHandler extends BaseBridgeHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.getHomes().isEmpty()) {
|
List<UserHomes> homes = user.getHomes();
|
||||||
|
if (homes == null || homes.isEmpty()) {
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
"User does not have access to any home");
|
"User does not have access to any home");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
homeId = user.getHomes().get(0).getId().longValue();
|
Integer firstHomeId = homes.get(0).getId();
|
||||||
|
if (firstHomeId == null) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Missing Home Id");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
homeId = firstHomeId.longValue();
|
||||||
|
|
||||||
HomeInfo homeInfo = api.showHome(homeId);
|
HomeInfo homeInfo = api.showHome(homeId);
|
||||||
TemperatureUnit temperatureUnit = org.openhab.binding.tado.internal.api.model.TemperatureUnit.FAHRENHEIT == homeInfo
|
TemperatureUnit temperatureUnit = org.openhab.binding.tado.internal.api.model.TemperatureUnit.FAHRENHEIT == homeInfo
|
||||||
@ -118,9 +131,9 @@ public class TadoHomeHandler extends BaseBridgeHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
if (this.initializationFuture != null || !this.initializationFuture.isDone()) {
|
ScheduledFuture<?> initializationFuture = this.initializationFuture;
|
||||||
this.initializationFuture.cancel(true);
|
if (initializationFuture != null && !initializationFuture.isCancelled()) {
|
||||||
this.initializationFuture = null;
|
initializationFuture.cancel(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,13 +141,12 @@ public class TadoHomeHandler extends BaseBridgeHandler {
|
|||||||
return api;
|
return api;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long getHomeId() {
|
public @Nullable Long getHomeId() {
|
||||||
return homeId;
|
return homeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HomeState getHomeState() throws IOException, ApiException {
|
public HomeState getHomeState() throws IOException, ApiException {
|
||||||
HomeApi api = getApi();
|
return api.homeState(getHomeId());
|
||||||
return api != null ? api.homeState(getHomeId()) : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateHomeState() {
|
public void updateHomeState() {
|
||||||
@ -173,6 +185,7 @@ public class TadoHomeHandler extends BaseBridgeHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public State getBatteryLowAlarm(long zoneId) {
|
public State getBatteryLowAlarm(long zoneId) {
|
||||||
return batteryChecker.getBatteryLowAlarm(zoneId);
|
TadoBatteryChecker batteryChecker = this.batteryChecker;
|
||||||
|
return batteryChecker != null ? batteryChecker.getBatteryLowAlarm(zoneId) : UnDefType.UNDEF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,8 @@ import java.io.IOException;
|
|||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants;
|
import org.openhab.binding.tado.internal.TadoBindingConstants;
|
||||||
import org.openhab.binding.tado.internal.api.ApiException;
|
import org.openhab.binding.tado.internal.api.ApiException;
|
||||||
import org.openhab.binding.tado.internal.api.model.MobileDevice;
|
import org.openhab.binding.tado.internal.api.model.MobileDevice;
|
||||||
@ -37,15 +39,17 @@ import org.slf4j.LoggerFactory;
|
|||||||
*
|
*
|
||||||
* @author Dennis Frommknecht - Initial contribution
|
* @author Dennis Frommknecht - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class TadoMobileDeviceHandler extends BaseHomeThingHandler {
|
public class TadoMobileDeviceHandler extends BaseHomeThingHandler {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(TadoMobileDeviceHandler.class);
|
private Logger logger = LoggerFactory.getLogger(TadoMobileDeviceHandler.class);
|
||||||
|
|
||||||
private TadoMobileDeviceConfig configuration;
|
private TadoMobileDeviceConfig configuration;
|
||||||
private ScheduledFuture<?> refreshTimer;
|
private @Nullable ScheduledFuture<?> refreshTimer;
|
||||||
|
|
||||||
public TadoMobileDeviceHandler(Thing thing) {
|
public TadoMobileDeviceHandler(Thing thing) {
|
||||||
super(thing);
|
super(thing);
|
||||||
|
configuration = getConfigAs(TadoMobileDeviceConfig.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -61,7 +65,6 @@ public class TadoMobileDeviceHandler extends BaseHomeThingHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
configuration = getConfigAs(TadoMobileDeviceConfig.class);
|
configuration = getConfigAs(TadoMobileDeviceConfig.class);
|
||||||
|
|
||||||
if (configuration.refreshInterval <= 0) {
|
if (configuration.refreshInterval <= 0) {
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Refresh interval of zone "
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Refresh interval of zone "
|
||||||
+ configuration.id + " of home " + getHomeId() + " must be greater than zero");
|
+ configuration.id + " of home " + getHomeId() + " must be greater than zero");
|
||||||
@ -135,13 +138,15 @@ public class TadoMobileDeviceHandler extends BaseHomeThingHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleZoneStateUpdate() {
|
private void scheduleZoneStateUpdate() {
|
||||||
|
ScheduledFuture<?> refreshTimer = this.refreshTimer;
|
||||||
if (refreshTimer == null || refreshTimer.isCancelled()) {
|
if (refreshTimer == null || refreshTimer.isCancelled()) {
|
||||||
refreshTimer = scheduler.scheduleWithFixedDelay(this::updateState, 5, configuration.refreshInterval,
|
this.refreshTimer = scheduler.scheduleWithFixedDelay(this::updateState, 5, configuration.refreshInterval,
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelScheduledStateUpdate() {
|
private void cancelScheduledStateUpdate() {
|
||||||
|
ScheduledFuture<?> refreshTimer = this.refreshTimer;
|
||||||
if (refreshTimer != null) {
|
if (refreshTimer != null) {
|
||||||
refreshTimer.cancel(false);
|
refreshTimer.cancel(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import javax.measure.quantity.Temperature;
|
import javax.measure.quantity.Temperature;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants;
|
import org.openhab.binding.tado.internal.TadoBindingConstants;
|
||||||
import org.openhab.binding.tado.internal.TadoBindingConstants.FanLevel;
|
import org.openhab.binding.tado.internal.TadoBindingConstants.FanLevel;
|
||||||
@ -33,13 +34,13 @@ import org.openhab.binding.tado.internal.TadoBindingConstants.ZoneType;
|
|||||||
import org.openhab.binding.tado.internal.TadoHvacChange;
|
import org.openhab.binding.tado.internal.TadoHvacChange;
|
||||||
import org.openhab.binding.tado.internal.adapter.TadoZoneStateAdapter;
|
import org.openhab.binding.tado.internal.adapter.TadoZoneStateAdapter;
|
||||||
import org.openhab.binding.tado.internal.api.ApiException;
|
import org.openhab.binding.tado.internal.api.ApiException;
|
||||||
|
import org.openhab.binding.tado.internal.api.GsonBuilderFactory;
|
||||||
import org.openhab.binding.tado.internal.api.TadoApiTypeUtils;
|
import org.openhab.binding.tado.internal.api.TadoApiTypeUtils;
|
||||||
import org.openhab.binding.tado.internal.api.client.HomeApi;
|
|
||||||
import org.openhab.binding.tado.internal.api.model.ACFanLevel;
|
import org.openhab.binding.tado.internal.api.model.ACFanLevel;
|
||||||
import org.openhab.binding.tado.internal.api.model.ACHorizontalSwing;
|
import org.openhab.binding.tado.internal.api.model.ACHorizontalSwing;
|
||||||
import org.openhab.binding.tado.internal.api.model.ACVerticalSwing;
|
import org.openhab.binding.tado.internal.api.model.ACVerticalSwing;
|
||||||
|
import org.openhab.binding.tado.internal.api.model.AcMode;
|
||||||
import org.openhab.binding.tado.internal.api.model.AcModeCapabilities;
|
import org.openhab.binding.tado.internal.api.model.AcModeCapabilities;
|
||||||
import org.openhab.binding.tado.internal.api.model.AirConditioningCapabilities;
|
|
||||||
import org.openhab.binding.tado.internal.api.model.CoolingZoneSetting;
|
import org.openhab.binding.tado.internal.api.model.CoolingZoneSetting;
|
||||||
import org.openhab.binding.tado.internal.api.model.GenericZoneCapabilities;
|
import org.openhab.binding.tado.internal.api.model.GenericZoneCapabilities;
|
||||||
import org.openhab.binding.tado.internal.api.model.GenericZoneSetting;
|
import org.openhab.binding.tado.internal.api.model.GenericZoneSetting;
|
||||||
@ -65,11 +66,12 @@ import org.openhab.core.thing.ThingStatusDetail;
|
|||||||
import org.openhab.core.thing.ThingStatusInfo;
|
import org.openhab.core.thing.ThingStatusInfo;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
import org.openhab.core.types.RefreshType;
|
import org.openhab.core.types.RefreshType;
|
||||||
import org.openhab.core.types.State;
|
|
||||||
import org.openhab.core.types.StateOption;
|
import org.openhab.core.types.StateOption;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link TadoZoneHandler} is responsible for handling commands of zones and update their state.
|
* The {@link TadoZoneHandler} is responsible for handling commands of zones and update their state.
|
||||||
*
|
*
|
||||||
@ -77,47 +79,61 @@ import org.slf4j.LoggerFactory;
|
|||||||
* @author Andrew Fiddian-Green - Added Low Battery Alarm, A/C Power and Open Window channels
|
* @author Andrew Fiddian-Green - Added Low Battery Alarm, A/C Power and Open Window channels
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class TadoZoneHandler extends BaseHomeThingHandler {
|
public class TadoZoneHandler extends BaseHomeThingHandler {
|
||||||
private Logger logger = LoggerFactory.getLogger(TadoZoneHandler.class);
|
private Logger logger = LoggerFactory.getLogger(TadoZoneHandler.class);
|
||||||
|
|
||||||
private final TadoStateDescriptionProvider stateDescriptionProvider;
|
private final TadoStateDescriptionProvider stateDescriptionProvider;
|
||||||
|
|
||||||
private TadoZoneConfig configuration;
|
private TadoZoneConfig configuration;
|
||||||
private ScheduledFuture<?> refreshTimer;
|
|
||||||
private ScheduledFuture<?> scheduledHvacChange;
|
private @Nullable ScheduledFuture<?> refreshTimer;
|
||||||
private GenericZoneCapabilities capabilities;
|
private @Nullable ScheduledFuture<?> scheduledHvacChange;
|
||||||
TadoHvacChange pendingHvacChange;
|
private @Nullable GenericZoneCapabilities capabilities;
|
||||||
|
private @Nullable TadoHvacChange pendingHvacChange;
|
||||||
|
|
||||||
|
private boolean disposing = false;
|
||||||
|
private @Nullable Gson gson;
|
||||||
|
|
||||||
public TadoZoneHandler(Thing thing, TadoStateDescriptionProvider stateDescriptionProvider) {
|
public TadoZoneHandler(Thing thing, TadoStateDescriptionProvider stateDescriptionProvider) {
|
||||||
super(thing);
|
super(thing);
|
||||||
this.stateDescriptionProvider = stateDescriptionProvider;
|
this.stateDescriptionProvider = stateDescriptionProvider;
|
||||||
|
configuration = getConfigAs(TadoZoneConfig.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getZoneId() {
|
public long getZoneId() {
|
||||||
return this.configuration.id;
|
return configuration.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFallbackTimerDuration() {
|
public int getFallbackTimerDuration() {
|
||||||
return this.configuration.fallbackTimerDuration;
|
return configuration.fallbackTimerDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable ZoneType getZoneType() {
|
public ZoneType getZoneType() {
|
||||||
String zoneTypeStr = this.thing.getProperties().get(TadoBindingConstants.PROPERTY_ZONE_TYPE);
|
String zoneTypeStr = thing.getProperties().get(TadoBindingConstants.PROPERTY_ZONE_TYPE);
|
||||||
return zoneTypeStr != null ? ZoneType.valueOf(zoneTypeStr) : null;
|
if (zoneTypeStr == null) {
|
||||||
|
throw new IllegalStateException("Zone type not initialized");
|
||||||
|
}
|
||||||
|
return ZoneType.valueOf(zoneTypeStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OverlayTerminationCondition getDefaultTerminationCondition() throws IOException, ApiException {
|
public OverlayTerminationCondition getDefaultTerminationCondition() throws IOException, ApiException {
|
||||||
OverlayTemplate overlayTemplate = getApi().showZoneDefaultOverlay(getHomeId(), getZoneId());
|
OverlayTemplate overlayTemplate = getApi().showZoneDefaultOverlay(getHomeId(), getZoneId());
|
||||||
|
logApiTransaction(overlayTemplate, false);
|
||||||
return terminationConditionTemplateToTerminationCondition(overlayTemplate.getTerminationCondition());
|
return terminationConditionTemplateToTerminationCondition(overlayTemplate.getTerminationCondition());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZoneState getZoneState() throws IOException, ApiException {
|
public ZoneState getZoneState() throws IOException, ApiException {
|
||||||
HomeApi api = getApi();
|
ZoneState zoneState = getApi().showZoneState(getHomeId(), getZoneId());
|
||||||
return api != null ? api.showZoneState(getHomeId(), getZoneId()) : null;
|
logApiTransaction(zoneState, false);
|
||||||
|
return zoneState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GenericZoneCapabilities getZoneCapabilities() {
|
public GenericZoneCapabilities getZoneCapabilities() {
|
||||||
return this.capabilities;
|
GenericZoneCapabilities capabilities = this.capabilities;
|
||||||
|
if (capabilities == null) {
|
||||||
|
throw new IllegalStateException("Zone capabilities not initialized");
|
||||||
|
}
|
||||||
|
return capabilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TemperatureUnit getTemperatureUnit() {
|
public TemperatureUnit getTemperatureUnit() {
|
||||||
@ -125,9 +141,17 @@ public class TadoZoneHandler extends BaseHomeThingHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Overlay setOverlay(Overlay overlay) throws IOException, ApiException {
|
public Overlay setOverlay(Overlay overlay) throws IOException, ApiException {
|
||||||
logger.debug("Setting overlay of home {} and zone {} with overlay: {}", getHomeId(), getZoneId(),
|
try {
|
||||||
overlay.toString());
|
logApiTransaction(overlay, true);
|
||||||
return getApi().updateZoneOverlay(getHomeId(), getZoneId(), overlay);
|
Overlay newOverlay = getApi().updateZoneOverlay(getHomeId(), getZoneId(), overlay);
|
||||||
|
logApiTransaction(newOverlay, false);
|
||||||
|
return newOverlay;
|
||||||
|
} catch (ApiException e) {
|
||||||
|
if (!logger.isTraceEnabled()) {
|
||||||
|
logger.warn("ApiException sending JSON content:\n{}", convertToJsonString(overlay));
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeOverlay() throws IOException, ApiException {
|
public void removeOverlay() throws IOException, ApiException {
|
||||||
@ -144,65 +168,75 @@ public class TadoZoneHandler extends BaseHomeThingHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (id) {
|
synchronized (this) {
|
||||||
case TadoBindingConstants.CHANNEL_ZONE_HVAC_MODE:
|
TadoHvacChange pendingHvacChange = this.pendingHvacChange;
|
||||||
pendingHvacChange.withHvacMode(((StringType) command).toFullString());
|
if (pendingHvacChange == null) {
|
||||||
scheduleHvacChange();
|
throw new IllegalStateException("Zone pendingHvacChange not initialized");
|
||||||
break;
|
}
|
||||||
case TadoBindingConstants.CHANNEL_ZONE_TARGET_TEMPERATURE:
|
|
||||||
QuantityType<Temperature> state = (QuantityType<Temperature>) command;
|
|
||||||
QuantityType<Temperature> stateInTargetUnit = getTemperatureUnit() == TemperatureUnit.FAHRENHEIT
|
|
||||||
? state.toUnit(ImperialUnits.FAHRENHEIT)
|
|
||||||
: state.toUnit(SIUnits.CELSIUS);
|
|
||||||
|
|
||||||
if (stateInTargetUnit != null) {
|
switch (id) {
|
||||||
pendingHvacChange.withTemperature(stateInTargetUnit.floatValue());
|
case TadoBindingConstants.CHANNEL_ZONE_HVAC_MODE:
|
||||||
|
pendingHvacChange.withHvacMode(((StringType) command).toFullString());
|
||||||
scheduleHvacChange();
|
scheduleHvacChange();
|
||||||
}
|
break;
|
||||||
|
case TadoBindingConstants.CHANNEL_ZONE_TARGET_TEMPERATURE:
|
||||||
|
if (command instanceof QuantityType<?>) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
QuantityType<Temperature> state = (QuantityType<Temperature>) command;
|
||||||
|
QuantityType<Temperature> stateInTargetUnit = getTemperatureUnit() == TemperatureUnit.FAHRENHEIT
|
||||||
|
? state.toUnit(ImperialUnits.FAHRENHEIT)
|
||||||
|
: state.toUnit(SIUnits.CELSIUS);
|
||||||
|
|
||||||
break;
|
if (stateInTargetUnit != null) {
|
||||||
case TadoBindingConstants.CHANNEL_ZONE_SWING:
|
pendingHvacChange.withTemperature(stateInTargetUnit.floatValue());
|
||||||
pendingHvacChange.withSwing(((OnOffType) command) == OnOffType.ON);
|
scheduleHvacChange();
|
||||||
scheduleHvacChange();
|
}
|
||||||
break;
|
}
|
||||||
case TadoBindingConstants.CHANNEL_ZONE_LIGHT:
|
break;
|
||||||
pendingHvacChange.withLight(((OnOffType) command) == OnOffType.ON);
|
case TadoBindingConstants.CHANNEL_ZONE_SWING:
|
||||||
scheduleHvacChange();
|
pendingHvacChange.withSwing(((OnOffType) command) == OnOffType.ON);
|
||||||
break;
|
scheduleHvacChange();
|
||||||
case TadoBindingConstants.CHANNEL_ZONE_FAN_SPEED:
|
break;
|
||||||
pendingHvacChange.withFanSpeed(((StringType) command).toFullString());
|
case TadoBindingConstants.CHANNEL_ZONE_LIGHT:
|
||||||
scheduleHvacChange();
|
pendingHvacChange.withLight(((OnOffType) command) == OnOffType.ON);
|
||||||
break;
|
scheduleHvacChange();
|
||||||
case TadoBindingConstants.CHANNEL_ZONE_FAN_LEVEL:
|
break;
|
||||||
String fanLevelString = ((StringType) command).toFullString();
|
case TadoBindingConstants.CHANNEL_ZONE_FAN_SPEED:
|
||||||
pendingHvacChange.withFanLevel(FanLevel.valueOf(fanLevelString.toUpperCase()));
|
pendingHvacChange.withFanSpeed(((StringType) command).toFullString());
|
||||||
break;
|
scheduleHvacChange();
|
||||||
case TadoBindingConstants.CHANNEL_ZONE_HORIZONTAL_SWING:
|
break;
|
||||||
String horizontalSwingString = ((StringType) command).toFullString();
|
case TadoBindingConstants.CHANNEL_ZONE_FAN_LEVEL:
|
||||||
pendingHvacChange.withHorizontalSwing(HorizontalSwing.valueOf(horizontalSwingString.toUpperCase()));
|
String fanLevelString = ((StringType) command).toFullString();
|
||||||
scheduleHvacChange();
|
pendingHvacChange.withFanLevel(FanLevel.valueOf(fanLevelString.toUpperCase()));
|
||||||
break;
|
scheduleHvacChange();
|
||||||
case TadoBindingConstants.CHANNEL_ZONE_VERTICAL_SWING:
|
break;
|
||||||
String verticalSwingString = ((StringType) command).toFullString();
|
case TadoBindingConstants.CHANNEL_ZONE_HORIZONTAL_SWING:
|
||||||
pendingHvacChange.withVerticalSwing(VerticalSwing.valueOf(verticalSwingString.toUpperCase()));
|
String horizontalSwingString = ((StringType) command).toFullString();
|
||||||
scheduleHvacChange();
|
pendingHvacChange.withHorizontalSwing(HorizontalSwing.valueOf(horizontalSwingString.toUpperCase()));
|
||||||
break;
|
scheduleHvacChange();
|
||||||
case TadoBindingConstants.CHANNEL_ZONE_OPERATION_MODE:
|
break;
|
||||||
String operationMode = ((StringType) command).toFullString();
|
case TadoBindingConstants.CHANNEL_ZONE_VERTICAL_SWING:
|
||||||
pendingHvacChange.withOperationMode(OperationMode.valueOf(operationMode));
|
String verticalSwingString = ((StringType) command).toFullString();
|
||||||
scheduleHvacChange();
|
pendingHvacChange.withVerticalSwing(VerticalSwing.valueOf(verticalSwingString.toUpperCase()));
|
||||||
break;
|
scheduleHvacChange();
|
||||||
case TadoBindingConstants.CHANNEL_ZONE_TIMER_DURATION:
|
break;
|
||||||
pendingHvacChange.activeFor(((DecimalType) command).intValue());
|
case TadoBindingConstants.CHANNEL_ZONE_OPERATION_MODE:
|
||||||
scheduleHvacChange();
|
String operationMode = ((StringType) command).toFullString();
|
||||||
break;
|
pendingHvacChange.withOperationMode(OperationMode.valueOf(operationMode));
|
||||||
|
scheduleHvacChange();
|
||||||
|
break;
|
||||||
|
case TadoBindingConstants.CHANNEL_ZONE_TIMER_DURATION:
|
||||||
|
pendingHvacChange.activeForMinutes(((DecimalType) command).intValue());
|
||||||
|
scheduleHvacChange();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
|
disposing = false;
|
||||||
configuration = getConfigAs(TadoZoneConfig.class);
|
configuration = getConfigAs(TadoZoneConfig.class);
|
||||||
|
|
||||||
if (configuration.refreshInterval <= 0) {
|
if (configuration.refreshInterval <= 0) {
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Refresh interval of zone "
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Refresh interval of zone "
|
||||||
+ getZoneId() + " of home " + getHomeId() + " must be greater than zero");
|
+ getZoneId() + " of home " + getHomeId() + " must be greater than zero");
|
||||||
@ -225,6 +259,7 @@ public class TadoZoneHandler extends BaseHomeThingHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
|
disposing = true;
|
||||||
cancelScheduledZoneStateUpdate();
|
cancelScheduledZoneStateUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +268,10 @@ public class TadoZoneHandler extends BaseHomeThingHandler {
|
|||||||
if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) {
|
if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) {
|
||||||
try {
|
try {
|
||||||
Zone zoneDetails = getApi().showZoneDetails(getHomeId(), getZoneId());
|
Zone zoneDetails = getApi().showZoneDetails(getHomeId(), getZoneId());
|
||||||
|
logApiTransaction(zoneDetails, false);
|
||||||
|
|
||||||
GenericZoneCapabilities capabilities = getApi().showZoneCapabilities(getHomeId(), getZoneId());
|
GenericZoneCapabilities capabilities = getApi().showZoneCapabilities(getHomeId(), getZoneId());
|
||||||
|
logApiTransaction(capabilities, false);
|
||||||
|
|
||||||
if (zoneDetails == null || capabilities == null) {
|
if (zoneDetails == null || capabilities == null) {
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
@ -244,7 +282,6 @@ public class TadoZoneHandler extends BaseHomeThingHandler {
|
|||||||
updateProperty(TadoBindingConstants.PROPERTY_ZONE_NAME, zoneDetails.getName());
|
updateProperty(TadoBindingConstants.PROPERTY_ZONE_NAME, zoneDetails.getName());
|
||||||
updateProperty(TadoBindingConstants.PROPERTY_ZONE_TYPE, zoneDetails.getType().name());
|
updateProperty(TadoBindingConstants.PROPERTY_ZONE_TYPE, zoneDetails.getType().name());
|
||||||
this.capabilities = capabilities;
|
this.capabilities = capabilities;
|
||||||
logger.debug("Got capabilities: {}", capabilities.toString());
|
|
||||||
} catch (IOException | ApiException e) {
|
} catch (IOException | ApiException e) {
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
"Could not connect to server due to " + e.getMessage());
|
"Could not connect to server due to " + e.getMessage());
|
||||||
@ -263,12 +300,14 @@ public class TadoZoneHandler extends BaseHomeThingHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateZoneState(boolean forceUpdate) {
|
private void updateZoneState(boolean forceUpdate) {
|
||||||
TadoHomeHandler home = getHomeHandler();
|
if ((thing.getStatus() != ThingStatus.ONLINE) || disposing) {
|
||||||
if (home != null) {
|
return;
|
||||||
home.updateHomeState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getHomeHandler().updateHomeState();
|
||||||
|
|
||||||
// No update during HVAC change debounce
|
// No update during HVAC change debounce
|
||||||
|
ScheduledFuture<?> scheduledHvacChange = this.scheduledHvacChange;
|
||||||
if (!forceUpdate && scheduledHvacChange != null && !scheduledHvacChange.isDone()) {
|
if (!forceUpdate && scheduledHvacChange != null && !scheduledHvacChange.isDone()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -276,18 +315,14 @@ public class TadoZoneHandler extends BaseHomeThingHandler {
|
|||||||
try {
|
try {
|
||||||
ZoneState zoneState = getZoneState();
|
ZoneState zoneState = getZoneState();
|
||||||
|
|
||||||
if (zoneState == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("Updating state of home {} and zone {}", getHomeId(), getZoneId());
|
logger.debug("Updating state of home {} and zone {}", getHomeId(), getZoneId());
|
||||||
|
|
||||||
TadoZoneStateAdapter state = new TadoZoneStateAdapter(zoneState, getTemperatureUnit());
|
TadoZoneStateAdapter state = new TadoZoneStateAdapter(zoneState, getTemperatureUnit());
|
||||||
updateStateIfNotNull(TadoBindingConstants.CHANNEL_ZONE_CURRENT_TEMPERATURE, state.getInsideTemperature());
|
updateState(TadoBindingConstants.CHANNEL_ZONE_CURRENT_TEMPERATURE, state.getInsideTemperature());
|
||||||
updateStateIfNotNull(TadoBindingConstants.CHANNEL_ZONE_HUMIDITY, state.getHumidity());
|
updateState(TadoBindingConstants.CHANNEL_ZONE_HUMIDITY, state.getHumidity());
|
||||||
|
|
||||||
updateStateIfNotNull(TadoBindingConstants.CHANNEL_ZONE_HEATING_POWER, state.getHeatingPower());
|
updateState(TadoBindingConstants.CHANNEL_ZONE_HEATING_POWER, state.getHeatingPower());
|
||||||
updateStateIfNotNull(TadoBindingConstants.CHANNEL_ZONE_AC_POWER, state.getAcPower());
|
updateState(TadoBindingConstants.CHANNEL_ZONE_AC_POWER, state.getAcPower());
|
||||||
|
|
||||||
updateState(TadoBindingConstants.CHANNEL_ZONE_OPERATION_MODE, state.getOperationMode());
|
updateState(TadoBindingConstants.CHANNEL_ZONE_OPERATION_MODE, state.getOperationMode());
|
||||||
|
|
||||||
@ -314,9 +349,8 @@ public class TadoZoneHandler extends BaseHomeThingHandler {
|
|||||||
"Could not connect to server due to " + e.getMessage());
|
"Could not connect to server due to " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (home != null) {
|
updateState(TadoBindingConstants.CHANNEL_ZONE_BATTERY_LOW_ALARM,
|
||||||
updateState(TadoBindingConstants.CHANNEL_ZONE_BATTERY_LOW_ALARM, home.getBatteryLowAlarm(getZoneId()));
|
getHomeHandler().getBatteryLowAlarm(getZoneId()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -333,32 +367,35 @@ public class TadoZoneHandler extends BaseHomeThingHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AcModeCapabilities acCapabilities = TadoApiTypeUtils.getModeCapabilities(
|
AcMode acMode = ((CoolingZoneSetting) setting).getMode();
|
||||||
(AirConditioningCapabilities) capabilities, ((CoolingZoneSetting) setting).getMode());
|
AcModeCapabilities acModeCapabilities = acMode == null ? new AcModeCapabilities()
|
||||||
|
: TadoApiTypeUtils.getModeCapabilities(acMode, capabilities);
|
||||||
|
|
||||||
if (acCapabilities != null) {
|
// update the options list of supported fan levels
|
||||||
Channel channel;
|
Channel channel = thing.getChannel(TadoBindingConstants.CHANNEL_ZONE_FAN_LEVEL);
|
||||||
|
if (channel != null) {
|
||||||
// update the options list of supported fan levels
|
List<ACFanLevel> fanLevels = acModeCapabilities.getFanLevel();
|
||||||
channel = thing.getChannel(TadoBindingConstants.CHANNEL_ZONE_FAN_LEVEL);
|
if (fanLevels != null) {
|
||||||
List<ACFanLevel> fanLevels = acCapabilities.getFanLevel();
|
|
||||||
if (channel != null && fanLevels != null) {
|
|
||||||
stateDescriptionProvider.setStateOptions(channel.getUID(),
|
stateDescriptionProvider.setStateOptions(channel.getUID(),
|
||||||
fanLevels.stream().map(u -> new StateOption(u.name(), u.name())).collect(Collectors.toList()));
|
fanLevels.stream().map(u -> new StateOption(u.name(), u.name())).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// update the options list of supported horizontal swing settings
|
// update the options list of supported horizontal swing settings
|
||||||
channel = thing.getChannel(TadoBindingConstants.CHANNEL_ZONE_HORIZONTAL_SWING);
|
channel = thing.getChannel(TadoBindingConstants.CHANNEL_ZONE_HORIZONTAL_SWING);
|
||||||
List<ACHorizontalSwing> horizontalSwings = acCapabilities.getHorizontalSwing();
|
if (channel != null) {
|
||||||
if (channel != null && horizontalSwings != null) {
|
List<ACHorizontalSwing> horizontalSwings = acModeCapabilities.getHorizontalSwing();
|
||||||
|
if (horizontalSwings != null) {
|
||||||
stateDescriptionProvider.setStateOptions(channel.getUID(), horizontalSwings.stream()
|
stateDescriptionProvider.setStateOptions(channel.getUID(), horizontalSwings.stream()
|
||||||
.map(u -> new StateOption(u.name(), u.name())).collect(Collectors.toList()));
|
.map(u -> new StateOption(u.name(), u.name())).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// update the options list of supported vertical swing settings
|
// update the options list of supported vertical swing settings
|
||||||
channel = thing.getChannel(TadoBindingConstants.CHANNEL_ZONE_VERTICAL_SWING);
|
channel = thing.getChannel(TadoBindingConstants.CHANNEL_ZONE_VERTICAL_SWING);
|
||||||
List<ACVerticalSwing> verticalSwings = acCapabilities.getVerticalSwing();
|
if (channel != null) {
|
||||||
if (channel != null && verticalSwings != null) {
|
List<ACVerticalSwing> verticalSwings = acModeCapabilities.getVerticalSwing();
|
||||||
|
if (verticalSwings != null) {
|
||||||
stateDescriptionProvider.setStateOptions(channel.getUID(), verticalSwings.stream()
|
stateDescriptionProvider.setStateOptions(channel.getUID(), verticalSwings.stream()
|
||||||
.map(u -> new StateOption(u.name(), u.name())).collect(Collectors.toList()));
|
.map(u -> new StateOption(u.name(), u.name())).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
@ -366,8 +403,9 @@ public class TadoZoneHandler extends BaseHomeThingHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleZoneStateUpdate() {
|
private void scheduleZoneStateUpdate() {
|
||||||
|
ScheduledFuture<?> refreshTimer = this.refreshTimer;
|
||||||
if (refreshTimer == null || refreshTimer.isCancelled()) {
|
if (refreshTimer == null || refreshTimer.isCancelled()) {
|
||||||
refreshTimer = scheduler.scheduleWithFixedDelay(new Runnable() {
|
this.refreshTimer = scheduler.scheduleWithFixedDelay(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
updateZoneState(false);
|
updateZoneState(false);
|
||||||
@ -377,21 +415,26 @@ public class TadoZoneHandler extends BaseHomeThingHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void cancelScheduledZoneStateUpdate() {
|
private void cancelScheduledZoneStateUpdate() {
|
||||||
|
ScheduledFuture<?> refreshTimer = this.refreshTimer;
|
||||||
if (refreshTimer != null) {
|
if (refreshTimer != null) {
|
||||||
refreshTimer.cancel(false);
|
refreshTimer.cancel(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleHvacChange() {
|
private void scheduleHvacChange() {
|
||||||
|
ScheduledFuture<?> scheduledHvacChange = this.scheduledHvacChange;
|
||||||
if (scheduledHvacChange != null) {
|
if (scheduledHvacChange != null) {
|
||||||
scheduledHvacChange.cancel(false);
|
scheduledHvacChange.cancel(false);
|
||||||
}
|
}
|
||||||
|
this.scheduledHvacChange = scheduler.schedule(() -> {
|
||||||
scheduledHvacChange = scheduler.schedule(() -> {
|
|
||||||
try {
|
try {
|
||||||
TadoHvacChange change = this.pendingHvacChange;
|
synchronized (this) {
|
||||||
this.pendingHvacChange = new TadoHvacChange(getThing());
|
TadoHvacChange pendingHvacChange = this.pendingHvacChange;
|
||||||
change.apply();
|
this.pendingHvacChange = new TadoHvacChange(getThing());
|
||||||
|
if (pendingHvacChange != null) {
|
||||||
|
pendingHvacChange.apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||||
} catch (ApiException e) {
|
} catch (ApiException e) {
|
||||||
@ -403,9 +446,32 @@ public class TadoZoneHandler extends BaseHomeThingHandler {
|
|||||||
}, configuration.hvacChangeDebounce, TimeUnit.SECONDS);
|
}, configuration.hvacChangeDebounce, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateStateIfNotNull(String channelID, State state) {
|
/**
|
||||||
if (state != null) {
|
* Helper method to log an API transaction on the given object.
|
||||||
updateState(channelID, state);
|
* If the logger level is 'debug', the transaction is simply logged.
|
||||||
|
* If the logger level is 'trace, the object's JSON serial contents are included.
|
||||||
|
*
|
||||||
|
* @param object the object to be logged.
|
||||||
|
* @param isCommand marks whether the transaction is a command to, or a response from, the server.
|
||||||
|
*/
|
||||||
|
private void logApiTransaction(Object object, boolean isCommand) {
|
||||||
|
if (logger.isDebugEnabled() || logger.isTraceEnabled()) {
|
||||||
|
String logType = isCommand ? "command" : "response";
|
||||||
|
if (logger.isTraceEnabled()) {
|
||||||
|
logger.trace("Api {}: homeId:{}, zoneId:{}, objectId:{}, content:\n{}", logType, getHomeId(),
|
||||||
|
getZoneId(), object.getClass().getSimpleName(), convertToJsonString(object));
|
||||||
|
} else if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Api {}: homeId:{}, zoneId:{}, objectId:{}", logType, getHomeId(), getZoneId(),
|
||||||
|
object.getClass().getSimpleName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized String convertToJsonString(Object object) {
|
||||||
|
Gson gson = this.gson;
|
||||||
|
if (gson == null) {
|
||||||
|
gson = this.gson = GsonBuilderFactory.defaultGsonBuilder().setPrettyPrinting().create();
|
||||||
|
}
|
||||||
|
return gson.toJson(object);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user