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.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),
105 ROLLERSHUTTER_VANE_POSITION(VeluxBindingConstants.THING_TYPE_VELUX_ROLLERSHUTTER,VeluxBindingConstants.CHANNEL_VANE_POSITION, TypeFlavor.MANIPULATOR_SHUTTER),
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),
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),
114 VSHUTTER_POSITION(VeluxBindingConstants.THING_TYPE_VELUX_VSHUTTER, VeluxBindingConstants.CHANNEL_VSHUTTER_POSITION, TypeFlavor.MANIPULATOR_SHUTTER),
118 private enum TypeFlavor {
120 * Used to present read-only non-volatile configuration parameters as StringItem.
122 READONLY_STATIC_STRING,
124 * Used to present read-only non-volatile configuration parameters as SwitchItem.
126 READONLY_STATIC_SWITCH,
128 * Used to present volatile configuration parameters as StringItem.
130 READONLY_VOLATILE_STRING,
132 * Used to present volatile configuration parameters as NumberItem.
134 READONLY_VOLATILE_NUMBER,
136 * Used to present volatile configuration parameters as NumberItem.
138 WRITEONLY_VOLATILE_SWITCH,
140 * Used to present volatile configuration parameters as SwitchItem.
142 READWRITE_VOLATILE_SWITCH,
144 * Used to initiate an action.
148 * Used to manipulate an actuator.
152 * Used to manipulate an actuator.
156 * Used to present read-only non-volatile configuration parameter (being handled as property of aThing).
160 * Used to define an UNUSABLE entry.
166 * ***************************
167 * ***** Private Objects *****
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;
181 private static final Logger LOGGER = LoggerFactory.getLogger(VeluxItemType.class);
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;
190 * ************************
191 * ***** Constructors *****
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
301 * ********************************
302 * ***** Class access methods *****
306 public String toString() {
307 return this.thingIdentifier + "/" + this.channelIdentifier;
311 * {@link VeluxItemType} access method to query Identifier on this type of item.
313 * @return <b>thingIdentifier</b> of type String describing the value of the enum {@link VeluxItemType}
316 public ThingTypeUID getThingTypeUID() {
317 return this.thingIdentifier;
321 * {@link VeluxItemType} access method to query common (channel/property) identifier on this type of item.
323 * @return <b>channelIdentifier</b> of type String describing the value of the enum {@link VeluxItemType}.
325 public String getIdentifier() {
326 return this.channelIdentifier;
330 * {@link VeluxItemType} access method to query the appropriate type of item.
332 * @return <b>itemClass</b> of type Item describing the possible type of this item.
334 public Class<? extends GenericItem> getItemClass() {
335 return this.itemClass;
339 * {@link VeluxItemType} access method to query Read possibility on this type of item.
341 * @return <b>itemIsReadable</b> of type boolean describing the ability to perform a write operation.
343 public boolean isReadable() {
344 return this.itemIsReadable;
348 * {@link VeluxItemType} access method to query Write possibility on this type of item.
350 * @return <b>itemIsWritable</b> of type boolean describing the ability to perform a write operation.
352 public boolean isWritable() {
353 return this.itemIsWritable;
357 * {@link VeluxItemType} access method to query Execute possibility on this type of item.
359 * @return <b>isExecute</b> of type boolean describing the ability to perform a write operation.
361 public boolean isExecutable() {
362 return this.itemIsExecutable;
366 * {@link VeluxItemType} access method to query the need of refresh on this type of item.
368 * @return <b>isExecute</b> of type boolean describing the ability to perform a write operation.
370 public boolean isToBeRefreshed() {
371 return this.itemIsToBeRefreshed;
375 * {@link VeluxItemType} access method to query the refreshMSecs interval on this type of item.
377 * @return <b>refreshDivider</b> of type int describing the factor.
379 public int getRefreshDivider() {
380 return this.itemsRefreshDivider;
384 * {@link VeluxItemType} access method to query the type of this item.
386 * @return <b>isChannel</b> of type boolean describing the need to be handled as channel.
388 public boolean isChannel() {
389 return this.itemIsChannel;
393 * {@link VeluxItemType} access method to query the type of this item.
395 * @return <b>itemIsProperty</b> of type boolean describing the need to be handled as property.
397 public boolean isProperty() {
398 return this.itemIsProperty;
402 * {@link VeluxItemType} access method to find an enum by itemTypeName.
404 * @param itemTypeName as name of requested Thing of type String.
406 * @return <b>veluxItemType</b> of type VeluxItemType describing the appropriate enum.
408 public VeluxItemType getByString(String itemTypeName) {
410 return VeluxItemType.valueOf(itemTypeName);
411 } catch (IllegalArgumentException e) {
417 * {@link VeluxItemType} access method to find an enum by name.
419 * @param thingIdentifier as name of requested Thing of type String.
420 * @param channelIdentifier as name of requested Channel of type String.
422 * @return <b>veluxItemType</b> of type VeluxItemType describing the appropriate enum.
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);
431 LOGGER.trace("getByThingAndChannel({},{}) returns enum UNKNOWN.", thingIdentifier, channelIdentifier);
436 * {@link VeluxItemType} access method to find similar enum entries by thingIdentifier.
438 * @param thingIdentifier as name of requested Thing of type String.
440 * @return <b>listOfveluxItemType</b> of type List of VeluxItemType containing all similar enum entries.
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) {
449 LOGGER.trace("getPropertyEntriesByThing({}) returns {}.", thingIdentifier, list);
454 * Helper function: Calculate modulo.
456 * @param a as dividend.
457 * @param b as divisor.
459 * @return <b>true</b> if zero is remainder after division.
461 private static boolean isModulo(int a, int b) {
466 * {@link VeluxItemType} access method to determine the necessity of being refreshed
467 * within the current refresh cycle.
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.
473 * @return <b>boolean</b> value which expresses the need.
475 public static boolean isToBeRefreshedNow(int refreshCycleCounter, ThingTypeUID thingIdentifier,
476 String channelIdentifier) {
477 VeluxItemType itemType = getByThingAndChannel(thingIdentifier, channelIdentifier);
479 if (itemType == VeluxItemType.UNKNOWN) {
480 LOGGER.warn("isToBeRefreshedNow({},{},{}): returning false, as item is not found.", refreshCycleCounter,
481 thingIdentifier, channelIdentifier);
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.");
492 LOGGER.trace("isToBeRefreshedNow(): returning false, as refresh cycle has not yet come for this item.");
495 LOGGER.trace("isToBeRefreshedNow(): returning false, as item is not refreshable.");