]> git.basschouten.com Git - openhab-addons.git/blob
eea101b75443c7850cecd271425190448b20d762
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.ecobee.action;
14
15 import java.lang.reflect.Method;
16 import java.lang.reflect.Proxy;
17 import java.util.Date;
18 import java.util.HashMap;
19 import java.util.Map;
20
21 import javax.measure.quantity.Temperature;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.binding.ecobee.internal.dto.thermostat.EventDTO;
26 import org.openhab.binding.ecobee.internal.enums.AckType;
27 import org.openhab.binding.ecobee.internal.enums.FanMode;
28 import org.openhab.binding.ecobee.internal.enums.HoldType;
29 import org.openhab.binding.ecobee.internal.enums.PlugState;
30 import org.openhab.binding.ecobee.internal.enums.VentilatorMode;
31 import org.openhab.binding.ecobee.internal.function.AcknowledgeFunction;
32 import org.openhab.binding.ecobee.internal.function.ControlPlugFunction;
33 import org.openhab.binding.ecobee.internal.function.CreateVacationFunction;
34 import org.openhab.binding.ecobee.internal.function.DeleteVacationFunction;
35 import org.openhab.binding.ecobee.internal.function.ResetPreferencesFunction;
36 import org.openhab.binding.ecobee.internal.function.ResumeProgramFunction;
37 import org.openhab.binding.ecobee.internal.function.SendMessageFunction;
38 import org.openhab.binding.ecobee.internal.function.SetHoldFunction;
39 import org.openhab.binding.ecobee.internal.function.SetOccupiedFunction;
40 import org.openhab.binding.ecobee.internal.function.UpdateSensorFunction;
41 import org.openhab.binding.ecobee.internal.handler.EcobeeThermostatBridgeHandler;
42 import org.openhab.binding.ecobee.internal.handler.EcobeeUtils;
43 import org.openhab.core.automation.annotation.ActionInput;
44 import org.openhab.core.automation.annotation.ActionOutput;
45 import org.openhab.core.automation.annotation.RuleAction;
46 import org.openhab.core.library.types.QuantityType;
47 import org.openhab.core.thing.binding.ThingActions;
48 import org.openhab.core.thing.binding.ThingActionsScope;
49 import org.openhab.core.thing.binding.ThingHandler;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 /**
54  * The {@link EcobeeActions} defines the thing actions for the Ecobee binding.
55  * <p>
56  * <b>Note:</b>The static method <b>invokeMethod</b> handles the case where
57  * the test <i>actions instanceof EcobeeActions</i> fails. This test can fail
58  * due to an issue in openHAB core v2.5.0 where the {@link EcobeeActions} class
59  * can be loaded by a different classloader than the <i>actions</i> instance.
60  *
61  * @author John Cocula - Initial contribution
62  * @author Mark Hilbush - Adapted for OH2/3
63  * @author Connor Petty - Proxy method for invoking actions
64  */
65 @ThingActionsScope(name = "ecobee")
66 @NonNullByDefault
67 public class EcobeeActions implements ThingActions, IEcobeeActions {
68
69     private static final Logger LOGGER = LoggerFactory.getLogger(EcobeeActions.class);
70
71     private @Nullable EcobeeThermostatBridgeHandler handler;
72
73     public EcobeeActions() {
74         LOGGER.debug("EcobeeActions: EcobeeActions: Actions service created");
75     }
76
77     @Override
78     public void setThingHandler(@Nullable ThingHandler handler) {
79         if (handler instanceof EcobeeThermostatBridgeHandler) {
80             this.handler = (EcobeeThermostatBridgeHandler) handler;
81         }
82     }
83
84     @Override
85     public @Nullable ThingHandler getThingHandler() {
86         return this.handler;
87     }
88
89     private static IEcobeeActions invokeMethodOf(@Nullable ThingActions actions) {
90         if (actions == null) {
91             throw new IllegalArgumentException("actions cannot be null");
92         }
93         if (actions.getClass().getName().equals(EcobeeActions.class.getName())) {
94             if (actions instanceof IEcobeeActions) {
95                 return (IEcobeeActions) actions;
96             } else {
97                 return (IEcobeeActions) Proxy.newProxyInstance(IEcobeeActions.class.getClassLoader(),
98                         new Class[] { IEcobeeActions.class }, (Object proxy, Method method, Object[] args) -> {
99                             Method m = actions.getClass().getDeclaredMethod(method.getName(),
100                                     method.getParameterTypes());
101                             return m.invoke(actions, args);
102                         });
103             }
104         }
105         throw new IllegalArgumentException("Actions is not an instance of EcobeeActions");
106     }
107
108     /**
109      * The acknowledge function allows an alert to be acknowledged.
110      *
111      * @see <a
112      *      href="https://www.ecobee.com/home/developer/api/documentation/v1/functions/Acknowledge.shtml">Acknowledge
113      *      </a>
114      */
115     @Override
116     @RuleAction(label = "Acknowledge", description = "Acknowledges an alert.")
117     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean acknowledge(
118             @ActionInput(name = "ackRef", description = "The acknowledge ref of alert") @Nullable String ackRef,
119             @ActionInput(name = "ackType", description = "The type of acknowledgement. Valid values: accept, decline, defer, unacknowledged") @Nullable String ackType,
120             @ActionInput(name = "remindMeLater", description = "(opt) Whether to remind at a later date, if this is a defer acknowledgement") @Nullable Boolean remindMeLater) {
121         LOGGER.debug("EcobeeActions: Action 'Acknowledge' called");
122         EcobeeThermostatBridgeHandler localHandler = handler;
123         if (localHandler == null) {
124             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
125             return false;
126         }
127         AcknowledgeFunction function = new AcknowledgeFunction(localHandler.getThermostatId(), ackRef,
128                 AckType.forValue(ackType), remindMeLater);
129         return localHandler.actionPerformFunction(function);
130     }
131
132     public static boolean acknowledge(@Nullable ThingActions actions, @Nullable String ackRef, @Nullable String ackType,
133             @Nullable Boolean remindMeLater) {
134         return invokeMethodOf(actions).acknowledge(ackRef, ackType, remindMeLater);
135     }
136
137     /**
138      * Control the on/off state of a plug by setting a hold on the plug.
139      *
140      * @see <a href="https://www.ecobee.com/home/developer/api/documentation/v1/functions/ControlPlug.shtml">Control
141      *      Plug</a>
142      */
143     @Override
144     @RuleAction(label = "Control Plug", description = "Control the on/off state of a plug by setting a hold on the plug.")
145     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean controlPlug(
146             @ActionInput(name = "plugName", description = "The name of the plug. Ensure each plug has a unique name.") @Nullable String plugName,
147             @ActionInput(name = "plugState", description = "The state to put the plug into. Valid values: on, off, resume.") @Nullable String plugState,
148             @ActionInput(name = "startDateTime", description = "(opt) The start date/time in thermostat time.") @Nullable Date startDateTime,
149             @ActionInput(name = "endDateTime", description = "(opt) The end date/time in thermostat time.") @Nullable Date endDateTime,
150             @ActionInput(name = "holdType", description = "(opt) The hold duration type. Valid values: dateTime, nextTransition, indefinite, holdHours.") @Nullable String holdType,
151             @ActionInput(name = "holdHours", description = "(opt) The number of hours to hold for, used and required if holdType='holdHours'.") @Nullable Number holdHours) {
152         LOGGER.debug("EcobeeActions: Action 'Control Plug' called");
153         EcobeeThermostatBridgeHandler localHandler = handler;
154         if (localHandler == null) {
155             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
156             return false;
157         }
158         ControlPlugFunction function = (new ControlPlugFunction(plugName, PlugState.forValue(plugState), startDateTime,
159                 endDateTime, (holdType == null) ? null : HoldType.forValue(holdType),
160                 (holdHours == null) ? null : Integer.valueOf(holdHours.intValue())));
161         return localHandler.actionPerformFunction(function);
162     }
163
164     public static boolean controlPlug(@Nullable ThingActions actions, @Nullable String plugName,
165             @Nullable String plugState, @Nullable Date startDateTime, @Nullable Date endDateTime,
166             @Nullable String holdType, @Nullable Number holdHours) {
167         return invokeMethodOf(actions).controlPlug(plugName, plugState, startDateTime, endDateTime, holdType,
168                 holdHours);
169     }
170
171     /**
172      * The create vacation function creates a vacation event on the thermostat.
173      *
174      * @see <a href="https://www.ecobee.com/home/developer/api/documentation/v1/functions/CreateVacation.shtml">Create
175      *      Vacation</a>
176      */
177     @Override
178     @RuleAction(label = "Create Vacation", description = "The create vacation function creates a vacation event on the thermostat.")
179     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean createVacation(
180             @ActionInput(name = "name", description = "The vacation event name. It must be unique.") @Nullable String name,
181             @ActionInput(name = "coolHoldTemp", description = "The temperature at which to set the cool vacation hold.") @Nullable QuantityType<Temperature> coolHoldTemp,
182             @ActionInput(name = "heatHoldTemp", description = "The temperature at which to set the heat vacation hold.") @Nullable QuantityType<Temperature> heatHoldTemp,
183             @ActionInput(name = "startDateTime", description = "(opt) The start date/time in thermostat time.") @Nullable Date startDateTime,
184             @ActionInput(name = "endDateTime", description = "(opt) The end date in thermostat time.") @Nullable Date endDateTime,
185             @ActionInput(name = "fan", description = "(opt) The fan mode during the vacation. Values: auto, on Default: auto") @Nullable String fan,
186             @ActionInput(name = "fanMinOnTime", description = "(opt) The minimum number of minutes to run the fan each hour. Range: 0-60, Default: 0") @Nullable Number fanMinOnTime) {
187         LOGGER.debug("EcobeeActions: Action 'Create Vacation' called");
188         EcobeeThermostatBridgeHandler localHandler = handler;
189         if (localHandler == null) {
190             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
191             return false;
192         }
193         CreateVacationFunction function = new CreateVacationFunction(name, coolHoldTemp, heatHoldTemp, startDateTime,
194                 endDateTime, (fan == null) ? null : FanMode.forValue(fan),
195                 (fanMinOnTime == null) ? null : Integer.valueOf(fanMinOnTime.intValue()));
196         return localHandler.actionPerformFunction(function);
197     }
198
199     public static boolean createVacation(@Nullable ThingActions actions, @Nullable String name,
200             @Nullable QuantityType<Temperature> coolHoldTemp, @Nullable QuantityType<Temperature> heatHoldTemp,
201             @Nullable Date startDateTime, @Nullable Date endDateTime, @Nullable String fan,
202             @Nullable Number fanMinOnTime) {
203         return invokeMethodOf(actions).createVacation(name, coolHoldTemp, heatHoldTemp, startDateTime, endDateTime, fan,
204                 fanMinOnTime);
205     }
206
207     /**
208      * The delete vacation function deletes a vacation event from a thermostat.
209      *
210      * @see <a href="https://www.ecobee.com/home/developer/api/documentation/v1/functions/DeleteVacation.shtml">Delete
211      *      Vacation</a>
212      */
213     @Override
214     @RuleAction(label = "Delete Vacation", description = "The delete vacation function deletes a vacation event from a thermostat.")
215     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean deleteVacation(
216             @ActionInput(name = "name", description = "The vacation event name to delete.") @Nullable String name) {
217         LOGGER.debug("EcobeeActions: Action 'Delete Vacation' called");
218         EcobeeThermostatBridgeHandler localHandler = handler;
219         if (localHandler == null) {
220             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
221             return false;
222         }
223         DeleteVacationFunction function = new DeleteVacationFunction(name);
224         return localHandler.actionPerformFunction(function);
225     }
226
227     public static boolean deleteVacation(@Nullable ThingActions actions, @Nullable String name) {
228         return invokeMethodOf(actions).deleteVacation(name);
229     }
230
231     /**
232      * The reset preferences function sets all of the user configurable settings back to the factory default values.
233      *
234      * @see <a href="https://www.ecobee.com/home/developer/api/documentation/v1/functions/ResetPreferences.shtml">Reset
235      *      Preferences</a>
236      */
237     @Override
238     @RuleAction(label = "Reset Preferences", description = "The reset preferences function sets all of the user configurable settings back to the factory default values.")
239     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean resetPreferences() {
240         LOGGER.debug("EcobeeActions: Action 'Reset Preferences' called");
241         EcobeeThermostatBridgeHandler localHandler = handler;
242         if (localHandler == null) {
243             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
244             return false;
245         }
246         ResetPreferencesFunction function = new ResetPreferencesFunction();
247         return localHandler.actionPerformFunction(function);
248     }
249
250     public static boolean resetPreferences(@Nullable ThingActions actions) {
251         return invokeMethodOf(actions).resetPreferences();
252     }
253
254     /**
255      * The resume program function removes the currently running event.
256      *
257      * @see <a href="https://www.ecobee.com/home/developer/api/documentation/v1/functions/ResumeProgram.shtml">Resume
258      *      Program</a>
259      */
260     @Override
261     @RuleAction(label = "Resume Program", description = "Removes the currently running event providing the event is not a mandatory demand response event")
262     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean resumeProgram(
263             @ActionInput(name = "resumeAll", description = "(opt) Should the thermostat be resumed to next event (false) or to its program (true)") @Nullable Boolean resumeAll) {
264         LOGGER.debug("EcobeeActions: Action 'Resume Program' called");
265         EcobeeThermostatBridgeHandler localHandler = handler;
266         if (localHandler == null) {
267             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
268             return false;
269         }
270         ResumeProgramFunction function = new ResumeProgramFunction(resumeAll);
271         return localHandler.actionPerformFunction(function);
272     }
273
274     public static boolean resumeProgram(@Nullable ThingActions actions, @Nullable Boolean resumeAll) {
275         return invokeMethodOf(actions).resumeProgram(resumeAll);
276     }
277
278     /**
279      * The send message function allows an alert message to be sent to the thermostat.
280      *
281      * @see <a href="https://www.ecobee.com/home/developer/api/documentation/v1/functions/SendMessage.shtml">Send
282      *      Message</a>
283      */
284     @Override
285     @RuleAction(label = "Send Message", description = "The send message function allows an alert message to be sent to the thermostat.")
286     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean sendMessage(
287             @ActionInput(name = "text", description = "The message text to send. Text will be truncated to 500 characters if longer") @Nullable String text) {
288         LOGGER.debug("EcobeeActions: Action 'SendMessage' called");
289         EcobeeThermostatBridgeHandler localHandler = handler;
290         if (localHandler == null) {
291             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
292             return false;
293         }
294         SendMessageFunction function = new SendMessageFunction(text);
295         return localHandler.actionPerformFunction(function);
296     }
297
298     public static boolean sendMessage(@Nullable ThingActions actions, @Nullable String text) {
299         return invokeMethodOf(actions).sendMessage(text);
300     }
301
302     /**
303      * Set an indefinite hold using the supplied the cool and heat hold temperatures
304      *
305      * @see <a href="https://www.ecobee.com/home/developer/api/documentation/v1/functions/SetHold.shtml">Set Hold</a>
306      */
307     @Override
308     @RuleAction(label = "Set Hold", description = "The set hold function sets the thermostat into a hold with the specified temperatures.")
309     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean setHold(
310             @ActionInput(name = "coolHoldTemp", description = "The temperature at which to set the cool hold.") @Nullable QuantityType<Temperature> coolHoldTemp,
311             @ActionInput(name = "heatHoldTemp", description = "The temperature at which to set the heat hold.") @Nullable QuantityType<Temperature> heatHoldTemp) {
312         if (coolHoldTemp == null || heatHoldTemp == null) {
313             throw new IllegalArgumentException("hold temperatures cannot be null");
314         }
315         Map<String, Object> params = new HashMap<String, Object>();
316         params.put("coolHoldTemp", coolHoldTemp);
317         params.put("heatHoldTemp", heatHoldTemp);
318         return setHold(params, null, null, null, null);
319     }
320
321     public static boolean setHold(@Nullable ThingActions actions, @Nullable QuantityType<Temperature> coolHoldTemp,
322             @Nullable QuantityType<Temperature> heatHoldTemp) {
323         return invokeMethodOf(actions).setHold(coolHoldTemp, heatHoldTemp);
324     }
325
326     /**
327      * Set a hold by providing the cool and heat temperatures and the number of hours.
328      */
329     @Override
330     @RuleAction(label = "Set Hold", description = "The set hold function sets the thermostat into a hold for the specified number of hours.")
331     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean setHold(
332             @ActionInput(name = "coolHoldTemp", description = "The temperature at which to set the cool hold.") @Nullable QuantityType<Temperature> coolHoldTemp,
333             @ActionInput(name = "heatHoldTemp", description = "The temperature at which to set the heat hold.") @Nullable QuantityType<Temperature> heatHoldTemp,
334             @ActionInput(name = "holdHours", description = "The number of hours for the hold.") @Nullable Number holdHours) {
335         if (coolHoldTemp == null || heatHoldTemp == null) {
336             throw new IllegalArgumentException("hold temperatures cannot be null");
337         }
338         if (holdHours == null) {
339             throw new IllegalArgumentException("number of hold hours is missing");
340         }
341         Map<String, Object> params = new HashMap<String, Object>();
342         params.put("coolHoldTemp", coolHoldTemp);
343         params.put("heatHoldTemp", heatHoldTemp);
344         params.put("holdType", HoldType.HOLD_HOURS);
345         params.put("holdHours", Integer.valueOf(holdHours.intValue()));
346         return setHold(params, null, null, null, null);
347     }
348
349     public static boolean setHold(@Nullable ThingActions actions, @Nullable QuantityType<Temperature> coolHoldTemp,
350             @Nullable QuantityType<Temperature> heatHoldTemp, @Nullable Number holdHours) {
351         return invokeMethodOf(actions).setHold(coolHoldTemp, heatHoldTemp, holdHours);
352     }
353
354     /**
355      * Set an indefinite hold using the supplied climateRef
356      */
357     @Override
358     @RuleAction(label = "Set Hold", description = "The set hold function sets the thermostat into a hold with the specified climate ref.")
359     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean setHold(
360             @ActionInput(name = "holdClimateRef", description = "The holdClimateRef used to set the hold.") @Nullable String holdClimateRef) {
361         EcobeeThermostatBridgeHandler localHandler = handler;
362         if (localHandler == null) {
363             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
364             return false;
365         }
366         if (holdClimateRef == null || !localHandler.isValidClimateRef(holdClimateRef)) {
367             throw new IllegalArgumentException("hold climate ref is missing or invalid");
368         }
369         Map<String, Object> params = new HashMap<String, Object>();
370         params.put("holdClimateRef", holdClimateRef);
371         return setHold(params, null, null, null, null);
372     }
373
374     public static boolean setHold(@Nullable ThingActions actions, @Nullable String holdClimateRef) {
375         return invokeMethodOf(actions).setHold(holdClimateRef);
376     }
377
378     /**
379      * Set a hold using the supplied climateRef for the supplied number of hours.
380      */
381     @Override
382     @RuleAction(label = "Set Hold", description = "The set hold function sets the thermostat into a hold with the specified climate ref.")
383     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean setHold(
384             @ActionInput(name = "holdClimateRef", description = "The holdClimateRef used to set the hold.") @Nullable String holdClimateRef,
385             @ActionInput(name = "holdHours", description = "The number of hours for the hold.") @Nullable Number holdHours) {
386         if (holdHours == null) {
387             throw new IllegalArgumentException("number of hold hours is missing");
388         }
389         EcobeeThermostatBridgeHandler localHandler = handler;
390         if (localHandler == null) {
391             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
392             return false;
393         }
394         if (holdClimateRef == null || !localHandler.isValidClimateRef(holdClimateRef)) {
395             throw new IllegalArgumentException("hold climate ref is missing or invalid");
396         }
397         Map<String, Object> params = new HashMap<String, Object>();
398         params.put("holdClimateRef", holdClimateRef);
399         params.put("holdType", HoldType.HOLD_HOURS);
400         params.put("holdHours", Integer.valueOf(holdHours.intValue()));
401         return setHold(params, null, null, null, null);
402     }
403
404     public static boolean setHold(@Nullable ThingActions actions, @Nullable String holdClimateRef,
405             @Nullable Number holdHours) {
406         return invokeMethodOf(actions).setHold(holdClimateRef, holdHours);
407     }
408
409     /**
410      * Set a hold
411      */
412     @Override
413     @RuleAction(label = "Set Hold", description = "The set hold function sets the thermostat into a hold with the specified temperature or climate ref.")
414     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean setHold(
415             @ActionInput(name = "coolHoldTemp", description = "(opt) The temperature at which to set the cool hold.") @Nullable QuantityType<Temperature> coolHoldTemp,
416             @ActionInput(name = "heatHoldTemp", description = "(opt) The temperature at which to set the heat hold.") @Nullable QuantityType<Temperature> heatHoldTemp,
417             @ActionInput(name = "holdClimateRef", description = "(opt) The Climate to use as reference for setting the coolHoldTemp, heatHoldTemp and fan settings for this hold. If this value is passed the coolHoldTemp and heatHoldTemp are not required.") @Nullable String holdClimateRef,
418             @ActionInput(name = "startDateTime", description = "(opt) The start date in thermostat time.") @Nullable Date startDateTime,
419             @ActionInput(name = "endDateTime", description = "(opt) The end date in thermostat time.") @Nullable Date endDateTime,
420             @ActionInput(name = "holdType", description = "(opt) The hold duration type. Valid values: dateTime, nextTransition, indefinite, holdHours.") @Nullable String holdType,
421             @ActionInput(name = "holdHours", description = "(opt) The number of hours to hold for, used and required if holdType='holdHours'.") @Nullable Number holdHours) {
422         Map<String, Object> params = new HashMap<String, Object>();
423         if (coolHoldTemp != null) {
424             params.put("coolHoldTemp", coolHoldTemp);
425         }
426         if (heatHoldTemp != null) {
427             params.put("heatHoldTemp", heatHoldTemp);
428         }
429         if (holdClimateRef != null) {
430             params.put("holdClimateRef", holdClimateRef);
431         }
432         return setHold(params, holdType, holdHours, startDateTime, endDateTime);
433     }
434
435     public static boolean setHold(@Nullable ThingActions actions, @Nullable QuantityType<Temperature> coolHoldTemp,
436             @Nullable QuantityType<Temperature> heatHoldTemp, @Nullable String holdClimateRef,
437             @Nullable Date startDateTime, @Nullable Date endDateTime, @Nullable String holdType,
438             @Nullable Number holdHours) {
439         return invokeMethodOf(actions).setHold(coolHoldTemp, heatHoldTemp, holdClimateRef, startDateTime, endDateTime,
440                 holdType, holdHours);
441     }
442
443     /**
444      * Set a hold by providing a parameter map
445      */
446     @Override
447     @RuleAction(label = "Set Hold", description = "The set hold function sets the thermostat into a hold with the specified event parameters.")
448     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean setHold(
449             @ActionInput(name = "params", description = "The map of hold parameters.") @Nullable Map<String, Object> params,
450             @ActionInput(name = "holdType", description = "(opt) The hold duration type. Valid values: dateTime, nextTransition, indefinite, holdHours.") @Nullable String holdType,
451             @ActionInput(name = "holdHours", description = "(opt) The number of hours to hold for, used and required if holdType='holdHours'.") @Nullable Number holdHours,
452             @ActionInput(name = "startDateTime", description = "(opt) The start date in thermostat time.") @Nullable Date startDateTime,
453             @ActionInput(name = "endDateTime", description = "(opt) The end date in thermostat time.") @Nullable Date endDateTime) {
454         LOGGER.debug("EcobeeActions: Action 'SetHold' called");
455         if (params == null) {
456             throw new IllegalArgumentException("params cannot be null");
457         }
458         EventDTO event = new EventDTO();
459         for (String key : params.keySet()) {
460             Object value = params.get(key);
461             switch (key) {
462                 case "isOccupied":
463                     event.isOccupied = ((Boolean) value);
464                     break;
465                 case "isCoolOff":
466                     event.isCoolOff = ((Boolean) value);
467                     break;
468                 case "isHeatOff":
469                     event.isHeatOff = ((Boolean) value);
470                     break;
471                 case "coolHoldTemp":
472                     event.coolHoldTemp = EcobeeUtils.convertQuantityTypeToEcobeeTemp(value);
473                     break;
474                 case "heatHoldTemp":
475                     event.heatHoldTemp = EcobeeUtils.convertQuantityTypeToEcobeeTemp(value);
476                     break;
477                 case "fan":
478                     event.fan = FanMode.forValue((String) value).toString();
479                     break;
480                 case "vent":
481                     event.vent = VentilatorMode.forValue((String) value).toString();
482                     break;
483                 case "ventilatorMinOnTime":
484                     event.ventilatorMinOnTime = ((Integer) value);
485                     break;
486                 case "isOptional":
487                     event.isOptional = ((Boolean) value);
488                     break;
489                 case "isTemperatureRelative":
490                     event.isTemperatureRelative = ((Boolean) value);
491                     break;
492                 case "coolRelativeTemp":
493                     event.coolRelativeTemp = EcobeeUtils.convertQuantityTypeToEcobeeTemp(value);
494                     break;
495                 case "heatRelativeTemp":
496                     event.heatRelativeTemp = EcobeeUtils.convertQuantityTypeToEcobeeTemp(value);
497                     break;
498                 case "isTemperatureAbsolute":
499                     event.isTemperatureAbsolute = ((Boolean) value);
500                     break;
501                 case "fanMinOnTime":
502                     event.fanMinOnTime = ((Integer) value);
503                     break;
504                 case "holdClimateRef":
505                     event.holdClimateRef = ((String) value);
506                     break;
507                 default:
508                     LOGGER.warn("Unrecognized event field '{}' with value '{}' ignored.", key, value);
509                     break;
510             }
511         }
512         EcobeeThermostatBridgeHandler localHandler = handler;
513         if (localHandler == null) {
514             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
515             return false;
516         }
517         SetHoldFunction function = new SetHoldFunction(event, (holdType == null) ? null : HoldType.forValue(holdType),
518                 (holdHours == null) ? null : holdHours.intValue(), startDateTime, endDateTime);
519         return localHandler.actionPerformFunction(function);
520     }
521
522     public static boolean setHold(@Nullable ThingActions actions, @Nullable Map<String, Object> params,
523             @Nullable String holdType, @Nullable Number holdHours, @Nullable Date startDateTime,
524             @Nullable Date endDateTime) {
525         return invokeMethodOf(actions).setHold(params, holdType, holdHours, startDateTime, endDateTime);
526     }
527
528     /**
529      * The set occupied function may only be used by EMS thermostats. The function switches a thermostat from occupied
530      * mode to unoccupied, or vice versa.
531      *
532      * @see <a href="https://www.ecobee.com/home/developer/api/documentation/v1/functions/SetOccupied.shtml">Set
533      *      Occupied</a>
534      */
535     @Override
536     @RuleAction(label = "Set Occupied", description = "The function switches a thermostat from occupied mode to unoccupied, or vice versa (EMS MODELS ONLY).")
537     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean setOccupied(
538             @ActionInput(name = "occupied", description = "The climate to use for the temperature, occupied (true) or unoccupied (false).") @Nullable Boolean occupied,
539             @ActionInput(name = "startDateTime", description = "(opt) The start date in thermostat time.") @Nullable Date startDateTime,
540             @ActionInput(name = "endDateTime", description = "(opt) The end date in thermostat time.") @Nullable Date endDateTime,
541             @ActionInput(name = "holdType", description = "(opt) The hold duration type. Valid values: dateTime, nextTransition, indefinite, holdHours.") @Nullable String holdType,
542             @ActionInput(name = "holdHours", description = "(opt) The number of hours to hold for, used and required if holdType='holdHours'.") @Nullable Number holdHours) {
543         LOGGER.debug("EcobeeActions: Action 'Set Occupied' called");
544         EcobeeThermostatBridgeHandler localHandler = handler;
545         if (localHandler == null) {
546             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
547             return false;
548         }
549         SetOccupiedFunction function = new SetOccupiedFunction(occupied, startDateTime, endDateTime,
550                 (holdType == null) ? null : HoldType.forValue(holdType),
551                 (holdHours == null) ? null : Integer.valueOf(holdHours.intValue()));
552         return localHandler.actionPerformFunction(function);
553     }
554
555     public static boolean setOccupied(@Nullable ThingActions actions, @Nullable Boolean occupied,
556             @Nullable Date startDateTime, @Nullable Date endDateTime, @Nullable String holdType,
557             @Nullable Number holdHours) {
558         return invokeMethodOf(actions).setOccupied(occupied, startDateTime, endDateTime, holdType, holdHours);
559     }
560
561     /**
562      * The update sensor function allows the caller to update the name of an ecobee3 remote sensor.
563      *
564      * @see <a href="https://www.ecobee.com/home/developer/api/documentation/v1/functions/UpdateSensor.shtml">Update
565      *      Sensor</a>
566      */
567     @Override
568     @RuleAction(label = "Update Sensor", description = "The update sensor function allows the caller to update the name of an ecobee3 remote sensor.")
569     public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean updateSensor(
570             @ActionInput(name = "name", description = "The updated name to give the sensor. Has a max length of 32, but shorter is recommended.") @Nullable String name,
571             @ActionInput(name = "deviceId", description = "The deviceId for the sensor, typically this indicates the enclosure and corresponds to the ThermostatRemoteSensor.id field. For example: rs:100") @Nullable String deviceId,
572             @ActionInput(name = "sensorId", description = "The identifier for the sensor within the enclosure. Corresponds to the RemoteSensorCapability.id. For example: 1") @Nullable String sensorId) {
573         LOGGER.debug("EcobeeActions: Action 'UpdateSensor' called");
574         EcobeeThermostatBridgeHandler localHandler = handler;
575         if (localHandler == null) {
576             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
577             return false;
578         }
579         UpdateSensorFunction function = new UpdateSensorFunction(name, deviceId, sensorId);
580         return localHandler.actionPerformFunction(function);
581     }
582
583     public static boolean updateSensor(@Nullable ThingActions actions, @Nullable String name, @Nullable String deviceId,
584             @Nullable String sensorId) {
585         return invokeMethodOf(actions).updateSensor(name, deviceId, sensorId);
586     }
587
588     /**
589      * Get the alerts list. Returns a JSON string containing all the alerts.
590      */
591     @Override
592     @RuleAction(label = "Get Alerts", description = "Get the alerts list")
593     public @ActionOutput(name = "alerts", type = "java.lang.String") @Nullable String getAlerts() {
594         LOGGER.debug("EcobeeActions: Action 'Get Alerts' called");
595         EcobeeThermostatBridgeHandler localHandler = handler;
596         if (localHandler == null) {
597             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
598             return null;
599         }
600         return localHandler.getAlerts();
601     }
602
603     public static @Nullable String getAlerts(@Nullable ThingActions actions) {
604         return invokeMethodOf(actions).getAlerts();
605     }
606
607     /**
608      * Get the events list. Returns a JSON string contains all events.
609      */
610     @Override
611     @RuleAction(label = "Get Events", description = "Get the events list")
612     public @ActionOutput(name = "events", type = "java.lang.String") @Nullable String getEvents() {
613         LOGGER.debug("EcobeeActions: Action 'Get Events' called");
614         EcobeeThermostatBridgeHandler localHandler = handler;
615         if (localHandler == null) {
616             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
617             return null;
618         }
619         return localHandler.getEvents();
620     }
621
622     public static @Nullable String getEvents(@Nullable ThingActions actions) {
623         return invokeMethodOf(actions).getEvents();
624     }
625
626     /**
627      * Get a list of climates. Returns a JSON string contains all climates.
628      */
629     @Override
630     @RuleAction(label = "Get Climates", description = "Get a list of climates")
631     public @ActionOutput(name = "climates", type = "java.lang.String") @Nullable String getClimates() {
632         LOGGER.debug("EcobeeActions: Action 'Get Climates' called");
633         EcobeeThermostatBridgeHandler localHandler = handler;
634         if (localHandler == null) {
635             LOGGER.info("EcobeeActions: Action service ThingHandler is null!");
636             return null;
637         }
638         return localHandler.getClimates();
639     }
640
641     public static @Nullable String getClimates(@Nullable ThingActions actions) {
642         return invokeMethodOf(actions).getClimates();
643     }
644 }