Skip to content

Commit

Permalink
Add ability to add endpoints and clusters to a device via the XML (#260)
Browse files Browse the repository at this point in the history
Signed-off-by: Chris Jackson <chris@cd-jackson.com>
  • Loading branch information
cdjackson authored and hsudbrock committed Nov 26, 2018
1 parent bb2477c commit d54d832
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 1 deletion.
Expand Up @@ -142,6 +142,9 @@ public class ZigBeeBindingConstants {
public static final ChannelTypeUID CHANNEL_DOORLOCK_STATE = new ChannelTypeUID("zigbee:door_state");

public static final String CHANNEL_PROPERTY_ENDPOINT = "zigbee_endpoint";
public static final String CHANNEL_PROPERTY_PROFILEID = "zigbee_profileid";
public static final String CHANNEL_PROPERTY_INPUTCLUSTERS = "zigbee_inputclusters";
public static final String CHANNEL_PROPERTY_OUTPUTCLUSTERS = "zigbee_outputclusters";

public static final String ITEM_TYPE_COLOR = "Color";
public static final String ITEM_TYPE_CONTACT = "Contact";
Expand Down
Expand Up @@ -10,6 +10,7 @@

import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -25,6 +26,7 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.config.core.ConfigDescription;
Expand Down Expand Up @@ -59,6 +61,7 @@
import com.zsmartsystems.zigbee.ZigBeeEndpoint;
import com.zsmartsystems.zigbee.ZigBeeNetworkNodeListener;
import com.zsmartsystems.zigbee.ZigBeeNode;
import com.zsmartsystems.zigbee.ZigBeeProfileType;
import com.zsmartsystems.zigbee.app.otaserver.ZclOtaUpgradeServer;
import com.zsmartsystems.zigbee.app.otaserver.ZigBeeOtaFile;
import com.zsmartsystems.zigbee.app.otaserver.ZigBeeOtaServerStatus;
Expand Down Expand Up @@ -222,6 +225,51 @@ private synchronized void doNodeInitialisation() {
logger.debug("{}: Using static definition with existing {} channels", nodeIeeeAddress, nodeChannels.size());
}

// Add statically defined endpoints and clusters
for (Channel channel : nodeChannels) {
// Process the channel properties
Map<String, String> properties = channel.getProperties();
int endpointId = Integer.parseInt(properties.get(ZigBeeBindingConstants.CHANNEL_PROPERTY_ENDPOINT));
ZigBeeEndpoint endpoint = node.getEndpoint(endpointId);
if (endpoint == null) {
int profileId;
if (properties.get(ZigBeeBindingConstants.CHANNEL_PROPERTY_PROFILEID) == null) {
profileId = ZigBeeProfileType.ZIGBEE_HOME_AUTOMATION.getKey();
} else {
profileId = Integer.parseInt(properties.get(ZigBeeBindingConstants.CHANNEL_PROPERTY_PROFILEID));
}

logger.debug("{}: Creating statically defined device endpoint {} with profile {}", nodeIeeeAddress,
endpointId, ZigBeeProfileType.getByValue(profileId));
endpoint = new ZigBeeEndpoint(coordinatorHandler.getNetworkManager(), node, endpointId);
endpoint.setProfileId(profileId);
node.addEndpoint(endpoint);
}

List<Integer> staticClusters;
boolean modified = false;
staticClusters = processClusterList(endpoint.getInputClusterIds(),
properties.get(ZigBeeBindingConstants.CHANNEL_PROPERTY_INPUTCLUSTERS));
if (!staticClusters.isEmpty()) {
logger.debug("{}: Forcing endpoint {} input clusters {}", nodeIeeeAddress, endpointId, staticClusters);
endpoint.setInputClusterIds(staticClusters);
modified = true;
}

staticClusters = processClusterList(endpoint.getOutputClusterIds(),
properties.get(ZigBeeBindingConstants.CHANNEL_PROPERTY_OUTPUTCLUSTERS));
if (!staticClusters.isEmpty()) {
logger.debug("{}: Forcing endpoint {} output clusters {}", nodeIeeeAddress, endpointId, staticClusters);
endpoint.setOutputClusterIds(staticClusters);
modified = true;
}

if (modified) {
logger.debug("{}: Updating endpoint {}", nodeIeeeAddress, endpointId);
node.updateEndpoint(endpoint);
}
}

try {
pollingPeriod = POLLING_PERIOD_MAX;

Expand Down Expand Up @@ -314,6 +362,26 @@ private synchronized void doNodeInitialisation() {
coordinatorHandler.serializeNetwork();
}

/**
* Process a static cluster list and add it to the existing list
*
* @param initialClusters a collection of existing clusters
* @param newClusters a string containing a comma separated list of clusters
* @return a list of clusters if the list is updated, or an empty list if it has not changed
*/
private List<Integer> processClusterList(Collection<Integer> initialClusters, String newClusters) {
if (newClusters == null || newClusters.length() == 0) {
return Collections.emptyList();
}

Set<Integer> clusters = new HashSet<Integer>();
clusters.addAll(initialClusters);
return clusters.addAll(
Arrays.asList(newClusters.split(",")).stream().map(s -> new Integer(s)).collect(Collectors.toSet()))
? new ArrayList<Integer>(clusters)
: Collections.emptyList();
}

@Override
public void dispose() {
logger.debug("{}: Handler dispose.", nodeIeeeAddress);
Expand Down
Expand Up @@ -8,6 +8,14 @@
*/
package org.openhab.binding.zigbee.handler;

import static org.junit.Assert.*;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.junit.Test;

/**
Expand All @@ -17,8 +25,52 @@
*
*/
public class ZigBeeThingHandlerTest {
private List<Integer> processClusterList(Collection<Integer> initialClusters, String newClusters)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException,
SecurityException {
Method privateMethod;

ZigBeeThingHandler handler = new ZigBeeThingHandler(null);

privateMethod = ZigBeeThingHandler.class.getDeclaredMethod("processClusterList", Collection.class,
String.class);
privateMethod.setAccessible(true);

return (List<Integer>) privateMethod.invoke(handler, initialClusters, newClusters);
}

@Test
public void testConfiguration() {
public void testProcessClusterList() throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException, NoSuchMethodException, SecurityException {
List<Integer> clusters = new ArrayList<>();

clusters = processClusterList(clusters, null);
assertEquals(0, clusters.size());

clusters = processClusterList(clusters, "");
assertEquals(0, clusters.size());

clusters = processClusterList(clusters, ",");
assertEquals(0, clusters.size());

clusters = processClusterList(clusters, "123,456");
assertEquals(2, clusters.size());
assertTrue(clusters.contains(123));
assertTrue(clusters.contains(456));

clusters = processClusterList(clusters, "123,456");
assertEquals(0, clusters.size());

clusters = processClusterList(clusters, "123,456");
assertEquals(2, clusters.size());
assertTrue(clusters.contains(123));
assertTrue(clusters.contains(456));

clusters = processClusterList(clusters, "321,654");
assertEquals(4, clusters.size());
assertTrue(clusters.contains(123));
assertTrue(clusters.contains(456));
assertTrue(clusters.contains(321));
assertTrue(clusters.contains(654));
}
}

0 comments on commit d54d832

Please sign in to comment.