diff --git a/addons/binding/org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorHandler.java b/addons/binding/org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorHandler.java index 740c092dc52d2..731c5b88db52b 100644 --- a/addons/binding/org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorHandler.java +++ b/addons/binding/org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorHandler.java @@ -21,11 +21,7 @@ import org.bubblecloud.zigbee.ZigBeeApi; import org.bubblecloud.zigbee.api.Device; import org.bubblecloud.zigbee.api.DeviceListener; -import org.bubblecloud.zigbee.api.ZigBeeDeviceException; import org.bubblecloud.zigbee.api.cluster.Cluster; -import org.bubblecloud.zigbee.api.cluster.general.ColorControl; -import org.bubblecloud.zigbee.api.cluster.general.LevelControl; -import org.bubblecloud.zigbee.api.cluster.general.OnOff; import org.bubblecloud.zigbee.api.cluster.impl.api.core.Attribute; import org.bubblecloud.zigbee.api.cluster.impl.api.core.ReportListener; import org.bubblecloud.zigbee.api.cluster.impl.api.core.ZigBeeClusterException; @@ -33,9 +29,6 @@ import org.bubblecloud.zigbee.network.model.DiscoveryMode; import org.bubblecloud.zigbee.network.port.ZigBeePort; import org.eclipse.smarthome.config.discovery.DiscoveryService; -import org.eclipse.smarthome.core.library.types.HSBType; -import org.eclipse.smarthome.core.library.types.OnOffType; -import org.eclipse.smarthome.core.library.types.PercentType; import org.eclipse.smarthome.core.thing.Bridge; import org.eclipse.smarthome.core.thing.ChannelUID; import org.eclipse.smarthome.core.thing.Thing; @@ -141,8 +134,6 @@ protected void browsingComplete() { logger.debug("ZigBee network READY. Found " + zigbeeApi.getDevices().size() + " nodes."); - updateStatus(ThingStatus.ONLINE); - final List devices = zigbeeApi.getDevices(); for (int i = 0; i < devices.size(); i++) { final Device device = devices.get(i); @@ -197,95 +188,6 @@ private Device getDeviceByIndexOrEndpointId(ZigBeeApi zigbeeApi, return device; } - public boolean LightPower(String lightAddress, OnOffType state) { - final Device device = getDeviceByIndexOrEndpointId(zigbeeApi, - lightAddress); - if (device == null) { - return false; - } - final OnOff onOff = device.getCluster(OnOff.class); - try { - if (state == OnOffType.ON) { - onOff.on(); - } else { - onOff.off(); - } - } catch (ZigBeeDeviceException e) { - e.printStackTrace(); - } - - return true; - } - - public boolean LightBrightness(String lightAddress, int state) { - final Device device = getDeviceByIndexOrEndpointId(zigbeeApi, - lightAddress); - if (device == null) { - return false; - } - - try { - final LevelControl levelControl = device - .getCluster(LevelControl.class); - levelControl.moveToLevelWithOnOff((short)(state * 254.0 / 100.0 + 0.5), 10); - } catch (ZigBeeDeviceException e) { - e.printStackTrace(); - } - - return true; - } - - public boolean LightColor(String lightAddress, HSBType state) { - final Device device = getDeviceByIndexOrEndpointId(zigbeeApi, - lightAddress); - if (device == null) { - return false; - } - - final ColorControl colorControl = device.getCluster(ColorControl.class); - if (colorControl == null) { - logger.debug("Device {} does not support color control.", - lightAddress); - return false; - } - - try { - int hue = state.getHue().intValue(); - int saturation = state.getSaturation().intValue(); - colorControl.moveToHue((int)(hue * 254.0 / 360.0 + 0.5), 0, 10); - colorControl.movetoSaturation((int)(saturation * 254.0 / 100.0 + 0.5), 10); - } catch (ZigBeeDeviceException e) { - e.printStackTrace(); - } - - return true; - } - - public boolean LightColorTemp(String lightAddress, PercentType state) { - final Device device = getDeviceByIndexOrEndpointId(zigbeeApi, - lightAddress); - if (device == null) { - return false; - } - - final ColorControl colorControl = device.getCluster(ColorControl.class); - if (colorControl == null) { - logger.debug("Device {} does not support color control.", - lightAddress); - return false; - } - - try { - // Range of 2000K to 6000K, gain = 4000K, offset = 2000K - double kelvin = state.intValue() * 4000.0 / 100.0 + 2000.0; - colorControl.moveToColorTemperature((short)(1e6 / kelvin + 0.5), 10); - } catch (ZigBeeDeviceException e) { - e.printStackTrace(); - } - - return true; - } - public Object attributeRead(String zigbeeAddress, int clusterId, int attributeIndex) { final Device device = getDeviceByIndexOrEndpointId(zigbeeApi, zigbeeAddress); @@ -319,7 +221,7 @@ public Object readAttribute(Device device, int clusterId, int attributeIndex) { } } - public Attribute openAttribute(String zigbeeAddress, short clusterId, AttributeDescriptor attributeId, ZigBeeEventListener listener) { + public Attribute openAttribute(String zigbeeAddress, Class clusterId, AttributeDescriptor attributeId, ZigBeeEventListener listener) { final Device device = getDeviceByIndexOrEndpointId(zigbeeApi, zigbeeAddress); Cluster cluster = device.getCluster(clusterId); if (cluster == null) { @@ -342,6 +244,15 @@ public void closeAttribute(Attribute attribute, ZigBeeEventListener listener) { } } + public T openCluster(String zigbeeAddress, Class clusterId) { + final Device device = getDeviceByIndexOrEndpointId(zigbeeApi, zigbeeAddress); + return device.getCluster(clusterId); + } + + public void closeCluster(Cluster cluster) { + + } + /** * Returns a list of all known devices * @return list of devices @@ -448,8 +359,9 @@ public void run(Device device) { // Signal to the handlers that they are known... ZigBeeEventListener listener = eventListeners.get(device.getEndpointId()); if (listener != null) { - listener.openDevice(); - listener.onEndpointStateChange(); + if (listener.openDevice()) { + listener.onEndpointStateChange(); + } } discoveryService.deviceAdded(device, description); diff --git a/addons/binding/org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeEventListener.java b/addons/binding/org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeEventListener.java index 796aa3dff63b4..07c60e419e90b 100644 --- a/addons/binding/org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeEventListener.java +++ b/addons/binding/org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeEventListener.java @@ -14,7 +14,7 @@ public interface ZigBeeEventListener { public void onEndpointStateChange(); - public void openDevice(); + public boolean openDevice(); public void closeDevice(); /** diff --git a/addons/binding/org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeLightHandler.java b/addons/binding/org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeLightHandler.java index caf1335e5a1f8..f95a7ffa99987 100644 --- a/addons/binding/org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeLightHandler.java +++ b/addons/binding/org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeLightHandler.java @@ -14,6 +14,7 @@ import org.eclipse.smarthome.core.thing.Bridge; 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.ThingTypeUID; import org.eclipse.smarthome.core.thing.binding.BaseThingHandler; import org.eclipse.smarthome.core.thing.binding.ThingHandler; @@ -24,13 +25,14 @@ import java.util.Dictionary; import java.util.Set; +import org.bubblecloud.zigbee.api.ZigBeeDeviceException; +import org.bubblecloud.zigbee.api.cluster.general.ColorControl; +import org.bubblecloud.zigbee.api.cluster.general.LevelControl; +import org.bubblecloud.zigbee.api.cluster.general.OnOff; import org.bubblecloud.zigbee.api.cluster.impl.api.core.Attribute; import org.bubblecloud.zigbee.api.cluster.impl.api.core.ReportListener; import org.bubblecloud.zigbee.api.cluster.impl.api.core.ZigBeeClusterException; import org.bubblecloud.zigbee.api.cluster.impl.attribute.Attributes; -import org.bubblecloud.zigbee.api.cluster.impl.general.ColorControlCluster; -import org.bubblecloud.zigbee.api.cluster.impl.general.LevelControlCluster; -import org.bubblecloud.zigbee.api.cluster.impl.general.OnOffCluster; import org.openhab.binding.zigbee.ZigBeeBindingConstants; import com.google.common.collect.Sets; @@ -38,8 +40,10 @@ public class ZigBeeLightHandler extends BaseThingHandler implements ZigBeeEventListener, ReportListener { - public final static Set SUPPORTED_THING_TYPES = Sets - .newHashSet(ZigBeeBindingConstants.THING_TYPE_COLOR_DIMMABLE_LIGHT); + public final static Set SUPPORTED_THING_TYPES = Sets .newHashSet( + ZigBeeBindingConstants.THING_TYPE_ON_OFF_LIGHT, + ZigBeeBindingConstants.THING_TYPE_DIMMABLE_LIGHT, + ZigBeeBindingConstants.THING_TYPE_COLOR_DIMMABLE_LIGHT); private static final int DIM_STEPSIZE = 30; @@ -49,6 +53,9 @@ public class ZigBeeLightHandler extends BaseThingHandler implements private Attribute attrHue; private Attribute attrSaturation; private Attribute attrColorTemp; + private OnOff clusOnOff; + private LevelControl clusLevel; + private ColorControl clusColor; private OnOffType currentOnOff; private HSBType currentHSB; @@ -72,6 +79,9 @@ public void initialize() { attrHue = null; attrSaturation = null; attrColorTemp = null; + clusOnOff = null; + clusLevel = null; + clusColor = null; } protected void bridgeHandlerInitialized(ThingHandler thingHandler, Bridge bridge) { @@ -83,6 +93,8 @@ protected void bridgeHandlerInitialized(ThingHandler thingHandler, Bridge bridge // getThing().setStatus(getBridge().getStatus()); } } + // until we get an update put the Thing offline + updateStatus(ThingStatus.OFFLINE); } @Override @@ -114,7 +126,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { } else if (command instanceof OnOffType) { currentOnOff = (OnOffType) command; } - coordinatorHandler.LightPower(lightAddress, currentOnOff); + commandOnOff(currentOnOff); break; case ZigBeeBindingConstants.CHANNEL_BRIGHTNESS: @@ -128,7 +140,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { level = 0; } } - coordinatorHandler.LightBrightness(lightAddress, level); + commandLevel(level); break; case ZigBeeBindingConstants.CHANNEL_COLOR: @@ -145,7 +157,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { } currentHSB = new HSBType(currentHSB.getHue(), saturation, PercentType.HUNDRED); } - coordinatorHandler.LightColor(lightAddress, currentHSB); + commandColor(currentHSB); break; case ZigBeeBindingConstants.CHANNEL_COLORTEMPERATURE: PercentType colorTemp = PercentType.ZERO; @@ -158,59 +170,82 @@ public void handleCommand(ChannelUID channelUID, Command command) { colorTemp = PercentType.ZERO; } } - coordinatorHandler.LightColorTemp(lightAddress, colorTemp); + commandColorTemp(colorTemp); break; } } @Override - public void onEndpointStateChange() { - try { - if (attrOnOff != null) { - updateStateOnOff((boolean)attrOnOff.getValue()); - } - if (attrLevel != null) { - updateStateLevel((int)attrLevel.getValue()); - } - if (attrHue != null && attrSaturation != null) { - updateStateColor((int)attrHue.getValue(), (int)attrSaturation.getValue()); - } - if (attrColorTemp != null) { - updateStateColorTemp((int)attrColorTemp.getValue()); - } - } catch (ZigBeeClusterException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - @Override - public void openDevice() { + public boolean openDevice() { attrOnOff = coordinatorHandler.openAttribute(lightAddress, - OnOffCluster.ID, Attributes.ON_OFF, this); + OnOff.class, Attributes.ON_OFF, this); + clusOnOff = (OnOff)coordinatorHandler.openCluster(lightAddress, OnOff.class); + if (attrOnOff == null || clusOnOff == null) { + logger.error("Error opening device on/off controls {}", lightAddress); + return false; + } if (this.getThing().getThingTypeUID().equals(ZigBeeBindingConstants.THING_TYPE_ON_OFF_LIGHT) == false) { attrLevel = coordinatorHandler.openAttribute(lightAddress, - LevelControlCluster.ID, Attributes.CURRENT_LEVEL, this); + LevelControl.class, Attributes.CURRENT_LEVEL, this); + clusLevel = coordinatorHandler.openCluster(lightAddress, LevelControl.class); + if (attrLevel == null || clusLevel == null) { + logger.error("Error opening device level controls {}", lightAddress); + return false; + } } if (this.getThing().getThingTypeUID().equals(ZigBeeBindingConstants.THING_TYPE_COLOR_DIMMABLE_LIGHT)) { attrHue = coordinatorHandler.openAttribute(lightAddress, - ColorControlCluster.ID, Attributes.CURRENT_HUE, null); + ColorControl.class, Attributes.CURRENT_HUE, null); attrSaturation = coordinatorHandler.openAttribute(lightAddress, - ColorControlCluster.ID, Attributes.CURRENT_SATURATION, null); + ColorControl.class, Attributes.CURRENT_SATURATION, null); attrColorTemp = coordinatorHandler.openAttribute(lightAddress, - ColorControlCluster.ID, Attributes.COLOR_TEMPERATURE, null); + ColorControl.class, Attributes.COLOR_TEMPERATURE, null); + clusColor = coordinatorHandler.openCluster(lightAddress, ColorControl.class); + if (attrHue == null || attrSaturation == null || attrColorTemp == null || clusColor == null) { + logger.error("Error opening device color controls {}", lightAddress); + return false; + } } + return true; } @Override public void closeDevice() { + updateStatus(ThingStatus.OFFLINE); + coordinatorHandler.closeAttribute(attrOnOff, this); coordinatorHandler.closeAttribute(attrLevel, this); coordinatorHandler.closeAttribute(attrHue, null); coordinatorHandler.closeAttribute(attrSaturation, null); coordinatorHandler.closeAttribute(attrColorTemp, null); + coordinatorHandler.closeCluster(clusOnOff); + coordinatorHandler.closeCluster(clusLevel); + coordinatorHandler.closeCluster(clusColor); + } + + @Override + public void onEndpointStateChange() { + try { + if (attrOnOff != null) { + updateStateOnOff((boolean)attrOnOff.getValue()); + } + if (attrLevel != null) { + updateStateLevel((int)attrLevel.getValue()); + } + if (attrHue != null && attrSaturation != null) { + updateStateColor((int)attrHue.getValue(), (int)attrSaturation.getValue()); + } + if (attrColorTemp != null) { + updateStateColorTemp((int)attrColorTemp.getValue()); + } + // Device is now online + updateStatus(ThingStatus.ONLINE); + } catch (ZigBeeClusterException e) { + updateStatus(ThingStatus.OFFLINE); + e.printStackTrace(); + } } @Override @@ -229,6 +264,25 @@ public void receivedReport(String endPointId, short clusterId, updateStateLevel((int)value); } } + + updateStatus(ThingStatus.ONLINE); + } + + public void commandOnOff(OnOffType state) { + if (clusOnOff == null) { + return; + } + try { + if (state == OnOffType.ON) { + clusOnOff.on(); + } else { + clusOnOff.off(); + } + updateStatus(ThingStatus.ONLINE); + } catch (ZigBeeDeviceException e) { + updateStatus(ThingStatus.OFFLINE); + e.printStackTrace(); + } } private void updateStateOnOff(boolean onOff) { @@ -236,6 +290,20 @@ private void updateStateOnOff(boolean onOff) { updateState(new ChannelUID(getThing().getUID(), ZigBeeBindingConstants.CHANNEL_SWITCH), currentOnOff); } + + private void commandLevel(int state) { + if (clusLevel == null) { + return; + } + try { + clusLevel.moveToLevelWithOnOff((short)(state * 254.0 / 100.0 + 0.5), 10); + updateStatus(ThingStatus.ONLINE); + } catch (ZigBeeDeviceException e) { + updateStatus(ThingStatus.OFFLINE); + e.printStackTrace(); + } + } + private void updateStateLevel(int level) { PercentType chanPercent; if (currentOnOff == OnOffType.OFF) { @@ -245,6 +313,23 @@ private void updateStateLevel(int level) { updateState(new ChannelUID(getThing().getUID(), ZigBeeBindingConstants.CHANNEL_BRIGHTNESS), chanPercent); } + public void commandColor(HSBType state) { + if (clusColor == null) { + return; + } + + try { + int hue = state.getHue().intValue(); + int saturation = state.getSaturation().intValue(); + clusColor.moveToHue((int)(hue * 254.0 / 360.0 + 0.5), 0, 10); + clusColor.movetoSaturation((int)(saturation * 254.0 / 100.0 + 0.5), 10); + updateStatus(ThingStatus.ONLINE); + } catch (ZigBeeDeviceException e) { + updateStatus(ThingStatus.OFFLINE); + e.printStackTrace(); + } + } + private void updateStateColor(int hue, int saturation) { currentHSB = new HSBType(new DecimalType(hue * 360.0 / 254.0 + 0.5), new PercentType((int)(saturation * 100.0 / 254.0 + 0.5)), PercentType.HUNDRED); @@ -253,8 +338,24 @@ private void updateStateColor(int hue, int saturation) { updateState(new ChannelUID(getThing().getUID(), ZigBeeBindingConstants.CHANNEL_COLOR), statePercent); } + public void commandColorTemp(PercentType state) { + if (clusColor == null) { + return; + } + + // Range of 2000K to 6500K, gain = 4500K, offset = 2000K + double kelvin = state.intValue() * 4500.0 / 100.0 + 2000.0; + try { + clusColor.moveToColorTemperature((short)(1e6 / kelvin + 0.5), 10); + updateStatus(ThingStatus.ONLINE); + } catch (ZigBeeDeviceException e) { + updateStatus(ThingStatus.OFFLINE); + e.printStackTrace(); + } + } + private void updateStateColorTemp(int colorTemp) { - // Range of 2000K to 6000K, gain = 4000K, offset = 2000K + // Range of 2000K to 6500K, gain = 4500K, offset = 2000K int value = (int)(((1e6 / colorTemp) - 2000.0) / 4000.0 * 100.0 + 0.5); if (value < 0) { value = 0; @@ -264,6 +365,7 @@ private void updateStateColorTemp(int colorTemp) { PercentType state = new PercentType(value); updateState(new ChannelUID(getThing().getUID(), ZigBeeBindingConstants.CHANNEL_COLORTEMPERATURE), state); } + /* * @Override public void onLightRemoved(HueBridge bridge, FullLight light) { *