diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/WMBusBindingConstants.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/WMBusBindingConstants.java index 808967b..c881f21 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/WMBusBindingConstants.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/WMBusBindingConstants.java @@ -94,6 +94,7 @@ public class WMBusBindingConstants { public static final String MANUFACTURER_AMBER = "amber"; public static final String MANUFACTURER_RADIO_CRAFTS = "rc"; public static final String MANUFACTURER_IMST = "imst"; + public static final String MANUFACTURER_CUL = "cul"; /** * Default frequency of reports. This is at the same time value after which device is considered to be offline. diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/StickModel.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/StickModel.java index 645ec54..feda0ef 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/StickModel.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/StickModel.java @@ -23,6 +23,6 @@ public enum StickModel { amber, rc, - imst - + imst, + cul } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusBridgeHandler.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusBridgeHandler.java index 6e8f700..0321200 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusBridgeHandler.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusBridgeHandler.java @@ -176,6 +176,8 @@ private static WMBusManufacturer parseManufacturer(String manufacturer) { return WMBusManufacturer.RADIO_CRAFTS; case MANUFACTURER_IMST: return WMBusManufacturer.IMST; + case MANUFACTURER_CUL: + return WMBusManufacturer.CUL; default: return null; } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnection.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnection.java index b5de981..670abb3 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnection.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnection.java @@ -70,6 +70,9 @@ public WMBusSerialBuilder(WMBusManufacturer wmBusManufacturer, WMBusListener lis case IMST: setBaudrate(57600); break; + case CUL: + setBaudrate(38400); + break; default: // should not occur throw new RuntimeException( @@ -154,6 +157,9 @@ WMBusConnection build(TransportLayer transportLayer) throws IOException { case RADIO_CRAFTS: wmBusConnection = new WMBusConnectionRadioCrafts(this.mode, this.listener, transportLayer); break; + case CUL: + wmBusConnection = new WMBusConnectionCUL(this.mode, this.listener, transportLayer); + break; default: // should not occur. throw new RuntimeException("Unknown Manufacturer."); @@ -167,6 +173,7 @@ WMBusConnection build(TransportLayer transportLayer) throws IOException { public enum WMBusManufacturer { AMBER, IMST, - RADIO_CRAFTS + RADIO_CRAFTS, + CUL } } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnectionCUL.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnectionCUL.java new file mode 100644 index 0000000..ff3dbd3 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnectionCUL.java @@ -0,0 +1,182 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.openmuc.jmbus.wireless; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.text.MessageFormat; +import java.util.Arrays; + +import org.openmuc.jmbus.DecodingException; +import org.openmuc.jmbus.HexUtils; +import org.openmuc.jmbus.transportlayer.TransportLayer; + +/** + * Was tested with nanocul CULFW 1.67 + */ +class WMBusConnectionCUL extends AbstractWMBusConnection { + + private class MessageReceiverImpl extends MessageReceiver { + + private final TransportLayer transportLayer; + + public MessageReceiverImpl(TransportLayer transportLayer, WMBusListener listener) { + super(listener); + this.transportLayer = transportLayer; + } + + @Override + public void run() { + + try { + + while (!isClosed()) { + task(); + } + + } catch (final IOException e) { + if (isClosed()) { + return; + } + super.notifyStoppedListening(e); + + } finally { + close(); + super.shutdown(); + } + } + + private void task() throws IOException { + + int b0; + DataInputStream is = getInputStream(); + + while (true) { + try { + this.transportLayer.setTimeout(0); + b0 = is.readByte(); // b = indicator of received message by cul + this.transportLayer.setTimeout(MESSAGE_FRAGEMENT_TIMEOUT); + + if ((b0 ^ 'b') == 0) { + // we found beginning of mBUS frame, in the b0 will be the length of message + break; + } + } catch (InterruptedIOException e) { + continue; + } + } + + StringBuilder data = new StringBuilder(); + String lengthInHex = new String(is.readNBytes(2)); + int length = Integer.parseInt(lengthInHex, 16); + + // strip CRCs + data.append(lengthInHex); + data.append(new String(is.readNBytes(9 * 2))); // rest of header 9 bytes as hex + is.readNBytes(2 * 2); // discard CRC after header + + int bytesReadAfterHeader = 0; + while (bytesReadAfterHeader < length - 9) { + data.append(new String(is.readNBytes(2))); + bytesReadAfterHeader++; + + if (bytesReadAfterHeader % 16 == 0 || bytesReadAfterHeader + 9 == length) { + is.readNBytes(2 * 2); // discard CRCs + } + } + + is.readLine(); // discard CRC after last block until \n finishes the message + notifyListener(data.toString()); + } + + private void notifyListener(final String data) { + Integer signalStrengthInDBm = 0; // no information about real strength available + try { + super.notifyNewMessage(WMBusMessage.decode(HexUtils.hexToBytes(data), signalStrengthInDBm, keyMap)); + } catch (DecodingException e) { + // ignore + } + } + } + + public WMBusConnectionCUL(WMBusMode mode, WMBusListener listener, TransportLayer tl) { + super(mode, listener, tl); + } + + @Override + protected MessageReceiver newMessageReceiver(TransportLayer transportLayer, WMBusListener listener) { + return new MessageReceiverImpl(transportLayer, listener); + } + + /** + * @param mode + * - the wMBus mode to be used for transmission + * @throws IOException + */ + @Override + protected void initializeWirelessTransceiver(WMBusMode mode) throws IOException { + + try { + setMode(mode); + } catch (Exception e) { + setMode(mode); // try again because cul may react slow + } + } + + private void setMode(WMBusMode mode) throws IOException { + switch (mode) { + case S: + writeCommand(new byte[] { 'b', 'r', 's' }); + expectResponse("SMODE".getBytes()); + break; + case T: + writeCommand(new byte[] { 'b', 'r', 't' }); + expectResponse("TMODE".getBytes()); + break; + case C: + writeCommand(new byte[] { 'b', 'r', 'c' }); + expectResponse("CMODE".getBytes()); + break; + default: + String message = MessageFormat.format("wMBUS Mode ''{0}'' is not supported", mode.toString()); + throw new IOException(message); + } + } + + /** + * Writes a {@code command} to the cul module. + * + * @param cmd + * cul command + * @throws IOException + * if an error occurred, while writing the command. + */ + private void writeCommand(byte[] cmd) throws IOException { + DataOutputStream os = getOutputStream(); + os.write(cmd); + os.write('\n'); + os.flush(); + } + + /** + * reads a response of the cul and compares with the expected value + * + * @param cmd + * expected response + * @throws IOException + * if an error occurred, while evaluating the command response. + */ + private void expectResponse(byte[] response) throws IOException { + byte[] actualResponse = getInputStream().readNBytes(response.length); + if (!Arrays.equals(response, actualResponse)) { + throw new IOException(MessageFormat.format( + "Setup of CUL failed! Could not set receive mode. Expected response was ''{0}'' but expected ''{1}''", + new String(actualResponse), new String(response))); + } + } +} diff --git a/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/bridge.xml b/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/bridge.xml index b01daf0..ea82e2a 100644 --- a/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/bridge.xml +++ b/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/bridge.xml @@ -21,6 +21,7 @@ +