]> git.basschouten.com Git - openhab-addons.git/blob
3dbe29f068f26d2a05caaed7036dcc56b866b059
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.velux.internal;
14
15 import java.util.ArrayList;
16 import java.util.List;
17
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.openhab.core.items.GenericItem;
20 import org.openhab.core.library.items.NumberItem;
21 import org.openhab.core.library.items.RollershutterItem;
22 import org.openhab.core.library.items.StringItem;
23 import org.openhab.core.library.items.SwitchItem;
24 import org.openhab.core.thing.ThingTypeUID;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 /**
29  * Enumeration of Types of a Velux item.
30  * <br>
31  * Provides information about:
32  * <ul>
33  * <li>associated thing identified by String</li>
34  * <li>defined channel identified by String</li>
35  * <li>{@link #getItemClass} item class,</li>
36  * <li>{@link #isReadable} about a read possibility,</li>
37  * <li>{@link #isWritable} about a write possibility,</li>
38  * <li>{@link #isExecutable} about an execute possibility,</li>
39  * <li>{@link #isToBeRefreshed} about necessarily to be refreshed,</li>
40  * <li>{@link #isToBeRefreshedNow} about necessarily to be refreshed at this time,</li>
41  * <li>{@link #isChannel} as indication of being handled as Channel of a thing,</li>
42  * <li>{@link #isProperty} as indication of being handled as property of a thing.</li>
43  * </ul>
44  *
45  * In addition there are helper methods providing information about:
46  *
47  * <ul>
48  * <li>{@link #getIdentifier} returning the common identifier string,</li>
49  * <li>{@link #getByThingAndChannel} to retrieve an enum instance selected by Thing
50  * and Channel identifier,</li>
51  * <li>{@link #getPropertyEntriesByThing} to retrieve any Thing identifiers as array of
52  * String,</li>
53  * </ul>
54  * <p>
55  * Within this enumeration, the expected behaviour of the OpenHAB item (resp. Channel or Property) is set. For each kind
56  * of Channel (i.e. bridge or device) parameter a set of information is defined:
57  * <ul>
58  * <li>
59  * Unique identification by:
60  * <ul>
61  * <li>Thing name as string,</li>
62  * <li>Channel name as string,</li>
63  * </ul>
64  * </li>
65  * <li>Channel type as OpenHAB type,</li>
66  * <li>ability flag whether this item is to be read,</li>
67  * <li>ability flag whether this item is able to be modified,</li>
68  * <li>ability flag whether this item is to be used as execution trigger.</li>
69  * </ul>
70  *
71  * @author Guenther Schreiner - Initial contribution
72  *
73  */
74 @NonNullByDefault
75 public enum VeluxItemType {
76     // @formatter:off
77     UNKNOWN(VeluxBindingConstants.THING_TYPE_BRIDGE,                            VeluxBindingConstants.UNKNOWN,                       TypeFlavor.UNUSABLE),
78     //
79     BINDING_INFORMATION(VeluxBindingConstants.THING_TYPE_BINDING,               VeluxBindingConstants.CHANNEL_BINDING_INFORMATION,   TypeFlavor.READONLY_VOLATILE_STRING),
80     //
81     BRIDGE_STATUS(VeluxBindingConstants.THING_TYPE_BRIDGE,                      VeluxBindingConstants.CHANNEL_BRIDGE_STATUS,         TypeFlavor.READONLY_VOLATILE_STRING),
82     BRIDGE_DOWNTIME(VeluxBindingConstants.THING_TYPE_BRIDGE,                    VeluxBindingConstants.CHANNEL_BRIDGE_DOWNTIME,       TypeFlavor.READONLY_VOLATILE_NUMBER),
83     BRIDGE_RELOAD(VeluxBindingConstants.THING_TYPE_BRIDGE,                      VeluxBindingConstants.CHANNEL_BRIDGE_RELOAD,         TypeFlavor.INITIATOR),
84     BRIDGE_DO_DETECTION(VeluxBindingConstants.THING_TYPE_BRIDGE,                VeluxBindingConstants.CHANNEL_BRIDGE_DO_DETECTION,   TypeFlavor.INITIATOR),
85
86     BRIDGE_FIRMWARE(VeluxBindingConstants.THING_TYPE_BRIDGE,                    VeluxBindingConstants.PROPERTY_BRIDGE_FIRMWARE,      TypeFlavor.PROPERTY),
87     BRIDGE_ADDRESS(VeluxBindingConstants.THING_TYPE_BRIDGE,                     VeluxBindingConstants.PROPERTY_BRIDGE_ADDRESS,       TypeFlavor.PROPERTY),
88     BRIDGE_SUBNETMASK(VeluxBindingConstants.THING_TYPE_BRIDGE,                  VeluxBindingConstants.PROPERTY_BRIDGE_SUBNETMASK,    TypeFlavor.PROPERTY),
89     BRIDGE_DEFAULTGW(VeluxBindingConstants.THING_TYPE_BRIDGE,                   VeluxBindingConstants.PROPERTY_BRIDGE_DEFAULTGW,     TypeFlavor.PROPERTY),
90     BRIDGE_DHCP(VeluxBindingConstants.THING_TYPE_BRIDGE,                        VeluxBindingConstants.PROPERTY_BRIDGE_DHCP,          TypeFlavor.PROPERTY),
91     BRIDGE_WLANSSID(VeluxBindingConstants.THING_TYPE_BRIDGE,                    VeluxBindingConstants.PROPERTY_BRIDGE_WLANSSID,      TypeFlavor.PROPERTY),
92     BRIDGE_WLANPASSWORD(VeluxBindingConstants.THING_TYPE_BRIDGE,                VeluxBindingConstants.PROPERTY_BRIDGE_WLANPASSWORD,  TypeFlavor.PROPERTY),
93     BRIDGE_PRODUCTS(VeluxBindingConstants.THING_TYPE_BRIDGE,                    VeluxBindingConstants.PROPERTY_BRIDGE_PRODUCTS,      TypeFlavor.PROPERTY),
94     BRIDGE_SCENES(VeluxBindingConstants.THING_TYPE_BRIDGE,                      VeluxBindingConstants.PROPERTY_BRIDGE_SCENES,        TypeFlavor.PROPERTY),
95     BRIDGE_CHECK(VeluxBindingConstants.THING_TYPE_BRIDGE,                       VeluxBindingConstants.PROPERTY_BRIDGE_CHECK,         TypeFlavor.PROPERTY),
96     //
97     ACTUATOR_POSITION(VeluxBindingConstants.THING_TYPE_VELUX_ACTUATOR,          VeluxBindingConstants.CHANNEL_ACTUATOR_POSITION,     TypeFlavor.MANIPULATOR_SHUTTER),
98     ACTUATOR_STATE(VeluxBindingConstants.THING_TYPE_VELUX_ACTUATOR,             VeluxBindingConstants.CHANNEL_ACTUATOR_STATE,        TypeFlavor.MANIPULATOR_SWITCH),
99     ACTUATOR_LIMIT_MINIMUM(VeluxBindingConstants.THING_TYPE_VELUX_ACTUATOR,     VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MINIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
100     ACTUATOR_LIMIT_MAXIMUM(VeluxBindingConstants.THING_TYPE_VELUX_ACTUATOR,     VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MAXIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
101     //
102     ROLLERSHUTTER_POSITION(VeluxBindingConstants.THING_TYPE_VELUX_ROLLERSHUTTER,VeluxBindingConstants.CHANNEL_ACTUATOR_POSITION,     TypeFlavor.MANIPULATOR_SHUTTER),
103     ROLLERSHUTTER_LIMIT_MINIMUM(VeluxBindingConstants.THING_TYPE_VELUX_ROLLERSHUTTER,VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MINIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
104     ROLLERSHUTTER_LIMIT_MAXIMUM(VeluxBindingConstants.THING_TYPE_VELUX_ROLLERSHUTTER,VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MAXIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
105     ROLLERSHUTTER_VANE_POSITION(VeluxBindingConstants.THING_TYPE_VELUX_ROLLERSHUTTER,VeluxBindingConstants.CHANNEL_VANE_POSITION,    TypeFlavor.MANIPULATOR_SHUTTER),
106     //
107     WINDOW_POSITION(VeluxBindingConstants.THING_TYPE_VELUX_WINDOW,              VeluxBindingConstants.CHANNEL_ACTUATOR_POSITION,     TypeFlavor.MANIPULATOR_SHUTTER),
108     WINDOW_LIMIT_MINIMUM(VeluxBindingConstants.THING_TYPE_VELUX_WINDOW,         VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MINIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
109     WINDOW_LIMIT_MAXIMUM(VeluxBindingConstants.THING_TYPE_VELUX_WINDOW,         VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MAXIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
110     //
111     SCENE_ACTION(VeluxBindingConstants.THING_TYPE_VELUX_SCENE,                  VeluxBindingConstants.CHANNEL_SCENE_ACTION,          TypeFlavor.INITIATOR),
112     SCENE_SILENTMODE(VeluxBindingConstants.THING_TYPE_VELUX_SCENE,              VeluxBindingConstants.CHANNEL_SCENE_SILENTMODE,      TypeFlavor.WRITEONLY_VOLATILE_SWITCH),
113     //
114     VSHUTTER_POSITION(VeluxBindingConstants.THING_TYPE_VELUX_VSHUTTER,          VeluxBindingConstants.CHANNEL_VSHUTTER_POSITION,     TypeFlavor.MANIPULATOR_SHUTTER),
115     ;
116     // @formatter:on
117
118     private enum TypeFlavor {
119         /**
120          * Used to present read-only non-volatile configuration parameters as StringItem.
121          */
122         READONLY_STATIC_STRING,
123         /**
124          * Used to present read-only non-volatile configuration parameters as SwitchItem.
125          */
126         READONLY_STATIC_SWITCH,
127         /**
128          * Used to present volatile configuration parameters as StringItem.
129          */
130         READONLY_VOLATILE_STRING,
131         /**
132          * Used to present volatile configuration parameters as NumberItem.
133          */
134         READONLY_VOLATILE_NUMBER,
135         /**
136          * Used to present volatile configuration parameters as NumberItem.
137          */
138         WRITEONLY_VOLATILE_SWITCH,
139         /**
140          * Used to present volatile configuration parameters as SwitchItem.
141          */
142         READWRITE_VOLATILE_SWITCH,
143         /**
144          * Used to initiate an action.
145          */
146         INITIATOR,
147         /**
148          * Used to manipulate an actuator.
149          */
150         MANIPULATOR_SHUTTER,
151         /**
152          * Used to manipulate an actuator.
153          */
154         MANIPULATOR_SWITCH,
155         /**
156          * Used to present read-only non-volatile configuration parameter (being handled as property of aThing).
157          */
158         PROPERTY,
159         /**
160          * Used to define an UNUSABLE entry.
161          */
162         UNUSABLE,
163     }
164
165     /*
166      * ***************************
167      * ***** Private Objects *****
168      */
169
170     private ThingTypeUID thingIdentifier;
171     private String channelIdentifier;
172     private Class<? extends GenericItem> itemClass;
173     private boolean itemIsReadable;
174     private boolean itemIsWritable;
175     private boolean itemIsExecutable;
176     private boolean itemIsToBeRefreshed;
177     private int itemsRefreshDivider;
178     private boolean itemIsChannel;
179     private boolean itemIsProperty;
180
181     private static final Logger LOGGER = LoggerFactory.getLogger(VeluxItemType.class);
182
183     private static final int REFRESH_CYCLE_FIRST_TIME = 0;
184     private static final int REFRESH_ONCE_A_DAY = 8640;
185     private static final int REFRESH_EACH_HOUR = 360;
186     private static final int REFRESH_EACH_MINUTE = 6;
187     private static final int REFRESH_EVERY_CYCLE = 1;
188
189     /*
190      * ************************
191      * ***** Constructors *****
192      */
193
194     VeluxItemType(ThingTypeUID thingIdentifier, String channelIdentifier, TypeFlavor typeFlavor) {
195         this.thingIdentifier = thingIdentifier;
196         this.channelIdentifier = channelIdentifier;
197         this.itemIsChannel = true;
198         this.itemIsProperty = false;
199         switch (typeFlavor) {
200             case READONLY_STATIC_STRING:
201                 this.itemClass = StringItem.class;
202                 this.itemIsReadable = true;
203                 this.itemIsWritable = false;
204                 this.itemIsExecutable = false;
205                 this.itemIsToBeRefreshed = true;
206                 this.itemsRefreshDivider = REFRESH_ONCE_A_DAY;
207                 break;
208             case READONLY_STATIC_SWITCH:
209                 this.itemClass = SwitchItem.class;
210                 this.itemIsReadable = true;
211                 this.itemIsWritable = false;
212                 this.itemIsExecutable = false;
213                 this.itemIsToBeRefreshed = true;
214                 this.itemsRefreshDivider = REFRESH_ONCE_A_DAY;
215                 break;
216
217             case READONLY_VOLATILE_STRING:
218                 this.itemClass = StringItem.class;
219                 this.itemIsReadable = true;
220                 this.itemIsWritable = false;
221                 this.itemIsExecutable = false;
222                 this.itemIsToBeRefreshed = true;
223                 this.itemsRefreshDivider = REFRESH_EACH_MINUTE;
224                 break;
225             case READONLY_VOLATILE_NUMBER:
226                 this.itemClass = NumberItem.class;
227                 this.itemIsReadable = true;
228                 this.itemIsWritable = false;
229                 this.itemIsExecutable = false;
230                 this.itemIsToBeRefreshed = true;
231                 this.itemsRefreshDivider = REFRESH_EVERY_CYCLE;
232                 break;
233             case WRITEONLY_VOLATILE_SWITCH:
234                 this.itemClass = SwitchItem.class;
235                 this.itemIsReadable = false;
236                 this.itemIsWritable = true;
237                 this.itemIsExecutable = false;
238                 this.itemIsToBeRefreshed = false;
239                 this.itemsRefreshDivider = REFRESH_EACH_MINUTE;
240                 break;
241             case READWRITE_VOLATILE_SWITCH:
242                 this.itemClass = SwitchItem.class;
243                 this.itemIsReadable = true;
244                 this.itemIsWritable = true;
245                 this.itemIsExecutable = false;
246                 this.itemIsToBeRefreshed = true;
247                 this.itemsRefreshDivider = REFRESH_EVERY_CYCLE;
248                 break;
249
250             case INITIATOR:
251                 this.itemClass = SwitchItem.class;
252                 this.itemIsReadable = false;
253                 this.itemIsWritable = false;
254                 this.itemIsExecutable = true;
255                 this.itemIsToBeRefreshed = false;
256                 this.itemsRefreshDivider = 1;
257                 break;
258
259             case MANIPULATOR_SHUTTER:
260                 this.itemClass = RollershutterItem.class;
261                 this.itemIsReadable = true;
262                 this.itemIsWritable = true;
263                 this.itemIsExecutable = false;
264                 this.itemIsToBeRefreshed = true;
265                 this.itemsRefreshDivider = REFRESH_EACH_MINUTE;
266                 break;
267
268             case MANIPULATOR_SWITCH:
269                 this.itemClass = SwitchItem.class;
270                 this.itemIsReadable = true;
271                 this.itemIsWritable = true;
272                 this.itemIsExecutable = false;
273                 this.itemIsToBeRefreshed = true;
274                 this.itemsRefreshDivider = REFRESH_EACH_MINUTE;
275                 break;
276
277             case PROPERTY:
278                 this.itemClass = StringItem.class;
279                 this.itemIsReadable = true;
280                 this.itemIsWritable = false;
281                 this.itemIsExecutable = false;
282                 this.itemIsToBeRefreshed = true;
283                 this.itemsRefreshDivider = REFRESH_EACH_HOUR;
284                 this.itemIsChannel = false;
285                 this.itemIsProperty = true;
286                 break;
287
288             case UNUSABLE:
289             default:
290                 this.itemClass = StringItem.class;
291                 this.itemIsReadable = false;
292                 this.itemIsWritable = false;
293                 this.itemIsExecutable = false;
294                 this.itemIsToBeRefreshed = false;
295                 this.itemsRefreshDivider = REFRESH_ONCE_A_DAY;
296                 this.itemIsChannel = false;
297         }
298     }
299
300     /*
301      * ********************************
302      * ***** Class access methods *****
303      */
304
305     @Override
306     public String toString() {
307         return this.thingIdentifier + "/" + this.channelIdentifier;
308     }
309
310     /**
311      * {@link VeluxItemType} access method to query Identifier on this type of item.
312      *
313      * @return <b>thingIdentifier</b> of type String describing the value of the enum {@link VeluxItemType}
314      *         return
315      */
316     public ThingTypeUID getThingTypeUID() {
317         return this.thingIdentifier;
318     }
319
320     /**
321      * {@link VeluxItemType} access method to query common (channel/property) identifier on this type of item.
322      *
323      * @return <b>channelIdentifier</b> of type String describing the value of the enum {@link VeluxItemType}.
324      */
325     public String getIdentifier() {
326         return this.channelIdentifier;
327     }
328
329     /**
330      * {@link VeluxItemType} access method to query the appropriate type of item.
331      *
332      * @return <b>itemClass</b> of type Item describing the possible type of this item.
333      */
334     public Class<? extends GenericItem> getItemClass() {
335         return this.itemClass;
336     }
337
338     /**
339      * {@link VeluxItemType} access method to query Read possibility on this type of item.
340      *
341      * @return <b>itemIsReadable</b> of type boolean describing the ability to perform a write operation.
342      */
343     public boolean isReadable() {
344         return this.itemIsReadable;
345     }
346
347     /**
348      * {@link VeluxItemType} access method to query Write possibility on this type of item.
349      *
350      * @return <b>itemIsWritable</b> of type boolean describing the ability to perform a write operation.
351      */
352     public boolean isWritable() {
353         return this.itemIsWritable;
354     }
355
356     /**
357      * {@link VeluxItemType} access method to query Execute possibility on this type of item.
358      *
359      * @return <b>isExecute</b> of type boolean describing the ability to perform a write operation.
360      */
361     public boolean isExecutable() {
362         return this.itemIsExecutable;
363     }
364
365     /**
366      * {@link VeluxItemType} access method to query the need of refresh on this type of item.
367      *
368      * @return <b>isExecute</b> of type boolean describing the ability to perform a write operation.
369      */
370     public boolean isToBeRefreshed() {
371         return this.itemIsToBeRefreshed;
372     }
373
374     /**
375      * {@link VeluxItemType} access method to query the refreshMSecs interval on this type of item.
376      *
377      * @return <b>refreshDivider</b> of type int describing the factor.
378      */
379     public int getRefreshDivider() {
380         return this.itemsRefreshDivider;
381     }
382
383     /**
384      * {@link VeluxItemType} access method to query the type of this item.
385      *
386      * @return <b>isChannel</b> of type boolean describing the need to be handled as channel.
387      */
388     public boolean isChannel() {
389         return this.itemIsChannel;
390     }
391
392     /**
393      * {@link VeluxItemType} access method to query the type of this item.
394      *
395      * @return <b>itemIsProperty</b> of type boolean describing the need to be handled as property.
396      */
397     public boolean isProperty() {
398         return this.itemIsProperty;
399     }
400
401     /**
402      * {@link VeluxItemType} access method to find an enum by itemTypeName.
403      *
404      * @param itemTypeName as name of requested Thing of type String.
405      *
406      * @return <b>veluxItemType</b> of type VeluxItemType describing the appropriate enum.
407      */
408     public VeluxItemType getByString(String itemTypeName) {
409         try {
410             return VeluxItemType.valueOf(itemTypeName);
411         } catch (IllegalArgumentException e) {
412             return UNKNOWN;
413         }
414     }
415
416     /**
417      * {@link VeluxItemType} access method to find an enum by name.
418      *
419      * @param thingIdentifier as name of requested Thing of type String.
420      * @param channelIdentifier as name of requested Channel of type String.
421      *
422      * @return <b>veluxItemType</b> of type VeluxItemType describing the appropriate enum.
423      */
424     public static VeluxItemType getByThingAndChannel(ThingTypeUID thingIdentifier, String channelIdentifier) {
425         for (VeluxItemType v : VeluxItemType.values()) {
426             if (thingIdentifier.equals(v.thingIdentifier) && channelIdentifier.equals(v.channelIdentifier)) {
427                 LOGGER.trace("getByThingAndChannel({},{}) returns enum {}.", thingIdentifier, channelIdentifier, v);
428                 return v;
429             }
430         }
431         LOGGER.trace("getByThingAndChannel({},{}) returns enum UNKNOWN.", thingIdentifier, channelIdentifier);
432         return UNKNOWN;
433     }
434
435     /**
436      * {@link VeluxItemType} access method to find similar enum entries by thingIdentifier.
437      *
438      * @param thingIdentifier as name of requested Thing of type String.
439      *
440      * @return <b>listOfveluxItemType</b> of type List of VeluxItemType containing all similar enum entries.
441      */
442     public static List<VeluxItemType> getPropertyEntriesByThing(ThingTypeUID thingIdentifier) {
443         List<VeluxItemType> list = new ArrayList<>();
444         for (VeluxItemType v : VeluxItemType.values()) {
445             if (thingIdentifier.equals(v.thingIdentifier) && v.itemIsProperty) {
446                 list.add(v);
447             }
448         }
449         LOGGER.trace("getPropertyEntriesByThing({}) returns {}.", thingIdentifier, list);
450         return list;
451     }
452
453     /**
454      * Helper function: Calculate modulo.
455      *
456      * @param a as dividend.
457      * @param b as divisor.
458      *
459      * @return <b>true</b> if zero is remainder after division.
460      */
461     private static boolean isModulo(int a, int b) {
462         return (a % b) == 0;
463     }
464
465     /**
466      * {@link VeluxItemType} access method to determine the necessity of being refreshed
467      * within the current refresh cycle.
468      *
469      * @param refreshCycleCounter as identification of the refresh round.
470      * @param thingIdentifier as name of requested Thing.
471      * @param channelIdentifier as name of requested Channel.
472      *
473      * @return <b>boolean</b> value which expresses the need.
474      */
475     public static boolean isToBeRefreshedNow(int refreshCycleCounter, ThingTypeUID thingIdentifier,
476             String channelIdentifier) {
477         VeluxItemType itemType = getByThingAndChannel(thingIdentifier, channelIdentifier);
478
479         if (itemType == VeluxItemType.UNKNOWN) {
480             LOGGER.warn("isToBeRefreshedNow({},{},{}): returning false, as item is not found.", refreshCycleCounter,
481                     thingIdentifier, channelIdentifier);
482             return false;
483         }
484
485         if (((refreshCycleCounter == REFRESH_CYCLE_FIRST_TIME) && (itemType.isReadable()))
486                 || (itemType.isToBeRefreshed())) {
487             if ((refreshCycleCounter == REFRESH_CYCLE_FIRST_TIME)
488                     || (isModulo(refreshCycleCounter, itemType.getRefreshDivider()))) {
489                 LOGGER.trace("isToBeRefreshedNow(): returning true, as item is to be refreshed, now.");
490                 return true;
491             } else {
492                 LOGGER.trace("isToBeRefreshedNow(): returning false, as refresh cycle has not yet come for this item.");
493             }
494         } else {
495             LOGGER.trace("isToBeRefreshedNow(): returning false, as item is not refreshable.");
496         }
497         return false;
498     }
499 }