2 * Copyright (c) 2010-2022 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.velux.internal;
15 import java.util.ArrayList;
16 import java.util.List;
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;
29 * Enumeration of Types of a Velux item.
31 * Provides information about:
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>
45 * In addition there are helper methods providing information about:
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
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:
59 * Unique identification by:
61 * <li>Thing name as string,</li>
62 * <li>Channel name as string,</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>
71 * @author Guenther Schreiner - Initial contribution
75 public enum VeluxItemType {
77 UNKNOWN(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.UNKNOWN, TypeFlavor.UNUSABLE),
79 BINDING_INFORMATION(VeluxBindingConstants.THING_TYPE_BINDING, VeluxBindingConstants.CHANNEL_BINDING_INFORMATION, TypeFlavor.READONLY_VOLATILE_STRING),
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),
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),
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),
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),
106 WINDOW_POSITION(VeluxBindingConstants.THING_TYPE_VELUX_WINDOW, VeluxBindingConstants.CHANNEL_ACTUATOR_POSITION, TypeFlavor.MANIPULATOR_SHUTTER),
107 WINDOW_LIMIT_MINIMUM(VeluxBindingConstants.THING_TYPE_VELUX_WINDOW, VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MINIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
108 WINDOW_LIMIT_MAXIMUM(VeluxBindingConstants.THING_TYPE_VELUX_WINDOW, VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MAXIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
110 SCENE_ACTION(VeluxBindingConstants.THING_TYPE_VELUX_SCENE, VeluxBindingConstants.CHANNEL_SCENE_ACTION, TypeFlavor.INITIATOR),
111 SCENE_SILENTMODE(VeluxBindingConstants.THING_TYPE_VELUX_SCENE, VeluxBindingConstants.CHANNEL_SCENE_SILENTMODE, TypeFlavor.WRITEONLY_VOLATILE_SWITCH),
113 VSHUTTER_POSITION(VeluxBindingConstants.THING_TYPE_VELUX_VSHUTTER, VeluxBindingConstants.CHANNEL_VSHUTTER_POSITION, TypeFlavor.MANIPULATOR_SHUTTER),
117 private enum TypeFlavor {
119 * Used to present read-only non-volatile configuration parameters as StringItem.
121 READONLY_STATIC_STRING,
123 * Used to present read-only non-volatile configuration parameters as SwitchItem.
125 READONLY_STATIC_SWITCH,
127 * Used to present volatile configuration parameters as StringItem.
129 READONLY_VOLATILE_STRING,
131 * Used to present volatile configuration parameters as NumberItem.
133 READONLY_VOLATILE_NUMBER,
135 * Used to present volatile configuration parameters as NumberItem.
137 WRITEONLY_VOLATILE_SWITCH,
139 * Used to present volatile configuration parameters as SwitchItem.
141 READWRITE_VOLATILE_SWITCH,
143 * Used to initiate an action.
147 * Used to manipulate an actuator.
151 * Used to manipulate an actuator.
155 * Used to present read-only non-volatile configuration parameter (being handled as property of aThing).
159 * Used to define an UNUSABLE entry.
165 * ***************************
166 * ***** Private Objects *****
169 private ThingTypeUID thingIdentifier;
170 private String channelIdentifier;
171 private Class<? extends GenericItem> itemClass;
172 private boolean itemIsReadable;
173 private boolean itemIsWritable;
174 private boolean itemIsExecutable;
175 private boolean itemIsToBeRefreshed;
176 private int itemsRefreshDivider;
177 private boolean itemIsChannel;
178 private boolean itemIsProperty;
180 private static final Logger LOGGER = LoggerFactory.getLogger(VeluxItemType.class);
182 private static final int REFRESH_CYCLE_FIRST_TIME = 0;
183 private static final int REFRESH_ONCE_A_DAY = 8640;
184 private static final int REFRESH_EACH_HOUR = 360;
185 private static final int REFRESH_EACH_MINUTE = 6;
186 private static final int REFRESH_EVERY_CYCLE = 1;
189 * ************************
190 * ***** Constructors *****
193 VeluxItemType(ThingTypeUID thingIdentifier, String channelIdentifier, TypeFlavor typeFlavor) {
194 this.thingIdentifier = thingIdentifier;
195 this.channelIdentifier = channelIdentifier;
196 this.itemIsChannel = true;
197 this.itemIsProperty = false;
198 switch (typeFlavor) {
199 case READONLY_STATIC_STRING:
200 this.itemClass = StringItem.class;
201 this.itemIsReadable = true;
202 this.itemIsWritable = false;
203 this.itemIsExecutable = false;
204 this.itemIsToBeRefreshed = true;
205 this.itemsRefreshDivider = REFRESH_ONCE_A_DAY;
207 case READONLY_STATIC_SWITCH:
208 this.itemClass = SwitchItem.class;
209 this.itemIsReadable = true;
210 this.itemIsWritable = false;
211 this.itemIsExecutable = false;
212 this.itemIsToBeRefreshed = true;
213 this.itemsRefreshDivider = REFRESH_ONCE_A_DAY;
216 case READONLY_VOLATILE_STRING:
217 this.itemClass = StringItem.class;
218 this.itemIsReadable = true;
219 this.itemIsWritable = false;
220 this.itemIsExecutable = false;
221 this.itemIsToBeRefreshed = true;
222 this.itemsRefreshDivider = REFRESH_EACH_MINUTE;
224 case READONLY_VOLATILE_NUMBER:
225 this.itemClass = NumberItem.class;
226 this.itemIsReadable = true;
227 this.itemIsWritable = false;
228 this.itemIsExecutable = false;
229 this.itemIsToBeRefreshed = true;
230 this.itemsRefreshDivider = REFRESH_EVERY_CYCLE;
232 case WRITEONLY_VOLATILE_SWITCH:
233 this.itemClass = SwitchItem.class;
234 this.itemIsReadable = false;
235 this.itemIsWritable = true;
236 this.itemIsExecutable = false;
237 this.itemIsToBeRefreshed = false;
238 this.itemsRefreshDivider = REFRESH_EACH_MINUTE;
240 case READWRITE_VOLATILE_SWITCH:
241 this.itemClass = SwitchItem.class;
242 this.itemIsReadable = true;
243 this.itemIsWritable = true;
244 this.itemIsExecutable = false;
245 this.itemIsToBeRefreshed = true;
246 this.itemsRefreshDivider = REFRESH_EVERY_CYCLE;
250 this.itemClass = SwitchItem.class;
251 this.itemIsReadable = false;
252 this.itemIsWritable = false;
253 this.itemIsExecutable = true;
254 this.itemIsToBeRefreshed = false;
255 this.itemsRefreshDivider = 1;
258 case MANIPULATOR_SHUTTER:
259 this.itemClass = RollershutterItem.class;
260 this.itemIsReadable = true;
261 this.itemIsWritable = true;
262 this.itemIsExecutable = false;
263 this.itemIsToBeRefreshed = true;
264 this.itemsRefreshDivider = REFRESH_EACH_MINUTE;
267 case MANIPULATOR_SWITCH:
268 this.itemClass = SwitchItem.class;
269 this.itemIsReadable = true;
270 this.itemIsWritable = true;
271 this.itemIsExecutable = false;
272 this.itemIsToBeRefreshed = true;
273 this.itemsRefreshDivider = REFRESH_EACH_MINUTE;
277 this.itemClass = StringItem.class;
278 this.itemIsReadable = true;
279 this.itemIsWritable = false;
280 this.itemIsExecutable = false;
281 this.itemIsToBeRefreshed = true;
282 this.itemsRefreshDivider = REFRESH_EACH_HOUR;
283 this.itemIsChannel = false;
284 this.itemIsProperty = true;
289 this.itemClass = StringItem.class;
290 this.itemIsReadable = false;
291 this.itemIsWritable = false;
292 this.itemIsExecutable = false;
293 this.itemIsToBeRefreshed = false;
294 this.itemsRefreshDivider = REFRESH_ONCE_A_DAY;
295 this.itemIsChannel = false;
300 * ********************************
301 * ***** Class access methods *****
305 public String toString() {
306 return this.thingIdentifier + "/" + this.channelIdentifier;
310 * {@link VeluxItemType} access method to query Identifier on this type of item.
312 * @return <b>thingIdentifier</b> of type String describing the value of the enum {@link VeluxItemType}
315 public ThingTypeUID getThingTypeUID() {
316 return this.thingIdentifier;
320 * {@link VeluxItemType} access method to query common (channel/property) identifier on this type of item.
322 * @return <b>channelIdentifier</b> of type String describing the value of the enum {@link VeluxItemType}.
324 public String getIdentifier() {
325 return this.channelIdentifier;
329 * {@link VeluxItemType} access method to query the appropriate type of item.
331 * @return <b>itemClass</b> of type Item describing the possible type of this item.
333 public Class<? extends GenericItem> getItemClass() {
334 return this.itemClass;
338 * {@link VeluxItemType} access method to query Read possibility on this type of item.
340 * @return <b>itemIsReadable</b> of type boolean describing the ability to perform a write operation.
342 public boolean isReadable() {
343 return this.itemIsReadable;
347 * {@link VeluxItemType} access method to query Write possibility on this type of item.
349 * @return <b>itemIsWritable</b> of type boolean describing the ability to perform a write operation.
351 public boolean isWritable() {
352 return this.itemIsWritable;
356 * {@link VeluxItemType} access method to query Execute possibility on this type of item.
358 * @return <b>isExecute</b> of type boolean describing the ability to perform a write operation.
360 public boolean isExecutable() {
361 return this.itemIsExecutable;
365 * {@link VeluxItemType} access method to query the need of refresh on this type of item.
367 * @return <b>isExecute</b> of type boolean describing the ability to perform a write operation.
369 public boolean isToBeRefreshed() {
370 return this.itemIsToBeRefreshed;
374 * {@link VeluxItemType} access method to query the refreshMSecs interval on this type of item.
376 * @return <b>refreshDivider</b> of type int describing the factor.
378 public int getRefreshDivider() {
379 return this.itemsRefreshDivider;
383 * {@link VeluxItemType} access method to query the type of this item.
385 * @return <b>isChannel</b> of type boolean describing the need to be handled as channel.
387 public boolean isChannel() {
388 return this.itemIsChannel;
392 * {@link VeluxItemType} access method to query the type of this item.
394 * @return <b>itemIsProperty</b> of type boolean describing the need to be handled as property.
396 public boolean isProperty() {
397 return this.itemIsProperty;
401 * {@link VeluxItemType} access method to find an enum by itemTypeName.
403 * @param itemTypeName as name of requested Thing of type String.
405 * @return <b>veluxItemType</b> of type VeluxItemType describing the appropriate enum.
407 public VeluxItemType getByString(String itemTypeName) {
409 return VeluxItemType.valueOf(itemTypeName);
410 } catch (IllegalArgumentException e) {
416 * {@link VeluxItemType} access method to find an enum by name.
418 * @param thingIdentifier as name of requested Thing of type String.
419 * @param channelIdentifier as name of requested Channel of type String.
421 * @return <b>veluxItemType</b> of type VeluxItemType describing the appropriate enum.
423 public static VeluxItemType getByThingAndChannel(ThingTypeUID thingIdentifier, String channelIdentifier) {
424 for (VeluxItemType v : VeluxItemType.values()) {
425 if (thingIdentifier.equals(v.thingIdentifier) && channelIdentifier.equals(v.channelIdentifier)) {
426 LOGGER.trace("getByThingAndChannel({},{}) returns enum {}.", thingIdentifier, channelIdentifier, v);
430 LOGGER.trace("getByThingAndChannel({},{}) returns enum UNKNOWN.", thingIdentifier, channelIdentifier);
435 * {@link VeluxItemType} access method to find similar enum entries by thingIdentifier.
437 * @param thingIdentifier as name of requested Thing of type String.
439 * @return <b>listOfveluxItemType</b> of type List of VeluxItemType containing all similar enum entries.
441 public static List<VeluxItemType> getPropertyEntriesByThing(ThingTypeUID thingIdentifier) {
442 List<VeluxItemType> list = new ArrayList<>();
443 for (VeluxItemType v : VeluxItemType.values()) {
444 if (thingIdentifier.equals(v.thingIdentifier) && v.itemIsProperty) {
448 LOGGER.trace("getPropertyEntriesByThing({}) returns {}.", thingIdentifier, list);
453 * Helper function: Calculate modulo.
455 * @param a as dividend.
456 * @param b as divisor.
458 * @return <b>true</b> if zero is remainder after division.
460 private static boolean isModulo(int a, int b) {
465 * {@link VeluxItemType} access method to determine the necessity of being refreshed
466 * within the current refresh cycle.
468 * @param refreshCycleCounter as identification of the refresh round.
469 * @param thingIdentifier as name of requested Thing.
470 * @param channelIdentifier as name of requested Channel.
472 * @return <b>boolean</b> value which expresses the need.
474 public static boolean isToBeRefreshedNow(int refreshCycleCounter, ThingTypeUID thingIdentifier,
475 String channelIdentifier) {
476 VeluxItemType itemType = getByThingAndChannel(thingIdentifier, channelIdentifier);
478 if (itemType == VeluxItemType.UNKNOWN) {
479 LOGGER.warn("isToBeRefreshedNow({},{},{}): returning false, as item is not found.", refreshCycleCounter,
480 thingIdentifier, channelIdentifier);
484 if (((refreshCycleCounter == REFRESH_CYCLE_FIRST_TIME) && (itemType.isReadable()))
485 || (itemType.isToBeRefreshed())) {
486 if ((refreshCycleCounter == REFRESH_CYCLE_FIRST_TIME)
487 || (isModulo(refreshCycleCounter, itemType.getRefreshDivider()))) {
488 LOGGER.trace("isToBeRefreshedNow(): returning true, as item is to be refreshed, now.");
491 LOGGER.trace("isToBeRefreshedNow(): returning false, as refresh cycle has not yet come for this item.");
494 LOGGER.trace("isToBeRefreshedNow(): returning false, as item is not refreshable.");