From f8bbb2b5a5ae2773225f6ad5387d35de012b33ba Mon Sep 17 00:00:00 2001 From: Mark Herwege Date: Wed, 15 Jun 2022 13:01:22 +0200 Subject: [PATCH] [nikohomecontrol] Bug fixes and improvements to thermostats (#11963) * Thermostat fixes and implement extra thermostat channels Signed-off-by: Mark Herwege --- .../README.md | 36 +++++---- .../NikoHomeControlBindingConstants.java | 2 + .../NikoHomeControlHandlerFactory.java | 26 +++--- .../handler/NikoHomeControlBridgeHandler.java | 12 ++- .../NikoHomeControlBridgeHandler1.java | 5 +- .../NikoHomeControlBridgeHandler2.java | 6 +- .../NikoHomeControlThermostatHandler.java | 43 ++++++---- .../internal/protocol/NhcControllerEvent.java | 8 ++ .../internal/protocol/NhcEnergyMeter.java | 6 +- .../internal/protocol/NhcThermostat.java | 80 +++++++++---------- .../NikoHomeControlCommunication.java | 12 ++- .../protocol/NikoHomeControlConstants.java | 1 + .../nhc2/NikoHomeControlCommunication2.java | 12 +-- .../OH-INF/i18n/nikohomecontrol.properties | 22 +++-- .../resources/OH-INF/thing/thing-types.xml | 52 +++++++++++- 15 files changed, 211 insertions(+), 112 deletions(-) diff --git a/bundles/org.openhab.binding.nikohomecontrol/README.md b/bundles/org.openhab.binding.nikohomecontrol/README.md index 45c6ab6279..185a8e0c91 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/README.md +++ b/bundles/org.openhab.binding.nikohomecontrol/README.md @@ -237,19 +237,25 @@ OnOff, IncreaseDecrease and Percent command types are supported. Note that sending an ON command will switch the dimmer to the value stored when last turning the dimmer off, or 100% depending on the configuration in the Niko Home Control Controller. This can be changed with the Niko Home Control programming software. -For thing type `blind` the supported channel is `rollershutter`. UpDown, StopMove and Percent command types are supported. +For thing type `blind` the supported channel is `rollershutter`. +UpDown, StopMove and Percent command types are supported. -For thing type `thermostat` the supported channels are `measured`, `mode`, `setpoint`, `overruletime` and `demand`. +For thing type `thermostat` the supported channels are `measured`, `heatingmode`, `mode`, `setpoint`, `overruletime`, `heatingdemand` and `demand`. `measured` gives the current temperature in QuantityType, allowing for different temperature units. This channel is read only. -`mode` can be set and shows the current thermostat mode. -Allowed values are 0 (day), 1 (night), 2 (eco), 3 (off), 4 (cool), 5 (prog 1), 6 (prog 2), 7 (prog 3). -If mode is set, the `setpoint` temperature will return to its standard value from the mode. -`setpoint` can be set and shows the current thermostat setpoint value in QuantityType. +`heatingmode` can be set and shows the current thermostat mode. +Allowed values are Day, Night, Eco, Off, Cool, Prog1, Prog2, Prog3. +As an alternative to `heatingmode` and for backward compatibility, the advanced channel `mode` is provided. +This channel has the same meaning, but with numeric values (0=Day, 1=Night, 2=Eco, 3=Off, 4=Cool, 5=Prog1, 6=Prog2, 7=Prog3) instead of string values. +If `heatingmode` or `mode` is set, the `setpoint` temperature will return to the standard value for the mode as defined in Niko Home Control. +`setpoint` shows the current thermostat setpoint value in QuantityType. When updating `setpoint`, it will overrule the temperature setpoint defined by the thermostat mode for `overruletime` duration. -`overruletime` is used to set the total duration to apply the setpoint temperature set in the setpoint channel before the thermostat returns to the setting in its mode. -`demand` is a number indicating of the system is actively heating/cooling. +`overruletime` is used to set the total duration to apply the setpoint temperature set in the setpoint channel before the thermostat returns to the setting from its mode. +`heatingdemand` is a string indicating if the system is actively heating/cooling. +This channel will have value Heating, Cooling or None. +As an alternative to `heatingdemand`, the advanced channel `demand` is provided. The value will be 1 for heating, -1 for cooling and 0 if not heating or cooling. +`heatingdemand` and `demand` are read only channels. Note that cooling in NHC I is set by the binding, and will incorrectly show cooling demand when the system does not have cooling capabilities. In NHC II, `measured` and `setpoint` temperatures will always report in 0.5°C increments due to a Niko Home Control II API restriction. @@ -310,12 +316,12 @@ Switch AllOff {channel="nikohomecontrol:onOff:nhc1:1:button"} Switch LivingRoom {channel="nikohomecontrol:onOff:nhc1:2:switch"} # Switch for onOff type action Dimmer TVRoom {channel="nikohomecontrol:dimmer:nhc1:3:brightness"} # Changing brightness dimmer type action Rollershutter Kitchen {channel="nikohomecontrol:blind:nhc1:4:rollershutter"} # Controlling rollershutter or blind type action -Number:Temperature CurTemperature "[%.1f °F]" {channel="nikohomecontrol:thermostat:nhc1:5:measured"} # Getting measured temperature from thermostat in °F, read only -Number ThermostatMode {channel="nikohomecontrol:thermostat:nhc1:5:mode"} # Get and set thermostat mode -Number:Temperature SetTemperature "[%.1f °C]" {channel="nikohomecontrol:thermostat:nhc1:5:setpoint"} # Get and set target temperature in °C -Number OverruleDuration {channel="nikohomecontrol:thermostat:nhc1:5:overruletime"} # Get and set the overrule time -Number ThermostatDemand {channel="nikohomecontrol:thermostat:nhc1:5:demand"} # Get the current heating/cooling demand -Number:Power CurPower "[%.0f W]" {channel="nikohomecontrol:energyMeter:nhc2:6:power"} # Get current power consumption +Number:Temperature CurTemperature "[%.1f °F]" {channel="nikohomecontrol:thermostat:nhc1:5:measured"} # Getting measured temperature from thermostat in °F, read only +String ThermostatMode {channel="nikohomecontrol:thermostat:nhc1:5:heatingmode"} # Get and set thermostat mode +Number:Temperature SetTemperature "[%.1f °C]" {channel="nikohomecontrol:thermostat:nhc1:5:setpoint"} # Get and set target temperature in °C +Number OverruleDuration {channel="nikohomecontrol:thermostat:nhc1:5:overruletime"} # Get and set the overrule time +String ThermostatDemand {channel="nikohomecontrol:thermostat:nhc1:5:heatingdemand"} # Get the current heating/cooling demand +Number:Power CurPower "[%.0f W]" {channel="nikohomecontrol:energyMeter:nhc2:6:power"} # Get current power consumption ``` .sitemap: @@ -327,7 +333,7 @@ Slider item=TVRoom Switch item=TVRoom # allows switching dimmer item off or on (with controller defined behavior) Rollershutter item=Kitchen Text item=CurTemperature -Selection item=ThermostatMode mappings=[0="day", 1="night", 2="eco", 3="off", 4="cool", 5="prog 1", 6="prog 2", 7="prog 3"] +Selection item=ThermostatMode mappings=[Day="day", Night="night", Eco="eco", Off="off", Prog1="Away"] Setpoint item=SetTemperature minValue=0 maxValue=30 Slider item=OverruleDuration minValue=0 maxValue=120 Text item=Power diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlBindingConstants.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlBindingConstants.java index 17922fee54..7b43c23f45 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlBindingConstants.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlBindingConstants.java @@ -69,6 +69,8 @@ public class NikoHomeControlBindingConstants { public static final String CHANNEL_OVERRULETIME = "overruletime"; public static final String CHANNEL_MODE = "mode"; public static final String CHANNEL_DEMAND = "demand"; + public static final String CHANNEL_HEATING_MODE = "heatingmode"; + public static final String CHANNEL_HEATING_DEMAND = "heatingdemand"; public static final String CHANNEL_POWER = "power"; diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlHandlerFactory.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlHandlerFactory.java index fda292a180..ad45b6953d 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlHandlerFactory.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlHandlerFactory.java @@ -21,6 +21,7 @@ import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlBridg import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlBridgeHandler2; import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlEnergyMeterHandler; import org.openhab.binding.nikohomecontrol.internal.handler.NikoHomeControlThermostatHandler; +import org.openhab.core.i18n.TimeZoneProvider; import org.openhab.core.net.NetworkAddressService; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; @@ -28,6 +29,7 @@ import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.binding.BaseThingHandlerFactory; import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandlerFactory; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @@ -42,7 +44,16 @@ import org.osgi.service.component.annotations.Reference; @Component(service = ThingHandlerFactory.class, configurationPid = "binding.nikohomecontrol") public class NikoHomeControlHandlerFactory extends BaseThingHandlerFactory { - private @NonNullByDefault({}) NetworkAddressService networkAddressService; + private final NetworkAddressService networkAddressService; + private final TimeZoneProvider timeZoneProvider; + + @Activate + public NikoHomeControlHandlerFactory(final @Reference NetworkAddressService networkAddressService, + final @Reference TimeZoneProvider timeZoneProvider) { + super(); + this.networkAddressService = networkAddressService; + this.timeZoneProvider = timeZoneProvider; + } @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { @@ -53,9 +64,9 @@ public class NikoHomeControlHandlerFactory extends BaseThingHandlerFactory { protected @Nullable ThingHandler createHandler(Thing thing) { if (BRIDGE_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) { if (BRIDGEII_THING_TYPE.equals(thing.getThingTypeUID())) { - return new NikoHomeControlBridgeHandler2((Bridge) thing, networkAddressService); + return new NikoHomeControlBridgeHandler2((Bridge) thing, networkAddressService, timeZoneProvider); } else { - return new NikoHomeControlBridgeHandler1((Bridge) thing); + return new NikoHomeControlBridgeHandler1((Bridge) thing, timeZoneProvider); } } else if (THING_TYPE_THERMOSTAT.equals(thing.getThingTypeUID())) { return new NikoHomeControlThermostatHandler(thing); @@ -67,13 +78,4 @@ public class NikoHomeControlHandlerFactory extends BaseThingHandlerFactory { return null; } - - @Reference - protected void setNetworkAddressService(NetworkAddressService networkAddressService) { - this.networkAddressService = networkAddressService; - } - - protected void unsetNetworkAddressService(NetworkAddressService networkAddressService) { - this.networkAddressService = null; - } } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler.java index 65b29eed69..deb9103e03 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler.java @@ -16,6 +16,7 @@ import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindin import java.net.InetAddress; import java.net.UnknownHostException; +import java.time.ZoneId; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; @@ -29,6 +30,7 @@ import org.openhab.binding.nikohomecontrol.internal.discovery.NikoHomeControlDis import org.openhab.binding.nikohomecontrol.internal.protocol.NhcControllerEvent; import org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlCommunication; import org.openhab.core.config.core.Configuration; +import org.openhab.core.i18n.TimeZoneProvider; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.ThingStatus; @@ -55,8 +57,11 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp private volatile @Nullable ScheduledFuture refreshTimer; - public NikoHomeControlBridgeHandler(Bridge nikoHomeControlBridge) { + protected final TimeZoneProvider timeZoneProvider; + + public NikoHomeControlBridgeHandler(Bridge nikoHomeControlBridge, TimeZoneProvider timeZoneProvider) { super(nikoHomeControlBridge); + this.timeZoneProvider = timeZoneProvider; } @Override @@ -253,6 +258,11 @@ public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler imp return getConfig().as(NikoHomeControlBridgeConfig.class).port; } + @Override + public ZoneId getTimeZone() { + return timeZoneProvider.getTimeZone(); + } + @Override public Collection> getServices() { return Set.of(NikoHomeControlDiscoveryService.class); diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler1.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler1.java index 958681befa..95e2451de3 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler1.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler1.java @@ -20,6 +20,7 @@ import java.util.Map; import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.nikohomecontrol.internal.protocol.nhc1.NikoHomeControlCommunication1; +import org.openhab.core.i18n.TimeZoneProvider; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingStatusDetail; @@ -37,8 +38,8 @@ public class NikoHomeControlBridgeHandler1 extends NikoHomeControlBridgeHandler private final Logger logger = LoggerFactory.getLogger(NikoHomeControlBridgeHandler1.class); - public NikoHomeControlBridgeHandler1(Bridge nikoHomeControlBridge) { - super(nikoHomeControlBridge); + public NikoHomeControlBridgeHandler1(Bridge nikoHomeControlBridge, TimeZoneProvider timeZoneProvider) { + super(nikoHomeControlBridge, timeZoneProvider); } @Override diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler2.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler2.java index 4e86d9b2b7..b5ad23707c 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler2.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler2.java @@ -24,6 +24,7 @@ import java.util.NoSuchElementException; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.nikohomecontrol.internal.protocol.nhc2.NikoHomeControlCommunication2; +import org.openhab.core.i18n.TimeZoneProvider; import org.openhab.core.net.NetworkAddressService; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ThingStatus; @@ -50,8 +51,9 @@ public class NikoHomeControlBridgeHandler2 extends NikoHomeControlBridgeHandler NetworkAddressService networkAddressService; - public NikoHomeControlBridgeHandler2(Bridge nikoHomeControlBridge, NetworkAddressService networkAddressService) { - super(nikoHomeControlBridge); + public NikoHomeControlBridgeHandler2(Bridge nikoHomeControlBridge, NetworkAddressService networkAddressService, + TimeZoneProvider timeZoneProvider) { + super(nikoHomeControlBridge, timeZoneProvider); this.networkAddressService = networkAddressService; } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlThermostatHandler.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlThermostatHandler.java index 20ce7d59cc..d545026b3b 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlThermostatHandler.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlThermostatHandler.java @@ -13,16 +13,16 @@ package org.openhab.binding.nikohomecontrol.internal.handler; import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindingConstants.*; +import static org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlConstants.*; import static org.openhab.core.library.unit.SIUnits.CELSIUS; import static org.openhab.core.types.RefreshType.REFRESH; +import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import javax.measure.quantity.Temperature; - import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.nikohomecontrol.internal.protocol.NhcThermostat; @@ -31,6 +31,7 @@ import org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlComm import org.openhab.binding.nikohomecontrol.internal.protocol.nhc2.NhcThermostat2; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StringType; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; @@ -105,33 +106,39 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement switch (channelUID.getId()) { case CHANNEL_MEASURED: case CHANNEL_DEMAND: + case CHANNEL_HEATING_DEMAND: updateStatus(ThingStatus.ONLINE); break; - case CHANNEL_MODE: if (command instanceof DecimalType) { nhcThermostat.executeMode(((DecimalType) command).intValue()); } updateStatus(ThingStatus.ONLINE); break; - + case CHANNEL_HEATING_MODE: + if (command instanceof StringType) { + nhcThermostat.executeMode(command.toString()); + } + updateStatus(ThingStatus.ONLINE); + break; case CHANNEL_SETPOINT: - QuantityType setpoint = null; - if (command instanceof QuantityType) { - setpoint = ((QuantityType) command).toUnit(CELSIUS); - // Always set the new setpoint temperature as an overrule - // If no overrule time is given yet, set the overrule time to the configuration parameter - int time = nhcThermostat.getOverruletime(); - if (time <= 0) { - time = overruleTime; - } + // Always set the new setpoint temperature as an overrule + // If no overrule time is given yet, set the overrule time to the configuration parameter + int time = nhcThermostat.getOverruletime(); + if (time <= 0) { + time = overruleTime; + } + if (command instanceof QuantityType) { + QuantityType setpoint = ((QuantityType) command).toUnit(CELSIUS); if (setpoint != null) { nhcThermostat.executeOverrule(Math.round(setpoint.floatValue() * 10), time); } + } else if (command instanceof DecimalType) { + BigDecimal setpoint = ((DecimalType) command).toBigDecimal(); + nhcThermostat.executeOverrule(Math.round(setpoint.floatValue() * 10), time); } updateStatus(ThingStatus.ONLINE); break; - case CHANNEL_OVERRULETIME: if (command instanceof DecimalType) { int overruletime = ((DecimalType) command).intValue(); @@ -255,7 +262,7 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement return; } - updateState(CHANNEL_MEASURED, new QuantityType<>(nhcThermostat.getMeasured() / 10.0, CELSIUS)); + updateState(CHANNEL_MEASURED, new QuantityType<>(measured / 10.0, CELSIUS)); int overruletime = nhcThermostat.getRemainingOverruletime(); updateState(CHANNEL_OVERRULETIME, new DecimalType(overruletime)); @@ -271,8 +278,10 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement } updateState(CHANNEL_MODE, new DecimalType(mode)); + updateState(CHANNEL_HEATING_MODE, new StringType(THERMOSTATMODES[mode])); updateState(CHANNEL_DEMAND, new DecimalType(demand)); + updateState(CHANNEL_HEATING_DEMAND, new StringType(THERMOSTATDEMAND[Math.abs(demand) <= 1 ? (demand + 1) : 0])); updateStatus(ThingStatus.ONLINE); } @@ -286,14 +295,14 @@ public class NikoHomeControlThermostatHandler extends BaseThingHandler implement private void scheduleRefreshOverruletime(NhcThermostat nhcThermostat) { cancelRefreshTimer(); - if (nhcThermostat.getRemainingOverruletime() <= 0) { + if (nhcThermostat.getRemainingOverruletime() == 0) { return; } refreshTimer = scheduler.scheduleWithFixedDelay(() -> { int remainingTime = nhcThermostat.getRemainingOverruletime(); updateState(CHANNEL_OVERRULETIME, new DecimalType(remainingTime)); - if (remainingTime <= 0) { + if (remainingTime == 0) { cancelRefreshTimer(); } }, 1, 1, TimeUnit.MINUTES); diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcControllerEvent.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcControllerEvent.java index ed6bee7b31..ecdd98f93f 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcControllerEvent.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcControllerEvent.java @@ -13,6 +13,7 @@ package org.openhab.binding.nikohomecontrol.internal.protocol; import java.net.InetAddress; +import java.time.ZoneId; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -64,6 +65,13 @@ public interface NhcControllerEvent { return ""; } + /** + * Get the time zone ID of the Niko Home Control system. + * + * @return the zone ID + */ + public ZoneId getTimeZone(); + /** * Called to indicate the connection with the Niko Home Control Controller is offline. * diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcEnergyMeter.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcEnergyMeter.java index 46f12673e8..ef049bebfe 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcEnergyMeter.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcEnergyMeter.java @@ -20,10 +20,8 @@ import org.slf4j.LoggerFactory; /** * The {@link NhcEnergyMeter} class represents the energyMeters metering Niko Home Control communication object. It - * contains all - * fields representing a Niko Home Control energyMeters meter and has methods to receive energyMeters usage information. - * A specific - * implementation is {@link NhcEnergyMeter2}. + * contains all fields representing a Niko Home Control energyMeters meter and has methods to receive energyMeters usage + * information. A specific implementation is {@link NhcEnergyMeter2}. * * @author Mark Herwege - Initial Contribution */ diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcThermostat.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcThermostat.java index afae188b4b..46fae6ce51 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcThermostat.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcThermostat.java @@ -12,8 +12,12 @@ */ package org.openhab.binding.nikohomecontrol.internal.protocol; +import static org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlConstants.THERMOSTATMODES; + import java.time.LocalDateTime; +import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; +import java.util.Arrays; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -47,7 +51,7 @@ public abstract class NhcThermostat { protected volatile int ecosave; protected volatile int demand; - private @Nullable LocalDateTime overruleStart; + private @Nullable volatile ZonedDateTime overruleStart; private @Nullable NhcThermostatEvent eventHandler; @@ -84,33 +88,6 @@ public abstract class NhcThermostat { updateChannels(); } - /** - * Update overrule values of the thermostat without touching the thermostat definition (id, name and location) and - * without changing the ThingHandler callback. - * - * @param overrule the overrule temperature in 0.1°C multiples - * @param overruletime in minutes - */ - public void updateState(int overrule, int overruletime) { - setOverrule(overrule); - setOverruletime(overruletime); - - updateChannels(); - } - - /** - * Update overrule values of the thermostat without touching the thermostat definition (id, name and location) and - * without changing the ThingHandler callback. - * - * @param overrule the overrule temperature in 0.1°C multiples - * @param overruletime in minutes - */ - public void updateState(int mode) { - setMode(mode); - - updateChannels(); - } - /** * Method called when thermostat is removed from the Niko Home Control Controller. */ @@ -249,6 +226,9 @@ public abstract class NhcThermostat { private void setOverrule(int overrule) { this.overrule = overrule; + if (overrule <= 0) { + stopOverrule(); + } } /** @@ -266,12 +246,14 @@ public abstract class NhcThermostat { * @param overruletime the overruletime in minutes */ private void setOverruletime(int overruletime) { - if (overruletime <= 0) { - stopOverrule(); - } else if (overruletime != this.overruletime) { - startOverrule(); + if (overruletime != this.overruletime) { + if (overruletime <= 0) { + stopOverrule(); + } else { + startOverrule(); + } + this.overruletime = overruletime; } - this.overruletime = overruletime; } /** @@ -289,7 +271,7 @@ public abstract class NhcThermostat { } /** - * @return the heating/cooling demand: 0 if no demand, >0 if heating, <0 if cooling + * @return the heating/cooling demand: 0 if no demand, 1 if heating, -1 if cooling */ public int getDemand() { return demand; @@ -310,6 +292,20 @@ public abstract class NhcThermostat { */ public abstract void executeMode(int mode); + /** + * Sends thermostat mode to Niko Home Control. + * + * @param mode allowed values are Day, Night, Eco, Off, Cool, Prog1, Prog2, Prog3 + */ + public void executeMode(String mode) { + int intMode = Arrays.asList(THERMOSTATMODES).indexOf(mode); + if (intMode < 0) { // if not recognized, default to Day + intMode = 0; + logger.debug("Thermostat mode {} not recognized, default to Day mode", mode); + } + executeMode(intMode); + }; + /** * Sends thermostat setpoint to Niko Home Control. This method is implemented in {@link NhcThermostat1} and * {@link NhcThermostat2}. @@ -320,22 +316,24 @@ public abstract class NhcThermostat { public abstract void executeOverrule(int overrule, int overruletime); /** - * @return remaining overrule time in minutes + * @return remaining overrule time in minutes, 0 or positive */ public int getRemainingOverruletime() { - if (overruleStart == null) { - return 0; - } else { + int remainingTime = 0; + if (overruleStart != null) { // overruletime time max 23h59min, therefore can safely cast to int - return overruletime - (int) ChronoUnit.MINUTES.between(overruleStart, LocalDateTime.now()); + remainingTime = Math.max(0, overruletime - (int) ChronoUnit.MINUTES.between(overruleStart, + LocalDateTime.now().atZone(nhcComm.getTimeZone()))); } + logger.trace("Getting remaining overrule time, remaining: {}", remainingTime); + return remainingTime; } /** * Start a new overrule, this method is used to be able to calculate the remaining overrule time */ private void startOverrule() { - overruleStart = LocalDateTime.now(); + overruleStart = LocalDateTime.now().atZone(nhcComm.getTimeZone()); } /** @@ -343,5 +341,7 @@ public abstract class NhcThermostat { */ private void stopOverrule() { overruleStart = null; + overruletime = 0; + overrule = 0; } } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlCommunication.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlCommunication.java index 22793b69db..d34d6f6f7e 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlCommunication.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlCommunication.java @@ -12,6 +12,7 @@ */ package org.openhab.binding.nikohomecontrol.internal.protocol; +import java.time.ZoneId; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; @@ -54,7 +55,7 @@ public abstract class NikoHomeControlCommunication { // restart attempts private volatile int delay = 0; private volatile int attempt = 0; - protected @Nullable ScheduledFuture scheduledRestart = null; + protected volatile @Nullable ScheduledFuture scheduledRestart = null; protected NikoHomeControlCommunication(NhcControllerEvent handler, ScheduledExecutorService scheduler) { this.handler = handler; @@ -137,6 +138,15 @@ public abstract class NikoHomeControlCommunication { */ public abstract boolean communicationActive(); + /** + * Return the timezone for the system. + * + * @return zoneId + */ + public ZoneId getTimeZone() { + return handler.getTimeZone(); + } + /** * Return all actions in the Niko Home Control Controller. * diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlConstants.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlConstants.java index f3fcf34dc7..0ca53a35cd 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlConstants.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlConstants.java @@ -47,4 +47,5 @@ public class NikoHomeControlConstants { // NhcII thermostat modes public static final String[] THERMOSTATMODES = { "Day", "Night", "Eco", "Off", "Cool", "Prog1", "Prog2", "Prog3" }; + public static final String[] THERMOSTATDEMAND = { "Cooling", "None", "Heating" }; } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java index 1bd6636a62..785c841243 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java @@ -569,11 +569,11 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication int measured = ambientTemperatureProperty.orElse(thermostat.getMeasured()); int setpoint = setpointTemperatureProperty.orElse(thermostat.getSetpoint()); - int overrule = thermostat.getOverrule(); - int overruletime = thermostat.getRemainingOverruletime(); - if (overruleActiveProperty.orElse(false)) { - overrule = overruleSetpointProperty.orElse(0); - overruletime = overruleTimeProperty.orElse(0); + int overrule = 0; + int overruletime = 0; + if (overruleActiveProperty.orElse(true)) { + overrule = overruleSetpointProperty.orElse(thermostat.getOverrule()); + overruletime = overruleTimeProperty.orElse(thermostat.getRemainingOverruletime()); } int ecosave = thermostat.getEcosave(); @@ -618,7 +618,7 @@ public class NikoHomeControlCommunication2 extends NikoHomeControlCommunication energyMeter.setPower(power); } catch (NumberFormatException e) { energyMeter.setPower(null); - logger.trace("received empty energy meter {} power reading", energyMeter.getId()); + logger.trace("wrong format in energy meter {} power reading", energyMeter.getId()); } } diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/i18n/nikohomecontrol.properties b/bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/i18n/nikohomecontrol.properties index 1cf24a8902..7c1f12cd35 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/i18n/nikohomecontrol.properties +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/i18n/nikohomecontrol.properties @@ -83,14 +83,20 @@ channelOverruletimeDescription = Time duration for overruling thermostat target channelModeLabel = Mode channelModeDescription = Thermostat mode -channelModeOption0 = day -channelModeOption1 = night -channelModeOption2 = eco -channelModeOption3 = off -channelModeOption4 = cool -channelModeOption5 = prog 1 -channelModeOption6 = prog 2 -channelModeOption7 = prog 3 +channelModeOption0 = Day +channelModeOption1 = Night +channelModeOption2 = Eco +channelModeOption3 = Off +channelModeOption4 = Cool +channelModeOption5 = Program 1 +channelModeOption6 = Program 2 +channelModeOption7 = Program 3 + +channelDemandLabel = Demand +channelDemandDescription = Heating/cooling demand +channelDemand-1 = Cooling +channelDemand0 = None +channelDemand1 = Heating channelPowerLabel = Power channelPowerDescription = Momentary power consumption/production (positive is consumption) diff --git a/bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/thing/thing-types.xml index 90af051350..a7c3ae1444 100644 --- a/bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/thing/thing-types.xml @@ -161,13 +161,16 @@ - - @text/ThermostatDescription + + @text/thermostatDescription + + + @@ -244,11 +247,27 @@ Number - + + String + + @text/channelModeDescription + + + + + + + + + + + + + + Number @text/channelModeDescription - Number @@ -262,6 +281,31 @@ + + String + + @text/channelDemandDescription + + + + + + + + + + Number + + @text/channelDemandDescription + + + + + + + + + Number:Power -- 2.47.3