diff --git a/README.md b/README.md index 8da7969..1bb58a3 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ This is a binding for the [openHAB](https://www.openhab.org/) / eclipse Smart Home home automation system. It aims to make data available to the user, which is already sent by lots of modern metering hardware (e.g. heat cost allocators, electricity/gas/water/heat meters) already widely deployed in houses and especially flats. -The binding is based on the [jMBus](https://www.openmuc.org/m-bus/) library, which provides all basic receiving and decoding. It is currently using [a fork](https://github.com/kaikreuzer/jmbus) of version 3.1.1 to make it work within openHAB. +The binding is based on the [jMBus](https://www.openmuc.org/m-bus/) library, which provides all basic receiving and decoding. It is currently using version 3.1.1 plus one extension for access to the RAW frame. Implementation of the Techem devices has been ported from [FHEM](https://forum.fhem.de/index.php/topic,42232.html). -The binding is working stable. To use it, you need a device to receive the transmissions. The underlying library supports transceivers of Amber, Radiocrafts (RC1180-MBUS) and IMST (iM871A-USB), the binding is mainly developed and tested with the [Amber Wireless AMB8465-M](https://www.amber-wireless.de/de/produkte/wireless-m-bus/alle-usb-sticks/wireless-m-bus-868-mhz-usb-stick-int-antenne-amb8465-m.html). -However, development is still going on and there are some known issues. One is, that sometimes when changing settings etc. to the stick, the serial port native parts segfault and the whole openHAB is restarting. This seems to be caused by a bug in the serial library or the jMBus library. +The binding is working stable. To use it, you need a device to receive the transmissions. The underlying library supports transceivers of Amber, Radiocrafts (RC1180-MBUS) and IMST (iM871A-USB), the binding is mainly developed and tested with the [Amber Wireless AMB8465-M](https://www.we-online.de/catalog/en/USB_RADIO_STICK_METERING). +However, development is still going on and there are some known issues. ### Features: * Receive WMBus frames as inbox discovery results @@ -39,23 +39,23 @@ There is some more information and discussion [in the forum](https://community.o ![Diagram in HABmin, fed by several HKVs ](doc/diagrams.png) ## Install -1. Drop the .jar from https://github.com/KuguHome/openhab-binding-wmbus/releases (or your own build, see below) into your openHAB2 Karaf deploy directory, e.g. `openhab2/addons` or `/usr/share/openhab2/addons/`. +1. Drop the .jar from https://github.com/KuguHome/openhab-binding-wmbus/releases (or your own build, see below) into your openHAB Karaf deploy directory, e.g. `openhab/addons` or `/usr/share/openhab/addons/`. 2. It should get picked up automatically and started by Karaf. 3. Run `bundle:list` in the [OSGi console](https://www.openhab.org/docs/administration/console.html), it should show a `wmbus` bundle in active state. If it is there but not active yet, try `feature:install openhab-transport-serial` or `bundle:start XXX` where `XXX` is the number of the wmbus bundle shown by the `list` command. -4. Open PaperUI in the browser. -5. Check that Configuration -> Bindings lists the WMBus Binding. -6. Go to Configuration -> Things. +4. Open OH3 UI in the browser. +5. Check that `Settings` -> `Things` -> `(+)` lists the WMBus Binding. +6. Configure WMBus Binding: Set `include the BridgeUID (stick/adapter name) into the ThingUID of the metering device` to `true`. 7. Manually add new WMBus Binding Thing -> WMBus Stick (exactly one). -8. Select/enter serial device (e.g. /dev/ttyUSB0, check via `dmesg` when plugging in the stick) as configuration parameter. +8. Select/enter serial device (e.g. `/dev/ttyUSB0`, check via `dmesg` when plugging in the stick) as configuration parameter. 9. Select receiving mode. T is most common, will also receive frames sent in mode C. S is transmitting only rarely. -10. The Thing should show `ONLINE` as status. If not, edit the Thing, this screen should include some more error details, also check OSGi console and `userdata/logs/openhab.log` or `/var/log/oppenhab2/openhab.log`. +10. The Thing should show `ONLINE` as status. If not, edit the Thing, this screen should include some more error details, also check OSGi console and `userdata/logs/openhab.log` or `/var/log/oppenhab/openhab.log`. 11. If everything is working correctly, devices should be discovered automatically and turn up as new Things in the Inbox as soon as a message is received from them. Manually adding the devices is not necessary, also the active search function when adding a Thing does nothing. Everything goes throught the discovery. 12. Search your devices in the Inbox by the ID that is printed outside or shown on the display (e.g. Techem HKVs display the last 4 digits) and add those devices via the checkmark button. Make sure "Item Linking Simple Mode" is activated or link the channels to items yourself. 13. On the "Control" page, the Thing with it's different channels should display, readings should be updated regularly about every 4 minutes: * Room/radiator temperature etc. are always current (at the time of sending/receiving the message). * Some device's "Current Reading" will only update once each day. 14. If a Persistence Add-on (e.g. InfluxDB) is installed, the readings will also be stored into the database. -15. In HABmin or HABPanel, diagrams/charts/graphs can be configured to have a look at the latest values in comparison. Grafana is a good third party software to get an overview. +15. In OH3 UI, diagrams/charts/graphs can be configured to have a look at the latest values in comparison. Grafana is a good third party software to get an overview. 16. If any Exceptions or other messages turn up in the logs or console, please let us know and open an issue here. ### Encrypted messages @@ -68,7 +68,7 @@ If your device is encrypted, you will need to get the AES key from the manufactu ## Build 1. Run `mvn package` in the root directory.. -2. The compilation result will be at `org.openhab.binding.wmbus/target/org.openhab.binding.wmbus-2.3.0-SNAPSHOT.jar`. +2. The compilation result will be at `org.openhab.binding.wmbus/target/org.openhab.binding.wmbus-3.1.0-SNAPSHOT.jar`. ## Development @@ -76,7 +76,7 @@ If your device is encrypted, you will need to get the AES key from the manufactu 2. Clone this repository. 3. File - Import - Maven - Existing Maven Projects. Give path to this git repository, select all three projects, add project to working set "WMBus" or similar. -For debugging and development, it is helpful to add the folloing to `/var/lib/openhab2/etc/org.ops4j.pax.logging.cfg` to log to a separate file `/var/log/openhab2/wmbus.log` +For debugging and development, it is helpful to add the folloing to `/var/lib/openhab/etc/org.ops4j.pax.logging.cfg` to log to a separate file `/var/log/openhab/wmbus.log` ``` # Define WMBus file appender @@ -100,8 +100,8 @@ log4j2.logger.org_openhab_binding_wmbus.appenderRef.wmbus.ref = WMBUS ``` ## Raw tool -There is an additional tool, that compiles as a second .jar file `org.openhab.binding.wmbus.tools-2.3.0-SNAPSHOT.jar` (also available from the releases page). If you drop this bundle into your addons folder or install it otherwise to openHAB, you can access the tool at http://localhost:8080/wmbus. It gives you the ability to inject frames to the binding, as if they were received via a stick. There is also a collector, which lists you each received WMbus frame as raw hex, together with timestamp and basic grouping (ID, Manufacturer, device type). -If you add the following lines to `/var/lib/openhab2/etc/org.ops4j.pax.logging.cfg`, you can also log all frames to a plaintext file `wmbustools.log`. The content of that file can later be fed to the injector. +There is an additional tool, that compiles as a second .jar file `org.openhab.binding.wmbus.tools-3.1.0-SNAPSHOT.jar` (also available from the releases page). If you drop this bundle into your addons folder or install it otherwise to openHAB, you can access the tool at http://localhost:8080/wmbus. It gives you the ability to inject frames to the binding, as if they were received via a stick. There is also a collector, which lists you each received WMbus frame as raw hex, together with timestamp and basic grouping (ID, Manufacturer, device type). +If you add the following lines to `/var/lib/openhab/etc/org.ops4j.pax.logging.cfg`, you can also log all frames to a plaintext file `wmbustools.log`. The content of that file can later be fed to the injector. ``` # Define WMBus Tools file appender diff --git a/org.openhab.binding.wmbus.tools/pom.xml b/org.openhab.binding.wmbus.tools/pom.xml index ec7fbb1..3793db7 100644 --- a/org.openhab.binding.wmbus.tools/pom.xml +++ b/org.openhab.binding.wmbus.tools/pom.xml @@ -1,75 +1,75 @@ - - 4.0.0 + + 4.0.0 - - org.openhab.binding - wmbus - 2.5.0-SNAPSHOT - + + org.openhab.addons.bundles + wmbus + 3.1.0-SNAPSHOT + - org.openhab.binding - org.openhab.binding.wmbus.tools + org.openhab.addons.bundles + org.openhab.binding.wmbus.tools - WMBus Binding Tools - - - false - + WMBus Binding Tools - - - org.openhab.binding - org.openhab.binding.wmbus - ${project.version} - + + false + - - com.google.guava - guava - 20.0 - provided - + + + org.openhab.addons.bundles + org.openhab.binding.wmbus + ${project.version} + - - org.openhab.core.bom - org.openhab.core.bom.compile - pom - provided - - - org.openhab.core.bom - org.openhab.core.bom.openhab-core - pom - provided - + + com.google.guava + guava + 20.0 + provided + - - junit - junit - 4.12 - test - - - org.assertj - assertj-core - 3.11.1 - test - - - org.slf4j - slf4j-simple - 1.7.2 - test - - - org.mockito - mockito-core - 2.23.0 - test - + + org.openhab.core.bom + org.openhab.core.bom.compile + pom + provided + + + org.openhab.core.bom + org.openhab.core.bom.openhab-core + pom + provided + - + + junit + junit + 4.12 + test + + + org.assertj + assertj-core + 3.11.1 + test + + + org.slf4j + slf4j-simple + 1.7.2 + test + + + org.mockito + mockito-core + 2.23.0 + test + + + diff --git a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/CollectorServlet.java b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/CollectorServlet.java index 855d77e..e2662ec 100644 --- a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/CollectorServlet.java +++ b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/CollectorServlet.java @@ -26,10 +26,10 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.handler.WMBusAdapter; import org.openhab.binding.wmbus.handler.WMBusMessageListener; +import org.openhab.core.util.HexUtils; import org.openmuc.jmbus.SecondaryAddress; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; diff --git a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/InjectorServlet.java b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/InjectorServlet.java index df803cf..ffd379b 100644 --- a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/InjectorServlet.java +++ b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/InjectorServlet.java @@ -8,14 +8,25 @@ */ package org.openhab.binding.wmbus.tools; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.*; +import java.util.stream.Collectors; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.apache.commons.io.IOUtils; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.thing.ThingRegistry; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.WMBusBindingConstants; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.handler.WMBusAdapter; import org.openhab.binding.wmbus.tools.processor.*; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingRegistry; +import org.openhab.core.util.HexUtils; import org.openmuc.jmbus.DecodingException; import org.openmuc.jmbus.wireless.VirtualWMBusMessageHelper; import org.openmuc.jmbus.wireless.WMBusMessage; @@ -28,16 +39,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.*; -import java.util.stream.Collectors; - /** * Very basic servlet which allows to send a test frame to deployed binding. * @@ -109,8 +110,8 @@ private void inject(WMBusAdapter adapter, String frames, HttpServletRequest req, boolean stripCRC = Optional.ofNullable(req.getParameter("stripCRC")).map(value -> Boolean.TRUE).orElse(false); boolean calculateLength = Optional.ofNullable(req.getParameter("calculateLength")).map(value -> Boolean.TRUE) .orElse(false); - boolean recalculateLength = Optional.ofNullable(req.getParameter("recalculateLength")).map(value -> Boolean.TRUE) - .orElse(false); + boolean recalculateLength = Optional.ofNullable(req.getParameter("recalculateLength")) + .map(value -> Boolean.TRUE).orElse(false); List> processors = new ArrayList<>(); processors.add(new RssiProcessor(rssiIndex, rssiValue)); @@ -184,5 +185,4 @@ public void activate() throws ServletException, NamespaceException { public void deactivate() { httpService.unregister("/wmbus"); } - } diff --git a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/LoggingMessageListener.java b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/LoggingMessageListener.java index c2787f6..7cb5dfb 100644 --- a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/LoggingMessageListener.java +++ b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/LoggingMessageListener.java @@ -8,11 +8,10 @@ */ package org.openhab.binding.wmbus.tools; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.WMBusDevice; -import org.openmuc.jmbus.wireless.WMBusMessage; import org.openhab.binding.wmbus.handler.WMBusAdapter; import org.openhab.binding.wmbus.handler.WMBusMessageListener; +import org.openhab.core.util.HexUtils; import org.osgi.service.component.annotations.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,5 +39,4 @@ public void onChangedWMBusDevice(WMBusAdapter adapter, WMBusDevice device) { private void log(WMBusDevice device) { logger.debug(HexUtils.bytesToHex(device.getOriginalMessage().asBlob())); } - } diff --git a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/Processor.java b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/Processor.java index c4fbe66..631db5d 100644 --- a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/Processor.java +++ b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/Processor.java @@ -17,8 +17,7 @@ */ public interface Processor { - String RSSI = "rssi"; - - T process(T frame, Map context); + String RSSI = "rssi"; + T process(T frame, Map context); } diff --git a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/CalculateLength.java b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/CalculateLength.java index 2979463..960dcf8 100644 --- a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/CalculateLength.java +++ b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/CalculateLength.java @@ -8,17 +8,16 @@ */ package org.openhab.binding.wmbus.tools.processor; -import org.openhab.binding.wmbus.tools.Processor; - import java.util.Map; -public class CalculateLength implements Processor { +import org.openhab.binding.wmbus.tools.Processor; - @Override - public String process(String frame, Map context) { - // remember of hex notation which doubles length - Integer len = frame.length() / 2; - return Integer.toHexString(len) + frame; - } +public class CalculateLength implements Processor { + @Override + public String process(String frame, Map context) { + // remember of hex notation which doubles length + Integer len = frame.length() / 2; + return Integer.toHexString(len) + frame; + } } diff --git a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/Processors.java b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/Processors.java index 4e1e297..1092dc5 100644 --- a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/Processors.java +++ b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/Processors.java @@ -8,11 +8,11 @@ */ package org.openhab.binding.wmbus.tools.processor; -import org.openhab.binding.wmbus.tools.Processor; - import java.util.List; import java.util.Map; +import org.openhab.binding.wmbus.tools.Processor; + /** * Helper type to orchestrate execution of several frame processors at once. * @@ -20,17 +20,16 @@ */ public class Processors { - public static T process(final T value, Map context, List> processors) { - if (processors.isEmpty()) { - return value; - } - - T result = value; - for (Processor processor : processors) { - result = processor.process(result, context); - } + public static T process(final T value, Map context, List> processors) { + if (processors.isEmpty()) { + return value; + } - return result; - } + T result = value; + for (Processor processor : processors) { + result = processor.process(result, context); + } + return result; + } } diff --git a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/RecalculateLength.java b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/RecalculateLength.java index 6f87e13..f1098ba 100644 --- a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/RecalculateLength.java +++ b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/RecalculateLength.java @@ -8,45 +8,44 @@ */ package org.openhab.binding.wmbus.tools.processor; -import org.openhab.binding.wmbus.tools.Processor; - import java.util.Map; +import org.openhab.binding.wmbus.tools.Processor; + public class RecalculateLength implements Processor { - @Override - public String process(String frame, Map context) { - int inputByteLength = frame.length() / 2; - - String newFrame = ""; - Integer numberOfBlocks; - int ciField = parseInt(frame, 20, 22); - - if (ciField == 0x7A){ - numberOfBlocks = (inputByteLength-14) / 16; - inputByteLength = 14 + numberOfBlocks*16; - newFrame += Integer.toHexString(inputByteLength); - newFrame += frame.substring(2, 26); - newFrame += Integer.toHexString(numberOfBlocks*16); - newFrame += frame.substring(28, (inputByteLength * 2) + 2); - return newFrame; + @Override + public String process(String frame, Map context) { + int inputByteLength = frame.length() / 2; + + String newFrame = ""; + Integer numberOfBlocks; + int ciField = parseInt(frame, 20, 22); + + if (ciField == 0x7A) { + numberOfBlocks = (inputByteLength - 14) / 16; + inputByteLength = 14 + numberOfBlocks * 16; + newFrame += Integer.toHexString(inputByteLength); + newFrame += frame.substring(2, 26); + newFrame += Integer.toHexString(numberOfBlocks * 16); + newFrame += frame.substring(28, (inputByteLength * 2) + 2); + return newFrame; + } + + if (ciField == 0x72) { + numberOfBlocks = (inputByteLength - 22) / 16; + inputByteLength = 22 + numberOfBlocks * 16; + newFrame += Integer.toHexString(inputByteLength); + newFrame += frame.substring(2, 42); + newFrame += Integer.toHexString(numberOfBlocks * 16); + newFrame += frame.substring(44, (inputByteLength * 2) + 2); + return newFrame; + } + + return newFrame; } - if (ciField == 0x72){ - numberOfBlocks = (inputByteLength-22) / 16; - inputByteLength = 22 + numberOfBlocks*16; - newFrame += Integer.toHexString(inputByteLength); - newFrame += frame.substring(2, 42); - newFrame += Integer.toHexString(numberOfBlocks*16); - newFrame += frame.substring(44, (inputByteLength * 2) + 2); - return newFrame; + private int parseInt(String frame, int startIndex, int endIndex) { + return Integer.parseInt(frame.substring(startIndex, endIndex), 16); } - - return newFrame; - } - - private int parseInt(String frame, int startIndex, int endIndex) { - return Integer.parseInt(frame.substring(startIndex, endIndex), 16); - } - } diff --git a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/RssiProcessor.java b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/RssiProcessor.java index db16a57..98a5875 100644 --- a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/RssiProcessor.java +++ b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/RssiProcessor.java @@ -8,33 +8,33 @@ */ package org.openhab.binding.wmbus.tools.processor; -import org.openhab.binding.wmbus.tools.Processor; - import java.util.Map; -public class RssiProcessor implements Processor { +import org.openhab.binding.wmbus.tools.Processor; - private final int rssiIndex; - private final int rssiValue; +public class RssiProcessor implements Processor { - public RssiProcessor(int rssiIndex, int rssiValue) { - this.rssiIndex = rssiIndex; - this.rssiValue = rssiValue; - } + private final int rssiIndex; + private final int rssiValue; - @Override - public String process(String frame, Map context) { - if (rssiIndex != 0) { - if (rssiIndex == 1) { // first byte starts from character at index 0. - context.put(RSSI, Integer.parseUnsignedInt(frame.substring(0, 2), 16)); - return frame.substring(2); - } else if (rssiIndex == -1) { - context.put(RSSI, Integer.parseUnsignedInt(frame.substring(frame.length() -2), 16)); - return frame.substring(0, frame.length() - 2); - } + public RssiProcessor(int rssiIndex, int rssiValue) { + this.rssiIndex = rssiIndex; + this.rssiValue = rssiValue; } - context.put(RSSI, rssiValue); - return frame; - } + @Override + public String process(String frame, Map context) { + if (rssiIndex != 0) { + if (rssiIndex == 1) { // first byte starts from character at index 0. + context.put(RSSI, Integer.parseUnsignedInt(frame.substring(0, 2), 16)); + return frame.substring(2); + } else if (rssiIndex == -1) { + context.put(RSSI, Integer.parseUnsignedInt(frame.substring(frame.length() - 2), 16)); + return frame.substring(0, frame.length() - 2); + } + } + + context.put(RSSI, rssiValue); + return frame; + } } diff --git a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/SkipCrcProcessor.java b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/SkipCrcProcessor.java index 357c963..b9299b1 100644 --- a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/SkipCrcProcessor.java +++ b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/SkipCrcProcessor.java @@ -8,49 +8,47 @@ */ package org.openhab.binding.wmbus.tools.processor; -import org.openhab.binding.wmbus.tools.Processor; - -import java.util.HashMap; import java.util.Map; +import org.openhab.binding.wmbus.tools.Processor; + public class SkipCrcProcessor implements Processor { - @Override - public String process(String frame, Map context) { - String strippedframe = ""; - int len = frame.length() / 2; // include all fields - - //int lengthField = Integer.decode(frame.substring(0, 2)); - int ciField = parseInt(frame, 22, 24); - boolean formatB = ciField == 0x72 || ciField == 0x7A; - - if (formatB) { - strippedframe += frame.substring(0, Math.min(18, frame.length() - 4)); - // block 1 + block 2 = 11 + ((16*n)+2) -- max 129 bytes - if (len <= 129) { - strippedframe += frame.substring(Math.min(22, frame.length()), frame.length() - 4); - } - // block 1 + block 2 + block 3= 11 + ((16*n)+2) + (16*n) -- bytes > 129 - else { - strippedframe += frame.substring(22, 256); - strippedframe += frame.substring(Math.min(260, frame.length()), frame.length() - 4); - } - } else { - // assume that we starts counting from C-field - strippedframe += frame.substring(0, Math.min(18, frame.length())); - int position = 22; - while (position < frame.length()) { - strippedframe += frame.substring(position, Math.min(position + 32, frame.length())); - position += 36; - } - strippedframe = strippedframe.substring(0,strippedframe.length()-4); + @Override + public String process(String frame, Map context) { + String strippedframe = ""; + int len = frame.length() / 2; // include all fields + + // int lengthField = Integer.decode(frame.substring(0, 2)); + int ciField = parseInt(frame, 22, 24); + boolean formatB = ciField == 0x72 || ciField == 0x7A; + + if (formatB) { + strippedframe += frame.substring(0, Math.min(18, frame.length() - 4)); + // block 1 + block 2 = 11 + ((16*n)+2) -- max 129 bytes + if (len <= 129) { + strippedframe += frame.substring(Math.min(22, frame.length()), frame.length() - 4); + } + // block 1 + block 2 + block 3= 11 + ((16*n)+2) + (16*n) -- bytes > 129 + else { + strippedframe += frame.substring(22, 256); + strippedframe += frame.substring(Math.min(260, frame.length()), frame.length() - 4); + } + } else { + // assume that we starts counting from C-field + strippedframe += frame.substring(0, Math.min(18, frame.length())); + int position = 22; + while (position < frame.length()) { + strippedframe += frame.substring(position, Math.min(position + 32, frame.length())); + position += 36; + } + strippedframe = strippedframe.substring(0, strippedframe.length() - 4); + } + + return strippedframe; } - return strippedframe; - } - - private int parseInt(String frame, int startIndex, int endIndex) { - return Integer.parseInt(frame.substring(startIndex, endIndex), 16); - } - + private int parseInt(String frame, int startIndex, int endIndex) { + return Integer.parseInt(frame.substring(startIndex, endIndex), 16); + } } diff --git a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/SkipProcessor.java b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/SkipProcessor.java index a9a6836..b37c030 100644 --- a/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/SkipProcessor.java +++ b/org.openhab.binding.wmbus.tools/src/main/java/org/openhab/binding/wmbus/tools/processor/SkipProcessor.java @@ -8,21 +8,21 @@ */ package org.openhab.binding.wmbus.tools.processor; -import org.openhab.binding.wmbus.tools.Processor; - import java.util.Map; +import org.openhab.binding.wmbus.tools.Processor; + public class SkipProcessor implements Processor { - private final int amount; + private final int amount; - public SkipProcessor(int amount) { - this.amount = amount; - } + public SkipProcessor(int amount) { + this.amount = amount; + } - @Override - public String process(String frame, Map context) { - // one byte is 2 characters in hex representation - return frame.substring(amount * 2); - } + @Override + public String process(String frame, Map context) { + // one byte is 2 characters in hex representation + return frame.substring(amount * 2); + } } diff --git a/org.openhab.binding.wmbus.tools/src/test/java/org/openhab/binding/wmbus/tools/processor/RecalculateLengthTest.java b/org.openhab.binding.wmbus.tools/src/test/java/org/openhab/binding/wmbus/tools/processor/RecalculateLengthTest.java index 8f613c2..947e619 100644 --- a/org.openhab.binding.wmbus.tools/src/test/java/org/openhab/binding/wmbus/tools/processor/RecalculateLengthTest.java +++ b/org.openhab.binding.wmbus.tools/src/test/java/org/openhab/binding/wmbus/tools/processor/RecalculateLengthTest.java @@ -1,59 +1,54 @@ package org.openhab.binding.wmbus.tools.processor; -import org.eclipse.smarthome.core.util.HexUtils; -import org.junit.Test; -import org.openmuc.jmbus.DecodingException; -import org.openmuc.jmbus.wireless.VirtualWMBusMessageHelper; -import org.openmuc.jmbus.wireless.WMBusMessage; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - +import org.junit.Test; +import org.openhab.core.util.HexUtils; +import org.openmuc.jmbus.DecodingException; +import org.openmuc.jmbus.wireless.VirtualWMBusMessageHelper; +import org.openmuc.jmbus.wireless.WMBusMessage; public class RecalculateLengthTest { RecalculateLength recalculateLength = new RecalculateLength(); Map context = new HashMap<>(); - @Test + @Test public void testValidFrame() throws DecodingException { String frame = "2e44972682213893071A7AB80020A56BE69947E41B7346595CCA02F2BF0E62C906B80BD18240811FD4879DA1296D3F"; String expectedFrame = "2e44972682213893071A7AB80020A56BE69947E41B7346595CCA02F2BF0E62C906B80BD18240811FD4879DA1296D3F"; - assertThat(recalculateLength.process(frame, context)) - .isEqualTo(expectedFrame); + assertThat(recalculateLength.process(frame, context)).isEqualTo(expectedFrame); byte[] payload = HexUtils.hexToBytes(expectedFrame); WMBusMessage message = VirtualWMBusMessageHelper.decode(payload, 100, Collections.emptyMap()); - assertThatThrownBy(() -> message.getVariableDataResponse().decode()) - .isInstanceOf(DecodingException.class).hasMessageContaining("address key"); + assertThatThrownBy(() -> message.getVariableDataResponse().decode()).isInstanceOf(DecodingException.class) + .hasMessageContaining("address key"); } @Test public void testShortHeader() throws DecodingException { String frame = "3244972682213893071A7AB80040A56BE69947E41B7346595CCA02F2BF0E62C906B80BD18240811FD4879DA1296D3F4279385A"; String expectedFrame = "2e44972682213893071A7AB80020A56BE69947E41B7346595CCA02F2BF0E62C906B80BD18240811FD4879DA1296D3F"; - assertThat(recalculateLength.process(frame, context)) - .isEqualTo(expectedFrame); + assertThat(recalculateLength.process(frame, context)).isEqualTo(expectedFrame); byte[] payload = HexUtils.hexToBytes(expectedFrame); WMBusMessage message = VirtualWMBusMessageHelper.decode(payload, 100, Collections.emptyMap()); - assertThatThrownBy(() -> message.getVariableDataResponse().decode()) - .isInstanceOf(DecodingException.class).hasMessageContaining("address key"); + assertThatThrownBy(() -> message.getVariableDataResponse().decode()).isInstanceOf(DecodingException.class) + .hasMessageContaining("address key"); } @Test public void testLongHeader() throws DecodingException { String frame = "3244C5140401806003077261885616C51400075B0B90054CC7D04A56C6919495f6565704D1D9085134926D705D40D2EE699337"; String expectedFrame = "2644C5140401806003077261885616C51400075B0B10054CC7D04A56C6919495f6565704D1D908"; - assertThat(recalculateLength.process(frame, context)) - .isEqualTo(expectedFrame); + assertThat(recalculateLength.process(frame, context)).isEqualTo(expectedFrame); byte[] payload = HexUtils.hexToBytes(expectedFrame); WMBusMessage message = VirtualWMBusMessageHelper.decode(payload, 100, Collections.emptyMap()); System.out.println(message.getVariableDataResponse().getNumberOfEncryptedBlocks()); - assertThatThrownBy(() -> message.getVariableDataResponse().decode()) - .isInstanceOf(DecodingException.class).hasMessageContaining("secondary address"); + assertThatThrownBy(() -> message.getVariableDataResponse().decode()).isInstanceOf(DecodingException.class) + .hasMessageContaining("secondary address"); } - -} \ No newline at end of file +} diff --git a/org.openhab.binding.wmbus.tools/src/test/java/org/openhab/binding/wmbus/tools/processor/SkipCrcProcessorTest.java b/org.openhab.binding.wmbus.tools/src/test/java/org/openhab/binding/wmbus/tools/processor/SkipCrcProcessorTest.java index ef26bdd..811441c 100644 --- a/org.openhab.binding.wmbus.tools/src/test/java/org/openhab/binding/wmbus/tools/processor/SkipCrcProcessorTest.java +++ b/org.openhab.binding.wmbus.tools/src/test/java/org/openhab/binding/wmbus/tools/processor/SkipCrcProcessorTest.java @@ -2,39 +2,40 @@ import java.util.HashMap; import java.util.Map; -import junit.framework.TestCase; + import org.junit.Test; -public class SkipCrcProcessorTest extends TestCase { +import junit.framework.TestCase; - SkipCrcProcessor stripCrc = new SkipCrcProcessor(); - Map context = new HashMap<>(); +public class SkipCrcProcessorTest extends TestCase { - @Test - public void testFrameFormatB() { - String input = "11111111111111111100007A1111111111111111111111111111110000"; - String output = "1111111111111111117A111111111111111111111111111111"; - String result = stripCrc.process(input, context); + SkipCrcProcessor stripCrc = new SkipCrcProcessor(); + Map context = new HashMap<>(); - assertEquals(output, result); - } + @Test + public void testFrameFormatB() { + String input = "11111111111111111100007A1111111111111111111111111111110000"; + String output = "1111111111111111117A111111111111111111111111111111"; + String result = stripCrc.process(input, context); - @Test - public void testFrame1() { - String input = "111111111111111111000011111111111111111111111111110000"; - String output = "1111111111111111111111111111111111111111111111"; - String result = stripCrc.process(input, context); + assertEquals(output, result); + } - assertEquals(output, result); - } + @Test + public void testFrame1() { + String input = "111111111111111111000011111111111111111111111111110000"; + String output = "1111111111111111111111111111111111111111111111"; + String result = stripCrc.process(input, context); - @Test - public void testFrame3() { - String input = "11111111111111111100001111111111111111111111111111111100001111111111110000"; - String output = "11111111111111111111111111111111111111111111111111111111111111"; - String result = stripCrc.process(input, context); + assertEquals(output, result); + } - assertEquals(output, result); - } + @Test + public void testFrame3() { + String input = "11111111111111111100001111111111111111111111111111111100001111111111110000"; + String output = "11111111111111111111111111111111111111111111111111111111111111"; + String result = stripCrc.process(input, context); -} \ No newline at end of file + assertEquals(output, result); + } +} diff --git a/org.openhab.binding.wmbus/lib/jmbus-3.1.1.sp2.jar b/org.openhab.binding.wmbus/lib/jmbus-3.1.1.sp2.jar deleted file mode 100644 index a53dcf1..0000000 Binary files a/org.openhab.binding.wmbus/lib/jmbus-3.1.1.sp2.jar and /dev/null differ diff --git a/org.openhab.binding.wmbus/pom.xml b/org.openhab.binding.wmbus/pom.xml index acb5938..5c2ef4e 100644 --- a/org.openhab.binding.wmbus/pom.xml +++ b/org.openhab.binding.wmbus/pom.xml @@ -1,129 +1,53 @@ - - 4.0.0 - - - org.openhab.binding - wmbus - 2.5.0-SNAPSHOT - - - org.openhab.binding - org.openhab.binding.wmbus - - WMBus Binding - - - false - org.openmuc.jmbus.* - - - - - com.google.guava - guava - 20.0 - provided - - - - - com.neuronrobotics - nrjavaserial - 3.13.0 - - - - - - - - org.openmuc - jrxtx - 1.0.1 - - - - org.openmuc - jmbus - 3.1.1.sp2 - system - ${basedir}/lib/jmbus-3.1.1.sp2.jar - - - - junit - junit - 4.12 - test - - - org.assertj - assertj-core - 3.11.1 - test - - - org.slf4j - slf4j-simple - 1.7.2 - test - - - org.mockito - mockito-core - 2.23.0 - test - - - - org.openhab.core.bom - org.openhab.core.bom.compile - pom - provided - - - org.openhab.core.bom - org.openhab.core.bom.openhab-core - pom - provided - - - org.openhab.core.bom - org.openhab.core.bom.test - pom - test - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 3.0.0-M1 - - - test - test - - - **/*Test.java - - - - test - - - - - - + + + 4.0.0 + + + org.openhab.addons.bundles + wmbus + 3.1.0-SNAPSHOT + + + org.openhab.addons.bundles + org.openhab.binding.wmbus + + WMBus Binding + + false + org.openhab.core.io.transport.serial + + + + junit + junit + 4.12 + test + + + org.assertj + assertj-core + 3.11.1 + test + + + org.slf4j + slf4j-simple + 1.7.2 + test + + + org.mockito + mockito-core + 2.23.0 + test + + + com.google.guava + guava + 20.0 + provided + + diff --git a/org.openhab.binding.wmbus/src/main/feature/feature.xml b/org.openhab.binding.wmbus/src/main/feature/feature.xml new file mode 100644 index 0000000..8aa0a06 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.wmbus/${project.version} + + diff --git a/org.openhab.binding.wmbus/src/main/history/dependencies.xml b/org.openhab.binding.wmbus/src/main/history/dependencies.xml new file mode 100644 index 0000000..014e781 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/history/dependencies.xml @@ -0,0 +1,9 @@ + + + + openhab-runtime-base + wrap + mvn:org.openhab.addons.bundles/org.openhab.binding.wmbus/3.1.0-SNAPSHOT + wrap:mvn:org.lastnpe.eea/eea-all/2.2.1 + + diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/BindingConfiguration.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/BindingConfiguration.java index b4c23bc..3b07cba 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/BindingConfiguration.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/BindingConfiguration.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus; @@ -18,5 +22,4 @@ public interface BindingConfiguration { Long getTimeToLive(); Boolean getIncludeBridgeUID(); - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/RecordType.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/RecordType.java index 6ee3fb6..be8055f 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/RecordType.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/RecordType.java @@ -1,17 +1,21 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus; import java.util.Arrays; -import org.eclipse.smarthome.core.util.HexUtils; +import org.openhab.core.util.HexUtils; import org.openmuc.jmbus.DataRecord; /** @@ -29,7 +33,8 @@ public class RecordType { * Below combination of dib/vib is intentionally invalid. It is a mark for manufacturer specific data which can be * appended as part of standard payload in the frame. */ - public final static RecordType MANUFACTURER_DATA = new RecordType(new byte[] {0x0, 0x0, 0x0, 0x0}, new byte[] {0x0, 0x0, 0x0, 0x0}); + public final static RecordType MANUFACTURER_DATA = new RecordType(new byte[] { 0x0, 0x0, 0x0, 0x0 }, + new byte[] { 0x0, 0x0, 0x0, 0x0 }); private final byte[] dib; private final byte[] vib; @@ -97,5 +102,4 @@ public boolean equals(Object obj) { } return true; } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/UnitRegistry.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/UnitRegistry.java index 65c7689..bd43f1f 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/UnitRegistry.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/UnitRegistry.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus; @@ -40,5 +44,4 @@ public interface UnitRegistry { * @return Optional containing quantity type according to unit mapping. */ Optional>> quantity(@Nullable DlmsUnit wmbusType); - } 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 c487889..808967b 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 @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus; @@ -12,8 +16,8 @@ import java.util.concurrent.TimeUnit; import java.util.function.Function; -import org.eclipse.smarthome.core.thing.ThingTypeUID; -import org.eclipse.smarthome.core.thing.type.ChannelTypeUID; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.type.ChannelTypeUID; import org.openmuc.jmbus.DeviceType; import com.google.common.collect.ImmutableSet; @@ -42,7 +46,7 @@ public class WMBusBindingConstants { // List all Thing Type UIDs, related to the WMBus Binding public final static ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, THING_TYPE_NAME_BRIDGE); public final static ThingTypeUID THING_TYPE_VIRTUAL_BRIDGE = new ThingTypeUID(BINDING_ID, - THING_TYPE_NAME_VIRTUAL_BRIDGE); + THING_TYPE_NAME_VIRTUAL_BRIDGE); public final static ThingTypeUID THING_TYPE_METER = new ThingTypeUID(BINDING_ID, THING_TYPE_NAME_METER); public final static ThingTypeUID THING_TYPE_ENCRYPTED_METER = new ThingTypeUID(BINDING_ID, @@ -121,5 +125,4 @@ public class WMBusBindingConstants { public static final String CONFKEY_BINDING_TIME_TO_LIVE = "timeToLive"; public static final String CONFKEY_BINDING_INCLUDE_BRIDGE_UID = "includeBridgeUID"; - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/WMBusCompanyIdentifiers.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/WMBusCompanyIdentifiers.java index 37568fc..9bbb7ec 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/WMBusCompanyIdentifiers.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/WMBusCompanyIdentifiers.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus; @@ -48,5 +52,4 @@ public class WMBusCompanyIdentifiers { return null; } } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/WMBusDevice.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/WMBusDevice.java index 4eed9d4..bddaddd 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/WMBusDevice.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/WMBusDevice.java @@ -1,16 +1,20 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.handler.WMBusAdapter; +import org.openhab.core.util.HexUtils; import org.openmuc.jmbus.DataRecord; import org.openmuc.jmbus.DecodingException; import org.openmuc.jmbus.EncryptionMode; @@ -112,4 +116,4 @@ public byte[] getDataValue() { public byte[] getRawData() { return rawData; } -} \ No newline at end of file +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/DateFieldMode.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/DateFieldMode.java index 0ebbda8..42000dc 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/DateFieldMode.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/DateFieldMode.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2019 by the respective copyright holders. - *

- * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.config; 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 84eabd8..645ec54 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 @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2019 by the respective copyright holders. - *

- * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.config; diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/WMBusBridgeConfig.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/WMBusBridgeConfig.java index 16c2881..91e4778 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/WMBusBridgeConfig.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/WMBusBridgeConfig.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2019 by the respective copyright holders. - *

- * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.config; @@ -28,5 +32,4 @@ public int[] getDeviceIDFilter() { } return idInts; } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/WMBusSerialBridgeConfig.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/WMBusSerialBridgeConfig.java index 8902261..80ef68b 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/WMBusSerialBridgeConfig.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/config/WMBusSerialBridgeConfig.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2019 by the respective copyright holders. - *

- * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.config; @@ -20,5 +24,4 @@ public class WMBusSerialBridgeConfig extends WMBusBridgeConfig { public StickModel stickModel; public String serialDevice; public WMBusMode radioMode; - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/AbstractWMBusDiscoveryParticipant.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/AbstractWMBusDiscoveryParticipant.java index 2ccd103..d472971 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/AbstractWMBusDiscoveryParticipant.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/AbstractWMBusDiscoveryParticipant.java @@ -1,19 +1,23 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device; import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.smarthome.core.thing.ThingTypeUID; -import org.eclipse.smarthome.core.thing.ThingUID; import org.openhab.binding.wmbus.BindingConfiguration; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.discovery.WMBusDiscoveryParticipant; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingUID; /** * Base class for discovery participants. diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/Meter.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/Meter.java index 12e96b6..dacd573 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/Meter.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/Meter.java @@ -1,17 +1,21 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device; import java.util.Set; -import org.eclipse.smarthome.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingTypeUID; /** * The {@link Meter} class defines common Meter device diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/UnknownMeter.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/UnknownMeter.java index 3f8612b..515f003 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/UnknownMeter.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/UnknownMeter.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device; @@ -12,13 +16,13 @@ import java.util.Map; import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.smarthome.core.thing.ChannelUID; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.types.Command; -import org.eclipse.smarthome.core.types.RefreshType; -import org.eclipse.smarthome.core.types.State; -import org.eclipse.smarthome.core.types.UnDefType; import org.openhab.binding.wmbus.handler.WMBusDeviceHandler; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; import org.openhab.io.transport.mbus.wireless.KeyStorage; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -69,6 +73,5 @@ public void handleCommand(@NonNull ChannelUID channelUID, @NonNull Command comma } } - } } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/generic/DynamicWMBusThingHandler.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/generic/DynamicWMBusThingHandler.java index 77f0884..54bb964 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/generic/DynamicWMBusThingHandler.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/generic/DynamicWMBusThingHandler.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.generic; @@ -14,25 +18,25 @@ import java.util.Optional; import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.smarthome.core.library.types.QuantityType; -import org.eclipse.smarthome.core.thing.Channel; -import org.eclipse.smarthome.core.thing.ChannelUID; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.thing.binding.builder.ChannelBuilder; -import org.eclipse.smarthome.core.thing.binding.builder.ThingBuilder; -import org.eclipse.smarthome.core.thing.type.ChannelType; -import org.eclipse.smarthome.core.thing.type.ChannelTypeUID; -import org.eclipse.smarthome.core.thing.util.ThingHelper; -import org.eclipse.smarthome.core.types.Command; -import org.eclipse.smarthome.core.types.RefreshType; -import org.eclipse.smarthome.core.types.State; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.RecordType; import org.openhab.binding.wmbus.UnitRegistry; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.handler.WMBusAdapter; import org.openhab.binding.wmbus.handler.WMBusDeviceHandler; import org.openhab.binding.wmbus.internal.WMBusChannelTypeProvider; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.binding.builder.ChannelBuilder; +import org.openhab.core.thing.binding.builder.ThingBuilder; +import org.openhab.core.thing.type.ChannelType; +import org.openhab.core.thing.type.ChannelTypeUID; +import org.openhab.core.thing.util.ThingHelper; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.State; +import org.openhab.core.util.HexUtils; import org.openhab.io.transport.mbus.wireless.KeyStorage; import org.openmuc.jmbus.DataRecord; import org.openmuc.jmbus.VariableDataStructure; @@ -143,5 +147,4 @@ public void handleCommand(@NonNull ChannelUID channelUID, @NonNull Command comma } } } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/generic/GenericWMBusThingHandler.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/generic/GenericWMBusThingHandler.java index 2b049f1..b9852ac 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/generic/GenericWMBusThingHandler.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/generic/GenericWMBusThingHandler.java @@ -1,26 +1,30 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.generic; import java.util.Map; import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.smarthome.core.library.types.QuantityType; -import org.eclipse.smarthome.core.thing.ChannelUID; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.types.Command; -import org.eclipse.smarthome.core.types.RefreshType; -import org.eclipse.smarthome.core.types.State; import org.openhab.binding.wmbus.RecordType; import org.openhab.binding.wmbus.UnitRegistry; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.handler.WMBusDeviceHandler; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.State; import org.openhab.io.transport.mbus.wireless.KeyStorage; import org.openmuc.jmbus.DataRecord; import org.slf4j.Logger; @@ -70,5 +74,4 @@ public void handleCommand(@NonNull ChannelUID channelUID, @NonNull Command comma } } } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronBindingConstants.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronBindingConstants.java index 125fc6b..b18fa21 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronBindingConstants.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronBindingConstants.java @@ -1,15 +1,30 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ package org.openhab.binding.wmbus.device.itron; import java.util.Set; -import org.eclipse.smarthome.core.thing.ThingTypeUID; + import org.openhab.binding.wmbus.WMBusBindingConstants; +import org.openhab.core.thing.ThingTypeUID; + import com.google.common.collect.ImmutableSet; public interface ItronBindingConstants { String ITRON_SMOKE_DETECTOR = "itron_smoke_detector"; - ThingTypeUID THING_TYPE_ITRON_SMOKE_DETECTOR = new ThingTypeUID(WMBusBindingConstants.BINDING_ID, ITRON_SMOKE_DETECTOR); + ThingTypeUID THING_TYPE_ITRON_SMOKE_DETECTOR = new ThingTypeUID(WMBusBindingConstants.BINDING_ID, + ITRON_SMOKE_DETECTOR); Set SUPPORTED_THING_TYPES = ImmutableSet.of(THING_TYPE_ITRON_SMOKE_DETECTOR); @@ -28,9 +43,9 @@ public interface ItronBindingConstants { String CHANNEL_STATUS_OUT_OF_TEMP_RANGE_OCCURRED = "status_out_of_temp_range_occurred"; String CHANNEL_STATUS_PRODUCT_CODE = "status_product_code"; String CHANNEL_STATUS_BATTERY_LIFETIME = "status_battery_lifetime"; - //String CHANNEL_STATUS_PERIMETER_INTRUSION = "status_perimeter_intrusion"; - //String CHANNEL_STATUS_REMOVAL_ERROR = "status_removal_error"; - //String CHANNEL_STATUS_DATA_ENCRYPTED = "status_data_encrypted"; + // String CHANNEL_STATUS_PERIMETER_INTRUSION = "status_perimeter_intrusion"; + // String CHANNEL_STATUS_REMOVAL_ERROR = "status_removal_error"; + // String CHANNEL_STATUS_DATA_ENCRYPTED = "status_data_encrypted"; String CHANNEL_LAST_SMOKE_ALERT_START_DATE = "last_smoke_alert_start_date"; String CHANNEL_LAST_SMOKE_ALERT_START_DATE_STRING = "last_smoke_alert_start_date_string"; @@ -67,6 +82,4 @@ public interface ItronBindingConstants { String CHANNEL_NUMBER_OF_TEST_SWITCHES_OPERATED = "number_of_test_switches_operated"; String CHANNEL_PERIMETER_INTRUSION_DAY_COUNTER_CUMULATED = "perimeter_intrusion_day_counter_cumulated"; String CHANNEL_SMOKE_INLET_DAY_COUNTER_CUMULATED = "smoke_inlet_day_counter_cumulated"; - } - diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronConfigStatusDataParser.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronConfigStatusDataParser.java index c859834..208e55b 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronConfigStatusDataParser.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronConfigStatusDataParser.java @@ -1,6 +1,19 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ package org.openhab.binding.wmbus.device.itron; import java.util.BitSet; + import org.openhab.binding.wmbus.device.techem.decoder.Buffer; public class ItronConfigStatusDataParser { @@ -19,7 +32,7 @@ public class ItronConfigStatusDataParser { ItronConfigStatusDataParser(Buffer buffer) { this.billing = buffer.readByte(); - this.status = BitSet.valueOf(new byte[] {buffer.readByte()}); + this.status = BitSet.valueOf(new byte[] { buffer.readByte() }); this.product = buffer.readByte(); this.battery = buffer.readByte(); this.sdErrors = buffer.readBytes(2); @@ -63,5 +76,4 @@ public byte getProductCode() { public int getBatteryLifetime() { return (battery & 0xFF) >> 1; } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronDiscoveryParticipant.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronDiscoveryParticipant.java index a8cac6d..2cd46e9 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronDiscoveryParticipant.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronDiscoveryParticipant.java @@ -1,27 +1,31 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.itron; import java.util.HashMap; import java.util.Map; import java.util.Set; + import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.smarthome.config.discovery.DiscoveryResult; -import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.thing.ThingTypeUID; -import org.eclipse.smarthome.core.thing.ThingUID; import org.openhab.binding.wmbus.BindingConfiguration; import org.openhab.binding.wmbus.WMBusBindingConstants; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.discovery.WMBusDiscoveryParticipant; +import org.openhab.core.config.discovery.DiscoveryResult; +import org.openhab.core.config.discovery.DiscoveryResultBuilder; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingUID; import org.openmuc.jmbus.DeviceType; import org.openmuc.jmbus.SecondaryAddress; import org.openmuc.jmbus.wireless.WMBusMessage; @@ -48,7 +52,7 @@ public class ItronDiscoveryParticipant implements WMBusDiscoveryParticipant { } @Override - public @Nullable ThingUID getThingUID(WMBusDevice device) { + public @NonNull ThingUID getThingUID(WMBusDevice device) { ThingTypeUID type = ItronBindingConstants.THING_TYPE_ITRON_SMOKE_DETECTOR; if (configuration.getIncludeBridgeUID()) { return new ThingUID(type, device.getAdapter().getUID(), device.getDeviceId()); @@ -68,12 +72,14 @@ public DiscoveryResult createResult(WMBusDevice device) { SecondaryAddress secondaryAddress = device.getOriginalMessage().getSecondaryAddress(); properties.put(Thing.PROPERTY_MODEL_ID, secondaryAddress.getVersion()); properties.put(WMBusBindingConstants.PROPERTY_DEVICE_ENCRYPTED, device.isEnrypted()); - + @NonNull ThingUID thingUID = getThingUID(device); - return DiscoveryResultBuilder.create(thingUID).withProperties(properties) - .withRepresentationProperty(WMBusBindingConstants.PROPERTY_DEVICE_ADDRESS).withLabel(label) - .withThingType(ItronBindingConstants.THING_TYPE_ITRON_SMOKE_DETECTOR) - .withBridge(device.getAdapter().getUID()).withLabel(label).withTTL(getTimeToLive()).build(); + if (thingUID != null) + return DiscoveryResultBuilder.create(thingUID).withProperties(properties) + .withRepresentationProperty(WMBusBindingConstants.PROPERTY_DEVICE_ADDRESS).withLabel(label) + .withThingType(ItronBindingConstants.THING_TYPE_ITRON_SMOKE_DETECTOR) + .withBridge(device.getAdapter().getUID()).withLabel(label).withTTL(getTimeToLive()).build(); + } return null; @@ -82,8 +88,8 @@ public DiscoveryResult createResult(WMBusDevice device) { private boolean isItronSmokeDetector(WMBusDevice device) { WMBusMessage message = device.getOriginalMessage(); - if (!ItronBindingConstants.ITRON_MANUFACTURER_ID.equals(message.getSecondaryAddress().getManufacturerId()) || - message.getSecondaryAddress().getDeviceType() != DeviceType.SMOKE_DETECTOR) { + if (!ItronBindingConstants.ITRON_MANUFACTURER_ID.equals(message.getSecondaryAddress().getManufacturerId()) + || message.getSecondaryAddress().getDeviceType() != DeviceType.SMOKE_DETECTOR) { return false; } @@ -102,5 +108,4 @@ public void unsetBindingConfiguration(BindingConfiguration configuration) { private Long getTimeToLive() { return configuration.getTimeToLive(); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronHandlerFactory.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronHandlerFactory.java index 0b4d0b9..ab74b7d 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronHandlerFactory.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronHandlerFactory.java @@ -1,30 +1,27 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.itron; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.thing.ThingTypeUID; -import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory; -import org.eclipse.smarthome.core.thing.binding.ThingHandler; -import org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory; import org.openhab.binding.wmbus.UnitRegistry; -import org.openhab.binding.wmbus.device.techem.TechemDevice; -import org.openhab.binding.wmbus.device.techem.TechemHeatMeter; -import org.openhab.binding.wmbus.device.techem.decoder.TechemFrameDecoder; -import org.openhab.binding.wmbus.device.techem.handler.TechemMeterHandler; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; import org.openhab.io.transport.mbus.wireless.FilteredKeyStorage; import org.openhab.io.transport.mbus.wireless.KeyStorage; -import org.osgi.service.component.ComponentContext; -import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Reference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -77,5 +74,4 @@ protected void setUnitRegistry(UnitRegistry unitRegistry) { protected void unsetUnitRegistry(UnitRegistry unitRegistry) { this.unitRegistry = null; } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronManufacturerDataParser.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronManufacturerDataParser.java index 04a5b2f..ce2b3cc 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronManufacturerDataParser.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronManufacturerDataParser.java @@ -1,3 +1,15 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ package org.openhab.binding.wmbus.device.itron; import java.time.DayOfWeek; @@ -5,12 +17,13 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.util.Arrays; + import org.openhab.binding.wmbus.device.techem.decoder.Buffer; public class ItronManufacturerDataParser { - private final static byte[] EMPTY_SHORT_DATE_1 = new byte[] {0x0, 0x0, 0x1, 0x1}; - private final static byte[] EMPTY_SHORT_DATE_2 = new byte[] {0x0, 0x0, 0x0, 0x0}; + private final static byte[] EMPTY_SHORT_DATE_1 = new byte[] { 0x0, 0x0, 0x1, 0x1 }; + private final static byte[] EMPTY_SHORT_DATE_2 = new byte[] { 0x0, 0x0, 0x0, 0x0 }; private final Buffer buffer; ItronManufacturerDataParser(Buffer buffer) { diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronSmokeDetectorHandler.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronSmokeDetectorHandler.java index 50bf91e..97ab158 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronSmokeDetectorHandler.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/itron/ItronSmokeDetectorHandler.java @@ -1,27 +1,41 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ package org.openhab.binding.wmbus.device.itron; import java.time.LocalDateTime; import java.util.Collections; import java.util.HashMap; import java.util.Map; + import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.smarthome.core.library.types.DecimalType; -import org.eclipse.smarthome.core.library.types.OnOffType; -import org.eclipse.smarthome.core.thing.ChannelUID; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.types.Command; -import org.eclipse.smarthome.core.types.UnDefType; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.RecordType; import org.openhab.binding.wmbus.UnitRegistry; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.device.generic.GenericWMBusThingHandler; import org.openhab.binding.wmbus.device.techem.decoder.Buffer; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; +import org.openhab.core.types.UnDefType; +import org.openhab.core.util.HexUtils; import org.openhab.io.transport.mbus.wireless.KeyStorage; import org.openmuc.jmbus.DataRecord; import org.openmuc.jmbus.DecodingException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import com.google.common.primitives.Longs; public class ItronSmokeDetectorHandler extends GenericWMBusThingHandler { @@ -41,7 +55,8 @@ protected WMBusDevice parseDevice(WMBusDevice device) throws DecodingException { WMBusDevice parsedDevice = super.parseDevice(device); DataRecord record = device.findRecord(CONFIG_STATUS_07_7F); - if (record != null && record.getDataValueType() == DataRecord.DataValueType.LONG && record.getDescription() == DataRecord.Description.MANUFACTURER_SPECIFIC) { + if (record != null && record.getDataValueType() == DataRecord.DataValueType.LONG + && record.getDescription() == DataRecord.Description.MANUFACTURER_SPECIFIC) { Long dataValue = (Long) record.getDataValue(); ItronConfigStatusDataParser configStatus = new ItronConfigStatusDataParser(Longs.toByteArray(dataValue)); @@ -52,26 +67,29 @@ protected WMBusDevice parseDevice(WMBusDevice device) throws DecodingException { parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_REMOVAL_OCCURRED, configStatus.isRemovalOccurred()); parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_PRODUCT_INSTALLED, configStatus.isProductInstalled()); parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_OPERATION_MODE, configStatus.getOperationMode()); - parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_PERIMETER_INTRUSION_OCCURRED, configStatus.isPerimeterIntrusionOccurred()); - parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_SMOKE_INLET_BLOCKED_OCCURRED, configStatus.isSmokeInletBlockedOccurred()); - parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_OUT_OF_TEMP_RANGE_OCCURRED, configStatus.isOutOfRangeTemperatureOccurred()); + parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_PERIMETER_INTRUSION_OCCURRED, + configStatus.isPerimeterIntrusionOccurred()); + parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_SMOKE_INLET_BLOCKED_OCCURRED, + configStatus.isSmokeInletBlockedOccurred()); + parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_OUT_OF_TEMP_RANGE_OCCURRED, + configStatus.isOutOfRangeTemperatureOccurred()); // third byte with error codes - parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_PRODUCT_CODE, HexUtils.byteToHex(configStatus.getProductCode())); + parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_PRODUCT_CODE, + HexUtils.byteToHex(configStatus.getProductCode())); // fourth byte with battery lifetime parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_BATTERY_LIFETIME, configStatus.getBatteryLifetime()); } // fifth and sixth byte SD errors - //parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_PERIMETER_INTRUSION, configStatus.readBytes(2)); + // parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_PERIMETER_INTRUSION, configStatus.readBytes(2)); // 7tn byte is modem error codes - //parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_REMOVAL_ERROR, configStatus.readByte()); + // parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_REMOVAL_ERROR, configStatus.readByte()); // 8tn byte is config byte - //parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_DATA_ENCRYPTED, configStatus.readByte()); - + // parsedFrame.put(ItronBindingConstants.CHANNEL_STATUS_DATA_ENCRYPTED, configStatus.readByte()); byte[] manufacturerData = parsedDevice.getOriginalMessage().getVariableDataResponse().getManufacturerData(); @@ -95,8 +113,10 @@ protected WMBusDevice parseDevice(WMBusDevice device) throws DecodingException { eventDate = parser.readShortDateTime(); parsedFrame.put(ItronBindingConstants.CHANNEL_LAST_PERIMETER_INTRUSION_OBSTACLE_OCCURRED_DATE, eventDate); - parsedFrame.put(ItronBindingConstants.CHANNEL_LAST_PERIMETER_INTRUSION_OBSTACLE_OCCURRED_DATE_NUMBER, eventDate); - parsedFrame.put(ItronBindingConstants.CHANNEL_LAST_PERIMETER_INTRUSION_OBSTACLE_OCCURRED_DATE_STRING, eventDate); + parsedFrame.put(ItronBindingConstants.CHANNEL_LAST_PERIMETER_INTRUSION_OBSTACLE_OCCURRED_DATE_NUMBER, + eventDate); + parsedFrame.put(ItronBindingConstants.CHANNEL_LAST_PERIMETER_INTRUSION_OBSTACLE_OCCURRED_DATE_STRING, + eventDate); eventDate = parser.readShortDateTime(); parsedFrame.put(ItronBindingConstants.CHANNEL_LAST_PERIMETER_INTRUSION_OBSTACLE_REMOVED_DATE, eventDate); @@ -125,7 +145,8 @@ protected WMBusDevice parseDevice(WMBusDevice device) throws DecodingException { parsedFrame.put(ItronBindingConstants.CHANNEL_NUMBER_OF_TEST_SWITCHES_OPERATED, buffer.readShort()); parsedFrame.put(ItronBindingConstants.CHANNEL_PERIMETER_INTRUSION_DAY_COUNTER_CUMULATED, buffer.readShort()); - parsedFrame.put(ItronBindingConstants.CHANNEL_SMOKE_INLET_DAY_COUNTER_CUMULATED, buffer.available() < 2 ? buffer.readByte() : buffer.readShort()); + parsedFrame.put(ItronBindingConstants.CHANNEL_SMOKE_INLET_DAY_COUNTER_CUMULATED, + buffer.available() < 2 ? buffer.readByte() : buffer.readShort()); return parsedDevice; } @@ -153,7 +174,4 @@ public void handleCommand(@NonNull ChannelUID channelUID, @NonNull Command comma super.handleCommand(channelUID, command); } } - - - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/Record.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/Record.java index 6c0115a..01b9b20 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/Record.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/Record.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem; diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemBindingConstants.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemBindingConstants.java index 1ac961a..8d59818 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemBindingConstants.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemBindingConstants.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem; @@ -12,9 +16,9 @@ import java.util.Set; import java.util.stream.Collectors; -import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.openhab.binding.wmbus.WMBusBindingConstants; import org.openhab.binding.wmbus.device.techem.Record.Type; +import org.openhab.core.thing.ThingTypeUID; import org.openmuc.jmbus.DeviceType; import com.google.common.collect.ImmutableMap; diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemDevice.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemDevice.java index 281d5a3..6afb726 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemDevice.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemDevice.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem; @@ -16,7 +20,6 @@ import org.openhab.binding.wmbus.device.techem.Record.Type; import org.openhab.binding.wmbus.handler.WMBusAdapter; import org.openmuc.jmbus.DeviceType; -import org.openmuc.jmbus.SecondaryAddress; import org.openmuc.jmbus.wireless.WMBusMessage; /** @@ -56,5 +59,4 @@ public List> getMeasurements() { public Optional> getRecord(Type type) { return measurements.stream().filter(record -> record.getType().equals(type)).findFirst(); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemDiscoveryParticipant.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemDiscoveryParticipant.java index e7cc974..eecee90 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemDiscoveryParticipant.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemDiscoveryParticipant.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem; @@ -15,16 +19,16 @@ import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.smarthome.config.discovery.DiscoveryResult; -import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.thing.ThingTypeUID; -import org.eclipse.smarthome.core.thing.ThingUID; import org.openhab.binding.wmbus.BindingConfiguration; import org.openhab.binding.wmbus.WMBusBindingConstants; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.device.techem.decoder.TechemFrameDecoder; import org.openhab.binding.wmbus.discovery.WMBusDiscoveryParticipant; +import org.openhab.core.config.discovery.DiscoveryResult; +import org.openhab.core.config.discovery.DiscoveryResultBuilder; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingUID; import org.openmuc.jmbus.SecondaryAddress; import org.openmuc.jmbus.wireless.WMBusMessage; import org.osgi.service.component.annotations.Component; @@ -145,5 +149,4 @@ public void unsetBindingConfiguration(BindingConfiguration configuration) { private Long getTimeToLive() { return configuration.getTimeToLive(); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemHandlerFactory.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemHandlerFactory.java index b5e4246..a1e71e3 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemHandlerFactory.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemHandlerFactory.java @@ -1,21 +1,25 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.thing.ThingTypeUID; -import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory; -import org.eclipse.smarthome.core.thing.binding.ThingHandler; -import org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory; import org.openhab.binding.wmbus.device.techem.decoder.TechemFrameDecoder; import org.openhab.binding.wmbus.device.techem.handler.TechemMeterHandler; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -95,5 +99,4 @@ public void setTechemFrameDecoder(TechemFrameDecoder decoder) { public void unsetTechemFrameDecoder(TechemFrameDecoder decoder) { this.techemFrameDecoder = null; } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemHeatCostAllocator.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemHeatCostAllocator.java index 12ebbf9..c56938c 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemHeatCostAllocator.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemHeatCostAllocator.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem; @@ -21,8 +25,8 @@ */ public class TechemHeatCostAllocator extends TechemDevice { - public TechemHeatCostAllocator(WMBusMessage originalMessage, WMBusAdapter adapter, Variant variant, List> measures) { + public TechemHeatCostAllocator(WMBusMessage originalMessage, WMBusAdapter adapter, Variant variant, + List> measures) { super(originalMessage, adapter, variant, measures); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemHeatMeter.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemHeatMeter.java index 4e7b73c..e750d86 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemHeatMeter.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemHeatMeter.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem; @@ -12,7 +16,6 @@ import java.util.List; import org.openhab.binding.wmbus.handler.WMBusAdapter; -import org.openmuc.jmbus.DeviceType; import org.openmuc.jmbus.wireless.WMBusMessage; /** @@ -22,8 +25,8 @@ */ public class TechemHeatMeter extends TechemDevice { - public TechemHeatMeter(WMBusMessage originalMessage, WMBusAdapter adapter, Variant variant, List> measures) { + public TechemHeatMeter(WMBusMessage originalMessage, WMBusAdapter adapter, Variant variant, + List> measures) { super(originalMessage, adapter, variant, measures); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemSmokeDetector.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemSmokeDetector.java index ea23b0c..a291391 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemSmokeDetector.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemSmokeDetector.java @@ -1,15 +1,20 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem; import java.util.List; + import org.openhab.binding.wmbus.handler.WMBusAdapter; import org.openmuc.jmbus.wireless.WMBusMessage; @@ -20,8 +25,8 @@ */ public class TechemSmokeDetector extends TechemDevice { - public TechemSmokeDetector(WMBusMessage originalMessage, WMBusAdapter adapter, Variant variant, List> records) { + public TechemSmokeDetector(WMBusMessage originalMessage, WMBusAdapter adapter, Variant variant, + List> records) { super(originalMessage, adapter, variant, records); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemUnknownDevice.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemUnknownDevice.java index 6a997de..a174e91 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemUnknownDevice.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemUnknownDevice.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem; @@ -12,7 +16,6 @@ import java.util.ArrayList; import org.openhab.binding.wmbus.handler.WMBusAdapter; -import org.openmuc.jmbus.DeviceType; import org.openmuc.jmbus.wireless.WMBusMessage; /** @@ -25,5 +28,4 @@ public class TechemUnknownDevice extends TechemHeatCostAllocator { public TechemUnknownDevice(WMBusMessage originalMessage, WMBusAdapter adapter, Variant variant) { super(originalMessage, adapter, variant, new ArrayList<>()); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemWaterMeter.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemWaterMeter.java index e25ec3e..1fa63e8 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemWaterMeter.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/TechemWaterMeter.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem; @@ -22,8 +26,8 @@ public class TechemWaterMeter extends TechemDevice { - public TechemWaterMeter(WMBusMessage originalMessage, WMBusAdapter adapter, Variant variant, List> measures) { + public TechemWaterMeter(WMBusMessage originalMessage, WMBusAdapter adapter, Variant variant, + List> measures) { super(originalMessage, adapter, variant, measures); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/Variant.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/Variant.java index 9e3c1e5..23d1626 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/Variant.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/Variant.java @@ -1,6 +1,7 @@ package org.openhab.binding.wmbus.device.techem; import java.util.Objects; + import org.openmuc.jmbus.DeviceType; public class Variant { @@ -52,8 +53,8 @@ public boolean equals(Object o) { return false; } Variant variant = (Variant) o; - return version == variant.version && reportedType == variant.reportedType && coding == variant - .coding && desiredType == variant.desiredType && matchingType == variant.matchingType; + return version == variant.version && reportedType == variant.reportedType && coding == variant.coding + && desiredType == variant.desiredType && matchingType == variant.matchingType; } @Override @@ -65,4 +66,4 @@ public int hashCode() { public String toString() { return getRawType() + "->" + getTechemType(); } -} \ No newline at end of file +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/AbstractTechemFrameDecoder.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/AbstractTechemFrameDecoder.java index cd93030..d565e82 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/AbstractTechemFrameDecoder.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/AbstractTechemFrameDecoder.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem.decoder; @@ -12,10 +16,10 @@ import java.time.temporal.ChronoUnit; import java.util.function.Function; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.device.techem.TechemDevice; import org.openhab.binding.wmbus.device.techem.Variant; +import org.openhab.core.util.HexUtils; import org.openmuc.jmbus.SecondaryAddress; import org.openmuc.jmbus.wireless.WMBusMessage; import org.slf4j.Logger; @@ -110,5 +114,4 @@ public T decode(WMBusDevice device) { // FIXME make this method abstract protected abstract T decode(WMBusDevice device, SecondaryAddress address, byte[] buffer); - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/Buffer.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/Buffer.java index 8c058dc..a385198 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/Buffer.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/Buffer.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem.decoder; @@ -15,7 +19,7 @@ import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.function.Function; -import org.eclipse.smarthome.core.util.HexUtils; + import org.openmuc.jmbus.SecondaryAddress; import org.openmuc.jmbus.wireless.WMBusMessage; import org.slf4j.Logger; @@ -129,7 +133,7 @@ public String readHistory() { history.append((readByte() & 0xFF)).append(";"); } - return history.substring(0, history.length() -1); + return history.substring(0, history.length() - 1); } public float readFloat(Function scale) { @@ -161,5 +165,4 @@ private final T orderedRead(ByteOrder readOrder, Function cal return callback.apply(buffer); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/CompositeTechemFrameDecoder.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/CompositeTechemFrameDecoder.java index e973c9e..1b76176 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/CompositeTechemFrameDecoder.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/CompositeTechemFrameDecoder.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem.decoder; @@ -55,11 +59,12 @@ public TechemDevice decode(WMBusDevice device) { for (TechemFrameDecoder decoder : decoders) { if (decoder.supports(device.getRawDeviceType())) { // same variant might be supported by multiple decoders, but first one which gives decoded result wins - logger.debug("Found decoder capable of handling device {}: {}", device.getRawDeviceType(), decoder.getClass().getName()); + logger.debug("Found decoder capable of handling device {}: {}", device.getRawDeviceType(), + decoder.getClass().getName()); result = decoder.decode(device); if (result != null) { logger.debug("Decoding result: {}, {}, {}", result, result.getRawDeviceType(), - result.getTechemDeviceType()); + result.getTechemDeviceType()); break; } else { logger.debug("Decoding of frame failed, unsupported device variant"); @@ -74,5 +79,4 @@ public TechemDevice decode(WMBusDevice device) { return null; } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/DebugBuffer.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/DebugBuffer.java index 87a5bc0..5c09502 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/DebugBuffer.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/DebugBuffer.java @@ -1,15 +1,20 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem.decoder; import java.time.LocalDateTime; import java.util.function.Function; + import org.openmuc.jmbus.SecondaryAddress; import org.openmuc.jmbus.wireless.WMBusMessage; @@ -106,5 +111,4 @@ private final String dump() { return output + "\n" + lowerLine + "\n" + middleLine; } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemFrameDecoder.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemFrameDecoder.java index 3c2ae19..87bc574 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemFrameDecoder.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemFrameDecoder.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem.decoder; @@ -16,5 +20,4 @@ public interface TechemFrameDecoder { boolean supports(String deviceVariant); T decode(WMBusDevice device); - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemHKVFrameDecoder.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemHKVFrameDecoder.java index 4233dcb..2d54252 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemHKVFrameDecoder.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemHKVFrameDecoder.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem.decoder; @@ -52,10 +56,10 @@ protected TechemHeatCostAllocator decode(WMBusDevice device, SecondaryAddress ad } if (coding == 0xA3) { - return new TechemUnknownDevice(device.getOriginalMessage(), device.getAdapter(), new Variant(variant.version, variant.reportedType, coding, DeviceType.UNKNOWN)); + return new TechemUnknownDevice(device.getOriginalMessage(), device.getAdapter(), + new Variant(variant.version, variant.reportedType, coding, DeviceType.UNKNOWN)); } return null; } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemHKVRoomTempFrameDecoder.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemHKVRoomTempFrameDecoder.java index 85113e3..c460981 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemHKVRoomTempFrameDecoder.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemHKVRoomTempFrameDecoder.java @@ -1,21 +1,26 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem.decoder; import java.util.ArrayList; import java.util.List; -import org.eclipse.smarthome.core.library.unit.SIUnits; + import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.device.techem.Record; import org.openhab.binding.wmbus.device.techem.TechemHeatCostAllocator; import org.openhab.binding.wmbus.device.techem.TechemUnknownDevice; import org.openhab.binding.wmbus.device.techem.Variant; +import org.openhab.core.library.unit.SIUnits; import org.openmuc.jmbus.DeviceType; import org.openmuc.jmbus.SecondaryAddress; @@ -65,10 +70,10 @@ protected TechemHeatCostAllocator decode(WMBusDevice device, SecondaryAddress ad } if (coding == 0xA3) { - return new TechemUnknownDevice(device.getOriginalMessage(), device.getAdapter(), new Variant(variant.version, variant.reportedType, coding, DeviceType.UNKNOWN)); + return new TechemUnknownDevice(device.getOriginalMessage(), device.getAdapter(), + new Variant(variant.version, variant.reportedType, coding, DeviceType.UNKNOWN)); } return null; } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemHeatMeterFrameDecoder.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemHeatMeterFrameDecoder.java index 138e95e..b8e4cae 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemHeatMeterFrameDecoder.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/device/techem/decoder/TechemHeatMeterFrameDecoder.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.device.techem.decoder; @@ -24,7 +28,7 @@ class TechemHeatMeterFrameDecoder extends AbstractTechemFrameDecoder map(measurement, measurement.getValue())) .ifPresent(state -> updateState(channelUID.getId(), state)); - } else if (CoreItemFactory.STRING.equals(acceptedType) && DateFieldMode.FORMATTED_STRING == getDateFieldMode()) { + } else if (CoreItemFactory.STRING.equals(acceptedType) + && DateFieldMode.FORMATTED_STRING == getDateFieldMode()) { record.map(measurement -> map(measurement, measurement.getValue())) .ifPresent(state -> updateState(channelUID.getId(), state)); - } else if (CoreItemFactory.NUMBER.equals(acceptedType) && DateFieldMode.UNIX_TIMESTAMP == getDateFieldMode()) { + } else if (CoreItemFactory.NUMBER.equals(acceptedType) + && DateFieldMode.UNIX_TIMESTAMP == getDateFieldMode()) { record.map(measurement -> map(measurement, measurement.getValue())) .ifPresent(state -> updateState(channelUID.getId(), state)); } else { - logger.info("Ignoring update of channel {}, it is date field with no proper mapping available.", channelUID); + logger.info( + "Ignoring update of channel {}, it is date field with no proper mapping available.", + channelUID); } } else { record.map(measurement -> map(measurement, measurement.getValue())) @@ -144,5 +152,4 @@ protected T parseDevice(WMBusDevice device) throws DecodingException { private static Map fetchMapping(@NonNull ThingTypeUID thingTypeUID) { return TechemBindingConstants.RECORD_MAP.get(thingTypeUID); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/discovery/CompositeMessageListener.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/discovery/CompositeMessageListener.java index 64f9442..6b2fa16 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/discovery/CompositeMessageListener.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/discovery/CompositeMessageListener.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.discovery; @@ -53,5 +57,4 @@ public void addMessageListener(WMBusMessageListener listener) { public void removeMessageListener(WMBusMessageListener listener) { this.listeners.add(listener); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/discovery/DebugMessageListener.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/discovery/DebugMessageListener.java index 67044a7..9b6b0fe 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/discovery/DebugMessageListener.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/discovery/DebugMessageListener.java @@ -1,9 +1,21 @@ +/** + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ package org.openhab.binding.wmbus.discovery; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.handler.WMBusAdapter; import org.openhab.binding.wmbus.handler.WMBusMessageListener; +import org.openhab.core.util.HexUtils; import org.openmuc.jmbus.DataRecord; import org.openmuc.jmbus.DecodingException; import org.openmuc.jmbus.EncryptionMode; @@ -55,7 +67,5 @@ private void log(WMBusDevice device) { logger.debug("Could not decode frame ({})", secondaryAddress, e.getMessage()); } } - } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/discovery/WMBusDiscoveryParticipant.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/discovery/WMBusDiscoveryParticipant.java index 8bbb4ba..25ef488 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/discovery/WMBusDiscoveryParticipant.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/discovery/WMBusDiscoveryParticipant.java @@ -1,20 +1,24 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.discovery; import java.util.Set; import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.smarthome.config.discovery.DiscoveryResult; -import org.eclipse.smarthome.core.thing.ThingTypeUID; -import org.eclipse.smarthome.core.thing.ThingUID; import org.openhab.binding.wmbus.WMBusDevice; +import org.openhab.core.config.discovery.DiscoveryResult; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingUID; /** * Discovery participant which is responsible for identification of WMBus device. @@ -51,5 +55,4 @@ public interface WMBusDiscoveryParticipant { */ @Nullable public ThingUID getThingUID(WMBusDevice device); - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/VirtualWMBusBridgeHandler.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/VirtualWMBusBridgeHandler.java index b94a798..06b4c7a 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/VirtualWMBusBridgeHandler.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/VirtualWMBusBridgeHandler.java @@ -1,30 +1,32 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. - *

- * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.handler; +import static org.openhab.binding.wmbus.WMBusBindingConstants.THING_TYPE_VIRTUAL_BRIDGE; + import java.util.Collection; import java.util.Collections; import java.util.Set; -import org.eclipse.smarthome.config.core.status.ConfigStatusMessage; -import org.eclipse.smarthome.core.thing.Bridge; -import org.eclipse.smarthome.core.thing.ThingStatus; -import org.eclipse.smarthome.core.thing.ThingTypeUID; -import org.openhab.binding.wmbus.WMBusBindingConstants; -import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.config.WMBusBridgeConfig; import org.openhab.binding.wmbus.internal.WMBusReceiver; +import org.openhab.core.config.core.status.ConfigStatusMessage; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingTypeUID; import org.openhab.io.transport.mbus.wireless.KeyStorage; -import static org.openhab.binding.wmbus.WMBusBindingConstants.THING_TYPE_VIRTUAL_BRIDGE; - /** * The {@link VirtualWMBusBridgeHandler} class defines This class represents the WMBus bridge which * does not ship any real connection . @@ -48,7 +50,7 @@ public Collection getConfigStatus() { /** * Connects to the WMBus radio module and updates bridge status. * - * @see org.eclipse.smarthome.core.thing.binding.BaseThingHandler#initialize() + * @see org.openhab.core.thing.binding.BaseThingHandler#initialize() */ @Override public void initialize() { @@ -82,5 +84,4 @@ public void reset() { wmbusReceiver = null; initialize(); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusAdapter.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusAdapter.java index 5257add..b5d69ab 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusAdapter.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusAdapter.java @@ -1,17 +1,22 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. - *

- * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.handler; -import org.eclipse.smarthome.core.common.registry.Identifiable; -import org.eclipse.smarthome.core.thing.ThingUID; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.config.DateFieldMode; +import org.openhab.core.common.registry.Identifiable; +import org.openhab.core.thing.ThingUID; /** * Representation of WMBus device which is holds a link to radio device. @@ -20,6 +25,7 @@ * * @author Łukasz Dywicki */ +@NonNullByDefault public interface WMBusAdapter extends Identifiable { void processMessage(WMBusDevice device); @@ -27,5 +33,4 @@ public interface WMBusAdapter extends Identifiable { void reset(); DateFieldMode getDateFieldMode(); - } 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 bc7a1e4..6e8f700 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 @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. - *

- * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.handler; @@ -14,25 +18,17 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import org.eclipse.smarthome.config.core.Configuration; -import org.eclipse.smarthome.config.core.status.ConfigStatusMessage; -import org.eclipse.smarthome.core.thing.Bridge; -import org.eclipse.smarthome.core.thing.ThingStatus; -import org.eclipse.smarthome.core.thing.ThingStatusDetail; -import org.openhab.binding.wmbus.WMBusBindingConstants; -import org.openhab.binding.wmbus.config.DateFieldMode; + import org.openhab.binding.wmbus.config.StickModel; import org.openhab.binding.wmbus.config.WMBusSerialBridgeConfig; import org.openhab.binding.wmbus.internal.WMBusReceiver; +import org.openhab.core.config.core.status.ConfigStatusMessage; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; import org.openhab.io.transport.mbus.wireless.KeyStorage; import org.openmuc.jmbus.wireless.WMBusConnection; import org.openmuc.jmbus.wireless.WMBusConnection.WMBusManufacturer; @@ -62,15 +58,18 @@ public Collection getConfigStatus() { // check stick model if (config.stickModel == null) { - messages.add(ConfigStatusMessage.Builder.error(CONFKEY_STICK_MODEL).withMessageKeySuffix(CONFKEY_STICK_MODEL).build()); + messages.add(ConfigStatusMessage.Builder.error(CONFKEY_STICK_MODEL) + .withMessageKeySuffix(CONFKEY_STICK_MODEL).build()); } // check serial device name if (config.serialDevice == null) { - messages.add(ConfigStatusMessage.Builder.error(CONFKEY_INTERFACE_NAME).withMessageKeySuffix(CONFKEY_INTERFACE_NAME).build()); + messages.add(ConfigStatusMessage.Builder.error(CONFKEY_INTERFACE_NAME) + .withMessageKeySuffix(CONFKEY_INTERFACE_NAME).build()); } // check radio mode if (config.radioMode == null) { - messages.add(ConfigStatusMessage.Builder.error(CONFKEY_RADIO_MODE).withMessageKeySuffix(CONFKEY_RADIO_MODE).build()); + messages.add(ConfigStatusMessage.Builder.error(CONFKEY_RADIO_MODE).withMessageKeySuffix(CONFKEY_RADIO_MODE) + .build()); } return messages; @@ -79,7 +78,7 @@ public Collection getConfigStatus() { /** * Connects to the WMBus radio module and updates bridge status. * - * @see org.eclipse.smarthome.core.thing.binding.BaseThingHandler#initialize() + * @see org.openhab.core.thing.binding.BaseThingHandler#initialize() */ @Override public void initialize() { @@ -95,8 +94,7 @@ public void initialize() { WMBusMode radioMode = config.radioMode; // connect to the radio module / open WMBus connection - logger.debug("Opening wmbus stick {} serial port {} in mode {}", stickModel, interfaceName, - radioMode); + logger.debug("Opening wmbus stick {} serial port {} in mode {}", stickModel, interfaceName, radioMode); WMBusManufacturer wmBusManufacturer = parseManufacturer(stickModel.name().toUpperCase()); if (wmBusManufacturer == null) { @@ -207,5 +205,4 @@ public void dispose() { initFuture = null; } } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusBridgeHandlerBase.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusBridgeHandlerBase.java index 3f36ff0..668b870 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusBridgeHandlerBase.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusBridgeHandlerBase.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. - *

- * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * Copyright (c) 2010-2021 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.handler; @@ -24,22 +28,23 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; + import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.smarthome.core.common.ThreadPoolManager; -import org.eclipse.smarthome.core.library.types.StringType; -import org.eclipse.smarthome.core.thing.Bridge; -import org.eclipse.smarthome.core.thing.ChannelUID; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.thing.ThingUID; -import org.eclipse.smarthome.core.thing.binding.ConfigStatusBridgeHandler; -import org.eclipse.smarthome.core.thing.binding.ThingHandler; -import org.eclipse.smarthome.core.types.Command; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.WMBusBindingConstants; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.config.DateFieldMode; import org.openhab.binding.wmbus.config.WMBusBridgeConfig; import org.openhab.binding.wmbus.internal.WMBusReceiver; +import org.openhab.core.common.ThreadPoolManager; +import org.openhab.core.library.types.StringType; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.ConfigStatusBridgeHandler; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.types.Command; +import org.openhab.core.util.HexUtils; import org.openhab.io.transport.mbus.wireless.KeyStorage; import org.openmuc.jmbus.DecodingException; import org.openmuc.jmbus.wireless.VirtualWMBusMessageHelper; @@ -119,7 +124,7 @@ private void notifyWMBusMessageListeners(final WMBusDevice device, final String // below we append thing handlers which are configured for given device address ArrayList listeners = new ArrayList<>(this.wmBusMessageListeners); handlers.stream().filter(h -> device.getDeviceAddress().equals(h.getDeviceAddress())) - .collect(Collectors.toCollection(() -> listeners)); + .collect(Collectors.toCollection(() -> listeners)); for (WMBusMessageListener wmBusMessageListener : listeners) { try { @@ -160,20 +165,24 @@ protected WMBusDevice decrypt(WMBusDevice device) { } catch (DecodingException parseException) { if (parseException.getMessage().startsWith("Unable to decode encrypted payload")) { try { - WMBusMessage message = VirtualWMBusMessageHelper - .decode(device.getOriginalMessage().asBlob(), device.getOriginalMessage().getRssi(), - keyStorage.toMap()); + WMBusMessage message = VirtualWMBusMessageHelper.decode(device.getOriginalMessage().asBlob(), + device.getOriginalMessage().getRssi(), keyStorage.toMap()); message.getVariableDataResponse().decode(); logger.info("Message from {} successfully decrypted, forwarding it to receivers", device.getDeviceAddress()); return new WMBusDevice(message, this); } catch (DecodingException decodingException) { + logger.info( + "Could not decode frame, probably we still miss encryption key, forwarding frame in original form. {}, {}, {}", + decodingException.getMessage(), device.getOriginalMessage().toString(), + keyStorage.toMap().toString()); + } catch (NoClassDefFoundError decodingException) { logger.info( "Could not decode frame, probably we still miss encryption key, forwarding frame in original form. {}", decodingException.getMessage()); } - } else if (parseException.getMessage().startsWith("Manufacturer specific CI:") || parseException - .getMessage().startsWith("Unable to decode message with this CI Field")) { + } else if (parseException.getMessage().startsWith("Manufacturer specific CI:") + || parseException.getMessage().startsWith("Unable to decode message with this CI Field")) { logger.debug("Found frame with manufacturer specific encoding, forwarding for futher processing."); } else { logger.debug("Unexpected error while parsing frame, forwarding frame in original form", parseException); @@ -230,7 +239,6 @@ public void channelUnlinked(ChannelUID channelUID) { } } - @Override public void childHandlerInitialized(@NonNull ThingHandler childHandler, @NonNull Thing childThing) { if (childHandler instanceof WMBusDeviceHandler) { @@ -252,9 +260,8 @@ public void reset() { @Override public DateFieldMode getDateFieldMode() { - return Optional.ofNullable(getConfigAs(WMBusBridgeConfig.class)) - .map(cfg -> cfg.dateFieldMode) - .orElse(DateFieldMode.DATE_TIME); + return Optional.ofNullable(getConfigAs(WMBusBridgeConfig.class)).map(cfg -> cfg.dateFieldMode) + .orElse(DateFieldMode.DATE_TIME); } static class StatusRunnable implements Runnable { @@ -265,10 +272,9 @@ public StatusRunnable(Set> handlers) { this.handlers = handlers; } - @Override public void run() { + @Override + public void run() { handlers.stream().forEach(WMBusDeviceHandler::checkStatus); } - } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusDeviceHandler.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusDeviceHandler.java index 2b0a393..0711f23 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusDeviceHandler.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusDeviceHandler.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.handler; @@ -21,24 +25,24 @@ import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.smarthome.config.core.Configuration; -import org.eclipse.smarthome.core.library.types.DateTimeType; -import org.eclipse.smarthome.core.library.types.DecimalType; -import org.eclipse.smarthome.core.library.types.StringType; -import org.eclipse.smarthome.core.thing.Bridge; -import org.eclipse.smarthome.core.thing.Channel; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.thing.ThingStatus; -import org.eclipse.smarthome.core.thing.ThingStatusDetail; -import org.eclipse.smarthome.core.thing.binding.BaseThingHandler; -import org.eclipse.smarthome.core.thing.binding.ThingHandler; -import org.eclipse.smarthome.core.types.RefreshType; -import org.eclipse.smarthome.core.types.State; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.WMBusBindingConstants; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.config.DateFieldMode; import org.openhab.binding.wmbus.internal.WMBusException; +import org.openhab.core.config.core.Configuration; +import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.binding.BaseThingHandler; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.State; +import org.openhab.core.util.HexUtils; import org.openhab.io.transport.mbus.wireless.KeyStorage; import org.openhab.io.transport.mbus.wireless.MapKeyStorage; import org.openmuc.jmbus.DataRecord; diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusMessageListener.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusMessageListener.java index 4ee1fb0..7dea0f9 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusMessageListener.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/handler/WMBusMessageListener.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.handler; @@ -32,5 +36,4 @@ public interface WMBusMessageListener { * @param device The message which was received. */ public void onChangedWMBusDevice(WMBusAdapter adapter, WMBusDevice device); - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/DynamicBindingConfiguration.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/DynamicBindingConfiguration.java index c01c81c..cbbf3d7 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/DynamicBindingConfiguration.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/DynamicBindingConfiguration.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.internal; @@ -30,7 +34,7 @@ public class DynamicBindingConfiguration implements BindingConfiguration { private final Logger logger = LoggerFactory.getLogger(DynamicBindingConfiguration.class); private Long timeToLive = WMBusBindingConstants.DEFAULT_TIME_TO_LIVE; - private Boolean includeBridgeUID = false; + private Boolean includeBridgeUID = true; @Activate public void activate(ComponentContext context) { @@ -53,7 +57,6 @@ private void setTimeToLive(Object value) { if (value instanceof String) { this.timeToLive = Long.parseLong((String) value); } - } @Override @@ -64,7 +67,7 @@ public Long getTimeToLive() { private void setIncludeBridgeUID(Object value) { if (value == null) { logger.debug("Setting up includeBridgeUID to default value"); - this.includeBridgeUID = false; + this.includeBridgeUID = true; return; } @@ -76,7 +79,6 @@ private void setIncludeBridgeUID(Object value) { if (value instanceof String) { this.includeBridgeUID = Boolean.parseBoolean((String) value); } - } @Override @@ -89,5 +91,4 @@ void updated(Map configuration) { setTimeToLive(configuration.get(WMBusBindingConstants.CONFKEY_BINDING_TIME_TO_LIVE)); setIncludeBridgeUID(configuration.get(WMBusBindingConstants.CONFKEY_BINDING_INCLUDE_BRIDGE_UID)); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/HexConverter.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/HexConverter.java index b14f849..49e8ebc 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/HexConverter.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/HexConverter.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.internal; diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusChannelTypeProvider.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusChannelTypeProvider.java index b2faf47..ade8071 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusChannelTypeProvider.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusChannelTypeProvider.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.internal; @@ -15,22 +19,26 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; + import javax.measure.Unit; + import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.smarthome.core.library.CoreItemFactory; -import org.eclipse.smarthome.core.thing.type.ChannelKind; -import org.eclipse.smarthome.core.thing.type.ChannelType; -import org.eclipse.smarthome.core.thing.type.ChannelTypeProvider; -import org.eclipse.smarthome.core.thing.type.ChannelTypeUID; -import org.eclipse.smarthome.core.types.EventDescription; -import org.eclipse.smarthome.core.types.StateDescription; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.UnitRegistry; import org.openhab.binding.wmbus.WMBusBindingConstants; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.config.DateFieldMode; import org.openhab.binding.wmbus.handler.WMBusAdapter; import org.openhab.binding.wmbus.handler.WMBusMessageListener; +import org.openhab.core.library.CoreItemFactory; +import org.openhab.core.thing.type.ChannelKind; +import org.openhab.core.thing.type.ChannelType; +import org.openhab.core.thing.type.ChannelTypeBuilder; +import org.openhab.core.thing.type.ChannelTypeProvider; +import org.openhab.core.thing.type.ChannelTypeUID; +import org.openhab.core.types.EventDescription; +import org.openhab.core.types.StateDescription; +import org.openhab.core.types.StateDescriptionFragmentBuilder; +import org.openhab.core.util.HexUtils; import org.openmuc.jmbus.DataRecord; import org.openmuc.jmbus.DataRecord.DataValueType; import org.openmuc.jmbus.DataRecord.Description; @@ -70,7 +78,7 @@ public Collection getChannelTypes(@Nullable Locale locale) { @Override public @Nullable ChannelType getChannelType(ChannelTypeUID channelTypeUID, @Nullable Locale locale) { return wmbusChannelMap.values().stream().filter(channelType -> channelType.getUID().equals(channelTypeUID)) - .findFirst().orElse(null); + .findFirst().orElse(null); } @Override @@ -112,13 +120,19 @@ private void calculateChannelTypes(WMBusDevice device) { StateDescription state = getStateDescription(record.getDataValueType(), record.getDescription(), unit, dateFieldMode); EventDescription event = null; - ChannelType channelType = new ChannelType(typeUID, false, itemType.get(), kind, label, description, - category, tags, state, event, null); + ChannelTypeBuilder channelTypeBuilder; + ChannelType channelType = ChannelTypeBuilder.state(channelTypeUID.get(), label, itemType.get()) + .isAdvanced(false).withDescription(description).withCategory(category) + .build();/* + * new ChannelType(typeUID, false, itemType.get(), kind, label, + * description, + * category, tags, state, null, event, null, null) + */ + wmbusChannelMap.put(typeUID.getId(), channelType); } } } - } private StateDescription getStateDescription(DataValueType type, Description description, @@ -134,8 +148,11 @@ private StateDescription getStateDescription(DataValueType type, Description des boolean date = type == DataValueType.DATE; String pattern = mappedUnit.map(unit -> formatUnit(false, number, date, dateFieldMode)) - .orElseGet(() -> formatUnit(true, number, date, dateFieldMode)); - return new StateDescription(null, null, null, pattern, true, null); + .orElseGet(() -> formatUnit(true, number, date, dateFieldMode)); + StateDescriptionFragmentBuilder stateFragment = StateDescriptionFragmentBuilder.create().withPattern(pattern) + .withReadOnly(true); + return stateFragment.build() + .toStateDescription()/* new StateDescription(null, null, null, pattern, true, null) */; } private String formatUnit(boolean unitless, boolean number, boolean date, DateFieldMode dateFieldMode) { @@ -232,5 +249,4 @@ public final static Optional getChannelId(DataRecord record) { public final static Optional getChannelType(DataRecord record) { return getChannelId(record).map(id -> new ChannelTypeUID(WMBusBindingConstants.BINDING_ID, id)); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusException.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusException.java index 9058390..a57a5bb 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusException.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusException.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.internal; @@ -20,5 +24,4 @@ public class WMBusException extends Exception { public WMBusException(String string) { super(string); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusHandlerFactory.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusHandlerFactory.java index 7f007c8..2225a25 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusHandlerFactory.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusHandlerFactory.java @@ -1,20 +1,18 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.internal; -import org.eclipse.smarthome.core.thing.Bridge; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.thing.ThingTypeUID; -import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory; -import org.eclipse.smarthome.core.thing.binding.ThingHandler; -import org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory; import org.openhab.binding.wmbus.UnitRegistry; import org.openhab.binding.wmbus.WMBusBindingConstants; import org.openhab.binding.wmbus.device.UnknownMeter.UnknownWMBusDeviceHandler; @@ -23,6 +21,12 @@ import org.openhab.binding.wmbus.handler.VirtualWMBusBridgeHandler; import org.openhab.binding.wmbus.handler.WMBusBridgeHandler; import org.openhab.binding.wmbus.handler.WMBusMessageListener; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.binding.BaseThingHandlerFactory; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerFactory; import org.openhab.io.transport.mbus.wireless.FilteredKeyStorage; import org.openhab.io.transport.mbus.wireless.KeyStorage; import org.osgi.service.component.ComponentContext; @@ -139,5 +143,4 @@ protected void setChannelTypeProvider(WMBusChannelTypeProvider channelTypeProvid protected void unsetChannelTypeProvider(WMBusChannelTypeProvider channelTypeProvider) { this.channelTypeProvider = null; } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusReceiver.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusReceiver.java index df4d712..54aebf0 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusReceiver.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/WMBusReceiver.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.internal; @@ -12,9 +16,9 @@ import java.io.IOException; import java.util.Arrays; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.handler.WMBusAdapter; +import org.openhab.core.util.HexUtils; import org.openmuc.jmbus.wireless.WMBusListener; import org.openmuc.jmbus.wireless.WMBusMessage; import org.slf4j.Logger; @@ -92,5 +96,4 @@ public void stoppedListening(IOException e) { wmBusBridgeHandler.reset(); logger.warn("Stopped listening for new messages. Reason: {}", e); } - -} \ No newline at end of file +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/discovery/WMBusDiscoveryService.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/discovery/WMBusDiscoveryService.java index 10db94f..c4fd1e8 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/discovery/WMBusDiscoveryService.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/discovery/WMBusDiscoveryService.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.internal.discovery; @@ -16,15 +20,15 @@ import java.util.Map; import java.util.Set; -import org.eclipse.smarthome.config.discovery.AbstractDiscoveryService; -import org.eclipse.smarthome.config.discovery.DiscoveryResult; -import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; -import org.eclipse.smarthome.core.thing.ThingTypeUID; -import org.eclipse.smarthome.core.thing.ThingUID; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.handler.WMBusAdapter; import org.openhab.binding.wmbus.handler.WMBusBridgeHandler; import org.openhab.binding.wmbus.handler.WMBusMessageListener; +import org.openhab.core.config.discovery.AbstractDiscoveryService; +import org.openhab.core.config.discovery.DiscoveryResult; +import org.openhab.core.config.discovery.DiscoveryResultBuilder; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -147,5 +151,4 @@ public void activate() { public void onChangedWMBusDevice(WMBusAdapter adapter, WMBusDevice wmBusDevice) { // nothing to do } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/discovery/WMBusDiscoveryService2.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/discovery/WMBusDiscoveryService2.java index 6f5932e..e5d0a92 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/discovery/WMBusDiscoveryService2.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/discovery/WMBusDiscoveryService2.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.internal.discovery; @@ -13,13 +17,6 @@ import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; -import org.eclipse.smarthome.config.discovery.AbstractDiscoveryService; -import org.eclipse.smarthome.config.discovery.DiscoveryResult; -import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; -import org.eclipse.smarthome.config.discovery.DiscoveryService; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.thing.ThingTypeUID; -import org.eclipse.smarthome.core.thing.ThingUID; import org.openhab.binding.wmbus.BindingConfiguration; import org.openhab.binding.wmbus.WMBusBindingConstants; import org.openhab.binding.wmbus.WMBusCompanyIdentifiers; @@ -27,6 +24,13 @@ import org.openhab.binding.wmbus.discovery.WMBusDiscoveryParticipant; import org.openhab.binding.wmbus.handler.WMBusAdapter; import org.openhab.binding.wmbus.handler.WMBusMessageListener; +import org.openhab.core.config.discovery.AbstractDiscoveryService; +import org.openhab.core.config.discovery.DiscoveryResult; +import org.openhab.core.config.discovery.DiscoveryResultBuilder; +import org.openhab.core.config.discovery.DiscoveryService; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingTypeUID; +import org.openhab.core.thing.ThingUID; import org.openmuc.jmbus.SecondaryAddress; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -118,7 +122,6 @@ public void onNewWMBusDevice(WMBusAdapter adapter, WMBusDevice device) { @Override public void onChangedWMBusDevice(WMBusAdapter adapter, WMBusDevice device) { - } private void deviceDiscovered(WMBusAdapter adapter, WMBusDevice device) { @@ -178,7 +181,7 @@ private void deviceDiscovered(WMBusAdapter adapter, WMBusDevice device) { } else { thingUID = new ThingUID(typeUID, device.getDeviceAddress()); } - + // logger.error("adapter '{}' thingUID '{}'", adapter.getUID(), thingUID); // Create the discovery result and add to the inbox DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties) .withRepresentationProperty(WMBusBindingConstants.PROPERTY_DEVICE_ADDRESS).withBridge(adapter.getUID()) @@ -199,5 +202,4 @@ public void unsetBindingConfiguration(BindingConfiguration configuration) { private Long getTimeToLive() { return configuration.getTimeToLive(); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/units/CompositeUnitRegistry.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/units/CompositeUnitRegistry.java index 55930e6..aae27f3 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/units/CompositeUnitRegistry.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/units/CompositeUnitRegistry.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.internal.units; @@ -28,7 +32,7 @@ /** * An unit registry intended to aggregate several other registers to mask actual lookup operation. * - * By default this registry is started up with {@link SmartHomeUnitsRegistry} which covers standard DLMS-SI/Imperial + * By default this registry is started up with {@link UnitsRegistry} which covers standard DLMS-SI/Imperial * units known to * framework. However some DLMS units are not supported and very specific to narrow fields which might not be added any * time soon. For this reason we leave an extensions for future cases if there is a device we desperately want, but its @@ -42,7 +46,7 @@ public class CompositeUnitRegistry implements UnitRegistry { private final Set registers = new LinkedHashSet<>(); public CompositeUnitRegistry() { - this(new SmartHomeUnitsRegistry()); + this(new UnitsRegistry()); } CompositeUnitRegistry(UnitRegistry... registers) { @@ -93,5 +97,4 @@ protected void setUnitRegistry(UnitRegistry registry) { protected void unsetUnitRegistry(UnitRegistry registry) { this.registers.remove(registry); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/units/SmartHomeUnitsRegistry.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/units/UnitsRegistry.java similarity index 84% rename from org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/units/SmartHomeUnitsRegistry.java rename to org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/units/UnitsRegistry.java index b965b94..ce4de1c 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/units/SmartHomeUnitsRegistry.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/binding/wmbus/internal/units/UnitsRegistry.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.binding.wmbus.internal.units; @@ -35,10 +39,10 @@ import javax.measure.quantity.Volume; import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.smarthome.core.library.unit.ImperialUnits; -import org.eclipse.smarthome.core.library.unit.SIUnits; -import org.eclipse.smarthome.core.library.unit.SmartHomeUnits; import org.openhab.binding.wmbus.UnitRegistry; +import org.openhab.core.library.unit.ImperialUnits; +import org.openhab.core.library.unit.SIUnits; +import org.openhab.core.library.unit.Units; import org.openmuc.jmbus.DlmsUnit; /** @@ -49,7 +53,7 @@ * * @author Łukasz Dywicki - Initial contribution. */ -public class SmartHomeUnitsRegistry implements UnitRegistry { +public class UnitsRegistry implements UnitRegistry { @Override public Optional> lookup(DlmsUnit wmbusType) { @@ -59,7 +63,7 @@ public Optional> lookup(DlmsUnit wmbusType) { switch (wmbusType) { case AMPERE: - return Optional.of(SmartHomeUnits.AMPERE); + return Optional.of(Units.AMPERE); case AMPERE_HOUR: break; case AMPERE_PER_METRE: @@ -72,12 +76,12 @@ public Optional> lookup(DlmsUnit wmbusType) { break; case BAR: // Not present in ESH 0.9 / 0.10.0.oh230 - // return Optional.of(SmartHomeUnits.BAR); + // return Optional.of(Units.BAR); break; case CALORIFIC_VALUE: break; case COULOMB: - return Optional.of(SmartHomeUnits.COULOMB); + return Optional.of(Units.COULOMB); case COUNT: break; case CUBIC_FEET: @@ -96,7 +100,7 @@ public Optional> lookup(DlmsUnit wmbusType) { case CURRENCY: break; case DAY: - return Optional.of(SmartHomeUnits.DAY); + return Optional.of(Units.DAY); case DEGREE: break; case DEGREE_CELSIUS: @@ -106,19 +110,19 @@ public Optional> lookup(DlmsUnit wmbusType) { case ENERGY_PER_VOLUME: break; case FARAD: - return Optional.of(SmartHomeUnits.FARAD); + return Optional.of(Units.FARAD); case HENRY: - return Optional.of(SmartHomeUnits.HENRY); + return Optional.of(Units.HENRY); case HERTZ: - return Optional.of(SmartHomeUnits.HERTZ); + return Optional.of(Units.HERTZ); case HOUR: - return Optional.of(SmartHomeUnits.HOUR); + return Optional.of(Units.HOUR); case JOULE: - return Optional.of(SmartHomeUnits.JOULE); + return Optional.of(Units.JOULE); case JOULE_PER_HOUR: break; case KELVIN: - return Optional.of(SmartHomeUnits.KELVIN); + return Optional.of(Units.KELVIN); case KILOGRAM: return Optional.of(SIUnits.KILOGRAM); case KILOGRAM_PER_HOUR: @@ -126,7 +130,7 @@ public Optional> lookup(DlmsUnit wmbusType) { case KILOGRAM_PER_SECOND: break; case LITRE: - return Optional.of(SmartHomeUnits.LITRE); + return Optional.of(Units.LITRE); case MASS_DENSITY: break; case METER_CONSTANT_OR_PULSE_VALUE: @@ -134,19 +138,19 @@ public Optional> lookup(DlmsUnit wmbusType) { case METRE: return Optional.of(SIUnits.METRE); case METRE_PER_SECOND: - return Optional.of(SmartHomeUnits.METRE_PER_SECOND); + return Optional.of(Units.METRE_PER_SECOND); case MIN: - return Optional.of(SmartHomeUnits.MINUTE); + return Optional.of(Units.MINUTE); case MOLE_PERCENT: break; case MONTH: - return Optional.of(SmartHomeUnits.FARAD); + return Optional.of(Units.FARAD); case NEWTON: - return Optional.of(SmartHomeUnits.NEWTON); + return Optional.of(Units.NEWTON); case NEWTONMETER: break; case OHM: - return Optional.of(SmartHomeUnits.OHM); + return Optional.of(Units.OHM); case OHM_METRE: break; case OTHER_UNIT: @@ -162,13 +166,13 @@ public Optional> lookup(DlmsUnit wmbusType) { case RESERVED: break; case SECOND: - return Optional.of(SmartHomeUnits.SECOND); + return Optional.of(Units.SECOND); case SIGNAL_STRENGTH: break; case SPECIFIC_ENERGY: break; case TESLA: - return Optional.of(SmartHomeUnits.TESLA); + return Optional.of(Units.TESLA); case US_GALLON: break; case US_GALLON_PER_HOUR: @@ -180,7 +184,7 @@ public Optional> lookup(DlmsUnit wmbusType) { case VAR_HOUR: break; case VOLT: - return Optional.of(SmartHomeUnits.VOLT); + return Optional.of(Units.VOLT); case VOLT_AMPERE: break; case VOLT_AMPERE_HOUR: @@ -192,15 +196,15 @@ public Optional> lookup(DlmsUnit wmbusType) { case VOLT_SQUARED_HOUR_METER_CONSTANT_OR_PULSE_VALUE: break; case WATT: - return Optional.of(SmartHomeUnits.WATT); + return Optional.of(Units.WATT); case WATT_HOUR: - return Optional.of(SmartHomeUnits.WATT_HOUR); + return Optional.of(Units.WATT_HOUR); case WEBER: - return Optional.of(SmartHomeUnits.WEBER); + return Optional.of(Units.WEBER); case WEEK: - return Optional.of(SmartHomeUnits.WEEK); + return Optional.of(Units.WEEK); case YEAR: - return Optional.of(SmartHomeUnits.YEAR); + return Optional.of(Units.YEAR); default: break; } @@ -354,5 +358,4 @@ public Optional>> quantity(@Nullable DlmsUnit wmbusT return Optional.empty(); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/io/transport/mbus/wireless/FilteredKeyStorage.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/io/transport/mbus/wireless/FilteredKeyStorage.java index 8c43620..c5b55ee 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/io/transport/mbus/wireless/FilteredKeyStorage.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/io/transport/mbus/wireless/FilteredKeyStorage.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.io.transport.mbus.wireless; @@ -13,9 +17,9 @@ import java.util.Map; import java.util.Optional; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.WMBusBindingConstants; +import org.openhab.core.thing.Thing; +import org.openhab.core.util.HexUtils; import org.openmuc.jmbus.SecondaryAddress; /** @@ -57,7 +61,6 @@ public Map toMap() { } private SecondaryAddress createKey(byte[] address) { - return SecondaryAddress.newFromWMBusLlHeader(address, 0); + return SecondaryAddress.newFromWMBusHeader(address, 0); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/io/transport/mbus/wireless/KeyStorage.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/io/transport/mbus/wireless/KeyStorage.java index 8d510f7..fe15c62 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/io/transport/mbus/wireless/KeyStorage.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/io/transport/mbus/wireless/KeyStorage.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.io.transport.mbus.wireless; @@ -26,5 +30,4 @@ public interface KeyStorage { void registerKey(byte[] address, byte[] key); Map toMap(); - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openhab/io/transport/mbus/wireless/MapKeyStorage.java b/org.openhab.binding.wmbus/src/main/java/org/openhab/io/transport/mbus/wireless/MapKeyStorage.java index 937da47..30f9a1b 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openhab/io/transport/mbus/wireless/MapKeyStorage.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openhab/io/transport/mbus/wireless/MapKeyStorage.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openhab.io.transport.mbus.wireless; @@ -42,7 +46,6 @@ public Map toMap() { } private SecondaryAddress createKey(byte[] address) { - return SecondaryAddress.newFromWMBusLlHeader(address, 0); + return SecondaryAddress.newFromWMBusHeader(address, 0); } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/AesCrypt.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/AesCrypt.java new file mode 100644 index 0000000..658b7fc --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/AesCrypt.java @@ -0,0 +1,68 @@ +/** + * 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; + +import java.security.GeneralSecurityException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +class AesCrypt { + private final byte[] key; + private final byte[] iv; + + protected final SecretKeySpec skeySpec; + protected final AlgorithmParameterSpec paramSpec; + protected Cipher cipher; + + public static AesCrypt newAesCrypt(byte[] key, byte[] iv) throws DecodingException { + return new AesCrypt(key, iv, "AES/CBC/NoPadding"); + } + + public static AesCrypt newAesCtrCrypt(byte[] key, byte[] iv) throws DecodingException { + return new AesCrypt(key, iv, "AES/CTR/NoPadding"); + } + + private AesCrypt(byte[] key, byte[] iv, String cipherName) throws DecodingException { + try { + this.cipher = Cipher.getInstance(cipherName); + } catch (NoSuchPaddingException | NoSuchAlgorithmException e) { + throw new DecodingException(e); + } + + this.key = Arrays.copyOf(key, key.length); + this.iv = Arrays.copyOf(iv, iv.length); + this.skeySpec = new SecretKeySpec(this.key, "AES"); + this.paramSpec = new IvParameterSpec(this.iv); + } + + public byte[] encrypt(byte[] rawData, int length) throws GeneralSecurityException { + byte[] tempData = Arrays.copyOf(rawData, length); + + this.cipher.init(Cipher.ENCRYPT_MODE, skeySpec, paramSpec); + return this.cipher.doFinal(tempData); + } + + public byte[] decrypt(byte[] rawData, int length) throws DecodingException { + byte[] encrypted = rawData; + + if (length != 0) { + encrypted = Arrays.copyOf(rawData, length); + } + + try { + cipher.init(Cipher.DECRYPT_MODE, skeySpec, paramSpec); + return cipher.doFinal(encrypted); + } catch (GeneralSecurityException e) { + throw new DecodingException(e); + } + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/Bcd.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/Bcd.java new file mode 100644 index 0000000..e7691cc --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/Bcd.java @@ -0,0 +1,91 @@ +/** + * 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; + +/** + * This class represents a binary-coded decimal (BCD) number as defined by the M-Bus standard. The class provides + * methods to convert the BCD to other types such as double, int or String. + */ +public class Bcd extends Number { + + private static final long serialVersionUID = 790515601507532939L; + private final byte[] value; + + /** + * Constructs a Bcd from the given bytes. The constructed Bcd will use the given byte array for + * internal storage of its value. It is therefore recommended not to change the byte array after construction. + * + * @param bcdBytes + * the byte array to be used for construction of the Bcd. + */ + public Bcd(byte[] bcdBytes) { + this.value = bcdBytes; + } + + public byte[] getBytes() { + return value; + } + + @Override + public String toString() { + byte[] bytes = new byte[value.length * 2]; + int c = 0; + + if ((value[value.length - 1] & 0xf0) == 0xf0) { + bytes[c++] = 0x2d; + } else { + bytes[c++] = (byte) (((value[value.length - 1] >> 4) & 0x0f) + 48); + } + + bytes[c++] = (byte) ((value[value.length - 1] & 0x0f) + 48); + + for (int i = value.length - 2; i >= 0; i--) { + bytes[c++] = (byte) (((value[i] >> 4) & 0x0f) + 48); + bytes[c++] = (byte) ((value[i] & 0x0f) + 48); + } + + return new String(bytes); + } + + @Override + public double doubleValue() { + return longValue(); + } + + @Override + public float floatValue() { + return longValue(); + } + + @Override + public int intValue() { + return (int) longValue(); + } + + @Override + public long longValue() { + long result = 0l; + long factor = 1l; + + for (int i = 0; i < (value.length - 1); i++) { + result += (value[i] & 0x0f) * factor; + factor = factor * 10l; + result += ((value[i] >> 4) & 0x0f) * factor; + factor = factor * 10l; + } + + result += (value[value.length - 1] & 0x0f) * factor; + factor = factor * 10l; + + if ((value[value.length - 1] & 0xf0) == 0xf0) { + result = result * -1; + } else { + result += ((value[value.length - 1] >> 4) & 0x0f) * factor; + } + + return result; + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/CRC16.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/CRC16.java new file mode 100644 index 0000000..5ff5e73 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/CRC16.java @@ -0,0 +1,56 @@ +/** + * 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; + +import java.nio.ByteBuffer; + +/** + * 16 bit cyclic redundancy check implementation. + */ +class CRC16 { + + private static byte[] computeCrc(byte[] bytes, int poly, int initialValue, int xorValue) { + int i; + int crcVal = initialValue; + byte[] crc = new byte[2]; + + for (byte b : bytes) { + for (i = 0x80; i != 0; i >>= 1) { + if ((crcVal & 0x8000) != 0) { + crcVal = (crcVal << 1) ^ poly; + } else { + crcVal = crcVal << 1; + } + if ((b & i) != 0) { + crcVal ^= poly; + } + } + } + + byte[] tmpCrc = ByteBuffer.allocate(4).putInt(Integer.reverseBytes(crcVal & 0xffff ^ xorValue)).array(); + crc[0] = tmpCrc[0]; + crc[1] = tmpCrc[1]; + + return crc; + } + + /** + * Computes the CRC16 according EN13757. + * + * @param bytes + * the data to be checked. + * @return the CRC16 result. + */ + public static byte[] calculateCrc16(byte[] bytes) { + return computeCrc(bytes, 0x3D65, 0x0000, 0xFFFF); + } + + /** + * Do not let this class be instantiated. + */ + private CRC16() { + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/DataRecord.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/DataRecord.java index ed2b76b..6373971 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/DataRecord.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/DataRecord.java @@ -1,23 +1,22 @@ +/** + * 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; -import static javax.xml.bind.DatatypeConverter.printHexBinary; - import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; import java.util.Calendar; -import org.openmuc.jmbus.Bcd; -import org.openmuc.jmbus.DecodingException; -import org.openmuc.jmbus.DlmsUnit; - /** * Representation of a data record (sometimes called variable data block). - * + * * A data record is the basic data entity of the M-Bus application layer. A variable data structure contains a list of * data records. Each data record represents a single data point. A data record consists of three fields: The data * information block (DIB), the value information block (VIB) and the data field. - * + * * The DIB codes the following parameters: *

    *
  • Storage number - a meter can have several storages e.g. to store historical time series data. The storage number @@ -29,7 +28,7 @@ * tariffs.
  • *
  • Subunit - can be used by a slave to distinguish several subunits of the metering device
  • *
- * + * * The VIB codes the following parameters: *
    *
  • Description - the meaning of the data value (e.g. "Energy", "Volume" etc.)
  • @@ -37,7 +36,7 @@ *
  • Multiplier - a factor by which the data value coded in the data field has to be multiplied with. * getScaledDataValue() returns the result of the data value multiplied with the multiplier.
  • *
- * + * */ public class DataRecord { @@ -46,17 +45,17 @@ public class DataRecord { * */ public enum DataValueType { - LONG, - DOUBLE, - DATE, - STRING, - BCD, - NONE; + LONG, + DOUBLE, + DATE, + STRING, + BCD, + NONE; } /** * Function coded in the DIB - * + * */ public enum FunctionField { /** @@ -79,7 +78,7 @@ public enum FunctionField { /** * Data description stored in the VIB - * + * */ public enum Description { ENERGY, @@ -111,6 +110,7 @@ public enum Description { CUSTOMER, RESERVED, OPERATING_TIME_BATTERY, + RF_LEVEL, HCA, REACTIVE_ENERGY, TEMPERATURE_LIMIT, @@ -196,7 +196,7 @@ public byte[] getRawData() { return rawData; } - int decode(byte[] buffer, int offset, int length) throws DecodingException { + int decode(byte[] buffer, int offset) throws DecodingException { int i = offset; decodeDib(buffer, i); @@ -272,10 +272,12 @@ int decode(byte[] buffer, int offset, int length) throws DecodingException { break; case 0x02: /* INT16 */ if (dateTypeG) { - int day = (0x1f) & buffer[i]; - int year1 = ((0xe0) & buffer[i++]) >> 5; - int month = (0x0f) & buffer[i]; - int year2 = ((0xf0) & buffer[i++]) >> 1; + int day = (0x1f) & buffer[i]; // Byte 1; Bit 1-5 + int year1 = ((0xe0) & buffer[i++]) >> 5; // Byte 1: Bit 6-8 + + int month = (0x0f) & buffer[i]; // Byte 2: Bit 9-12 + int year2 = ((0xf0) & buffer[i++]) >> 1; // Byte 2: Bit 13-16 + int year = (2000 + year1 + year2); Calendar calendar = Calendar.getInstance(); @@ -284,6 +286,10 @@ int decode(byte[] buffer, int offset, int length) throws DecodingException { dataValue = calendar.getTime(); dataValueType = DataValueType.DATE; + } else if ((buffer[i + 1] & 0x80) == 0x80) { + // negative + dataValue = Long.valueOf((buffer[i++] & 0xff) | ((buffer[i++] & 0xff) << 8) | 0xffff << 16); + dataValueType = DataValueType.LONG; } else { dataValue = Long.valueOf((buffer[i++] & 0xff) | ((buffer[i++] & 0xff) << 8)); dataValueType = DataValueType.LONG; @@ -302,13 +308,18 @@ int decode(byte[] buffer, int offset, int length) throws DecodingException { break; case 0x04: /* INT32 */ if (dateTypeF) { - int min = (buffer[i++] & 0x3f); - int hour = (buffer[i] & 0x1f); - int yearh = (0x60 & buffer[i++]) >> 5; - int day = (buffer[i] & 0x1f); - int year1 = (0xe0 & buffer[i++]) >> 5; - int mon = (buffer[i] & 0x0f); - int year2 = (0xf0 & buffer[i++]) >> 1; + Calendar calendar = Calendar.getInstance(); + int min = (buffer[i++] & 0x3f); // Byte 1: Bit 1-6 + + int hour = (buffer[i] & 0x1f); // Byte 2: Bit 9-13 + int yearh = (0x60 & buffer[i]) >> 5; // Byte 2: Bit 14-15 + int dst = (0x80 & buffer[i++]) >> 7; // Byte 2: Bit 16 + + int day = (buffer[i] & 0x1f); // Byte 3: Bit 17-21 + int year1 = (0xe0 & buffer[i++]) >> 5; // Byte 3: Bit 22-24 + + int mon = (buffer[i] & 0x0f); // Byte 4: Bit 25-28 + int year2 = (0xf0 & buffer[i++]) >> 1; // Byte 4: Bit 29-32 if (yearh == 0) { yearh = 1; @@ -316,15 +327,17 @@ int decode(byte[] buffer, int offset, int length) throws DecodingException { int year = 1900 + 100 * yearh + year1 + year2; - Calendar calendar = Calendar.getInstance(); - calendar.set(year, mon - 1, day, hour, min, 0); + if (dst == 1) { + calendar.set(Calendar.DST_OFFSET, 60000); + } + dataValue = calendar.getTime(); dataValueType = DataValueType.DATE; } else { - dataValue = Long.valueOf((buffer[i++] & 0xff) | ((buffer[i++] & 0xff) << 8) - | ((buffer[i++] & 0xff) << 16) | ((buffer[i++] & 0xff) << 24)); + dataValue = (long) ByteBuffer.wrap(buffer, i, 4).order(ByteOrder.LITTLE_ENDIAN).getInt(); + i += 4; dataValueType = DataValueType.LONG; } break; @@ -337,22 +350,20 @@ int decode(byte[] buffer, int offset, int length) throws DecodingException { case 0x06: /* INT48 */ if ((buffer[i + 5] & 0x80) == 0x80) { // negative - dataValue = Long - .valueOf((buffer[i++] & 0xff) | ((buffer[i++] & 0xff) << 8) | ((buffer[i++] & 0xff) << 16) - | ((buffer[i++] & 0xff) << 24) | (((long) buffer[i++] & 0xff) << 32) - | (((long) buffer[i++] & 0xff) << 40) | (0xffl << 48) | (0xffl << 56)); + dataValue = Long.valueOf( + (buffer[i++] & 0xffL) | ((buffer[i++] & 0xffL) << 8) | ((buffer[i++] & 0xffL) << 16) + | ((buffer[i++] & 0xffL) << 24) | ((buffer[i++] & 0xffL) << 32) + | ((buffer[i++] & 0xffL) << 40) | (0xffL << 48) | (0xffL << 56)); } else { - dataValue = Long.valueOf((buffer[i++] & 0xff) | ((buffer[i++] & 0xff) << 8) - | ((buffer[i++] & 0xff) << 16) | ((buffer[i++] & 0xff) << 24) - | (((long) buffer[i++] & 0xff) << 32) | (((long) buffer[i++] & 0xff) << 40)); + dataValue = Long.valueOf((buffer[i++] & 0xffL) | ((buffer[i++] & 0xffL) << 8) + | ((buffer[i++] & 0xffL) << 16) | ((buffer[i++] & 0xffL) << 24) + | ((buffer[i++] & 0xffL) << 32) | ((buffer[i++] & 0xffL) << 40)); } dataValueType = DataValueType.LONG; break; case 0x07: /* INT64 */ - dataValue = Long.valueOf((buffer[i++] & 0xff) | ((buffer[i++] & 0xff) << 8) - | ((buffer[i++] & 0xff) << 16) | ((buffer[i++] & 0xff) << 24) - | (((long) buffer[i++] & 0xff) << 32) | (((long) buffer[i++] & 0xff) << 40) - | (((long) buffer[i++] & 0xff) << 48) | (((long) buffer[i++] & 0xff) << 56)); + dataValue = ByteBuffer.wrap(buffer, i, 8).order(ByteOrder.LITTLE_ENDIAN).getLong(); + i += 8; dataValueType = DataValueType.LONG; break; case 0x09: @@ -389,11 +400,6 @@ int decode(byte[] buffer, int offset, int length) throws DecodingException { throw new DecodingException("Unsupported LVAR Field: " + variableLength); } - // TODO check this: - // if (variableLength >= 0xc0) { - // throw new DecodingException("Variable length (LVAR) field >= 0xc0: " + variableLength); - // } - byte[] rawData = new byte[dataLength0x0d]; for (int j = 0; j < dataLength0x0d; j++) { @@ -456,7 +462,7 @@ int encode(byte[] buffer, int offset) { /** * Returns a byte array containing the DIB (i.e. the DIF and the DIFEs) contained in the data record. - * + * * @return a byte array containing the DIB */ public byte[] getDib() { @@ -465,7 +471,7 @@ public byte[] getDib() { /** * Returns a byte array containing the VIB (i.e. the VIF and the VIFEs) contained in the data record. - * + * * @return a byte array containing the VIB */ public byte[] getVib() { @@ -476,7 +482,7 @@ public byte[] getVib() { * Returns the decoded data field of the data record as an Object. The Object is of one of the four types Long, * Double, String or Date depending on information coded in the DIB/VIB. The DataType can be checked using * getDataValueType(). - * + * * @return the data value */ public Object getDataValue() { @@ -490,13 +496,17 @@ public DataValueType getDataValueType() { /** * Returns the data (value) multiplied by the multiplier as a Double. If the data is not a number than null is * returned. - * + * * @return the data (value) multiplied by the multiplier as a Double */ public Double getScaledDataValue() { - try { - return ((Number) dataValue).doubleValue() * Math.pow(10, multiplierExponent); - } catch (ClassCastException e) { + if (dataValue != null) { + try { + return ((Number) dataValue).doubleValue() * Math.pow(10, multiplierExponent); + } catch (ClassCastException e) { + return null; + } + } else { return null; } } @@ -532,7 +542,7 @@ public String getUserDefinedDescription() { /** * The multiplier is coded in the VIF. Is always a power of 10. This function returns the exponent. The base is * always 10. - * + * * @return the exponent of the multiplier. */ public int getMultiplierExponent() { @@ -559,7 +569,7 @@ private void decodeTimeUnit(int vif) { } } - private int decodeUserDefinedVif(byte[] buffer, int offset) throws DecodingException { + private int decodeUserDefinedVif(byte[] buffer, int offset) { int length = buffer[offset]; StringBuilder sb = new StringBuilder(); @@ -571,7 +581,6 @@ private int decodeUserDefinedVif(byte[] buffer, int offset) throws DecodingExcep userDefinedDescription = sb.toString(); return length + 1; - } private void decodeMainVif(int vif) { @@ -583,7 +592,6 @@ private void decodeMainVif(int vif) { decodeE1(vif); } - } private void decodeE1(int vif) { @@ -888,7 +896,7 @@ private void decodeMainExtendedVif(byte vif) throws DecodingException { description = Description.RESERVED; } else if ((vif & 0x7c) == 0x24) { // E010 01nn description = Description.STORAGE_INTERVALL; - this.unit = unitFor(vif); + this.unit = timeUnitFor(vif); } else if ((vif & 0x7f) == 0x28) { // E010 1000 description = Description.STORAGE_INTERVALL; unit = DlmsUnit.MONTH; @@ -902,19 +910,13 @@ private void decodeMainExtendedVif(byte vif) throws DecodingException { unit = DlmsUnit.SECOND; } else if ((vif & 0x7c) == 0x2c) { // E010 11nn description = Description.DURATION_LAST_READOUT; - this.unit = unitFor(vif); + this.unit = timeUnitFor(vif); } else if ((vif & 0x7c) == 0x30) { // E011 00nn description = Description.TARIF_DURATION; - switch (vif & 0x03) { - case 0: // E011 0000 - description = Description.NOT_SUPPORTED; // TODO: TARIF_START (Date/Time) - break; - default: - this.unit = unitFor(vif); - } + this.unit = timeUnitFor(vif); } else if ((vif & 0x7c) == 0x34) { // E011 01nn description = Description.TARIF_PERIOD; - this.unit = unitFor(vif); + this.unit = timeUnitFor(vif); } else if ((vif & 0x7f) == 0x38) { // E011 1000 description = Description.TARIF_PERIOD; unit = DlmsUnit.MONTH; @@ -954,7 +956,8 @@ private void decodeMainExtendedVif(byte vif) throws DecodingException { } else if ((vif & 0x7f) == 0x70) { // E111 0000 description = Description.NOT_SUPPORTED; // TODO: BATTERY_CHANGE_DATE_TIME } else if ((vif & 0x7f) == 0x71) { // E111 0001 - description = Description.NOT_SUPPORTED; // TODO: RF_LEVEL dBm + description = Description.RF_LEVEL; + this.unit = DlmsUnit.SIGNAL_STRENGTH; } else if ((vif & 0x7f) == 0x72) { // E111 0010 description = Description.NOT_SUPPORTED; // TODO: DAYLIGHT_SAVING (begin, ending, deviation) } else if ((vif & 0x7f) == 0x73) { // E111 0011 @@ -989,7 +992,7 @@ private static DlmsUnit unitBiggerFor(byte vif) throws DecodingException { } } - private static DlmsUnit unitFor(byte vif) throws DecodingException { + private static DlmsUnit timeUnitFor(byte vif) throws DecodingException { int u = vif & 0x03; switch (u) { case 0: // E010 1100 @@ -1304,14 +1307,13 @@ private void decodeAlternateExtendedVif(byte vif) { } } - } @Override public String toString() { - StringBuilder builder = new StringBuilder().append("DIB:").append(printHexBinary(dib)).append(", VIB:") - .append(printHexBinary(vib)).append(" -> descr:").append(description); + StringBuilder builder = new StringBuilder().append("DIB:").append(HexUtils.bytesToHex(dib)).append(", VIB:") + .append(HexUtils.bytesToHex(vib)).append(" -> descr:").append(description); if (description == Description.USER_DEFINED) { builder.append(" :").append(getUserDefinedDescription()); @@ -1368,11 +1370,9 @@ public String toString() { } return builder.toString(); - } public int getDataLength() { return dataLength; } - } diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/DecodingException.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/DecodingException.java new file mode 100644 index 0000000..b7b3aa6 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/DecodingException.java @@ -0,0 +1,26 @@ +/** + * 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; + +/** + * Signals that a M-Bus message could not be decoded. + */ +public class DecodingException extends Exception { + + private static final long serialVersionUID = 1735527302166708223L; + + public DecodingException(String msg) { + super(msg); + } + + public DecodingException(Throwable cause) { + super(cause); + } + + public DecodingException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/DeviceType.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/DeviceType.java new file mode 100644 index 0000000..1ba052f --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/DeviceType.java @@ -0,0 +1,122 @@ +/** + * 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; + +import java.util.HashMap; +import java.util.Map; + +/** + * The device type that is part of the data header of a Variable Data Response. + */ +public enum DeviceType { + OTHER(0x00), + OIL_METER(0x01), + ELECTRICITY_METER(0x02), + GAS_METER(0x03), + HEAT_METER(0x04), + STEAM_METER(0x05), + WARM_WATER_METER(0x06), + WATER_METER(0x07), + HEAT_COST_ALLOCATOR(0x08), + COMPRESSED_AIR(0x09), + COOLING_METER_OUTLET(0x0a), + COOLING_METER_INLET(0x0b), + HEAT_METER_INLET(0x0c), + HEAT_COOLING_METER(0x0d), + BUS_SYSTEM_COMPONENT(0x0e), + UNKNOWN(0x0f), + RESERVED_FOR_METER_16(0x10), + RESERVED_FOR_METER_17(0x11), + RESERVED_FOR_METER_18(0x12), + RESERVED_FOR_METER_19(0x13), + CALORIFIC_VALUE(0x14), + HOT_WATER_METER(0x15), + COLD_WATER_METER(0x16), + DUAL_REGISTER_WATER_METER(0x17), + PRESSURE_METER(0x18), + AD_CONVERTER(0x19), + SMOKE_DETECTOR(0x1a), + ROOM_SENSOR_TEMP_HUM(0x1b), + GAS_DETECTOR(0x1c), + RESERVED_FOR_SENSOR_0X1D(0x1d), + RESERVED_FOR_SENSOR_0X1E(0x1e), + RESERVED_FOR_SENSOR_0X1F(0x1f), + BREAKER_ELEC(0x20), + VALVE_GAS_OR_WATER(0x21), + RESERVED_FOR_SWITCHING_DEVICE_0X22(0x22), + RESERVED_FOR_SWITCHING_DEVICE_0X23(0x23), + RESERVED_FOR_SWITCHING_DEVICE_0X24(0x24), + CUSTOMER_UNIT_DISPLAY_DEVICE(0x25), + RESERVED_FOR_CUSTOMER_UNIT_0X26(0x26), + RESERVED_FOR_CUSTOMER_UNIT_0X27(0x27), + WASTE_WATER_METER(0x28), + GARBAGE(0x29), + RESERVED_FOR_CO2(0x2a), + RESERVED_FOR_ENV_METER_0X2B(0x2b), + RESERVED_FOR_ENV_METER_0X2C(0x2c), + RESERVED_FOR_ENV_METER_0X2D(0x2d), + RESERVED_FOR_ENV_METER_0X2E(0x2e), + RESERVED_FOR_ENV_METER_0X2F(0x2f), + RESERVED_FOR_SYSTEM_DEVICES_0X30(0x30), + COM_CONTROLLER(0x31), + UNIDIRECTION_REPEATER(0x32), + BIDIRECTION_REPEATER(0x33), + RESERVED_FOR_SYSTEM_DEVICES_0X34(0x34), + RESERVED_FOR_SYSTEM_DEVICES_0X35(0x35), + RADIO_CONVERTER_SYSTEM_SIDE(0x36), + RADIO_CONVERTER_METER_SIDE(0x37), + RESERVED_FOR_SYSTEM_DEVICES_0X38(0x38), + RESERVED_FOR_SYSTEM_DEVICES_0X39(0x39), + RESERVED_FOR_SYSTEM_DEVICES_0X3A(0x3a), + RESERVED_FOR_SYSTEM_DEVICES_0X3B(0x3b), + RESERVED_FOR_SYSTEM_DEVICES_0X3C(0x3c), + RESERVED_FOR_SYSTEM_DEVICES_0X3D(0x3d), + RESERVED_FOR_SYSTEM_DEVICES_0X3E(0x3e), + RESERVED_FOR_SYSTEM_DEVICES_0X3F(0x3f), + RESERVED(0xff); + + private final int id; + + private static final Map idMap = new HashMap<>(); + + static { + for (DeviceType enumInstance : DeviceType.values()) { + if (idMap.put(enumInstance.getId(), enumInstance) != null) { + throw new IllegalArgumentException("duplicate ID: " + enumInstance.getId()); + } + } + } + + private DeviceType(int id) { + this.id = id; + } + + /** + * Returns the ID of this DeviceType. + * + * @return the ID + */ + public int getId() { + return id; + } + + /** + * Returns the DeviceType that corresponds to the given ID. Returns DeviceType.RESERVED if no DeviceType with the + * given ID exists. + * + * @param id + * the ID + * @return the DeviceType that corresponds to the given ID + */ + public static DeviceType getInstance(int id) { + DeviceType enumInstance = idMap.get(id); + if (enumInstance == null) { + enumInstance = DeviceType.RESERVED; + } + return enumInstance; + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/DlmsUnit.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/DlmsUnit.java new file mode 100644 index 0000000..ccf85ae --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/DlmsUnit.java @@ -0,0 +1,150 @@ +/** + * 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; + +import java.util.HashMap; +import java.util.Map; + +/** + * The units as defined in IEC 62056-6-2. Some units not defined in IEC 62056-6-2 but needed by M-Bus were added. + */ +public enum DlmsUnit { + // can be found in IEC 62056-6-2 2017 Capture 5.2.2 + YEAR(1, "a"), + MONTH(2, "mo"), + WEEK(3, "wk"), + DAY(4, "d"), + HOUR(5, "h"), + MIN(6, "min"), + SECOND(7, "s"), + DEGREE(8, "°"), + DEGREE_CELSIUS(9, "°C"), + CURRENCY(10, ""), + METRE(11, "m"), + METRE_PER_SECOND(12, "m/s"), + CUBIC_METRE(13, "m³"), + CUBIC_METRE_CORRECTED(14, "m³"), + CUBIC_METRE_PER_HOUR(15, "m³/h"), + CUBIC_METRE_PER_HOUR_CORRECTED(16, "m³/h"), + CUBIC_METRE_PER_DAY(17, "m³/d"), + CUBIC_METRE_PER_DAY_CORRECTED(18, "m³/d"), + LITRE(19, "l"), + KILOGRAM(20, "kg"), + NEWTON(21, "N"), + NEWTONMETER(22, "Nm"), + PASCAL(23, "Pa"), + BAR(24, "bar"), + JOULE(25, "J"), + JOULE_PER_HOUR(26, "J/h"), + WATT(27, "W"), + VOLT_AMPERE(28, "VA"), + VAR(29, "var"), + WATT_HOUR(30, "Wh"), + VOLT_AMPERE_HOUR(31, "VAh"), + VAR_HOUR(32, "varh"), + AMPERE(33, "A"), + COULOMB(34, "C"), + VOLT(35, "V"), + VOLT_PER_METRE(36, "V/m"), + FARAD(37, "F"), + OHM(38, "Ohm"), + OHM_METRE(39, "Ohm m²/m"), + WEBER(40, "Wb"), + TESLA(41, "T"), + AMPERE_PER_METRE(42, "A/m"), + HENRY(43, "H"), + HERTZ(44, "Hz"), + ACTIVE_ENERGY_METER_CONSTANT_OR_PULSE_VALUE(45, "1/(Wh)"), + REACTIVE_ENERGY_METER_CONSTANT_OR_PULSE_VALUE(46, "1/(varh)"), + APPARENT_ENERGY_METER_CONSTANT_OR_PULSE_VALUE(47, "1(VAh)"), + VOLT_SQUARED_HOURS(48, "V²h"), + AMPERE_SQUARED_HOURS(49, "A²h"), + KILOGRAM_PER_SECOND(50, "kg/s"), + SIEMENS(51, "S"), + KELVIN(52, "K"), + VOLT_SQUARED_HOUR_METER_CONSTANT_OR_PULSE_VALUE(53, "1/(V²h)"), + AMPERE_SQUARED_HOUR_METER_CONSTANT_OR_PULSE_VALUE(54, "1/(A²h)"), + METER_CONSTANT_OR_PULSE_VALUE(55, "1/m³"), + PERCENTAGE(56, "%"), + AMPERE_HOUR(57, "Ah"), + + ENERGY_PER_VOLUME(60, "Wh/m³"), + CALORIFIC_VALUE(61, "J/m³"), + MOLE_PERCENT(62, "Mol %"), + MASS_DENSITY(63, "g/m³"), + PASCAL_SECOND(64, "Pa s"), + SPECIFIC_ENERGY(65, "J/kg"), + + SIGNAL_STRENGTH(70, "dBm"), + SIGNAL_STRENGTH_MICROVOLT(71, "dBµv"), + LOGARITHMIC(72, "dB"), + + RESERVED(253, ""), + OTHER_UNIT(254, "other"), + COUNT(255, "count"), + + // not mentioned in 62056, added for MBus: + CUBIC_METRE_PER_SECOND(150, "m³/s"), + CUBIC_METRE_PER_MINUTE(151, "m³/min"), + KILOGRAM_PER_HOUR(152, "kg/h"), + CUBIC_FEET(153, "cft"), + US_GALLON(154, "Impl. gal."), + US_GALLON_PER_MINUTE(155, "Impl. gal./min"), + US_GALLON_PER_HOUR(156, "Impl. gal./h"), + DEGREE_FAHRENHEIT(157, "°F"); + + private final int id; + private final String unit; + + private static final Map idMap = new HashMap<>(); + + static { + for (DlmsUnit enumInstance : DlmsUnit.values()) { + if (idMap.put(enumInstance.getId(), enumInstance) != null) { + throw new IllegalArgumentException("duplicate ID: " + enumInstance.getId()); + } + } + } + + private DlmsUnit(int id, String unit) { + this.id = id; + this.unit = unit; + } + + /** + * Returns the ID of this DlmsUnit. + * + * @return the ID + */ + public int getId() { + return id; + } + + /** + * Returns the unit sign of this DlmsUnit. + * + * @return the ID + */ + public String getUnit() { + return unit; + } + + /** + * Returns the DlmsUnit that corresponds to the given ID. Returns DlmsUnit.RESERVED if no DlmsUnit with the given ID + * exists. + * + * @param id + * the ID + * @return the DlmsUnit that corresponds to the given ID + */ + public static DlmsUnit getInstance(int id) { + DlmsUnit enumInstance = idMap.get(id); + if (enumInstance == null) { + enumInstance = DlmsUnit.RESERVED; + } + return enumInstance; + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/EncryptionMode.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/EncryptionMode.java new file mode 100644 index 0000000..626464a --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/EncryptionMode.java @@ -0,0 +1,99 @@ +/** + * 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; + +import java.util.HashMap; +import java.util.Map; + +/** + * The encryption modes. + */ +public enum EncryptionMode { + /** + * No encryption. + */ + NONE(0), + /** + * AES with Counter Mode (CTR) noPadding and IV. + */ + AES_128(1), + /** + * DES with Cipher Block Chaining Mode (CBC).
+ * Not supported yet. + */ + DES_CBC(2), + /** + * DES with Cipher Block Chaining Mode (CBC) and Initial Vector.
+ * Not supported yet. + */ + DES_CBC_IV(3), + RESERVED_04(4), + /** + * AES with Cipher Block Chaining Mode (CBC) and Initial Vector. + */ + AES_CBC_IV(5), + RESERVED_06(6), + /** + * AES 128 with Cipher Block Chaining Mode (CBC) and dynamic key and Initial Vector with 0.
+ * TR-03109-1 Anlage Feinspezifikation Drahtlose LMN Schnittstelle-Teil2
+ * Not supported yet. + */ + AES_CBC_IV_0(7), + RESERVED_08(8), + RESERVED_09(9), + RESERVED_10(10), + RESERVED_11(11), + RESERVED_12(12), + /** + * TLS 1.2
+ * TR-03109-1 Anlage Feinspezifikation Drahtlose LMN Schnittstelle-Teil2
+ * Not supported yet. + */ + TLS(13), + RESERVED_14(14), + RESERVED_15(15); + + private final int id; + + private static final Map idMap = new HashMap<>(); + + static { + for (EncryptionMode enumInstance : EncryptionMode.values()) { + if (idMap.put(enumInstance.getId(), enumInstance) != null) { + throw new IllegalArgumentException("duplicate ID: " + enumInstance.getId()); + } + } + } + + private EncryptionMode(int id) { + this.id = id; + } + + /** + * Returns the ID of this EncryptionMode. + * + * @return the ID + */ + public int getId() { + return id; + } + + /** + * Returns the EncryptionMode that corresponds to the given ID. Throws an IllegalArgumentException if no + * EncryptionMode with the given ID exists. + * + * @param id + * the ID + * @return the EncryptionMode that corresponds to the given ID + */ + public static EncryptionMode getInstance(int id) { + EncryptionMode enumInstance = idMap.get(id); + if (enumInstance == null) { + throw new IllegalArgumentException("invalid ID: " + id); + } + return enumInstance; + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/HexUtils.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/HexUtils.java new file mode 100644 index 0000000..b5d5273 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/HexUtils.java @@ -0,0 +1,32 @@ +package org.openmuc.jmbus; + +public class HexUtils { + + private static final String HEXES = "0123456789ABCDEF"; + + public static String bytesToHex(byte[] bytes) { + if (bytes == null) { + return null; + } + final StringBuilder hex = new StringBuilder(2 * bytes.length); + for (final byte b : bytes) { + hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F))); + } + return hex.toString(); + } + + public static byte[] hexToBytes(String hexString) { + byte[] bytes = new byte[hexString.length() / 2]; + int index; + + for (int i = 0; i < bytes.length; i++) { + index = i * 2; + bytes[i] = (byte) Integer.parseInt(hexString.substring(index, index + 2), 16); + } + return bytes; + } + + private HexUtils() { + // hide it + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/MBusConnection.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/MBusConnection.java new file mode 100644 index 0000000..8c53f3a --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/MBusConnection.java @@ -0,0 +1,536 @@ +/** + * 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; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.List; + +import org.openmuc.jmbus.MBusMessage.MessageType; +import org.openmuc.jmbus.VerboseMessage.MessageDirection; +import org.openmuc.jmbus.transportlayer.SerialBuilder; +import org.openmuc.jmbus.transportlayer.TcpBuilder; +import org.openmuc.jmbus.transportlayer.TransportLayer; + +/** + * M-Bus Application Layer connection. + *

+ * Use this access point to communicate using the M-Bus wired protocol. + *

+ * + * @see MBusConnection#newSerialBuilder(String) + * @see MBusConnection#newTcpBuilder(String, int) + */ +public class MBusConnection implements AutoCloseable { + + private static final int START_BYTE = 0x68; + private static final int STOP_BYTE = 0x16; + private static final int SINGLE_CHARACTER = 0xe5; + + // 261 is the maximum size of a long frame + private static final int MAX_MESSAGE_SIZE = 261; + + private final byte[] outputBuffer = new byte[MAX_MESSAGE_SIZE]; + + private final byte[] dataRecordsAsBytes = new byte[MAX_MESSAGE_SIZE]; + + private final boolean[] frameCountBits; + + private DataOutputStream os; + private DataInputStream is; + + private SecondaryAddress secondaryAddress; + + private VerboseMessageListener verboseMessageListener; + + private final TransportLayer transportLayer; + + /** + * Creates an M-Bus Service Access Point that is used to read meters. + * + * @param transportLayer + * Underlying transport layer + * @see MBusConnection#open() + */ + private MBusConnection(TransportLayer transportLayer) { + this.transportLayer = transportLayer; + + // set all frame bits to true + this.frameCountBits = new boolean[254]; + for (int i = 0; i < frameCountBits.length; i++) { + frameCountBits[i] = true; + } + } + + private void open() throws IOException { + try { + this.transportLayer.open(); + } catch (IOException e) { + this.transportLayer.close(); + throw e; + } + + this.os = transportLayer.getOutputStream(); + this.is = transportLayer.getInputStream(); + } + + /** + * Closes the service access point. + */ + @Override + public void close() { + transportLayer.close(); + } + + /** + * Sets the verbose mode on if a implementation of debugMessageListener has been set. + * + * @param verboseMessageListener + * Implementation of debugMessageListener + */ + public void setVerboseMessageListener(VerboseMessageListener verboseMessageListener) { + this.verboseMessageListener = verboseMessageListener; + } + + /** + * Scans for secondary addresses and returns all detected devices in a list and if SecondaryAddressListener not null + * to the listen listener. + * + * @param wildcardMask + * a wildcard mask for masking + * @param secondaryAddressListener + * listener to get scan messages and scanned secondary address just at time.
+ * If null, all detected address will only returned if finished. + * @param delay + * delay between every sent message. Sometimes needed for slow devices. Deactivated if 0 or less. + * + * @return a list of secondary addresses of all detected devices + * @throws IOException + * if any kind of error (including timeout) occurs while writing to the remote device. Note that the + * connection is not closed when an IOException is thrown. + */ + public List scan(String wildcardMask, SecondaryAddressListener secondaryAddressListener, + long delay) throws IOException { + + if (wildcardMask == null || wildcardMask.isEmpty()) { + wildcardMask = "ffffffff"; + } + + return ScanSecondaryAddress.scan(this, wildcardMask, secondaryAddressListener, delay); + } + + /** + * Reads a meter using primary addressing. Sends a data request (REQ_UD2) to the remote device and returns the + * variable data structure from the received RSP_UD frame. + * + * @param primaryAddress + * the primary address of the meter to read. For secondary address use 0xfd. + * @return the variable data structure from the received RSP_UD frame + * @throws IOException + * if any kind of error (including timeout) occurs while trying to read the remote device. Note that the + * connection is not closed when an IOException is thrown. + */ + public VariableDataStructure read(int primaryAddress) throws IOException { + if (transportLayer.isClosed()) { + throw new IllegalStateException("Port is not open."); + } + + if (frameCountBits[primaryAddress]) { + sendShortMessage(primaryAddress, 0x7b); + frameCountBits[primaryAddress] = false; + } else { + sendShortMessage(primaryAddress, 0x5b); + frameCountBits[primaryAddress] = true; + } + + MBusMessage mBusMessage = receiveMessage(); + + if (mBusMessage.getMessageType() != MessageType.RSP_UD) { + throw new IOException( + "Received wrong kind of message. Expected RSP_UD but got: " + mBusMessage.getMessageType()); + } + + if (mBusMessage.getAddressField() != primaryAddress) { + // throw new IOException("Received RSP_UD message with unexpected address field. Expected " + primaryAddress + // + " but received " + mBusMessage.getAddressField()); + } + + try { + mBusMessage.getVariableDataResponse().decode(); + } catch (DecodingException e) { + throw new IOException("Error decoding incoming RSP_UD message.", e); + } + + return mBusMessage.getVariableDataResponse(); + } + + /** + * Sends a long message with individual parameters. Used for messages which arn't not predefined in + * {@link MBusConnection}.
+ * If no response message is expected, set hasResponse to false. Returns null if hasResponse is + * false + * + * @param primaryAddr + * the primary address of the meter to read. For secondary address use 0xfd. + * @param controlField + * control field (C Field) has the size of 1 byte. + * @param ci + * control information field (CI Field) has the size of 1 byte. + * @param data + * the data to sends to the meter. + * @param responseExpected + * set this flag to false if no response is expected else true. If false + * returns null + * @return returns null if boolean hasResponse is false.
+ * returns the {@link MBusMessage} if a message received. + * @throws IOException + * if any kind of error (including timeout) occurs while trying to send to or read the remote device. + * Note that the connection is not closed when an IOException is thrown. + */ + public MBusMessage sendLongMessage(int primaryAddr, int controlField, int ci, byte[] data, boolean responseExpected) + throws IOException { + MBusMessage mBusMessage = null; + + sendLongMessage(primaryAddr, controlField, ci, data.length, data); + + if (responseExpected) { + mBusMessage = receiveMessage(); + } + return mBusMessage; + } + + /** + * Sends a short message with individual parameters. Used for messages which arn't not predefined in + * {@link MBusConnection}.
+ * For normal readout use {@link MBusConnection#read(int)}.
+ * If no response message is expected, set hasResponse to false. Returns null if hasResponse is + * false + * + * @param primaryAddr + * the primary address of the meter to read. For secondary address use 0xfd. + * @param cmd + * the command to send to the meter. + * @param responseExpected + * set this flag to false if no response is expected else true. If false + * returns null + * @return returns null if boolean hasResponse is false.
+ * returns the {@link MBusMessage} if a message received. + * @throws IOException + * f any kind of error (including timeout) occurs while trying to send to or read the remote device. + * Note that the connection is not closed when an IOException is thrown. + */ + public MBusMessage sendShortMessage(int primaryAddr, int cmd, boolean responseExpected) throws IOException { + MBusMessage mBusMessage = null; + + sendShortMessage(primaryAddr, cmd); + + if (responseExpected) { + mBusMessage = receiveMessage(); + } + return mBusMessage; + } + + /** + * Writes to a meter using primary addressing. Sends a data send (SND_UD) to the remote device and returns a true if + * slave sends a 0x7e else false + * + * @param primaryAddress + * the primary address of the meter to write. For secondary address use 0xfd. + * @param data + * the data to sends to the meter. + * @throws IOException + * if any kind of error (including timeout) occurs while writing to the remote device. Note that the + * connection is not closed when an IOException is thrown. + */ + public void write(int primaryAddress, byte[] data) throws IOException { + if (data == null) { + data = new byte[0]; + } + + sendLongMessage(primaryAddress, 0x73, 0x51, data.length, data); + MBusMessage mBusMessage = receiveMessage(); + + if (mBusMessage.getMessageType() != MessageType.SINGLE_CHARACTER) { + throw new IOException("Unable to select component."); + } + } + + /** + * Selects the meter with the specified secondary address. After this the meter can be read on primary address 0xfd. + * + * @param secondaryAddress + * the secondary address of the meter to select. + * @throws IOException + * if any kind of error (including timeout) occurs while trying to read the remote device. Note that the + * connection is not closed when an IOException is thrown. + */ + public void selectComponent(SecondaryAddress secondaryAddress) throws IOException { + this.secondaryAddress = secondaryAddress; + componentSelection(false); + } + + /** + * Deselects the previously selected meter. + * + * @throws IOException + * if any kind of error (including timeout) occurs while trying to read the remote device. Note that the + * connection is not closed when an IOException is thrown. + */ + public void deselectComponent() throws IOException { + if (secondaryAddress == null) { + return; + } + componentSelection(true); + secondaryAddress = null; + } + + /** + * Selection of wanted records. + * + * @param primaryAddress + * primary address of the slave + * @param dataRecords + * data record to select + * @throws IOException + * if any kind of error (including timeout) occurs while trying to read the remote device. Note that the + * connection is not closed when an IOException is thrown. + */ + public void selectForReadout(int primaryAddress, List dataRecords) throws IOException { + int i = 0; + for (DataRecord dataRecord : dataRecords) { + i += dataRecord.encode(dataRecordsAsBytes, i); + } + sendLongMessage(primaryAddress, 0x53, 0x51, i, dataRecordsAsBytes); + MBusMessage mBusMessage = receiveMessage(); + + if (mBusMessage.getMessageType() != MessageType.SINGLE_CHARACTER) { + throw new IOException("unable to select component"); + } + } + + /** + * Sends a application reset to the slave with specified primary address. + * + * @param primaryAddress + * primary address of the slave + * @throws IOException + * if any kind of error (including timeout) occurs while trying to read the remote device. Note that the + * connection is not closed when an IOException is thrown. + */ + public void resetReadout(int primaryAddress) throws IOException { + sendLongMessage(primaryAddress, 0x53, 0x50, 0, new byte[] {}); + MBusMessage mBusMessage = receiveMessage(); + + if (mBusMessage.getMessageType() != MessageType.SINGLE_CHARACTER) { + throw new IOException("Unable to reset application."); + } + } + + /** + * Sends a SND_NKE message to reset the FCB (frame counter bit). + * + * @param primaryAddress + * the primary address of the meter to reset. + * @throws IOException + * if an error occurs during the reset process. + */ + public void linkReset(int primaryAddress) throws IOException { + sendShortMessage(primaryAddress, 0x40); + MBusMessage mBusMessage = receiveMessage(); + + if (mBusMessage.getMessageType() != MessageType.SINGLE_CHARACTER) { + throw new IOException("Unable to reset link."); + } + + frameCountBits[primaryAddress] = true; + } + + private void componentSelection(boolean deselect) throws IOException { + byte[] ba = secondaryAddressAsBa(); + + // send select/deselect + if (deselect) { + sendLongMessage(0xfd, 0x53, 0x56, 8, ba); + } else { + sendLongMessage(0xfd, 0x53, 0x52, 8, ba); + } + + MBusMessage mBusMessage = receiveMessage(); + + if (mBusMessage.getMessageType() != MessageType.SINGLE_CHARACTER) { + throw new IOException("unable to select component"); + } + } + + private byte[] secondaryAddressAsBa() { + byte[] ba = new byte[8]; + + ((ByteBuffer) ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).put(secondaryAddress.asByteArray()) + .position(0)).get(ba, 0, 8); + return ba; + } + + private void sendShortMessage(int slaveAddr, int cmd) throws IOException { + synchronized (os) { + outputBuffer[0] = 0x10; + outputBuffer[1] = (byte) (cmd); + outputBuffer[2] = (byte) (slaveAddr); + outputBuffer[3] = (byte) (cmd + slaveAddr); + outputBuffer[4] = STOP_BYTE; + + verboseMessage(MessageDirection.SEND, outputBuffer, 0, 5); + + os.write(outputBuffer, 0, 5); + } + } + + void sendLongMessage(int slaveAddr, int controlField, int ci, int length, byte[] data) throws IOException { + synchronized (os) { + outputBuffer[0] = START_BYTE; + outputBuffer[1] = (byte) (length + 3); + outputBuffer[2] = (byte) (length + 3); + outputBuffer[3] = START_BYTE; + outputBuffer[4] = (byte) controlField; + outputBuffer[5] = (byte) slaveAddr; + outputBuffer[6] = (byte) ci; + + for (int i = 0; i < length; i++) { + outputBuffer[7 + i] = data[i]; + } + + outputBuffer[length + 7] = computeChecksum(length, outputBuffer); + + outputBuffer[length + 8] = STOP_BYTE; + + verboseMessage(MessageDirection.SEND, outputBuffer, 0, length + 9); + + os.write(outputBuffer, 0, length + 9); + } + } + + private static byte computeChecksum(int length, byte[] oBuffer) { + int checksum = 0; + for (int j = 4; j < (length + 7); j++) { + checksum += oBuffer[j]; + } + return (byte) (checksum & 0xff); + } + + MBusMessage receiveMessage() throws IOException { + byte[] receivedBytes; + int b0 = is.read(); + if (b0 == SINGLE_CHARACTER) { + receivedBytes = new byte[] { (byte) b0 }; + } else if ((b0 & 0xff) == START_BYTE) { + int b1 = is.readByte() & 0xff; + + /** + * The L field gives the quantity of the user data inputs plus 3 (for C,A,CI). + */ + int messageLength = b1 + 6; + + receivedBytes = new byte[messageLength]; + receivedBytes[0] = (byte) b0; + receivedBytes[1] = (byte) b1; + + is.readFully(receivedBytes, 2, messageLength - 2); + + if (receivedBytes[messageLength - 1] != STOP_BYTE) { + receivedBytes = readUntilStop(receivedBytes, messageLength); + } + // skip undesired Calling Direction Frame (echo) + if ((receivedBytes[4] & 0x40) == 0x40) { + return receiveMessage(); + } + + } else if ((b0 & 0xff) == 0x10) { + // skip undesired Short Frame (echo) + receivedBytes = new byte[4]; + is.readFully(receivedBytes, 0, 4); + return receiveMessage(); + } else { + throw new IOException(String.format("Received unknown message: %02X", b0)); + } + + verboseMessage(MessageDirection.RECEIVE, receivedBytes, 0, receivedBytes.length); + + return MBusMessage.decode(receivedBytes, receivedBytes.length); + } + + private byte[] readUntilStop(byte[] receivedBytes, int messageLength) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(messageLength); + baos.write(receivedBytes); + byte read = is.readByte(); + baos.write(read); + try { + while (read != STOP_BYTE) { + read = is.readByte(); + baos.write(read); + } + } catch (Exception e) { + // ignore + } + receivedBytes = baos.toByteArray(); + return receivedBytes; + } + + private void verboseMessage(MessageDirection direction, byte[] array, int from, int to) { + if (this.verboseMessageListener != null) { + byte[] message = Arrays.copyOfRange(array, from, to); + + VerboseMessage debugMessage = new VerboseMessage(direction, message); + this.verboseMessageListener.newVerboseMessage(debugMessage); + } + } + + public static MBusTcpBuilder newTcpBuilder(String hostAddress, int port) { + return new MBusTcpBuilder(hostAddress, port); + } + + public static class MBusTcpBuilder extends TcpBuilder { + + protected MBusTcpBuilder(String hostAddress, int port) { + super(hostAddress, port); + } + + @Override + public MBusConnection build() throws IOException { + MBusConnection mBusConnection = new MBusConnection(buildTransportLayer()); + mBusConnection.open(); + return mBusConnection; + } + } + + /** + * Create a new builder to connect to a serial. + * + * @param serialPortName + * the serial port. e.g. /dev/ttyS0. + * @return a new connection builder. + */ + public static MBusSerialBuilder newSerialBuilder(String serialPortName) { + return new MBusSerialBuilder(serialPortName); + } + + public static class MBusSerialBuilder extends SerialBuilder { + + protected MBusSerialBuilder(String serialPortName) { + super(serialPortName); + } + + @Override + public MBusConnection build() throws IOException { + MBusConnection mBusConnection = new MBusConnection(buildTransportLayer()); + mBusConnection.open(); + return mBusConnection; + } + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/MBusMessage.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/MBusMessage.java new file mode 100644 index 0000000..161001c --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/MBusMessage.java @@ -0,0 +1,131 @@ +/** + * 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; + +import java.io.IOException; + +/** + * + * Represents a wired M-Bus link layer message according to EN 13757-2. The messages are in format class FT 1.2 + * according to IEC 60870-5-2. + * + * If the M-Bus message is of frame type Long Frame it contains user data and it contains the following fields: + *
    + *
  • Length (1 byte) -
  • + *
  • Control field (1 byte) -
  • + *
  • Address field (1 byte) -
  • + *
  • CI field (1 byte) -
  • + *
  • The APDU (Variable Data Response) -
  • + *
+ */ +public class MBusMessage { + + private static final int RSP_UD_HEADER_LENGTH = 6; + + public enum MessageType { + // the other message types (e.g. SND_NKE, REQ_UD2) cannot be sent from slave to master and are therefore + // omitted. + SINGLE_CHARACTER(0xE5), + RSP_UD(0x68); + + private static final MessageType[] VALUES = values(); + private final int value; + + private MessageType(int value) { + this.value = value; + } + + private static MessageType messageTypeFor(byte value) throws IOException { + int vAsint = value & 0xff; + for (MessageType messageType : VALUES) { + if (vAsint == messageType.value) { + return messageType; + } + } + throw new IOException(String.format("Unexpected first frame byte: 0x%02X.", value)); + } + } + + private final MessageType messageType; + private final int addressField; + private final VariableDataStructure variableDataStructure; + + private MBusMessage(MessageType messageType, int addressField, VariableDataStructure variableDataStructure) { + this.messageType = messageType; + this.addressField = addressField; + this.variableDataStructure = variableDataStructure; + } + + public static MBusMessage decode(byte[] buffer, int length) throws IOException { + MessageType messageType = MessageType.messageTypeFor(buffer[0]); + int addressField; + VariableDataStructure variableDataStructure; + + switch (messageType) { + case SINGLE_CHARACTER: + addressField = 0; + variableDataStructure = null; + break; + case RSP_UD: + int messageLength = getLongFrameMessageLength(buffer, length); + checkLongFrameFields(buffer); + addressField = buffer[5] & 0xff; + variableDataStructure = new VariableDataStructure(buffer, RSP_UD_HEADER_LENGTH, messageLength, null, + null); + break; + default: + // should not occur. + throw new RuntimeException("Case not supported " + messageType); + } + + return new MBusMessage(messageType, addressField, variableDataStructure); + } + + private static void checkLongFrameFields(byte[] buffer) throws IOException { + if (buffer[1] != buffer[2]) { + throw new IOException("Length fields are not identical in long frame!"); + } + + if (buffer[3] != MessageType.RSP_UD.value) { + throw new IOException("Fourth byte of long frame was not 0x68."); + } + + int controlField = buffer[4] & 0xff; + + if ((controlField & 0xcf) != 0x08) { + throw new IOException(String.format("Unexpected control field value: 0x%02X.", controlField)); + } + } + + private static int getLongFrameMessageLength(byte[] buffer, int length) throws IOException { + int messageLength = buffer[1] & 0xff; + + if (messageLength != length - RSP_UD_HEADER_LENGTH) { + throw new IOException("Wrong length field in frame header does not match the buffer length. Length field: " + + messageLength + ", buffer length: " + length + " !"); + } + return messageLength; + } + + public int getAddressField() { + return addressField; + } + + public MessageType getMessageType() { + return messageType; + } + + public VariableDataStructure getVariableDataResponse() { + return variableDataStructure; + } + + @Override + public String toString() { + return new StringBuilder().append("message type: ").append(messageType).append("\naddress field: ") + .append(addressField & 0xff).append("\nVariable Data Structure:\n").append(variableDataStructure) + .toString(); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/ScanSecondaryAddress.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/ScanSecondaryAddress.java new file mode 100644 index 0000000..6e38b5b --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/ScanSecondaryAddress.java @@ -0,0 +1,227 @@ +/** + * 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; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.text.MessageFormat; +import java.util.LinkedList; +import java.util.List; + +import org.openmuc.jmbus.MBusMessage.MessageType; + +class ScanSecondaryAddress { + + private static final int MAX_LENGTH = 16; + private static int pos = 0; + private static byte[] value = new byte[MAX_LENGTH]; + + public static List scan(MBusConnection mBusConnection, String wildcardMask, + SecondaryAddressListener secondaryAddressListener, long waitTime) throws IOException { + + List secondaryAddresses = new LinkedList<>(); + + boolean stop = false; + boolean collision = false; + + wildcardMask = flipString(wildcardMask); + wildcardMask += "ffffffff"; + + for (int i = 0; i < MAX_LENGTH; ++i) { + value[i] = Byte.parseByte(wildcardMask.substring(i, i + 1), 16); + } + + pos = wildcardMask.indexOf('f'); + if (pos == 8 || pos < 0) { + pos = 7; + } + value[pos] = 0; + + while (!stop) { + String msg = MessageFormat.format("scan with wildcard: {0}", HexUtils.bytesToHex(toSendByteArray(value))); + notifyScanMsg(secondaryAddressListener, msg); + + SecondaryAddress secondaryAddessesWildCard = SecondaryAddress.newFromLongHeader(toSendByteArray(value), 0); + SecondaryAddress readSecondaryAddress = null; + + if (scanSelection(mBusConnection, secondaryAddessesWildCard)) { + sleep(waitTime); + + try { + readSecondaryAddress = mBusConnection.read(0xfd).getSecondaryAddress(); + } catch (InterruptedIOException e) { + notifyScanMsg(secondaryAddressListener, "Read (REQ_UD2) TimeoutException"); + collision = false; + } catch (IOException e) { + notifyScanMsg(secondaryAddressListener, "Read (REQ_UD2) IOException / Collision"); + collision = true; + } + sleep(waitTime); + + if (collision) { + if (pos < 7) { + ++pos; + value[pos] = 0; + } else { + stop = handler(); + } + collision = false; + } else { + if (readSecondaryAddress != null) { + String message = "Detected Device:\n" + readSecondaryAddress.toString(); + notifyScanMsg(secondaryAddressListener, message); + secondaryAddresses.add(readSecondaryAddress); + if (secondaryAddressListener != null) { + secondaryAddressListener.newDeviceFound(readSecondaryAddress); + } + stop = handler(); + } else { + + notifyScanMsg(secondaryAddressListener, + "Problem to decode secondary address. Perhaps a collision."); + if (pos < 7) { + ++pos; + value[pos] = 0; + } else { + stop = handler(); + } + collision = false; + } + } + } else { + stop = handler(); + } + } + if (mBusConnection != null) { + mBusConnection.close(); + } + return secondaryAddresses; + } + + /** + * Scans if any device response to the given wildcard. + * + * @param mBusConnection + * object to the open mbus connection + * + * @param wildcard + * secondary address wildcard e.g. f1ffffffffffffff + * @return true if any device response else false + * @throws IOException + */ + private static boolean scanSelection(MBusConnection mBusConnection, SecondaryAddress wildcard) throws IOException { + ByteBuffer bf = ByteBuffer.allocate(8); + byte[] ba = new byte[8]; + + bf.order(ByteOrder.LITTLE_ENDIAN); + + bf.put(wildcard.asByteArray()); + + bf.position(0); + bf.get(ba, 0, 8); + + mBusConnection.sendLongMessage(0xfd, 0x53, 0x52, 8, ba); + + try { + MBusMessage mBusMessage = mBusConnection.receiveMessage(); + + return mBusMessage.getMessageType() == MessageType.SINGLE_CHARACTER; + } catch (InterruptedIOException e) { + return false; + } catch (IOException e) { + return true; + } + } + + private static void notifyScanMsg(SecondaryAddressListener secondaryAddressListener, String message) { + if (secondaryAddressListener != null) { + secondaryAddressListener.newScanMessage(message); + } + } + + private static boolean handler() { + boolean stop; + + ++value[pos]; + + if (value[pos] < 10) { + stop = false; + } else { + if (pos > 0) { + --pos; + ++value[pos]; + setFValue(); + + while (value[pos] > 10) { + --pos; + ++value[pos]; + setFValue(); + } + stop = false; + } else { + stop = true; + } + } + + return stop; + } + + private static void setFValue() { + for (int i = pos + 1; i < 8; ++i) { + value[i] = 0xf; + } + } + + private static byte[] toSendByteArray(byte[] value) { + byte[] sendByteArray = new byte[8]; + + for (int i = 0; i < MAX_LENGTH; ++i) { + + if (i % 2 > 0) { + sendByteArray[i / 2] |= value[i] << 4; + } else { + sendByteArray[i / 2] |= value[i]; + } + } + return sendByteArray; + } + + /** + * Flips character pairs.
+ * from 01253fffffffffff to 1052f3ffffffffff + * + * @param value + * a string value like 01253fffffffffff + * @return a fliped string value. + */ + private static String flipString(String value) { + StringBuilder flipped = new StringBuilder(); + + for (int i = 0; i < value.length(); i += 2) { + flipped.append(value.charAt(i + 1)); + flipped.append(value.charAt(i)); + } + return flipped.toString(); + } + + /** + * Don't let anyone instantiate this class. + */ + private ScanSecondaryAddress() { + } + + private static void sleep(long millis) throws IOException { + if (millis > 0) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + throw new IOException(e); + } + } + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/SecondaryAddress.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/SecondaryAddress.java new file mode 100644 index 0000000..515bf42 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/SecondaryAddress.java @@ -0,0 +1,229 @@ +/** + * 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; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; + +/** + * This class represents a secondary address. Use the static initializer to initialize the + */ +public class SecondaryAddress implements Comparable { + + private static final int SECONDARY_ADDRESS_LENGTH = 8; + + private static final int ID_NUMBER_LENGTH = 4; + + private final String manufacturerId; + private final Bcd deviceId; + private final int version; + private final DeviceType deviceType; + private final byte[] bytes; + private final int hashCode; + private final boolean isLongHeader; + + /** + * Instantiate a new secondary address within a long header. + * + * @param buffer + * the byte buffer. + * @param offset + * the offset. + * @return a new secondary address. + */ + public static SecondaryAddress newFromLongHeader(byte[] buffer, int offset) { + return new SecondaryAddress(buffer, offset, true); + } + + /** + * Instantiate a new secondary address within a wireless M-Bus link layer header. + * + * @param buffer + * the byte buffer. + * @param offset + * the offset. + * @return a new secondary address. + */ + public static SecondaryAddress newFromWMBusHeader(byte[] buffer, int offset) { + return new SecondaryAddress(buffer, offset, false); + } + + /** + * Instantiate a new secondary address for a manufacturer ID. + * + * @param idNumber + * ID number. + * @param manufactureId + * manufacturer ID. + * @param version + * the version. + * @param media + * the media. + * @return a new secondary address. + * @throws NumberFormatException + * if the idNumber is not long enough. + */ + public static SecondaryAddress newFromManufactureId(byte[] idNumber, String manufactureId, byte version, byte media, + boolean longHeader) throws NumberFormatException { + if (idNumber.length != ID_NUMBER_LENGTH) { + throw new NumberFormatException("Wrong length of ID. Length must be " + ID_NUMBER_LENGTH + " byte."); + } + + byte[] mfId = encodeManufacturerId(manufactureId); + + ByteBuffer byteBuffer = ByteBuffer.allocate(idNumber.length + mfId.length + 1 + 1); + if (longHeader) { + byteBuffer.put(idNumber).put(mfId); + } else { + byteBuffer.put(mfId).put(idNumber); + } + byte[] buffer = byteBuffer.put(version).put(media).array(); + + return new SecondaryAddress(buffer, 0, true); + } + + /** + * The {@link SecondaryAddress} as byte array. + * + * @return the byte array (octet string) representation. + */ + public byte[] asByteArray() { + return bytes; + } + + /** + * Get the manufacturer ID. + * + * @return the ID. + */ + public String getManufacturerId() { + return manufacturerId; + } + + /** + * Returns the device ID. This is secondary address of the device. + * + * @return the device ID + */ + public Bcd getDeviceId() { + return deviceId; + } + + /** + * Returns the device type (e.g. gas, water etc.) + * + * @return the device type + */ + public DeviceType getDeviceType() { + return deviceType; + } + + /** + * Get the version. + * + * @return the version. + */ + public int getVersion() { + return version; + } + + public boolean isLongHeader() { + return isLongHeader; + } + + @Override + public String toString() { + return new StringBuilder().append("manufacturer ID: ").append(manufacturerId).append(", device ID: ") + .append(deviceId).append(", device version: ").append(version).append(", device type: ") + .append(deviceType).append(", as bytes: ").append(HexUtils.bytesToHex(bytes)).toString(); + } + + @Override + public int hashCode() { + return this.hashCode; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof SecondaryAddress)) { + return false; + } + + SecondaryAddress other = (SecondaryAddress) obj; + + return Arrays.equals(this.bytes, other.bytes); + } + + @Override + public int compareTo(SecondaryAddress sa) { + return Integer.compare(hashCode(), sa.hashCode()); + } + + private SecondaryAddress(byte[] buffer, int offset, boolean longHeader) { + this.bytes = Arrays.copyOfRange(buffer, offset, offset + SECONDARY_ADDRESS_LENGTH); + + this.hashCode = Arrays.hashCode(this.bytes); + this.isLongHeader = longHeader; + + try (ByteArrayInputStream is = new ByteArrayInputStream(this.bytes)) { + if (longHeader) { + this.deviceId = decodeDeviceId(is); + this.manufacturerId = decodeManufacturerId(is); + } else { + this.manufacturerId = decodeManufacturerId(is); + this.deviceId = decodeDeviceId(is); + } + this.version = is.read() & 0xff; + this.deviceType = DeviceType.getInstance(is.read() & 0xff); + } catch (IOException e) { + // should not occur + throw new RuntimeException(e); + } + } + + private static String decodeManufacturerId(ByteArrayInputStream is) { + int manufacturerIdAsInt = (is.read() & 0xff) + (is.read() << 8); + char c = (char) ((manufacturerIdAsInt & 0x1f) + 64); + manufacturerIdAsInt = (manufacturerIdAsInt >> 5); + char c1 = (char) ((manufacturerIdAsInt & 0x1f) + 64); + manufacturerIdAsInt = (manufacturerIdAsInt >> 5); + char c2 = (char) ((manufacturerIdAsInt & 0x1f) + 64); + + return new StringBuilder().append(c2).append(c1).append(c).toString(); + } + + private static byte[] encodeManufacturerId(String manufactureId) { + if (manufactureId.length() != 3) { + return new byte[] { 0, 0 }; + } + + manufactureId = manufactureId.toUpperCase(); + char[] manufactureIdArray = manufactureId.toCharArray(); + int manufacturerIdAsInt = (manufactureIdArray[0] - 64) * 32 * 32; + manufacturerIdAsInt += (manufactureIdArray[1] - 64) * 32; + manufacturerIdAsInt += (manufactureIdArray[2] - 64); + + ByteBuffer buf = ByteBuffer.allocate(2); + buf.order(ByteOrder.LITTLE_ENDIAN); + buf.putShort((short) manufacturerIdAsInt); + + return buf.array(); + } + + private static Bcd decodeDeviceId(ByteArrayInputStream is) throws IOException { + int msgSize = 4; + byte[] idArray = new byte[msgSize]; + int actual = is.read(idArray); + + if (msgSize != actual) { + throw new IOException("Failed to read BCD data. Data missing."); + } + return new Bcd(idArray); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/SecondaryAddressListener.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/SecondaryAddressListener.java new file mode 100644 index 0000000..5309804 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/SecondaryAddressListener.java @@ -0,0 +1,30 @@ +/** + * 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; + +import java.util.EventListener; + +/** + * Listener to get secondary address scan message e.g. for console tools and to get messages. + */ +public interface SecondaryAddressListener extends EventListener { + + /** + * New scan message. + * + * @param message + * messages from scan secondary address + */ + void newScanMessage(String message); + + /** + * New device found. + * + * @param secondaryAddress + * secondary address of detected device + */ + void newDeviceFound(SecondaryAddress secondaryAddress); +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/VariableDataStructure.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/VariableDataStructure.java new file mode 100644 index 0000000..88f45cf --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/VariableDataStructure.java @@ -0,0 +1,495 @@ +/** + * 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; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Representation of the data transmitted in RESP-UD (M-Bus) and SND-NR (wM-Bus) messages. + * + * @see #decode() + */ +public class VariableDataStructure { + + private static final ConcurrentHashMap> deviceHistory = new ConcurrentHashMap<>(); + + private final byte[] buffer; + private final int offset; + private final int length; + private byte[] header = new byte[0]; + private final SecondaryAddress linkLayerSecondaryAddress; + private final Map keyMap; + + private SecondaryAddress secondaryAddress; + private int accessNumber; + private int status; + + /* Extended Link Layer (ELL) (0x8d) specific */ + private byte communicationControl; + private byte[] sessionNumber; + /* End of ELL specific */ + + private EncryptionMode encryptionMode; + private int numberOfEncryptedBlocks; + private byte[] manufacturerData = new byte[0]; + private byte[] vdr = new byte[0]; + private boolean moreRecordsFollow = false; + + private boolean decoded = false; + + private List dataRecords; + + private int ciField; + + public VariableDataStructure(byte[] buffer, int offset, int length, SecondaryAddress linkLayerSecondaryAddress, + Map keyMap) { + this.buffer = buffer; + this.offset = offset; + this.length = length; + this.linkLayerSecondaryAddress = linkLayerSecondaryAddress; + this.keyMap = keyMap; + this.dataRecords = new LinkedList<>(); + } + + /** + * This method is used to + * + * @throws DecodingException + */ + public void decode() throws DecodingException { + if (!decoded) { + try { + ciField = readUnsignedByte(buffer, offset); + + switch (ciField) { + case 0x72: + decodeLongHeaderData(); + break; + case 0x78: /* no header */ + encryptionMode = EncryptionMode.NONE; + decodeDataRecords(buffer, offset + 1, length - 1); + break; + case 0x7a: /* short header */ + decodeShortHeader(); + break; + case 0x8d: /* Extended Link Layer */ + decodeExtendedLinkLayer(buffer, offset + 1); // 6 bytes header + CRC + header = Arrays.copyOfRange(buffer, offset, offset + 7); // don't include CRC + vdr = new byte[length - 7]; + System.arraycopy(buffer, offset + 7, vdr, 0, length - 7); + if (encryptionMode.equals(EncryptionMode.AES_128)) { + decryptMessage(getKey()); + } + + if ((vdr[2] & 0xff) == 0x78) { + decodeDataRecords(vdr, 3, length - 10); + } else if ((vdr[2] & 0xff) == 0x79) { + decodeShortFrame(vdr, 3, length - 10); + } + break; + case 0x33: + String msg = String.format( + "Received telegram with CI 0x33. Decoding not implemented. Device Serial: %s, Manufacturer: %s.", + linkLayerSecondaryAddress.getDeviceId().toString(), + linkLayerSecondaryAddress.getManufacturerId()); + throw new DecodingException(msg); + default: + String strFormat = "Unable to decode message with this CI Field: 0x%02X."; + if ((ciField >= 0xA0) && (ciField <= 0xB7)) { + strFormat = "Manufacturer specific CI: 0x%02X."; + } + + throw new DecodingException(String.format(strFormat, ciField)); + } + } catch (RuntimeException e) { + throw new DecodingException(e); + } + decoded = true; + } + } + + private void decodeShortHeader() throws DecodingException { + decodeShortHeader(buffer, offset + 1); + + switch (encryptionMode) { + case NONE: + decodeDataRecords(buffer, offset + 5, length - 5); + break; + case AES_CBC_IV: + decryptAesCbcIv(buffer, offset + 5, numberOfEncryptedBlocks * 16); + break; + case AES_128: + case AES_CBC_IV_0: + case DES_CBC: + case DES_CBC_IV: + case RESERVED_04: + case RESERVED_06: + case RESERVED_08: + case RESERVED_09: + case RESERVED_10: + case RESERVED_11: + case RESERVED_12: + case RESERVED_14: + case RESERVED_15: + case TLS: + default: + throw new DecodingException("Unsupported encryption mode used: " + encryptionMode); + } + } + + private void decryptAesCbcIv(byte[] buffer, int offset, int encryptedDataLength) throws DecodingException { + vdr = new byte[encryptedDataLength]; + + System.arraycopy(buffer, offset, vdr, 0, encryptedDataLength); + + byte[] key = keyMap.get(linkLayerSecondaryAddress); + if (key == null) { + String msg = MessageFormat.format( + "Unable to decode encrypted payload. \nSecondary address key was not registered: \n{0}", + linkLayerSecondaryAddress); + throw new DecodingException(msg); + } + + decodeDataRecords(decryptMessage(key), 0, encryptedDataLength); + } + + private void decodeLongHeaderData() throws DecodingException { + final int headerLength = 13; + header = Arrays.copyOfRange(buffer, offset, offset + headerLength); + + secondaryAddress = SecondaryAddress.newFromLongHeader(buffer, offset + 1); + + decodeShortHeader(buffer, offset + 1 + 8); + + vdr = new byte[length - headerLength]; + System.arraycopy(buffer, offset + headerLength, vdr, 0, length - headerLength); + + switch (encryptionMode) { + case NONE: + // nothing to do + break; + case AES_CBC_IV: + decryptMessage(getKey()); + break; + case AES_128: + case AES_CBC_IV_0: + case DES_CBC: + case DES_CBC_IV: + case RESERVED_04: + case RESERVED_06: + case RESERVED_08: + case RESERVED_09: + case RESERVED_10: + case RESERVED_11: + case RESERVED_12: + case RESERVED_14: + case RESERVED_15: + case TLS: + default: + throw new DecodingException("Unsupported encryption mode used: " + encryptionMode); + } + decodeDataRecords(vdr, 0, length - headerLength); + } + + public SecondaryAddress getSecondaryAddress() { + return secondaryAddress; + } + + public int getAccessNumber() { + return accessNumber; + } + + public EncryptionMode getEncryptionMode() { + return encryptionMode; + } + + public byte[] getManufacturerData() { + return manufacturerData; + } + + public int getNumberOfEncryptedBlocks() { + return numberOfEncryptedBlocks; + } + + public int getStatus() { + return status; + } + + public List getDataRecords() { + return dataRecords; + } + + public boolean moreRecordsFollow() { + return moreRecordsFollow; + } + + private void decodeExtendedLinkLayer(byte[] buffer, int offset) { + int i = offset; + + communicationControl = buffer[i++]; + accessNumber = buffer[i++]; + sessionNumber = new byte[] { buffer[i++], buffer[i++], buffer[i++], buffer[i++] }; + encryptionMode = EncryptionMode.getInstance(sessionNumber[3] >> 5); + byte[] checksum = new byte[] { buffer[i++], buffer[i++] }; + + byte[] crc = CRC16.calculateCrc16(Arrays.copyOfRange(buffer, i, buffer.length - 1)); + if (checksum[0] == crc[0] && checksum[1] == crc[1]) { + encryptionMode = EncryptionMode.NONE; + } + } + + private void decodeShortHeader(byte[] buffer, int offset) { + int i = offset; + + accessNumber = readUnsignedByte(buffer, i++); + status = readUnsignedByte(buffer, i++); + numberOfEncryptedBlocks = (buffer[i++] & 0xf0) >> 4; + encryptionMode = EncryptionMode.getInstance(buffer[i++] & 0x0f); + + if (msgIsNotEnc(buffer, i) || numberOfEncryptedBlocks == 0) { + encryptionMode = EncryptionMode.NONE; + } + } + + private static boolean msgIsNotEnc(byte[] buffer, int i) { + byte b = buffer[i]; + byte b2 = buffer[i + 1]; + return b == (byte) 0x2f && b2 == (byte) 0x02; + } + + private static int readUnsignedByte(byte[] msg, int i) { + return msg[i] & 0xff; + } + + public byte[] getHeader() { + return this.header; + } + + private void decodeDataRecords(byte[] buffer, int offset, int length) throws DecodingException { + int i = offset; + + while (i < offset + length - 2) { + + if ((buffer[i] & 0xef) == 0x0f) { + // manufacturer specific data + + moreRecordsFollow = (buffer[i] & 0x10) == 0x10; + + manufacturerData = Arrays.copyOfRange(buffer, i + 1, offset + length - 2); + return; + } + + if (buffer[i] == 0x2f) { + // this is a fill byte because some encryption mechanisms need multiples of 8 bytes to encode data + i++; + continue; + } + + DataRecord dataRecord = new DataRecord(); + i = dataRecord.decode(buffer, i); + + dataRecords.add(dataRecord); + } + + if (linkLayerSecondaryAddress != null) { + deviceHistory.put(linkLayerSecondaryAddress, dataRecords); + } + } + + private void decodeShortFrame(byte[] data, int offset, int length) throws DecodingException { + if (!deviceHistory.containsKey(linkLayerSecondaryAddress)) { + deviceHistory.put(linkLayerSecondaryAddress, new LinkedList()); + } + + ByteBuffer buf = ByteBuffer.wrap(data, offset, length); + buf.order(ByteOrder.nativeOrder()); + + // skip checksum data + buf.position(4); + + this.dataRecords = deviceHistory.get(linkLayerSecondaryAddress); + + ListIterator iter = this.dataRecords.listIterator(); + while (iter.hasNext()) { + DataRecord dr = iter.next(); + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + os.write(dr.getDib()); + os.write(dr.getVib()); + + int tempOffset = dr.getDib().length + dr.getVib().length; + + // This might not be right + int dataLegth = tempOffset + dr.getDataLength(); + byte[] b = new byte[dataLegth - tempOffset]; + buf.get(b); + os.write(b); + + DataRecord newDataRecord = new DataRecord(); + newDataRecord.decode(os.toByteArray(), 0); + iter.set(newDataRecord); + } catch (IOException e) { + // ignore + } + + } + } + + public byte[] decryptMessage(byte[] key) throws DecodingException { + + if (encryptionMode == EncryptionMode.NONE) { + return vdr; + } + + if (key == null) { + throw new DecodingException("AES key for given address not specified."); + } + + final int len = numberOfEncryptedBlocks * 16; + + if (len > vdr.length) { + throw new DecodingException("Number of encrypted exceeds payload size!"); + } + + switch (encryptionMode) { + case AES_CBC_IV: + decryptAesCbcIv(key, len); + break; + case AES_128: + decryptAes128(key, len); + break; + default: + throw new DecodingException("Unsupported encryption mode: " + encryptionMode); + } + + return vdr; + } + + private void decryptAes128(byte[] key, final int len) throws DecodingException { + byte[] iv = createIvKamstrup(); + byte[] result = AesCrypt.newAesCtrCrypt(key, iv).decrypt(vdr, len); + + byte[] crc = CRC16.calculateCrc16(Arrays.copyOfRange(result, 2, result.length)); + + if (result[0] != crc[0] || result[1] != crc[1]) { + throw new DecodingException(newDecyptionExceptionMsg()); + } + vdr = result; + } + + private void decryptAesCbcIv(byte[] key, final int len) throws DecodingException { + byte[] iv = createIv(); + byte[] result = AesCrypt.newAesCrypt(key, iv).decrypt(this.vdr, len); + + if (!(result[0] == 0x2f && result[1] == 0x2f)) { + throw new DecodingException(newDecyptionExceptionMsg()); + } + System.arraycopy(result, 0, vdr, 0, len); + } + + private String newDecyptionExceptionMsg() { + String deviceId = linkLayerSecondaryAddress.getDeviceId().toString(); + String manId = linkLayerSecondaryAddress.getManufacturerId(); + return String.format("%s - %s - Decryption unsuccessful! Wrong AES/CTR Key?", deviceId, manId); + } + + private byte[] createIv() { + byte[] iv = new byte[16]; + byte[] saBytes = linkLayerSecondaryAddress.asByteArray(); + + if (linkLayerSecondaryAddress.isLongHeader()) { + System.arraycopy(saBytes, 0, iv, 4, 2); // Manufacture + System.arraycopy(saBytes, 2, iv, 0, 4); // Identification + System.arraycopy(saBytes, 6, iv, 6, 2); // Version and Device Type + } else if (ciField == 0x72) { + saBytes = secondaryAddress.asByteArray(); + System.arraycopy(saBytes, 0, iv, 2, 4); // Identification + System.arraycopy(saBytes, 4, iv, 0, 2); // Manufacture + System.arraycopy(saBytes, 6, iv, 6, 2); // Version and Device Type + } else { + System.arraycopy(saBytes, 0, iv, 0, 8); + } + + for (int i = 8; i < iv.length; i++) { + iv[i] = (byte) accessNumber; + } + + return iv; + } + + private byte[] createIvKamstrup() throws DecodingException { + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + + os.write(linkLayerSecondaryAddress.asByteArray(), 0, 8); + /* set hop count to 0 in case a repeater is used */ + os.write(communicationControl & ~(1 << 4)); + os.write(sessionNumber); + os.write(new byte[3]); // 3 * 0x00 + + return os.toByteArray(); + } catch (IOException e) { + throw new DecodingException("Unable to create initial vector for decryption.", e); + } + } + + private byte[] getKey() throws DecodingException { + byte[] key = keyMap.get(linkLayerSecondaryAddress); + if (key != null) { + return key; + } + + String msg = "Unable to decode encrypted payload because no key for the following secondary address was registered: " + + linkLayerSecondaryAddress; + throw new DecodingException(msg); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + if (!decoded) { + if (dataRecords.isEmpty()) { + int from = offset; + int to = from + length; + String hexString = HexUtils.bytesToHex(Arrays.copyOfRange(buffer, from, to)); + return MessageFormat.format("VariableDataResponse has not been decoded. Bytes:\n{0}", hexString); + } else { + builder.append("VariableDataResponse has not been fully decoded. " + dataRecords.size() + + " data records decoded.\n"); + } + } + + if (secondaryAddress != null) { + builder.append("Secondary address: {").append(secondaryAddress).append("}\n"); + } + + builder.append("Short Header: {Access No.: ").append(accessNumber).append(", status: ").append(status) + .append(", encryption mode: ").append(encryptionMode).append(", number of encrypted blocks: ") + .append(numberOfEncryptedBlocks).append("}"); + + for (DataRecord dataRecord : dataRecords) { + builder.append("\n").append(dataRecord.toString()); + } + + if (manufacturerData.length != 0) { + String manDaraHexStr = HexUtils.bytesToHex(manufacturerData); + builder.append("\nManufacturer specific bytes:\n").append(manDaraHexStr); + } + + if (moreRecordsFollow) { + builder.append("\nMore records follow ..."); + } + return builder.toString(); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/VerboseMessage.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/VerboseMessage.java new file mode 100644 index 0000000..958c77f --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/VerboseMessage.java @@ -0,0 +1,48 @@ +/** + * 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; + +/** + * This class represents a verbose message. This may be useful to debug a connection. + * + * @see VerboseMessageListener + */ +public class VerboseMessage { + + private final MessageDirection messageDirection; + private final byte[] message; + + VerboseMessage(MessageDirection messageDirection, byte[] message) { + this.messageDirection = messageDirection; + this.message = message; + } + + /** + * Get the message data. + * + * @return an octet string. + */ + public byte[] getMessage() { + return message; + } + + /** + * Get the direction of the message. + * + * @return the message direction. + */ + public MessageDirection getMessageDirection() { + return messageDirection; + } + + /** + * The direction of message. + */ + public enum MessageDirection { + SEND, + RECEIVE; + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/VerboseMessageListener.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/VerboseMessageListener.java new file mode 100644 index 0000000..8c6d03d --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/VerboseMessageListener.java @@ -0,0 +1,20 @@ +/** + * 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; + +import java.util.EventListener; + +/** + * + * @see MBusConnection#setVerboseMessageListener(VerboseMessageListener) + */ +public interface VerboseMessageListener extends EventListener { + /** + * + * @param debugMessage + */ + void newVerboseMessage(VerboseMessage debugMessage); +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/package-info.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/package-info.java new file mode 100644 index 0000000..a69ebc0 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/package-info.java @@ -0,0 +1,11 @@ +/** + * 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/. + */ +/** + * Main jmbus package. + * + * @see org.openmuc.jmbus.MBusConnection + */ +package org.openmuc.jmbus; diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/Builder.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/Builder.java new file mode 100644 index 0000000..70c2b78 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/Builder.java @@ -0,0 +1,64 @@ +/** + * 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.transportlayer; + +import java.io.IOException; + +/** + * A abstract builder to an active M-Bus connection. + * + * @param + * the resulting connection after calling {@link #build()}. + * @param + * the inheriting builder type. + */ +public abstract class Builder> { + + private int timeout; + + protected Builder() { + this.timeout = 500; + } + + /** + * Set the connection timeout. The timeout must be ≥ zero. A timeout of zero is interpreted as infinite timeout, + * + * @param timeout + * a timeout in milliseconds. + * @return the builder itself. + */ + public B setTimeout(int timeout) { + this.timeout = timeout; + return self(); + } + + int getTimeout() { + return timeout; + } + + @SuppressWarnings("unchecked") + protected B self() { + return (B) this; + } + + /** + * Build the TransportLayer with the given settings. + * + * @return TransportLayer to connect to the M-Bus device + * @throws IOException + * if an I/O exception occurred. + */ + protected abstract TransportLayer buildTransportLayer() throws IOException; + + /** + * This return an active M-Bus connection. + * + * @return a new active M-Bus connection. + * @throws IOException + * if an I/O exception occurred opening the connection to the remote device. + */ + public abstract C build() throws IOException; +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/SerialBuilder.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/SerialBuilder.java new file mode 100644 index 0000000..5658071 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/SerialBuilder.java @@ -0,0 +1,109 @@ +/** + * 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.transportlayer; + +import org.openmuc.jrxtx.DataBits; +import org.openmuc.jrxtx.Parity; +import org.openmuc.jrxtx.SerialPortBuilder; +import org.openmuc.jrxtx.StopBits; + +/** + * Connection builder for serial connections. + */ +public abstract class SerialBuilder> extends Builder { + + private String serialPortName; + private int baudrate; + + private DataBits dataBits; + private StopBits stopBits; + private Parity parity; + + /** + * Constructor of the Serial Settings Builder, for connecting M-Bus devices over serial connections like RS232 and + * RS485. With default settings. + * + * @param serialPortName + * examples for serial port identifiers are on Linux "/dev/ttyS0" or "/dev/ttyUSB0" and on Windows "COM1" + **/ + protected SerialBuilder(String serialPortName) { + this.serialPortName = serialPortName; + + this.baudrate = 2400; + this.dataBits = DataBits.DATABITS_8; + this.stopBits = StopBits.STOPBITS_1; + this.parity = Parity.EVEN; + } + + /** + * Sets the baudrate of the device + * + * @param baudrate + * the baud rate to use. + * @return the builder itself + */ + public S setBaudrate(int baudrate) { + this.baudrate = baudrate; + return self(); + } + + /** + * Sets the serial port name of the device + * + * @param serialPortName + * examples for serial port identifiers are on Linux {@code "/dev/ttyS0"} or {@code "/dev/ttyUSB0"} and + * on Windows {@code "COM1"}. + * @return the builder itself. + */ + public S setSerialPortName(String serialPortName) { + this.serialPortName = serialPortName; + return self(); + } + + /** + * Sets the number of DataBits, default is {@link DataBits#DATABITS_8}. + * + * @param dataBits + * the new number of databits. + * @return the builder itself. + */ + public S setDataBits(DataBits dataBits) { + this.dataBits = dataBits; + return self(); + } + + /** + * Sets the stop bits, default is 1 + * + * @param stopBits + * Possible values are 1, 1.5 or 2 + * @return the builder itself + */ + public S setStopBits(StopBits stopBits) { + this.stopBits = stopBits; + return self(); + } + + /** + * Sets the parity, default is NONE + * + * @param parity + * Possible values are NONE, EVEN, ODD, SPACE or MARK. + * @return the builder itself + */ + public S setParity(Parity parity) { + this.parity = parity; + return self(); + } + + @Override + protected TransportLayer buildTransportLayer() { + SerialPortBuilder serialPortBuilder = SerialPortBuilder.newBuilder(serialPortName).setBaudRate(baudrate) + .setDataBits(dataBits).setStopBits(stopBits).setStopBits(stopBits).setParity(parity); + + return new SerialLayer(getTimeout(), serialPortBuilder); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/SerialLayer.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/SerialLayer.java new file mode 100644 index 0000000..5fc272c --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/SerialLayer.java @@ -0,0 +1,73 @@ +/** + * 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.transportlayer; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.openmuc.jrxtx.SerialPort; +import org.openmuc.jrxtx.SerialPortBuilder; + +class SerialLayer implements TransportLayer { + private final SerialPortBuilder serialPortBuilder; + private final int timeout; + + private DataOutputStream os; + private DataInputStream is; + private SerialPort serialPort; + + public SerialLayer(int timeout, SerialPortBuilder serialPortBuilder) { + this.serialPortBuilder = serialPortBuilder; + this.timeout = timeout; + } + + @Override + public void open() throws IOException { + serialPort = serialPortBuilder.build(); + serialPort.setSerialPortTimeout(timeout); + + os = new DataOutputStream(serialPort.getOutputStream()); + is = new DataInputStream(serialPort.getInputStream()); + } + + @Override + public DataOutputStream getOutputStream() { + return os; + } + + @Override + public DataInputStream getInputStream() { + return is; + } + + @Override + public void close() { + if (serialPort == null || serialPort.isClosed()) { + return; + } + try { + serialPort.close(); + } catch (IOException e) { + // ignore + } + } + + @Override + public boolean isClosed() { + return serialPort == null; + } + + @Override + public void setTimeout(int timeout) throws IOException { + serialPort.setSerialPortTimeout(timeout); + } + + @Override + public int getTimeout() { + return serialPort.getSerialPortTimeout(); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/TcpBuilder.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/TcpBuilder.java new file mode 100644 index 0000000..8a7c6cb --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/TcpBuilder.java @@ -0,0 +1,73 @@ +/** + * 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.transportlayer; + +/** + * Connection builder for TCP connections.
+ * M-Bus over TCP has the same data like M-Bus over Serial connection, only the transport layer and below differs. + */ +public abstract class TcpBuilder> extends Builder { + + private String hostAddress; + private int port; + private int connectionTimeout = 10000; // 10 s + + /** + * Constructor of the TCP/IP Settings Builder, for connecting M-Bus devices over TCP/IP. + * + * @param hostAddress + * examples for IP host address port are "127.0.0.1, localhost, ..." + * @param port + * the TCP port of the host + **/ + protected TcpBuilder(String hostAddress, int port) { + setHostAddress(hostAddress); + setPort(port); + } + + /** + * Sets the TCP port of this communication + * + * @param port + * the TCP port of the host + * @return the builder itself + * + **/ + public S setPort(int port) { + this.port = port; + return self(); + } + + /** + * Sets the IP host address of the device + * + * @param hostAddress + * examples for IP host address port are "127.0.0.1, localhost, ..." + * @return the builder itself + */ + public S setHostAddress(String hostAddress) { + this.hostAddress = hostAddress; + return self(); + } + + /** + * Sets the TCP connection timeout. + * + * @param connectionTimeout + * the TCP connection timeout + * @return the builder itself + * + **/ + public S setConnectionTimeout(int connectionTimeout) { + this.connectionTimeout = connectionTimeout; + return self(); + } + + @Override + protected TransportLayer buildTransportLayer() { + return new TcpLayer(hostAddress, port, connectionTimeout, getTimeout()); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/TcpLayer.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/TcpLayer.java new file mode 100644 index 0000000..73a7612 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/TcpLayer.java @@ -0,0 +1,116 @@ +/** + * 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.transportlayer; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.text.MessageFormat; + +class TcpLayer implements TransportLayer { + private final String hostAddress; + private final int port; + private final int timeout; + private final int connectionTimeout; + + private Socket client; + private DataOutputStream os; + private DataInputStream is; + + TcpLayer(String hostAddress, int port, int connectionTimeout, int timeout) { + this.hostAddress = hostAddress; + this.port = port; + this.timeout = timeout; + this.connectionTimeout = connectionTimeout; + } + + @Override + public void open() throws IOException { + InetAddress hostname = InetAddress.getByName(hostAddress); + + try { + SocketAddress socketAddress = new InetSocketAddress(hostname, port); + this.client = new Socket(); + this.client.connect(socketAddress, connectionTimeout); + this.client.setSoTimeout(timeout); + } catch (IOException e) { + String msg = MessageFormat.format("Connecting to {0}:{1} failed.", hostname, port); + throw new IOException(msg, e); + } + + initialiseIOStreams(); + } + + private void initialiseIOStreams() throws IOException { + try { + this.os = new DataOutputStream(client.getOutputStream()); + this.is = new DataInputStream(client.getInputStream()); + } catch (IOException e) { + close(); + throw new IOException("Error getting output or input stream from TCP connection.", e); + } + flushInputStream(); + } + + @Override + public void close() { + if (client == null || client.isClosed()) { + return; + } + try { + client.close(); + } catch (IOException e) { + // ignore this here + } + client = null; + } + + @Override + public DataOutputStream getOutputStream() { + return os; + } + + @Override + public DataInputStream getInputStream() { + return is; + } + + @Override + public boolean isClosed() { + return client.isClosed(); + } + + @Override + public void setTimeout(int timeout) throws IOException { + client.setSoTimeout(timeout); + } + + @Override + public int getTimeout() throws IOException { + return client.getSoTimeout(); + } + + /** + * Flushes the input stream if it contains readable bytes + * + * @throws IOException + * if an error occurs while reading the input stream. + */ + private void flushInputStream() throws IOException { + try { + while (is.available() > 0) { + is.readFully(new byte[is.available()]); + } + } catch (IOException e) { + close(); + throw new IOException("Error flushing input stream from TCP connection.", e); + } + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/TransportLayer.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/TransportLayer.java new file mode 100644 index 0000000..33e7866 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/TransportLayer.java @@ -0,0 +1,72 @@ +/** + * 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.transportlayer; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * The MBus transport layer interface. + */ +public interface TransportLayer extends AutoCloseable { + + /** + * Opens the transport layer. The layer needs to be opened before attempting to read a device. + * + * @throws IOException + * if an I/O error occurs while opening. + * + */ + void open() throws IOException; + + /** + * Closes the transport layer. + */ + @Override + void close(); + + /** + * Get the output stream of the layer. + * + * @return the output stream. + */ + DataOutputStream getOutputStream(); + + /** + * Get the input stream of the layer. + * + * @return the input stream. + */ + DataInputStream getInputStream(); + + /** + * Check if the layer is open. + * + * @return {@code true} if the layer is closed. + */ + boolean isClosed(); + + /** + * Set the response timeout. + * + * @param timeout + * the timeout in MILLIS. + * @throws IOException + * if an I/O error occurs. + */ + void setTimeout(int timeout) throws IOException; + + /** + * Get the response timeout in MILLIS. + * + * @return the response timeout in MILLIS. + * + * @throws IOException + * if an I/O error occurs. + */ + int getTimeout() throws IOException; +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/package-info.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/package-info.java new file mode 100644 index 0000000..1f30e2f --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/transportlayer/package-info.java @@ -0,0 +1,9 @@ +/** + * 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/. + */ +/** + * This package contains the transport layers and their builders. + */ +package org.openmuc.jmbus.transportlayer; diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/AbstractWMBusConnection.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/AbstractWMBusConnection.java new file mode 100644 index 0000000..c755aed --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/AbstractWMBusConnection.java @@ -0,0 +1,132 @@ +/** + * 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.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.openmuc.jmbus.SecondaryAddress; +import org.openmuc.jmbus.transportlayer.TransportLayer; + +abstract class AbstractWMBusConnection implements WMBusConnection { + + private static final int ACK = 0x3E; + + protected static final int BUFFER_LENGTH = 1000; + protected static final int MESSAGE_FRAGEMENT_TIMEOUT = 1000; + + private TransportLayer transportLayer; + + private final WMBusMode mode; + private final WMBusListener listener; + + final Map keyMap = new HashMap<>(); + + private volatile boolean closed; + private final ExecutorService receiverService; + + protected AbstractWMBusConnection(WMBusMode mode, WMBusListener listener, TransportLayer tl) { + this.listener = listener; + this.mode = mode; + this.transportLayer = tl; + + this.closed = true; + this.receiverService = Executors.newSingleThreadExecutor(); + } + + @Override + public final void close() { + if (this.transportLayer == null || this.closed) { + // nothing to do + return; + } + + try { + this.receiverService.shutdown(); + this.transportLayer.close(); + } finally { + this.transportLayer = null; + this.closed = true; + } + } + + @Override + public final void addKey(SecondaryAddress address, byte[] key) { + this.keyMap.put(address, key); + } + + @Override + public final void removeKey(SecondaryAddress address) { + this.keyMap.remove(address); + } + + public final void open() throws IOException { + if (!closed) { + return; + } + try { + transportLayer.open(); + + initializeWirelessTransceiver(mode); + + } catch (IOException e) { + transportLayer.close(); + + throw e; + } + this.receiverService.execute(newMessageReceiver(this.transportLayer, this.listener)); + + this.closed = false; + } + + protected abstract MessageReceiver newMessageReceiver(TransportLayer transportLayer, WMBusListener listener); + + protected abstract void initializeWirelessTransceiver(WMBusMode mode) throws IOException; + + protected boolean isClosed() { + return closed; + } + + protected DataInputStream getInputStream() { + return this.transportLayer.getInputStream(); + } + + protected DataOutputStream getOutputStream() { + return this.transportLayer.getOutputStream(); + } + + protected long discardNoise() throws IOException { + DataInputStream inputStream = getInputStream(); + + if (inputStream.available() == 0) { + return 0; + } + + transportLayer.setTimeout(MESSAGE_FRAGEMENT_TIMEOUT); + try { + return inputStream.skip(500); + + } catch (InterruptedIOException e) { + // ignore + return 0; + } + } + + protected void waitForAck() throws IOException { + transportLayer.setTimeout(MESSAGE_FRAGEMENT_TIMEOUT); + + int b = getInputStream().read(); + if (b != ACK) { + throw new IOException(String.format("Did not receive ACK. Received 0x%02X instead.", b)); + } + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/HciMessageException.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/HciMessageException.java new file mode 100644 index 0000000..995d6ad --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/HciMessageException.java @@ -0,0 +1,17 @@ +package org.openmuc.jmbus.wireless; + +import java.io.IOException; + +class HciMessageException extends IOException { + + private static final long serialVersionUID = -1789394121831686912L; + private final byte[] data; + + public HciMessageException(byte[] data) { + this.data = data; + } + + public byte[] getData() { + return data; + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/MessageReceiver.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/MessageReceiver.java new file mode 100644 index 0000000..70acec5 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/MessageReceiver.java @@ -0,0 +1,52 @@ +/** + * 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.IOException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +abstract class MessageReceiver implements Runnable { + + private final ExecutorService executor; + private final WMBusListener listener; + + public MessageReceiver(WMBusListener listener) { + this.listener = listener; + this.executor = Executors.newSingleThreadExecutor(); + } + + protected void shutdown() { + this.executor.shutdown(); + } + + protected void notifyStoppedListening(final IOException ioException) { + executor.execute(new Runnable() { + @Override + public void run() { + listener.stoppedListening(ioException); + } + }); + } + + protected void notifyNewMessage(final WMBusMessage wmBusMessage) { + executor.execute(new Runnable() { + @Override + public void run() { + listener.newMessage(wmBusMessage); + } + }); + } + + protected void notifyDiscarded(final byte[] discardedBytes) { + executor.execute(new Runnable() { + @Override + public void run() { + listener.discardedBytes(discardedBytes); + } + }); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/VirtualWMBusMessageHelper.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/VirtualWMBusMessageHelper.java index 85e315a..001769c 100644 --- a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/VirtualWMBusMessageHelper.java +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/VirtualWMBusMessageHelper.java @@ -1,10 +1,14 @@ /** - * Copyright (c) 2010-2018 by the respective copyright holders. + * Copyright (c) 2010-2021 Contributors to the openHAB project * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 */ package org.openmuc.jmbus.wireless; @@ -24,6 +28,5 @@ public class VirtualWMBusMessageHelper { public static WMBusMessage decode(byte[] buffer, Integer signalStrengthInDBm, Map keyMap) throws DecodingException { return WMBusMessage.decode(buffer, signalStrengthInDBm, keyMap); - } } 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 new file mode 100644 index 0000000..b5de981 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnection.java @@ -0,0 +1,172 @@ +/** + * 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.IOException; +import java.text.MessageFormat; + +import org.openmuc.jmbus.SecondaryAddress; +import org.openmuc.jmbus.transportlayer.SerialBuilder; +import org.openmuc.jmbus.transportlayer.TcpBuilder; +import org.openmuc.jmbus.transportlayer.TransportLayer; +import org.openmuc.jrxtx.DataBits; +import org.openmuc.jrxtx.Parity; +import org.openmuc.jrxtx.StopBits; + +/** + * A Wireless Mbus Connection. + * + * @see #addKey(SecondaryAddress, byte[]) + */ +public interface WMBusConnection extends AutoCloseable { + + /** + * Closes the service access point. + */ + @Override + void close() throws IOException; + + /** + * Stores a pair of secondary address and cryptographic key. The stored keys are automatically used to decrypt + * messages when a wireless M-Bus message is been decoded. + * + * @param address + * the secondary address. + * @param key + * the cryptographic key. + * + * @see #removeKey(SecondaryAddress) + */ + void addKey(SecondaryAddress address, byte[] key); + + /** + * Removes the stored key for the given secondary address. + * + * @param address + * the secondary address for which to remove the stored key. + * + * @see #addKey(SecondaryAddress, byte[]) + */ + void removeKey(SecondaryAddress address); + + class WMBusSerialBuilder extends SerialBuilder { + + private final Builder builder; + + public WMBusSerialBuilder(WMBusManufacturer wmBusManufacturer, WMBusListener listener, String serialPortName) { + super(serialPortName); + builder = new Builder(wmBusManufacturer, listener); + + switch (wmBusManufacturer) { + case RADIO_CRAFTS: + setBaudrate(19200); + break; + case AMBER: + setBaudrate(9600); + break; + case IMST: + setBaudrate(57600); + break; + default: + // should not occur + throw new RuntimeException( + MessageFormat.format("Error unknown manufacturer {0}.", wmBusManufacturer)); + } + setStopBits(StopBits.STOPBITS_1).setParity(Parity.NONE).setDataBits(DataBits.DATABITS_8); + } + + public WMBusSerialBuilder setMode(WMBusMode mode) { + builder.mode = mode; + return self(); + } + + public WMBusSerialBuilder setWmBusManufacturer(WMBusManufacturer wmBusManufacturer) { + builder.wmBusManufacturer = wmBusManufacturer; + return self(); + } + + public WMBusSerialBuilder setListener(WMBusListener connectionListener) { + builder.listener = connectionListener; + return self(); + } + + @Override + public WMBusConnection build() throws IOException { + return builder.build(buildTransportLayer()); + } + } + + class WMBusTcpBuilder extends TcpBuilder { + + private final Builder builder; + + public WMBusTcpBuilder(WMBusManufacturer wmBusManufacturer, WMBusListener listener, String hostAddress, + int port) { + super(hostAddress, port); + builder = new Builder(wmBusManufacturer, listener); + } + + public WMBusTcpBuilder setMode(WMBusMode mode) { + builder.mode = mode; + return self(); + } + + public WMBusTcpBuilder setWmBusManufacturer(WMBusManufacturer wmBusManufacturer) { + builder.wmBusManufacturer = wmBusManufacturer; + return self(); + } + + public WMBusTcpBuilder setListener(WMBusListener connectionListener) { + builder.listener = connectionListener; + return self(); + } + + @Override + public WMBusConnection build() throws IOException { + return builder.build(buildTransportLayer()); + } + } + + class Builder { + + private WMBusManufacturer wmBusManufacturer; + private WMBusMode mode; + private WMBusListener listener; + + Builder(WMBusManufacturer wmBusManufacturer, WMBusListener listener) { + this.listener = listener; + this.wmBusManufacturer = wmBusManufacturer; + this.mode = WMBusMode.T; + } + + WMBusConnection build(TransportLayer transportLayer) throws IOException { + AbstractWMBusConnection wmBusConnection; + switch (this.wmBusManufacturer) { + case AMBER: + wmBusConnection = new WMBusConnectionAmber(this.mode, this.listener, transportLayer); + break; + case IMST: + wmBusConnection = new WMBusConnectionImst(this.mode, this.listener, transportLayer); + break; + case RADIO_CRAFTS: + wmBusConnection = new WMBusConnectionRadioCrafts(this.mode, this.listener, transportLayer); + break; + default: + // should not occur. + throw new RuntimeException("Unknown Manufacturer."); + } + + wmBusConnection.open(); + return wmBusConnection; + } + } + + public enum WMBusManufacturer { + AMBER, + IMST, + RADIO_CRAFTS + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnectionAmber.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnectionAmber.java new file mode 100644 index 0000000..67981a3 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnectionAmber.java @@ -0,0 +1,244 @@ +/** + * 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.nio.ByteBuffer; +import java.text.MessageFormat; +import java.util.Arrays; + +import org.openmuc.jmbus.DecodingException; +import org.openmuc.jmbus.transportlayer.TransportLayer; + +/** + * Was tested with the Amber 8426M Wireless M-Bus stick. + */ +class WMBusConnectionAmber extends AbstractWMBusConnection { + + private class MessageReceiverImpl extends MessageReceiver { + + private static final int MBUS_BL_CONTROL = 0x44; + + private int discardCount = 0; + 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 { + + ByteBuffer discardBuffer = ByteBuffer.allocate(100); + + int b0, b1; + DataInputStream is = getInputStream(); + while (true) { + try { + this.transportLayer.setTimeout(0); + b0 = is.read(); + this.transportLayer.setTimeout(MESSAGE_FRAGEMENT_TIMEOUT); + b1 = is.read(); + + if (b0 == 0xff && b1 == 0x03) { + // it's optional if UART_CMD_Out_Enable is enabled on amber module + // then you will get also CRC at the end of message frame + continue; + } + + if ((b1 ^ MBUS_BL_CONTROL) == 0) { + // we found beginning of mBUS frame, in the b0 will be the length of message + break; + } + + if (discardBuffer.capacity() - discardBuffer.position() < 2) { + discard(discardBuffer.array(), 0, discardBuffer.position()); + discardBuffer.clear(); + } + discardBuffer.put((byte) b0); + discardBuffer.put((byte) b1); + } catch (InterruptedIOException e) { + continue; + } + } + + int length = (b0 & 0xff) + 1; // +1 because length don't count the length byte itself + byte[] data = new byte[length]; + + data[0] = (byte) b0; + data[1] = (byte) b1; + + int readLength = length - 2; // we already have first two bytes + int actualLength = is.read(data, 2, readLength); + + if (readLength != actualLength) { + discard(data, 0, actualLength); + return; + } + + if (is.available() > 0) { + // if there is one more bit it will be CRC, it's optional + byte crc = is.readByte(); + byte countedCRC = (byte) (0xFF ^ 0x03); + for (byte element : data) { + countedCRC = (byte) (countedCRC ^ element); + } + if (crc == countedCRC) { + notifyListener(data); + } else { + notifyDiscarded(data); + } + } else { + // parse data without CRC check + notifyListener(data); + } + + if (discardBuffer.position() > 0) { + discard(discardBuffer.array(), 0, discardBuffer.position()); + } + } + + private void notifyListener(final byte[] data) { + int rssi = data[data.length - 1] & 0xff; + final Integer signalStrengthInDBm; + int rssiOffset = 74; + if (rssi >= 128) { + signalStrengthInDBm = ((rssi - 256) / 2) - rssiOffset; + } else { + signalStrengthInDBm = (rssi / 2) - rssiOffset; + } + + data[0] = (byte) (data[0] - 1); + + try { + super.notifyNewMessage(WMBusMessage.decode(data, signalStrengthInDBm, keyMap)); + } catch (DecodingException e) { + super.notifyDiscarded(data); + } + } + + private void discard(byte[] data, int offset, int length) { + discardCount++; + final byte[] discardedBytes = Arrays.copyOfRange(data, offset, offset + length); + + super.notifyDiscarded(discardedBytes); + + if (discardCount >= 5) { + try { + reset(); + } catch (IOException e) { + // ignoring reset errors here.. + } + discardCount = 0; + } + } + } + + public WMBusConnectionAmber(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 { + switch (mode) { + case S: + amberSetReg((byte) 0x46, (byte) 0x03); + break; + case T: + amberSetReg((byte) 0x46, (byte) 0x08); // T2-OTHER (correct for receiving station in T mode) + break; + case C: + amberSetReg((byte) 0x46, (byte) 0x0e); // C2-OTHER + break; + default: + String message = MessageFormat.format("wMBUS Mode ''{0}'' is not supported", mode.toString()); + throw new IOException(message); + } + amberSetReg((byte) 0x45, (byte) 0x01); // Enable attaching RSSI to message + } + + /** + * Writes a {@code CMD_SET_REQ} to the Amber module. + * + * @param cmd + * register address of the Amber module. + * @param data + * new value(s) for this register address(es). + * @throws IOException + * if an error occurred, while writing the command. + */ + private void writeCommand(byte cmd, byte[] data) throws IOException { + DataOutputStream os = getOutputStream(); + + byte[] header = ByteBuffer.allocate(3).put((byte) 0xFF).put(cmd).put((byte) data.length).array(); + + os.write(header); + os.write(data); + + byte checksum = computeCheckSum(data, computeCheckSum(header, (byte) 0)); + + os.write(checksum); + } + + private void amberSetReg(byte reg, byte value) throws IOException { + byte[] data = { reg, 0x01, value }; + + writeCommand((byte) 0x09, data); + + discardNoise(); + } + + /** + * Writes a reset command to the Amber module + * + * @throws IOException + * if the reset command failed. + */ + private void reset() throws IOException { + writeCommand((byte) 0x05, new byte[] {}); + } + + private static byte computeCheckSum(byte[] data, byte checksum) { + for (byte element : data) { + checksum = (byte) (checksum ^ element); + } + return checksum; + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnectionImst.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnectionImst.java new file mode 100644 index 0000000..db68548 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnectionImst.java @@ -0,0 +1,373 @@ +/** + * 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.IOException; +import java.io.InterruptedIOException; +import java.nio.ByteBuffer; +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 IMST iM871A-USB Wireless M-Bus stick.
+ */ +class WMBusConnectionImst extends AbstractWMBusConnection { + + private class MessageReceiverImpl extends MessageReceiver { + + private static final byte MBUS_BL_CONTROL = 0x44; + private final TransportLayer transportLayer; + + public MessageReceiverImpl(TransportLayer transportLayer, WMBusListener listener) { + super(listener); + this.transportLayer = transportLayer; + } + + @Override + public void run() { + try { + + while (!isClosed()) { + try { + task(); + } catch (InterruptedIOException e) { + // ignore a timeout.. + } catch (HciMessageException e) { + super.notifyDiscarded(e.getData()); + } + } + + } catch (IOException e) { + if (isClosed()) { + return; + } + + super.notifyStoppedListening(e); + } finally { + close(); + super.shutdown(); + } + } + + private void task() throws IOException { + HciMessage hciMessage = readHciMsg(); + + final byte[] wmbusMessage = hciMessage.getPayload(); + final int signalStrengthInDBm = hciMessage.getRSSI(); + try { + super.notifyNewMessage(WMBusMessage.decode(wmbusMessage, signalStrengthInDBm, keyMap)); + } catch (DecodingException e) { + super.notifyDiscarded(wmbusMessage); + } + } + + private HciMessage readHciMsg() throws IOException { + while (true) { + HciMessage hciMessage = HciMessage.decode(this.transportLayer); + + if (hciMessage.getPayload().length <= 1) { + continue; + } + + if (hciMessage.getPayload()[1] == MBUS_BL_CONTROL) { + return hciMessage; + } else { + discard(hciMessage); + } + } + } + + private void discard(HciMessage hciMessage) { + super.notifyDiscarded(hciMessage.payload); + } + } + + public WMBusConnectionImst(WMBusMode mode, WMBusListener listener, TransportLayer tl) { + super(mode, listener, tl); + } + + @Override + protected MessageReceiver newMessageReceiver(TransportLayer transportLayer, WMBusListener listener) { + return new MessageReceiverImpl(transportLayer, listener); + } + + @Override + protected void initializeWirelessTransceiver(WMBusMode mode) throws IOException { + + byte[] payload = ByteBuffer.allocate(6).put((byte) 0x00) // NVM Flag: change configuration only temporary + .put((byte) 0x03) // IIFlag 1: Bit 0 Device Mode and Bit 1 Radio Mode + .put((byte) 0x00) // Device Mode: Meter + .put(linkRadioModeFor(mode)) // Link/Radio Mode + .put((byte) 0x10) // IIFlag 2: Bit 4 : Auto RSSI Attachment + .put((byte) 0x01) // Rx-Timestamp attached for each received Radio message + .array(); + + writeCommand(Const.DEVMGMT_ID, Const.DEVMGMT_MSG_SET_CONFIG_REQ, payload); + } + + private static byte linkRadioModeFor(WMBusMode mode) throws IOException { + switch (mode) { + case S: + return 0x01; // Link/Radio Mode: S1-m + case T: + return 0x04; // Link/Radio Mode: T2 + case C: + return 0x08; // Link/Radio Mode: C2 with telegram format A (C2 + format B = 0x09) + default: + String msg = MessageFormat.format("wMBUS Mode ''{0}'' is not supported", mode); + throw new IOException(msg); + } + } + + private boolean writeCommand(byte endpointId, byte msgId, byte[] payload) { + byte controlField = 0; + int lengthPayloadAll = payload.length & 0xFF; + double numOfPackagesTemp = (double) lengthPayloadAll / Const.MAX_SINGLE_PAYLOAD_SIZE; + + int numOfPackages = (int) numOfPackagesTemp; + int comma = (int) (numOfPackagesTemp - numOfPackages) * 100; + if (numOfPackages == 0 || comma != 0) { + ++numOfPackages; + } + + if (numOfPackages > Const.MAX_PACKAGES) { + return false; + } + + for (int i = 0; i < numOfPackages; ++i) { + int payloadSendLength = Const.MAX_SINGLE_PAYLOAD_SIZE; + if (numOfPackages - i == 1) { + payloadSendLength = lengthPayloadAll - (numOfPackages - 1) * Const.MAX_SINGLE_PAYLOAD_SIZE; + } + byte[] payloadSend = new byte[payloadSendLength]; + System.arraycopy(payload, i * payloadSendLength, payloadSend, 0, payloadSendLength); + + byte controlField_EndpointField = (byte) ((controlField << 4) | endpointId & 0xff); + byte[] hciHeader = { Const.START_OF_FRAME, controlField_EndpointField, msgId, (byte) payloadSendLength }; + + byte[] hciMessage = new byte[Const.HCI_HEADER_LENGTH + payloadSendLength]; + System.arraycopy(hciHeader, 0, hciMessage, 0, hciHeader.length); + System.arraycopy(payloadSend, 0, hciMessage, hciHeader.length, payloadSend.length); + + try { + getOutputStream().write(hciMessage); + } catch (IOException e) { + return false; + } + } + return true; + } + + /** + * Writes a reset command to the IMST module + */ + public void reset() { + writeCommand(Const.DEVMGMT_MSG_FACTORY_RESET_REQ, Const.DEVMGMT_ID, new byte[0]); + } + + /** + * IMST constants packages + */ + class Const { + public static final byte START_OF_FRAME = (byte) 0xA5; + // A5 01 03 + public static final int MAX_PACKAGES = 255; + public static final int MAX_SINGLE_PAYLOAD_SIZE = 255; + public static final int HCI_HEADER_LENGTH = 4; + + // ControlField + public static final byte RESERVED = 0x00; // 0b0000 + public static final byte TIMESTAMP_ATTACHED = 0x02; // 0b0010 + public static final byte RSSI_ATTACHED = 0x04; // 0b0100 + public static final byte CRC16_ATTACHED = 0x08; // 0b1000 (FCS) + + // List of Endpoint Identifier + public static final byte DEVMGMT_ID = 0x01; + public static final byte RADIOLINK_ID = 0x02; + public static final byte RADIOLINKTEST_ID = 0x03; + public static final byte HWTEST_ID = 0x04; + + // Device Management MessageIdentifier + public static final byte DEVMGMT_MSG_PING_REQ = 0x01; + public static final byte DEVMGMT_MSG_PING_RSP = 0x02; + public static final byte DEVMGMT_MSG_SET_CONFIG_REQ = 0x03; + public static final byte DEVMGMT_MSG_SET_CONFIG_RSP = 0x04; + public static final byte DEVMGMT_MSG_GET_CONFIG_REQ = 0x05; + public static final byte DEVMGMT_MSG_GET_CONFIG_RSP = 0x06; + public static final byte DEVMGMT_MSG_RESET_REQ = 0x07; + public static final byte DEVMGMT_MSG_RESET_RSP = 0x08; + public static final byte DEVMGMT_MSG_FACTORY_RESET_REQ = 0x09; + public static final byte DEVMGMT_MSG_FACTORY_RESET_RSP = 0x0A; + public static final byte DEVMGMT_MSG_GET_OPMODE_REQ = 0x0B; + public static final byte DEVMGMT_MSG_GET_OPMODE_RSP = 0x0C; + public static final byte DEVMGMT_MSG_SET_OPMODE_REQ = 0x0D; + public static final byte DEVMGMT_MSG_SET_OPMODE_RSP = 0x0E; + public static final byte DEVMGMT_MSG_GET_DEVICEINFO_REQ = 0x0F; + public static final byte DEVMGMT_MSG_GET_DEVICEINFO_RSP = 0x10; + public static final byte DEVMGMT_MSG_GET_SYSSTATUS_REQ = 0x11; + public static final byte DEVMGMT_MSG_GET_SYSSTATUS_RSP = 0x12; + public static final byte DEVMGMT_MSG_GET_FWINFO_REQ = 0x13; + public static final byte DEVMGMT_MSG_GET_FWINFO_RSP = 0x14; + public static final byte DEVMGMT_MSG_GET_RTC_REQ = 0x19; + public static final byte DEVMGMT_MSG_GET_RTC_RSP = 0x1A; + public static final byte DEVMGMT_MSG_SET_RTC_REQ = 0x1B; + public static final byte DEVMGMT_MSG_SET_RTC_RSP = 0x1C; + public static final byte DEVMGMT_MSG_ENTER_LPM_REQ = 0x1D; + public static final byte DEVMGMT_MSG_ENTER_LPM_RSP = 0x1E; + public static final byte DEVMGMT_MSG_SET_AES_ENCKEY_REQ = 0x21; + public static final byte DEVMGMT_MSG_SET_AES_ENCKEY_RSP = 0x22; + public static final byte DEVMGMT_MSG_ENABLE_AES_ENCKEY_REQ = 0x23; + public static final byte DEVMGMT_MSG_ENABLE_AES_ENCKEY_RSP = 0x24; + public static final byte DEVMGMT_MSG_SET_AES_DECKEY_RSP_0X25 = 0x25; + public static final byte DEVMGMT_MSG_SET_AES_DECKEY_RSP_0X26 = 0x26; + public static final byte DEVMGMT_MSG_AES_DEC_ERROR_IND = 0x27; + + // Radio Link Message Identifier + public static final byte RADIOLINK_MSG_WMBUSMSG_REQ = 0x01; + public static final byte RADIOLINK_MSG_WMBUSMSG_RSP = 0x02; + public static final byte RADIOLINK_MSG_WMBUSMSG_IND = 0x03; + public static final byte RADIOLINK_MSG_DATA_REQ = 0x04; + public static final byte RADIOLINK_MSG_DATA_RSP = 0x05; + + private Const() { + // hide constructor + } + } + + /** + *
  • HCI Message + *
      + *
    • StartOfFrame 8 Bit: 0xA5 + *
    • MsgHeader 24 Bit: + *
        + *
      • ControlField 4 Bit: + *
          + *
        • 0000b Reserved + *
        • 0010b Time Stamp Field attached + *
        • 0100b RSSI Field attached + *
        • 1000b CRC16 Field attached + *
        + *
      • EndPoint ID 4 Bit: Identifies a logical message endpoint which groups several messages. + *
      • Msg ID Field 8 Bit: Identifies the message type. + *
      • LengthFiled 8 Bit: Number of bytes in the payload. If null no payload. + *
      + *
    • PayloadField n * 8 Bit: wMBus Message + *
    • Time Stamp (optional): 32 Bit Timestamp of the RTC + *
    • RSSI (optional) 8 Bit: Receive Signal Strength Indicator + *
    • FCS (optional) 16 Bit: CRC from Control Field up to last byte of Payload, Time Stamp or RSSI Field.
    • + *
    + * + */ + private static class HciMessage { + + private final byte controlField;; + private final byte endpointID; + private final byte msgId; + private final int length; + + private final byte[] payload; + private final int timeStamp; + private final int rSSI; + private final int fCS; + + private HciMessage(byte controlField, byte endpointID, byte msgId, int length, byte[] payload, int timeStamp, + int rSSI, int fCS) { + this.controlField = controlField; + this.endpointID = endpointID; + this.msgId = msgId; + this.length = length; + this.payload = payload; + this.timeStamp = timeStamp; + this.rSSI = rSSI; + this.fCS = fCS; + } + + public static HciMessage decode(TransportLayer transportLayer) throws IOException { + DataInputStream is = transportLayer.getInputStream(); + byte b0; + byte b1; + + transportLayer.setTimeout(0); + b0 = is.readByte(); + if (b0 != Const.START_OF_FRAME) { + String msg = String.format("First byte does not start with %02X.", Const.START_OF_FRAME); + throw new IOException(msg); + } + + transportLayer.setTimeout(MESSAGE_FRAGEMENT_TIMEOUT); + // this may time out. + b1 = is.readByte(); + + byte controlField = (byte) ((b1 >> 4) & 0x0F); + byte endpointId = (byte) (b1 & 0x0F); + + byte msgId = is.readByte(); + int length = is.readUnsignedByte(); + + byte[] payload = readPayload(is, length); + + int timeStamp = 0; + if ((controlField & Const.TIMESTAMP_ATTACHED) == Const.TIMESTAMP_ATTACHED) { + timeStamp = is.readInt(); + } + + int rSSI = 0; + if ((controlField & Const.RSSI_ATTACHED) == Const.RSSI_ATTACHED) { + double b = -100.0 - (4000.0 / 150.0); + double m = 80.0 / 150.0; + rSSI = (int) (m * is.readUnsignedByte() + b); + } + + int fCS = 0; + if ((controlField & Const.CRC16_ATTACHED) == Const.CRC16_ATTACHED) { + fCS = is.readUnsignedShort(); + } + + return new HciMessage(controlField, endpointId, msgId, length, payload, timeStamp, rSSI, fCS); + } + + private static byte[] readPayload(DataInputStream is, final int length) throws IOException { + byte[] payload = new byte[length + 1]; + payload[0] = (byte) length; + + int readLength = is.read(payload, 1, length); + + if (readLength != length) { + byte[] data = Arrays.copyOfRange(payload, 1, 1 + readLength); + throw new HciMessageException(data); + } + + return payload; + } + + @Override + public String toString() { + return new StringBuilder().append("Control Field: ").append(byteAsHexString(controlField)) + .append("\nEndpointID: ").append(byteAsHexString(endpointID)).append("\nMsg ID: ") + .append(byteAsHexString(msgId)).append("\nLength: ").append(length) + .append("\nTimestamp: ").append(timeStamp).append("\nRSSI: ").append(rSSI) + .append("\nFCS: ").append(fCS).append("\nPayload:\n").append(HexUtils.bytesToHex(payload)) + .toString(); + } + + private static String byteAsHexString(byte b) { + return String.format("%02X", b); + } + + public byte[] getPayload() { + return payload; + } + + public int getRSSI() { + return rSSI; + } + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnectionRadioCrafts.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnectionRadioCrafts.java new file mode 100644 index 0000000..5cdb7e5 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusConnectionRadioCrafts.java @@ -0,0 +1,229 @@ +/** + * 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.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.transportlayer.TransportLayer; + +/* + * Radio Craft W-MBUS frame: + * + * @formatter:off + * +---+----+-----------+ + * | L | CI | APPL_DATA | + * +---+----+-----------+ + * ~ L is the length (not including the length byte itself) + * ~ CI is the Control Information byte + * @formatter:on + */ +class WMBusConnectionRadioCrafts extends AbstractWMBusConnection { + + private class MessageReceiverImpl extends MessageReceiver { + + /** + * Indicates message from primary station, function send/no reply (SND -N + */ + private static final byte CONTROL_BYTE = 0x44; + private final TransportLayer transportLayer; + + private final byte[] discardBuffer = new byte[BUFFER_LENGTH]; + private int bufferPointer = 0; + + public MessageReceiverImpl(TransportLayer transportLayer, WMBusListener listener) { + super(listener); + this.transportLayer = transportLayer; + } + + @Override + public void run() { + try { + + while (!isClosed()) { + + byte[] messageData = initMessageData(); + + int len = messageData.length - 2; + handleData(messageData, len); + + } + } catch (final IOException e) { + if (!isClosed()) { + super.notifyStoppedListening(e); + } + + } finally { + close(); + super.shutdown(); + } + } + + private void handleData(byte[] messageData, int len) throws IOException { + try { + int numReadBytes = getInputStream().read(messageData, 2, len); + + if (len == numReadBytes) { + notifyListener(messageData); + } else { + discard(messageData, 0, numReadBytes + 2); + } + } catch (InterruptedIOException e) { + discard(messageData, 0, 2); + } + } + + private byte[] initMessageData() throws IOException { + byte b0, b1; + while (true) { + this.transportLayer.setTimeout(0); + b0 = getInputStream().readByte(); + this.transportLayer.setTimeout(MESSAGE_FRAGEMENT_TIMEOUT); + + try { + // this may time out. + b1 = getInputStream().readByte(); + } catch (InterruptedIOException e) { + continue; + } + + if (b1 == CONTROL_BYTE) { + break; + } + + discardBuffer[bufferPointer++] = b0; + discardBuffer[bufferPointer++] = b1; + + if (bufferPointer - 2 >= discardBuffer.length) { + discard(discardBuffer, 0, bufferPointer); + bufferPointer = 0; + } + + } + + int messageLength = b0 & 0xff; + + final byte[] messageData = new byte[messageLength + 1]; + messageData[0] = b0; + messageData[1] = b1; + + return messageData; + } + + private void notifyListener(final byte[] messageBytes) { + messageBytes[0] = (byte) (messageBytes[0] - 1); + int rssi = messageBytes[messageBytes.length - 1] & 0xff; + + final int signalStrengthInDBm = (rssi * -1) / 2; + try { + super.notifyNewMessage(WMBusMessage.decode(messageBytes, signalStrengthInDBm, keyMap)); + } catch (DecodingException e) { + super.notifyDiscarded(messageBytes); + } + } + + private void discard(byte[] buffer, int offset, int length) { + final byte[] discardedBytes = Arrays.copyOfRange(buffer, offset, offset + length); + + super.notifyDiscarded(discardedBytes); + } + } + + public WMBusConnectionRadioCrafts(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 { + // enter config mode + sendByteInConfigMode(0x00); + + DataOutputStream os = getOutputStream(); + int modeFlag = getModeFlag(mode); + + init(os, modeFlag); + + // /* Set Auto Answer Register */ + // sendByteInConfigMode(0x41); + // sendByteInConfigMode(0xff); + + // leave config mode + os.write(0x58); + os.flush(); + } + + private int getModeFlag(WMBusMode mode) throws IOException { + int modeFlag; + + switch (mode) { + case C: + modeFlag = 0x04; + break; + case S: + modeFlag = 0x00; + break; + case T: + modeFlag = 0x02; + break; + default: + String msg = MessageFormat.format("wMBUS Mode ''{0}'' is not supported", mode.toString()); + throw new IOException(msg); + } + return modeFlag; + } + + private void init(DataOutputStream os, int modeFlag) throws IOException { + requestSetMode(os, modeFlag); + + requestSetMasterMode(os); + + requestRssiInformation(os); + } + + private void requestSetMode(DataOutputStream os, int modeFlag) throws IOException { + sendRequest(os, 0x03, modeFlag); + } + + private void requestSetMasterMode(DataOutputStream os) throws IOException { + sendRequest(os, 0x12, 0x01); + } + + private void requestRssiInformation(DataOutputStream os) throws IOException { + sendRequest(os, 0x05, 0x01); + } + + private void sendRequest(DataOutputStream os, int b0, int b1) throws IOException { + sendByteInConfigMode(0x4d); + os.write(b0); + os.write(b1); + sendByteInConfigMode(0xff); + } + + private void sendByteInConfigMode(int b) throws IOException { + + discardNoise(); + + DataOutputStream os = getOutputStream(); + os.write(b); + os.flush(); + + waitForAck(); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusListener.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusListener.java new file mode 100644 index 0000000..b274f26 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusListener.java @@ -0,0 +1,39 @@ +/** + * 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.IOException; +import java.util.EventListener; + +/** + * The wireless M-Bus event/new message listener interface. + */ +public interface WMBusListener extends EventListener { + + /** + * Received a new wireless M-Bus message. + * + * @param message + * the message. + */ + void newMessage(WMBusMessage message); + + /** + * Callback, when noisy data has been discarded. + * + * @param bytes + * the data which has been discarded. + */ + void discardedBytes(byte[] bytes); + + /** + * Callback, if the connection has been interrupted. + * + * @param cause + * the cause of the interruption. + */ + void stoppedListening(IOException cause); +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusMessage.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusMessage.java new file mode 100644 index 0000000..84ffea2 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusMessage.java @@ -0,0 +1,129 @@ +/** + * 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.text.MessageFormat; +import java.util.Map; + +import org.openmuc.jmbus.DecodingException; +import org.openmuc.jmbus.SecondaryAddress; +import org.openmuc.jmbus.VariableDataStructure; + +/** + * Represents a wireless M-Bus link layer message without the CRC checksum. + * + * {@link WMBusMessage} is structured as follows: + *
      + *
    • Length (1 byte) - the length (number of bytes) of the complete message without the length byte and the CRC bytes. + *
    • + *
    • Control field (1 byte) - defines the frame type. 0x44 signifies an SND-NR (send no request) message that is sent + * by meters in S1 mode.
    • + *
    • Secondary address (8 bytes) - the secondary address consists of: + *
        + *
      • Manufacturer ID (2 bytes) -
      • + *
      • Address (6 bytes) - consists of + *
          + *
        • Device ID (4 bytes) -
        • + *
        • Version (1 byte) -
        • + *
        • Device type (1 byte) -
        • + *
        + *
      • + *
      + *
    • + *
    + */ +public class WMBusMessage { + + private final Integer signalStrengthInDBm; + + private final byte[] buffer; + private final int controlField; + private final SecondaryAddress secondaryAddress; + private final VariableDataStructure vdr; + + private WMBusMessage(Integer signalStrengthInDBm, byte[] buffer, int controlField, + SecondaryAddress secondaryAddress, VariableDataStructure vdr) { + this.signalStrengthInDBm = signalStrengthInDBm; + this.buffer = buffer; + this.controlField = controlField; + this.secondaryAddress = secondaryAddress; + this.vdr = vdr; + } + + /* + * Only decodes the wireless M-Bus message itself. + */ + static WMBusMessage decode(byte[] buffer, Integer signalStrengthInDBm, Map keyMap) + throws DecodingException { + int length = buffer[0] & 0xff; + + if (length > (buffer.length - 1)) { + String msg = MessageFormat.format( + "Byte buffer has only a length of {0} while the specified length field is {1}.", buffer.length, + length); + throw new DecodingException(msg); + } + + int controlField = buffer[1] & 0xff; + SecondaryAddress secondaryAddress = SecondaryAddress.newFromWMBusHeader(buffer, 2); + VariableDataStructure vdr = new VariableDataStructure(buffer, 10, length - 9, secondaryAddress, keyMap); + + return new WMBusMessage(signalStrengthInDBm, buffer, controlField, secondaryAddress, vdr); + } + + /** + * Get the message as binary large object (byte array). + * + * @return the byte array representation of the message. + */ + public byte[] asBlob() { + return buffer; + } + + public int getControlField() { + return controlField; + } + + /** + * Get the secondary address. + * + * @return the secondary address. + */ + public SecondaryAddress getSecondaryAddress() { + return secondaryAddress; + } + + /** + * Get the variable data structure of the message. + * + * @return the variable data structure. + */ + public VariableDataStructure getVariableDataResponse() { + return vdr; + } + + /** + * Returns the received signal string indication (RSSI) in dBm. + * + * @return the RSSI. + */ + public Integer getRssi() { + return signalStrengthInDBm; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + + if (signalStrengthInDBm != null) { + builder.append("Message was received with signal strength: ").append(signalStrengthInDBm).append("dBm\n"); + } + + return builder.append("Control Field: ").append(String.format("0x%02X", controlField)) + .append("\nSecondary Address -> ").append(secondaryAddress).append("\nVariable Data Response:\n") + .append(vdr).toString(); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusMode.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusMode.java new file mode 100644 index 0000000..943aab3 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/WMBusMode.java @@ -0,0 +1,24 @@ +/** + * 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; + +/** + * The wireless M-Bus modes. + */ +public enum WMBusMode { + /** + * Compact (868.95 MHz). Combination of range (S) and battery efficiency (T). Suitable for frequent sending. + */ + C, + /** + * Frequent (868.95 MHz). Meter sends data several times/day. + */ + T, + /** + * Stationary (868.3 MHz). Meter sends data few times/day. + */ + S; +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/package-info.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/package-info.java new file mode 100644 index 0000000..a613d45 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jmbus/wireless/package-info.java @@ -0,0 +1,12 @@ +/** + * 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/. + */ +/** + * This package contain relevant classes to receive wireless M-Bus messages. + * + * @see org.openmuc.jmbus.wireless.WMBusConnection.WMBusSerialBuilder + * @see org.openmuc.jmbus.wireless.WMBusConnection + */ +package org.openmuc.jmbus.wireless; diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/DataBits.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/DataBits.java new file mode 100644 index 0000000..87be3bc --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/DataBits.java @@ -0,0 +1,36 @@ +package org.openmuc.jrxtx; + +import org.openhab.core.io.transport.serial.SerialPort; + +/** + * The data bits. + */ +@SuppressWarnings("deprecation") +public enum DataBits { + /** + * 5 data bits will be used for each character. + */ + DATABITS_5(SerialPort.DATABITS_5), + /** + * 6 data bits will be used for each character. + */ + DATABITS_6(SerialPort.DATABITS_6), + /** + * 8 data bits will be used for each character. + */ + DATABITS_7(SerialPort.DATABITS_7), + /** + * 8 data bits will be used for each character. + */ + DATABITS_8(SerialPort.DATABITS_8),; + + private int odlValue; + + private DataBits(int oldValue) { + this.odlValue = oldValue; + } + + int getOldValue() { + return this.odlValue; + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/FlowControl.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/FlowControl.java new file mode 100644 index 0000000..8e00c8a --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/FlowControl.java @@ -0,0 +1,29 @@ +package org.openmuc.jrxtx; + +/** + * The flow control. + * + * @see SerialPort#setFlowControl(FlowControl) + * @see SerialPortBuilder#setFlowControl(FlowControl) + */ +public enum FlowControl { + /** + * No flow control. + */ + NONE, + + /** + * Hardware flow control on input and output (RTS/CTS). + * + *

    + * Sets RFR (ready for receiving) formally known as RTS and the CTS (clear to send) flag. + *

    + */ + RTS_CTS, + + /** + * Software flow control on input and output. + */ + XON_XOFF + +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/JRxTxPort.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/JRxTxPort.java new file mode 100644 index 0000000..396cf5a --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/JRxTxPort.java @@ -0,0 +1,340 @@ +package org.openmuc.jrxtx; + +import static java.text.MessageFormat.format; +import static org.openhab.core.io.transport.serial.SerialPort.*; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.openhab.core.io.transport.serial.PortInUseException; +import org.openhab.core.io.transport.serial.SerialPortIdentifier; +import org.openhab.core.io.transport.serial.SerialPortManager; +import org.openhab.core.io.transport.serial.UnsupportedCommOperationException; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.util.tracker.ServiceTracker; + +/** + * This class is a workaround: + * jrxtx library includes gnu.io.* classes and j62056.jar is depending on that. As we are + * using nrjavaserial as an implementation of gnu.io, we can't go that way! + * -> As a workaround I shaded the {@link JRxTxPort} class which is used by j62056.jar and modified it to + * work with any implementation of {@link SerialPort} (formerly it was just working with the implementation + * gnu.io.RXTXPort). + * + * @author MatthiasS + * + */ +class JRxTxPort implements org.openmuc.jrxtx.SerialPort { + + private volatile boolean closed; + + private org.openhab.core.io.transport.serial.SerialPort rxtxPort; + + private SerialInputStream serialIs; + private SerialOutputStream serial0s; + + private String portName; + + private DataBits dataBits; + + private Parity parity; + + private StopBits stopBits; + + private int baudRate; + + private int serialPortTimeout; + + private FlowControl flowControl; + + public static JRxTxPort openSerialPort(String portName, int baudRate, Parity parity, DataBits dataBits, + StopBits stopBits, FlowControl flowControl) throws IOException { + try { + BundleContext bundleContext = FrameworkUtil.getBundle(JRxTxPort.class).getBundleContext(); + ServiceTracker serviceTracker = new ServiceTracker<>(bundleContext, + SerialPortManager.class, null); + serviceTracker.open(); + SerialPortManager serialPortManager = serviceTracker.getService(); + + SerialPortIdentifier serialPortIdentifier = serialPortManager.getIdentifier(portName); + if (serialPortIdentifier == null) { + String errMessage = format("Serial port {0} not found or port is busy.", portName); + throw new PortNotFoundException(errMessage); + } + org.openhab.core.io.transport.serial.SerialPort comPort = serialPortIdentifier.open("meterreader", 0); + // if (!(comPort instanceof RXTXPort)) { + // throw new SerialPortException("Unable to open the serial port. Port is not RXTX."); + // } + + try { + comPort.setSerialPortParams(baudRate, dataBits.getOldValue(), stopBits.getOldValue(), + parity.getOldValue()); + + setFlowControl(flowControl, comPort); + } catch (UnsupportedCommOperationException e) { + String message = format("Unable to apply config on serial port.\n{0}", e.getMessage()); + throw new SerialPortException(message); + } + + return new JRxTxPort(comPort, portName, baudRate, parity, dataBits, stopBits, flowControl); + // } catch (NoSuchPortException e) { + // String errMessage = format("Serial port {0} not found or port is busy.", portName); + // throw new PortNotFoundException(errMessage); + } catch (PortInUseException e) { + String errMessage = format("Serial port {0} is already in use.", portName); + throw new PortNotFoundException(errMessage); + // } catch (UnsupportedCommOperationException e1) { + // throw new IOException(e1); + } + } + + private static void setFlowControl(FlowControl flowControl, + org.openhab.core.io.transport.serial.SerialPort rxtxPort) throws IOException { + try { + switch (flowControl) { + case RTS_CTS: + rxtxPort.setFlowControlMode(FLOWCONTROL_RTSCTS_IN | FLOWCONTROL_RTSCTS_OUT); + break; + case XON_XOFF: + rxtxPort.setFlowControlMode(FLOWCONTROL_XONXOFF_IN | FLOWCONTROL_XONXOFF_OUT); + + break; + + case NONE: + default: + rxtxPort.setFlowControlMode(FLOWCONTROL_NONE); + break; + } + } catch (UnsupportedCommOperationException e) { + throw new IOException("Failed to set FlowControl mode", e); + } + } + + private JRxTxPort(org.openhab.core.io.transport.serial.SerialPort comPort, String portName, int baudRate, + Parity parity, DataBits dataBits, StopBits stopBits, FlowControl flowControl) throws IOException { + this.rxtxPort = comPort; + this.portName = portName; + this.baudRate = baudRate; + this.parity = parity; + this.dataBits = dataBits; + this.stopBits = stopBits; + this.flowControl = flowControl; + + this.closed = false; + + this.serial0s = new SerialOutputStream(this.rxtxPort.getOutputStream()); + this.serialIs = new SerialInputStream(); + } + + @Override + public InputStream getInputStream() throws IOException { + if (isClosed()) { + throw new SerialPortException("Serial port is closed"); + } + return this.serialIs; + } + + @Override + public OutputStream getOutputStream() throws IOException { + if (isClosed()) { + throw new SerialPortException("Serial port is closed"); + } + + return this.serial0s; + } + + @Override + public synchronized void close() throws IOException { + if (isClosed()) { + return; + } + + try { + this.serial0s.closeStream(); + this.serialIs.closeStream(); + this.rxtxPort.close(); + this.serial0s = null; + this.serialIs = null; + this.rxtxPort = null; + } finally { + this.closed = true; + } + } + + @Override + public boolean isClosed() { + return this.closed; + } + + private class SerialInputStream extends InputStream { + private static final long SLEEP_TIME = 10L; // sleep appropriate time + + @Override + public synchronized int read() throws IOException { + long elapsedTime = 0; + + InputStream serialInputStream = rxtxPort.getInputStream(); + do { + if (serialInputStream.available() > 0) { + return serialInputStream.read(); + } + try { + Thread.sleep(SLEEP_TIME); + elapsedTime += SLEEP_TIME; + } catch (InterruptedException e) { + // ignore + } + + if (isClosed()) { + throw new SerialPortException("Serial port has been closed."); + } + } while (getSerialPortTimeout() == 0 || elapsedTime <= getSerialPortTimeout()); + + throw new SerialPortTimeoutException(); + } + + @Override + public int available() throws IOException { + return rxtxPort.getInputStream().available(); + } + + private void closeStream() throws IOException { + rxtxPort.getInputStream().close(); + } + + @Override + public void close() throws IOException { + JRxTxPort.this.close(); + } + } + + private class SerialOutputStream extends OutputStream { + + private OutputStream serialOutputStream; + + public SerialOutputStream(OutputStream serialOutputStream) { + this.serialOutputStream = serialOutputStream; + } + + @Override + public void write(int b) throws IOException { + checkIfOpen(); + + this.serialOutputStream.write(b); + } + + private void checkIfOpen() throws SerialPortException { + if (isClosed()) { + throw new SerialPortException("Port has been closed."); + } + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + checkIfOpen(); + this.serialOutputStream.write(b, off, len); + } + + @Override + public void write(byte[] b) throws IOException { + checkIfOpen(); + this.serialOutputStream.write(b); + } + + @Override + public void flush() throws IOException { + checkIfOpen(); + this.serialOutputStream.flush(); + } + + private void closeStream() throws IOException { + this.serialOutputStream.close(); + } + + @Override + public void close() throws IOException { + JRxTxPort.this.close(); + } + } + + @Override + public String getPortName() { + return this.portName; + } + + @Override + public DataBits getDataBits() { + return this.dataBits; + } + + @Override + public void setDataBits(DataBits dataBits) throws IOException { + this.dataBits = dataBits; + updateWrappedPort(); + } + + @Override + public Parity getParity() { + return this.parity; + } + + @Override + public void setParity(Parity parity) throws IOException { + this.parity = parity; + updateWrappedPort(); + } + + @Override + public StopBits getStopBits() { + return this.stopBits; + } + + @Override + public void setStopBits(StopBits stopBits) throws IOException { + this.stopBits = stopBits; + updateWrappedPort(); + } + + @Override + public int getBaudRate() { + return this.baudRate; + } + + @Override + public void setBaudRate(int baudRate) throws IOException { + this.baudRate = baudRate; + updateWrappedPort(); + } + + private void updateWrappedPort() throws IOException { + try { + this.rxtxPort.setSerialPortParams(this.baudRate, this.dataBits.getOldValue(), this.stopBits.getOldValue(), + this.parity.getOldValue()); + } catch (UnsupportedCommOperationException e) { + throw new IOException(e.getMessage()); + } + } + + @Override + public int getSerialPortTimeout() { + return this.serialPortTimeout; + } + + @Override + public void setSerialPortTimeout(int serialPortTimeout) throws IOException { + this.serialPortTimeout = serialPortTimeout; + } + + @Override + public void setFlowControl(FlowControl flowControl) throws IOException { + setFlowControl(flowControl, this.rxtxPort); + this.flowControl = flowControl; + } + + @Override + public FlowControl getFlowControl() { + return this.flowControl; + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/Parity.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/Parity.java new file mode 100644 index 0000000..a2541b8 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/Parity.java @@ -0,0 +1,54 @@ +package org.openmuc.jrxtx; + +import org.openhab.core.io.transport.serial.SerialPort; + +/** + * The parity. + */ +@SuppressWarnings("deprecation") +public enum Parity { + /** + * No parity bit will be sent with each data character at all. + */ + NONE(SerialPort.PARITY_NONE), + /** + * An odd parity bit will be sent with each data character. I.e. will be set to 1 if the data character contains an + * even number of bits set to 1. + */ + ODD(SerialPort.PARITY_ODD), + /** + * An even parity bit will be sent with each data character. I.e. will be set to 1 if the data character contains an + * odd number of bits set to 1. + */ + EVEN(SerialPort.PARITY_EVEN), + /** + * A mark parity bit (i.e. always 1) will be sent with each data character. + */ + MARK(SerialPort.PARITY_MARK), + /** + * A space parity bit (i.e. always 0) will be sent with each data character + */ + SPACE(4),; + + private static final Parity[] VALUES = values(); + private int odlValue; + + private Parity(int oldValue) { + this.odlValue = oldValue; + } + + int getOldValue() { + return this.odlValue; + } + + static Parity forValue(int parity) { + for (Parity p : VALUES) { + if (p.odlValue == parity) { + return p; + } + } + + // should not occur + throw new RuntimeException("Error."); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/PortNotFoundException.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/PortNotFoundException.java new file mode 100644 index 0000000..4d7c7eb --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/PortNotFoundException.java @@ -0,0 +1,20 @@ +package org.openmuc.jrxtx; + +/** + * Signals that the provided serial port name provided via {@link SerialPortBuilder#newBuilder(String)}, + * {@link SerialPortBuilder#setPortName(String)} doesn't exist on the host system. + */ +public class PortNotFoundException extends SerialPortException { + + private static final long serialVersionUID = 2766015292714524756L; + + /** + * Constructs a new PortNotFoundException with the specified detail message. + * + * @param message + * the detail message. + */ + public PortNotFoundException(String message) { + super(message); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/SerialPort.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/SerialPort.java new file mode 100644 index 0000000..7732ab7 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/SerialPort.java @@ -0,0 +1,172 @@ +package org.openmuc.jrxtx; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Serial port for communication using UARTs. Can be used for communication protocols such as RS-232 and RS-485. + *

    + * A SerialPort is created using {@link SerialPortBuilder}. Once closed it cannot be opened again but has to be + * recreated. + */ +public interface SerialPort extends Closeable { + + /** + * Returns the input stream for this serial port. + *

    + * Closing the returned InputStream will close the associated serial port. + * + * @return the InputStream object that can be used to read from the port. + * @throws IOException + * if an I/O error occurred + */ + InputStream getInputStream() throws IOException; + + /** + * Returns the output stream for this serial port. + * + * @return the OutputStream object that can be used to write to the port. + * @throws IOException + * if an I/O error occurred. + */ + OutputStream getOutputStream() throws IOException; + + /** + * Closes the serial port. + *

    + * Also closes the associated input and output streams. + * + * @throws IOException + * if an I/O error occurred. + */ + void close() throws IOException; + + /** + * Returns whether the serial port is currently open and available for communication. + * + * @return true if the serial port is closed. + */ + boolean isClosed(); + + /** + * Get the name of the serial port. + * + * @return the serial port name. + */ + String getPortName(); + + /** + * Get the current data bits config. + * + * @return the dataBits the data bits. + */ + DataBits getDataBits(); + + /** + * Set the data bits. + * + * @param dataBits + * the new dataBits. + * @throws IOException + * if an I/O exception occurred when setting the new data bits.. + */ + void setDataBits(DataBits dataBits) throws IOException; + + /** + * Get the parity. + * + * @return the new parity. + */ + Parity getParity(); + + /** + * Set the new parity. + * + * @param parity + * the new parity. + * @throws IOException + * if an I/O exception occurred when setting the new parity. + */ + void setParity(Parity parity) throws IOException; + + /** + * Get the current stop bits settings. + * + * @return the stopBits the stop bits. + */ + StopBits getStopBits(); + + /** + * Set the stop bits. + * + * @param stopBits + * the stopBits to set + * @throws IOException + * if an I/O exception occurred when setting the new stop bits. + */ + void setStopBits(StopBits stopBits) throws IOException; + + /** + * @return the baudRate setting. + * + * @see #setBaudRate(int) + */ + int getBaudRate(); + + /** + * Sets the baud rate of the system. + * + * @param baudRate + * the new baud rate. + * @throws IOException + * if an I/O exception occurred when setting the new baud rate. + * + * @see #getBaudRate() + */ + void setBaudRate(int baudRate) throws IOException; + + /** + * Returns setting for serial port timeout. 0 returns implies that the option is disabled (i.e., + * timeout of infinity). + * + * @return the serialPortTimeout. + * + * @see #setSerialPortTimeout(int) + */ + int getSerialPortTimeout(); + + /** + * Enable/disable serial port timeout with the specified timeout, in milliseconds. With this option set to a + * non-zero timeout, a read() call on the InputStream associated with this serial port will block for only this + * amount of time. If the timeout expires, a org.openmuc.jrxtx.SerialPortTimeoutExcepption is raised, though the + * serial port is still valid. The option must be enabled prior to entering the blocking operation to have effect. + * The timeout must be > 0. A timeout of zero is interpreted as an infinite timeout. + * + * @param serialPortTimeout + * the specified timeout, in milliseconds. + * @throws IOException + * if there is an error in the underlying protocol. + * + * @see #getSerialPortTimeout() + */ + void setSerialPortTimeout(int serialPortTimeout) throws IOException; + + /** + * Set the flow control type. + * + * @param flowControl + * the flow control. + * @throws IOException + * if an I/O exception occurred when setting the new baud rate. + */ + void setFlowControl(FlowControl flowControl) throws IOException; + + /** + * Get the current flow control settings. + * + * @return the flow control. + */ + FlowControl getFlowControl(); +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/SerialPortBuilder.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/SerialPortBuilder.java new file mode 100644 index 0000000..68983fc --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/SerialPortBuilder.java @@ -0,0 +1,142 @@ +package org.openmuc.jrxtx; + +import java.io.IOException; + +/** + * Builder class for SerialPorts. Provides a convenient way to set the various fields of a SerialPort. + * + * Example: + * + *

    + * 
    + * SerialPort port = newBuilder("/dev/ttyS0")
    + *                   .setBaudRate(19200)
    + *                   .setParity(Parity.EVEN)
    + *                   .build();
    + * InputStream is = port.getInputStream();
    + * ..
    + * 
    + * 
    + */ +@SuppressWarnings("deprecation") +public class SerialPortBuilder { + + private String portName; + private int baudRate; + private DataBits dataBits; + private Parity parity; + private StopBits stopBits; + private FlowControl flowControl; + + private SerialPortBuilder(String portName) { + this.portName = portName; + this.baudRate = 9600; + this.dataBits = DataBits.DATABITS_8; + this.parity = Parity.EVEN; + this.stopBits = StopBits.STOPBITS_1; + this.flowControl = FlowControl.NONE; + } + + /** + * Constructs a new SerialPortBuilder with the default values. + * + * @param portName + * the serial port name. E.g. on Unix systems: "/dev/ttyUSB0" and on Unix + * @return returns the new builder. + */ + public static SerialPortBuilder newBuilder(String portName) { + return new SerialPortBuilder(portName); + } + + /** + * Set the serial port name. + * + * @param portName + * the serial port name e.g. "/dev/ttyUSB0" + * @return the serial port builder. + */ + public SerialPortBuilder setPortName(String portName) { + this.portName = portName; + return this; + } + + /** + * Set the baud rate for the serial port. Values such as 9600 or 115200. + * + * @param baudRate + * the baud rate. + * @return the serial port builder. + * + * @see SerialPortBuilder#setBaudRate(int) + */ + public SerialPortBuilder setBaudRate(int baudRate) { + this.baudRate = baudRate; + return this; + } + + /** + * Set the number of data bits transfered with the serial port. + * + * @param dataBits + * the number of dataBits. + * @return the serial port builder. + * @see SerialPort#setDataBits(DataBits) + */ + public SerialPortBuilder setDataBits(DataBits dataBits) { + this.dataBits = dataBits; + return this; + } + + /** + * Set the parity of the serial port. + * + * @param parity + * the parity. + * @return the serial port builder. + * @see SerialPort#setParity(Parity) + */ + public SerialPortBuilder setParity(Parity parity) { + this.parity = parity; + return this; + } + + /** + * Set the number of stop bits after each data bits. + * + * @param stopBits + * the number of stop bits. + * @return the serial port builder. + * + * @see SerialPort#setStopBits(StopBits) + */ + public SerialPortBuilder setStopBits(StopBits stopBits) { + this.stopBits = stopBits; + return this; + } + + /** + * Set the flow control type. + * + * @param flowControl + * the flow control. + * + * @return the serial port builder. + * + * @see SerialPort#setFlowControl(FlowControl) + */ + public SerialPortBuilder setFlowControl(FlowControl flowControl) { + this.flowControl = flowControl; + return this; + } + + /** + * Combine all of the options that have been set and return a new SerialPort object. + * + * @return a new serial port object. + * @throws IOException + * if an I/O exception occurred while opening the serial port. + */ + public SerialPort build() throws IOException { + return JRxTxPort.openSerialPort(portName, baudRate, parity, dataBits, stopBits, flowControl); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/SerialPortException.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/SerialPortException.java new file mode 100644 index 0000000..472de9c --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/SerialPortException.java @@ -0,0 +1,23 @@ +package org.openmuc.jrxtx; + +import java.io.IOException; + +/** + * Signals that a I/O exception with the SerialPort occurred. + * + * @see SerialPort + */ +public class SerialPortException extends IOException { + + private static final long serialVersionUID = -4848841747671551647L; + + /** + * Constructs a new SerialPortException with the specified detail message. + * + * @param message + * the detail message. + */ + public SerialPortException(String message) { + super(message); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/SerialPortTimeoutException.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/SerialPortTimeoutException.java new file mode 100644 index 0000000..fb38143 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/SerialPortTimeoutException.java @@ -0,0 +1,25 @@ +package org.openmuc.jrxtx; + +import java.io.InterruptedIOException; + +/** + * Signals that the read function of the SerialPort input stream has timed out. + */ +public class SerialPortTimeoutException extends InterruptedIOException { + + private static final long serialVersionUID = -5808479011360793837L; + + public SerialPortTimeoutException() { + super(); + } + + /** + * Constructs a new SerialPortTimeoutException with the specified detail message. + * + * @param message + * the detail message. + */ + public SerialPortTimeoutException(String message) { + super(message); + } +} diff --git a/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/StopBits.java b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/StopBits.java new file mode 100644 index 0000000..28cc9ce --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/java/org/openmuc/jrxtx/StopBits.java @@ -0,0 +1,32 @@ +package org.openmuc.jrxtx; + +import org.openhab.core.io.transport.serial.SerialPort; + +/** + * The stop bits. + */ +@SuppressWarnings("deprecation") +public enum StopBits { + /** + * 1 stop bit will be sent at the end of every character. + */ + STOPBITS_1(SerialPort.STOPBITS_1), + /** + * 1.5 stop bits will be sent at the end of every character + */ + STOPBITS_1_5(SerialPort.STOPBITS_1_5), + /** + * 2 stop bits will be sent at the end of every character + */ + STOPBITS_2(SerialPort.STOPBITS_2); + + private int odlValue; + + private StopBits(int oldValue) { + this.odlValue = oldValue; + } + + int getOldValue() { + return this.odlValue; + } +} diff --git a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/binding/binding.xml b/org.openhab.binding.wmbus/src/main/resources/ESH-INF/binding/binding.xml deleted file mode 100644 index 117087e..0000000 --- a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/binding/binding.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - WMBus Binding - The WMBus binding uses a WMBus radio USB stick to receive messages and decode the contents to show the data of the devices in the UI. It uses the jMBus library, but currently, only the Techem heat cost allocators are supported. - Hanno - Felix Wagner, Ernst Rohlicek, Roman Malyugin - - - - - Amount of time (in minutes) over which discovery results are retained in inbox. By default set to 720 minutes (24 hours) - minute - - - Whether to include the BridgeUID (stick/adapter name) into the ThingUID of the metering device. May be helpful when receiving data from different sites or in different modes. By default set to false. - - - - diff --git a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/bridge.xml b/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/bridge.xml deleted file mode 100644 index c7be726..0000000 --- a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/bridge.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - The WMBus bridge represents the USB stick used to receive WMBus messages. There are three different sticks supported: Amber Wireless AMB8465-M, Radiocrafts RC1180-MBUS and IMST iM871A-USB - - - - - - - The stick model used. - - true - - - - - - - - serial-port - - The name of the serial port (e.g. /dev/ttyUSB0 or COM5). - true - - - Radio mode to operate the WMBus radio module on. - - - - - - - true - - - Type of which date/time channels should be. - - - - - - - true - DATE_TIME - - - Encryption Keys in form ID:KEY;ID:KEY all in hex format like given to the jMBus message printer test program. - - true - - - List of device IDs to filter during receive. If empty, all received devices will be handled, if at least one ID is set, only messages from this device will be handled. Device ID in decumal format as shown in WMBus message prints and given out by the jMBus message printer test program. - - true - - - - - - - The WMBus receiver which is not attached to serial port. - - - - - - - - Type of which date/time channels should be. - - - - - - - true - DATE_TIME - - - Encryption Keys in form ID:KEY;ID:KEY all in hex format like given to the jMBus message printer test program. - - true - - - List of device IDs to filter during receive. If empty, all received devices will be handled, if at least one ID is set, only messages from this device will be handled. Device ID in decumal format as shown in WMBus message prints and given out by the jMBus message printer test program. - - true - - - - - - String - - Raw representation of last frame received by device encoded in HEX form. - - - - - diff --git a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/channel-types.xml b/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/channel-types.xml deleted file mode 100644 index 9e878a8..0000000 --- a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/channel-types.xml +++ /dev/null @@ -1,157 +0,0 @@ - - - - - Number:Energy - - Current energy reading - Energy - - - - - - Number:Volume - - Current volume reading - Volume - - - - - - - Number:Power - - Current power reading. - Power - - - - - - Number:Dimensionless - - - Current flow volume reading. - VolumetricFlowRate - - - - - - Number:Temperature - - Current flow temperature reading. - FlowPipe - - - - - - Number:Temperature - - Current return temperature reading. - ReturnPipe - - - - - - Number:Temperature - - Current external temperature reading. - Temperature - - - - - - Number:Temperature - - Current difference between flow and return temperatures. - Temperature - - - - - - Number:Power - - Maximum power reading registered by meter. - Power - - - - - - Number:Dimensionless - - - Maximum flow volume reading registered by meter. - VolumetricFlowRate - - - - - - Number:Temperature - - Maximum flow temperature reading registered by meter. - Temperature - - - - - - Number:Temperature - - Maximum return temperature reading registered by meter. - Temperature - - - - - - Number:Temperature - - Maximum external temperature reading registered by meter. - Temperature - - - - - - Number:Time - - Time since meter reported error (?). - Time - - - - - - DateTime - - The date, when the device last encountered an error. May be set to manufacturing date, installation date or sometime far in the future if none happened yet. - Date - - - - - - Number - - Current error flags value. - QualityOfService - - - - - diff --git a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/itron.xml b/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/itron.xml deleted file mode 100644 index ec9a9aa..0000000 --- a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/itron.xml +++ /dev/null @@ -1,417 +0,0 @@ - - - - - - - - - - - - - - Smoke detectors implemented on top of WM-Bus specification, manufactured by Itron. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DateTime - - Date and time with resolution up to a second. - - - - - - DateTime - - Date and time with resolution up to a second, formatted as a string. - - - - - - DateTime - - Date and time with resolution up to a second, formatted as a unix timestamp. - - - - - - - Switch - - Removal occurred - - - - - Switch - - Billing month - - - - - Switch - - Product is installed. - - - - - Number - - Operation mode. - - - - - - - - - - - Switch - - Perimeter intrusion occurred - - - - - Switch - - Smoke inlet blocked occurred - - - - - Switch - - Temperature out of range occurred - - - - - String - - - - - - - Number - - Battery lifetime - - - - - - - - DateTime - - Last Smoke Alert Start dates - - - - - DateTime - - Last Smoke Alert Start dates (formatted as string) - - - - - DateTime - - Last Smoke Alert Start dates (formatted as number) - - - - - DateTime - - Last Smoke Alert End dates - - - - - DateTime - - Last Smoke Alert End dates (formatted as string) - - - - - DateTime - - Last Smoke Alert End dates (formatted as number) - - - - - DateTime - - Last Beeper stopped during smoke alert dates - - - - - DateTime - - Last Beeper stopped during smoke alert dates (formatted as string) - - - - - DateTime - - Last Beeper stopped during smoke alert dates (formatted as number) - - - - - DateTime - - Last Perimeter Intrusion (Obstacle occured) dates - - - - - DateTime - - Last Perimeter Intrusion (Obstacle occured) dates (formatted as string) - - - - - DateTime - - Last Perimeter Intrusion (Obstacle occured) dates (formatted as number) - - - - - DateTime - - Last Perimeter Intrusion (Obstacle removed) dates - - - - - DateTime - - Last Perimeter Intrusion (Obstacle removed) dates (formatted as string) - - - - - DateTime - - Last Perimeter Intrusion (Obstacle removed) dates (formatted as number) - - - - - DateTime - - last Smoke inlet (Blocked) dates - - - - - DateTime - - Last Smoke inlet (Blocked) dates (formatted as string) - - - - - DateTime - - Last Smoke inlet (Blocked) dates (formatted as number) - - - - - DateTime - - Last Smoke inlet (Blocking removed) dates - - - - - DateTime - - Last Smoke inlet (Blocking removed) dates (formatted as string) - - - - - DateTime - - Last Smoke inlet (Blocking removed) dates (formatted as number) - - - - - DateTime - - Last out of Temperate Range date - - - - - DateTime - - Last out of Temperate Range date (formatted as string) - - - - - DateTime - - Last out of Temperate Range date (formatted as number) - - - - - DateTime - - Last Testswitch dates - - - - - DateTime - - Last Testswitch dates (formatted as string) - - - - - DateTime - - Last Testswitch dates (formatted as number) - - - - - Number - - Number of test switches operated - - - - - - Number - - Perimeter Intrusion day counter cumulated - - - - - - Number - - Smoke inlet day counter cumulated - - - - - \ No newline at end of file diff --git a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/techem.xml b/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/techem.xml deleted file mode 100644 index 574ad0a..0000000 --- a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/techem.xml +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - - - - - A heat cost allocator of Techem - - - - - - - - - - - - - - - - - - - - - - - - A heat cost allocator of Techem - - - - - - - - - - - - - - - - - - - - - - - - - A heat cost allocator of Techem - - - - - - - - - - - - - - - - - - - - - - - - - A heat cost allocator of Techem - - - - - - - - - - - - - - - - - - - - - - - - - - - A heat cost allocator of Techem - - - - - - - - - - - - - - - - - - - - - - - - - - A smoke detector of Techem - - - - - - - - - - - - - - - - - - - - - - A warm water meter of Techem - - - - - - - - - - - - - - - - - - - - - - - - - - - A cold water meter of Techem - - - - - - - - - - - - - - - - - - - - - - - - A heat meter of Techem - - - - - - - - - - - - - - - - - diff --git a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/thing-types.xml b/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/thing-types.xml deleted file mode 100644 index 03ed6c7..0000000 --- a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/thing/thing-types.xml +++ /dev/null @@ -1,244 +0,0 @@ - - - - - - - - - - - - - - Universal WMBus device. - - - - - Identifier which lets to find device (in hexdecimal format). - true - - - - - Frequency of updates sent by device. This value is used to determine if device goes offline. - Recommended value depends on manufacturer and specific meter and should be adjusted manually. - Defaults to 60 minutes which is quite long. - - false - minutes - - - - - - - - - - - - - WMBus device which uses secured communication - you need to provide a encryption key to read reported values. - - - - - Identifier which lets to find device (in hexdecimal format). - true - - - - - Frequency of updates sent by device. This value is used to determine if device goes offline. - Recommended value depends on manufacturer and specific meter and should be adjusted manually. - Defaults to 60 minutes which is quite long. - - false - minutes - - - - - Encryption key in hexadecimal format to decode frames sent by this device. Value of this configuration parameter - is optional and required only in case when meter is configured to use encrypted communication. - - false - encryption - - - - - - - Number - - Current temperature in the room in degrees celsius. - Temperature - - - - - Number - - Current temperature of the radiator in degrees celsius. - Temperature - - - - - Number - - Current heat cost allocation reading. - Energy - - - - - Number - - Heat cost allocation reading of previous month. - Energy - - - - - Number - - Heat cost allocation reading of the previous accounting period, usually yearly. - Energy - - - - - DateTime - - The time when the current reading was taken. - Date - - - - - String - - The time when the current reading was taken, formatted as text. - Date - - - - - Number - - The time when the current reading was taken, formatted as UNIX timestmap. - Date - - - - - DateTime - - The time when the previous month's reading was taken. - Date - - - - - String - - The time when the previous month's reading was taken, formatted as text. - Date - - - - - Number - - The time when the previous month's reading was taken, formatted as UNIX timestmap. - Date - - - - - DateTime - - The time when the reading of the previous period was taken. - Date - - - - - String - - The time when the reading of the previous period was taken, formatted as text. - Date - - - - - Number - - The time when the reading of the previous period was taken, formatted as UNIX timestmap. - Date - - - - - Number - - The Received Signal Strength Indication, power of the radio signal in dBm (decibel milliwatt) - QualityOfService - - - - - String - - The Readings of all last months separately. - Date - - - - - Number - - The status byte represented as number. - System - - - - - Number - - Consumption of water/heat accumulated in periods between 1-16. - - - - - - DateTime - - The time when the current reading was taken. - Date - - - - - String - - The time when the current reading was taken, formatted as text. - Date - - - - - Number - - The time when the current reading was taken, formatted as UNIX timestmap. - Date - - - - \ No newline at end of file diff --git a/org.openhab.binding.wmbus/src/main/resources/OH-INF/binding/binding.xml b/org.openhab.binding.wmbus/src/main/resources/OH-INF/binding/binding.xml new file mode 100644 index 0000000..8f9028e --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/resources/OH-INF/binding/binding.xml @@ -0,0 +1,26 @@ + + + + WMBus Binding + The WMBus binding uses a WMBus radio USB stick to receive messages and decode the contents to show the + data of the devices in the UI. It uses the jMBus library, but currently, only the Techem heat cost allocators are + supported. + Hanno - Felix Wagner, Ernst Rohlicek, Roman Malyugin + + + + + Amount of time (in minutes) over which discovery results are retained in inbox. By default set to 720 + minutes (24 hours) + minute + + + Whether to include the BridgeUID (stick/adapter name) into the ThingUID of the metering device. May be + helpful when receiving data from different sites or in different modes. By default set to true. + + + + + diff --git a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/i18n/wmbus.properties b/org.openhab.binding.wmbus/src/main/resources/OH-INF/i18n/wmbus.properties similarity index 100% rename from org.openhab.binding.wmbus/src/main/resources/ESH-INF/i18n/wmbus.properties rename to org.openhab.binding.wmbus/src/main/resources/OH-INF/i18n/wmbus.properties diff --git a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/i18n/wmbus_xx_XX.properties b/org.openhab.binding.wmbus/src/main/resources/OH-INF/i18n/wmbus_xx_XX.properties similarity index 73% rename from org.openhab.binding.wmbus/src/main/resources/ESH-INF/i18n/wmbus_xx_XX.properties rename to org.openhab.binding.wmbus/src/main/resources/OH-INF/i18n/wmbus_xx_XX.properties index 6f17200..76062d0 100644 --- a/org.openhab.binding.wmbus/src/main/resources/ESH-INF/i18n/wmbus_xx_XX.properties +++ b/org.openhab.binding.wmbus/src/main/resources/OH-INF/i18n/wmbus_xx_XX.properties @@ -8,6 +8,10 @@ binding.wmbus.description = thing-type.wmbus.sample.label = thing-type.wmbus.sample.description = +# thing type config description +thing-type.config.wmbus.sample.config1.label = +thing-type.config.wmbus.sample.config1.description = + # channel types channel-type.wmbus.sample-channel.label = channel-type.wmbus.sample-channel.description = 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 new file mode 100644 index 0000000..b01daf0 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/bridge.xml @@ -0,0 +1,113 @@ + + + + + + The WMBus bridge represents the USB stick used to receive WMBus messages. There are three different + sticks supported: Amber Wireless AMB8465-M, Radiocrafts RC1180-MBUS and IMST iM871A-USB + + + + + + + The stick model used. + + true + + + + + + + + serial-port + + The name of the serial port (e.g. /dev/ttyUSB0 or COM5). + true + + + Radio mode to operate the WMBus radio module on. + + + + + + + true + + + Type of which date/time channels should be. + + + + + + + true + DATE_TIME + + + Encryption Keys in form ID:KEY;ID:KEY all in hex format like given to the jMBus message printer test + program. + + true + + + List of device IDs to filter during receive. If empty, all received devices will be handled, if at + least one ID is set, only messages from this device will be handled. Device ID in decumal format as shown in WMBus + message prints and given out by the jMBus message printer test program. + + true + + + + + + + The WMBus receiver which is not attached to serial port. + + + + + + + + Type of which date/time channels should be. + + + + + + + true + DATE_TIME + + + Encryption Keys in form ID:KEY;ID:KEY all in hex format like given to the jMBus message printer test + program. + + true + + + List of device IDs to filter during receive. If empty, all received devices will be handled, if at + least one ID is set, only messages from this device will be handled. Device ID in decumal format as shown in WMBus + message prints and given out by the jMBus message printer test program. + + true + + + + + + String + + Raw representation of last frame received by device encoded in HEX form. + + + + + diff --git a/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/channel-types.xml b/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/channel-types.xml new file mode 100644 index 0000000..6f67033 --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/channel-types.xml @@ -0,0 +1,159 @@ + + + + + Number:Energy + + Current energy reading + Energy + + + + + + Number:Volume + + Current volume reading + Volume + + + + + + + Number:Power + + Current power reading. + Power + + + + + + Number:Dimensionless + + + Current flow volume reading. + VolumetricFlowRate + + + + + + Number:Temperature + + Current flow temperature reading. + FlowPipe + + + + + + Number:Temperature + + Current return temperature reading. + ReturnPipe + + + + + + Number:Temperature + + Current external temperature reading. + Temperature + + + + + + Number:Temperature + + Current difference between flow and return temperatures. + Temperature + + + + + + Number:Power + + Maximum power reading registered by meter. + Power + + + + + + Number:Dimensionless + + + Maximum flow volume reading registered by meter. + VolumetricFlowRate + + + + + + Number:Temperature + + Maximum flow temperature reading registered by meter. + Temperature + + + + + + Number:Temperature + + Maximum return temperature reading registered by meter. + Temperature + + + + + + Number:Temperature + + Maximum external temperature reading registered by meter. + Temperature + + + + + + Number:Time + + Time since meter reported error (?). + Time + + + + + + DateTime + + The date, when the device last encountered an error. May be set to manufacturing date, installation date + or sometime far in the future if none happened yet. + Date + + + + + + Number + + Current error flags value. + QualityOfService + + + + + diff --git a/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/itron.xml b/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/itron.xml new file mode 100644 index 0000000..580bf8a --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/itron.xml @@ -0,0 +1,429 @@ + + + + + + + + + + + + + + Smoke detectors implemented on top of WM-Bus specification, manufactured by Itron. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DateTime + + Date and time with resolution up to a second. + + + + + + DateTime + + Date and time with resolution up to a second, formatted as a string. + + + + + + DateTime + + Date and time with resolution up to a second, formatted as a unix timestamp. + + + + + + + Switch + + Removal occurred + + + + + Switch + + Billing month + + + + + Switch + + Product is installed. + + + + + Number + + Operation mode. + + + + + + + + + + + Switch + + Perimeter intrusion occurred + + + + + Switch + + Smoke inlet blocked occurred + + + + + Switch + + Temperature out of range occurred + + + + + String + + + + + + + Number + + Battery lifetime + + + + + + + + DateTime + + Last Smoke Alert Start dates + + + + + DateTime + + Last Smoke Alert Start dates (formatted as string) + + + + + DateTime + + Last Smoke Alert Start dates (formatted as number) + + + + + DateTime + + Last Smoke Alert End dates + + + + + DateTime + + Last Smoke Alert End dates (formatted as string) + + + + + DateTime + + Last Smoke Alert End dates (formatted as number) + + + + + DateTime + + Last Beeper stopped during smoke alert dates + + + + + DateTime + + Last Beeper stopped during smoke alert dates (formatted as string) + + + + + DateTime + + Last Beeper stopped during smoke alert dates (formatted as number) + + + + + DateTime + + Last Perimeter Intrusion (Obstacle occured) dates + + + + + DateTime + + Last Perimeter Intrusion (Obstacle occured) dates (formatted as string) + + + + + DateTime + + Last Perimeter Intrusion (Obstacle occured) dates (formatted as number) + + + + + DateTime + + Last Perimeter Intrusion (Obstacle removed) dates + + + + + DateTime + + Last Perimeter Intrusion (Obstacle removed) dates (formatted as string) + + + + + DateTime + + Last Perimeter Intrusion (Obstacle removed) dates (formatted as number) + + + + + DateTime + + last Smoke inlet (Blocked) dates + + + + + DateTime + + Last Smoke inlet (Blocked) dates (formatted as string) + + + + + DateTime + + Last Smoke inlet (Blocked) dates (formatted as number) + + + + + DateTime + + Last Smoke inlet (Blocking removed) dates + + + + + DateTime + + Last Smoke inlet (Blocking removed) dates (formatted as string) + + + + + DateTime + + Last Smoke inlet (Blocking removed) dates (formatted as number) + + + + + DateTime + + Last out of Temperate Range date + + + + + DateTime + + Last out of Temperate Range date (formatted as string) + + + + + DateTime + + Last out of Temperate Range date (formatted as number) + + + + + DateTime + + Last Testswitch dates + + + + + DateTime + + Last Testswitch dates (formatted as string) + + + + + DateTime + + Last Testswitch dates (formatted as number) + + + + + Number + + Number of test switches operated + + + + + + Number + + Perimeter Intrusion day counter cumulated + + + + + + Number + + Smoke inlet day counter cumulated + + + + + diff --git a/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/techem.xml b/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/techem.xml new file mode 100644 index 0000000..986cf4a --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/techem.xml @@ -0,0 +1,231 @@ + + + + + + + + + + + A heat cost allocator of Techem + + + + + + + + + + + + + + + + + + + + + + + + A heat cost allocator of Techem + + + + + + + + + + + + + + + + + + + + + + + + + A heat cost allocator of Techem + + + + + + + + + + + + + + + + + + + + + + + + + A heat cost allocator of Techem + + + + + + + + + + + + + + + + + + + + + + + + + + + A heat cost allocator of Techem + + + + + + + + + + + + + + + + + + + + + + + + + + A smoke detector of Techem + + + + + + + + + + + + + + + + + + + + + + A warm water meter of Techem + + + + + + + + + + + + + + + + + + + + + + + + + + + A cold water meter of Techem + + + + + + + + + + + + + + + + + + + + + + + + A heat meter of Techem + + + + + + + + + + + + + + + + + diff --git a/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/thing-types.xml b/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/thing-types.xml new file mode 100644 index 0000000..0876c2f --- /dev/null +++ b/org.openhab.binding.wmbus/src/main/resources/OH-INF/thing/thing-types.xml @@ -0,0 +1,248 @@ + + + + + + + + + + + + + Universal WMBus device. + + + + + Identifier which lets to find device (in hexdecimal format). + true + + + + + Frequency of updates sent by device. This value is used to determine if device goes offline. + Recommended value depends on manufacturer and specific meter and should be adjusted manually. + Defaults to 60 minutes + which is quite long. + + false + minutes + + + + + + + + + + + + + WMBus device which uses secured communication - you need to provide a encryption key to read reported + values. + + + + + Identifier which lets to find device (in hexdecimal format). + true + + + + + Frequency of updates sent by device. This value is used to determine if device goes offline. + Recommended value depends on manufacturer and specific meter and should be adjusted manually. + Defaults to 60 minutes + which is quite long. + + false + minutes + + + + + Encryption key in hexadecimal format to decode frames sent by this device. Value of this configuration + parameter + is optional and required only in case when meter is configured to use encrypted communication. + + false + encryption + + + + + + + Number + + Current temperature in the room in degrees celsius. + Temperature + + + + + Number + + Current temperature of the radiator in degrees celsius. + Temperature + + + + + Number + + Current heat cost allocation reading. + Energy + + + + + Number + + Heat cost allocation reading of previous month. + Energy + + + + + Number + + Heat cost allocation reading of the previous accounting period, usually yearly. + Energy + + + + + DateTime + + The time when the current reading was taken. + Date + + + + + String + + The time when the current reading was taken, formatted as text. + Date + + + + + Number + + The time when the current reading was taken, formatted as UNIX timestmap. + Date + + + + + DateTime + + The time when the previous month's reading was taken. + Date + + + + + String + + The time when the previous month's reading was taken, formatted as text. + Date + + + + + Number + + The time when the previous month's reading was taken, formatted as UNIX timestmap. + Date + + + + + DateTime + + The time when the reading of the previous period was taken. + Date + + + + + String + + The time when the reading of the previous period was taken, formatted as text. + Date + + + + + Number + + The time when the reading of the previous period was taken, formatted as UNIX timestmap. + Date + + + + + Number + + The Received Signal Strength Indication, power of the radio signal in dBm (decibel milliwatt) + QualityOfService + + + + + String + + The Readings of all last months separately. + Date + + + + + Number + + The status byte represented as number. + System + + + + + Number + + Consumption of water/heat accumulated in periods between 1-16. + + + + + + DateTime + + The time when the current reading was taken. + Date + + + + + String + + The time when the current reading was taken, formatted as text. + Date + + + + + Number + + The time when the current reading was taken, formatted as UNIX timestmap. + Date + + + + diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/AbstractWMBusTest.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/AbstractWMBusTest.java index 689e2fb..5cbd8fd 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/AbstractWMBusTest.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/AbstractWMBusTest.java @@ -2,9 +2,9 @@ import java.util.Collections; -import org.eclipse.smarthome.core.util.HexUtils; import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.handler.WMBusAdapter; +import org.openhab.core.util.HexUtils; import org.openmuc.jmbus.DecodingException; import org.openmuc.jmbus.wireless.VirtualWMBusMessageHelper; import org.openmuc.jmbus.wireless.WMBusMessage; @@ -39,7 +39,6 @@ public class AbstractWMBusTest { public final static String MESSAGE_118_SD_2 = "294468508364866476F0A000DE246F2500586F25010019000013006BA1007CB2008DC3009ED4000FE500F40000"; public final static String MESSAGE_118_SD_3 = "294468501857639176f0a000e3267b2700dc7b2700000e0001315678006ba1007cb2008dc3009ed4000fe5"; - public final static int RSSI = 10; protected final WMBusDevice message(String messageHex) throws DecodingException { @@ -52,5 +51,4 @@ protected final WMBusDevice message(String messageHex, WMBusAdapter adapter) thr return new WMBusDevice(message, adapter); } - } diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/RecordPredicate.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/RecordPredicate.java index 7941894..7eb9da1 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/RecordPredicate.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/RecordPredicate.java @@ -1,10 +1,11 @@ package org.openhab.binding.wmbus.device; import java.util.function.Predicate; + import org.openhab.binding.wmbus.device.techem.Record; /** - * Predicate for testing records reported by techem decoders. + * Predicate for testing records reported by techem decoders. * * @author Łukasz Dywicki - initial contribution */ @@ -23,5 +24,4 @@ public interface RecordPredicate extends Predicate> { * @return Arguments for formatting predicate description. */ Object[] arguments(); - } diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/generic/GenericWMBusThingHandlerTest.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/generic/GenericWMBusThingHandlerTest.java index 1952628..7368938 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/generic/GenericWMBusThingHandlerTest.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/generic/GenericWMBusThingHandlerTest.java @@ -3,20 +3,6 @@ import java.util.Map; import org.assertj.core.api.Assertions; -import org.eclipse.smarthome.config.core.Configuration; -import org.eclipse.smarthome.core.library.types.QuantityType; -import org.eclipse.smarthome.core.library.unit.SIUnits; -import org.eclipse.smarthome.core.thing.Bridge; -import org.eclipse.smarthome.core.thing.Channel; -import org.eclipse.smarthome.core.thing.ChannelUID; -import org.eclipse.smarthome.core.thing.Thing; -import org.eclipse.smarthome.core.thing.ThingUID; -import org.eclipse.smarthome.core.thing.binding.ThingHandler; -import org.eclipse.smarthome.core.thing.binding.ThingHandlerCallback; -import org.eclipse.smarthome.core.thing.binding.builder.BridgeBuilder; -import org.eclipse.smarthome.core.thing.binding.builder.ChannelBuilder; -import org.eclipse.smarthome.core.thing.binding.builder.ThingBuilder; -import org.eclipse.smarthome.core.types.State; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -31,6 +17,20 @@ import org.openhab.binding.wmbus.WMBusDevice; import org.openhab.binding.wmbus.handler.WMBusBridgeHandler; import org.openhab.binding.wmbus.internal.units.CompositeUnitRegistry; +import org.openhab.core.config.core.Configuration; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.unit.SIUnits; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerCallback; +import org.openhab.core.thing.binding.builder.BridgeBuilder; +import org.openhab.core.thing.binding.builder.ChannelBuilder; +import org.openhab.core.thing.binding.builder.ThingBuilder; +import org.openhab.core.types.State; import org.openhab.io.transport.mbus.wireless.MapKeyStorage; import org.openmuc.jmbus.DataRecord; import org.openmuc.jmbus.DlmsUnit; @@ -72,11 +72,10 @@ public GenericWMBusThingHandlerTest() { handler = new GenericWMBusThingHandler(createTestThing(), new MapKeyStorage(), new CompositeUnitRegistry(), CHANNEL_MAPPING) { @Override - protected org.eclipse.smarthome.core.thing.Bridge getBridge() { + protected org.openhab.core.thing.Bridge getBridge() { return createTestBridge(adapter); }; }; - } @Before @@ -125,5 +124,4 @@ static Bridge createTestBridge(ThingHandler handler) { bridge.setHandler(handler); return bridge; } - } diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/itron/ItronConfigStatusDataParserTest.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/itron/ItronConfigStatusDataParserTest.java index dd9c4fb..df8ffd4 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/itron/ItronConfigStatusDataParserTest.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/itron/ItronConfigStatusDataParserTest.java @@ -2,38 +2,30 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.eclipse.smarthome.core.util.HexUtils; import org.junit.Test; +import org.openhab.core.util.HexUtils; public class ItronConfigStatusDataParserTest { - private ItronConfigStatusDataParser parser = new ItronConfigStatusDataParser(HexUtils.hexToBytes("0C173E7E00208080")); + private ItronConfigStatusDataParser parser = new ItronConfigStatusDataParser( + HexUtils.hexToBytes("0C173E7E00208080")); @Test public void testParser() { - assertThat(parser.getBillingDate()) - .isEqualTo(12); + assertThat(parser.getBillingDate()).isEqualTo(12); - assertThat(parser.isRemovalOccurred()) - .isEqualTo(true); + assertThat(parser.isRemovalOccurred()).isEqualTo(true); - assertThat(parser.isProductInstalled()) - .isEqualTo(true); + assertThat(parser.isProductInstalled()).isEqualTo(true); - assertThat(parser.getOperationMode()) - .isEqualTo(1); + assertThat(parser.getOperationMode()).isEqualTo(1); - assertThat(parser.isPerimeterIntrusionOccurred()) - .isEqualTo(true); + assertThat(parser.isPerimeterIntrusionOccurred()).isEqualTo(true); - assertThat(parser.isSmokeInletBlockedOccurred()) - .isEqualTo(false); + assertThat(parser.isSmokeInletBlockedOccurred()).isEqualTo(false); - assertThat(parser.isOutOfRangeTemperatureOccurred()) - .isEqualTo(false); + assertThat(parser.isOutOfRangeTemperatureOccurred()).isEqualTo(false); - assertThat(parser.getProductCode()) - .isEqualTo((byte) 0x3E); + assertThat(parser.getProductCode()).isEqualTo((byte) 0x3E); } - -} \ No newline at end of file +} diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/itron/ItronManufacturerDataParserTest.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/itron/ItronManufacturerDataParserTest.java index 49fbbbe..7f5ad5c 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/itron/ItronManufacturerDataParserTest.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/itron/ItronManufacturerDataParserTest.java @@ -3,11 +3,11 @@ import static org.assertj.core.api.Assertions.*; import java.time.LocalDateTime; -import org.assertj.core.api.Assertions; -import org.eclipse.smarthome.core.util.HexUtils; + import org.junit.Ignore; import org.junit.Test; import org.openhab.binding.wmbus.device.techem.decoder.Buffer; +import org.openhab.core.util.HexUtils; public class ItronManufacturerDataParserTest { @@ -23,21 +23,19 @@ private static byte[] hex(String hexStr) { @Test public void testShortDate() { assertThat(new ItronManufacturerDataParser(new Buffer(_2019_12_29_0313)).readShortDateTime()) - .isEqualTo(LocalDateTime.of(2019, 12, 29, 3, 13)); + .isEqualTo(LocalDateTime.of(2019, 12, 29, 3, 13)); assertThat(new ItronManufacturerDataParser(new Buffer(_2020_01_09_1241)).readShortDateTime()) - .isEqualTo(LocalDateTime.of(2020, 1, 9, 12, 41)); + .isEqualTo(LocalDateTime.of(2020, 1, 9, 12, 41)); assertThat(new ItronManufacturerDataParser(new Buffer(_2020_01_08_2121)).readShortDateTime()) - .isEqualTo(LocalDateTime.of(2020, 1, 8, 21, 21)); + .isEqualTo(LocalDateTime.of(2020, 1, 8, 21, 21)); } @Test @Ignore // parsing logic is not yet done public void testLongDate() { assertThat(new ItronManufacturerDataParser(new Buffer(_2020_01_10_132057)).readLongDateTime()) - .isEqualTo(LocalDateTime.of(2020, 1, 10, 13, 20, 57)); - + .isEqualTo(LocalDateTime.of(2020, 1, 10, 13, 20, 57)); } - } diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/TechemDecoderTest.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/TechemDecoderTest.java index 6c0762f..06d109c 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/TechemDecoderTest.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/TechemDecoderTest.java @@ -7,7 +7,6 @@ import org.assertj.core.api.Assertions; import org.assertj.core.api.Condition; -import org.eclipse.smarthome.core.library.unit.SIUnits; import org.junit.Test; import org.openhab.binding.wmbus.device.AbstractWMBusTest; import org.openhab.binding.wmbus.device.techem.Record.Type; @@ -18,6 +17,7 @@ import org.openhab.binding.wmbus.device.techem.predicate.QuantityPredicate; import org.openhab.binding.wmbus.device.techem.predicate.RssiPredicate; import org.openhab.binding.wmbus.device.techem.predicate.StringPredicate; +import org.openhab.core.library.unit.SIUnits; import org.openmuc.jmbus.DeviceType; import tec.uom.se.unit.Units; @@ -34,8 +34,7 @@ public void testWarmWater112Parser() throws Exception { expectedDevice(DeviceType.WARM_WATER_METER)); Assertions.assertThat(device.getDeviceType()).isEqualTo(TechemBindingConstants._68TCH11298_6.getTechemType()); - Assertions.assertThat(device.getMeasurements()).hasSize(8) - .areAtLeastOne(record(Record.Type.STATUS, 0)) + Assertions.assertThat(device.getMeasurements()).hasSize(8).areAtLeastOne(record(Record.Type.STATUS, 0)) .areAtLeastOne(record(Record.Type.COUNTER, 3)) .areAtLeastOne(record(Record.Type.ALMANAC, "4;4;3;3;3;3;3;3;2;3;3;3;3;3;3;3;4;2;4")) .areAtLeastOne(record(Record.Type.CURRENT_VOLUME, 6.5, Units.CUBIC_METRE)) @@ -50,8 +49,7 @@ public void testColdWater112Parser() throws Exception { expectedDevice(DeviceType.COLD_WATER_METER)); Assertions.assertThat(device.getDeviceType()).isEqualTo(TechemBindingConstants._68TCH112114_16.getTechemType()); - Assertions.assertThat(device.getMeasurements()).hasSize(6) - .areAtLeastOne(record(Record.Type.STATUS, 0)) + Assertions.assertThat(device.getMeasurements()).hasSize(6).areAtLeastOne(record(Record.Type.STATUS, 0)) .areAtLeastOne(record(Record.Type.CURRENT_VOLUME, 36.3, Units.CUBIC_METRE)) .areAtLeastOne(record(Record.Type.PAST_VOLUME, 190.2, Units.CUBIC_METRE)).areAtLeastOne(rssi()); } @@ -64,8 +62,7 @@ public void testWarmWater116Parser() throws Exception { expectedDevice(DeviceType.WARM_WATER_METER)); Assertions.assertThat(device.getDeviceType()).isEqualTo(TechemBindingConstants._68TCH11698_6.getTechemType()); - Assertions.assertThat(device.getMeasurements()).hasSize(8) - .areAtLeastOne(record(Record.Type.STATUS, 6)) + Assertions.assertThat(device.getMeasurements()).hasSize(8).areAtLeastOne(record(Record.Type.STATUS, 6)) .areAtLeastOne(record(Record.Type.COUNTER, 0)) .areAtLeastOne(record(Record.Type.ALMANAC, "1;1;1;1;0;1;1;0;0;1;0;0;1;1;2;2;1;2;2;1;2;1;1;2;2;1;230;0")) .areAtLeastOne(record(Record.Type.CURRENT_VOLUME, 2.1, Units.CUBIC_METRE)) @@ -80,8 +77,7 @@ public void testColdWater116Parser() throws Exception { expectedDevice(DeviceType.COLD_WATER_METER)); Assertions.assertThat(device.getDeviceType()).isEqualTo(TechemBindingConstants._68TCH116114_16.getTechemType()); - Assertions.assertThat(device.getMeasurements()).hasSize(6) - .areAtLeastOne(record(Record.Type.STATUS, 6)) + Assertions.assertThat(device.getMeasurements()).hasSize(6).areAtLeastOne(record(Record.Type.STATUS, 6)) .areAtLeastOne(record(Record.Type.CURRENT_VOLUME, 18.1, Units.CUBIC_METRE)) .areAtLeastOne(record(Record.Type.PAST_VOLUME, 43.5, Units.CUBIC_METRE)).areAtLeastOne(rssi()); } @@ -92,7 +88,8 @@ public void testHeat113Parser() throws Exception { Assertions.assertThat(device).isNotNull().isInstanceOfSatisfying(TechemHeatMeter.class, expectedDevice(DeviceType.HEAT_METER)); - Assertions.assertThat(device.getDeviceType()).isEqualTo(TechemBindingConstants._68TCH11367_4_A2.getTechemType()); + Assertions.assertThat(device.getDeviceType()) + .isEqualTo(TechemBindingConstants._68TCH11367_4_A2.getTechemType()); Assertions.assertThat(device.getMeasurements()).hasSize(5) .areAtLeastOne(record(Record.Type.CURRENT_VOLUME, 1769472.0)) @@ -107,8 +104,7 @@ public void testHKV45() throws Exception { expectedDevice(DeviceType.HEAT_COST_ALLOCATOR)); Assertions.assertThat(device.getDeviceType()).isEqualTo(TechemBindingConstants._68TCH6967_8.getTechemType()); - Assertions.assertThat(device.getMeasurements()).hasSize(7) - .areAtLeastOne(record(Record.Type.STATUS, 0)) + Assertions.assertThat(device.getMeasurements()).hasSize(7).areAtLeastOne(record(Record.Type.STATUS, 0)) .areAtLeastOne(record(Record.Type.CURRENT_VOLUME, 5240.0)) .areAtLeastOne(record(Record.Type.PAST_VOLUME, 18727.0)).areAtLeastOne(rssi()); } @@ -121,8 +117,7 @@ public void testHKV6480() throws Exception { expectedDevice(DeviceType.HEAT_COST_ALLOCATOR)); Assertions.assertThat(device.getDeviceType()).isEqualTo(TechemBindingConstants._68TCH100128_8.getTechemType()); - Assertions.assertThat(device.getMeasurements()).hasSize(7) - .areAtLeastOne(record(Record.Type.STATUS, 17)) + Assertions.assertThat(device.getMeasurements()).hasSize(7).areAtLeastOne(record(Record.Type.STATUS, 17)) .areAtLeastOne(record(Record.Type.CURRENT_VOLUME, 65.0)) .areAtLeastOne(record(Record.Type.PAST_VOLUME, 104.0)).areAtLeastOne(rssi()); } @@ -135,10 +130,10 @@ public void testHKV6980() throws Exception { expectedDevice(DeviceType.HEAT_COST_ALLOCATOR)); Assertions.assertThat(device.getDeviceType()).isEqualTo(TechemBindingConstants._68TCH105128_8.getTechemType()); - Assertions.assertThat(device.getMeasurements()).hasSize(10) - .areAtLeastOne(record(Record.Type.STATUS, 17)) + Assertions.assertThat(device.getMeasurements()).hasSize(10).areAtLeastOne(record(Record.Type.STATUS, 17)) .areAtLeastOne(record(Record.Type.COUNTER, 16)) - .areAtLeastOne(record(Record.Type.ALMANAC, "1;0;0;2;0;0;0;0;0;0;0;0;0;0;17;11;0;32;54;29;34;31;110;146;135;73;0")) + .areAtLeastOne(record(Record.Type.ALMANAC, + "1;0;0;2;0;0;0;0;0;0;0;0;0;0;17;11;0;32;54;29;34;31;110;146;135;73;0")) .areAtLeastOne(record(Record.Type.CURRENT_VOLUME, 410.0)) .areAtLeastOne(record(Record.Type.PAST_VOLUME, 1999.0)) .areAtLeastOne(record(Record.Type.ROOM_TEMPERATURE, 21.52, SIUnits.CELSIUS)) @@ -153,10 +148,10 @@ public void testHKV148() throws Exception { expectedDevice(DeviceType.HEAT_COST_ALLOCATOR)); Assertions.assertThat(device.getDeviceType()).isEqualTo(TechemBindingConstants._68TCH148128_8.getTechemType()); - Assertions.assertThat(device.getMeasurements()).hasSize(10) - .areAtLeastOne(record(Record.Type.STATUS, 15)) + Assertions.assertThat(device.getMeasurements()).hasSize(10).areAtLeastOne(record(Record.Type.STATUS, 15)) .areAtLeastOne(record(Record.Type.COUNTER, 0)) - .areAtLeastOne(record(Record.Type.ALMANAC, "0;0;0;0;0;0;7;31;36;30;69;78;66;88;132;120;119;94;79;46;20;0;0;0;0;219;0")) + .areAtLeastOne(record(Record.Type.ALMANAC, + "0;0;0;0;0;0;7;31;36;30;69;78;66;88;132;120;119;94;79;46;20;0;0;0;0;219;0")) .areAtLeastOne(record(Record.Type.CURRENT_VOLUME, 258.0)) .areAtLeastOne(record(Record.Type.PAST_VOLUME, 412.0)) .areAtLeastOne(record(Record.Type.ROOM_TEMPERATURE, 26.48, SIUnits.CELSIUS)) @@ -172,8 +167,7 @@ public void testSD76F0() throws Exception { Assertions.assertThat(device.getDeviceType()) .isEqualTo(TechemBindingConstants._68TCH118255_161_A0.getTechemType()); - Assertions.assertThat(device.getMeasurements()).hasSize(4) - .areAtLeastOne(record(Type.STATUS, 0)) + Assertions.assertThat(device.getMeasurements()).hasSize(4).areAtLeastOne(record(Type.STATUS, 0)) .areAtLeastOne(record(Type.CURRENT_READING_DATE, LocalDate.of(LocalDate.now().getYear(), 3, 23))) .areAtLeastOne(record(Type.CURRENT_READING_DATE_SMOKE, LocalDate.of(2019, 11, 27))) .areAtLeastOne(rssi()); @@ -189,8 +183,7 @@ public void testSD76F0_extra() throws Exception { Assertions.assertThat(device.getDeviceType()) .isEqualTo(TechemBindingConstants._68TCH118255_161_A0.getTechemType()); - Assertions.assertThat(device.getMeasurements()).hasSize(4) - .areAtLeastOne(record(Type.STATUS, 0)) + Assertions.assertThat(device.getMeasurements()).hasSize(4).areAtLeastOne(record(Type.STATUS, 0)) .areAtLeastOne(record(Type.CURRENT_READING_DATE, LocalDate.of(LocalDate.now().getYear(), 2, 22))) .areAtLeastOne(record(Type.CURRENT_READING_DATE_SMOKE, LocalDate.of(2018, 11, 15))) .areAtLeastOne(rssi()); @@ -237,5 +230,4 @@ private Consumer expectedDevice(DeviceType deviceTyp Assertions.assertThat(device.getTechemDeviceType()).isEqualTo(deviceType); }; } - } diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/TechemDiscoveryTest.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/TechemDiscoveryTest.java index 2a95940..c739b48 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/TechemDiscoveryTest.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/TechemDiscoveryTest.java @@ -3,8 +3,6 @@ import static org.mockito.Mockito.when; import org.assertj.core.api.Assertions; -import org.eclipse.smarthome.config.discovery.DiscoveryResult; -import org.eclipse.smarthome.core.thing.ThingUID; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -15,6 +13,8 @@ import org.openhab.binding.wmbus.device.techem.decoder.CompositeTechemFrameDecoder; import org.openhab.binding.wmbus.handler.WMBusAdapter; import org.openhab.binding.wmbus.internal.DynamicBindingConfiguration; +import org.openhab.core.config.discovery.DiscoveryResult; +import org.openhab.core.thing.ThingUID; import org.openmuc.jmbus.DecodingException; @RunWith(MockitoJUnitRunner.class) @@ -106,5 +106,4 @@ private DiscoveryResult result(String message) throws DecodingException { return discoverer.createResult(message(message, adapter)); } - } diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/TechemHandlerFactoryTest.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/TechemHandlerFactoryTest.java index 01223e4..738e9b2 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/TechemHandlerFactoryTest.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/TechemHandlerFactoryTest.java @@ -1,11 +1,11 @@ package org.openhab.binding.wmbus.device.techem; import org.assertj.core.api.Assertions; -import org.eclipse.smarthome.core.thing.binding.ThingHandler; -import org.eclipse.smarthome.core.thing.internal.ThingImpl; import org.junit.Before; import org.junit.Test; import org.openhab.binding.wmbus.device.techem.decoder.CompositeTechemFrameDecoder; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.internal.ThingImpl; public class TechemHandlerFactoryTest implements TechemBindingConstants { @@ -71,5 +71,4 @@ public void testWZ43Support() { ThingHandler handler = handlerFactory.createHandler(thing); Assertions.assertThat(handler).isNotNull(); } - } diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/FloatPredicate.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/FloatPredicate.java index 87a0f33..c815400 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/FloatPredicate.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/FloatPredicate.java @@ -27,8 +27,7 @@ public boolean test(Record record) { } protected void testValue(Object value) { - Assertions.assertThat(value).isInstanceOf(Float.class) - .isEqualTo(expectedValue); + Assertions.assertThat(value).isInstanceOf(Float.class).isEqualTo(expectedValue); } public String description() { diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/IntegerPredicate.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/IntegerPredicate.java index 9592918..71bdd7e 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/IntegerPredicate.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/IntegerPredicate.java @@ -1,6 +1,7 @@ package org.openhab.binding.wmbus.device.techem.predicate; import java.util.function.Predicate; + import org.assertj.core.api.Assertions; import org.openhab.binding.wmbus.device.techem.Record; @@ -27,8 +28,7 @@ public boolean test(Record record) { } protected void testValue(Object value) { - Assertions.assertThat(value).isInstanceOf(Integer.class) - .isEqualTo(expectedValue); + Assertions.assertThat(value).isInstanceOf(Integer.class).isEqualTo(expectedValue); } public String description() { diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/LocalDatePredicate.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/LocalDatePredicate.java index 28e8d04..60d9202 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/LocalDatePredicate.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/LocalDatePredicate.java @@ -2,6 +2,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; + import org.assertj.core.api.Assertions; import org.openhab.binding.wmbus.device.RecordPredicate; import org.openhab.binding.wmbus.device.techem.Record; diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/QuantityPredicate.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/QuantityPredicate.java index a3c260e..f6a1b68 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/QuantityPredicate.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/QuantityPredicate.java @@ -2,6 +2,7 @@ import javax.measure.Quantity; import javax.measure.Unit; + import org.assertj.core.api.Assertions; import org.openhab.binding.wmbus.device.techem.Record; @@ -19,8 +20,7 @@ protected void testValue(Object value) { Assertions.assertThat(value).isInstanceOf(Quantity.class); Quantity quantity = (Quantity) value; - Assertions.assertThat(quantity.getValue().floatValue()) - .isEqualTo(Double.valueOf(expectedValue).floatValue()); + Assertions.assertThat(quantity.getValue().floatValue()).isEqualTo(Double.valueOf(expectedValue).floatValue()); Assertions.assertThat(quantity.getUnit()).isEqualTo(unit); } diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/RssiPredicate.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/RssiPredicate.java index 981b1de..b9d8d31 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/RssiPredicate.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/RssiPredicate.java @@ -11,5 +11,4 @@ public RssiPredicate(int expectedValue) { public String description() { return "Missing RSSI record, with expected value %d"; } - } diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/StringPredicate.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/StringPredicate.java index 724bb63..ed7bb26 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/StringPredicate.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/device/techem/predicate/StringPredicate.java @@ -27,8 +27,7 @@ public boolean test(Record record) { } protected void testValue(Object value) { - Assertions.assertThat(value).isInstanceOf(String.class) - .isEqualTo(expectedValue); + Assertions.assertThat(value).isInstanceOf(String.class).isEqualTo(expectedValue); } public String description() { @@ -38,5 +37,4 @@ public String description() { public Object[] arguments() { return new Object[] { type, expectedValue }; } - } diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/BaseUnitRegistryTest.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/BaseUnitRegistryTest.java index e792527..82a350e 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/BaseUnitRegistryTest.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/BaseUnitRegistryTest.java @@ -13,11 +13,11 @@ import javax.measure.Unit; import org.assertj.core.api.Assertions; -import org.eclipse.smarthome.core.library.unit.ImperialUnits; -import org.eclipse.smarthome.core.library.unit.SIUnits; -import org.eclipse.smarthome.core.library.unit.SmartHomeUnits; import org.junit.Test; import org.openhab.binding.wmbus.UnitRegistry; +import org.openhab.core.library.unit.ImperialUnits; +import org.openhab.core.library.unit.SIUnits; +import org.openhab.core.library.unit.Units; import org.openmuc.jmbus.DlmsUnit; /** @@ -35,7 +35,7 @@ protected BaseUnitRegistryTest(UnitRegistry registry) { @Test public void testConversionOf_ampere() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.AMPERE)).hasValue(SmartHomeUnits.AMPERE); + Assertions.assertThat(lookup(DlmsUnit.AMPERE)).hasValue(Units.AMPERE); } @Test @@ -75,7 +75,7 @@ public void testConversionOf_calorific_value() throws Exception { @Test public void testConversionOf_coulomb() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.COULOMB)).contains(SmartHomeUnits.COULOMB); + Assertions.assertThat(lookup(DlmsUnit.COULOMB)).contains(Units.COULOMB); } @Test @@ -123,7 +123,7 @@ public void testConversionOf_currency() throws Exception { @Test public void testConversionOf_day() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.DAY)).contains(SmartHomeUnits.DAY); + Assertions.assertThat(lookup(DlmsUnit.DAY)).contains(Units.DAY); } @Test @@ -148,27 +148,27 @@ public void testConversionOf_energy_per_volume() throws Exception { @Test public void testConversionOf_farad() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.FARAD)).contains(SmartHomeUnits.FARAD); + Assertions.assertThat(lookup(DlmsUnit.FARAD)).contains(Units.FARAD); } @Test public void testConversionOf_henry() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.HENRY)).contains(SmartHomeUnits.HENRY); + Assertions.assertThat(lookup(DlmsUnit.HENRY)).contains(Units.HENRY); } @Test public void testConversionOf_hertz() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.HERTZ)).contains(SmartHomeUnits.HERTZ); + Assertions.assertThat(lookup(DlmsUnit.HERTZ)).contains(Units.HERTZ); } @Test public void testConversionOf_hour() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.HOUR)).contains(SmartHomeUnits.HOUR); + Assertions.assertThat(lookup(DlmsUnit.HOUR)).contains(Units.HOUR); } @Test public void testConversionOf_joule() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.JOULE)).contains(SmartHomeUnits.JOULE); + Assertions.assertThat(lookup(DlmsUnit.JOULE)).contains(Units.JOULE); } @Test @@ -178,7 +178,7 @@ public void testConversionOf_joule_per_hour() throws Exception { @Test public void testConversionOf_kelvin() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.KELVIN)).contains(SmartHomeUnits.KELVIN); + Assertions.assertThat(lookup(DlmsUnit.KELVIN)).contains(Units.KELVIN); } @Test @@ -198,7 +198,7 @@ public void testConversionOf_kilogram_per_second() throws Exception { @Test public void testConversionOf_litre() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.LITRE)).contains(SmartHomeUnits.LITRE); + Assertions.assertThat(lookup(DlmsUnit.LITRE)).contains(Units.LITRE); } @Test @@ -218,12 +218,12 @@ public void testConversionOf_metre() throws Exception { @Test public void testConversionOf_metre_per_second() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.METRE_PER_SECOND)).contains(SmartHomeUnits.METRE_PER_SECOND); + Assertions.assertThat(lookup(DlmsUnit.METRE_PER_SECOND)).contains(Units.METRE_PER_SECOND); } @Test public void testConversionOf_min() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.MIN)).contains(SmartHomeUnits.MINUTE); + Assertions.assertThat(lookup(DlmsUnit.MIN)).contains(Units.MINUTE); } @Test @@ -233,12 +233,12 @@ public void testConversionOf_mole_percent() throws Exception { @Test public void testConversionOf_month() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.MONTH)).contains(SmartHomeUnits.FARAD); + Assertions.assertThat(lookup(DlmsUnit.MONTH)).contains(Units.FARAD); } @Test public void testConversionOf_newton() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.NEWTON)).contains(SmartHomeUnits.NEWTON); + Assertions.assertThat(lookup(DlmsUnit.NEWTON)).contains(Units.NEWTON); } @Test @@ -248,7 +248,7 @@ public void testConversionOf_newtonmeter() throws Exception { @Test public void testConversionOf_ohm() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.OHM)).contains(SmartHomeUnits.OHM); + Assertions.assertThat(lookup(DlmsUnit.OHM)).contains(Units.OHM); } @Test @@ -288,7 +288,7 @@ public void testConversionOf_reserved() throws Exception { @Test public void testConversionOf_second() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.SECOND)).contains(SmartHomeUnits.SECOND); + Assertions.assertThat(lookup(DlmsUnit.SECOND)).contains(Units.SECOND); } @Test @@ -303,7 +303,7 @@ public void testConversionOf_specific_energy() throws Exception { @Test public void testConversionOf_tesla() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.TESLA)).contains(SmartHomeUnits.TESLA); + Assertions.assertThat(lookup(DlmsUnit.TESLA)).contains(Units.TESLA); } @Test @@ -333,7 +333,7 @@ public void testConversionOf_var_hour() throws Exception { @Test public void testConversionOf_volt() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.VOLT)).contains(SmartHomeUnits.VOLT); + Assertions.assertThat(lookup(DlmsUnit.VOLT)).contains(Units.VOLT); } @Test @@ -363,31 +363,30 @@ public void testConversionOf_volt_squared_hour_meter_constant_or_pulse_value() t @Test public void testConversionOf_watt() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.WATT)).contains(SmartHomeUnits.WATT); + Assertions.assertThat(lookup(DlmsUnit.WATT)).contains(Units.WATT); } @Test public void testConversionOf_watt_hour() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.WATT_HOUR)).contains(SmartHomeUnits.WATT_HOUR); + Assertions.assertThat(lookup(DlmsUnit.WATT_HOUR)).contains(Units.WATT_HOUR); } @Test public void testConversionOf_weber() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.WEBER)).contains(SmartHomeUnits.WEBER); + Assertions.assertThat(lookup(DlmsUnit.WEBER)).contains(Units.WEBER); } @Test public void testConversionOf_week() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.WEEK)).contains(SmartHomeUnits.WEEK); + Assertions.assertThat(lookup(DlmsUnit.WEEK)).contains(Units.WEEK); } @Test public void testConversionOf_year() throws Exception { - Assertions.assertThat(lookup(DlmsUnit.YEAR)).contains(SmartHomeUnits.YEAR); + Assertions.assertThat(lookup(DlmsUnit.YEAR)).contains(Units.YEAR); } protected Optional> lookup(DlmsUnit wmbusType) { return registry.lookup(wmbusType); } - } diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/CompositeUnitRegistryTest.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/CompositeUnitRegistryTest.java index 6a9be2d..a603dbc 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/CompositeUnitRegistryTest.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/CompositeUnitRegistryTest.java @@ -9,7 +9,7 @@ package org.openhab.binding.wmbus.internal.units; /** - * Test of {@link CompositeUnitRegistry} with {@link SmartHomeUnitsRegistry}. + * Test of {@link CompositeUnitRegistry} with {@link UnitsRegistry}. * * They should behave in same way together. * @@ -18,7 +18,6 @@ public class CompositeUnitRegistryTest extends BaseUnitRegistryTest { public CompositeUnitRegistryTest() { - super(new CompositeUnitRegistry(new SmartHomeUnitsRegistry())); + super(new CompositeUnitRegistry(new UnitsRegistry())); } - } diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/ExtendedCompositeUnitRegistryTest.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/ExtendedCompositeUnitRegistryTest.java index 2431654..9f9199b 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/ExtendedCompositeUnitRegistryTest.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/ExtendedCompositeUnitRegistryTest.java @@ -15,12 +15,12 @@ import org.assertj.core.api.Assertions; import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.smarthome.core.library.unit.SmartHomeUnits; import org.openhab.binding.wmbus.UnitRegistry; +import org.openhab.core.library.unit.Units; import org.openmuc.jmbus.DlmsUnit; /** - * Test of {@link CompositeUnitRegistry} with {@link SmartHomeUnitsRegistry} and specific extension which provides + * Test of {@link CompositeUnitRegistry} with {@link UnitsRegistry} and specific extension which provides * support for {@link DlmsUnit#COUNT} unit. * * @author Łukasz Dywicki - Initial contribution. @@ -28,7 +28,7 @@ public class ExtendedCompositeUnitRegistryTest extends BaseUnitRegistryTest { public ExtendedCompositeUnitRegistryTest() { - super(new CompositeUnitRegistry(new SmartHomeUnitsRegistry(), new CountUnitRegistry())); + super(new CompositeUnitRegistry(new UnitsRegistry(), new CountUnitRegistry())); } @Override @@ -36,7 +36,7 @@ public void testConversionOf_count() throws Exception { try { super.testConversionOf_count(); } catch (AssertionError e) { - Assertions.assertThat(registry.lookup(DlmsUnit.COUNT)).contains(SmartHomeUnits.ONE); + Assertions.assertThat(registry.lookup(DlmsUnit.COUNT)).contains(Units.ONE); } } @@ -45,7 +45,7 @@ static class CountUnitRegistry implements UnitRegistry { @Override public Optional> lookup(DlmsUnit wmbusType) { if (DlmsUnit.COUNT.equals(wmbusType)) { - return Optional.of(SmartHomeUnits.ONE); + return Optional.of(Units.ONE); } return Optional.empty(); diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/SmartHomeUnitsRegistryTest.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/UnitsRegistryTest.java similarity index 75% rename from org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/SmartHomeUnitsRegistryTest.java rename to org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/UnitsRegistryTest.java index a201b61..8c8ef7a 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/SmartHomeUnitsRegistryTest.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/binding/wmbus/internal/units/UnitsRegistryTest.java @@ -13,10 +13,9 @@ * * @author Łukasz Dywicki - Initial contribution. */ -public class SmartHomeUnitsRegistryTest extends BaseUnitRegistryTest { +public class UnitsRegistryTest extends BaseUnitRegistryTest { - public SmartHomeUnitsRegistryTest() { - super(new SmartHomeUnitsRegistry()); + public UnitsRegistryTest() { + super(new UnitsRegistry()); } - } diff --git a/org.openhab.binding.wmbus/src/test/java/org/openhab/io/transport/mbus/wireless/MapKeyStorageTest.java b/org.openhab.binding.wmbus/src/test/java/org/openhab/io/transport/mbus/wireless/MapKeyStorageTest.java index 1b6e82d..04ef034 100644 --- a/org.openhab.binding.wmbus/src/test/java/org/openhab/io/transport/mbus/wireless/MapKeyStorageTest.java +++ b/org.openhab.binding.wmbus/src/test/java/org/openhab/io/transport/mbus/wireless/MapKeyStorageTest.java @@ -1,9 +1,8 @@ package org.openhab.io.transport.mbus.wireless; import org.assertj.core.api.Assertions; -import org.eclipse.smarthome.core.util.HexUtils; import org.junit.Test; -import org.openhab.io.transport.mbus.wireless.MapKeyStorage; +import org.openhab.core.util.HexUtils; import org.openmuc.jmbus.SecondaryAddress; /** @@ -15,7 +14,7 @@ public class MapKeyStorageTest { private static final String ADDRESS_HEX = "2423870723421147"; private static final byte[] ADDRESS_BYTE = HexUtils.hexToBytes(ADDRESS_HEX); - private static final SecondaryAddress ADDRESS_OBJECT = SecondaryAddress.newFromWMBusLlHeader(ADDRESS_BYTE, 0); + private static final SecondaryAddress ADDRESS_OBJECT = SecondaryAddress.newFromWMBusHeader(ADDRESS_BYTE, 0); private static final byte[] KEY = new byte[] { 0x01, 0x02 }; private final MapKeyStorage storage = new MapKeyStorage(); diff --git a/pom.xml b/pom.xml index a39afe8..76dc42f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,132 +1,77 @@ - - 4.0.0 + + 4.0.0 - - org.openhab.addons - org.openhab.addons.reactor - 2.5.0 - - + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 3.1.0-SNAPSHOT + + - org.openhab.binding - wmbus - 2.5.0-SNAPSHOT - pom + org.openhab.addons.bundles + wmbus + 3.1.0-SNAPSHOT + pom - WMBus Binding Aggregator + WMBus Binding Aggregator - - gnu.io*;version=0 - - - - org.openhab.binding.wmbus - org.openhab.binding.wmbus.tools - - - - - - org.commonjava.maven.plugins - directory-maven-plugin - 0.3.1 - - - directories - none - - directory-of - - - basedirRoot - - org.openhab.addons - org.openhab.addons.reactor - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - ${project.build.outputDirectory}/META-INF/MANIFEST.MF - - true - - - - biz.aQute.bnd - bnd-maven-plugin - - - org.apache.maven.plugins - maven-source-plugin - - - attach-sources - - jar - - - - - - - - - - jcenter - JCenter Repository - https://jcenter.bintray.com - - true - never - - - false - - - - openhab-artifactory-release - JFrog Artifactory Repository - https://openhab.jfrog.io/openhab/libs-release - - true - never - - - false - - - - openhab-snapshots-release - JFrog Artifactory Repository - https://openhab.jfrog.io/openhab/libs-snapshot-local - - false - never - - - true - - - - - - - jcenter - https://jcenter.bintray.com - - - openhab-artifactory-release - https://openhab.jfrog.io/openhab/libs-release - - + + org.openhab.binding.wmbus + org.openhab.binding.wmbus.tools + + + + + org.commonjava.maven.plugins + directory-maven-plugin + 0.3.1 + + + directories + none + + directory-of + + + basedirRoot + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + true + + + + biz.aQute.bnd + bnd-maven-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + +