diff --git a/plugins/hal-zigbee/build.gradle b/plugins/hal-zigbee/build.gradle index fc27b146..34410b83 100644 --- a/plugins/hal-zigbee/build.gradle +++ b/plugins/hal-zigbee/build.gradle @@ -1,12 +1,14 @@ -repositories { - maven { - url "https://dl.bintray.com/tlaukkan/bubblecloud" - } -} - dependencies { + def ZIGBEE_LIB_VERSION = "1.3.10" + implementation project(':hal-core') + implementation "com.zsmartsystems.zigbee:com.zsmartsystems.zigbee:${ZIGBEE_LIB_VERSION}" + implementation "com.zsmartsystems.zigbee:com.zsmartsystems.zigbee.serial:${ZIGBEE_LIB_VERSION}" + implementation "com.zsmartsystems.zigbee:com.zsmartsystems.zigbee.dongle.cc2531:${ZIGBEE_LIB_VERSION}" + implementation "com.zsmartsystems.zigbee:com.zsmartsystems.zigbee.dongle.xbee:${ZIGBEE_LIB_VERSION}" + implementation "com.zsmartsystems.zigbee:com.zsmartsystems.zigbee.dongle.conbee:${ZIGBEE_LIB_VERSION}" + implementation 'com.fazecast:jSerialComm:2.6.2' - implementation 'org.bubblecloud.zigbee4java:zigbee-api:3.0.3' + implementation 'org.slf4j:slf4j-jdk14:1.7.30' } diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/HalZigbeeController.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/HalZigbeeController.java index a12afce8..04a559e2 100644 --- a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/HalZigbeeController.java +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/HalZigbeeController.java @@ -1,9 +1,13 @@ package se.hal.plugin.zigbee; -import org.bubblecloud.zigbee.v3.SerialPort; -import org.bubblecloud.zigbee.v3.ZigBeeApiDongleImpl; -import org.bubblecloud.zigbee.v3.ZigBeeDevice; -import org.bubblecloud.zigbee.v3.ZigBeeDongleTiCc2531Impl; + +import com.zsmartsystems.zigbee.ZigBeeNetworkManager; +import com.zsmartsystems.zigbee.ZigBeeStatus; +import com.zsmartsystems.zigbee.dongle.cc2531.ZigBeeDongleTiCc2531; +import com.zsmartsystems.zigbee.dongle.conbee.ZigBeeDongleConBee; +import com.zsmartsystems.zigbee.dongle.xbee.ZigBeeDongleXBee; +import com.zsmartsystems.zigbee.transport.ZigBeePort; +import com.zsmartsystems.zigbee.transport.ZigBeeTransportTransmit; import se.hal.HalContext; import se.hal.intf.*; import se.hal.struct.AbstractDevice; @@ -19,10 +23,10 @@ public class HalZigbeeController implements HalSensorController, HalEventControl private static final Logger logger = LogUtil.getLogger(); private static final String CONFIG_ZIGBEE_PORT = "zigbee.com_port"; - private static final String CONFIG_ZIGBEE_PANID = "zigbee.pan_id"; - private SerialPort port; - protected ZigBeeApiDongleImpl zigbeeApi; + private ZigBeePort serialPort; + private ZigBeeDataStore dataStore; + private ZigBeeNetworkManager networkManager; private HalSensorReportListener sensorListener; private HalEventReportListener eventListener; @@ -34,31 +38,55 @@ public class HalZigbeeController implements HalSensorController, HalEventControl @Override public boolean isAvailable() { - return HalContext.containsProperty(CONFIG_ZIGBEE_PORT) && - HalContext.containsProperty(CONFIG_ZIGBEE_PANID); + return HalContext.containsProperty(CONFIG_ZIGBEE_PORT); } @Override public void initialize() { initialize( - HalContext.getStringProperty(CONFIG_ZIGBEE_PORT), - HalContext.getIntegerProperty(CONFIG_ZIGBEE_PANID)); + HalContext.getStringProperty(CONFIG_ZIGBEE_PORT)); } - public void initialize(String comPort, int panId) { - byte[] networkKey = null; // Default network key - port = new SerialPortJSC(comPort); - zigbeeApi = new ZigBeeApiDongleImpl( - new ZigBeeDongleTiCc2531Impl(port, -6480, 11, networkKey, false), - false); + public void initialize(String comPort) { + serialPort = new ZigBeeJSerialCommPort(comPort); + dataStore = new ZigBeeDataStore(); - zigbeeApi.startup(); + ZigBeeTransportTransmit dongle = getDongle("CC2531"); + ZigBeeNetworkManager networkManager = new ZigBeeNetworkManager(dongle); + networkManager.setNetworkDataStore(dataStore); + + ZigBeeStatus initResponse = networkManager.initialize(); + System.out.println("NetworkManager.initialize() returned " + initResponse); + + System.out.println("PAN ID = " + networkManager.getZigBeePanId()); + System.out.println("Extended PAN ID = " + networkManager.getZigBeeExtendedPanId()); + System.out.println("Channel = " + networkManager.getZigBeeChannel()); + + if (dongle instanceof ZigBeeDongleTiCc2531) { + ZigBeeDongleTiCc2531 tiDongle = (ZigBeeDongleTiCc2531) dongle; + tiDongle.setLedMode(1, false); + tiDongle.setLedMode(2, false); + } + } + + private ZigBeeTransportTransmit getDongle(String name) { + switch (name) { + case "CC2531": + return new ZigBeeDongleTiCc2531(serialPort); + case "XBEE": + return new ZigBeeDongleXBee(serialPort); + case "CONBEE": + return new ZigBeeDongleConBee(serialPort); + default: + logger.severe("Unknown ZigBee dongle: " + name); + return null; + } } @Override public void close() { logger.info("Shutting down Zigbee port."); - zigbeeApi.shutdown(); - port.close(); + networkManager.shutdown(); + serialPort.close(); } diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/SerialPortJSC.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/SerialPortJSC.java deleted file mode 100644 index e7f315e1..00000000 --- a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/SerialPortJSC.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020 Ziver Koc - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package se.hal.plugin.zigbee; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.InputStream; -import java.io.OutputStream; - -import com.fazecast.jSerialComm.SerialPort; - -/** - * Wrapper for usage of JSerialComm library with Zigbee4Java - * - * @author Ziver Koc - */ -public class SerialPortJSC implements org.bubblecloud.zigbee.v3.SerialPort { - private final static Logger LOGGER = LoggerFactory.getLogger(SerialPortJSC.class); - - /** - * The default baud rate. - */ - public static final int DEFAULT_BAUD_RATE = 38400; - - private final String portName; - private final int baudRate; - - private SerialPort serialPort; - private InputStream inputStream; - private OutputStream outputStream; - - /** - * Constructor which sets port name to given value and baud rate to default. - */ - public SerialPortJSC(final String portName) { - this(portName, DEFAULT_BAUD_RATE); - } - - /** - * Constructor setting port name and baud rate. - * @param portName the port name - * @param baudRate the baud rate - */ - public SerialPortJSC(final String portName, final int baudRate) { - this.portName = portName; - this.baudRate = baudRate; - } - - - @Override - public boolean open() { - if (serialPort != null) { - throw new RuntimeException("Serial port already open."); - } - - try { - LOGGER.info("Connecting to com port... (" + portName + ")"); - serialPort = SerialPort.getCommPort(portName); - serialPort.setBaudRate(baudRate); - serialPort.setComPortTimeouts( - SerialPort.TIMEOUT_READ_BLOCKING, 0, 0); - - if (!serialPort.openPort()) { - LOGGER.error("Could not open port: " + portName); - return false; - } - - outputStream = serialPort.getOutputStream(); - inputStream = serialPort.getInputStream(); - return true; - } catch (Exception e) { - LOGGER.warn("Unable to open serial port: " + e.getMessage()); - return false; - } - } - - @Override - public void close() { - if (serialPort == null) - return; - - try { - inputStream.close(); - outputStream.flush(); - outputStream.close(); - serialPort.closePort(); - - LOGGER.info("Serial portName '" + portName + "' closed."); - - serialPort = null; - inputStream = null; - outputStream = null; - } catch (Exception e) { - LOGGER.warn("Error closing portName portName: '" + portName + "'", e); - } - } - - @Override - public OutputStream getOutputStream() { - return outputStream; - } - - @Override - public InputStream getInputStream() { - return inputStream; - } -} diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/ZigBeeDataStore.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/ZigBeeDataStore.java new file mode 100644 index 00000000..fc06686c --- /dev/null +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/ZigBeeDataStore.java @@ -0,0 +1,57 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2021 Ziver Koc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package se.hal.plugin.zigbee; + +import com.zsmartsystems.zigbee.IeeeAddress; +import com.zsmartsystems.zigbee.database.ZigBeeNetworkDataStore; +import com.zsmartsystems.zigbee.database.ZigBeeNodeDao; + +import java.util.HashSet; +import java.util.Set; + +public class ZigBeeDataStore implements ZigBeeNetworkDataStore { + + @Override + public Set readNetworkNodes() { + System.out.println("ZigBeeDataStore.readNetworkNodes()"); + return new HashSet<>(); + } + + @Override + public ZigBeeNodeDao readNode(IeeeAddress address) { + System.out.println("ZigBeeDataStore.readNetworkNodes(" + address + ")"); + return null; + } + + @Override + public void writeNode(ZigBeeNodeDao node) { + System.out.println("ZigBeeDataStore.writeNode(" + node + ")"); + } + + @Override + public void removeNode(IeeeAddress address) { + System.out.println("ZigBeeDataStore.removeNode(" + address + ")"); + } +} diff --git a/plugins/hal-zigbee/src/se/hal/plugin/zigbee/ZigBeeJSerialCommPort.java b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/ZigBeeJSerialCommPort.java new file mode 100644 index 00000000..74b7d941 --- /dev/null +++ b/plugins/hal-zigbee/src/se/hal/plugin/zigbee/ZigBeeJSerialCommPort.java @@ -0,0 +1,190 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Ziver Koc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package se.hal.plugin.zigbee; + +import com.zsmartsystems.zigbee.transport.ZigBeePort; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fazecast.jSerialComm.SerialPort; + +/** + * ZigBeePort implementation using jSerialComm library + * + * @author Ziver Koc + */ +public class ZigBeeJSerialCommPort implements ZigBeePort { + private final static Logger logger = LoggerFactory.getLogger(ZigBeeJSerialCommPort.class); + + /** + * The default baud rate. + */ + public static final int DEFAULT_BAUD_RATE = 38400; + + /** + * The default flow control. + */ + public static final FlowControl DEFAULT_FLOW_CONTROL = FlowControl.FLOWCONTROL_OUT_NONE; + + + private final String portName; + private final int baudRate; + private final FlowControl flowControl; + private SerialPort serialPort; + + + /** + * Constructor which sets port name to given value and baud rate to default. + * + * @param portName the port name + */ + public ZigBeeJSerialCommPort(String portName) { + this(portName, DEFAULT_BAUD_RATE); + } + + /** + * Constructor setting port name and baud rate. + * + * @param portName the port name + * @param baudRate the default baud rate + */ + public ZigBeeJSerialCommPort(String portName, int baudRate) { + this(portName, baudRate, DEFAULT_FLOW_CONTROL); + } + + /** + * Constructor setting port name and baud rate. + * + * @param portName the port name + * @param baudRate the default baud rate + */ + public ZigBeeJSerialCommPort(String portName, int baudRate, FlowControl flowControl) { + this.portName = portName; + this.baudRate = baudRate; + this.flowControl = flowControl; + } + + + @Override + public boolean open() { + return open(baudRate); + } + + @Override + public boolean open(int baudRate) { + return open(baudRate, flowControl); + } + + @Override + public boolean open(int baudRate, FlowControl flowControl) { + try { + openSerialPort(portName, baudRate, flowControl); + + return true; + } catch (Exception e) { + logger.warn("Unable to open serial port: " + e.getMessage()); + return false; + } + } + + /** + * Opens serial port. + * + * @param portName the port name + * @param baudRate the baud rate + * @param flowControl the flow control option + */ + private void openSerialPort(String portName, int baudRate, FlowControl flowControl) { + if (serialPort != null) { + throw new RuntimeException("Serial port already open."); + } + + logger.debug("Opening port {} at {} baud with {}.", portName, baudRate, flowControl); + + serialPort = SerialPort.getCommPort(portName); + serialPort.setBaudRate(baudRate); + serialPort.setComPortTimeouts( + SerialPort.TIMEOUT_READ_BLOCKING, 0, 0); + + if (!serialPort.openPort()) { + throw new RuntimeException("Error opening serial port: " + portName); + } + + switch (flowControl) { + case FLOWCONTROL_OUT_NONE: + serialPort.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED); + break; + case FLOWCONTROL_OUT_RTSCTS: + serialPort.setFlowControl( + SerialPort.FLOW_CONTROL_RTS_ENABLED | SerialPort.FLOW_CONTROL_CTS_ENABLED); + break; + case FLOWCONTROL_OUT_XONOFF: + serialPort.setFlowControl( + SerialPort.FLOW_CONTROL_XONXOFF_IN_ENABLED | SerialPort.FLOW_CONTROL_XONXOFF_OUT_ENABLED); + break; + default: + break; + } + } + + @Override + public void close() { + if (serialPort == null) + return; + + try { + logger.info("Closing Serial port: '" + portName + "'"); + serialPort.closePort(); + serialPort = null; + } catch (Exception e) { + logger.warn("Error closing portName portName: '" + portName + "'", e); + } + } + + @Override + public void write(int value) { + serialPort.writeBytes(new byte[]{(byte) value}, 1); + } + + @Override + public int read() { + return read(0); + } + + @Override + public int read(int timeout) { + byte[] buff = new byte[1]; + serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, timeout, 0); + serialPort.readBytes(buff, 1); + return buff[0]; + } + + @Override + public void purgeRxBuffer() { + while(serialPort.bytesAwaitingWrite() != 0) { + try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();} + } + } +} diff --git a/plugins/hal-zigbee/test/se/hal/plugin/zigbee/HalZigbeeControllerTest.java b/plugins/hal-zigbee/test/se/hal/plugin/zigbee/HalZigbeeControllerTest.java index 6cef9cae..e4603350 100644 --- a/plugins/hal-zigbee/test/se/hal/plugin/zigbee/HalZigbeeControllerTest.java +++ b/plugins/hal-zigbee/test/se/hal/plugin/zigbee/HalZigbeeControllerTest.java @@ -24,13 +24,13 @@ package se.hal.plugin.zigbee; -import org.bubblecloud.zigbee.v3.ZigBeeDevice; import zutil.log.CompactLogFormatter; import zutil.log.LogUtil; import java.io.IOException; import java.util.logging.Level; + public class HalZigbeeControllerTest { public static void main(String[] args) throws IOException, InterruptedException { @@ -38,18 +38,7 @@ public class HalZigbeeControllerTest { LogUtil.setGlobalLevel(Level.ALL); HalZigbeeController controller = new HalZigbeeController(); - controller.initialize("COM3", -6); - - System.out.println("Enable pairing."); - controller.zigbeeApi.permitJoin(true); - - //controller.zigbeeApi - - Thread.sleep(10000); - - for (ZigBeeDevice device : controller.zigbeeApi.getDevices()) { - System.out.println("Device: " + device); - } + controller.initialize("COM3"); System.out.println("Press ENTER to exit application."); System.in.read();