2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.nikohomecontrol.internal.protocol;
15 import static org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlConstants.THERMOSTATMODES;
17 import java.time.LocalDateTime;
18 import java.time.ZonedDateTime;
19 import java.time.temporal.ChronoUnit;
20 import java.util.Arrays;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.nikohomecontrol.internal.protocol.nhc1.NhcThermostat1;
25 import org.openhab.binding.nikohomecontrol.internal.protocol.nhc2.NhcThermostat2;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
30 * The {@link NhcThermostat} class represents the thermostat Niko Home Control communication object. It contains all
31 * fields representing a Niko Home Control thermostat and has methods to set the thermostat in Niko Home Control and
32 * receive thermostat updates. Specific implementation are {@link NhcThermostat1} and {@link NhcThermostat2}.
34 * @author Mark Herwege - Initial Contribution
37 public abstract class NhcThermostat {
39 private final Logger logger = LoggerFactory.getLogger(NhcThermostat.class);
41 protected NikoHomeControlCommunication nhcComm;
44 protected String name;
45 protected @Nullable String location;
46 protected volatile int measured;
47 protected volatile int setpoint;
48 protected volatile int mode;
49 protected volatile int overrule;
50 protected volatile int overruletime;
51 protected volatile int ecosave;
52 protected volatile int demand;
54 private @Nullable volatile ZonedDateTime overruleStart;
56 private @Nullable NhcThermostatEvent eventHandler;
58 protected NhcThermostat(String id, String name, @Nullable String location, NikoHomeControlCommunication nhcComm) {
61 this.location = location;
62 this.nhcComm = nhcComm;
66 * Update all values of the thermostat without touching the thermostat definition (id, name and location) and
67 * without changing the ThingHandler callback.
69 * @param measured current temperature in 0.1°C multiples
70 * @param setpoint the setpoint temperature in 0.1°C multiples
71 * @param mode thermostat mode 0 = day, 1 = night, 2 = eco, 3 = off, 4 = cool, 5 = prog1, 6 = prog2, 7 =
73 * @param overrule the overrule temperature in 0.1°C multiples
74 * @param overruletime in minutes
76 * @param demand 0 if no demand, > 0 if heating, < 0 if cooling
78 public void updateState(int measured, int setpoint, int mode, int overrule, int overruletime, int ecosave,
80 setMeasured(measured);
81 setSetpoint(setpoint);
83 setOverrule(overrule);
84 setOverruletime(overruletime);
92 * Method called when thermostat is removed from the Niko Home Control Controller.
94 public void thermostatRemoved() {
95 logger.debug("action removed {}, {}", id, name);
96 NhcThermostatEvent eventHandler = this.eventHandler;
97 if (eventHandler != null) {
98 eventHandler.thermostatRemoved();
103 private void updateChannels() {
104 NhcThermostatEvent handler = eventHandler;
105 if (handler != null) {
106 logger.debug("update channels for {}", id);
107 handler.thermostatEvent(measured, setpoint, mode, overrule, demand);
112 * This method should be called when an object implementing the {@link NhcThermostatEvent} interface is initialized.
113 * It keeps a record of the event handler in that object so it can be updated when the action receives an update
114 * from the Niko Home Control IP-interface.
116 * @param eventHandler
118 public void setEventHandler(NhcThermostatEvent eventHandler) {
119 this.eventHandler = eventHandler;
123 * This method should be called when an object implementing the {@link NhcThermostatEvent} interface is disposed.
124 * It resets the reference, so no updates go to the handler anymore.
127 public void unsetEventHandler() {
128 this.eventHandler = null;
132 * Get id of the thermostat.
136 public String getId() {
141 * Get name of thermostat.
143 * @return thermostat name
145 public String getName() {
150 * Set name of thermostat.
152 * @param name thermostat name
154 public void setName(String name) {
159 * Get location name of thermostat.
161 * @return location name
163 public @Nullable String getLocation() {
168 * Set location name of thermostat.
170 * @param location thermostat location name
172 public void setLocation(@Nullable String location) {
173 this.location = location;
177 * Get measured temperature.
179 * @return measured temperature in 0.1°C multiples
181 public int getMeasured() {
185 private void setMeasured(int measured) {
186 this.measured = measured;
190 * @return the setpoint temperature in 0.1°C multiples
192 public int getSetpoint() {
196 private void setSetpoint(int setpoint) {
197 this.setpoint = setpoint;
201 * Get the thermostat mode.
204 * 0 = day, 1 = night, 2 = eco, 3 = off, 4 = cool, 5 = prog 1, 6 = prog 2, 7 = prog 3
206 public int getMode() {
210 private void setMode(int mode) {
215 * Get the overrule temperature.
217 * @return the overrule temperature in 0.1°C multiples
219 public int getOverrule() {
227 private void setOverrule(int overrule) {
228 this.overrule = overrule;
235 * Get the duration for an overrule temperature
237 * @return the overruletime in minutes
239 public int getOverruletime() {
244 * Set the duration for an overrule temperature
246 * @param overruletime the overruletime in minutes
248 private void setOverruletime(int overruletime) {
249 if (overruletime != this.overruletime) {
250 if (overruletime <= 0) {
255 this.overruletime = overruletime;
260 * @return the ecosave mode
262 public int getEcosave() {
267 * @param ecosave the ecosave mode to set
269 private void setEcosave(int ecosave) {
270 this.ecosave = ecosave;
274 * @return the heating/cooling demand: 0 if no demand, 1 if heating, -1 if cooling
276 public int getDemand() {
281 * @param demand set the heating/cooling demand
283 private void setDemand(int demand) {
284 this.demand = demand;
288 * Sends thermostat mode to Niko Home Control. This method is implemented in {@link NhcThermostat1} and
289 * {@link NhcThermostat2}.
293 public abstract void executeMode(int mode);
296 * Sends thermostat mode to Niko Home Control.
298 * @param mode allowed values are Day, Night, Eco, Off, Cool, Prog1, Prog2, Prog3
300 public void executeMode(String mode) {
301 int intMode = Arrays.asList(THERMOSTATMODES).indexOf(mode);
302 if (intMode < 0) { // if not recognized, default to Day
304 logger.debug("Thermostat mode {} not recognized, default to Day mode", mode);
306 executeMode(intMode);
310 * Sends thermostat setpoint to Niko Home Control. This method is implemented in {@link NhcThermostat1} and
311 * {@link NhcThermostat2}.
313 * @param overrule temperature to overrule the setpoint in 0.1°C multiples
314 * @param overruletime time duration in min for overrule
316 public abstract void executeOverrule(int overrule, int overruletime);
319 * @return remaining overrule time in minutes, 0 or positive
321 public int getRemainingOverruletime() {
322 int remainingTime = 0;
323 if (overruleStart != null) {
324 // overruletime time max 23h59min, therefore can safely cast to int
325 remainingTime = Math.max(0, overruletime - (int) ChronoUnit.MINUTES.between(overruleStart,
326 LocalDateTime.now().atZone(nhcComm.getTimeZone())));
328 logger.trace("Getting remaining overrule time, remaining: {}", remainingTime);
329 return remainingTime;
333 * Start a new overrule, this method is used to be able to calculate the remaining overrule time
335 private void startOverrule() {
336 overruleStart = LocalDateTime.now().atZone(nhcComm.getTimeZone());
340 * Reset overrule start
342 private void stopOverrule() {
343 overruleStart = null;