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.digitalstrom.internal.handler;
15 import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.*;
17 import java.math.BigDecimal;
18 import java.util.ArrayList;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.LinkedList;
22 import java.util.List;
26 import org.apache.commons.lang.StringUtils;
27 import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
28 import org.openhab.binding.digitalstrom.internal.lib.GeneralLibConstance;
29 import org.openhab.binding.digitalstrom.internal.lib.config.Config;
30 import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
31 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
32 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.GeneralDeviceInformation;
33 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceSceneSpec;
34 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
35 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ChangeableDeviceConfigEnum;
36 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.DeviceBinarayInputEnum;
37 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.OutputModeEnum;
38 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.SensorEnum;
39 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceBinaryInput;
40 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.impl.DeviceStateUpdateImpl;
41 import org.openhab.binding.digitalstrom.internal.providers.DsChannelTypeProvider;
42 import org.openhab.core.config.core.Configuration;
43 import org.openhab.core.library.types.DecimalType;
44 import org.openhab.core.library.types.IncreaseDecreaseType;
45 import org.openhab.core.library.types.OnOffType;
46 import org.openhab.core.library.types.PercentType;
47 import org.openhab.core.library.types.StopMoveType;
48 import org.openhab.core.library.types.StringType;
49 import org.openhab.core.library.types.UpDownType;
50 import org.openhab.core.thing.Bridge;
51 import org.openhab.core.thing.Channel;
52 import org.openhab.core.thing.ChannelUID;
53 import org.openhab.core.thing.Thing;
54 import org.openhab.core.thing.ThingStatus;
55 import org.openhab.core.thing.ThingStatusDetail;
56 import org.openhab.core.thing.ThingStatusInfo;
57 import org.openhab.core.thing.ThingTypeUID;
58 import org.openhab.core.thing.binding.BaseThingHandler;
59 import org.openhab.core.thing.binding.ThingHandler;
60 import org.openhab.core.thing.binding.builder.ChannelBuilder;
61 import org.openhab.core.thing.binding.builder.ThingBuilder;
62 import org.openhab.core.thing.type.ChannelTypeUID;
63 import org.openhab.core.types.Command;
64 import org.openhab.core.types.RefreshType;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
69 * The {@link DeviceHandler} is responsible for handling the configuration, load supported channels of a
70 * digitalSTROM device and handling commands, which are sent to one of the channels. <br>
72 * For that it uses the {@link BridgeHandler} and the {@link DeviceStateUpdate} mechanism of the {@link Device} to
73 * execute the actual command and implements the {@link DeviceStatusListener} to get informed about changes from the
74 * accompanying {@link Device}.
76 * @author Michael Ochel - Initial contribution
77 * @author Matthias Siegele - Initial contribution
79 public class DeviceHandler extends BaseThingHandler implements DeviceStatusListener {
81 private final Logger logger = LoggerFactory.getLogger(DeviceHandler.class);
84 * Contains all supported thing types of this handler, will be filled by DsDeviceThingTypeProvider.
86 public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>();
88 public static final String TWO_STAGE_SWITCH_IDENTICATOR = "2";
89 public static final String THREE_STAGE_SWITCH_IDENTICATOR = "3";
92 private Device device;
93 private BridgeHandler dssBridgeHandler;
95 private Command lastComand;
96 private String currentChannel;
97 private List<String> loadedSensorChannels;
100 * Creates a new {@link DeviceHandler}.
102 * @param thing must not be null
104 public DeviceHandler(Thing thing) {
109 public void initialize() {
110 logger.debug("Initializing DeviceHandler.");
111 if (StringUtils.isNotBlank((String) getConfig().get(DigitalSTROMBindingConstants.DEVICE_DSID))) {
112 dSID = getConfig().get(DigitalSTROMBindingConstants.DEVICE_DSID).toString();
113 final Bridge bridge = getBridge();
114 if (bridge != null) {
115 bridgeStatusChanged(bridge.getStatusInfo());
117 // Set status to OFFLINE if no bridge is available e.g. because the bridge has been removed and the
118 // Thing was reinitialized.
119 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge is missing!");
122 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "dSID is missing");
127 public void dispose() {
128 logger.debug("Handler disposed... unregister DeviceStatusListener");
130 if (dssBridgeHandler != null) {
131 dssBridgeHandler.unregisterDeviceStatusListener(this);
134 if (device != null) {
135 device.setSensorDataRefreshPriority(Config.REFRESH_PRIORITY_NEVER, Config.REFRESH_PRIORITY_NEVER,
136 Config.REFRESH_PRIORITY_NEVER);
142 public void handleRemoval() {
143 if (getDssBridgeHandler() != null) {
144 this.dssBridgeHandler.childThingRemoved(dSID);
146 updateStatus(ThingStatus.REMOVED);
150 public void thingUpdated(Thing thing) {
152 if (device == null) {
158 public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
159 if (bridgeStatusInfo.getStatus().equals(ThingStatus.ONLINE)) {
161 if (getDssBridgeHandler() != null) {
162 if (device == null) {
163 updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
164 "waiting for listener registration");
165 dssBridgeHandler.registerDeviceStatusListener(this);
167 updateStatus(ThingStatus.ONLINE);
170 updateStatus(ThingStatus.OFFLINE);
173 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No dSID is set!");
176 if (bridgeStatusInfo.getStatus().equals(ThingStatus.OFFLINE)) {
177 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
179 logger.debug("Set status to {}", getThing().getStatusInfo());
183 public void handleCommand(ChannelUID channelUID, Command command) {
184 BridgeHandler dssBridgeHandler = getDssBridgeHandler();
185 if (dssBridgeHandler == null) {
186 logger.debug("BridgeHandler not found. Cannot handle command without bridge.");
190 if (device == null) {
192 "Device not known on StructureManager or DeviceStatusListener is not registerd. Cannot handle command.");
196 if (command instanceof RefreshType) {
198 SensorEnum sensorType = SensorEnum.valueOf(channelUID.getId());
199 dssBridgeHandler.sendComandsToDSS(device, new DeviceStateUpdateImpl(sensorType, 1));
200 } catch (IllegalArgumentException e) {
201 dssBridgeHandler.sendComandsToDSS(device,
202 new DeviceStateUpdateImpl(DeviceStateUpdate.REFRESH_OUTPUT, 0));
204 } else if (!device.isShade()) {
205 if (DsChannelTypeProvider.isOutputChannel(channelUID.getId())) {
206 if (command instanceof PercentType) {
207 device.setOutputValue(
208 (short) fromPercentToValue(((PercentType) command).intValue(), device.getMaxOutputValue()));
209 } else if (command instanceof OnOffType) {
210 if (OnOffType.ON.equals(command)) {
211 device.setIsOn(true);
213 device.setIsOn(false);
215 } else if (command instanceof IncreaseDecreaseType) {
216 if (IncreaseDecreaseType.INCREASE.equals(command)) {
221 } else if (command instanceof StringType) {
222 device.setOutputValue(Short.parseShort(((StringType) command).toString()));
225 logger.debug("Command sent to an unknown channel id: {}", channelUID);
228 if (channelUID.getId().contains(DsChannelTypeProvider.ANGLE)) {
229 if (command instanceof PercentType) {
230 device.setAnglePosition(
231 (short) fromPercentToValue(((PercentType) command).intValue(), device.getMaxSlatAngle()));
232 } else if (command instanceof OnOffType) {
233 if (OnOffType.ON.equals(command)) {
234 device.setAnglePosition(device.getMaxSlatAngle());
236 device.setAnglePosition(device.getMinSlatAngle());
238 } else if (command instanceof IncreaseDecreaseType) {
239 if (IncreaseDecreaseType.INCREASE.equals(command)) {
240 device.increaseSlatAngle();
242 device.decreaseSlatAngle();
245 } else if (channelUID.getId().contains(DsChannelTypeProvider.SHADE)) {
246 if (command instanceof PercentType) {
247 int percent = ((PercentType) command).intValue();
248 if (!device.getHWinfo().equals("GR-KL200")) {
249 percent = 100 - percent;
251 device.setSlatPosition(fromPercentToValue(percent, device.getMaxSlatPosition()));
252 this.lastComand = command;
253 } else if (command instanceof StopMoveType) {
254 if (StopMoveType.MOVE.equals(command)) {
255 handleCommand(channelUID, this.lastComand);
257 dssBridgeHandler.stopOutputValue(device);
259 } else if (command instanceof UpDownType) {
260 if (UpDownType.UP.equals(command)) {
261 device.setIsOpen(true);
262 this.lastComand = command;
264 device.setIsOpen(false);
265 this.lastComand = command;
269 logger.debug("Command sent to an unknown channel id: {}", channelUID);
274 private int fromPercentToValue(int percent, int max) {
275 if (percent < 0 || percent == 0) {
278 if (max < 0 || max == 0) {
281 return (int) (max * ((float) percent / 100));
284 private synchronized BridgeHandler getDssBridgeHandler() {
285 if (this.dssBridgeHandler == null) {
286 Bridge bridge = getBridge();
287 if (bridge == null) {
288 logger.debug("Bride cannot be found");
291 ThingHandler handler = bridge.getHandler();
293 if (handler instanceof BridgeHandler) {
294 dssBridgeHandler = (BridgeHandler) handler;
299 return dssBridgeHandler;
302 private boolean sensorChannelsLoaded() {
303 return loadedSensorChannels != null && !loadedSensorChannels.isEmpty();
307 public synchronized void onDeviceStateChanged(DeviceStateUpdate deviceStateUpdate) {
308 if (device != null) {
309 if (deviceStateUpdate != null) {
310 if (sensorChannelsLoaded()) {
311 if (deviceStateUpdate.isSensorUpdateType()) {
312 updateState(getSensorChannelID(deviceStateUpdate.getTypeAsSensorEnum()),
313 new DecimalType(deviceStateUpdate.getValueAsFloat()));
314 logger.debug("Update state");
317 if (deviceStateUpdate.isBinarayInputType()) {
318 if (deviceStateUpdate.getValueAsShort() == 1) {
319 updateState(getBinaryInputChannelID(deviceStateUpdate.getTypeAsDeviceBinarayInputEnum()),
322 updateState(getBinaryInputChannelID(deviceStateUpdate.getTypeAsDeviceBinarayInputEnum()),
327 if (!device.isShade()) {
328 if (currentChannel != null) {
329 switch (deviceStateUpdate.getType()) {
330 case DeviceStateUpdate.OUTPUT_DECREASE:
331 case DeviceStateUpdate.OUTPUT_INCREASE:
332 case DeviceStateUpdate.OUTPUT:
333 if (currentChannel.contains(DsChannelTypeProvider.DIMMER)) {
334 if (deviceStateUpdate.getValueAsInteger() > 0) {
335 updateState(currentChannel, new PercentType(fromValueToPercent(
336 deviceStateUpdate.getValueAsInteger(), device.getMaxOutputValue())));
338 updateState(currentChannel, OnOffType.OFF);
340 } else if (currentChannel.contains(DsChannelTypeProvider.STAGE)) {
341 if (currentChannel.contains(TWO_STAGE_SWITCH_IDENTICATOR)) {
342 updateState(currentChannel,
343 new StringType(convertStageValue((short) 2, device.getOutputValue())));
345 updateState(currentChannel,
346 new StringType(convertStageValue((short) 3, device.getOutputValue())));
350 case DeviceStateUpdate.ON_OFF:
351 if (currentChannel.contains(DsChannelTypeProvider.STAGE)) {
352 onDeviceStateChanged(new DeviceStateUpdateImpl(DeviceStateUpdate.OUTPUT,
353 device.getOutputValue()));
355 if (deviceStateUpdate.getValueAsInteger() > 0) {
356 updateState(currentChannel, OnOffType.ON);
358 updateState(currentChannel, OnOffType.OFF);
367 switch (deviceStateUpdate.getType()) {
368 case DeviceStateUpdate.SLAT_DECREASE:
369 case DeviceStateUpdate.SLAT_INCREASE:
370 case DeviceStateUpdate.SLATPOSITION:
371 percent = fromValueToPercent(deviceStateUpdate.getValueAsInteger(),
372 device.getMaxSlatPosition());
374 case DeviceStateUpdate.OPEN_CLOSE:
375 if (deviceStateUpdate.getValueAsInteger() > 0) {
379 case DeviceStateUpdate.OPEN_CLOSE_ANGLE:
380 if (device.isBlind() && currentChannel != null) {
381 if (deviceStateUpdate.getValueAsInteger() > 0) {
382 updateState(currentChannel, PercentType.HUNDRED);
384 updateState(currentChannel, PercentType.ZERO);
388 case DeviceStateUpdate.SLAT_ANGLE_DECREASE:
389 case DeviceStateUpdate.SLAT_ANGLE_INCREASE:
390 case DeviceStateUpdate.SLAT_ANGLE:
391 if (device.isBlind() && currentChannel != null) {
392 updateState(currentChannel,
393 new PercentType(fromValueToPercent(deviceStateUpdate.getValueAsInteger(),
394 device.getMaxSlatAngle())));
400 if (!device.getHWinfo().equals("GR-KL210")) {
401 percent = 100 - percent;
403 updateState(DsChannelTypeProvider.SHADE, new PercentType(percent));
405 logger.debug("Update state");
410 private int fromValueToPercent(int value, int max) {
411 if (value <= 0 || max <= 0) {
414 int percentValue = new BigDecimal(value * ((float) 100 / max)).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
415 return percentValue < 0 ? 0 : percentValue > 100 ? 100 : percentValue;
419 public synchronized void onDeviceRemoved(GeneralDeviceInformation device) {
420 if (device instanceof Device) {
421 this.device = (Device) device;
422 if (this.getThing().getStatus().equals(ThingStatus.ONLINE)) {
423 if (!((Device) device).isPresent()) {
424 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
425 "Device is not present in the digitalSTROM-System.");
427 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
428 "Device is not avaible in the digitalSTROM-System.");
432 logger.debug("Set status to {}", getThing().getStatus());
437 public synchronized void onDeviceAdded(GeneralDeviceInformation device) {
438 if (device instanceof Device) {
439 this.device = (Device) device;
440 if (this.device.isPresent()) {
441 ThingStatusInfo statusInfo = this.dssBridgeHandler.getThing().getStatusInfo();
442 updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
443 logger.debug("Set status to {}", getThing().getStatus());
445 // load scene configurations persistently into the thing
446 for (Short i : this.device.getSavedScenes()) {
447 onSceneConfigAdded(i);
449 logger.debug("Load saved scene specification into device");
450 this.device.saveConfigSceneSpecificationIntoDevice(getThing().getProperties());
452 checkDeviceInfoProperties(this.device);
453 // load sensor priorities into the device and load sensor channels of the thing
454 if (!this.device.isShade()) {
455 loadSensorChannels();
456 // check and load output channel of the thing
457 checkOutputChannel();
458 } else if (this.device.isBlind()) {
459 // load channel for set the angle of jalousie devices
460 String channelTypeID = DsChannelTypeProvider.getOutputChannelTypeID(
461 ((Device) device).getFunctionalColorGroup(), ((Device) device).getOutputMode());
462 loadOutputChannel(new ChannelTypeUID(BINDING_ID, channelTypeID),
463 DsChannelTypeProvider.getItemType(channelTypeID));
466 // load first channel values
467 onDeviceStateInitial(this.device);
471 onDeviceRemoved(device);
475 * Updates device info properties.
477 * @param device (must not be null)
479 private void checkDeviceInfoProperties(Device device) {
480 boolean propertiesChanged = false;
481 Map<String, String> properties = editProperties();
483 if (device.getName() != null) {
484 properties.put(DigitalSTROMBindingConstants.DEVICE_NAME, device.getName());
485 propertiesChanged = true;
487 if (device.getDSUID() != null) {
488 properties.put(DigitalSTROMBindingConstants.DEVICE_UID, device.getDSUID());
489 propertiesChanged = true;
491 if (device.getHWinfo() != null) {
492 properties.put(DigitalSTROMBindingConstants.DEVICE_HW_INFO, device.getHWinfo());
493 propertiesChanged = true;
495 if (device.getZoneId() != -1) {
496 properties.put(DigitalSTROMBindingConstants.DEVICE_ZONE_ID, device.getZoneId() + "");
497 propertiesChanged = true;
499 if (device.getGroups() != null) {
500 properties.put(DigitalSTROMBindingConstants.DEVICE_GROUPS, device.getGroups().toString());
501 propertiesChanged = true;
503 if (device.getOutputMode() != null) {
504 properties.put(DigitalSTROMBindingConstants.DEVICE_OUTPUT_MODE, device.getOutputMode().toString());
505 propertiesChanged = true;
507 if (device.getFunctionalColorGroup() != null) {
508 properties.put(DigitalSTROMBindingConstants.DEVICE_FUNCTIONAL_COLOR_GROUP,
509 device.getFunctionalColorGroup().toString());
510 propertiesChanged = true;
512 if (device.getMeterDSID() != null) {
513 properties.put(DigitalSTROMBindingConstants.DEVICE_METER_ID, device.getMeterDSID().toString());
514 propertiesChanged = true;
516 if (!device.getBinaryInputs().isEmpty()) {
517 properties.put(DigitalSTROMBindingConstants.DEVICE_BINARAY_INPUTS, getBinarayInputList());
518 propertiesChanged = true;
520 if (propertiesChanged) {
521 super.updateProperties(properties);
522 propertiesChanged = false;
526 private String getBinarayInputList() {
527 List<String> binarayInputs = new ArrayList<>(device.getBinaryInputs().size());
528 for (DeviceBinaryInput binInput : device.getBinaryInputs()) {
529 DeviceBinarayInputEnum devBinInp = DeviceBinarayInputEnum.getdeviceBinarayInput(binInput.getInputType());
530 if (devBinInp != null) {
531 binarayInputs.add(devBinInp.toString().toLowerCase());
534 return binarayInputs.toString();
537 private void loadSensorChannels() {
538 if (device != null && device.isPresent()) {
539 // load sensor priorities into the device
540 boolean configChanged = false;
541 Configuration config = getThing().getConfiguration();
542 logger.debug("Add sensor priorities to the device");
544 String activePowerPrio = Config.REFRESH_PRIORITY_NEVER;
545 if (config.get(DigitalSTROMBindingConstants.ACTIVE_POWER_REFRESH_PRIORITY) != null) {
546 activePowerPrio = config.get(DigitalSTROMBindingConstants.ACTIVE_POWER_REFRESH_PRIORITY).toString();
548 config.put(DigitalSTROMBindingConstants.ACTIVE_POWER_REFRESH_PRIORITY, Config.REFRESH_PRIORITY_NEVER);
549 configChanged = true;
551 // By devices with output mode WIPE the active power always will be read out to check, if the device is not
552 // in standby any more.
553 if (OutputModeEnum.WIPE.equals(device.getOutputMode())
554 && activePowerPrio.equals(Config.REFRESH_PRIORITY_NEVER)) {
555 config.put(DigitalSTROMBindingConstants.ACTIVE_POWER_REFRESH_PRIORITY, Config.REFRESH_PRIORITY_LOW);
556 configChanged = true;
559 String outputCurrentPrio = Config.REFRESH_PRIORITY_NEVER;
560 if (config.get(DigitalSTROMBindingConstants.OUTPUT_CURRENT_REFRESH_PRIORITY) != null) {
561 outputCurrentPrio = config.get(DigitalSTROMBindingConstants.OUTPUT_CURRENT_REFRESH_PRIORITY).toString();
563 config.put(DigitalSTROMBindingConstants.OUTPUT_CURRENT_REFRESH_PRIORITY, Config.REFRESH_PRIORITY_NEVER);
564 configChanged = true;
567 String electricMeterPrio = Config.REFRESH_PRIORITY_NEVER;
568 if (config.get(DigitalSTROMBindingConstants.ELECTRIC_METER_REFRESH_PRIORITY) != null) {
569 electricMeterPrio = config.get(DigitalSTROMBindingConstants.ELECTRIC_METER_REFRESH_PRIORITY).toString();
571 config.put(DigitalSTROMBindingConstants.ELECTRIC_METER_REFRESH_PRIORITY, Config.REFRESH_PRIORITY_NEVER);
572 configChanged = true;
576 super.updateConfiguration(config);
577 configChanged = false;
580 device.setSensorDataRefreshPriority(activePowerPrio, electricMeterPrio, outputCurrentPrio);
582 "add sensor prioritys: active power = {}, output current = {}, electric meter = {} to device with id {}",
583 activePowerPrio, outputCurrentPrio, electricMeterPrio, device.getDSID());
585 // check and load sensor channels of the thing
586 checkSensorChannel();
590 private boolean addLoadedSensorChannel(String sensorChannelType) {
591 if (loadedSensorChannels == null) {
592 loadedSensorChannels = new LinkedList<>();
594 if (!loadedSensorChannels.contains(sensorChannelType.toString())) {
595 return loadedSensorChannels.add(sensorChannelType.toString());
600 private boolean removeLoadedSensorChannel(String sensorChannelType) {
601 if (loadedSensorChannels == null) {
604 return loadedSensorChannels.remove(sensorChannelType);
607 private boolean isSensorChannelLoaded(String sensorChannelType) {
608 if (loadedSensorChannels == null) {
611 return loadedSensorChannels.contains(sensorChannelType);
614 private void checkSensorChannel() {
615 List<Channel> channelList = new LinkedList<>(this.getThing().getChannels());
617 boolean channelListChanged = false;
619 // if sensor channels with priority never are loaded delete these channels
620 if (!channelList.isEmpty()) {
621 Iterator<Channel> channelInter = channelList.iterator();
622 while (channelInter.hasNext()) {
623 Channel channel = channelInter.next();
624 String channelID = channel.getUID().getId();
625 if (channelID.startsWith(DsChannelTypeProvider.BINARY_INPUT_PRE)) {
626 DeviceBinarayInputEnum devBinInput = getBinaryInput(channelID);
627 if (device.getBinaryInput(devBinInput) != null) {
628 addLoadedSensorChannel(channelID);
630 logger.debug("remove {} binary input channel", channelID);
631 channelInter.remove();
632 channelListChanged = removeLoadedSensorChannel(channelID);
635 SensorEnum sensorType = getSensorEnum(channelID);
636 if (sensorType != null) {
637 if (SensorEnum.isPowerSensor(sensorType)) {
638 if (device.checkPowerSensorRefreshPriorityNever(sensorType)) {
639 logger.debug("remove {} sensor channel", channelID);
640 channelInter.remove();
641 channelListChanged = removeLoadedSensorChannel(channelID);
643 addLoadedSensorChannel(channelID);
646 if (device.supportsSensorType(sensorType)) {
647 addLoadedSensorChannel(channelID);
649 logger.debug("remove {} sensor channel", channelID);
650 channelInter.remove();
651 removeLoadedSensorChannel(channelID);
652 channelListChanged = true;
659 for (SensorEnum sensorType : device.getPowerSensorTypes()) {
660 if (!device.checkPowerSensorRefreshPriorityNever(sensorType)
661 && !isSensorChannelLoaded(getSensorChannelID(sensorType))) {
662 logger.debug("create {} sensor channel", sensorType.toString());
663 channelList.add(getSensorChannel(sensorType));
664 channelListChanged = addLoadedSensorChannel(getSensorChannelID(sensorType));
667 if (device.hasClimateSensors()) {
668 for (SensorEnum sensorType : device.getClimateSensorTypes()) {
669 if (!isSensorChannelLoaded(getSensorChannelID(sensorType))) {
670 logger.debug("create {} sensor channel", sensorType.toString());
671 channelList.add(getSensorChannel(sensorType));
672 channelListChanged = addLoadedSensorChannel(getSensorChannelID(sensorType));
676 if (device.isBinaryInputDevice()) {
677 for (DeviceBinaryInput binInput : device.getBinaryInputs()) {
678 DeviceBinarayInputEnum binInputType = DeviceBinarayInputEnum
679 .getdeviceBinarayInput(binInput.getInputType());
680 if (binInputType != null && !isSensorChannelLoaded(getBinaryInputChannelID(binInputType))) {
681 logger.debug("create {} sensor channel", binInputType.toString());
682 channelList.add(getBinaryChannel(binInputType));
683 channelListChanged = addLoadedSensorChannel(getBinaryInputChannelID(binInputType));
688 if (channelListChanged) {
689 logger.debug("load new channel list");
690 ThingBuilder thingBuilder = editThing();
691 thingBuilder.withChannels(channelList);
692 updateThing(thingBuilder.build());
696 private Channel getSensorChannel(SensorEnum sensorType) {
697 return ChannelBuilder.create(getSensorChannelUID(sensorType), "Number")
698 .withType(DsChannelTypeProvider.getSensorChannelUID(sensorType)).build();
701 private Channel getBinaryChannel(DeviceBinarayInputEnum binaryInputType) {
702 return ChannelBuilder.create(getBinaryInputChannelUID(binaryInputType), "Switch")
703 .withType(DsChannelTypeProvider.getBinaryInputChannelUID(binaryInputType)).build();
706 private void checkOutputChannel() {
707 if (device == null) {
708 logger.debug("Can not load a channel without a device!");
711 // if the device have no output channel or it is disabled all output channels will be deleted
712 if (!device.isDeviceWithOutput()) {
713 loadOutputChannel(null, null);
715 String channelTypeID = DsChannelTypeProvider.getOutputChannelTypeID(device.getFunctionalColorGroup(),
716 device.getOutputMode());
717 logger.debug("load channel: typeID={}, itemType={}",
718 DsChannelTypeProvider.getOutputChannelTypeID(device.getFunctionalColorGroup(), device.getOutputMode()),
719 DsChannelTypeProvider.getItemType(channelTypeID));
720 if (channelTypeID != null && (currentChannel == null || !currentChannel.equals(channelTypeID))) {
721 loadOutputChannel(new ChannelTypeUID(BINDING_ID, channelTypeID),
722 DsChannelTypeProvider.getItemType(channelTypeID));
726 private void loadOutputChannel(ChannelTypeUID channelTypeUID, String acceptedItemType) {
727 if (channelTypeUID == null || acceptedItemType == null) {
730 currentChannel = channelTypeUID.getId();
732 List<Channel> channelList = new LinkedList<>(this.getThing().getChannels());
733 boolean channelIsAlreadyLoaded = false;
734 boolean channelListChanged = false;
736 if (!channelList.isEmpty()) {
737 Iterator<Channel> channelInter = channelList.iterator();
738 while (channelInter.hasNext()) {
739 Channel channel = channelInter.next();
740 if (DsChannelTypeProvider.isOutputChannel(channel.getUID().getId())) {
741 if (!channel.getUID().getId().equals(currentChannel)
742 && !(device.isShade() && channel.getUID().getId().equals(DsChannelTypeProvider.SHADE))) {
743 channelInter.remove();
744 channelListChanged = true;
746 if (!channel.getUID().getId().equals(DsChannelTypeProvider.SHADE)) {
747 channelIsAlreadyLoaded = true;
754 if (!channelIsAlreadyLoaded && currentChannel != null) {
755 Channel channel = ChannelBuilder
756 .create(new ChannelUID(this.getThing().getUID(), channelTypeUID.getId()), acceptedItemType)
757 .withType(channelTypeUID).build();
758 channelList.add(channel);
759 channelListChanged = true;
762 if (channelListChanged) {
763 ThingBuilder thingBuilder = editThing();
764 thingBuilder.withChannels(channelList);
765 updateThing(thingBuilder.build());
766 logger.debug("load channel: {} with item: {}", channelTypeUID.getAsString(), acceptedItemType);
770 private ChannelUID getSensorChannelUID(SensorEnum sensorType) {
771 return new ChannelUID(getThing().getUID(), getSensorChannelID(sensorType));
774 private String getSensorChannelID(SensorEnum sensorType) {
775 return sensorType.toString().toLowerCase();
778 private ChannelUID getBinaryInputChannelUID(DeviceBinarayInputEnum binaryInputType) {
779 return new ChannelUID(getThing().getUID(), getBinaryInputChannelID(binaryInputType));
782 private String getBinaryInputChannelID(DeviceBinarayInputEnum binaryInputType) {
783 return DsChannelTypeProvider.BINARY_INPUT_PRE + binaryInputType.toString().toLowerCase();
786 private DeviceBinarayInputEnum getBinaryInput(String channelID) {
788 return DeviceBinarayInputEnum
789 .valueOf(channelID.replace(DsChannelTypeProvider.BINARY_INPUT_PRE, "").toUpperCase());
790 } catch (IllegalArgumentException e) {
795 private SensorEnum getSensorEnum(String channelID) {
797 return SensorEnum.valueOf(channelID.toUpperCase());
798 } catch (IllegalArgumentException e) {
804 public void channelLinked(ChannelUID channelUID) {
805 if (device != null) {
806 SensorEnum sensorType = getSensorEnum(channelUID.getId());
807 if (sensorType != null) {
808 Float val = device.getFloatSensorValue(sensorType);
810 updateState(channelUID, new DecimalType(val));
813 Short val = device.getBinaryInputState(getBinaryInput(channelUID.getId()));
816 updateState(channelUID, OnOffType.ON);
818 updateState(channelUID, OnOffType.OFF);
822 if (channelUID.getId().contains(DsChannelTypeProvider.DIMMER)) {
824 updateState(channelUID,
825 new PercentType(fromValueToPercent(device.getOutputValue(), device.getMaxOutputValue())));
827 updateState(channelUID, new PercentType(0));
831 if (channelUID.getId().contains(DsChannelTypeProvider.SWITCH)) {
833 updateState(channelUID, OnOffType.ON);
835 updateState(channelUID, OnOffType.OFF);
839 if (channelUID.getId().contains(DsChannelTypeProvider.SHADE)) {
840 updateState(channelUID,
841 new PercentType(fromValueToPercent(device.getSlatPosition(), device.getMaxSlatPosition())));
844 if (channelUID.getId().contains(DsChannelTypeProvider.ANGLE)) {
845 updateState(channelUID,
846 new PercentType(fromValueToPercent(device.getAnglePosition(), device.getMaxSlatAngle())));
849 if (channelUID.getId().contains(DsChannelTypeProvider.STAGE)) {
850 if (channelUID.getId().contains(TWO_STAGE_SWITCH_IDENTICATOR)) {
851 updateState(channelUID, new StringType(convertStageValue((short) 2, device.getOutputValue())));
854 if (channelUID.getId().contains(THREE_STAGE_SWITCH_IDENTICATOR)) {
855 updateState(channelUID, new StringType(convertStageValue((short) 3, device.getOutputValue())));
862 private String convertStageValue(short stage, short value) {
866 return OPTION_COMBINED_BOTH_OFF;
867 } else if (value >= 85 && value < 170) {
868 return OPTION_COMBINED_FIRST_ON;
869 } else if (value >= 170 && value <= 255) {
870 return OPTION_COMBINED_BOTH_ON;
874 return OPTION_COMBINED_BOTH_OFF;
875 } else if (value >= 64 && value < 128) {
876 return OPTION_COMBINED_FIRST_ON;
877 } else if (value >= 128 && value < 192) {
878 return OPTION_COMBINED_SECOND_ON;
879 } else if (value >= 192 && value <= 255) {
880 return OPTION_COMBINED_BOTH_ON;
886 private void onDeviceStateInitial(Device device) {
887 if (device != null) {
888 if (currentChannel != null) {
889 if (isLinked(currentChannel)) {
890 channelLinked(new ChannelUID(getThing().getUID(), currentChannel));
893 if (!device.isShade()) {
894 if (loadedSensorChannels != null) {
895 for (String sensor : loadedSensorChannels) {
896 Channel channel = getThing().getChannel(sensor);
897 if (channel != null && isLinked(sensor)) {
898 channelLinked(channel.getUID());
903 if (isLinked(DsChannelTypeProvider.SHADE)) {
904 channelLinked(new ChannelUID(getThing().getUID(), DsChannelTypeProvider.SHADE));
911 public synchronized void onSceneConfigAdded(short sceneId) {
912 if (device != null) {
913 String saveScene = "";
914 DeviceSceneSpec sceneSpec = device.getSceneConfig(sceneId);
915 if (sceneSpec != null) {
916 saveScene = sceneSpec.toString();
919 Integer[] sceneValue = device.getSceneOutputValue(sceneId);
920 if (sceneValue[GeneralLibConstance.SCENE_ARRAY_INDEX_VALUE] != -1) {
921 saveScene = saveScene + ", sceneValue: " + sceneValue[0];
923 if (sceneValue[GeneralLibConstance.SCENE_ARRAY_INDEX_ANGLE] != -1) {
924 saveScene = saveScene + ", sceneAngle: " + sceneValue[1];
926 String key = DigitalSTROMBindingConstants.DEVICE_SCENE + sceneId;
927 if (!saveScene.isEmpty()) {
928 logger.debug("Save scene configuration: [{}] to thing with UID {}", saveScene, getThing().getUID());
929 super.updateProperty(key, saveScene);
930 // persist the new property
931 // super.updateThing(editThing().build());
937 public void onDeviceConfigChanged(ChangeableDeviceConfigEnum whichConfig) {
938 if (whichConfig != null) {
939 switch (whichConfig) {
941 super.updateProperty(DEVICE_NAME, device.getName());
944 super.updateProperty(DEVICE_METER_ID, device.getMeterDSID().getValue());
947 super.updateProperty(DEVICE_ZONE_ID, device.getZoneId() + "");
950 super.updateProperty(DEVICE_GROUPS, device.getGroups().toString());
952 case FUNCTIONAL_GROUP:
953 super.updateProperty(DEVICE_FUNCTIONAL_COLOR_GROUP, device.getFunctionalColorGroup().toString());
954 checkOutputChannel();
957 super.updateProperty(DEVICE_OUTPUT_MODE, device.getOutputMode().toString());
958 checkOutputChannel();
961 super.updateProperty(DEVICE_BINARAY_INPUTS, getBinarayInputList());
962 checkSensorChannel();
971 public String getDeviceStatusListenerID() {