]> git.basschouten.com Git - openhab-addons.git/blob
d7da59f8b55dc83050fdca983f8de1badc79e795
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.nikohomecontrol.internal.protocol;
14
15 import static org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlConstants.THERMOSTATMODES;
16
17 import java.time.LocalDateTime;
18 import java.time.ZonedDateTime;
19 import java.time.temporal.ChronoUnit;
20 import java.util.Arrays;
21
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;
28
29 /**
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}.
33  *
34  * @author Mark Herwege - Initial Contribution
35  */
36 @NonNullByDefault
37 public abstract class NhcThermostat {
38
39     private final Logger logger = LoggerFactory.getLogger(NhcThermostat.class);
40
41     protected NikoHomeControlCommunication nhcComm;
42
43     protected String id;
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;
53
54     private @Nullable volatile ZonedDateTime overruleStart;
55
56     private @Nullable NhcThermostatEvent eventHandler;
57
58     protected NhcThermostat(String id, String name, @Nullable String location, NikoHomeControlCommunication nhcComm) {
59         this.id = id;
60         this.name = name;
61         this.location = location;
62         this.nhcComm = nhcComm;
63     }
64
65     /**
66      * Update all values of the thermostat without touching the thermostat definition (id, name and location) and
67      * without changing the ThingHandler callback.
68      *
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 =
72      *            prog3
73      * @param overrule the overrule temperature in 0.1°C multiples
74      * @param overruletime in minutes
75      * @param ecosave
76      * @param demand 0 if no demand, > 0 if heating, < 0 if cooling
77      */
78     public void updateState(int measured, int setpoint, int mode, int overrule, int overruletime, int ecosave,
79             int demand) {
80         setMeasured(measured);
81         setSetpoint(setpoint);
82         setMode(mode);
83         setOverrule(overrule);
84         setOverruletime(overruletime);
85         setEcosave(ecosave);
86         setDemand(demand);
87
88         updateChannels();
89     }
90
91     /**
92      * Method called when thermostat is removed from the Niko Home Control Controller.
93      */
94     public void thermostatRemoved() {
95         logger.debug("action removed {}, {}", id, name);
96         NhcThermostatEvent eventHandler = this.eventHandler;
97         if (eventHandler != null) {
98             eventHandler.thermostatRemoved();
99             unsetEventHandler();
100         }
101     }
102
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);
108         }
109     }
110
111     /**
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.
115      *
116      * @param eventHandler
117      */
118     public void setEventHandler(NhcThermostatEvent eventHandler) {
119         this.eventHandler = eventHandler;
120     }
121
122     /**
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.
125      *
126      */
127     public void unsetEventHandler() {
128         this.eventHandler = null;
129     }
130
131     /**
132      * Get id of the thermostat.
133      *
134      * @return id
135      */
136     public String getId() {
137         return id;
138     }
139
140     /**
141      * Get name of thermostat.
142      *
143      * @return thermostat name
144      */
145     public String getName() {
146         return name;
147     }
148
149     /**
150      * Set name of thermostat.
151      *
152      * @param name thermostat name
153      */
154     public void setName(String name) {
155         this.name = name;
156     }
157
158     /**
159      * Get location name of thermostat.
160      *
161      * @return location name
162      */
163     public @Nullable String getLocation() {
164         return location;
165     }
166
167     /**
168      * Set location name of thermostat.
169      *
170      * @param location thermostat location name
171      */
172     public void setLocation(@Nullable String location) {
173         this.location = location;
174     }
175
176     /**
177      * Get measured temperature.
178      *
179      * @return measured temperature in 0.1°C multiples
180      */
181     public int getMeasured() {
182         return measured;
183     }
184
185     private void setMeasured(int measured) {
186         this.measured = measured;
187     }
188
189     /**
190      * @return the setpoint temperature in 0.1°C multiples
191      */
192     public int getSetpoint() {
193         return setpoint;
194     }
195
196     private void setSetpoint(int setpoint) {
197         this.setpoint = setpoint;
198     }
199
200     /**
201      * Get the thermostat mode.
202      *
203      * @return the mode:
204      *         0 = day, 1 = night, 2 = eco, 3 = off, 4 = cool, 5 = prog 1, 6 = prog 2, 7 = prog 3
205      */
206     public int getMode() {
207         return mode;
208     }
209
210     private void setMode(int mode) {
211         this.mode = mode;
212     }
213
214     /**
215      * Get the overrule temperature.
216      *
217      * @return the overrule temperature in 0.1°C multiples
218      */
219     public int getOverrule() {
220         if (overrule > 0) {
221             return overrule;
222         } else {
223             return setpoint;
224         }
225     }
226
227     private void setOverrule(int overrule) {
228         this.overrule = overrule;
229         if (overrule <= 0) {
230             stopOverrule();
231         }
232     }
233
234     /**
235      * Get the duration for an overrule temperature
236      *
237      * @return the overruletime in minutes
238      */
239     public int getOverruletime() {
240         return overruletime;
241     }
242
243     /**
244      * Set the duration for an overrule temperature
245      *
246      * @param overruletime the overruletime in minutes
247      */
248     private void setOverruletime(int overruletime) {
249         if (overruletime != this.overruletime) {
250             if (overruletime <= 0) {
251                 stopOverrule();
252             } else {
253                 startOverrule();
254             }
255             this.overruletime = overruletime;
256         }
257     }
258
259     /**
260      * @return the ecosave mode
261      */
262     public int getEcosave() {
263         return ecosave;
264     }
265
266     /**
267      * @param ecosave the ecosave mode to set
268      */
269     private void setEcosave(int ecosave) {
270         this.ecosave = ecosave;
271     }
272
273     /**
274      * @return the heating/cooling demand: 0 if no demand, 1 if heating, -1 if cooling
275      */
276     public int getDemand() {
277         return demand;
278     }
279
280     /**
281      * @param demand set the heating/cooling demand
282      */
283     private void setDemand(int demand) {
284         this.demand = demand;
285     }
286
287     /**
288      * Sends thermostat mode to Niko Home Control. This method is implemented in {@link NhcThermostat1} and
289      * {@link NhcThermostat2}.
290      *
291      * @param mode
292      */
293     public abstract void executeMode(int mode);
294
295     /**
296      * Sends thermostat mode to Niko Home Control.
297      *
298      * @param mode allowed values are Day, Night, Eco, Off, Cool, Prog1, Prog2, Prog3
299      */
300     public void executeMode(String mode) {
301         int intMode = Arrays.asList(THERMOSTATMODES).indexOf(mode);
302         if (intMode < 0) { // if not recognized, default to Day
303             intMode = 0;
304             logger.debug("Thermostat mode {} not recognized, default to Day mode", mode);
305         }
306         executeMode(intMode);
307     }
308
309     /**
310      * Sends thermostat setpoint to Niko Home Control. This method is implemented in {@link NhcThermostat1} and
311      * {@link NhcThermostat2}.
312      *
313      * @param overrule temperature to overrule the setpoint in 0.1°C multiples
314      * @param overruletime time duration in min for overrule
315      */
316     public abstract void executeOverrule(int overrule, int overruletime);
317
318     /**
319      * @return remaining overrule time in minutes, 0 or positive
320      */
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())));
327         }
328         logger.trace("Getting remaining overrule time, remaining: {}", remainingTime);
329         return remainingTime;
330     }
331
332     /**
333      * Start a new overrule, this method is used to be able to calculate the remaining overrule time
334      */
335     private void startOverrule() {
336         overruleStart = LocalDateTime.now().atZone(nhcComm.getTimeZone());
337     }
338
339     /**
340      * Reset overrule start
341      */
342     private void stopOverrule() {
343         overruleStart = null;
344         overruletime = 0;
345         overrule = 0;
346     }
347 }