]> git.basschouten.com Git - openhab-addons.git/commitdiff
[nikohomecontrol] Bug fixes and improvements to thermostats (#11963)
authorMark Herwege <mherwege@users.noreply.github.com>
Wed, 15 Jun 2022 11:01:22 +0000 (13:01 +0200)
committerGitHub <noreply@github.com>
Wed, 15 Jun 2022 11:01:22 +0000 (13:01 +0200)
* Thermostat fixes and implement extra thermostat channels

Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
15 files changed:
bundles/org.openhab.binding.nikohomecontrol/README.md
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlBindingConstants.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/NikoHomeControlHandlerFactory.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler1.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlBridgeHandler2.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/handler/NikoHomeControlThermostatHandler.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcControllerEvent.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcEnergyMeter.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NhcThermostat.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlCommunication.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/NikoHomeControlConstants.java
bundles/org.openhab.binding.nikohomecontrol/src/main/java/org/openhab/binding/nikohomecontrol/internal/protocol/nhc2/NikoHomeControlCommunication2.java
bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/i18n/nikohomecontrol.properties
bundles/org.openhab.binding.nikohomecontrol/src/main/resources/OH-INF/thing/thing-types.xml

index 45c6ab6279f6adca6c4acc2de147052b9334751b..185a8e0c912403cd630f36ec1087f7becd0ac1e6 100644 (file)
@@ -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<Temperature>, 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<Temperature>.
+`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<Temperature>.
 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
index 17922fee545726b535de12beb4af0c4cd963c533..7b43c23f45e810b9d57a27d0d12a6a70538c000e 100644 (file)
@@ -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";
 
index fda292a180adba667bbd51cafc897ff2befdd21d..ad45b6953d99fa74ff9c05746a24c5dccf807260 100644 (file)
@@ -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;
-    }
 }
index 65b29eed699ad29d66aaa6146da3acdc5461c68a..deb9103e03e8bb4ce687386da116e6b6ff8a2f62 100644 (file)
@@ -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<Class<? extends ThingHandlerService>> getServices() {
         return Set.of(NikoHomeControlDiscoveryService.class);
index 958681befa1b530cb2aa2b6138a10027412ab0cf..95e2451de305b4004f8e68b1dfec3489732bc0f5 100644 (file)
@@ -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
index 4e86d9b2b7be6f94085c4ebeb069583c2889b4ea..b5ad23707cca572871aa11a325958a62d852e9bf 100644 (file)
@@ -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;
     }
 
index 20ce7d59ccb5c187e9b6c4874b7da55aaedea521..d545026b3bca75596a05bf8d61c2f262f420628c 100644 (file)
 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<Temperature> setpoint = null;
-                if (command instanceof QuantityType) {
-                    setpoint = ((QuantityType<Temperature>) 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);
index ed6bee7b31627b95225d466f0d5134ab4596be1b..ecdd98f93fbdd8da6736bf08c8fa1f38392f085e 100644 (file)
@@ -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.
      *
index 46f12673e8eae2d6ed5725a74409638244300ab6..ef049bebfe6b3048e78b8db2dd5c149cc4022073 100644 (file)
@@ -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
  */
index afae188b4bcfdf867cbec4d3530f892ca8a17735..46fae6ce51544f4612ad1c49d616031416788391 100644 (file)
  */
 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;
     }
 }
index 22793b69db4c66c2e0aa59fdc392a254d6eac41f..d34d6f6f7e76707fdcdfd1499fc0f70404b5596f 100644 (file)
@@ -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.
      *
index f3fcf34dc715f62682c6b72dbcf5b92d1a6e1d46..0ca53a35cd7688a8fdd3bf96ea401cda44bd4593 100644 (file)
@@ -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" };
 }
index 1bd6636a62054bdd4981a9e1d77e01d857ab638d..785c841243e79b62d6534a839072ca1d53de20a3 100644 (file)
@@ -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());
         }
     }
 
index 1cf24a89022a752ee5190bcc971cf1a8589b29f8..7c1f12cd35349c4048be54b40b801693920be8c1 100644 (file)
@@ -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)
index 90af05135016e20f1e83f19451c0777ed9e74bdb..a7c3ae1444579a015614738d442861dd1c262a3f 100644 (file)
                        <bridge-type-ref id="bridge"/>
                        <bridge-type-ref id="bridge2"/>
                </supported-bridge-type-refs>
-               <label>@text/ThermostatLabel</label>
-               <description>@text/ThermostatDescription</description>
+               <label>@text/thermostatLabel</label>
+               <description>@text/thermostatDescription</description>
                <channels>
                        <channel id="measured" typeId="measured"/>
+                       <channel id="heatingmode" typeId="heatingmode"/>
                        <channel id="mode" typeId="mode"/>
                        <channel id="setpoint" typeId="setpoint"/>
                        <channel id="overruletime" typeId="overruletime"/>
+                       <channel id="heatingdemand" typeId="heatingdemand"/>
+                       <channel id="demand" typeId="demand"/>
                </channels>
                <config-description>
                        <parameter name="thermostatId" type="text" required="true">
                <category>Number</category>
                <state min="0" max="1440" step="5"/>
        </channel-type>
-       <channel-type id="mode">
+       <channel-type id="heatingmode">
+               <item-type>String</item-type>
+               <label>@text/channelModeLabel</label>
+               <description>@text/channelModeDescription</description>
+               <state>
+                       <options>
+                               <option value="Day">@text/channelModeOption0</option>
+                               <option value="Night">@text/channelModeOption1</option>
+                               <option value="Eco">@text/channelModeOption2</option>
+                               <option value="Off">@text/channelModeOption3</option>
+                               <option value="Cool">@text/channelModeOption4</option>
+                               <option value="Prog1">@text/channelModeOption5</option>
+                               <option value="Prog2">@text/channelModeOption6</option>
+                               <option value="Prog3">@text/channelModeOption7</option>
+                       </options>
+               </state>
+       </channel-type>
+       <channel-type id="mode" advanced="true">
                <item-type>Number</item-type>
                <label>@text/channelModeLabel</label>
                <description>@text/channelModeDescription</description>
-               <category>Number</category>
                <state>
                        <options>
                                <option value="0">@text/channelModeOption0</option>
                        </options>
                </state>
        </channel-type>
+       <channel-type id="heatingdemand">
+               <item-type>String</item-type>
+               <label>@text/channelDemandLabel</label>
+               <description>@text/channelDemandDescription</description>
+               <state readOnly="true">
+                       <options>
+                               <option value="Cooling">@text/channelDemand-1</option>
+                               <option value="None">@text/channelDemand0</option>
+                               <option value="Heating">@text/channelDemand1</option>
+                       </options>
+               </state>
+       </channel-type>
+       <channel-type id="demand" advanced="true">
+               <item-type>Number</item-type>
+               <label>@text/channelDemandLabel</label>
+               <description>@text/channelDemandDescription</description>
+               <state readOnly="true">
+                       <options>
+                               <option value="-1">@text/channelDemand-1</option>
+                               <option value="0">@text/channelDemand0</option>
+                               <option value="1">@text/channelDemand1</option>
+                       </options>
+               </state>
+       </channel-type>
+
        <channel-type id="power">
                <item-type>Number:Power</item-type>
                <label>@text/channelPowerLabel</label>