Added Zigbee attribute listener
This commit is contained in:
parent
1adaf8bc46
commit
3a49b15dea
11 changed files with 530 additions and 81 deletions
|
|
@ -0,0 +1,42 @@
|
||||||
|
package se.hal.struct.devicedata;
|
||||||
|
|
||||||
|
import se.hal.intf.HalSensorData;
|
||||||
|
|
||||||
|
|
||||||
|
public class PressureSensorData extends HalSensorData {
|
||||||
|
|
||||||
|
private double pressure;
|
||||||
|
|
||||||
|
|
||||||
|
public PressureSensorData(){}
|
||||||
|
public PressureSensorData(double pressure, long timestamp){
|
||||||
|
super.setTimestamp(timestamp);
|
||||||
|
this.pressure = pressure;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return pressure + " hPa";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Storage methods
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return pressure in degrees hPa
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public double getData() {
|
||||||
|
return pressure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param pressure the temperature to set in degrees hPa
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setData(double pressure) {
|
||||||
|
this.pressure = pressure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -26,5 +26,6 @@ se.hal.level = ALL
|
||||||
# -------------------------------------
|
# -------------------------------------
|
||||||
|
|
||||||
com.zsmartsystems.zigbee.level = INFO
|
com.zsmartsystems.zigbee.level = INFO
|
||||||
|
profiling.com.zsmartsystems.zigbee.level = INFO
|
||||||
#com.zsmartsystems.zigbee.dongle.cc2531.zigbee.util.ByteUtils.level = INFO
|
#com.zsmartsystems.zigbee.dongle.cc2531.zigbee.util.ByteUtils.level = INFO
|
||||||
#com.zsmartsystems.zigbee.dongle.cc2531.network.packet.ZToolPacketStream.level = INFO
|
#com.zsmartsystems.zigbee.dongle.cc2531.network.packet.ZToolPacketStream.level = INFO
|
||||||
|
|
@ -15,15 +15,22 @@ import com.zsmartsystems.zigbee.transport.TransportConfig;
|
||||||
import com.zsmartsystems.zigbee.transport.TransportConfigOption;
|
import com.zsmartsystems.zigbee.transport.TransportConfigOption;
|
||||||
import com.zsmartsystems.zigbee.transport.ZigBeePort;
|
import com.zsmartsystems.zigbee.transport.ZigBeePort;
|
||||||
import com.zsmartsystems.zigbee.transport.ZigBeeTransportTransmit;
|
import com.zsmartsystems.zigbee.transport.ZigBeeTransportTransmit;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclAttribute;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclAttributeListener;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclCluster;
|
||||||
import com.zsmartsystems.zigbee.zcl.clusters.*;
|
import com.zsmartsystems.zigbee.zcl.clusters.*;
|
||||||
import com.zsmartsystems.zigbee.zdo.field.NodeDescriptor;
|
import com.zsmartsystems.zigbee.zdo.field.NodeDescriptor;
|
||||||
import se.hal.HalContext;
|
import se.hal.HalContext;
|
||||||
import se.hal.intf.*;
|
import se.hal.intf.*;
|
||||||
|
import se.hal.plugin.zigbee.device.*;
|
||||||
import zutil.Timer;
|
import zutil.Timer;
|
||||||
import zutil.log.LogUtil;
|
import zutil.log.LogUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -32,9 +39,11 @@ import java.util.logging.Logger;
|
||||||
public class HalZigbeeController implements HalSensorController,
|
public class HalZigbeeController implements HalSensorController,
|
||||||
HalEventController,
|
HalEventController,
|
||||||
HalAutostartController,
|
HalAutostartController,
|
||||||
|
HalScannableController,
|
||||||
ZigBeeAnnounceListener,
|
ZigBeeAnnounceListener,
|
||||||
ZigBeeNetworkNodeListener,
|
ZigBeeNetworkNodeListener,
|
||||||
HalScannableController {
|
ZigBeeNetworkEndpointListener,
|
||||||
|
ZclAttributeListener {
|
||||||
|
|
||||||
private static final Logger logger = LogUtil.getLogger();
|
private static final Logger logger = LogUtil.getLogger();
|
||||||
|
|
||||||
|
|
@ -51,14 +60,14 @@ public class HalZigbeeController implements HalSensorController,
|
||||||
|
|
||||||
private Timer permitJoinTimer;
|
private Timer permitJoinTimer;
|
||||||
private HalDeviceReportListener deviceListener;
|
private HalDeviceReportListener deviceListener;
|
||||||
private List<HalAbstractDevice> registeredDevices;
|
private List<ZigbeeHalDeviceConfig> registeredDevices = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
public HalZigbeeController() {}
|
public HalZigbeeController() {}
|
||||||
|
|
||||||
// --------------------------
|
// ------------------------------------------
|
||||||
// Lifecycle Methods
|
// Lifecycle Methods
|
||||||
// --------------------------
|
// ------------------------------------------
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAvailable() {
|
public boolean isAvailable() {
|
||||||
|
|
@ -179,58 +188,128 @@ public class HalZigbeeController implements HalSensorController,
|
||||||
serialPort.close();
|
serialPort.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------
|
// ------------------------------------------
|
||||||
// Zigbee Methods
|
// Zigbee Node Methods
|
||||||
// --------------------------
|
// ------------------------------------------
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deviceStatusUpdate(ZigBeeNodeStatus deviceStatus, Integer networkAddress, IeeeAddress ieeeAddress) {
|
public void deviceStatusUpdate(ZigBeeNodeStatus deviceStatus, Integer networkAddress, IeeeAddress ieeeAddress) {
|
||||||
System.out.println(deviceStatus.name() + " status updated.");
|
logger.fine("New device connected to network: " + ieeeAddress + "(" + deviceStatus + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void announceUnknownDevice(Integer networkAddress) {
|
public void announceUnknownDevice(Integer networkAddress) {
|
||||||
System.out.println("Unknown device: " + networkAddress);
|
logger.fine("Unknown device connected to network: " + networkAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void nodeAdded(final ZigBeeNode node) {
|
public void nodeAdded(final ZigBeeNode node) {
|
||||||
System.out.println("nodeAdded: " + node);
|
nodeUpdated(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nodeUpdated(final ZigBeeNode node) {
|
||||||
// If this is the coordinator (NWK address 0), ignore this device
|
// If this is the coordinator (NWK address 0), ignore this device
|
||||||
if (node.getLogicalType() == NodeDescriptor.LogicalType.COORDINATOR || node.getNetworkAddress() == 0) {
|
if (node.getLogicalType() == NodeDescriptor.LogicalType.COORDINATOR || node.getNetworkAddress() == 0) {
|
||||||
System.out.println(node.getIeeeAddress() + ": is a coordinator, skipping.");
|
logger.fine("[Node: " + node.getIeeeAddress() + "]: Node is coordinator, ignoring registration.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!node.isDiscovered()) {
|
if (!node.isDiscovered()) {
|
||||||
System.out.println(node.getIeeeAddress() + ": Node discovery not complete");
|
logger.fine("[Node: " + node.getIeeeAddress() + "]: Node discovery not complete, ignoring registration.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the device properties discovery.
|
// Perform the device properties discovery.
|
||||||
|
|
||||||
System.out.println(node.getIeeeAddress() + ": " +
|
node.removeNetworkEndpointListener(this);
|
||||||
"Manufacturer=" + node.getNodeDescriptor().getManufacturerCode());
|
node.addNetworkEndpointListener(this);
|
||||||
}
|
logger.fine("[Node: " + node.getIeeeAddress() + "]: Node has been registered: " +
|
||||||
|
"Manufacturer=" + node.getNodeDescriptor().getManufacturerCode() +
|
||||||
@Override
|
"Type=" + node.getNodeDescriptor().getLogicalType());
|
||||||
public void nodeUpdated(final ZigBeeNode node) {
|
|
||||||
System.out.println("nodeUpdated: " + node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void nodeRemoved(final ZigBeeNode node) {
|
public void nodeRemoved(final ZigBeeNode node) {
|
||||||
System.out.println("nodeRemoved: " + node);
|
node.removeNetworkEndpointListener(this);
|
||||||
|
logger.fine("[Node: " + node.getIeeeAddress() + "]: Node registration has been removed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------
|
// ------------------------------------------
|
||||||
|
// Zigbee Endpoint Methods
|
||||||
|
// ------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deviceAdded(ZigBeeEndpoint endpoint) {
|
||||||
|
deviceUpdated(endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deviceUpdated(ZigBeeEndpoint endpoint) {
|
||||||
|
logger.fine("[Node: " + endpoint.getIeeeAddress() + ", Endpoint: " + endpoint.getEndpointId() + "]: Received a Zigbee endpoint update: " + endpoint);
|
||||||
|
|
||||||
|
for (int inputClusterId : endpoint.getInputClusterIds()) {
|
||||||
|
ZigbeeHalDeviceConfig config = createDeviceConfig(inputClusterId);
|
||||||
|
|
||||||
|
if (config != null)
|
||||||
|
registerCluster(endpoint, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ZigbeeHalDeviceConfig createDeviceConfig(int clusterId) {
|
||||||
|
switch (clusterId) {
|
||||||
|
case ZclRelativeHumidityMeasurementCluster.CLUSTER_ID: return new ZigbeeHumidityConfig();
|
||||||
|
case ZclOnOffCluster.CLUSTER_ID: return new ZigbeeOnOffConfig();
|
||||||
|
case ZclPressureMeasurementCluster.CLUSTER_ID: return new ZigbeePressureConfig();
|
||||||
|
case ZclTemperatureMeasurementCluster.CLUSTER_ID: return new ZigbeeTemperatureConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerCluster(ZigBeeEndpoint endpoint, ZigbeeHalDeviceConfig config) {
|
||||||
|
ZclCluster cluster = endpoint.getInputCluster(config.getZigbeeClusterId());
|
||||||
|
if (cluster != null) {
|
||||||
|
config.setZigbeeNodeAddress(endpoint.getIeeeAddress());
|
||||||
|
cluster.addAttributeListener(this);
|
||||||
|
|
||||||
|
// // TODO: Notify listener that a device is online
|
||||||
|
if (deviceListener != null)
|
||||||
|
deviceListener.reportReceived(config, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deviceRemoved(ZigBeeEndpoint endpoint) {
|
||||||
|
logger.fine("[Node: " + endpoint.getIeeeAddress() + ", Endpoint: " + endpoint.getEndpointId() + "]: Endpoint removed: " + endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// Zigbee Cluster Attribute Methods
|
||||||
|
// ------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void attributeUpdated(ZclAttribute attribute, Object value) {
|
||||||
|
if (deviceListener != null) {
|
||||||
|
ZigbeeHalDeviceConfig config = createDeviceConfig(attribute.getCluster().getId());
|
||||||
|
|
||||||
|
if (config != null)
|
||||||
|
deviceListener.reportReceived(config, config.getDeviceData(attribute));
|
||||||
|
else
|
||||||
|
logger.severe("Cluster ID (" + attribute.getCluster().getId() + ") is not supported but a listener was added.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
// Hal Overrides
|
// Hal Overrides
|
||||||
// --------------------------
|
// ------------------------------------------
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void register(HalDeviceConfig deviceConfig) {
|
public void register(HalDeviceConfig deviceConfig) {
|
||||||
|
if (deviceConfig instanceof ZigbeeHalDeviceConfig && !registeredDevices.contains(deviceConfig)) {
|
||||||
|
ZigbeeHalDeviceConfig zigbeeDevice = (ZigbeeHalDeviceConfig) deviceConfig;
|
||||||
|
registeredDevices.add(zigbeeDevice);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -245,7 +324,9 @@ public class HalZigbeeController implements HalSensorController,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send(HalEventConfig eventConfig, HalEventData eventData) {
|
public void send(HalEventConfig eventConfig, HalEventData eventData) {
|
||||||
|
if (eventConfig instanceof ZigbeeHalEventDeviceConfig) {
|
||||||
|
((ZigbeeHalEventDeviceConfig) eventConfig).sendZigbeeCommand(networkManager, eventData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -255,6 +336,8 @@ public class HalZigbeeController implements HalSensorController,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startScan() {
|
public void startScan() {
|
||||||
|
logger.info("Starting Zigbee pairing process.");
|
||||||
|
|
||||||
networkManager.permitJoin(120);
|
networkManager.permitJoin(120);
|
||||||
permitJoinTimer = new Timer(120_000);
|
permitJoinTimer = new Timer(120_000);
|
||||||
permitJoinTimer.start();
|
permitJoinTimer.start();
|
||||||
|
|
|
||||||
|
|
@ -45,36 +45,6 @@ public class ZigBeeDataStore implements ZigBeeNetworkDataStore {
|
||||||
private HashMap<IeeeAddress,ZigBeeNodeDao> devices = new HashMap<>();
|
private HashMap<IeeeAddress,ZigBeeNodeDao> devices = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
public ZigBeeDataStore() {
|
|
||||||
/*ZigBeeNodeDao controller = new ZigBeeNodeDao();
|
|
||||||
controller.setIeeeAddress(new IeeeAddress("00124B001CCE1B5F"));
|
|
||||||
controller.setNetworkAddress(0);
|
|
||||||
controller.setBindingTable(new HashSet<>());
|
|
||||||
controller.setEndpoints(Collections.EMPTY_LIST);
|
|
||||||
controller.setNodeDescriptor(null);
|
|
||||||
controller.setPowerDescriptor(null);
|
|
||||||
writeNode(controller);
|
|
||||||
|
|
||||||
ZigBeeNodeDao ikeaOutlet = new ZigBeeNodeDao();
|
|
||||||
ikeaOutlet.setIeeeAddress(new IeeeAddress("00158D000488A47F"));
|
|
||||||
ikeaOutlet.setNetworkAddress(10697);
|
|
||||||
ikeaOutlet.setBindingTable(new HashSet<>());
|
|
||||||
ikeaOutlet.setEndpoints(Collections.EMPTY_LIST);
|
|
||||||
ikeaOutlet.setNodeDescriptor(null);
|
|
||||||
ikeaOutlet.setPowerDescriptor(null);
|
|
||||||
writeNode(ikeaOutlet);
|
|
||||||
|
|
||||||
ZigBeeNodeDao aquaraTemp = new ZigBeeNodeDao();
|
|
||||||
aquaraTemp.setIeeeAddress(new IeeeAddress("842E14FFFE63AE4B"));
|
|
||||||
aquaraTemp.setNetworkAddress(52953);
|
|
||||||
aquaraTemp.setBindingTable(new HashSet<>());
|
|
||||||
aquaraTemp.setEndpoints(Collections.EMPTY_LIST);
|
|
||||||
aquaraTemp.setNodeDescriptor(null);
|
|
||||||
aquaraTemp.setPowerDescriptor(null);
|
|
||||||
writeNode(aquaraTemp);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<IeeeAddress> readNetworkNodes() {
|
public Set<IeeeAddress> readNetworkNodes() {
|
||||||
return devices.keySet();
|
return devices.keySet();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
package se.hal.plugin.zigbee.device;
|
||||||
|
|
||||||
|
import com.zsmartsystems.zigbee.IeeeAddress;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclAttribute;
|
||||||
|
import se.hal.intf.HalAbstractController;
|
||||||
|
import se.hal.intf.HalDeviceConfig;
|
||||||
|
import se.hal.intf.HalDeviceData;
|
||||||
|
import se.hal.plugin.zigbee.HalZigbeeController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic class that is extended by all Endpoint config classes.
|
||||||
|
*/
|
||||||
|
public abstract class ZigbeeHalDeviceConfig implements HalDeviceConfig {
|
||||||
|
private String zigbeeNodeAddressStr;
|
||||||
|
private transient IeeeAddress zigbeeNodeAddress;
|
||||||
|
|
||||||
|
|
||||||
|
public void setZigbeeNodeAddress(IeeeAddress zigbeeNodeAddress) {
|
||||||
|
this.zigbeeNodeAddress = zigbeeNodeAddress;
|
||||||
|
this.zigbeeNodeAddressStr = zigbeeNodeAddress.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IeeeAddress getZigbeeNodeAddress() {
|
||||||
|
if (zigbeeNodeAddress == null && zigbeeNodeAddressStr != null)
|
||||||
|
zigbeeNodeAddress = new IeeeAddress(zigbeeNodeAddressStr);
|
||||||
|
return zigbeeNodeAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// Abstract Methods
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param zclAttribute
|
||||||
|
* @return a HalDeviceData object containing the same value representation as the endpoint.
|
||||||
|
*/
|
||||||
|
public abstract HalDeviceData getDeviceData(ZclAttribute zclAttribute);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the cluster ID that is supported by this device config class
|
||||||
|
*/
|
||||||
|
public abstract int getZigbeeClusterId();
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// Hal Methods
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends HalAbstractController> getDeviceControllerClass() {
|
||||||
|
return HalZigbeeController.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
ZigbeeHalDeviceConfig that = (ZigbeeHalDeviceConfig) o;
|
||||||
|
return zigbeeNodeAddress.equals(that.zigbeeNodeAddress) &&
|
||||||
|
getZigbeeClusterId() == that.getZigbeeClusterId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
package se.hal.plugin.zigbee.device;
|
||||||
|
|
||||||
|
import com.zsmartsystems.zigbee.CommandResult;
|
||||||
|
import com.zsmartsystems.zigbee.ZigBeeEndpoint;
|
||||||
|
import com.zsmartsystems.zigbee.ZigBeeNetworkManager;
|
||||||
|
import com.zsmartsystems.zigbee.ZigBeeNode;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclCluster;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclCommand;
|
||||||
|
import se.hal.intf.HalEventData;
|
||||||
|
import zutil.log.LogUtil;
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic class that is extended by all Endpoint config classes.
|
||||||
|
*/
|
||||||
|
public abstract class ZigbeeHalEventDeviceConfig extends ZigbeeHalDeviceConfig {
|
||||||
|
private static final Logger logger = LogUtil.getLogger();
|
||||||
|
|
||||||
|
|
||||||
|
public ZclCluster getZigbeeCluster(ZigBeeNetworkManager networkManager) {
|
||||||
|
ZigBeeNode node = networkManager.getNode(getZigbeeNodeAddress());
|
||||||
|
|
||||||
|
for (ZigBeeEndpoint endpoint : node.getEndpoints()) {
|
||||||
|
ZclCluster cluster = endpoint.getInputCluster(getZigbeeClusterId());
|
||||||
|
if (cluster != null) {
|
||||||
|
return cluster;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendZigbeeCommand(ZigBeeNetworkManager networkManager, HalEventData data) {
|
||||||
|
ZclCluster cluster = getZigbeeCluster(networkManager);
|
||||||
|
|
||||||
|
if (cluster != null) {
|
||||||
|
try {
|
||||||
|
ZclCommand command = getZigbeeCommandObject(data);
|
||||||
|
// Need to do reflection as the generic method has visibility protected.
|
||||||
|
CommandResult result =
|
||||||
|
(CommandResult) ZclCluster.class.getMethod("sendCommand", ZclCommand.class).invoke(command);
|
||||||
|
|
||||||
|
if (result.isError() || result.isTimeout()) {
|
||||||
|
logger.warning("[Endpoint: " + cluster.getZigBeeAddress() + "] Command failed with error: " + result.isError() + " (timeout=" + result.isTimeout() + ")");
|
||||||
|
} else {
|
||||||
|
logger.info("[Endpoint: " + cluster.getZigBeeAddress() + "] Command has been successfully sent");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warning("[Endpoint: " + cluster.getZigBeeAddress() + "] Failed to send command [" + e.getMessage() + "]");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warning("[Node: " + getZigbeeNodeAddress() + "] Unable to find cluster.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method will create a Zigbee command object based on the value of the Hal event data.
|
||||||
|
*
|
||||||
|
* @param data is the Hal event data value that should be converted.
|
||||||
|
* @return a new Zigbee command object or null if no equal representation can be created based on the data.
|
||||||
|
*/
|
||||||
|
protected abstract ZclCommand getZigbeeCommandObject(HalEventData data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package se.hal.plugin.zigbee.device;
|
||||||
|
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclAttribute;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.clusters.ZclRelativeHumidityMeasurementCluster;
|
||||||
|
import se.hal.intf.HalDeviceData;
|
||||||
|
import se.hal.intf.HalSensorConfig;
|
||||||
|
import se.hal.struct.devicedata.HumiditySensorData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A device configuration for a specific endpoint on a Zigbee device.
|
||||||
|
*/
|
||||||
|
public class ZigbeeHumidityConfig extends ZigbeeHalDeviceConfig implements HalSensorConfig {
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// Zigbee Methods
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HalDeviceData getDeviceData(ZclAttribute zclAttribute) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getZigbeeClusterId() {
|
||||||
|
return ZclRelativeHumidityMeasurementCluster.CLUSTER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// Hal Methods
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDataInterval() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AggregationMethod getAggregationMethod() {
|
||||||
|
return AggregationMethod.AVERAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends HalDeviceData> getDeviceDataClass() {
|
||||||
|
return HumiditySensorData.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
package se.hal.plugin.zigbee.device;
|
||||||
|
|
||||||
|
import com.zsmartsystems.zigbee.ZigBeeEndpoint;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclAttribute;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclCluster;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclCommand;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.clusters.ZclOnOffCluster;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.clusters.onoff.OffCommand;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.clusters.onoff.OnCommand;
|
||||||
|
import se.hal.intf.HalDeviceData;
|
||||||
|
import se.hal.intf.HalEventConfig;
|
||||||
|
import se.hal.intf.HalEventData;
|
||||||
|
import se.hal.struct.devicedata.OnOffEventData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A device configuration for a specific endpoint on a Zigbee device.
|
||||||
|
*/
|
||||||
|
public class ZigbeeOnOffConfig extends ZigbeeHalEventDeviceConfig implements HalEventConfig {
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// Zigbee Methods
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HalDeviceData getDeviceData(ZclAttribute zclAttribute) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getZigbeeClusterId() {
|
||||||
|
return ZclOnOffCluster.CLUSTER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ZclCommand getZigbeeCommandObject(HalEventData data) {
|
||||||
|
if (! (data instanceof OnOffEventData))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return (((OnOffEventData) data).isOn() ? new OnCommand() : new OffCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// Hal Methods
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends HalDeviceData> getDeviceDataClass() {
|
||||||
|
return OnOffEventData.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package se.hal.plugin.zigbee.device;
|
||||||
|
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclAttribute;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.clusters.ZclTemperatureMeasurementCluster;
|
||||||
|
import se.hal.intf.HalDeviceData;
|
||||||
|
import se.hal.intf.HalSensorConfig;
|
||||||
|
import se.hal.struct.devicedata.TemperatureSensorData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A device configuration for a specific endpoint on a Zigbee device.
|
||||||
|
*/
|
||||||
|
public class ZigbeePressureConfig extends ZigbeeHalDeviceConfig implements HalSensorConfig {
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// Zigbee Methods
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HalDeviceData getDeviceData(ZclAttribute zclAttribute) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getZigbeeClusterId() {
|
||||||
|
return ZclTemperatureMeasurementCluster.CLUSTER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// Hal Methods
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDataInterval() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AggregationMethod getAggregationMethod() {
|
||||||
|
return AggregationMethod.AVERAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends HalDeviceData> getDeviceDataClass() {
|
||||||
|
return TemperatureSensorData.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
package se.hal.plugin.zigbee.device;
|
||||||
|
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclAttribute;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.clusters.ZclTemperatureMeasurementCluster;
|
||||||
|
import se.hal.intf.HalDeviceData;
|
||||||
|
import se.hal.intf.HalSensorConfig;
|
||||||
|
import se.hal.struct.devicedata.TemperatureSensorData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A device configuration for a specific endpoint on a Zigbee device.
|
||||||
|
*/
|
||||||
|
public class ZigbeeTemperatureConfig extends ZigbeeHalDeviceConfig implements HalSensorConfig {
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// Zigbee Methods
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HalDeviceData getDeviceData(ZclAttribute zclAttribute) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getZigbeeClusterId() {
|
||||||
|
return ZclTemperatureMeasurementCluster.CLUSTER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// Hal Methods
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDataInterval() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AggregationMethod getAggregationMethod() {
|
||||||
|
return AggregationMethod.AVERAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends HalDeviceData> getDeviceDataClass() {
|
||||||
|
return TemperatureSensorData.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -27,87 +27,122 @@ package se.hal.plugin.zigbee;
|
||||||
import com.zsmartsystems.zigbee.ZigBeeEndpoint;
|
import com.zsmartsystems.zigbee.ZigBeeEndpoint;
|
||||||
import com.zsmartsystems.zigbee.ZigBeeNetworkManager;
|
import com.zsmartsystems.zigbee.ZigBeeNetworkManager;
|
||||||
import com.zsmartsystems.zigbee.ZigBeeNode;
|
import com.zsmartsystems.zigbee.ZigBeeNode;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclAttribute;
|
||||||
|
import com.zsmartsystems.zigbee.zcl.ZclCluster;
|
||||||
import zutil.log.CompactLogFormatter;
|
import zutil.log.CompactLogFormatter;
|
||||||
import zutil.log.LogUtil;
|
import zutil.log.LogUtil;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Scanner;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
|
||||||
public class HalZigbeeControllerTest {
|
public class HalZigbeeControllerTest {
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException, InterruptedException {
|
||||||
LogUtil.readConfiguration("logging.properties");
|
LogUtil.readConfiguration("logging.properties");
|
||||||
LogUtil.setGlobalFormatter(new CompactLogFormatter());
|
LogUtil.setGlobalFormatter(new CompactLogFormatter());
|
||||||
LogUtil.setGlobalLevel(Level.ALL);
|
LogUtil.setGlobalLevel(Level.ALL);
|
||||||
|
|
||||||
HalZigbeeController controller = new HalZigbeeController();
|
HalZigbeeController controller = new HalZigbeeController();
|
||||||
controller.initialize("COM3", HalZigbeeController.ZIGBEE_DONGLE_CC2531);
|
controller.initialize("COM5", HalZigbeeController.ZIGBEE_DONGLE_CC2531);
|
||||||
|
|
||||||
handleConsoleInput('h', controller.networkManager);
|
Scanner in = new Scanner(System.in);
|
||||||
|
handleConsoleInput("h", in, controller.networkManager);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
char input = waitForInout();
|
System.out.print("");
|
||||||
handleConsoleInput(input, controller.networkManager);
|
System.out.print("Input command and finish with ENTER: ");
|
||||||
|
|
||||||
if (input == 'q') break;
|
while (!in.hasNext()) { Thread.sleep(200); }
|
||||||
|
|
||||||
|
String command = in.next().trim();
|
||||||
|
handleConsoleInput(command, in, controller.networkManager);
|
||||||
|
in.nextLine(); // read in the rest of the input line
|
||||||
|
|
||||||
|
if (command.equals("q")) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
controller.close();
|
controller.close();
|
||||||
|
System.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void handleConsoleInput(char input, ZigBeeNetworkManager networkManager) {
|
private static void handleConsoleInput(String command, Scanner in, ZigBeeNetworkManager networkManager) {
|
||||||
switch (input) {
|
switch (command) {
|
||||||
case 'i':
|
case "i":
|
||||||
System.out.println("PAN ID = " + networkManager.getZigBeePanId());
|
System.out.println("PAN ID = " + networkManager.getZigBeePanId());
|
||||||
System.out.println("Extended PAN ID = " + networkManager.getZigBeeExtendedPanId());
|
System.out.println("Extended PAN ID = " + networkManager.getZigBeeExtendedPanId());
|
||||||
System.out.println("Channel = " + networkManager.getZigBeeChannel());
|
System.out.println("Channel = " + networkManager.getZigBeeChannel());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case "l":
|
||||||
|
System.out.println("-----------------------------------------------------------------------");
|
||||||
for (ZigBeeNode node : networkManager.getNodes()) {
|
for (ZigBeeNode node : networkManager.getNodes()) {
|
||||||
System.out.println(node + " (" + node.getNodeState() + ")");
|
System.out.println("[node id: " + node.getNetworkAddress() + "] " + node + " (" + node.getNodeState() + ")");
|
||||||
|
|
||||||
for (ZigBeeEndpoint endpoint : node.getEndpoints()) {
|
for (ZigBeeEndpoint endpoint : node.getEndpoints()) {
|
||||||
System.out.println(" - " + endpoint);
|
System.out.println(" - [endpoint id: " + endpoint.getDeviceId() + "] " + endpoint);
|
||||||
|
System.out.println(" - Input Clusters:");
|
||||||
|
|
||||||
|
for (int inputClusterId : endpoint.getInputClusterIds()) {
|
||||||
|
ZclCluster cluster = endpoint.getInputCluster(inputClusterId);
|
||||||
|
System.out.println(" - [cluster id: " + inputClusterId + "] " + cluster);
|
||||||
|
|
||||||
|
if (cluster != null) {
|
||||||
|
for (ZclAttribute attr : cluster.getAttributes()) {
|
||||||
|
System.out.println(" - [attr id: " + attr.getId() + "] " + attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(" - Output Clusters:");
|
||||||
|
|
||||||
|
for (int outputClusterId : endpoint.getOutputClusterIds()) {
|
||||||
|
ZclCluster cluster = endpoint.getInputCluster(outputClusterId);
|
||||||
|
System.out.println(" - [cluster id: " + outputClusterId + "] " + endpoint);
|
||||||
|
|
||||||
|
if (cluster != null) {
|
||||||
|
for (ZclAttribute attr : cluster.getAttributes()) {
|
||||||
|
System.out.println(" - [attr id: " + attr.getId() + "] " + attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println(" Number of Endpoints: " + node.getEndpoints().size());
|
System.out.println(" Number of Endpoints: " + node.getEndpoints().size());
|
||||||
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
System.out.println("--------------------------");
|
||||||
System.out.println("Number of ZigBee Nodes: " + networkManager.getNodes().size());
|
System.out.println("Number of ZigBee Nodes: " + networkManager.getNodes().size());
|
||||||
|
System.out.println("-----------------------------------------------------------------------");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p':
|
case "a":
|
||||||
|
ZigBeeNode node = networkManager.getNode(in.nextInt());
|
||||||
|
ZigBeeEndpoint endpoint = node.getEndpoint(in.nextInt());
|
||||||
|
System.out.println(" - [id: " + endpoint.getDeviceId() + "]" + endpoint);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "p":
|
||||||
System.out.println("Enabling pairing.");
|
System.out.println("Enabling pairing.");
|
||||||
networkManager.permitJoin(200);
|
networkManager.permitJoin(200);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'q':
|
case "q":
|
||||||
System.out.println("Shutting down.");
|
System.out.println("Shutting down.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'h':
|
case "h":
|
||||||
default:
|
default:
|
||||||
System.out.println("Available commands:");
|
System.out.println("Available commands:");
|
||||||
System.out.println(" i: List network info");
|
System.out.println(" i: List network info");
|
||||||
System.out.println(" l: List available ZigBee Nodes");
|
System.out.println(" l: List available ZigBee Nodes");
|
||||||
|
System.out.println(" a <node id> <endpoint id> <attribute id>: read attribute");
|
||||||
System.out.println(" p: Enable pairing of ZigBee devices");
|
System.out.println(" p: Enable pairing of ZigBee devices");
|
||||||
System.out.println(" q: Quit");
|
System.out.println(" q: Quit");
|
||||||
System.out.println(" h: Help text");
|
System.out.println(" h: Help text");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static char waitForInout() throws IOException {
|
|
||||||
System.out.print("");
|
|
||||||
System.out.print("Input command and finish with ENTER: ");
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
char input=(char)System.in.read();
|
|
||||||
if (input != '\n')
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue