2 * Copyright (c) 2010-2020 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.handler;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ScheduledExecutorService;
18 import java.util.concurrent.ScheduledFuture;
19 import java.util.concurrent.TimeUnit;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.velux.internal.VeluxBinding;
24 import org.openhab.binding.velux.internal.VeluxBindingConstants;
25 import org.openhab.binding.velux.internal.VeluxItemType;
26 import org.openhab.binding.velux.internal.bridge.VeluxBridge;
27 import org.openhab.binding.velux.internal.bridge.VeluxBridgeActuators;
28 import org.openhab.binding.velux.internal.bridge.VeluxBridgeDeviceStatus;
29 import org.openhab.binding.velux.internal.bridge.VeluxBridgeGetFirmware;
30 import org.openhab.binding.velux.internal.bridge.VeluxBridgeGetHouseStatus;
31 import org.openhab.binding.velux.internal.bridge.VeluxBridgeInstance;
32 import org.openhab.binding.velux.internal.bridge.VeluxBridgeLANConfig;
33 import org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider;
34 import org.openhab.binding.velux.internal.bridge.VeluxBridgeScenes;
35 import org.openhab.binding.velux.internal.bridge.VeluxBridgeSetHouseStatusMonitor;
36 import org.openhab.binding.velux.internal.bridge.VeluxBridgeWLANConfig;
37 import org.openhab.binding.velux.internal.bridge.common.BridgeAPI;
38 import org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol;
39 import org.openhab.binding.velux.internal.bridge.json.JsonVeluxBridge;
40 import org.openhab.binding.velux.internal.bridge.slip.SlipVeluxBridge;
41 import org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration;
42 import org.openhab.binding.velux.internal.development.Threads;
43 import org.openhab.binding.velux.internal.handler.utils.ExtendedBaseBridgeHandler;
44 import org.openhab.binding.velux.internal.handler.utils.Thing2VeluxActuator;
45 import org.openhab.binding.velux.internal.handler.utils.ThingProperty;
46 import org.openhab.binding.velux.internal.things.VeluxExistingProducts;
47 import org.openhab.binding.velux.internal.things.VeluxExistingScenes;
48 import org.openhab.binding.velux.internal.things.VeluxProduct;
49 import org.openhab.binding.velux.internal.things.VeluxProduct.ProductBridgeIndex;
50 import org.openhab.binding.velux.internal.things.VeluxProductPosition;
51 import org.openhab.binding.velux.internal.utils.Localization;
52 import org.openhab.core.common.ThreadPoolManager;
53 import org.openhab.core.library.types.DecimalType;
54 import org.openhab.core.library.types.OnOffType;
55 import org.openhab.core.library.types.PercentType;
56 import org.openhab.core.thing.Bridge;
57 import org.openhab.core.thing.ChannelUID;
58 import org.openhab.core.thing.ThingStatus;
59 import org.openhab.core.thing.ThingStatusDetail;
60 import org.openhab.core.thing.ThingTypeUID;
61 import org.openhab.core.types.Command;
62 import org.openhab.core.types.RefreshType;
63 import org.openhab.core.types.State;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
68 * <B>Common interaction with the </B><I>Velux</I><B> bridge.</B>
70 * It implements the communication between <B>OpenHAB</B> and the <I>Velux</I> Bridge:
72 * <LI><B>OpenHAB</B> Event Bus → <I>Velux</I> <B>bridge</B>
74 * Sending commands and value updates.</LI>
77 * <LI><I>Velux</I> <B>bridge</B> → <B>OpenHAB</B>:
79 * Retrieving information by sending a Refresh command.</LI>
82 * Entry point for this class is the method
83 * {@link VeluxBridgeHandler#handleCommand handleCommand}.
85 * @author Guenther Schreiner - Initial contribution.
88 public class VeluxBridgeHandler extends ExtendedBaseBridgeHandler implements VeluxBridgeInstance, VeluxBridgeProvider {
89 private final Logger logger = LoggerFactory.getLogger(VeluxBridgeHandler.class);
94 * Scheduler for continuous refresh by scheduleWithFixedDelay.
96 private @Nullable ScheduledFuture<?> refreshJob = null;
99 * Counter of refresh invocations by {@link refreshJob}.
101 private int refreshCounter = 0;
104 * Dedicated thread pool for the long-running bridge communication threads.
106 private ScheduledExecutorService handleScheduler = ThreadPoolManager
107 .getScheduledPool(VeluxBindingConstants.BINDING_ID);
109 private VeluxBridge myJsonBridge = new JsonVeluxBridge(this);
110 private VeluxBridge mySlipBridge = new SlipVeluxBridge(this);
113 * **************************************
114 * ***** Default visibility Objects *****
117 VeluxBridge thisBridge = myJsonBridge;
118 public BridgeParameters bridgeParameters = new BridgeParameters();
119 Localization localization;
122 * Mapping from ChannelUID to class Thing2VeluxActuator, which return Velux device information, probably cached.
124 Map<ChannelUID, Thing2VeluxActuator> channel2VeluxActuator = new ConcurrentHashMap<>();
127 * Information retrieved by {@link VeluxBinding#VeluxBinding}.
129 private VeluxBridgeConfiguration veluxBridgeConfiguration = new VeluxBridgeConfiguration();
132 * ************************
133 * ***** Constructors *****
136 public VeluxBridgeHandler(final Bridge bridge, Localization localization) {
138 logger.trace("VeluxBridgeHandler(constructor with bridge={}, localization={}) called.", bridge, localization);
139 this.localization = localization;
140 logger.debug("Creating a VeluxBridgeHandler for thing '{}'.", getThing().getUID());
147 * Set of information retrieved from the bridge/gateway:
150 * <LI>{@link #actuators} - Already known actuators,</LI>
151 * <LI>{@link #scenes} - Already on the gateway defined scenes,</LI>
152 * <LI>{@link #gateway} - Current status of the gateway status,</LI>
153 * <LI>{@link #firmware} - Information about the gateway firmware revision,</LI>
154 * <LI>{@link #lanConfig} - Information about the gateway configuration,</LI>
155 * <LI>{@link #wlanConfig} - Information about the gateway configuration.</LI>
159 public class BridgeParameters {
160 /** Information retrieved by {@link VeluxBridgeActuators#getProducts} */
161 public VeluxBridgeActuators actuators = new VeluxBridgeActuators();
163 /** Information retrieved by {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeScenes#getScenes} */
164 VeluxBridgeScenes scenes = new VeluxBridgeScenes();
166 /** Information retrieved by {@link VeluxBridgeDeviceStatus#retrieve} */
167 VeluxBridgeDeviceStatus.Channel gateway = new VeluxBridgeDeviceStatus().getChannel();
169 /** Information retrieved by {@link VeluxBridgeGetFirmware#retrieve} */
170 VeluxBridgeGetFirmware.Channel firmware = new VeluxBridgeGetFirmware().getChannel();
172 /** Information retrieved by {@link VeluxBridgeLANConfig#retrieve} */
173 VeluxBridgeLANConfig.Channel lanConfig = new VeluxBridgeLANConfig().getChannel();
175 /** Information retrieved by {@link VeluxBridgeWLANConfig#retrieve} */
176 VeluxBridgeWLANConfig.Channel wlanConfig = new VeluxBridgeWLANConfig().getChannel();
182 * Provide the ThingType for a given Channel.
184 * Separated into this private method to deal with the deprecated method.
187 * @param channelUID for type {@link ChannelUID}.
188 * @return thingTypeUID of type {@link ThingTypeUID}.
190 @SuppressWarnings("deprecation")
191 ThingTypeUID thingTypeUIDOf(ChannelUID channelUID) {
192 return channelUID.getThingUID().getThingTypeUID();
195 // Objects and Methods for interface VeluxBridgeInstance
198 * Information retrieved by ...
201 public VeluxBridgeConfiguration veluxBridgeConfiguration() {
202 return veluxBridgeConfiguration;
206 * Information retrieved by {@link VeluxBridgeActuators#getProducts}
209 public VeluxExistingProducts existingProducts() {
210 return bridgeParameters.actuators.getChannel().existingProducts;
214 * Information retrieved by {@link VeluxBridgeScenes#getScenes}
217 public VeluxExistingScenes existingScenes() {
218 return bridgeParameters.scenes.getChannel().existingScenes;
221 // Objects and Methods for interface VeluxBridgeProvider *****
224 public boolean bridgeCommunicate(BridgeCommunicationProtocol communication) {
225 logger.warn("bridgeCommunicate() called. Should never be called (as implemented by protocol-specific layers).");
230 public @Nullable BridgeAPI bridgeAPI() {
231 logger.warn("bridgeAPI() called. Should never be called (as implemented by protocol-specific layers).");
235 // Provisioning/Deprovisioning methods *****
238 public void initialize() {
239 logger.info("Initializing Velux Bridge '{}'.", getThing().getUID());
240 // The framework requires you to return from this method quickly.
241 // Setting the thing status to UNKNOWN temporarily and let the background task decide for the real status.
242 logger.trace("initialize() called.");
243 updateStatus(ThingStatus.UNKNOWN);
244 // Take care of unusual situations...
245 if (scheduler.isShutdown()) {
246 logger.warn("initialize(): scheduler is shutdown, aborting the initialization of this bridge.");
249 if (handleScheduler.isShutdown()) {
250 logger.trace("initialize(): handleScheduler is shutdown, aborting the initialization of this bridge.");
253 logger.trace("initialize(): preparing background initialization task.");
254 // Background initialization...
255 scheduler.execute(() -> {
256 logger.trace("initialize.scheduled(): Further work within scheduler.execute().");
257 logger.trace("initialize.scheduled(): Initializing bridge configuration parameters.");
258 this.veluxBridgeConfiguration = new VeluxBinding(getConfigAs(VeluxBridgeConfiguration.class)).checked();
259 logger.trace("initialize.scheduled(): work on updated bridge configuration parameters.");
260 bridgeParamsUpdated();
262 logger.debug("initialize.scheduled(): activated scheduler with {} milliseconds.",
263 this.veluxBridgeConfiguration.refreshMSecs);
264 refreshJob = scheduler.scheduleWithFixedDelay(() -> {
267 } catch (RuntimeException e) {
268 logger.warn("Exception occurred during activated refresh scheduler: {}.", e.getMessage());
270 }, this.veluxBridgeConfiguration.refreshMSecs, this.veluxBridgeConfiguration.refreshMSecs,
271 TimeUnit.MILLISECONDS);
272 logger.trace("initialize.scheduled(): done.");
274 logger.trace("initialize() done.");
278 * NOTE: It takes care about shutting down the connections before removal of this binding.
281 public synchronized void dispose() {
282 logger.info("Shutting down Velux Bridge '{}'.", getThing().getUID());
283 logger.trace("dispose(): shutting down continous refresh.");
284 // Just for avoidance of Potential null pointer access
285 ScheduledFuture<?> currentRefreshJob = refreshJob;
286 if (currentRefreshJob != null) {
287 logger.trace("dispose(): stopping the refresh.");
288 currentRefreshJob.cancel(true);
290 // Background execution of dispose
291 scheduler.execute(() -> {
292 logger.trace("dispose.scheduled(): (synchronous) logout initiated.");
293 thisBridge.bridgeLogout();
294 logger.trace("dispose.scheduled(): shutting down JSON bridge.");
295 myJsonBridge.shutdown();
296 logger.trace("dispose.scheduled(): shutting down SLIP bridge.");
297 mySlipBridge.shutdown();
299 logger.trace("dispose(): calling super class.");
301 logger.trace("dispose() done.");
305 * NOTE: It takes care by calling {@link #handleCommand} with the REFRESH command, that every used channel is
309 public void channelLinked(ChannelUID channelUID) {
310 if (thing.getStatus() == ThingStatus.ONLINE) {
311 channel2VeluxActuator.put(channelUID, new Thing2VeluxActuator(this, channelUID));
312 logger.trace("channelLinked({}) refreshing channel value with help of handleCommand as Thing is online.",
313 channelUID.getAsString());
314 handleCommand(channelUID, RefreshType.REFRESH);
316 logger.trace("channelLinked({}) doing nothing as Thing is not online.", channelUID.getAsString());
321 public void channelUnlinked(ChannelUID channelUID) {
322 logger.trace("channelUnlinked({}) called.", channelUID.getAsString());
325 // Reconfiguration methods
327 private void bridgeParamsUpdated() {
328 logger.debug("bridgeParamsUpdated() called.");
330 // Determine the appropriate bridge communication channel
331 boolean validBridgeFound = false;
332 if (myJsonBridge.supportedProtocols.contains(veluxBridgeConfiguration.protocol)) {
333 logger.debug("bridgeParamsUpdated(): choosing JSON as communication method.");
334 thisBridge = myJsonBridge;
335 validBridgeFound = true;
337 if (mySlipBridge.supportedProtocols.contains(veluxBridgeConfiguration.protocol)) {
338 logger.debug("bridgeParamsUpdated(): choosing SLIP as communication method.");
339 thisBridge = mySlipBridge;
340 validBridgeFound = true;
342 if (!validBridgeFound) {
343 logger.debug("No valid protocol selected, aborting this {} binding.", VeluxBindingConstants.BINDING_ID);
344 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
345 "@text/runtime.bridge-offline-no-valid-bridgeProtocol-selected");
346 logger.trace("bridgeParamsUpdated() done.");
350 logger.trace("bridgeParamsUpdated(): Trying to authenticate towards bridge.");
352 if (!thisBridge.bridgeLogin()) {
353 logger.warn("{} bridge login sequence failed; expecting bridge is OFFLINE.",
354 VeluxBindingConstants.BINDING_ID);
355 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
356 "@text/runtime.bridge-offline-login-sequence-failed");
357 logger.trace("bridgeParamsUpdated() done.");
361 logger.trace("bridgeParamsUpdated(): Querying bridge state.");
362 bridgeParameters.gateway = new VeluxBridgeDeviceStatus().retrieve(thisBridge);
364 logger.trace("bridgeParamsUpdated(): Fetching existing scenes.");
365 bridgeParameters.scenes.getScenes(thisBridge);
366 logger.info("Found {} scenes:\n\t{}", VeluxBindingConstants.BINDING_ID,
367 bridgeParameters.scenes.getChannel().existingScenes.toString(false, "\n\t"));
368 logger.trace("bridgeParamsUpdated(): Fetching existing actuators/products.");
369 bridgeParameters.actuators.getProducts(thisBridge);
370 logger.info("Found {} actuators:\n\t{}", VeluxBindingConstants.BINDING_ID,
371 bridgeParameters.actuators.getChannel().existingProducts.toString(false, "\n\t"));
373 if (thisBridge.bridgeAPI().setHouseStatusMonitor() != null) {
374 logger.trace("bridgeParamsUpdated(): Activating HouseStatusMonitor.");
375 if (new VeluxBridgeSetHouseStatusMonitor().modifyHSM(thisBridge, true)) {
376 logger.trace("bridgeParamsUpdated(): HSM activated.");
378 logger.warn("Activation of House-Status-Monitoring failed (might lead to a lack of status updates).");
382 veluxBridgeConfiguration.hasChanged = false;
383 logger.info("{} Bridge is online with {} scenes and {} actuators, now.", VeluxBindingConstants.BINDING_ID,
384 bridgeParameters.scenes.getChannel().existingScenes.getNoMembers(),
385 bridgeParameters.actuators.getChannel().existingProducts.getNoMembers());
386 logger.debug("Velux veluxBridge is online, now.");
387 updateStatus(ThingStatus.ONLINE);
388 logger.trace("bridgeParamsUpdated() successfully finished.");
391 // Continuous synchronization methods
393 private synchronized void refreshOpenHAB() {
394 logger.debug("refreshOpenHAB() initiated by {} starting cycle {}.", Thread.currentThread(), refreshCounter);
396 if (handleScheduler.isShutdown()) {
397 logger.trace("refreshOpenHAB(): handleScheduler is shutdown, recreating a scheduler pool.");
398 handleScheduler = ThreadPoolManager.getScheduledPool(VeluxBindingConstants.BINDING_ID);
401 logger.trace("refreshOpenHAB(): processing of possible HSM messages.");
402 // Background execution of bridge related I/O
403 handleScheduler.execute(() -> {
404 logger.trace("refreshOpenHAB.scheduled() initiated by {} will process HouseStatus.",
405 Thread.currentThread());
406 if (new VeluxBridgeGetHouseStatus().evaluateState(thisBridge)) {
407 logger.trace("refreshOpenHAB.scheduled(): successfully processed of GetHouseStatus()");
409 logger.trace("refreshOpenHAB.scheduled() initiated by {} has finished.", Thread.currentThread());
413 "refreshOpenHAB(): looping through all (both child things and bridge) linked channels for a need of refresh.");
414 for (ChannelUID channelUID : BridgeChannels.getAllLinkedChannelUIDs(this)) {
415 if (VeluxItemType.isToBeRefreshedNow(refreshCounter, thingTypeUIDOf(channelUID), channelUID.getId())) {
416 logger.trace("refreshOpenHAB(): refreshing channel {}.", channelUID);
417 handleCommand(channelUID, RefreshType.REFRESH);
420 logger.trace("refreshOpenHAB(): looping through properties for a need of refresh.");
421 for (VeluxItemType veluxItem : VeluxItemType.getPropertyEntriesByThing(getThing().getThingTypeUID())) {
422 if (VeluxItemType.isToBeRefreshedNow(refreshCounter, getThing().getThingTypeUID(),
423 veluxItem.getIdentifier())) {
424 logger.trace("refreshOpenHAB(): refreshing property {}.", veluxItem.getIdentifier());
425 handleCommand(new ChannelUID(getThing().getUID(), veluxItem.getIdentifier()), RefreshType.REFRESH);
428 logger.debug("refreshOpenHAB() initiated by {} finished cycle {}.", Thread.currentThread(), refreshCounter);
433 * In case of recognized changes in the real world, the method will
434 * update the corresponding states via openHAB event bus.
436 private void syncChannelsWithProducts() {
437 if (!bridgeParameters.actuators.getChannel().existingProducts.isDirty()) {
440 logger.trace("syncChannelsWithProducts(): there are some existing products with changed parameters.");
441 outer: for (VeluxProduct product : bridgeParameters.actuators.getChannel().existingProducts
442 .valuesOfModified()) {
443 logger.trace("syncChannelsWithProducts(): actuator {} has changed values.", product.getProductName());
444 ProductBridgeIndex productPbi = product.getBridgeProductIndex();
445 logger.trace("syncChannelsWithProducts(): bridge index is {}.", productPbi);
446 for (ChannelUID channelUID : BridgeChannels.getAllLinkedChannelUIDs(this)) {
447 if (!channel2VeluxActuator.containsKey(channelUID)) {
448 logger.trace("syncChannelsWithProducts(): channel {} not found.", channelUID);
451 if (!channel2VeluxActuator.get(channelUID).isKnown()) {
452 logger.trace("syncChannelsWithProducts(): channel {} not registered on bridge.", channelUID);
455 ProductBridgeIndex channelPbi = channel2VeluxActuator.get(channelUID).getProductBridgeIndex();
456 if (!channelPbi.equals(productPbi)) {
459 // Handle value inversion
460 boolean isInverted = channel2VeluxActuator.get(channelUID).isInverted();
461 logger.trace("syncChannelsWithProducts(): isInverted is {}.", isInverted);
462 VeluxProductPosition position = new VeluxProductPosition(product.getCurrentPosition());
463 if (position.isValid()) {
464 PercentType positionAsPercent = position.getPositionAsPercentType(isInverted);
465 logger.debug("syncChannelsWithProducts(): updating channel {} to position {}%.", channelUID,
467 updateState(channelUID, positionAsPercent);
469 logger.trace("syncChannelsWithProducts(): update of channel {} to position {} skipped.", channelUID,
475 logger.trace("syncChannelsWithProducts(): resetting dirty flag.");
476 bridgeParameters.actuators.getChannel().existingProducts.resetDirtyFlag();
477 logger.trace("syncChannelsWithProducts() done.");
480 // Processing of openHAB events
483 public void handleCommand(ChannelUID channelUID, Command command) {
484 logger.trace("handleCommand({}): command {} on channel {} will be scheduled.", Thread.currentThread(), command,
485 channelUID.getAsString());
486 logger.debug("handleCommand({},{}) called.", channelUID.getAsString(), command);
488 // Background execution of bridge related I/O
489 handleScheduler.execute(() -> {
490 logger.trace("handleCommand.scheduled({}) Start work with calling handleCommandScheduled().",
491 Thread.currentThread());
492 handleCommandScheduled(channelUID, command);
493 logger.trace("handleCommand.scheduled({}) done.", Thread.currentThread());
495 logger.trace("handleCommand({}) done.", Thread.currentThread());
499 * Normally called by {@link #handleCommand} to handle a command for a given channel with possibly long execution
502 * <B>NOTE:</B> This method is to be called as separated thread to ensure proper openHAB framework in parallel.
505 * @param channelUID the {@link ChannelUID} of the channel to which the command was sent,
506 * @param command the {@link Command}.
508 private synchronized void handleCommandScheduled(ChannelUID channelUID, Command command) {
509 logger.trace("handleCommandScheduled({}): command {} on channel {}.", Thread.currentThread(), command,
510 channelUID.getAsString());
511 logger.debug("handleCommandScheduled({},{}) called.", channelUID.getAsString(), command);
514 * ===========================================================
518 if (veluxBridgeConfiguration.isProtocolTraceEnabled) {
519 Threads.findDeadlocked();
522 String channelId = channelUID.getId();
523 State newState = null;
524 String itemName = channelUID.getAsString();
525 VeluxItemType itemType = VeluxItemType.getByThingAndChannel(thingTypeUIDOf(channelUID), channelUID.getId());
527 if (itemType == VeluxItemType.UNKNOWN) {
528 logger.warn("{} Cannot determine type of Channel {}, ignoring command {}.",
529 VeluxBindingConstants.LOGGING_CONTACT, channelUID, command);
530 logger.trace("handleCommandScheduled() aborting.");
535 if (!channel2VeluxActuator.containsKey(channelUID)) {
536 channel2VeluxActuator.put(channelUID, new Thing2VeluxActuator(this, channelUID));
539 if (veluxBridgeConfiguration.hasChanged) {
540 logger.trace("handleCommandScheduled(): work on updated bridge configuration parameters.");
541 bridgeParamsUpdated();
544 syncChannelsWithProducts();
546 if (command instanceof RefreshType) {
548 * ===========================================================
551 logger.trace("handleCommandScheduled(): work on refresh.");
552 if (!itemType.isReadable()) {
553 logger.debug("handleCommandScheduled(): received a Refresh command for a non-readable item.");
555 logger.trace("handleCommandScheduled(): refreshing item {} (type {}).", itemName, itemType);
556 try { // expecting an IllegalArgumentException for unknown Velux device
560 newState = ChannelBridgeStatus.handleRefresh(channelUID, channelId, this);
562 case BRIDGE_DOWNTIME:
563 newState = new DecimalType(
564 thisBridge.lastCommunication() - thisBridge.lastSuccessfulCommunication());
566 case BRIDGE_FIRMWARE:
567 newState = ChannelBridgeFirmware.handleRefresh(channelUID, channelId, this);
569 case BRIDGE_IPADDRESS:
570 case BRIDGE_SUBNETMASK:
571 case BRIDGE_DEFAULTGW:
573 newState = ChannelBridgeLANconfig.handleRefresh(channelUID, channelId, this);
575 case BRIDGE_WLANSSID:
576 case BRIDGE_WLANPASSWORD:
577 newState = ChannelBridgeWLANconfig.handleRefresh(channelUID, channelId, this);
580 newState = ChannelBridgeScenes.handleRefresh(channelUID, channelId, this);
582 case BRIDGE_PRODUCTS:
583 newState = ChannelBridgeProducts.handleRefresh(channelUID, channelId, this);
586 newState = ChannelBridgeCheck.handleRefresh(channelUID, channelId, this);
589 case ACTUATOR_POSITION:
591 case ROLLERSHUTTER_POSITION:
592 case WINDOW_POSITION:
593 newState = ChannelActuatorPosition.handleRefresh(channelUID, channelId, this);
595 case ACTUATOR_LIMIT_MINIMUM:
596 case ROLLERSHUTTER_LIMIT_MINIMUM:
597 case WINDOW_LIMIT_MINIMUM:
598 newState = ChannelActuatorLimitation.handleRefresh(channelUID, "", this);
600 case ACTUATOR_LIMIT_MAXIMUM:
601 case ROLLERSHUTTER_LIMIT_MAXIMUM:
602 case WINDOW_LIMIT_MAXIMUM:
603 newState = ChannelActuatorLimitation.handleRefresh(channelUID, channelId, this);
606 // VirtualShutter channels
607 case VSHUTTER_POSITION:
608 newState = ChannelVShutterPosition.handleRefresh(channelUID, channelId, this);
613 "handleCommandScheduled(): cannot handle REFRESH on channel {} as it is of type {}.",
614 itemName, channelId);
616 } catch (IllegalArgumentException e) {
617 logger.warn("Cannot handle REFRESH on channel {} as it isn't (yet) known to the bridge.", itemName);
619 if (newState != null) {
620 if (itemType.isChannel()) {
621 logger.debug("handleCommandScheduled(): updating channel {} to {}.", channelUID, newState);
622 updateState(channelUID, newState);
624 if (itemType.isProperty()) {
625 logger.debug("handleCommandScheduled(): updating property {} to {}.", channelUID, newState);
626 ThingProperty.setValue(this, itemType.getIdentifier(), newState.toString());
630 logger.info("handleCommandScheduled({},{}): updating of item {} (type {}) failed.",
631 channelUID.getAsString(), command, itemName, itemType);
636 * ===========================================================
639 logger.trace("handleCommandScheduled(): working on item {} (type {}) with COMMAND {}.", itemName, itemType,
641 Command newValue = null;
642 try { // expecting an IllegalArgumentException for unknown Velux device
646 if (command == OnOffType.ON) {
647 logger.trace("handleCommandScheduled(): about to reload informations from veluxBridge.");
648 bridgeParamsUpdated();
650 logger.trace("handleCommandScheduled(): ignoring OFF command.");
653 case BRIDGE_DO_DETECTION:
654 ChannelBridgeDoDetection.handleCommand(channelUID, channelId, command, this);
659 ChannelSceneAction.handleCommand(channelUID, channelId, command, this);
661 case SCENE_SILENTMODE:
662 ChannelSceneSilentmode.handleCommand(channelUID, channelId, command, this);
666 case ACTUATOR_POSITION:
668 case ROLLERSHUTTER_POSITION:
669 case WINDOW_POSITION:
670 ChannelActuatorPosition.handleCommand(channelUID, channelId, command, this);
672 case ACTUATOR_LIMIT_MINIMUM:
673 case ROLLERSHUTTER_LIMIT_MINIMUM:
674 case WINDOW_LIMIT_MINIMUM:
675 ChannelActuatorLimitation.handleCommand(channelUID, channelId, command, this);
677 case ACTUATOR_LIMIT_MAXIMUM:
678 case ROLLERSHUTTER_LIMIT_MAXIMUM:
679 case WINDOW_LIMIT_MAXIMUM:
680 ChannelActuatorLimitation.handleCommand(channelUID, channelId, command, this);
683 // VirtualShutter channels
684 case VSHUTTER_POSITION:
685 newValue = ChannelVShutterPosition.handleCommand(channelUID, channelId, command, this);
689 logger.warn("{} Cannot handle command {} on channel {} (type {}).",
690 VeluxBindingConstants.LOGGING_CONTACT, command, itemName, itemType);
692 } catch (IllegalArgumentException e) {
693 logger.warn("Cannot handle command on channel {} as it isn't (yet) known to the bridge.", itemName);
695 if (newValue != null) {
696 postCommand(channelUID, newValue);
699 ThingProperty.setValue(this, VeluxBindingConstants.PROPERTY_BRIDGE_TIMESTAMP_ATTEMPT,
700 new java.util.Date(thisBridge.lastCommunication()).toString());
701 ThingProperty.setValue(this, VeluxBindingConstants.PROPERTY_BRIDGE_TIMESTAMP_SUCCESS,
702 new java.util.Date(thisBridge.lastSuccessfulCommunication()).toString());
703 logger.trace("handleCommandScheduled({}) done.", Thread.currentThread());