diff --git a/.classpath b/.classpath index c6f6ed7dc..497c32a8a 100644 --- a/.classpath +++ b/.classpath @@ -3,11 +3,12 @@ - - - + + + + diff --git a/ESH-INF/i18n/thingstate.properties b/ESH-INF/i18n/thingstate.properties index 71cef2637..48bae54f1 100644 --- a/ESH-INF/i18n/thingstate.properties +++ b/ESH-INF/i18n/thingstate.properties @@ -1,2 +1,7 @@ -zigbee.status.offline_initialize_fail=Failed to initialize ZigBee transport layer -zigbee.status.offline_startup_fail=Failed to startup ZigBee transport layer +zigbee.status.offline_initializefail=Failed to initialize ZigBee transport layer +zigbee.status.offline_startupfail=Failed to startup ZigBee transport layer +zigbee.status.offline_notinitialized=Not initialized +zigbee.status.offline_noaddress=Node address is not set +zigbee.status.offline_nodenotfound=Node is not found on network + +zigbee.firmware.failed=Firmware update failed \ No newline at end of file diff --git a/ESH-INF/thing/_channels.xml b/ESH-INF/thing/_channels.xml index b16c9c0dd..9ad607335 100644 --- a/ESH-INF/thing/_channels.xml +++ b/ESH-INF/thing/_channels.xml @@ -1,73 +1,81 @@ - + - - - Color - - The color channel allows to control the color of a light. + + + Color + + The color channel allows to control the color of a light. It is also possible to dim values and switch the light on and off. - ColorLight - + ColorLight + - - - Dimmer - - The color temperature channel allows to set the color + + + Dimmer + + The color temperature channel allows to set the color temperature of a light from 0 (cold) to 100 (warm). - ColorLight - + ColorLight + - - - Number - - Indicates the current temperature - Temperature - - - - - - Select the scale for temperature readings - 0 - - - - - - - + + + Number + + Indicates the current temperature + Temperature + + + + + + Select the scale for temperature readings + 0 + + + + + + + - - - Number - - Indicates the current relative humidity - Humidity - - - + + + Number + + Indicates the current relative humidity + Humidity + + + - - - Switch - - Switches the power on and off - Light - + + + Switch + + Indicates if an occupancy sensor is triggered + Motion + + - - - Dimmer - - Sets the level of the light - Light - + + + Switch + + Switches the power on and off + Light + - \ No newline at end of file + + + Dimmer + + Sets the level of the light + Light + + + diff --git a/ESH-INF/thing/_controller_ember.xml b/ESH-INF/thing/_controller_ember.xml index 71503477c..032850682 100644 --- a/ESH-INF/thing/_controller_ember.xml +++ b/ESH-INF/thing/_controller_ember.xml @@ -11,6 +11,7 @@ + serial-port Serial Port diff --git a/ESH-INF/thing/_controller_telegesis.xml b/ESH-INF/thing/_controller_telegesis.xml new file mode 100644 index 000000000..56271b0ca --- /dev/null +++ b/ESH-INF/thing/_controller_telegesis.xml @@ -0,0 +1,88 @@ + + + + + + Telegesis ETRX3 Dongle + + + + + serial-port + Serial Port + + + + + Serial Port Baud Rate + 19200 + + + + + + + + + + + + + + + + + Resets the Controller and sets the configuration to the configured values. + true + + + + + Channel number + -1 + + + + + + + + + + + + + + + + + + + true + + + + + PAN Network ID + 0 + + + + false + true + + + + + Extended PAN Network ID: 16 byte hexadecimal value + 0000000000000000 + true + + + + + + diff --git a/ESH-INF/thing/_controller_ti2351.xml b/ESH-INF/thing/_controller_ti2351.xml index 2941b3163..6fe8e4553 100644 --- a/ESH-INF/thing/_controller_ti2351.xml +++ b/ESH-INF/thing/_controller_ti2351.xml @@ -11,6 +11,7 @@ + serial-port Serial Port diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF index 2a8f93d27..fd67a90af 100644 --- a/META-INF/MANIFEST.MF +++ b/META-INF/MANIFEST.MF @@ -5,6 +5,7 @@ Bundle-SymbolicName: org.openhab.binding.zigbee;singleton:=true Bundle-Vendor: openHAB Bundle-Version: 2.2.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-Activator: org.openhab.binding.zigbee.internal.ZigBeeActivator Import-Package: com.google.common.collect, com.thoughtworks.xstream, com.thoughtworks.xstream.converters, @@ -12,6 +13,7 @@ Import-Package: com.google.common.collect, com.thoughtworks.xstream.io.xml, gnu.io, org.apache.commons.io, + org.eclipse.jdt.annotation;resolution:=optional, org.eclipse.smarthome.config.core, org.eclipse.smarthome.config.discovery, org.eclipse.smarthome.core.i18n, @@ -19,15 +21,17 @@ Import-Package: com.google.common.collect, org.eclipse.smarthome.core.thing, org.eclipse.smarthome.core.thing.binding, org.eclipse.smarthome.core.thing.binding.builder, + org.eclipse.smarthome.core.thing.binding.firmware, org.eclipse.smarthome.core.thing.type, org.eclipse.smarthome.core.types, org.osgi.framework, + org.osgi.service.component.annotations;version="1.3.0", org.slf4j Service-Component: OSGI-INF/*.xml Export-Package: org.openhab.binding.zigbee, org.openhab.binding.zigbee.handler Bundle-ClassPath: ., - lib/com.zsmartsystems.zigbee-1.0.0-SNAPSHOT.jar, - lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.0-SNAPSHOT.jar, - lib/com.zsmartsystems.zigbee.dongle.ember-1.0.0-SNAPSHOT.jar -Bundle-ActivationPolicy: lazy + lib/com.zsmartsystems.zigbee-1.0.1-SNAPSHOT.jar, + lib/com.zsmartsystems.zigbee.dongle.ember-1.0.1-SNAPSHOT.jar, + lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.1-SNAPSHOT.jar, + lib/com.zsmartsystems.zigbee.dongle.telegesis-1.0.1-SNAPSHOT.jar diff --git a/OSGI-INF/ZigBeeHandlerFactory.xml b/OSGI-INF/ZigBeeHandlerFactory.xml index e8e2667a2..3afafa122 100644 --- a/OSGI-INF/ZigBeeHandlerFactory.xml +++ b/OSGI-INF/ZigBeeHandlerFactory.xml @@ -17,4 +17,6 @@ + + diff --git a/build.properties b/build.properties index e4b1005ca..fdef7c82e 100644 --- a/build.properties +++ b/build.properties @@ -5,7 +5,8 @@ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ ESH-INF/,\ - lib/com.zsmartsystems.zigbee-1.0.0-SNAPSHOT.jar,\ - lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.0-SNAPSHOT.jar,\ - lib/com.zsmartsystems.zigbee.dongle.ember-1.0.0-SNAPSHOT.jar + lib/com.zsmartsystems.zigbee-1.0.1-SNAPSHOT.jar,\ + lib/com.zsmartsystems.zigbee.dongle.ember-1.0.1-SNAPSHOT.jar,\ + lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.1-SNAPSHOT.jar,\ + lib/com.zsmartsystems.zigbee.dongle.telegesis-1.0.1-SNAPSHOT.jar \ No newline at end of file diff --git a/lib/com.zsmartsystems.zigbee-1.0.0-SNAPSHOT-sources.jar b/lib/com.zsmartsystems.zigbee-1.0.0-SNAPSHOT-sources.jar deleted file mode 100644 index 6be35b1bb..000000000 Binary files a/lib/com.zsmartsystems.zigbee-1.0.0-SNAPSHOT-sources.jar and /dev/null differ diff --git a/lib/com.zsmartsystems.zigbee-1.0.0-SNAPSHOT.jar b/lib/com.zsmartsystems.zigbee-1.0.0-SNAPSHOT.jar deleted file mode 100644 index 2cb59b58d..000000000 Binary files a/lib/com.zsmartsystems.zigbee-1.0.0-SNAPSHOT.jar and /dev/null differ diff --git a/lib/com.zsmartsystems.zigbee-1.0.1-SNAPSHOT-sources.jar b/lib/com.zsmartsystems.zigbee-1.0.1-SNAPSHOT-sources.jar new file mode 100644 index 000000000..a506213d9 Binary files /dev/null and b/lib/com.zsmartsystems.zigbee-1.0.1-SNAPSHOT-sources.jar differ diff --git a/lib/com.zsmartsystems.zigbee-1.0.1-SNAPSHOT.jar b/lib/com.zsmartsystems.zigbee-1.0.1-SNAPSHOT.jar new file mode 100644 index 000000000..b9144958f Binary files /dev/null and b/lib/com.zsmartsystems.zigbee-1.0.1-SNAPSHOT.jar differ diff --git a/lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.0-SNAPSHOT-sources.jar b/lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.0-SNAPSHOT-sources.jar deleted file mode 100644 index efd4ab5ab..000000000 Binary files a/lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.0-SNAPSHOT-sources.jar and /dev/null differ diff --git a/lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.0-SNAPSHOT.jar b/lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.0-SNAPSHOT.jar deleted file mode 100644 index 54ab35b68..000000000 Binary files a/lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.0-SNAPSHOT.jar and /dev/null differ diff --git a/lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.1-SNAPSHOT-sources.jar b/lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.1-SNAPSHOT-sources.jar new file mode 100644 index 000000000..c17d6f41b Binary files /dev/null and b/lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.1-SNAPSHOT-sources.jar differ diff --git a/lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.1-SNAPSHOT.jar b/lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.1-SNAPSHOT.jar new file mode 100644 index 000000000..cda85a64a Binary files /dev/null and b/lib/com.zsmartsystems.zigbee.dongle.cc2531-1.0.1-SNAPSHOT.jar differ diff --git a/lib/com.zsmartsystems.zigbee.dongle.ember-1.0.0-SNAPSHOT-sources.jar b/lib/com.zsmartsystems.zigbee.dongle.ember-1.0.0-SNAPSHOT-sources.jar deleted file mode 100644 index 97ece1e1e..000000000 Binary files a/lib/com.zsmartsystems.zigbee.dongle.ember-1.0.0-SNAPSHOT-sources.jar and /dev/null differ diff --git a/lib/com.zsmartsystems.zigbee.dongle.ember-1.0.0-SNAPSHOT.jar b/lib/com.zsmartsystems.zigbee.dongle.ember-1.0.0-SNAPSHOT.jar deleted file mode 100644 index 577c9a178..000000000 Binary files a/lib/com.zsmartsystems.zigbee.dongle.ember-1.0.0-SNAPSHOT.jar and /dev/null differ diff --git a/lib/com.zsmartsystems.zigbee.dongle.ember-1.0.1-SNAPSHOT-sources.jar b/lib/com.zsmartsystems.zigbee.dongle.ember-1.0.1-SNAPSHOT-sources.jar new file mode 100644 index 000000000..c721ffc77 Binary files /dev/null and b/lib/com.zsmartsystems.zigbee.dongle.ember-1.0.1-SNAPSHOT-sources.jar differ diff --git a/lib/com.zsmartsystems.zigbee.dongle.ember-1.0.1-SNAPSHOT.jar b/lib/com.zsmartsystems.zigbee.dongle.ember-1.0.1-SNAPSHOT.jar new file mode 100644 index 000000000..6cdd9267e Binary files /dev/null and b/lib/com.zsmartsystems.zigbee.dongle.ember-1.0.1-SNAPSHOT.jar differ diff --git a/lib/com.zsmartsystems.zigbee.dongle.telegesis-1.0.1-SNAPSHOT-sources.jar b/lib/com.zsmartsystems.zigbee.dongle.telegesis-1.0.1-SNAPSHOT-sources.jar new file mode 100644 index 000000000..84e19dd11 Binary files /dev/null and b/lib/com.zsmartsystems.zigbee.dongle.telegesis-1.0.1-SNAPSHOT-sources.jar differ diff --git a/lib/com.zsmartsystems.zigbee.dongle.telegesis-1.0.1-SNAPSHOT.jar b/lib/com.zsmartsystems.zigbee.dongle.telegesis-1.0.1-SNAPSHOT.jar new file mode 100644 index 000000000..bdbf6902d Binary files /dev/null and b/lib/com.zsmartsystems.zigbee.dongle.telegesis-1.0.1-SNAPSHOT.jar differ diff --git a/src/main/java/org/openhab/binding/zigbee/ZigBeeBindingConstants.java b/src/main/java/org/openhab/binding/zigbee/ZigBeeBindingConstants.java index 77188cb32..04ebdfa71 100644 --- a/src/main/java/org/openhab/binding/zigbee/ZigBeeBindingConstants.java +++ b/src/main/java/org/openhab/binding/zigbee/ZigBeeBindingConstants.java @@ -32,8 +32,9 @@ public class ZigBeeBindingConstants { public static final String BINDING_ID = "zigbee"; // Coordinator (Bridges) - public final static ThingTypeUID COORDINATOR_TYPE_CC2531 = new ThingTypeUID(BINDING_ID, "coordinator_cc2531"); public final static ThingTypeUID COORDINATOR_TYPE_EMBER = new ThingTypeUID(BINDING_ID, "coordinator_ember"); + public final static ThingTypeUID COORDINATOR_TYPE_CC2531 = new ThingTypeUID(BINDING_ID, "coordinator_cc2531"); + public final static ThingTypeUID COORDINATOR_TYPE_TELEGESIS = new ThingTypeUID(BINDING_ID, "coordinator_telegesis"); // List of Thing Type UIDs public final static ThingTypeUID THING_TYPE_GENERIC_DEVICE = new ThingTypeUID(BINDING_ID, "device"); @@ -58,6 +59,8 @@ public class ZigBeeBindingConstants { public static final String CHANNEL_TEMPERATURE_VALUE = "sensor_temperature"; public static final String CHANNEL_HUMIDITY_VALUE = "sensor_humidity"; + public static final String CHANNEL_OCCUPANCY_SENSOR = "sensor_occupancy"; + public static final String CHANNEL_PROPERTY_ADDRESS = "zigbee_address"; public static final String CHANNEL_PROPERTY_CLUSTER = "zigbee_cluster"; diff --git a/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeChannelConverter.java b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeChannelConverter.java index ecd99bd65..4f10a0a88 100644 --- a/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeChannelConverter.java +++ b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeChannelConverter.java @@ -29,8 +29,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.zsmartsystems.zigbee.ZigBeeDevice; -import com.zsmartsystems.zigbee.ZigBeeDeviceAddress; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; +import com.zsmartsystems.zigbee.ZigBeeEndpointAddress; /** * ZigBeeChannelConverter class. Base class for all converters that convert between ZigBee clusters and openHAB @@ -45,7 +45,7 @@ public abstract class ZigBeeChannelConverter { protected ZigBeeCoordinatorHandler coordinator = null; protected ChannelUID channelUID = null; - protected ZigBeeDevice device = null; + protected ZigBeeEndpoint device = null; /** * Map of all channels supported by the binding @@ -61,8 +61,7 @@ public abstract class ZigBeeChannelConverter { channelMap.put(ZigBeeBindingConstants.CHANNEL_COLOR_COLOR, ZigBeeConverterColorColor.class); channelMap.put(ZigBeeBindingConstants.CHANNEL_COLOR_TEMPERATURE, ZigBeeConverterColorTemperature.class); channelMap.put(ZigBeeBindingConstants.CHANNEL_TEMPERATURE_VALUE, ZigBeeConverterTemperature.class); - // clusterMap.put(ZigBeeApiConstants.CLUSTER_ID_TEMPERATURE_MEASUREMENT, - // ZigBeeTemperatureMeasurementClusterHandler.class); + channelMap.put(ZigBeeBindingConstants.CHANNEL_OCCUPANCY_SENSOR, ZigBeeConverterOccupancy.class); } /** @@ -76,15 +75,15 @@ public ZigBeeChannelConverter() { /** * Creates the converter handler * - * @param thing - * @param channelUID - * @param coordinator + * @param thing the {@link ZigBeeThingHandler} the channel is part of + * @param channelUID the {@link channelUID} for the channel + * @param coordinator the {@link ZigBeeCoordinatorHandler} this node is part of * @param address * @return true if the handler was created successfully - false otherwise */ public boolean createConverter(ZigBeeThingHandler thing, ChannelUID channelUID, ZigBeeCoordinatorHandler coordinator, String address) { - this.device = coordinator.getDevice(new ZigBeeDeviceAddress(address)); + this.device = coordinator.getEndpoint(new ZigBeeEndpointAddress(address)); if (this.device == null) { return false; } @@ -95,8 +94,16 @@ public boolean createConverter(ZigBeeThingHandler thing, ChannelUID channelUID, return true; } + /** + * Initialise the converter. This is called by the {@link ZigBeeThingHandler} when the channel is created. The + * converter should initialise any internal states, open any clusters, add reporting and binding that it needs to + * operate. + */ public abstract void initializeConverter(); + /** + * Closes the converter and releases any resources. + */ public void disposeConverter() { } @@ -119,9 +126,9 @@ public Runnable handleCommand(final Command command) { return null; } - public abstract Channel getChannel(ThingUID thingUID, ZigBeeDevice device); + public abstract Channel getChannel(ThingUID thingUID, ZigBeeEndpoint device); - public static List getChannels(ThingUID thingUID, ZigBeeDevice device) { + public static List getChannels(ThingUID thingUID, ZigBeeEndpoint device) { List channels = new ArrayList(); Constructor constructor; @@ -177,18 +184,16 @@ public ConfigDescription getConfigDescription() { return null; } - protected Channel createChannel(ZigBeeDevice device, ThingUID thingUID, String channelType, String itemType, + protected Channel createChannel(ZigBeeEndpoint device, ThingUID thingUID, String channelType, String itemType, String label) { Map properties = new HashMap(); - properties.put(ZigBeeBindingConstants.CHANNEL_PROPERTY_ADDRESS, device.getDeviceAddress().toString()); + properties.put(ZigBeeBindingConstants.CHANNEL_PROPERTY_ADDRESS, device.getEndpointAddress().toString()); // properties.put(ZigBeeBindingConstants.CHANNEL_PROPERTY_CLUSTER, Integer.toString(getClusterId())); ChannelTypeUID channelTypeUID = new ChannelTypeUID(ZigBeeBindingConstants.BINDING_ID, channelType); return ChannelBuilder .create(new ChannelUID(thingUID, - device.getIeeeAddress() + "_" + device.getEndpoint() + "_" + channelType), itemType) + device.getIeeeAddress() + "_" + device.getEndpointId() + "_" + channelType), itemType) .withType(channelTypeUID).withLabel(label).withProperties(properties).build(); } - - // public abstract int getClusterId(); } diff --git a/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterColorColor.java b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterColorColor.java index 7ad4f1f45..d07a26bf1 100644 --- a/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterColorColor.java +++ b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterColorColor.java @@ -21,7 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.zsmartsystems.zigbee.ZigBeeDevice; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.zcl.ZclAttribute; import com.zsmartsystems.zigbee.zcl.ZclAttributeListener; import com.zsmartsystems.zigbee.zcl.clusters.ZclColorControlCluster; @@ -61,6 +61,9 @@ public void initializeConverter() { return; } + clusterLevelControl.bind(); + clusterColorControl.bind(); + // Add a listener, then request the status clusterLevelControl.addAttributeListener(this); clusterColorControl.addAttributeListener(this); @@ -72,10 +75,8 @@ public void initializeConverter() { try { clusterColorControl.setCurrentHueReporting(1, 600, 1).get(); clusterLevelControl.setCurrentLevelReporting(1, 600, 1).get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { - e.printStackTrace(); + } catch (ExecutionException | InterruptedException e) { + logger.debug("Exception configuring color reporting", e); } initialised = true; @@ -136,7 +137,7 @@ public void run() { } @Override - public Channel getChannel(ThingUID thingUID, ZigBeeDevice device) { + public Channel getChannel(ThingUID thingUID, ZigBeeEndpoint device) { if (device.getCluster(ZclColorControlCluster.CLUSTER_ID) == null || device.getCluster(ZclLevelControlCluster.CLUSTER_ID) == null) { return null; diff --git a/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterColorTemperature.java b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterColorTemperature.java index 2c350a1af..01dae9104 100644 --- a/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterColorTemperature.java +++ b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterColorTemperature.java @@ -8,8 +8,6 @@ */ package org.openhab.binding.zigbee.converter; -import java.util.concurrent.ExecutionException; - import org.eclipse.smarthome.core.library.types.OnOffType; import org.eclipse.smarthome.core.library.types.PercentType; import org.eclipse.smarthome.core.thing.Channel; @@ -19,7 +17,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.zsmartsystems.zigbee.ZigBeeDevice; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.zcl.ZclAttribute; import com.zsmartsystems.zigbee.zcl.ZclAttributeListener; import com.zsmartsystems.zigbee.zcl.clusters.ZclColorControlCluster; @@ -48,18 +46,13 @@ public void initializeConverter() { return; } - clusterColorControl.addAttributeListener(this); + clusterColorControl.bind(); + clusterColorControl.addAttributeListener(this); clusterColorControl.getColorTemperature(0); // Configure reporting - no faster than once per second - no slower than 10 minutes. - try { - clusterColorControl.setCurrentHueReporting(1, 600, 1).get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { - e.printStackTrace(); - } + clusterColorControl.setCurrentHueReporting(1, 600, 1); initialised = true; } @@ -103,7 +96,7 @@ public void run() { } @Override - public Channel getChannel(ThingUID thingUID, ZigBeeDevice device) { + public Channel getChannel(ThingUID thingUID, ZigBeeEndpoint device) { if (device.getCluster(ZclColorControlCluster.CLUSTER_ID) == null) { return null; } diff --git a/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterOccupancy.java b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterOccupancy.java new file mode 100644 index 000000000..6b436d89a --- /dev/null +++ b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterOccupancy.java @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2014-2016 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.openhab.binding.zigbee.converter; + +import org.eclipse.smarthome.core.library.types.OnOffType; +import org.eclipse.smarthome.core.thing.Channel; +import org.eclipse.smarthome.core.thing.ThingUID; +import org.openhab.binding.zigbee.ZigBeeBindingConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.zsmartsystems.zigbee.ZigBeeEndpoint; +import com.zsmartsystems.zigbee.zcl.ZclAttribute; +import com.zsmartsystems.zigbee.zcl.ZclAttributeListener; +import com.zsmartsystems.zigbee.zcl.clusters.ZclOccupancySensingCluster; + +/** + * Converter for the occupancy sensor. + * + * @author Chris Jackson - Initial Contribution + * + */ +public class ZigBeeConverterOccupancy extends ZigBeeChannelConverter implements ZclAttributeListener { + private Logger logger = LoggerFactory.getLogger(ZigBeeConverterOccupancy.class); + + private ZclOccupancySensingCluster clusterOccupancy; + + private boolean initialised = false; + + @Override + public void initializeConverter() { + if (initialised == true) { + return; + } + logger.debug("{}: Initialising device occupancy cluster", device.getIeeeAddress()); + + clusterOccupancy = (ZclOccupancySensingCluster) device.getCluster(ZclOccupancySensingCluster.CLUSTER_ID); + if (clusterOccupancy == null) { + logger.error("{}: Error opening occupancy cluster", device.getIeeeAddress()); + return; + } + + clusterOccupancy.bind(); + + // Add a listener, then request the status + clusterOccupancy.addAttributeListener(this); + clusterOccupancy.getOccupancy(0); + + // Configure reporting - no faster than once per second - no slower than 10 minutes. + clusterOccupancy.setOccupancyReporting(1, 600); + initialised = true; + } + + @Override + public void disposeConverter() { + if (initialised == false) { + return; + } + + logger.debug("{}: Closing device on/off cluster", device.getIeeeAddress()); + + if (clusterOccupancy != null) { + clusterOccupancy.removeAttributeListener(this); + } + } + + @Override + public void handleRefresh() { + if (initialised == false) { + return; + } + } + + @Override + public Channel getChannel(ThingUID thingUID, ZigBeeEndpoint device) { + if (device.getCluster(ZclOccupancySensingCluster.CLUSTER_ID) == null) { + return null; + } + return createChannel(device, thingUID, ZigBeeBindingConstants.CHANNEL_OCCUPANCY_SENSOR, + ZigBeeBindingConstants.ITEM_TYPE_SWITCH, "Occupancy"); + } + + @Override + public void attributeUpdated(ZclAttribute attribute) { + logger.debug("{}: ZigBee attribute reports {}", device.getIeeeAddress(), attribute); + if (attribute.getId() == ZclOccupancySensingCluster.ATTR_OCCUPANCY) { + Boolean value = (Boolean) attribute.getLastValue(); + if (value != null && value == true) { + updateChannelState(OnOffType.ON); + } else { + updateChannelState(OnOffType.OFF); + } + } + } +} diff --git a/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterSwitchLevel.java b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterSwitchLevel.java index 42e270194..b6af10e53 100644 --- a/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterSwitchLevel.java +++ b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterSwitchLevel.java @@ -17,7 +17,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.zsmartsystems.zigbee.ZigBeeDevice; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.zcl.ZclAttribute; import com.zsmartsystems.zigbee.zcl.ZclAttributeListener; import com.zsmartsystems.zigbee.zcl.clusters.ZclLevelControlCluster; @@ -46,6 +46,8 @@ public void initializeConverter() { return; } + clusterLevelControl.bind(); + // Add a listener, then request the status clusterLevelControl.addAttributeListener(this); clusterLevelControl.getCurrentLevel(0); @@ -91,7 +93,7 @@ public void run() { } @Override - public Channel getChannel(ThingUID thingUID, ZigBeeDevice device) { + public Channel getChannel(ThingUID thingUID, ZigBeeEndpoint device) { if (device.getCluster(ZclLevelControlCluster.CLUSTER_ID) == null) { return null; } diff --git a/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterSwitchOnoff.java b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterSwitchOnoff.java index 353c45a7b..929ae20d2 100644 --- a/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterSwitchOnoff.java +++ b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterSwitchOnoff.java @@ -8,8 +8,6 @@ */ package org.openhab.binding.zigbee.converter; -import java.util.concurrent.ExecutionException; - import org.eclipse.smarthome.core.library.types.OnOffType; import org.eclipse.smarthome.core.library.types.PercentType; import org.eclipse.smarthome.core.thing.Channel; @@ -19,7 +17,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.zsmartsystems.zigbee.ZigBeeDevice; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.zcl.ZclAttribute; import com.zsmartsystems.zigbee.zcl.ZclAttributeListener; import com.zsmartsystems.zigbee.zcl.clusters.ZclOnOffCluster; @@ -49,18 +47,14 @@ public void initializeConverter() { return; } + clusterOnOff.bind(); + // Add a listener, then request the status clusterOnOff.addAttributeListener(this); clusterOnOff.getOnOff(0); // Configure reporting - no faster than once per second - no slower than 10 minutes. - try { - clusterOnOff.setOnOffReporting(1, 600).get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { - e.printStackTrace(); - } + clusterOnOff.setOnOffReporting(1, 600); initialised = true; } @@ -118,7 +112,7 @@ public void run() { } @Override - public Channel getChannel(ThingUID thingUID, ZigBeeDevice device) { + public Channel getChannel(ThingUID thingUID, ZigBeeEndpoint device) { if (device.getCluster(ZclOnOffCluster.CLUSTER_ID) == null) { return null; } diff --git a/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterTemperature.java b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterTemperature.java index 64c970a49..7267fd6c9 100644 --- a/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterTemperature.java +++ b/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeConverterTemperature.java @@ -9,7 +9,6 @@ package org.openhab.binding.zigbee.converter; import java.math.BigDecimal; -import java.util.concurrent.ExecutionException; import org.eclipse.smarthome.core.library.types.DecimalType; import org.eclipse.smarthome.core.thing.Channel; @@ -18,12 +17,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.zsmartsystems.zigbee.ZigBeeDevice; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.zcl.ZclAttribute; import com.zsmartsystems.zigbee.zcl.ZclAttributeListener; import com.zsmartsystems.zigbee.zcl.clusters.ZclTemperatureMeasurementCluster; /** + * Converter for the temperature channel * * @author Chris Jackson - Initial Contribution * @@ -46,18 +46,14 @@ public void initializeConverter() { return; } + cluster.bind(); + // Add a listener, then request the status cluster.addAttributeListener(this); cluster.getMeasuredValue(60); // Configure reporting - no faster than once per second - no slower than 10 minutes. - try { - cluster.setMeasuredValueReporting(1, 600, 0.1).get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { - e.printStackTrace(); - } + cluster.setMeasuredValueReporting(1, 600, 0.1); initialised = true; } @@ -80,7 +76,7 @@ public void handleRefresh() { } @Override - public Channel getChannel(ThingUID thingUID, ZigBeeDevice device) { + public Channel getChannel(ThingUID thingUID, ZigBeeEndpoint device) { if (device.getCluster(ZclTemperatureMeasurementCluster.CLUSTER_ID) == null) { return null; } diff --git a/src/main/java/org/openhab/binding/zigbee/discovery/ZigBeeDiscoveryService.java b/src/main/java/org/openhab/binding/zigbee/discovery/ZigBeeDiscoveryService.java index 162c7130f..19c7c9a66 100644 --- a/src/main/java/org/openhab/binding/zigbee/discovery/ZigBeeDiscoveryService.java +++ b/src/main/java/org/openhab/binding/zigbee/discovery/ZigBeeDiscoveryService.java @@ -18,6 +18,7 @@ import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; import org.eclipse.smarthome.config.discovery.DiscoveryServiceCallback; import org.eclipse.smarthome.config.discovery.ExtendedDiscoveryService; +import org.eclipse.smarthome.core.thing.ThingStatus; import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.ThingUID; import org.openhab.binding.zigbee.ZigBeeBindingConstants; @@ -26,7 +27,7 @@ import org.slf4j.LoggerFactory; import com.zsmartsystems.zigbee.ZigBeeNode; -import com.zsmartsystems.zigbee.zdo.descriptors.NodeDescriptor.LogicalType; +import com.zsmartsystems.zigbee.zdo.field.NodeDescriptor.LogicalType; /** * The {@link ZigBeeDiscoveryService} tracks ZigBee devices which are associated @@ -71,6 +72,11 @@ public void deactivate() { @Override public void startScan() { + if (coordinatorHandler.getThing().getStatus() != ThingStatus.ONLINE) { + logger.debug("ZigBee coordinator is offline - aborted scan for {}", coordinatorHandler.getThing().getUID()); + return; + } + logger.debug("Starting ZigBee scan for {}", coordinatorHandler.getThing().getUID()); // Update the inbox with all devices we already know about diff --git a/src/main/java/org/openhab/binding/zigbee/discovery/ZigBeeNodePropertyDiscoverer.java b/src/main/java/org/openhab/binding/zigbee/discovery/ZigBeeNodePropertyDiscoverer.java index c6a02fd69..050823641 100644 --- a/src/main/java/org/openhab/binding/zigbee/discovery/ZigBeeNodePropertyDiscoverer.java +++ b/src/main/java/org/openhab/binding/zigbee/discovery/ZigBeeNodePropertyDiscoverer.java @@ -1,18 +1,19 @@ package org.openhab.binding.zigbee.discovery; +import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.Set; +import org.eclipse.smarthome.core.thing.Thing; import org.openhab.binding.zigbee.ZigBeeBindingConstants; import org.openhab.binding.zigbee.handler.ZigBeeCoordinatorHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.zsmartsystems.zigbee.ZigBeeDevice; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.ZigBeeNode; import com.zsmartsystems.zigbee.zcl.clusters.ZclBasicCluster; -import com.zsmartsystems.zigbee.zdo.descriptors.PowerDescriptor; +import com.zsmartsystems.zigbee.zdo.field.PowerDescriptor; /** * Implements a reusable method to return a set of properties about the device @@ -28,7 +29,7 @@ public Map getProperties(final ZigBeeCoordinatorHandler coordina logger.debug("{}: ZigBee node property discovery start", node.getIeeeAddress()); // Create a list of devices for the discovery service to work with - Set devices = coordinatorHandler.getNodeDevices(node.getIeeeAddress()); + Collection devices = coordinatorHandler.getNodeEndpoints(node.getIeeeAddress()); // Make sure we found some devices! if (devices.size() == 0) { @@ -40,7 +41,7 @@ public Map getProperties(final ZigBeeCoordinatorHandler coordina Map properties = new HashMap(); ZclBasicCluster basicCluster = null; - for (ZigBeeDevice device : devices) { + for (ZigBeeEndpoint device : devices) { basicCluster = (ZclBasicCluster) device.getCluster(ZclBasicCluster.CLUSTER_ID); if (basicCluster != null) { break; @@ -70,7 +71,7 @@ public Map getProperties(final ZigBeeCoordinatorHandler coordina } Integer hwVersion = basicCluster.getHwVersion(Long.MAX_VALUE); if (hwVersion != null) { - properties.put(ZigBeeBindingConstants.THING_PROPERTY_HWVERSION, hwVersion.toString()); + properties.put(Thing.PROPERTY_HARDWARE_VERSION, hwVersion.toString()); } else { logger.debug("{}: Hardware version request timeout", node.getIeeeAddress()); } @@ -91,7 +92,7 @@ public Map getProperties(final ZigBeeCoordinatorHandler coordina Integer appVersion = basicCluster.getApplicationVersion(Long.MAX_VALUE); if (appVersion != null) { - properties.put(ZigBeeBindingConstants.THING_PROPERTY_APPVERSION, appVersion.toString()); + properties.put(Thing.PROPERTY_FIRMWARE_VERSION, appVersion.toString()); } else { logger.debug("{}: Application version request timeout", node.getIeeeAddress()); } diff --git a/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorCC2531Handler.java b/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorCC2531Handler.java index 9952a9053..cc66340a5 100644 --- a/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorCC2531Handler.java +++ b/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorCC2531Handler.java @@ -8,18 +8,14 @@ */ package org.openhab.binding.zigbee.handler; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.math.BigDecimal; -import java.util.TooManyListenersException; import org.eclipse.smarthome.core.i18n.TranslationProvider; 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.types.Command; import org.openhab.binding.zigbee.ZigBeeBindingConstants; +import org.openhab.binding.zigbee.internal.ZigBeeSerialPort; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,35 +24,19 @@ import com.zsmartsystems.zigbee.serialization.DefaultSerializer; import com.zsmartsystems.zigbee.transport.ZigBeePort; -import gnu.io.CommPort; -import gnu.io.CommPortIdentifier; -import gnu.io.NoSuchPortException; -import gnu.io.PortInUseException; -import gnu.io.SerialPort; -import gnu.io.SerialPortEvent; -import gnu.io.SerialPortEventListener; -import gnu.io.UnsupportedCommOperationException; - /** * The {@link ZigBeeCoordinatorCC2531Handler} is responsible for handling * commands, which are sent to one of the channels. * * @author Chris Jackson - Initial contribution */ -public class ZigBeeCoordinatorCC2531Handler extends ZigBeeCoordinatorHandler - implements ZigBeePort, SerialPortEventListener { +public class ZigBeeCoordinatorCC2531Handler extends ZigBeeCoordinatorHandler { private Logger logger = LoggerFactory.getLogger(ZigBeeCoordinatorCC2531Handler.class); - // The serial port. - private SerialPort serialPort; - - // The serial port input stream. - private InputStream inputStream; - - // The serial port output stream. - private OutputStream outputStream; + private final int DEFAULT_BAUD = 115200; private String portId; + private int portBaud; private int magicNumber = 0xef; @@ -81,8 +61,15 @@ public void initialize() { .intValue(); } + if (getConfig().get(ZigBeeBindingConstants.CONFIGURATION_BAUD) != null) { + portBaud = ((BigDecimal) getConfig().get(ZigBeeBindingConstants.CONFIGURATION_BAUD)).intValue(); + } else { + portBaud = DEFAULT_BAUD; + } + portId = (String) getConfig().get(ZigBeeBindingConstants.CONFIGURATION_PORT); - final ZigBeeDongleTiCc2531 dongle = new ZigBeeDongleTiCc2531(this); + ZigBeePort serialPort = new ZigBeeSerialPort(portId, portBaud, false); + final ZigBeeDongleTiCc2531 dongle = new ZigBeeDongleTiCc2531(serialPort); dongle.setMagicNumber(magicNumber); @@ -91,116 +78,4 @@ public void initialize() { startZigBee(dongle, DefaultSerializer.class, DefaultDeserializer.class); } - - @Override - public void dispose() { - close(); - } - - @Override - public void thingUpdated(Thing thing) { - super.thingUpdated(thing); - } - - private void openSerialPort(final String serialPortName, int baudRate) { - logger.debug("Connecting to serial port [{}]", serialPortName); - try { - CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(serialPortName); - CommPort commPort = portIdentifier.open("org.openhab.binding.zigbee", 2000); - serialPort = (gnu.io.SerialPort) commPort; - serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, - gnu.io.SerialPort.PARITY_NONE); - ((CommPort) serialPort).enableReceiveThreshold(1); - serialPort.enableReceiveTimeout(2000); - - // RXTX serial port library causes high CPU load - // Start event listener, which will just sleep and slow down event loop - serialPort.addEventListener(this); - serialPort.notifyOnDataAvailable(true); - - logger.info("Serial port [{}] is initialized.", portId); - } catch (NoSuchPortException e) { - logger.error("Serial Error: Port {} does not exist", serialPortName); - return; - } catch (PortInUseException e) { - logger.error("Serial Error: Port {} in use.", serialPortName); - return; - } catch (UnsupportedCommOperationException e) { - logger.error("Serial Error: Unsupported comm operation on Port {}.", serialPortName); - return; - } catch (TooManyListenersException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return; - } - - try { - inputStream = serialPort.getInputStream(); - outputStream = serialPort.getOutputStream(); - - // Write the 'magic byte' - // Note that this might change in future, or with different dongles - outputStream.write(magicNumber); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - return; - } - - @Override - public boolean open() { - logger.debug("Opening ZigBee CC2531 serial port"); - try { - openSerialPort(portId, 230400); - return true; - } catch (Exception e) { - logger.error("Serial Open Error...", e); - return false; - } - } - - @Override - public void close() { - logger.debug("Closing ZigBee CC2531 serial port"); - try { - if (serialPort != null) { - serialPort.enableReceiveTimeout(1); - - inputStream.close(); - outputStream.flush(); - outputStream.close(); - - serialPort.close(); - - serialPort = null; - inputStream = null; - outputStream = null; - - logger.info("Serial port [{}] is closed.", portId); - } - } catch (Exception e) { - logger.error("Error closing serial port: ", e); - } - } - - @Override - public OutputStream getOutputStream() { - return outputStream; - } - - @Override - public InputStream getInputStream() { - return inputStream; - } - - @Override - public void serialEvent(SerialPortEvent arg0) { - try { - logger.trace("RXTX library CPU load workaround, sleep forever"); - Thread.sleep(Long.MAX_VALUE); - } catch (InterruptedException e) { - } - } } diff --git a/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorEmberHandler.java b/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorEmberHandler.java index cf01f5e24..7a013c9b8 100644 --- a/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorEmberHandler.java +++ b/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorEmberHandler.java @@ -8,20 +8,14 @@ */ package org.openhab.binding.zigbee.handler; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.math.BigDecimal; -import java.util.TooManyListenersException; import org.eclipse.smarthome.core.i18n.TranslationProvider; 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.ThingStatusDetail; import org.eclipse.smarthome.core.types.Command; import org.openhab.binding.zigbee.ZigBeeBindingConstants; +import org.openhab.binding.zigbee.internal.ZigBeeSerialPort; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,23 +25,13 @@ import com.zsmartsystems.zigbee.transport.ZigBeePort; import com.zsmartsystems.zigbee.transport.ZigBeeTransportTransmit; -import gnu.io.CommPort; -import gnu.io.CommPortIdentifier; -import gnu.io.NoSuchPortException; -import gnu.io.PortInUseException; -import gnu.io.SerialPort; -import gnu.io.SerialPortEvent; -import gnu.io.SerialPortEventListener; -import gnu.io.UnsupportedCommOperationException; - /** * The {@link ZigBeeCoordinatorEmberHandler} is responsible for handling * commands, which are sent to one of the channels. * * @author Chris Jackson - Initial contribution */ -public class ZigBeeCoordinatorEmberHandler extends ZigBeeCoordinatorHandler - implements ZigBeePort, SerialPortEventListener { +public class ZigBeeCoordinatorEmberHandler extends ZigBeeCoordinatorHandler { private Logger logger = LoggerFactory.getLogger(ZigBeeCoordinatorEmberHandler.class); private final int DEFAULT_BAUD = 115200; @@ -55,15 +39,6 @@ public class ZigBeeCoordinatorEmberHandler extends ZigBeeCoordinatorHandler private String portId; private int portBaud; - // The serial port. - private SerialPort serialPort; - - // The serial port input stream. - private InputStream inputStream; - - // The serial port output stream. - private OutputStream outputStream; - public ZigBeeCoordinatorEmberHandler(Bridge coordinator, TranslationProvider translationProvider) { super(coordinator, translationProvider); } @@ -87,7 +62,8 @@ public void initialize() { } else { portBaud = DEFAULT_BAUD; } - final ZigBeeTransportTransmit dongle = new ZigBeeDongleEzsp(this); + ZigBeePort serialPort = new ZigBeeSerialPort(portId, portBaud, true); + final ZigBeeTransportTransmit dongle = new ZigBeeDongleEzsp(serialPort); logger.debug("ZigBee Coordinator Ember opening Port:'{}' PAN:{}, EPAN:{}, Channel:{}", portId, Integer.toHexString(panId), extendedPanId, Integer.toString(channelId)); @@ -95,114 +71,4 @@ public void initialize() { startZigBee(dongle, DefaultSerializer.class, DefaultDeserializer.class); } - @Override - public void dispose() { - close(); - } - - @Override - public void thingUpdated(Thing thing) { - super.thingUpdated(thing); - } - - private void openSerialPort(final String serialPortName, int baudRate) { - logger.info("Connecting to serial port [{}] at {}", serialPortName, baudRate); - try { - CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(serialPortName); - CommPort commPort = portIdentifier.open("org.openhab.binding.zigbee", 2000); - serialPort = (gnu.io.SerialPort) commPort; - serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, - gnu.io.SerialPort.PARITY_NONE); - serialPort.setFlowControlMode(gnu.io.SerialPort.FLOWCONTROL_RTSCTS_OUT); - - ((CommPort) serialPort).enableReceiveThreshold(1); - serialPort.enableReceiveTimeout(2000); - - // RXTX serial port library causes high CPU load - // Start event listener, which will just sleep and slow down event loop - serialPort.addEventListener(this); - serialPort.notifyOnDataAvailable(true); - - logger.info("Serial port [{}] is initialized.", portId); - } catch (NoSuchPortException e) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, - "Serial Error: Port" + serialPortName + " does not exist"); - return; - } catch (PortInUseException e) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, - "Serial Error: Port" + serialPortName + " is in use"); - return; - } catch (UnsupportedCommOperationException e) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, - "Serial Error: Unsupported comm operation on Port " + serialPortName); - return; - } catch (TooManyListenersException e) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, - "Serial Error: Too many listeners on Port " + serialPortName); - return; - } - - try { - inputStream = serialPort.getInputStream(); - outputStream = serialPort.getOutputStream(); - } catch (IOException e) { - logger.error("Error getting serial streams", e); - } - - return; - } - - @Override - public boolean open() { - try { - openSerialPort(portId, portBaud); - return true; - } catch (Exception e) { - logger.error("Error...", e); - return false; - } - } - - @Override - public void close() { - try { - if (serialPort != null) { - serialPort.enableReceiveTimeout(1); - - inputStream.close(); - outputStream.flush(); - outputStream.close(); - - serialPort.close(); - - serialPort = null; - inputStream = null; - outputStream = null; - - logger.info("Serial port [{}] is closed.", portId); - } - } catch (Exception e) { - // logger.warn("Error closing serial port: '" + serialPort.getName() - // + "'", e); - } - } - - @Override - public OutputStream getOutputStream() { - return outputStream; - } - - @Override - public InputStream getInputStream() { - return inputStream; - } - - @Override - public void serialEvent(SerialPortEvent arg0) { - try { - logger.trace("RXTX library CPU load workaround, sleep forever"); - Thread.sleep(Long.MAX_VALUE); - } catch (InterruptedException e) { - } - } } diff --git a/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorHandler.java b/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorHandler.java index 25d1e2310..82c3832eb 100644 --- a/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorHandler.java +++ b/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorHandler.java @@ -12,10 +12,10 @@ import java.math.BigDecimal; import java.text.MessageFormat; -import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; -import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -39,23 +39,24 @@ import com.zsmartsystems.zigbee.ExtendedPanId; import com.zsmartsystems.zigbee.IeeeAddress; -import com.zsmartsystems.zigbee.ZigBeeAddress; -import com.zsmartsystems.zigbee.ZigBeeDevice; -import com.zsmartsystems.zigbee.ZigBeeDeviceAddress; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; +import com.zsmartsystems.zigbee.ZigBeeEndpointAddress; +import com.zsmartsystems.zigbee.ZigBeeKey; import com.zsmartsystems.zigbee.ZigBeeNetworkManager; import com.zsmartsystems.zigbee.ZigBeeNetworkManager.ZigBeeInitializeResponse; +import com.zsmartsystems.zigbee.ZigBeeNetworkMeshMonitor; import com.zsmartsystems.zigbee.ZigBeeNetworkNodeListener; import com.zsmartsystems.zigbee.ZigBeeNetworkStateListener; import com.zsmartsystems.zigbee.ZigBeeNode; -import com.zsmartsystems.zigbee.internal.ZigBeeNetworkMeshMonitor; import com.zsmartsystems.zigbee.serialization.ZigBeeDeserializer; import com.zsmartsystems.zigbee.serialization.ZigBeeSerializer; +import com.zsmartsystems.zigbee.transport.ZigBeeTransportFirmwareUpdate; import com.zsmartsystems.zigbee.transport.ZigBeeTransportState; import com.zsmartsystems.zigbee.transport.ZigBeeTransportTransmit; import com.zsmartsystems.zigbee.zcl.ZclCluster; -import com.zsmartsystems.zigbee.zdo.descriptors.NeighborTable; -import com.zsmartsystems.zigbee.zdo.descriptors.NodeDescriptor.LogicalType; -import com.zsmartsystems.zigbee.zdo.descriptors.RoutingTable; +import com.zsmartsystems.zigbee.zdo.field.NeighborTable; +import com.zsmartsystems.zigbee.zdo.field.NodeDescriptor.LogicalType; +import com.zsmartsystems.zigbee.zdo.field.RoutingTable; /** * The {@link ZigBeeCoordinatorHandler} is responsible for handling commands, @@ -79,13 +80,13 @@ public abstract class ZigBeeCoordinatorHandler extends BaseBridgeHandler private IeeeAddress nodeIeeeAddress = null; - private ZigBeeTransportTransmit zigbeeTransport; + protected ZigBeeTransportTransmit zigbeeTransport; private ZigBeeNetworkManager networkManager; private Class serializerClass; private Class deserializerClass; - protected int[] networkKey; + protected ZigBeeKey networkKey; private boolean macAddressSet = false; @@ -226,17 +227,16 @@ public void initialize() { logger.debug("Key String {}", networkKeyString); // Process the network key - networkKey = processNetworkKey(networkKeyString); - logger.debug("Key array {}", networkKey); + try { + networkKey = new ZigBeeKey(networkKeyString); + } catch (IllegalArgumentException e) { + networkKey = new ZigBeeKey(); + } // If no key exists, generate a random key and save it back to the configuration - if (networkKey == null || networkKey.length != 16 - || Arrays.equals(networkKey, new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }) - || networkKeyString.length() == 0) { - networkKeyString = createNetworkKey(); - logger.debug("Key initialised String {}", networkKeyString); - networkKey = processNetworkKey(networkKeyString); - logger.debug("Key initialised array {}", networkKey); + if (!networkKey.isValid()) { + networkKey = ZigBeeKey.createRandom(); + logger.debug("Key initialised {}", networkKey); } logger.debug("Key final array {}", networkKey); @@ -334,7 +334,7 @@ private void initialiseZigBee() { ExtendedPanId currentExtendedPanId = networkManager.getZigBeeExtendedPanId(); if (initializeNetwork) { - networkManager.setZigBeeSecurityKey(networkKey); + networkManager.setZigBeeNetworkKey(networkKey); networkManager.setZigBeeChannel(channelId); networkManager.setZigBeePanId(panId); networkManager.setZigBeeExtendedPanId(extendedPanId); @@ -368,67 +368,7 @@ private void initialiseZigBee() { // Start the mesh monitor meshMonitor = new ZigBeeNetworkMeshMonitor(networkManager); - meshMonitor.startup(86400); - } - - // Create random network key - private String createNetworkKey() { - logger.debug("Creating random ZigBee network key."); - String networkKeyString = ""; - for (int cnt = 0; cnt < 16; cnt++) { - int value = (int) Math.floor((Math.random() * 255)); - if (cnt != 0) { - networkKeyString += " "; - } - networkKeyString += String.format("%02X", value); - } - - try { - // Persist the key - Configuration configuration = editConfiguration(); - configuration.put(CONFIGURATION_NETWORKKEY, networkKeyString); - - // If the thing is defined statically, then this will fail and we will never start! - updateConfiguration(configuration); - - logger.debug("Created random ZigBee network key."); - } catch (IllegalStateException e) { - logger.debug("Error updating configuration", e); - } - - return networkKeyString; - } - - /** - * Process the network key. The key is provided as a string of hexadecimal values. Values can be space or comma - * delimited, or can have no separation between values. Values can be prefixed with 0x or not. - * - * @param value {@link String} containing the new network key - */ - private int[] processNetworkKey(String value) { - if (value == null) { - logger.debug("Network key must not be null"); - return null; - } - - String hexString = value.replace("0x", ""); - hexString = hexString.replace(",", ""); - hexString = hexString.replace(" ", ""); - - if ((hexString.length() % 2) != 0) { - logger.debug("Network key must contain an even number of characters"); - return null; - } - - int[] networkKey = new int[hexString.length() / 2]; - char enc[] = hexString.toCharArray(); - for (int i = 0; i < enc.length; i += 2) { - StringBuilder curr = new StringBuilder(2); - curr.append(enc[i]).append(enc[i + 1]); - networkKey[i / 2] = Integer.parseInt(curr.toString(), 16); - } - - return networkKey; + meshMonitor.startup(90); } /** @@ -452,18 +392,9 @@ public void run() { public void handleConfigurationUpdate(Map configurationParameters) { logger.debug("{}: Configuration received (Coordinator).", nodeIeeeAddress); - // Sanity check - if (configurationParameters == null) { - logger.warn("{}: No configuration parameters provided.", nodeIeeeAddress); - return; - } - Configuration configuration = editConfiguration(); for (Entry configurationParameter : configurationParameters.entrySet()) { switch (configurationParameter.getKey()) { - case ZigBeeBindingConstants.CONFIGURATION_BAUD: - configuration.put(CONFIGURATION_BAUD, configurationParameter.getValue()); - break; case ZigBeeBindingConstants.CONFIGURATION_JOINENABLE: if ((Boolean) configurationParameter.getValue() == true) { permitJoin(nodeIeeeAddress, 60); @@ -471,8 +402,9 @@ public void handleConfigurationUpdate(Map configurationParameter configuration.put(CONFIGURATION_JOINENABLE, false); break; default: - logger.warn("{}: Unhandled configuration parameter {}.", nodeIeeeAddress, - configurationParameter.getKey()); + configuration.put(configurationParameter.getKey(), configurationParameter.getValue()); + logger.debug("{}: Unhandled configuration parameter {} >> {}.", nodeIeeeAddress, + configurationParameter.getKey(), configurationParameter.getValue()); break; } } @@ -481,22 +413,8 @@ public void handleConfigurationUpdate(Map configurationParameter updateConfiguration(configuration); } - /** - * Returns a list of all known devices - * - * @return list of devices - */ - public List getDeviceList() { - return networkManager.getDevices(); - } - public void startDeviceDiscovery() { - final List devices = networkManager.getDevices(); - for (ZigBeeDevice device : devices) { - // addNewNode(node); - } - - // TODO: Move to discovery handler + // TODO: Move to discovery handler? // Allow devices to join for 60 seconds networkManager.permitJoin(60); @@ -611,30 +529,48 @@ public void nodeUpdated(ZigBeeNode node) { properties.put(ZigBeeBindingConstants.THING_PROPERTY_LOGICALTYPE, node.getLogicalType().toString()); + // If this dongle supports firmware updates, then set the version + if (zigbeeTransport instanceof ZigBeeTransportFirmwareUpdate) { + ZigBeeTransportFirmwareUpdate firmwareTransport = (ZigBeeTransportFirmwareUpdate) zigbeeTransport; + properties.put(Thing.PROPERTY_FIRMWARE_VERSION, firmwareTransport.getFirmwareVersion()); + } + updateProperties(properties); } - public ZigBeeDevice getDevice(ZigBeeAddress address) { + public ZigBeeEndpoint getEndpoint(ZigBeeEndpointAddress address) { if (networkManager == null) { return null; } - return networkManager.getDevice(address); + ZigBeeNode node = networkManager.getNode(address.getAddress()); + if (node == null) { + return null; + } + return node.getEndpoint(address.getEndpoint()); } - public Set getNodeDevices(IeeeAddress nodeIeeeAddress) { - return networkManager.getNodeDevices(nodeIeeeAddress); + public Collection getNodeEndpoints(IeeeAddress nodeIeeeAddress) { + if (networkManager == null) { + return Collections. emptySet(); + } + ZigBeeNode node = networkManager.getNode(nodeIeeeAddress); + if (node == null) { + return Collections. emptySet(); + } + + return node.getEndpoints(); } public Set getNodes() { return networkManager.getNodes(); } - public ZclCluster getCluster(ZigBeeDeviceAddress address, int clusterId) { - ZigBeeDevice device = networkManager.getDevice(address); - if (device == null) { + public ZclCluster getCluster(ZigBeeEndpointAddress address, int clusterId) { + ZigBeeEndpoint endpoint = getEndpoint(address); + if (endpoint == null) { return null; } - return device.getCluster(clusterId); + return endpoint.getCluster(clusterId); } @Override @@ -657,6 +593,9 @@ public void networkStateUpdated(final ZigBeeTransportState state) { } public ZigBeeNode getNode(IeeeAddress nodeIeeeAddress) { + if (networkManager == null) { + return null; + } return networkManager.getNode(nodeIeeeAddress); } @@ -676,7 +615,7 @@ public boolean permitJoin(IeeeAddress address, int duration) { logger.debug("{}: ZigBee join command to {}", address, node.getNetworkAddress()); - networkManager.permitJoin(new ZigBeeDeviceAddress(node.getNetworkAddress()), duration); + networkManager.permitJoin(new ZigBeeEndpointAddress(node.getNetworkAddress()), duration); return true; } @@ -709,4 +648,16 @@ public boolean leave(IeeeAddress address) { public IeeeAddress getIeeeAddress() { return nodeIeeeAddress; } -} \ No newline at end of file + + /** + * Search for a node - will perform a discovery on the defined {@link IeeeAddress} + * + * @param nodeIeeeAddress {@link IeeeAddress} of the node to discover + */ + public void rediscoverNode(IeeeAddress nodeIeeeAddress) { + if (networkManager == null) { + return; + } + networkManager.rediscoverNode(nodeIeeeAddress); + } +} diff --git a/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorTelegesisHandler.java b/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorTelegesisHandler.java new file mode 100644 index 000000000..81889816a --- /dev/null +++ b/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeCoordinatorTelegesisHandler.java @@ -0,0 +1,159 @@ +/** + * Copyright (c) 2014-2016 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.openhab.binding.zigbee.handler; + +import java.math.BigDecimal; + +import org.eclipse.smarthome.core.i18n.TranslationProvider; +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.ThingStatusDetail; +import org.eclipse.smarthome.core.thing.binding.firmware.Firmware; +import org.eclipse.smarthome.core.thing.binding.firmware.FirmwareUpdateHandler; +import org.eclipse.smarthome.core.thing.binding.firmware.ProgressCallback; +import org.eclipse.smarthome.core.thing.binding.firmware.ProgressStep; +import org.eclipse.smarthome.core.types.Command; +import org.openhab.binding.zigbee.ZigBeeBindingConstants; +import org.openhab.binding.zigbee.internal.ZigBeeSerialPort; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.zsmartsystems.zigbee.dongle.telegesis.ZigBeeDongleTelegesis; +import com.zsmartsystems.zigbee.serialization.DefaultDeserializer; +import com.zsmartsystems.zigbee.serialization.DefaultSerializer; +import com.zsmartsystems.zigbee.transport.ZigBeePort; +import com.zsmartsystems.zigbee.transport.ZigBeeTransportFirmwareCallback; +import com.zsmartsystems.zigbee.transport.ZigBeeTransportFirmwareStatus; +import com.zsmartsystems.zigbee.transport.ZigBeeTransportFirmwareUpdate; +import com.zsmartsystems.zigbee.transport.ZigBeeTransportTransmit; + +/** + * The {@link ZigBeeCoordinatorTelegesisHandler} is responsible for handling + * commands, which are sent to one of the channels. + * + * @author Chris Jackson - Initial contribution + */ +public class ZigBeeCoordinatorTelegesisHandler extends ZigBeeCoordinatorHandler implements FirmwareUpdateHandler { + private Logger logger = LoggerFactory.getLogger(ZigBeeCoordinatorTelegesisHandler.class); + + private final int DEFAULT_BAUD = 19200; + + private String portId; + private int portBaud; + private ZigBeeTransportTransmit dongle; + + public ZigBeeCoordinatorTelegesisHandler(Bridge coordinator, TranslationProvider translationProvider) { + super(coordinator, translationProvider); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + // Not required - yet! + } + + @Override + public void initialize() { + logger.debug("Initializing ZigBee Telegesis serial bridge handler."); + + // Call the parent to finish any global initialisation + super.initialize(); + + portId = (String) getConfig().get(ZigBeeBindingConstants.CONFIGURATION_PORT); + if (portId == null || portId.length() == 0) { + logger.debug("ZigBee Telegesis serial port is not set."); + return; + } + + if (getConfig().get(ZigBeeBindingConstants.CONFIGURATION_BAUD) != null) { + portBaud = ((BigDecimal) getConfig().get(ZigBeeBindingConstants.CONFIGURATION_BAUD)).intValue(); + } else { + portBaud = DEFAULT_BAUD; + } + ZigBeePort serialPort = new ZigBeeSerialPort(portId, portBaud, false); + dongle = new ZigBeeDongleTelegesis(serialPort); + + logger.debug("ZigBee Coordinator Telegesis opening Port:'{}' PAN:{}, EPAN:{}, Channel:{}", portId, + Integer.toHexString(panId), extendedPanId, Integer.toString(channelId)); + + startZigBee(dongle, DefaultSerializer.class, DefaultDeserializer.class); + } + + @Override + public void thingUpdated(Thing thing) { + super.thingUpdated(thing); + } + + @Override + public void updateFirmware(Firmware firmware, ProgressCallback progressCallback) { + logger.debug("Telegesis coordinator: update firmware with {}", firmware.getVersion()); + + updateStatus(ThingStatus.OFFLINE); + zigbeeTransport.shutdown(); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.FIRMWARE_UPDATING); + + // Define the sequence of the firmware update so that external consumers can listen for the progress + progressCallback.defineSequence(ProgressStep.DOWNLOADING, ProgressStep.TRANSFERRING, ProgressStep.UPDATING); + + ZigBeeTransportFirmwareUpdate firmwareUpdate = (ZigBeeTransportFirmwareUpdate) zigbeeTransport; + firmwareUpdate.updateFirmware(firmware.getInputStream(), new ZigBeeTransportFirmwareCallback() { + @Override + public void firmwareUpdateCallback(ZigBeeTransportFirmwareStatus status) { + logger.debug("Telegesis dongle firmware status: {}", status); + switch (status) { + case FIRMWARE_UPDATE_STARTED: + // ProgressStep.DOWNLOADING + progressCallback.next(); + break; + case FIRMWARE_TRANSFER_STARTED: + // ProgressStep.TRANSFERRING + progressCallback.next(); + break; + case FIRMWARE_TRANSFER_COMPLETE: + // ProgressStep.UPDATING + progressCallback.next(); + break; + case FIRMWARE_UPDATE_COMPLETE: + progressCallback.success(); + + // Restart the handler... + dispose(); + initialize(); + break; + case FIRMWARE_UPDATE_CANCELLED: + progressCallback.canceled(); + break; + case FIRMWARE_UPDATE_FAILED: + progressCallback.failed("zigbee.firmware.failed"); + break; + default: + break; + } + } + }); + } + + @Override + public void cancel() { + logger.debug("Telegesis coordinator: cancel firmware update"); + ZigBeeTransportFirmwareUpdate firmwareUpdate = (ZigBeeTransportFirmwareUpdate) zigbeeTransport; + firmwareUpdate.cancelUpdateFirmware(); + } + + @Override + public boolean isUpdateExecutable() { + // Always allow the firmware to be updated + // Don't link this to online/offline as if the bootload fails, then the dongle + // will always start in the bootloader. This will mean the dongle is always offline + // but as long as we can open the serial port we should be able to bootload new + // firmware. + return true; + } +} diff --git a/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeThingHandler.java b/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeThingHandler.java index 9a250ac62..2a9056abb 100644 --- a/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeThingHandler.java +++ b/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeThingHandler.java @@ -11,6 +11,7 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; +import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -28,21 +29,26 @@ import org.eclipse.smarthome.core.thing.ThingStatusInfo; import org.eclipse.smarthome.core.thing.binding.BaseThingHandler; import org.eclipse.smarthome.core.thing.binding.builder.ThingBuilder; +import org.eclipse.smarthome.core.thing.binding.firmware.Firmware; +import org.eclipse.smarthome.core.thing.binding.firmware.FirmwareUpdateHandler; +import org.eclipse.smarthome.core.thing.binding.firmware.ProgressCallback; +import org.eclipse.smarthome.core.thing.binding.firmware.ProgressStep; import org.eclipse.smarthome.core.types.Command; import org.eclipse.smarthome.core.types.State; import org.openhab.binding.zigbee.ZigBeeBindingConstants; import org.openhab.binding.zigbee.converter.ZigBeeChannelConverter; import org.openhab.binding.zigbee.discovery.ZigBeeNodePropertyDiscoverer; import org.openhab.binding.zigbee.internal.ZigBeeActivator; +import org.osgi.framework.ServiceRegistration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.zsmartsystems.zigbee.IeeeAddress; -import com.zsmartsystems.zigbee.ZigBeeDevice; +import com.zsmartsystems.zigbee.ZigBeeEndpoint; import com.zsmartsystems.zigbee.ZigBeeNetworkNodeListener; import com.zsmartsystems.zigbee.ZigBeeNode; -import com.zsmartsystems.zigbee.zdo.descriptors.NeighborTable; -import com.zsmartsystems.zigbee.zdo.descriptors.RoutingTable; +import com.zsmartsystems.zigbee.zdo.field.NeighborTable; +import com.zsmartsystems.zigbee.zdo.field.RoutingTable; /** * @@ -65,6 +71,9 @@ public class ZigBeeThingHandler extends BaseThingHandler implements ZigBeeNetwor private final TranslationProvider translationProvider; + private FirmwareHandler firmwareHandler = null; + private ServiceRegistration firmwareRegistration; + public ZigBeeThingHandler(Thing zigbeeDevice, TranslationProvider translationProvider) { super(zigbeeDevice); this.translationProvider = translationProvider; @@ -112,6 +121,7 @@ public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { coordinatorHandler = (ZigBeeCoordinatorHandler) getBridge().getHandler(); coordinatorHandler.addNetworkNodeListener(this); + coordinatorHandler.rediscoverNode(nodeIeeeAddress); initialiseZigBeeNode(); } @@ -141,11 +151,20 @@ private void doNodeInitialisation() { return; } + // While checking the endpoints, see if OTA cluster is supported + boolean otaSupported = false; + // Create the channels from the device // Process all the endpoints for this device and add all channels as derived from the supported clusters List clusterChannels = new ArrayList(); - for (ZigBeeDevice device : coordinatorHandler.getNodeDevices(nodeIeeeAddress)) { + for (ZigBeeEndpoint device : coordinatorHandler.getNodeEndpoints(nodeIeeeAddress)) { clusterChannels.addAll(ZigBeeChannelConverter.getChannels(getThing().getUID(), device)); + + // Check if this endpoint supports OTA firmware update + // TODO Use ZclOtaUpgradeCluster.CLUSTER.ID + if (device.getInputClusterIds().contains(0x19)) { + otaSupported = true; + } } logger.debug("{}: Created {} channels", nodeIeeeAddress, clusterChannels.size()); @@ -184,12 +203,24 @@ private void doNodeInitialisation() { nodeInitialised = true; - return; + // If this node supports the OTA firmware cluster, then register the FirmwareUpdateHandler + otaSupported = true; + if (otaSupported) { + firmwareHandler = new FirmwareHandler(getThing(), this); + + // Register the FirmwareUpdateHandler as an OSGi service + firmwareRegistration = (ServiceRegistration) bundleContext.registerService( + FirmwareUpdateHandler.class.getName(), firmwareHandler, new Hashtable()); + } } @Override public void dispose() { - logger.debug("Handler disposes. Unregistering listener."); + if (firmwareRegistration != null) { + firmwareRegistration.unregister(); + } + + logger.debug("Handler dispose. Unregistering listener."); if (nodeIeeeAddress != null) { if (coordinatorHandler != null) { // coordinatorHandler.unsubscribeEvents(nodeAddress, this); @@ -202,12 +233,6 @@ public void dispose() { public void handleConfigurationUpdate(Map configurationParameters) { logger.debug("{}: Configuration received.", nodeIeeeAddress); - // Sanity check - if (configurationParameters == null) { - logger.warn("{}: No configuration parameters provided.", nodeIeeeAddress); - return; - } - Configuration configuration = editConfiguration(); for (Entry configurationParameter : configurationParameters.entrySet()) { switch (configurationParameter.getKey()) { @@ -234,14 +259,14 @@ public void handleCommand(ChannelUID channelUID, Command command) { // Check that we have a coordinator to work through if (coordinatorHandler == null) { - logger.warn("Coordinator handler not found. Cannot handle command without coordinator."); + logger.debug("Coordinator handler not found. Cannot handle command without coordinator."); updateStatus(ThingStatus.OFFLINE); return; } ZigBeeChannelConverter handler = channels.get(channelUID); if (handler == null) { - logger.warn("No handler found for {}", channelUID); + logger.debug("No handler found for {}", channelUID); return; } @@ -374,4 +399,51 @@ public ZigBeeCoordinatorHandler getCoordinatorHandler() { public IeeeAddress getIeeeAddress() { return nodeIeeeAddress; } + + class FirmwareHandler implements FirmwareUpdateHandler { + private final Thing thing; + private final ZigBeeThingHandler thingHandler; + + FirmwareHandler(Thing thing, ZigBeeThingHandler thingHandler) { + this.thing = thing; + this.thingHandler = thingHandler; + } + + @Override + public Thing getThing() { + return thing; + } + + @Override + public void updateFirmware(Firmware firmware, ProgressCallback progressCallback) { + thingHandler.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.FIRMWARE_UPDATING); + + progressCallback.defineSequence(ProgressStep.DOWNLOADING, ProgressStep.TRANSFERRING, ProgressStep.UPDATING); + + // download / read firmware image + progressCallback.next(); + + // transfer image to device + progressCallback.next(); + + // triggering the actual firmware update + progressCallback.next(); + + // here: send immediately the success information because it is not mandatory for this implementation to + // wait for the successful update of the device + progressCallback.success(); + } + + @Override + public void cancel() { + // TODO Auto-generated method stub + + } + + @Override + public boolean isUpdateExecutable() { + // TODO Auto-generated method stub + return false; + } + } } diff --git a/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeActivator.java b/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeActivator.java index c1137076d..5a60150ac 100644 --- a/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeActivator.java +++ b/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeActivator.java @@ -21,7 +21,7 @@ */ public final class ZigBeeActivator implements BundleActivator { - private static Logger logger = LoggerFactory.getLogger(ZigBeeActivator.class); + private Logger logger = LoggerFactory.getLogger(ZigBeeActivator.class); private static BundleContext context; diff --git a/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeConfigProvider.java b/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeConfigProvider.java index 200d7ff1c..2c66f2ce4 100644 --- a/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeConfigProvider.java +++ b/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeConfigProvider.java @@ -40,7 +40,7 @@ import com.zsmartsystems.zigbee.IeeeAddress; import com.zsmartsystems.zigbee.ZigBeeNode; -import com.zsmartsystems.zigbee.zdo.descriptors.NodeDescriptor.LogicalType; +import com.zsmartsystems.zigbee.zdo.field.NodeDescriptor.LogicalType; /** * diff --git a/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeHandlerFactory.java b/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeHandlerFactory.java index 2b7ed498d..34c806f52 100644 --- a/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeHandlerFactory.java +++ b/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeHandlerFactory.java @@ -17,6 +17,7 @@ import org.openhab.binding.zigbee.ZigBeeBindingConstants; import org.openhab.binding.zigbee.handler.ZigBeeCoordinatorCC2531Handler; import org.openhab.binding.zigbee.handler.ZigBeeCoordinatorEmberHandler; +import org.openhab.binding.zigbee.handler.ZigBeeCoordinatorTelegesisHandler; import org.openhab.binding.zigbee.handler.ZigBeeThingHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,11 +53,14 @@ protected ThingHandler createHandler(Thing thing) { logger.debug("Creating coordinator handler for {}", thing); // Handle coordinators here + if (thingTypeUID.equals(ZigBeeBindingConstants.COORDINATOR_TYPE_EMBER)) { + return new ZigBeeCoordinatorEmberHandler((Bridge) thing, translationProvider); + } if (thingTypeUID.equals(ZigBeeBindingConstants.COORDINATOR_TYPE_CC2531)) { return new ZigBeeCoordinatorCC2531Handler((Bridge) thing, translationProvider); } - if (thingTypeUID.equals(ZigBeeBindingConstants.COORDINATOR_TYPE_EMBER)) { - return new ZigBeeCoordinatorEmberHandler((Bridge) thing, translationProvider); + if (thingTypeUID.equals(ZigBeeBindingConstants.COORDINATOR_TYPE_TELEGESIS)) { + return new ZigBeeCoordinatorTelegesisHandler((Bridge) thing, translationProvider); } // Everything else gets handled in a single handler diff --git a/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeNetworkStateSerializerImpl.java b/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeNetworkStateSerializerImpl.java index 56dece9fe..bb83c4dd6 100644 --- a/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeNetworkStateSerializerImpl.java +++ b/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeNetworkStateSerializerImpl.java @@ -21,16 +21,15 @@ import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; import com.thoughtworks.xstream.io.xml.StaxDriver; -import com.zsmartsystems.zigbee.ZigBeeDevice; import com.zsmartsystems.zigbee.ZigBeeNetworkManager; import com.zsmartsystems.zigbee.ZigBeeNetworkStateSerializer; import com.zsmartsystems.zigbee.ZigBeeNode; -import com.zsmartsystems.zigbee.dao.ZigBeeDeviceDao; +import com.zsmartsystems.zigbee.dao.ZigBeeEndpointDao; import com.zsmartsystems.zigbee.dao.ZigBeeNodeDao; -import com.zsmartsystems.zigbee.zdo.descriptors.NodeDescriptor.FrequencyBandType; -import com.zsmartsystems.zigbee.zdo.descriptors.NodeDescriptor.MacCapabilitiesType; -import com.zsmartsystems.zigbee.zdo.descriptors.NodeDescriptor.ServerCapabilitiesType; -import com.zsmartsystems.zigbee.zdo.descriptors.PowerDescriptor.PowerSourceType; +import com.zsmartsystems.zigbee.zdo.field.NodeDescriptor.FrequencyBandType; +import com.zsmartsystems.zigbee.zdo.field.NodeDescriptor.MacCapabilitiesType; +import com.zsmartsystems.zigbee.zdo.field.NodeDescriptor.ServerCapabilitiesType; +import com.zsmartsystems.zigbee.zdo.field.PowerDescriptor.PowerSourceType; /** * Serializes and deserializes the ZigBee network state. @@ -70,7 +69,7 @@ private XStream openStream() { stream.setClassLoader(ZigBeeNetworkStateSerializerImpl.class.getClassLoader()); stream.alias("ZigBeeNode", ZigBeeNodeDao.class); - stream.alias("ZigBeeDevice", ZigBeeDeviceDao.class); + stream.alias("ZigBeeEndpoint", ZigBeeEndpointDao.class); stream.alias("MacCapabilitiesType", MacCapabilitiesType.class); stream.alias("ServerCapabilitiesType", ServerCapabilitiesType.class); stream.alias("PowerSourceType", PowerSourceType.class); @@ -81,23 +80,19 @@ private XStream openStream() { /** * Serializes the network state. * - * @param networkState the network state + * @param networkManager the network state * @return the serialized network state as json {@link String}. */ @Override - public void serialize(final ZigBeeNetworkManager networkState) { + public void serialize(final ZigBeeNetworkManager networkManager) { XStream stream = openStream(); final List destinations = new ArrayList(); - for (ZigBeeNode node : networkState.getNodes()) { + for (ZigBeeNode node : networkManager.getNodes()) { ZigBeeNodeDao nodeDao = ZigBeeNodeDao.createFromZigBeeNode(node); destinations.add(nodeDao); } - for (ZigBeeDevice device : networkState.getDevices()) { - ZigBeeDeviceDao deviceDao = ZigBeeDeviceDao.createFromZigBeeDevice(device); - destinations.add(deviceDao); - } final File file = new File(networkStateFilePath + "/" + networkStateFileName); try { @@ -136,8 +131,6 @@ public void deserialize(final ZigBeeNetworkManager networkState) { for (final Object object : objects) { if (object instanceof ZigBeeNodeDao) { networkState.addNode(ZigBeeNodeDao.createFromZigBeeDao(networkState, (ZigBeeNodeDao) object)); - } else { - networkState.addDevice(ZigBeeDeviceDao.createFromZigBeeDao(networkState, (ZigBeeDeviceDao) object)); } } } catch (UnsupportedEncodingException | FileNotFoundException e) { diff --git a/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeSerialPort.java b/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeSerialPort.java new file mode 100644 index 000000000..36edfc063 --- /dev/null +++ b/src/main/java/org/openhab/binding/zigbee/internal/ZigBeeSerialPort.java @@ -0,0 +1,264 @@ +package org.openhab.binding.zigbee.internal; +/** + * Copyright (c) 2016-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 + */ + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.TooManyListenersException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.zsmartsystems.zigbee.transport.ZigBeePort; + +import gnu.io.CommPort; +import gnu.io.CommPortIdentifier; +import gnu.io.NoSuchPortException; +import gnu.io.PortInUseException; +import gnu.io.SerialPort; +import gnu.io.SerialPortEvent; +import gnu.io.SerialPortEventListener; +import gnu.io.UnsupportedCommOperationException; + +/** + * The default/reference Java serial port implementation using serial events to provide a non-blocking read call. + * + * @author Chris Jackson + */ +public class ZigBeeSerialPort implements ZigBeePort, SerialPortEventListener { + /** + * The logger. + */ + private final static Logger logger = LoggerFactory.getLogger(ZigBeeSerialPort.class); + + /** + * The portName portName. + */ + private SerialPort serialPort; + + /** + * The serial port input stream. + */ + private InputStream inputStream; + + /** + * The serial port output stream. + */ + private OutputStream outputStream; + + /** + * The port identifier. + */ + private final String portName; + + /** + * The baud rate. + */ + private final int baudRate; + + /** + * True to enable RTS / CTS flow control + */ + private final boolean flowControl; + + /** + * The circular fifo queue for receive data + */ + private int[] buffer = new int[512]; + + /** + * The receive buffer end pointer (where we put the newly received data) + */ + private int end = 0; + + /** + * The receive buffer start pointer (where we take the data to pass to the application) + */ + private int start = 0; + + /** + * The length of the receive buffer + */ + private int maxLength = 512; + + /** + * Synchronisation object for buffer queue manipulation + */ + private Object bufferSynchronisationObject = new Object(); + + /** + * Constructor setting port name and baud rate. + * + * @param portName the port name + * @param baudRate the baud rate + * @param flowControl to use flow control + */ + public ZigBeeSerialPort(String portName, int baudRate, boolean flowControl) { + this.portName = portName; + this.baudRate = baudRate; + this.flowControl = flowControl; + } + + @Override + public boolean open() { + return open(baudRate); + } + + @Override + public boolean open(int baudRate) { + try { + logger.debug("Connecting to serial port [{}] at {} baud, flow control {}.", portName, baudRate, + flowControl ? "enabled" : "disabled"); + try { + CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); + CommPort commPort = portIdentifier.open("org.openhab.binding.zigbee", 100); + serialPort = (SerialPort) commPort; + serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, + SerialPort.PARITY_NONE); + if (flowControl) { + serialPort.setFlowControlMode(gnu.io.SerialPort.FLOWCONTROL_RTSCTS_OUT); + } else { + serialPort.setFlowControlMode(gnu.io.SerialPort.FLOWCONTROL_NONE); + } + serialPort.enableReceiveThreshold(1); + serialPort.enableReceiveTimeout(100); + serialPort.addEventListener(this); + serialPort.notifyOnDataAvailable(true); + + logger.info("Serial port [{}] is initialized.", portName); + } catch (NoSuchPortException e) { + logger.error("Serial Error: Port {} does not exist", portName); + return false; + } catch (PortInUseException e) { + logger.error("Serial Error: Port {} in use.", portName); + return false; + } catch (UnsupportedCommOperationException e) { + logger.error("Serial Error: Unsupported comm operation on Port {}.", portName); + return false; + } catch (TooManyListenersException e) { + logger.error("Serial Error: Too many listeners on Port {}.", portName); + return false; + } + + try { + inputStream = serialPort.getInputStream(); + outputStream = serialPort.getOutputStream(); + } catch (IOException e) { + } + + return true; + } catch (Exception e) { + logger.warn("Unable to open serial port: " + e.getMessage()); + return false; + } + } + + @Override + public void close() { + try { + if (serialPort != null) { + synchronized (this) { + serialPort.enableReceiveTimeout(1); + + inputStream.close(); + outputStream.flush(); + outputStream.close(); + + serialPort.close(); + + serialPort = null; + inputStream = null; + outputStream = null; + this.notify(); + } + + logger.info("Serial port '" + portName + "' closed."); + } + } catch (Exception e) { + logger.warn("Error closing serial port: '" + portName + "'", e); + } + } + + @Override + public void write(int value) { + if (outputStream == null) { + return; + } + try { + outputStream.write(value); + } catch (IOException e) { + } + } + + @Override + public int read() { + return read(9999999); + } + + @Override + public int read(int timeout) { + long endTime = System.currentTimeMillis() + timeout; + + try { + while (System.currentTimeMillis() < endTime) { + synchronized (bufferSynchronisationObject) { + if (start != end) { + int value = buffer[start++]; + if (start >= maxLength) { + start = 0; + } + return value; + } + } + + synchronized (this) { + if (serialPort == null) { + return -1; + } + + wait(endTime - System.currentTimeMillis()); + } + } + return -1; + } catch (InterruptedException e) { + e.printStackTrace(); + } + return -1; + } + + @Override + public void serialEvent(SerialPortEvent event) { + if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE) { + try { + synchronized (bufferSynchronisationObject) { + int recv; + while ((recv = inputStream.read()) != -1) { + buffer[end++] = recv; + if (end >= maxLength) { + end = 0; + } + } + } + } catch (IOException e) { + } + + synchronized (this) { + this.notify(); + } + } + } + + @Override + public void purgeRxBuffer() { + synchronized (bufferSynchronisationObject) { + start = 0; + end = 0; + } + } +}