The ZCL library API allows facilitating the development of application which interfaces
with the Cleode UBee™ dongle.
It includes a JAR ("zcl-connector.jar") and a C++ dynamic library
(".dll" for Windows, ".so" for Linux or ".dynlib" for MacOSX).
This API provides services for the following functionalities:
The detection of UBee on any USB port is automatic, except in the case where the port name is specified.
The return value of startUbee() service indicates if the UBee is detected or not.
When UBee is detected, an ubeeStarted event is notified and you can check the license validity.
If UBee is unplugged, an ubeeReleased event is notified. And thereafter every 5 seconds, the API verify if UBee is replugged.
When you call the stopUbee() service, an ubeeStopped event is notified.
If UBee is awaiting reprogramming, an ubeeWaitingBoot event is notified.
public class Application implements AliveCallback { ZigbeeConnectorServices zcs = ZigbeeConnector.singleton.getZigbeeConnectorServices(); public Application() throws IOException { // Start the communication with UBee boolean result = zcs.startUbee(this); //Display if the UBee is detected or not System.out.printf("UBee is %s \n", (result ? "detected" : "not detected")); System.out.println("Press any key to Quit the application"); // Wait for the pressing any key System.in.read(); // Stop the communication with UBee zcs.stopUbee(); } public void ubeeStarted() { System.out.println("====> UBee Started notification"); System.out.printf("UBee License validity for %s : %s\n", zcs.getCoordinator(), Boolean.toString(zcs.isLicenseValid())); } @Override public void ubeeReleased() { System.out.println("====> UBee Released notification"); } @Override public void ubeeStopped() { System.out.println("====> UBee Stopped notification"); } @Override public void ubeeWaitingBoot() { System.out.println("====> UBee Waiting Boot notification"); } }
Starting UBee on a specific port name
// Windows zcs.startUbee(this, "COM22"); // Linux zcs.startUbee(this, "/dev/ttyUSB1");
This subscription allows to receive the events such as associating, updating and deleting of the Zigbee nodes.
It is strongly recommended to make a clone of the node if you want to store the node instance and to modify it.
After the UBee is starting, a discovery of Zigbee node is done and at least 3 events are notified for each node.
- When the structure of the node has been read : Created / Discover.
- When the model identifier of the node has been read : Updated / ModelID.
- When the bindings of the node has been read : Updated / Bindings.
public class Application implements AliveCallback, ZigbeeConnectorNodeEvents { ZigbeeConnectorServices zcs = ZigbeeConnector.singleton.getZigbeeConnectorServices(); public Application() throws IOException { // Subcribe to receive node events zcs.subscribe(this); // Start the communication with UBee zcs.startUbee(this); System.out.println("Press any key to Quit the application"); // Wait for the pressing any key System.in.read(); // Stop the communication with UBee zcs.stopUbee(); } ... @Override public void notifyNodeCreated(final Node node, final Reason reason) { System.out.printf("====> Node Created %s : %s\n", node, reason); } @Override public void notifyNodeUpdated(final Node node, final Reason reason) { System.out.printf("====> Node Updated %s : %s\n", node, reason); } @Override public void notifyNodeDeleted(final Node node, final Reason reason) { System.out.printf("====> Node Deleted %s : %s\n", node, reason); } }
The Read Attributes command is used to read the attribute values of a cluster from the device.
The response of this request is received on the callback passed as parameter to the service.
A timeout expires if the device is not responding to the request.
The timeout period for router is 15 seconds by default, and 30 seconds for end-devices.
ZigbeeConnectorServices zcs = ZigbeeConnector.singleton.getZigbeeConnectorServices(); ZigbeeAddressResolvingServices zars = ZigbeeConnector.singleton.getZigbeeAddressResolvingServices(); ResponseCallBack<ReadAttributeResponse[]> reader = new ResponseCallBack<ReadAttributeResponse[]>() { @Override public void responseReceived( int nwkAddr, int epNumber, int clusterId, int seqNumber, final ReadAttributeResponse[] responses) { if (responses != null) { // Responses received for (ReadAttributeResponse attr : responses) { if (attr.getStatus() == Status.SUCCESS) { // Successful reading of this attribute } else { // Unsuccessful reading of this attribute } } } else { // Timeout expired ! } } }; // Search a device by its IEEE address IEEEAddress ieeeAddr = IEEEAddress.convertString("11-22-33-44-55-66-77-88"); Node node = zars.searchNode(ieeeAddr); // Read the fourth first attributes of the Basic cluster int seqNumber = zcs.sendReadAttributesCommand(reader, node.getNwkAddr(), node.getEpByInCluster(ClusterName.Basic_Attributes.getId()), ClusterName.Basic_Attributes.getId(), new Attribute[] { Attribute.factory.newInstance(AttrConstants.ZCL_VERSION_ATTR), Attribute.factory.newInstance(AttrConstants.APP_VERSION_ATTR), Attribute.factory.newInstance(AttrConstants.STACK_VERSION_ATTR), Attribute.factory.newInstance(AttrConstants.HW_VERSION_ATTR) });
The Write Attributes command is used to write/modify the attribute values of a cluster into the device.
The response of this request is received on the callback passed as parameter to the service.
A timeout expires if the device is not responding to the request.
The timeout period for router is 15 seconds by default, and 30 seconds for end-devices.
ZigbeeConnectorServices zcs = ZigbeeConnector.singleton.getZigbeeConnectorServices(); ZigbeeAddressResolvingServices zars = ZigbeeConnector.singleton.getZigbeeAddressResolvingServices(); ResponseCallBack<WriteAttributeResponse[]> writer = new ResponseCallBack<WriteAttributeResponse[]>() { @Override public void responseReceived( int nwkAddr, int epNumber, int clusterId, int seqNumber, final WriteAttributeResponse[] responses) { if (responses != null) { // Responses received for (WriteAttributeResponse attr : responses) { if (attr.getStatus() == Status.SUCCESS) { // Successful writing of this attribute } else { // Unsuccessful writing of this attribute } } } else { // Timeout expired ! } } }; // Search a device by its IEEE address IEEEAddress ieeeAddr = IEEEAddress.convertString("11-22-33-44-55-66-77-88"); Node node = zars.searchNode(ieeeAddr); // Fill the attribute to be written WriteAttribute attr = WriteAttribute.factory.newInstance(); attr.setIdentifier(AttrConstants.LOCATION_DESCRIPTION_ATTR); attr.setDataType(DataType.CHARACTER_STRING); attr.setDataAsString("Office"); // Write the location description attribute of this device int seqNumber = zcs.sendWriteAttributesCommand(writer, node.getNwkAddr(), node.getEpByInCluster(ClusterName.Basic_Attributes.getId()), ClusterName.Basic_Attributes.getId(), new WriteAttribute[] { attr });
The Discover Attributes command is used to know the attributes of a cluster implemented by the device.
A timeout expires if the device is not responding to the request.
The timeout period for router is 15 seconds by default, and 30 seconds for end-devices.
ZigbeeConnectorServices zcs = ZigbeeConnector.singleton.getZigbeeConnectorServices(); ZigbeeAddressResolvingServices zars = ZigbeeConnector.singleton.getZigbeeAddressResolvingServices(); ResponseCallBack<DiscoveredAttribute[]> discover = new ResponseCallBack<DiscoveredAttribute[]>() { @Override public void responseReceived( int nwkAddr, int epNumber, int clusterId, int seqNumber, final DiscoveredAttribute[] responses) { if (responses != null) { // Responses received for (DiscoveredAttribute attr : responses) { // Display the list of discovered attributes System.out.printf("AttrId(0x%04x) - DataType(%s)\n", attr.getIdentifier(), attr.getDataType()); } } else { // Timeout expired ! } } }; // Search a device by its IEEE address IEEEAddress ieeeAddr = IEEEAddress.convertString("11-22-33-44-55-66-77-88"); Node node = zars.searchNode(ieeeAddr); // Send a Discover Attributes command to discover the attributes // of Basic cluster implemented by this device int seqNumber = zcs.sendDiscoverAttributesCommand(discover, node.getNwkAddr(), node.getEpByInCluster(ClusterName.Basic_Attributes.getId()), ClusterName.Basic_Attributes.getId(), AttrConstants.ZCL_VERSION_ATTR, 20, true);
The Read Reporting Configuration command is used to read the configuration details of the reporting mechanism for one or more of the attributes of a cluster.
A timeout expires if the device is not responding to the request.
The timeout period for router is 15 seconds by default, and 30 seconds for end-devices.
ZigbeeConnectorServices zcs = ZigbeeConnector.singleton.getZigbeeConnectorServices(); ZigbeeAddressResolvingServices zars = ZigbeeConnector.singleton.getZigbeeAddressResolvingServices(); ResponseCallBack<ReadReportingConfigAttributeResponse[]> reader = new ResponseCallBack<ReadReportingConfigAttributeResponse[]>() { @Override public void responseReceived( int nwkAddr, int epNumber, int clusterId, int seqNumber, final ReadReportingConfigAttributeResponse[] responses) { if (responses != null) { // Responses received for (ReadReportingConfigAttributeResponse attr : responses) { if (attr.getStatus() == Status.SUCCESS) { // Successful reading of the reporting configuration of this attribute } else { // Unsuccessful reading of the reporting configuration of this attribute } } } else { // Timeout expired ! } } }; // Search a device by its IEEE address IEEEAddress ieeeAddr = IEEEAddress.convertString("11-22-33-44-55-66-77-88"); Node zrc = zars.searchNode(ieeeAddr); // Fill the attribute for which we want to read the reporting configuration ReadReportingConfigAttribute attr = ReadReportingConfigAttribute.factory.newInstance(ReportingDirection.ReportsReceived); attr.setIdentifier(AttrConstants.MEASURED_VALUE_ATTR); // Read the reporting configuration int seqNumber = zcs.sendReadReportingConfigurationCommand(reader, zrc.getNwkAddr(), zrc.getEpByInCluster(ClusterName.Temperature_Measurement.getId()), ClusterName.Temperature_Measurement.getId(), new ReadReportingConfigAttribute[] { attr });
The Configure Reporting command is used to configure the reporting mechanism for one or more of the attributes of a cluster.
A timeout expires if the device is not responding to the request.
The timeout period for router is 15 seconds by default, and 30 seconds for end-devices.
ZigbeeConnectorServices zcs = ZigbeeConnector.singleton.getZigbeeConnectorServices(); ZigbeeAddressResolvingServices zars = ZigbeeConnector.singleton.getZigbeeAddressResolvingServices(); ResponseCallBack<ReportingConfigurationAttributeResponse[]> writer = new ResponseCallBack<ReportingConfigurationAttributeResponse[]>() { @Override public void responseReceived( int nwkAddr, int epNumber, int clusterId, int seqNumber, final ReportingConfigurationAttributeResponse[] responses) { if (responses != null) { // Responses received for (ReportingConfigurationAttributeResponse attr : responses) { if (attr.getStatus() == Status.SUCCESS) { // Successful writing of the reporting configuration of this attribute } else { // Unsuccessful writing of the reporting configuration of this attribute } } } else { // Timeout expired ! } } }; // Search a device by its IEEE address IEEEAddress ieeeAddr = IEEEAddress.convertString("11-22-33-44-55-66-77-88"); Node zrc = zars.searchNode(ieeeAddr); // Fill the attribute for which we want to write the reporting configuration ReportingConfigurationAttribute attr = ReportingConfigurationAttribute.factory.newInstance(ReportingDirection.ReportsReceived); attr.setIdentifier(AttrConstants.MEASURED_VALUE_ATTR); attr.setDataType(DataType.SIGNED_16BITS); attr.setMinReportingInterval((short) 300); attr.setMaxReportingInterval((short) 3600); attr.setReportableChange(100, DataType.SIGNED_16BITS); // Write the reporting configuration int seqNumber = zcs.sendConfigureReportingCommand(writer, zrc.getNwkAddr(), zrc.getEpByInCluster(ClusterName.Temperature_Measurement.getId()), ClusterName.Temperature_Measurement.getId(), new ReportingConfigurationAttribute[] { attr }); }
The Cluster Specific command is used to send a specific command to a cluster.
Look in the Zigbee specfication to know which cluster supports Cluster Specific command.
Examples:
ZigbeeConnectorServices zcs = ZigbeeConnector.singleton.getZigbeeConnectorServices(); ZigbeeAddressResolvingServices zars = ZigbeeConnector.singleton.getZigbeeAddressResolvingServices(); // Search a device by its IEEE address IEEEAddress ieeeAddr = IEEEAddress.convertString("11-22-33-44-55-66-77-88"); Node zplug = zars.searchNode(ieeeAddr); // Send a Toggle command to a Plug device zcs.sendClusterSpecificCommand(zplug.getNwkAddr(), zplug.getEpByInCluster(ClusterName.On_Off.getId()), ClusterName.On_Off.getId(), AttrConstants.TOGGLE_COMMAND, null);
The ZCL frame command is the generic command that covers all other commands.
For example:
if you want to toggle the state of a ZPlug and verify
that the ZPlug received the command and well decoded it,
you have to use this generic command .
ZigbeeConnectorServices zcs = ZigbeeConnector.singleton.getZigbeeConnectorServices(); ZigbeeAddressResolvingServices zars = ZigbeeConnector.singleton.getZigbeeAddressResolvingServices(); ResponseCallBack<ZCLFrame> receiver = new ResponseCallBack<ZCLFrame>() { @Override public void responseReceived( int nwkAddr, int epNumber, int clusterId, int seqNumber, final ZCLFrame response) { if (response != null) { // ZCL Frame response received if (response.getPayload().isDefaultResponse()) { DefaultResponsePayload payload = response.getPayload().getDefaultResponsePayload(); if (payload.getStatus() == Status.SUCCESS) { // Successful decoding of the Toggle command } else { // Unsuccessful decoding of the Toggle command } } } else { // Timeout expired ! } } }; // Search a device by its IEEE address IEEEAddress ieeeAddr = IEEEAddress.convertString("11-22-33-44-55-66-77-88"); Node zplug = zars.searchNode(ieeeAddr); // Fill the ZCL Frame request ZCLFrame frame = ZCLFrame.factory.newZCLFrameInstance(); frame.getHeader().getFrameControl().setFrameType(FrameType.SpecificCluster); frame.getHeader().getFrameControl().setDirection(Direction.ClientToServer); frame.getHeader().getFrameControl().setManufacturerCode(ManufacturerCode.NotIncludeInZCLFrame); frame.getHeader().getFrameControl().setResponseStatus(ResponseStatus.ResponseReturned); frame.getHeader().setCmdIdentifierAsValue(AttrConstants.TOGGLE_COMMAND); // Send a Toggle command to a ZPlug device and verify // that the ZPlug received the command and well decoded it zcs.sendZCLFrameCommand(receiver, zplug.getNwkAddr(), zplug.getEpByInCluster(ClusterName.On_Off.getId()), ClusterName.On_Off.getId(), frame);
The notification events is based on the Observer pattern (also known as Listener in Java).
You have to implement the ZigbeeConnectorEvents interface for consuming the events.
You have also to create a Binding in the device to UBee
The Report Attribute is a notification sent by a device in according to the Reporting Configuration of the attribute.
The Cluster Specific command can be regarded as a notification sent by a device for any Cluster such as IAS Zone, Alarm, etc.
// Listener instance which receives notifications ZigbeeConnectorEvents receiver = new ZigbeeConnectorEvents() { @Override public void notifyReportAttribute( int nwkAddr, int epNumber, int clusterID, int seqNumber, final ReportAttribute[] attributes) { } @Override public void notifyClusterSpecificCommand( int nwkAddr, int epNumber, int clusterID, int seqNumber, byte command, ClusterSpecCmdAttribute[] attributes) { } };
You can subscribe to receive notifications from all devices.
ZigbeeConnectorEventsSubscribe zces = ZigbeeConnector.singleton.getZigbeeConnectorEventsSubscribe(); // Subscribe to receive notification events from all devices zces.subscribe(receiver, ZigbeeConnectorEventsSubscribe.allNodes); ... // Unsubscribe to receive notification events from all devices zces.unsubscribe(receiver, ZigbeeConnectorEventsSubscribe.allNodes);
Or you can subscribe to receive notifications from only one device.
ZigbeeConnectorEventsSubscribe zces = ZigbeeConnector.singleton.getZigbeeConnectorEventsSubscribe(); ZigbeeAddressResolvingServices zars = ZigbeeConnector.singleton.getZigbeeAddressResolvingServices(); // Search a device by its IEEE address IEEEAddress ieeeAddr = IEEEAddress.convertString("11-22-33-44-55-66-77-88"); Node node = zars.searchNode(ieeeAddr); // Subscribe to receive notification events from only this device zces.subscribe(receiver, node.getNwkAddr()); ... // Unsubscribe to receive notification events from only this device zces.unsubscribe(receiver, node.getNwkAddr());
For receiving notifications for attributes of a cluster from a device, you have to create a binding from this device to UBee.
final ZigbeeConnectorServices zcs = ZigbeeConnector.singleton.getZigbeeConnectorServices(); final ZigbeeAddressResolvingServices zars = ZigbeeConnector.singleton.getZigbeeAddressResolvingServices(); BindResponse response = new BindResponse() { @Override public void responseReceived(int nwkAddr, final BindCmd cmd, final Status status) { if (status == Status.SUCCESS) { Node node = zars.searchNode(nwkAddr); for (Binding binding : node.getBindings()) { // Display the bindings } } } }; // Search a ZRC device by its IEEE address IEEEAddress ieeeAddr = IEEEAddress.convertString("11-22-33-44-55-66-77-88"); Node zrc = zars.searchNode(ieeeAddr); // Search the UBee by its network address Node ubee = zars.searchNode(ZigbeeAddressResolvingServices.COORDINATOR_NWK_ADDR); // Create a binding to receive notification from ZRC on UBee zcs.sendBindRequest(response, zrc.getNwkAddr(), zrc.getIEEEAddress(), zrc.getEpByInCluster(ClusterName.Temperature_Measurement.getId()), ClusterName.Temperature_Measurement.getId(), ubee.getIEEEAddress(), ubee.getEpByOutCluster(ClusterName.Temperature_Measurement.getId()));
For actuating a device by a remote control such as ZRC, ZSC or ZKey, you have to create a binding between this two devices.
final ZigbeeConnectorServices zcs = ZigbeeConnector.singleton.getZigbeeConnectorServices(); final ZigbeeAddressResolvingServices zars = ZigbeeConnector.singleton.getZigbeeAddressResolvingServices(); BindResponse response = new BindResponse() { @Override public void responseReceived(int nwkAddr, final BindCmd cmd, final Status status) { if (status == Status.SUCCESS) { // Verify that the binding is added Node node = zars.searchNode(nwkAddr); for (Binding binding : node.getBindings()) { // Display the bindings } } } }; // Search a ZRC device by its IEEE address IEEEAddress ieeeAddr = IEEEAddress.convertString("11-22-33-44-55-66-77-88"); Node zrc = zars.searchNode(ieeeAddr); //Search a ZPlug device by its IEEE address ieeeAddr = IEEEAddress.convertString("12-23-34-45-56-67-78-89"); Node zplug = zars.searchNode(ieeeAddr); // Create a binding to control the ZPlug by the ZRC zcs.sendBindRequest(response, zrc.getNwkAddr(), zrc.getIEEEAddress(), zrc.getEpByOutCluster(ClusterName.On_Off.getId()), ClusterName.On_Off.getId(), zplug.getIEEEAddress(), zplug.getEpByInCluster(ClusterName.On_Off.getId()));
You can also control several devices belonging to the same group by creating a binding in the ZRC to a group ID.
int groupID = 0x0001; // Create a binding to control the devices of the group 0x0001 by the ZRC zcs.sendBindRequest(response, zrc.getNwkAddr(), zrc.getIEEEAddress(), zrc.getEpByOutCluster(ClusterName.On_Off.getId()), ClusterName.On_Off.getId(), groupID);
If you are unable or do not wish to put the license file in the same directory of your application,
you can specify the directory for searching the license file.
The path initialization have to be done before the "startUbee() call.
ZigbeeConnectorServices zcs = ZigbeeConnector.singleton.getZigbeeConnectorServices(); // Set the path of the license file zcs.setLicensePath("/usr/local/myappli"); // Start the communication with UBee zcs.startUbee(...);
If you are unable or do not wish to read the license key in the file,
you can set the license key by programming.
The license initialization have to be done before the "startUbee() call.
ZigbeeConnectorServices zcs = ZigbeeConnector.singleton.getZigbeeConnectorServices(); // Set the license key by programming zcs.setLicenseKey("AAAAABBBBBCCCCCDDDDDEEEEE"); // Start the communication with UBee zcs.startUbee(...);