From 6af51084152c7135b1240d25f45e3f722823c357 Mon Sep 17 00:00:00 2001 From: David Masshardt Date: Mon, 13 Aug 2018 20:00:48 +0200 Subject: [PATCH] [Serial] Added setting to select charset for string encoding - Adds a new setting to select charset for string encoding. - Problem parsing more than one setting is solved. - The BASE64 setting can now also be written as BASE64() and then it will be parsed correctly at any position inside the string. - Readme updated regarding the new charset setting and the new BASE64 settings format. Signed-off-by: David Masshardt --- .../org.openhab.binding.serial/README.md | 5 +-- .../serial/internal/SerialBinding.java | 28 +++++++++------ .../binding/serial/internal/SerialDevice.java | 35 ++++++++++++++++--- 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/bundles/binding/org.openhab.binding.serial/README.md b/bundles/binding/org.openhab.binding.serial/README.md index c3da40dfde4..33626d42b9f 100644 --- a/bundles/binding/org.openhab.binding.serial/README.md +++ b/bundles/binding/org.openhab.binding.serial/README.md @@ -1,6 +1,6 @@ # Serial Binding -The Serial binding allows openHAB to communicate in ASCII over serial ports attached to the openHAB server. +The Serial binding allows openHAB to communicate over serial ports attached to the openHAB server. | Item Type | Function | |-----------|----------| @@ -64,9 +64,10 @@ where: * `` is the identification of the serial port on the host system, e.g. `COM1` on Windows, `/dev/ttyS0` on Linux or `/dev/tty.PL2303-0000103D` on Mac. The same `` can be bound to multiple items. * `` is the baud rate of the port. If no baud rate is specified, the binding defaults to 9600 baud. * `REGEX()` allows parsing for special strings or numbers in the serial stream. A capture group (e.g. REGEX(Position:([0-9.]*)) can be used to capture "12" in `Position:12` or substitution (e.g. REGEX(s/Position:100/ON/) or REGEX(s/Position:100/ON/g)) to replace (FIRST or ALL) "Position:100" strings in response with "ON". This is based on the [RegEx Service](https://github.com/openhab/openhab1-addons/wiki/Transformations#regex-transformation-service) and [ESH RegExTransformationService](https://github.com/eclipse/smarthome/tree/master/extensions/transform/org.eclipse.smarthome.transform.regex). This is optional. -* `BASE64` enables the Base64 mode. With this mode all data received on the serial port is saved in Base64 format. All data that is sent to the serial port also has to be Base64 encoded. (This was implemented because some serial devices are using bytes that are not supported by the REST interface). +* `BASE64()` enables the Base64 mode. With this mode all data received on the serial port is saved in Base64 format. All data that is sent to the serial port also has to be Base64 encoded. (This was implemented because some serial devices are using bytes that are not supported by the REST interface). * `ON(),OFF()` used in conjunction with a Switch, this mapping will send specific commands to serial port and also match a serial command to specific ON/OFF state. This makes it unnecessary to use a rule to send a command to serial. * `UP(),DOWN(),STOP()` used in conjunction with a Rollershutter, this mapping will send specific commands to serial port. Use REGEX to parse Rollershutter postion (0-100%) coming as feedback over serial link. +* `CHARSET()` set's the charset to be used for converting to a String and back to bytes when writing. (e.g. UTF-8, ISO-8859-1, etc.) Base64 can be decoded in the rules by importing `javax.xml.bind.DatatypeConverter` and then decoding the value like this: diff --git a/bundles/binding/org.openhab.binding.serial/src/main/java/org/openhab/binding/serial/internal/SerialBinding.java b/bundles/binding/org.openhab.binding.serial/src/main/java/org/openhab/binding/serial/internal/SerialBinding.java index a1b614a80a7..ebaed01d543 100644 --- a/bundles/binding/org.openhab.binding.serial/src/main/java/org/openhab/binding/serial/internal/SerialBinding.java +++ b/bundles/binding/org.openhab.binding.serial/src/main/java/org/openhab/binding/serial/internal/SerialBinding.java @@ -189,6 +189,7 @@ public void processBindingConfiguration(String context, Item item, String bindin String downCommand = null; String stopCommand = null; String format = null; + String charset = null; int parameterSplitterAt = bindingConfig.indexOf(","); @@ -196,31 +197,38 @@ public void processBindingConfiguration(String context, Item item, String bindin String[] split = bindingConfig.substring(parameterSplitterAt + 1, bindingConfig.length()).split("\\),"); for (int i = 0; i < split.length; i++) { String substring = split[i]; + + //Remove the closing bracket on the last setting, because this isn't removed by the split. + if (i == split.length - 1 && substring.endsWith(")")) + substring = substring.substring(0, substring.length() - 1); if (substring.startsWith("REGEX(")) { - pattern = substring.substring(6, substring.length()-1); + pattern = substring.substring(6, substring.length()); logger.debug("REGEX: '{}'", pattern); } else if (substring.startsWith("FORMAT(")) { - format = substring.substring(7, substring.length()-1); + format = substring.substring(7, substring.length()); logger.debug("FORMAT: '{}'", format); - } else if (substring.equals("BASE64")) { + } else if (substring.equals("BASE64") || substring.equals("BASE64(")) { base64 = true; logger.debug("Base64-Mode enabled"); } else if (substring.startsWith("ON(")) { - onCommand = substring.substring(3, substring.length()-1); + onCommand = substring.substring(3, substring.length()); logger.debug("ON: '{}'", onCommand); } else if (substring.startsWith("OFF(")) { - offCommand = substring.substring(4, substring.length()-1); + offCommand = substring.substring(4, substring.length()); logger.debug("OFF: '{}'", offCommand); } else if (substring.startsWith("UP(")) { - upCommand = substring.substring(3, substring.length()-1); + upCommand = substring.substring(3, substring.length()); logger.debug("UP: '{}'", upCommand); } else if (substring.startsWith("DOWN(")) { - downCommand = substring.substring(5, substring.length()-1); + downCommand = substring.substring(5, substring.length()); logger.debug("DOWN: '{}'", downCommand); } else if (substring.startsWith("STOP(")) { - stopCommand = substring.substring(5, substring.length()-1); + stopCommand = substring.substring(5, substring.length()); logger.debug("STOP: '{}'", stopCommand); + } else if (substring.startsWith("CHARSET(")) { + charset = substring.substring(8, substring.length()); + logger.debug("CHARSET: '{}'", charset); } else { logger.warn("Unrecognized transform: {}", substring); } @@ -248,9 +256,9 @@ public void processBindingConfiguration(String context, Item item, String bindin SerialDevice serialDevice = serialDevices.get(port); if (serialDevice == null) { if (baudRate > 0) { - serialDevice = new SerialDevice(port, baudRate); + serialDevice = new SerialDevice(port, baudRate, charset); } else { - serialDevice = new SerialDevice(port); + serialDevice = new SerialDevice(port, charset); } serialDevice.setEventPublisher(eventPublisher); diff --git a/bundles/binding/org.openhab.binding.serial/src/main/java/org/openhab/binding/serial/internal/SerialDevice.java b/bundles/binding/org.openhab.binding.serial/src/main/java/org/openhab/binding/serial/internal/SerialDevice.java index dff74b010b8..0b36786d23a 100644 --- a/bundles/binding/org.openhab.binding.serial/src/main/java/org/openhab/binding/serial/internal/SerialDevice.java +++ b/bundles/binding/org.openhab.binding.serial/src/main/java/org/openhab/binding/serial/internal/SerialDevice.java @@ -11,6 +11,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; @@ -60,6 +62,7 @@ public class SerialDevice implements SerialPortEventListener { private CommPortIdentifier portId; private SerialPort serialPort; + private Charset charset; private InputStream inputStream; @@ -117,12 +120,36 @@ public void removeConfig(String itemName) { } public SerialDevice(String port) { - this.port = port; + this(port, null); + } + + public SerialDevice(String port, String charsetName) { + this(port, 9600, charsetName); } public SerialDevice(String port, int baud) { + this(port, baud, null); + } + + public SerialDevice(String port, int baud, String charsetName) { this.port = port; this.baud = baud; + setCharset(charsetName); + } + + private void setCharset(String charsetName) { + try { + if (charsetName == null) { + charset = Charset.defaultCharset(); + } else { + charset = Charset.forName(charsetName); + } + + logger.debug("Serial port '{}' charset '{}' set.", port, charsetName); + } catch (IllegalCharsetNameException e) { + logger.warn("Serial port '{}' charset '{}' not found.", port, charsetName); + charset = Charset.defaultCharset(); + } } public void setEventPublisher(EventPublisher eventPublisher) { @@ -276,7 +303,7 @@ public void serialEvent(SerialPortEvent event) { // read data from serial device while (inputStream.available() > 0) { int bytes = inputStream.read(readBuffer); - sb.append(new String(readBuffer, 0, bytes)); + sb.append(new String(readBuffer, 0, bytes, charset)); } try { // add wait states around reading the stream, so that interrupted transmissions are merged @@ -325,7 +352,7 @@ public void serialEvent(SerialPortEvent event) { } } else if (entry.getValue().type == StringItem.class) { if (entry.getValue().base64) { - result = Base64.encodeBase64String(result.getBytes()); + result = Base64.encodeBase64String(result.getBytes(charset)); } eventPublisher.postUpdate(entry.getKey(), new StringType(result)); @@ -383,7 +410,7 @@ public void writeString(String msg) { if (msg.startsWith("BASE64:")) { outputStream.write(Base64.decodeBase64(msg.substring(7, msg.length()))); } else { - outputStream.write(msg.getBytes()); + outputStream.write(msg.getBytes(charset)); } outputStream.flush();