/**
* Copyright (c) 2014-2017 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.smarthome.binding.digitalstrom.handler;
import static org.eclipse.smarthome.binding.digitalstrom.DigitalSTROMBindingConstants.*;
import java.math.BigDecimal;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.eclipse.smarthome.binding.digitalstrom.DigitalSTROMBindingConstants;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.Device;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.ChangeableDeviceConfigEnum;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.DeviceSceneSpec;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.DeviceStateUpdate;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.DeviceStateUpdateImpl;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.FunctionalColorGroupEnum;
import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.OutputModeEnum;
import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.library.types.IncreaseDecreaseType;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.library.types.PercentType;
import org.eclipse.smarthome.core.library.types.StopMoveType;
import org.eclipse.smarthome.core.library.types.StringType;
import org.eclipse.smarthome.core.library.types.UpDownType;
import org.eclipse.smarthome.core.thing.Bridge;
import org.eclipse.smarthome.core.thing.Channel;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.thing.ThingStatus;
import org.eclipse.smarthome.core.thing.ThingStatusDetail;
import org.eclipse.smarthome.core.thing.ThingStatusInfo;
import org.eclipse.smarthome.core.thing.ThingTypeUID;
import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
import org.eclipse.smarthome.core.thing.binding.ThingHandler;
import org.eclipse.smarthome.core.thing.binding.builder.ChannelBuilder;
import org.eclipse.smarthome.core.thing.binding.builder.ThingBuilder;
import org.eclipse.smarthome.core.thing.type.ChannelTypeUID;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Sets;
/**
* The {@link DeviceHandler} is responsible for handling the configuration, load supported channels of a
* digitalSTROM device and handling commands, which are sent to one of the channels. <br>
* <br>
* For that it uses the {@link BridgeHandler} and the {@link DeviceStateUpdate} mechanism of the {@link Device} to
* execute the actual command and implements the {@link DeviceStatusListener} to get informed about changes from the
* accompanying {@link Device}.
*
* @author Michael Ochel - Initial contribution
* @author Matthias Siegele - Initial contribution
*
*/
public class DeviceHandler extends BaseThingHandler implements DeviceStatusListener {
private Logger logger = LoggerFactory.getLogger(DeviceHandler.class);
public final static Set<ThingTypeUID> SUPPORTED_THING_TYPES = Sets.newHashSet(
DigitalSTROMBindingConstants.THING_TYPE_GE_DEVICE, DigitalSTROMBindingConstants.THING_TYPE_SW_DEVICE,
DigitalSTROMBindingConstants.THING_TYPE_GR_DEVICE);
private String dSID = null;
private Device device;
private BridgeHandler dssBridgeHandler;
private Command lastComand = null;
private String currentChannel = null;
private boolean isActivePowerChannelLoaded = false;
private boolean isOutputCurrentChannelLoaded = false;
private boolean isElectricMeterChannelLoaded = false;
public DeviceHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
logger.debug("Initializing DeviceHandler.");
if (StringUtils.isNotBlank((String) getConfig().get(DigitalSTROMBindingConstants.DEVICE_DSID))) {
dSID = getConfig().get(DigitalSTROMBindingConstants.DEVICE_DSID).toString();
if (getBridge() != null) {
bridgeStatusChanged(getBridge().getStatusInfo());
} else {
// Set status to OFFLINE if no bridge is available e.g. because the bridge has been removed and the
// Thing was reinitialized.
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge is missing!");
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "dSID is missing");
}
}
@Override
public void dispose() {
logger.debug("Handler disposed... unregister DeviceStatusListener");
if (dSID != null) {
if (dssBridgeHandler != null) {
dssBridgeHandler.unregisterDeviceStatusListener(this);
}
}
if (device != null) {
device.setSensorDataRefreshPriority(REFRESH_PRIORITY_NEVER, REFRESH_PRIORITY_NEVER, REFRESH_PRIORITY_NEVER);
}
device = null;
}
@Override
public void handleRemoval() {
if (getDssBridgeHandler() != null) {
this.dssBridgeHandler.childThingRemoved(dSID);
}
updateStatus(ThingStatus.REMOVED);
}
@Override
public void thingUpdated(Thing thing) {
this.thing = thing;
if (device == null) {
initialize();
}
}
@Override
public void handleConfigurationUpdate(Map<String, Object> configurationParmeters) {
Configuration configuration = editConfiguration();
for (Entry<String, Object> configurationParmeter : configurationParmeters.entrySet()) {
configuration.put(configurationParmeter.getKey(), configurationParmeter.getValue());
}
// check device info, load sensor priorities into the device and load sensor channels of the thing
checkDeviceInfoConfig(configuration, device);
loadSensorChannels(configuration);
updateConfiguration(configuration);
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
if (bridgeStatusInfo.getStatus().equals(ThingStatus.ONLINE)) {
if (dSID != null) {
if (getDssBridgeHandler() != null) {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
"waiting for listener registration");
logger.debug("Set status to {}", getThing().getStatus());
dssBridgeHandler.registerDeviceStatusListener(this);
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No dSID is set!");
}
}
if (bridgeStatusInfo.getStatus().equals(ThingStatus.OFFLINE)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
}
if (bridgeStatusInfo.getStatus().equals(ThingStatus.REMOVED)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Bridge has been removed.");
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
BridgeHandler dssBridgeHandler = getDssBridgeHandler();
if (dssBridgeHandler == null) {
logger.warn("BridgeHandler not found. Cannot handle command without bridge.");
return;
}
if (device == null) {
logger.warn(
"Device not known on StructureManager or DeviceStatusListener is not registerd. Cannot handle command.");
return;
}
if (command instanceof RefreshType) {
switch (channelUID.getId()) {
case CHANNEL_ID_ACTIVE_POWER:
dssBridgeHandler.sendComandsToDSS(device,
new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_ACTIVE_POWER, 1));
break;
case CHANNEL_ID_OUTPUT_CURRENT:
dssBridgeHandler.sendComandsToDSS(device,
new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_OUTPUT_CURRENT, 1));
break;
case CHANNEL_ID_ELECTRIC_METER:
dssBridgeHandler.sendComandsToDSS(device,
new DeviceStateUpdateImpl(DeviceStateUpdate.UPDATE_ELECTRIC_METER, 1));
break;
default:
dssBridgeHandler.sendComandsToDSS(device,
new DeviceStateUpdateImpl(DeviceStateUpdate.REFRESH_OUTPUT, 0));
break;
}
} else if (!device.isShade()) {
if (this.channelIsOutputChannel(channelUID.getId())) {
if (command instanceof PercentType) {
device.setOutputValue(
(short) fromPercentToValue(((PercentType) command).intValue(), device.getMaxOutputValue()));
} else if (command instanceof OnOffType) {
if (OnOffType.ON.equals(command)) {
device.setIsOn(true);
} else {
device.setIsOn(false);
}
} else if (command instanceof IncreaseDecreaseType) {
if (IncreaseDecreaseType.INCREASE.equals(command)) {
device.increase();
} else {
device.decrease();
}
} else if (command instanceof StringType) {
device.setOutputValue(Short.parseShort(((StringType) command).toString()));
}
} else {
logger.warn("Command sent to an unknown channel id: " + channelUID);
}
} else {
if (channelUID.getId().equals(CHANNEL_ID_SHADE_ANGLE)) {
if (command instanceof PercentType) {
device.setAnglePosition(
(short) fromPercentToValue(((PercentType) command).intValue(), device.getMaxSlatAngle()));
} else if (command instanceof OnOffType) {
if (OnOffType.ON.equals(command)) {
device.setAnglePosition(device.getMaxSlatAngle());
} else {
device.setAnglePosition(device.getMinSlatAngle());
}
} else if (command instanceof IncreaseDecreaseType) {
if (IncreaseDecreaseType.INCREASE.equals(command)) {
device.increaseSlatAngle();
} else {
device.decreaseSlatAngle();
}
}
} else if (channelUID.getId().equals(DigitalSTROMBindingConstants.CHANNEL_ID_SHADE)) {
if (command instanceof PercentType) {
int percent = ((PercentType) command).intValue();
if (!device.getHWinfo().equals("GR-KL200")) {
percent = 100 - percent;
}
device.setSlatPosition(fromPercentToValue(percent, device.getMaxSlatPosition()));
this.lastComand = command;
} else if (command instanceof StopMoveType) {
if (StopMoveType.MOVE.equals(command)) {
handleCommand(channelUID, this.lastComand);
} else {
dssBridgeHandler.stopOutputValue(device);
}
} else if (command instanceof UpDownType) {
if (UpDownType.UP.equals(command)) {
device.setIsOpen(true);
this.lastComand = command;
} else {
device.setIsOpen(false);
this.lastComand = command;
}
}
} else {
logger.warn("Command sent to an unknown channel id: " + channelUID);
}
}
}
private int fromPercentToValue(int percent, int max) {
if (percent < 0 || percent == 0) {
return 0;
}
if (max < 0 || max == 0) {
return 0;
}
return (int) (max * ((float) percent / 100));
}
private synchronized BridgeHandler getDssBridgeHandler() {
if (this.dssBridgeHandler == null) {
Bridge bridge = getBridge();
if (bridge == null) {
logger.debug("Bride cannot be found");
return null;
}
ThingHandler handler = bridge.getHandler();
if (handler instanceof BridgeHandler) {
dssBridgeHandler = (BridgeHandler) handler;
dssBridgeHandler.registerDeviceStatusListener(this);
} else {
return null;
}
}
return dssBridgeHandler;
}
@Override
public synchronized void onDeviceStateChanged(DeviceStateUpdate deviceStateUpdate) {
if (device != null) {
if (deviceStateUpdate != null) {
logger.debug("Update ESH-State");
if (!device.isShade()) {
switch (deviceStateUpdate.getType()) {
case DeviceStateUpdate.UPDATE_BRIGHTNESS_DECREASE:
case DeviceStateUpdate.UPDATE_BRIGHTNESS_INCREASE:
case DeviceStateUpdate.UPDATE_BRIGHTNESS:
switch (currentChannel) {
case CHANNEL_ID_COMBINED_2_STAGE_SWITCH:
case CHANNEL_ID_GENERAL_COMBINED_2_STAGE_SWITCH:
updateState(new ChannelUID(getThing().getUID(), currentChannel),
new StringType(convertStageValue((short) 2, device.getOutputValue())));
break;
case CHANNEL_ID_COMBINED_3_STAGE_SWITCH:
case CHANNEL_ID_GENERAL_COMBINED_3_STAGE_SWITCH:
updateState(new ChannelUID(getThing().getUID(), currentChannel),
new StringType(convertStageValue((short) 3, device.getOutputValue())));
break;
case CHANNEL_ID_BRIGHTNESS:
case CHANNEL_ID_GENERAL_DIMM:
if (deviceStateUpdate.getValue() > 0) {
updateState(new ChannelUID(getThing().getUID(), currentChannel),
new PercentType(fromValueToPercent(deviceStateUpdate.getValue(),
device.getMaxOutputValue())));
} else {
updateState(new ChannelUID(getThing().getUID(), currentChannel), OnOffType.OFF);
}
break;
}
break;
case DeviceStateUpdate.UPDATE_ON_OFF:
switch (currentChannel) {
case CHANNEL_ID_COMBINED_2_STAGE_SWITCH:
case CHANNEL_ID_GENERAL_COMBINED_2_STAGE_SWITCH:
updateState(new ChannelUID(getThing().getUID(), currentChannel),
new StringType(convertStageValue((short) 2, device.getOutputValue())));
break;
case CHANNEL_ID_COMBINED_3_STAGE_SWITCH:
case CHANNEL_ID_GENERAL_COMBINED_3_STAGE_SWITCH:
updateState(new ChannelUID(getThing().getUID(), currentChannel),
new StringType(convertStageValue((short) 3, device.getOutputValue())));
break;
default:
if (deviceStateUpdate.getValue() > 0) {
updateState(new ChannelUID(getThing().getUID(), currentChannel), OnOffType.ON);
} else {
updateState(new ChannelUID(getThing().getUID(), currentChannel), OnOffType.OFF);
}
}
break;
case DeviceStateUpdate.UPDATE_ELECTRIC_METER:
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_ELECTRIC_METER),
new DecimalType(deviceStateUpdate.getValue() * 0.01));
break;
case DeviceStateUpdate.UPDATE_OUTPUT_CURRENT:
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_OUTPUT_CURRENT),
new DecimalType(deviceStateUpdate.getValue()));
break;
case DeviceStateUpdate.UPDATE_ACTIVE_POWER:
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_ACTIVE_POWER),
new DecimalType(deviceStateUpdate.getValue()));
break;
default:
return;
}
} else {
int percent = 0;
switch (deviceStateUpdate.getType()) {
case DeviceStateUpdate.UPDATE_SLAT_DECREASE:
case DeviceStateUpdate.UPDATE_SLAT_INCREASE:
case DeviceStateUpdate.UPDATE_SLATPOSITION:
percent = fromValueToPercent(deviceStateUpdate.getValue(), device.getMaxSlatPosition());
break;
case DeviceStateUpdate.UPDATE_OPEN_CLOSE:
if (deviceStateUpdate.getValue() > 0) {
percent = 100;
}
break;
case DeviceStateUpdate.UPDATE_OPEN_CLOSE_ANGLE:
if (device.isBlind()) {
if (deviceStateUpdate.getValue() > 0) {
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_SHADE_ANGLE),
PercentType.HUNDRED);
} else {
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_SHADE_ANGLE),
PercentType.ZERO);
}
}
return;
case DeviceStateUpdate.UPDATE_SLAT_ANGLE_DECREASE:
case DeviceStateUpdate.UPDATE_SLAT_ANGLE_INCREASE:
case DeviceStateUpdate.UPDATE_SLAT_ANGLE:
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_SHADE_ANGLE), new PercentType(
fromValueToPercent(deviceStateUpdate.getValue(), device.getMaxSlatAngle())));
return;
default:
return;
}
if (!device.getHWinfo().equals("GR-KL210")) {
percent = 100 - percent;
}
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_SHADE), new PercentType(percent));
}
}
}
}
private int fromValueToPercent(int value, int max) {
if (value <= 0 || max <= 0) {
return 0;
}
return new BigDecimal(value * ((float) 100 / max)).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
}
@Override
public synchronized void onDeviceRemoved(Device device) {
this.device = null;
if (this.getThing().getStatus().equals(ThingStatus.ONLINE)) {
if (device != null && !device.isPresent()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
"Device is not present in the digitalSTROM-System.");
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
"Device is not avaible in the digitalSTROM-System.");
}
}
logger.debug("Set status to {}", getThing().getStatus());
}
@Override
public synchronized void onDeviceAdded(Device device) {
if (device.isPresent()) {
this.device = device;
ThingStatusInfo statusInfo = this.dssBridgeHandler.getThing().getStatusInfo();
updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
logger.debug("Set status to {}", getThing().getStatus());
Configuration config = getThing().getConfiguration();
checkDeviceInfoConfig(config, device);
// load sensor priorities into the device and load sensor channels of the thing
if (!device.isShade()) {
loadSensorChannels(config);
// check and load output channel of the thing
checkOutputChannel();
} else if (device.isBlind()) {
// load channel for set the angle of jalousie devices
loadOutputChannel(CHANNEL_TYPE_SHADE_ANGLE, "Dimmer");
}
// load first channel values
onDeviceStateInitial(device);
// load scene configurations persistently into the thing
for (Short i : device.getSavedScenes()) {
onSceneConfigAdded(i);
}
device.saveConfigSceneSpecificationIntoDevice(this.getThing().getProperties());
logger.debug("Load saved scene specification into device");
} else {
onDeviceRemoved(device);
}
}
/**
* Checks the configuration and add missing configuration.
*
* @param thing configuration (must not be null)
* @param device (must not be null)
*/
private void checkDeviceInfoConfig(Configuration config, Device device) {
boolean configChanged = false;
// check device info
if (config.get(DigitalSTROMBindingConstants.DEVICE_NAME) == null
|| config.get(DigitalSTROMBindingConstants.DEVICE_NAME).toString().isEmpty()) {
if (device.getName() != null) {
config.put(DigitalSTROMBindingConstants.DEVICE_NAME, device.getName());
configChanged = true;
}
}
if (config.get(DigitalSTROMBindingConstants.DEVICE_UID) == null
|| config.get(DigitalSTROMBindingConstants.DEVICE_UID).toString().isEmpty()) {
if (device.getDSUID() != null) {
config.put(DigitalSTROMBindingConstants.DEVICE_UID, device.getDSUID());
configChanged = true;
}
}
if (config.get(DigitalSTROMBindingConstants.DEVICE_HW_INFO) == null
|| config.get(DigitalSTROMBindingConstants.DEVICE_HW_INFO).toString().isEmpty()) {
if (device.getHWinfo() != null) {
config.put(DigitalSTROMBindingConstants.DEVICE_HW_INFO, device.getHWinfo());
configChanged = true;
}
}
if (config.get(DigitalSTROMBindingConstants.DEVICE_ZONE_ID) == null
|| config.get(DigitalSTROMBindingConstants.DEVICE_ZONE_ID).toString().isEmpty()) {
if (device.getZoneId() != -1) {
config.put(DigitalSTROMBindingConstants.DEVICE_ZONE_ID, device.getZoneId());
configChanged = true;
}
}
if (config.get(DigitalSTROMBindingConstants.DEVICE_GROUPS) == null
|| config.get(DigitalSTROMBindingConstants.DEVICE_GROUPS).toString().isEmpty()) {
if (device.getGroups() != null) {
config.put(DigitalSTROMBindingConstants.DEVICE_GROUPS, device.getGroups().toString());
configChanged = true;
}
}
if (config.get(DigitalSTROMBindingConstants.DEVICE_OUTPUT_MODE) == null
|| config.get(DigitalSTROMBindingConstants.DEVICE_OUTPUT_MODE).toString().isEmpty()) {
if (device.getOutputMode() != null) {
config.put(DigitalSTROMBindingConstants.DEVICE_OUTPUT_MODE, device.getOutputMode().toString());
configChanged = true;
}
}
if (config.get(DigitalSTROMBindingConstants.DEVICE_FUNCTIONAL_COLOR_GROUP) == null
|| config.get(DigitalSTROMBindingConstants.DEVICE_FUNCTIONAL_COLOR_GROUP).toString().isEmpty()) {
if (device.getFunctionalColorGroup() != null) {
config.put(DigitalSTROMBindingConstants.DEVICE_FUNCTIONAL_COLOR_GROUP,
device.getFunctionalColorGroup().toString());
configChanged = true;
}
}
if (config.get(DigitalSTROMBindingConstants.DEVICE_METER_ID) == null
|| config.get(DigitalSTROMBindingConstants.DEVICE_METER_ID).toString().isEmpty()) {
if (device.getMeterDSID() != null) {
config.put(DigitalSTROMBindingConstants.DEVICE_METER_ID, device.getMeterDSID().toString());
configChanged = true;
}
}
if (configChanged) {
super.updateConfiguration(config);
configChanged = false;
}
}
private void loadSensorChannels(Configuration config) {
if (device != null && device.isPresent()) {
// load sensor priorities into the device
boolean configChanged = false;
logger.debug("Add sensor priorities to the device");
String activePowerPrio = DigitalSTROMBindingConstants.REFRESH_PRIORITY_NEVER;
if (config.get(DigitalSTROMBindingConstants.ACTIVE_POWER_REFRESH_PRIORITY) != null) {
activePowerPrio = config.get(DigitalSTROMBindingConstants.ACTIVE_POWER_REFRESH_PRIORITY).toString();
} else {
config.put(DigitalSTROMBindingConstants.ACTIVE_POWER_REFRESH_PRIORITY,
DigitalSTROMBindingConstants.REFRESH_PRIORITY_NEVER);
configChanged = true;
}
String outputCurrentPrio = DigitalSTROMBindingConstants.REFRESH_PRIORITY_NEVER;
if (config.get(DigitalSTROMBindingConstants.OUTPUT_CURRENT_REFRESH_PRIORITY) != null) {
outputCurrentPrio = config.get(DigitalSTROMBindingConstants.OUTPUT_CURRENT_REFRESH_PRIORITY).toString();
} else {
config.put(DigitalSTROMBindingConstants.OUTPUT_CURRENT_REFRESH_PRIORITY,
DigitalSTROMBindingConstants.REFRESH_PRIORITY_NEVER);
configChanged = true;
}
String electricMeterPrio = DigitalSTROMBindingConstants.REFRESH_PRIORITY_NEVER;
if (config.get(DigitalSTROMBindingConstants.ELECTRIC_METER_REFRESH_PRIORITY) != null) {
electricMeterPrio = config.get(DigitalSTROMBindingConstants.ELECTRIC_METER_REFRESH_PRIORITY).toString();
} else {
config.put(DigitalSTROMBindingConstants.ELECTRIC_METER_REFRESH_PRIORITY,
DigitalSTROMBindingConstants.REFRESH_PRIORITY_NEVER);
configChanged = true;
}
if (configChanged) {
super.updateConfiguration(config);
configChanged = false;
}
device.setSensorDataRefreshPriority(activePowerPrio, electricMeterPrio, outputCurrentPrio);
logger.debug("add sensor prioritys: active power = " + activePowerPrio + ", output current = "
+ outputCurrentPrio + ", electric meter = " + electricMeterPrio + " to device with id "
+ device.getDSID());
// check and load sensor channels of the thing
checkSensorChannel(activePowerPrio, outputCurrentPrio, electricMeterPrio);
}
}
private void checkSensorChannel(String activePowerPrio, String outputCurrentPrio, String electricMeterPrio) {
List<Channel> channelList = new LinkedList<Channel>(this.getThing().getChannels());
boolean channelListChanged = false;
// if sensor channels with priority never are loaded delete these channels
if (!channelList.isEmpty()) {
Iterator<Channel> channelInter = channelList.iterator();
while (channelInter.hasNext()) {
Channel channel = channelInter.next();
switch (channel.getUID().getId()) {
case CHANNEL_ID_ACTIVE_POWER:
if (activePowerPrio.equals(REFRESH_PRIORITY_NEVER)) {
logger.debug("remove active power sensor channel");
channelInter.remove();
isActivePowerChannelLoaded = false;
channelListChanged = true;
} else {
isActivePowerChannelLoaded = true;
}
break;
case CHANNEL_ID_OUTPUT_CURRENT:
if (outputCurrentPrio.equals(REFRESH_PRIORITY_NEVER)) {
logger.debug("remove output current sensor channel");
channelInter.remove();
isOutputCurrentChannelLoaded = false;
channelListChanged = true;
} else {
isOutputCurrentChannelLoaded = true;
}
break;
case CHANNEL_ID_ELECTRIC_METER:
if (electricMeterPrio.equals(REFRESH_PRIORITY_NEVER)) {
logger.debug("remove eclectric meter sensor channel");
channelInter.remove();
isElectricMeterChannelLoaded = false;
channelListChanged = true;
} else {
isElectricMeterChannelLoaded = true;
}
break;
}
}
}
// if sensor channels with priority unequal never are not loaded these channels will be loaded now
if (!activePowerPrio.equals(REFRESH_PRIORITY_NEVER) && !isActivePowerChannelLoaded) {
logger.debug("create active power sensor channel");
Channel channel = ChannelBuilder
.create(new ChannelUID(this.getThing().getUID(), CHANNEL_ID_ACTIVE_POWER), "Number")
.withType(DigitalSTROMBindingConstants.CHANNEL_TYPE_ACTIVE_POWER).build();
channelList.add(channel);
isActivePowerChannelLoaded = true;
channelListChanged = true;
}
if (!outputCurrentPrio.equals(REFRESH_PRIORITY_NEVER) && !isOutputCurrentChannelLoaded) {
logger.debug("create output current sensor channel");
Channel channel = ChannelBuilder
.create(new ChannelUID(this.getThing().getUID(), CHANNEL_ID_OUTPUT_CURRENT), "Number")
.withType(DigitalSTROMBindingConstants.CHANNEL_TYPE_OUTPUT_CURRENT).build();
channelList.add(channel);
isOutputCurrentChannelLoaded = true;
channelListChanged = true;
}
if (!electricMeterPrio.equals(REFRESH_PRIORITY_NEVER) && !isElectricMeterChannelLoaded) {
logger.debug("create eclectric meter sensor channel");
Channel channel = ChannelBuilder
.create(new ChannelUID(this.getThing().getUID(), CHANNEL_ID_ELECTRIC_METER), "Number")
.withType(DigitalSTROMBindingConstants.CHANNEL_TYPE_ELECTRIC_METER).build();
channelList.add(channel);
isElectricMeterChannelLoaded = true;
channelListChanged = true;
}
if (channelListChanged) {
logger.debug("load new channel list");
ThingBuilder thingBuilder = editThing();
thingBuilder.withChannels(channelList);
updateThing(thingBuilder.build());
}
}
private void checkOutputChannel() {
if (device == null) {
logger.debug("Can not load a channel without a device!");
return;
}
// if the device have no output channel or it is disabled all output channels will be deleted
if (!device.isDeviceWithOutput()) {
loadOutputChannel(null, null);
}
if (device.getFunctionalColorGroup().equals(FunctionalColorGroupEnum.YELLOW)) {
if (device.isDimmable() && (currentChannel == null || currentChannel != CHANNEL_ID_BRIGHTNESS)) {
loadOutputChannel(CHANNEL_TYPE_BRIGHTNESS, "Dimmer");
} else if (device.isSwitch() && (currentChannel == null || currentChannel != CHANNEL_ID_LIGHT_SWITCH)) {
loadOutputChannel(CHANNEL_TYPE_LIGHT_SWITCH, "Switch");
} else if (device.getOutputMode().equals(OutputModeEnum.COMBINED_2_STAGE_SWITCH)
&& (currentChannel == null || currentChannel != CHANNEL_ID_COMBINED_2_STAGE_SWITCH)) {
loadOutputChannel(CHANNEL_TYPE_COMBINED_2_STAGE_SWITCH, "String");
} else if (device.getOutputMode().equals(OutputModeEnum.COMBINED_3_STAGE_SWITCH)
&& (currentChannel == null || currentChannel != CHANNEL_ID_COMBINED_3_STAGE_SWITCH)) {
loadOutputChannel(CHANNEL_TYPE_COMBINED_3_STAGE_SWITCH, "String");
}
} else {
if (device.isDimmable() && (currentChannel == null || currentChannel != CHANNEL_ID_GENERAL_DIMM)) {
loadOutputChannel(CHANNEL_TYPE_GENERAL_DIMM, "Dimmer");
} else if (device.isSwitch() && (currentChannel == null || currentChannel != CHANNEL_ID_GENERAL_SWITCH)) {
loadOutputChannel(CHANNEL_TYPE_GENERAL_SWITCH, "Switch");
} else if (device.getOutputMode().equals(OutputModeEnum.COMBINED_2_STAGE_SWITCH)
&& (currentChannel == null || currentChannel != CHANNEL_ID_GENERAL_COMBINED_2_STAGE_SWITCH)) {
loadOutputChannel(CHANNEL_TYPE_GENERAL_COMBINED_2_STAGE_SWITCH, "String");
} else if (device.getOutputMode().equals(OutputModeEnum.COMBINED_3_STAGE_SWITCH)
&& (currentChannel == null || currentChannel != CHANNEL_ID_GENERAL_COMBINED_3_STAGE_SWITCH)) {
loadOutputChannel(CHANNEL_TYPE_GENERAL_COMBINED_3_STAGE_SWITCH, "String");
} else {
loadOutputChannel(null, null);
}
}
}
private void loadOutputChannel(ChannelTypeUID channelTypeUID, String acceptedItemType) {
currentChannel = channelTypeUID.getId();
List<Channel> channelList = new LinkedList<Channel>(this.getThing().getChannels());
boolean channelIsAlreadyLoaded = false;
boolean channelListChanged = false;
if (!channelList.isEmpty()) {
Iterator<Channel> channelInter = channelList.iterator();
while (channelInter.hasNext()) {
Channel eshChannel = channelInter.next();
if (channelIsOutputChannel(eshChannel.getUID().getId())) {
if (!eshChannel.getUID().getId().equals(currentChannel)) {
channelInter.remove();
channelListChanged = true;
} else {
channelIsAlreadyLoaded = true;
}
}
}
}
if (!channelIsAlreadyLoaded && currentChannel != null) {
Channel channel = ChannelBuilder
.create(new ChannelUID(this.getThing().getUID(), channelTypeUID.getId()), acceptedItemType)
.withType(channelTypeUID).build();
channelList.add(channel);
channelListChanged = true;
}
if (channelListChanged) {
ThingBuilder thingBuilder = editThing();
thingBuilder.withChannels(channelList);
updateThing(thingBuilder.build());
logger.debug("load channel: {} with item: {}", channelTypeUID.getAsString(), acceptedItemType);
}
}
private boolean channelIsOutputChannel(String id) {
switch (id) {
case CHANNEL_ID_GENERAL_DIMM:
case CHANNEL_ID_GENERAL_SWITCH:
case CHANNEL_ID_BRIGHTNESS:
case CHANNEL_ID_LIGHT_SWITCH:
case CHANNEL_ID_SHADE_ANGLE:
case CHANNEL_ID_GENERAL_COMBINED_2_STAGE_SWITCH:
case CHANNEL_ID_GENERAL_COMBINED_3_STAGE_SWITCH:
case CHANNEL_ID_COMBINED_2_STAGE_SWITCH:
case CHANNEL_ID_COMBINED_3_STAGE_SWITCH:
return true;
default:
return false;
}
}
@Override
public void channelLinked(ChannelUID channelUID) {
if (device != null) {
switch (channelUID.getId()) {
case CHANNEL_ID_GENERAL_DIMM:
if (device.isOn()) {
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_GENERAL_DIMM), new PercentType(
fromValueToPercent(device.getOutputValue(), device.getMaxOutputValue())));
} else {
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_GENERAL_DIMM), new PercentType(0));
}
break;
case CHANNEL_ID_GENERAL_SWITCH:
if (device.isOn()) {
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_GENERAL_SWITCH), OnOffType.ON);
} else {
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_GENERAL_SWITCH), OnOffType.OFF);
}
break;
case CHANNEL_ID_BRIGHTNESS:
if (device.isOn()) {
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_BRIGHTNESS), new PercentType(
fromValueToPercent(device.getOutputValue(), device.getMaxOutputValue())));
} else {
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_BRIGHTNESS), new PercentType(0));
}
case CHANNEL_ID_LIGHT_SWITCH:
if (device.isOn()) {
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_LIGHT_SWITCH), OnOffType.ON);
} else {
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_LIGHT_SWITCH), OnOffType.OFF);
}
break;
case CHANNEL_ID_SHADE:
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_SHADE),
new PercentType(fromValueToPercent(device.getSlatPosition(), device.getMaxSlatPosition())));
break;
case CHANNEL_ID_SHADE_ANGLE:
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_SHADE_ANGLE),
new PercentType(fromValueToPercent(device.getAnglePosition(), device.getMaxSlatAngle())));
break;
case CHANNEL_ID_ELECTRIC_METER:
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_ELECTRIC_METER),
new DecimalType(device.getElectricMeter() * 0.01));
break;
case CHANNEL_ID_OUTPUT_CURRENT:
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_OUTPUT_CURRENT),
new DecimalType(device.getOutputCurrent()));
break;
case CHANNEL_ID_ACTIVE_POWER:
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_ACTIVE_POWER),
new DecimalType(device.getActivePower()));
break;
case CHANNEL_ID_GENERAL_COMBINED_2_STAGE_SWITCH:
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_GENERAL_COMBINED_2_STAGE_SWITCH),
new StringType(convertStageValue((short) 2, device.getOutputValue())));
break;
case CHANNEL_ID_GENERAL_COMBINED_3_STAGE_SWITCH:
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_GENERAL_COMBINED_3_STAGE_SWITCH),
new StringType(convertStageValue((short) 3, device.getOutputValue())));
break;
case CHANNEL_ID_COMBINED_2_STAGE_SWITCH:
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_COMBINED_2_STAGE_SWITCH),
new StringType(convertStageValue((short) 2, device.getOutputValue())));
break;
case CHANNEL_ID_COMBINED_3_STAGE_SWITCH:
updateState(new ChannelUID(getThing().getUID(), CHANNEL_ID_COMBINED_3_STAGE_SWITCH),
new StringType(convertStageValue((short) 3, device.getOutputValue())));
break;
default:
return;
}
}
}
private String convertStageValue(short stage, short value) {
switch (stage) {
case 2:
if (value < 85) {
return "0";
} else if (value >= 85 && value < 170) {
return "90";
} else if (value >= 170 && value <= 255) {
return "200";
}
case 3:
if (value < 64) {
return "0";
} else if (value >= 64 && value < 128) {
return "90";
} else if (value >= 128 && value < 192) {
return "130";
} else if (value >= 192 && value <= 255) {
return "200";
}
}
return null;
}
private void onDeviceStateInitial(Device device) {
if (device != null) {
if (currentChannel != null) {
if (isLinked(currentChannel)) {
channelLinked(new ChannelUID(getThing().getUID(), currentChannel));
}
}
if (!device.isShade()) {
if (isActivePowerChannelLoaded) {
if (getThing().getChannel(CHANNEL_ID_ACTIVE_POWER) != null && isLinked(CHANNEL_ID_ACTIVE_POWER)) {
channelLinked(new ChannelUID(getThing().getUID(), CHANNEL_ID_ACTIVE_POWER));
}
}
if (isOutputCurrentChannelLoaded) {
if (getThing().getChannel(CHANNEL_ID_OUTPUT_CURRENT) != null
&& isLinked(CHANNEL_ID_OUTPUT_CURRENT)) {
channelLinked(new ChannelUID(getThing().getUID(), CHANNEL_ID_OUTPUT_CURRENT));
}
}
if (isElectricMeterChannelLoaded) {
if (getThing().getChannel(CHANNEL_ID_ELECTRIC_METER) != null
&& isLinked(CHANNEL_ID_ELECTRIC_METER)) {
channelLinked(new ChannelUID(getThing().getUID(), CHANNEL_ID_ELECTRIC_METER));
}
}
} else {
if (isLinked(CHANNEL_ID_SHADE)) {
channelLinked(new ChannelUID(getThing().getUID(), CHANNEL_ID_SHADE));
}
}
}
}
@Override
public synchronized void onSceneConfigAdded(short sceneId) {
if (device != null) {
String saveScene = "";
DeviceSceneSpec sceneSpec = device.getSceneConfig(sceneId);
if (sceneSpec != null) {
saveScene = sceneSpec.toString();
}
Integer[] sceneValue = device.getSceneOutputValue(sceneId);
if (sceneValue[0] != -1) {
saveScene = saveScene + ", sceneValue: " + sceneValue[0];
}
if (sceneValue[1] != -1) {
saveScene = saveScene + ", sceneAngle: " + sceneValue[1];
}
String key = DigitalSTROMBindingConstants.DEVICE_SCENE + sceneId;
if (!saveScene.isEmpty()) {
logger.debug("Save scene configuration: [{}] to thing with UID {}", saveScene, getThing().getUID());
if (getThing().getProperties().get(key) != null) {
updateProperty(key, saveScene);
} else {
Map<String, String> properties = editProperties();
properties.put(key, saveScene);
updateProperties(properties);
}
}
}
}
@Override
public void onDeviceConfigChanged(ChangeableDeviceConfigEnum whichConfig) {
Configuration config = editConfiguration();
switch (whichConfig) {
case DEVICE_NAME:
config.put(DEVICE_NAME, device.getName());
break;
case METER_DSID:
config.put(DEVICE_METER_ID, device.getMeterDSID().getValue());
break;
case ZONE_ID:
config.put(DEVICE_ZONE_ID, device.getZoneId());
break;
case GROUPS:
config.put(DEVICE_GROUPS, device.getGroups().toString());
break;
case FUNCTIONAL_GROUP:
config.put(DEVICE_FUNCTIONAL_COLOR_GROUP, device.getFunctionalColorGroup().toString());
checkOutputChannel();
break;
case OUTPUT_MODE:
config.put(DEVICE_OUTPUT_MODE, device.getOutputMode().toString());
checkOutputChannel();
break;
}
super.updateConfiguration(config);
}
@Override
public String getDeviceStatusListenerID() {
return this.dSID;
}
}