From: M Valla <12682715+mvalla@users.noreply.github.com> Date: Mon, 23 Nov 2020 18:21:55 +0000 (+0100) Subject: [openwebnet] Fixed handling of ZigBee USB gateway and devices (fixes #8915 #8917... X-Git-Url: https://git.basschouten.com/?a=commitdiff_plain;h=874962e00ab5a96fb11df4d0801daa7921ab2235;p=openhab-addons.git [openwebnet] Fixed handling of ZigBee USB gateway and devices (fixes #8915 #8917 #8962) (#9076) * [openwebnet] Fixed config, handling and discovery of ZigBee devices (fixes #8915 and fixes #8917). Added test for ownID. Now uses openwebnet4j v0.3.2 * [openwebnet] ZigBee: improved handling of wrong 'where' parameter. Updated README. Improved logging. * [openwebnet] Improved discoveryByActivation to distinguish dimmers from lights. Now using openwebnet4j 0.3.2-1 Signed-off-by: Massimo Valla --- diff --git a/bundles/org.openhab.binding.openwebnet/README.md b/bundles/org.openhab.binding.openwebnet/README.md index 32c56977c2..0acd60016f 100644 --- a/bundles/org.openhab.binding.openwebnet/README.md +++ b/bundles/org.openhab.binding.openwebnet/README.md @@ -9,7 +9,7 @@ The binding supports: - commands from openHAB and feedback (events) from BUS/SCS and wireless network ![F454 Gateway](doc/F454_gateway.png) -![USB ZigBee Gateway](doc/USB_gateway.jpg) +![ZigBee USB Gateway](doc/USB_gateway.jpg) ## Supported Things @@ -35,19 +35,19 @@ The following Things and OpenWebNet `WHOs` are supported: ### For BUS/SCS -| Category | WHO | Thing Type IDs | Description | Status | -| -------------------- | :----------: | :---------------------------------: | ----------------------------------------------------------- | ---------------- | -| Gateway Management | `13` | `bus_gateway` | Any IP gateway supporting OpenWebNet protocol should work (e.g. F454 / MyHOMEServer1 / MH202 / F455 / MH200N, ...) | Successfully tested: F454, MyHOMEServer1, MyHOME_Screen10, F455, F452, F453AV, MH201, MH202, MH200N. Some connection stability issues/gateway resets reported with MH202 | -| Lighting | `1` | `bus_on_off_switch`, `bus_dimmer` | BUS switches and dimmers. | Successfully tested: F411/2, F411/4, F411U2, F422, F429. Some discovery issues reported with F429 (DALI Dimmers) | -| Automation | `2` | `bus_automation` | BUS roller shutters, with position feedback and auto-calibration | Successfully tested: LN4672M2 | +| Category | WHO | Thing Type IDs | Description | Status | +| -------------------- | :----------: | :------------------------------------------: | -------------------------------------------------------------- | ---------------- | +| Gateway Management | `13` | `bus_gateway` | Any IP gateway supporting OpenWebNet protocol should work (e.g. F454 / MyHOMEServer1 / MH202 / F455 / MH200N, ...) | Successfully tested: F454, MyHOMEServer1, MyHOME_Screen10, F455, F452, F453AV, MH201, MH202, MH200N. Some connection stability issues/gateway resets reported with MH202 | +| Lighting | `1` | `bus_on_off_switch`, `bus_dimmer` | BUS switches and dimmers | Successfully tested: F411/2, F411/4, F411U2, F422, F429. Some discovery issues reported with F429 (DALI Dimmers) | +| Automation | `2` | `bus_automation` | BUS roller shutters, with position feedback and auto-calibration | Successfully tested: LN4672M2 | ### For ZigBee (Radio) -| Category | WHO | Thing Type IDs | Description | Status | -| ---------- | :---: | :-------------------------------: | :-------------------------------------------------------------------: | ------------------------------------ | -| Gateway | `13` | `zb_gateway` | Wireless ZigBee USB Gateway (models: BTI-3578 / LG 088328) | Tested: BTI-3578 and LG 088328 | -| Lighting | `1` | `zb_dimmer`, `zb_on_off_switch`, `zb_on_off_switch2u` | ZigBee dimmers, switches and 2-unit switches | Tested: BTI-4591, BTI-3584, BTI-4585 | -| Automation | `2` | `zb_automation` | ZigBee roller shutters | | +| Category | WHO | Thing Type IDs | Description | Status | +| -------------------- | :----: | :-------------------------------: | :-------------------------------------------------------------------: | ------------------------------------ | +| Gateway Management | `13` | `zb_gateway` | ZigBee USB Gateway (models: BTI-3578 / LG 088328) | Tested: BTI-3578 and LG 088328 | +| Lighting | `1` | `zb_dimmer`, `zb_on_off_switch`, `zb_on_off_switch2u` | ZigBee dimmers, switches and 2-unit switches | Tested: BTI-4591, BTI-3584, BTI-4585 | +| Automation | `2` | `zb_automation` | ZigBee roller shutters | | ## Discovery @@ -64,15 +64,15 @@ For other gateways you can add them manually, see [Thing Configuration](#thing-c #### Discovery by Activation -Devices can also be discovered if activated while an Inbox Scan is active: start a new Scan, wait 15-20 seconds and then _while the Scan is still active_ (spinning arrow in Inbox), activate the physical device (for example dim the dimmer) to have it discovered by the binding. +BUS devices can also be discovered if activated while an Inbox Scan is active: start a new Scan, wait 15-20 seconds and then _while the Scan is still active_ (spinning arrow in Inbox), activate the physical device (for example dim the dimmer) to have it discovered by the binding. If a device cannot be discovered automatically it's always possible to add it manually, see [Configuring Devices](#configuring-devices). ### ZigBee Discovery -- Zigbee USB gateway discovery is *not supported* at the moment: the gateway thing must be added manually see [Thing Configuration](#thing-configuration) below -- The ZigBee USB Gateway must be inserted in one of the USB ports of the openHAB computer before discovery is started -- ***IMPORTANT NOTE:*** As for other OH2 bindings using the USB/serial ports, on Linux the `openhab` user must be member of the `dialout` group, to be able to use USB/serial port: set the group with the following command: +- ZigBee USB gateway discovery is *not supported* at the moment: the gateway thing must be added manually see [Thing Configuration](#thing-configuration) below +- The ZigBee USB Gateway must be inserted in one of the USB ports of the openHAB computer before a discovery is started +- ***IMPORTANT NOTE:*** As for other openHAB bindings using the USB/serial ports, on Linux the `openhab` user must be member of the `dialout` group to be able to use USB/serial port; set the group with the following command: ``` $ sudo usermod -a -G dialout openhab @@ -105,12 +105,12 @@ Alternatively the BUS/SCS Gateway thing can be configured using the `.things` fi ### Configuring Wireless ZigBee USB Gateway -To add a ZigBee USB gateway manually using PaperUI: go to *Inbox > "+" > OpenWebNet > click `ADD MANUALLY`* and then select `ZigBee USB Gateway`. +To add a ZigBee USB Gateway manually using PaperUI: go to *Inbox > "+" > OpenWebNet > click `ADD MANUALLY`* and then select `ZigBee USB Gateway`. Configuration parameters are: - `serialPort` : the serial port where the ZigBee USB Gateway is connected (`String`, *mandatory*) - - Example: `COM3` + - Examples: `/dev/ttyUSB0` (Linux/RaPi), `COM3` (Windows) ### Configuring Devices @@ -119,20 +119,20 @@ Devices can be discovered automatically from Inbox after a gateway has been conf Devices can be also added manually from PaperUI. For each device it must be configured: - the associated gateway (`Bridge Selection` menu) -- the `WHERE` config parameter (`OpenWebNet Device Address`): - - example for BUS/SCS: Point to Point `A=2 PL=4` --> `WHERE="24"` - - example for BUS/SCS: Point to Point `A=6 PL=4` on local bus --> `WHERE="64#4#01"` - - example for ZigBee devices: use decimal format address without the UNIT part and network: ZigBee `WHERE=414122201#9` --> `WHERE="4141222"` +- the `where` config parameter (`OpenWebNet Device Address`): + - example for BUS/SCS device with WHERE address Point to Point `A=2 PL=4` --> `where="24"` + - example for BUS/SCS device with WHERE address Point to Point `A=03 PL=11` on local bus --> `where="0311#4#01"` + - example for ZigBee devices: `where=765432101#9`. The ID of the device (ADDR part) is usually written in hexadecimal on the device itself, for example `ID 0074CBB1`: convert to decimal (`7654321`) and add `01#9` at the end to obtain `where=765432101#9`. For 2-unit switch devices (`zb_on_off_switch2u`), last part should be `00#9`. ## Channels Devices support some of the following channels: -| Channel Type ID (channel ID) | Item Type | Description | Read/Write | -|--------------------------|---------------|-------------------------------------------------------------------------|:----------:| -| `switch` | Switch | To switch the device `ON` and `OFF` | R/W | -| `brightness` | Dimmer | To adjust the brightness value (Percent, `ON`, `OFF`) | R/W | -| `shutter` | Rollershutter | To activate roller shutters (`UP`, `DOWN`, `STOP`, Percent - [see Shutter position](#shutter-position)) | R/W | +| Channel Type ID (channel ID) | Item Type | Description | Read/Write | +|------------------------------------------------|---------------|---------------------------------------------------------|:----------:| +| `switch` or `switch_01`/`02` for ZigBee | Switch | To switch the device `ON` and `OFF` | R/W | +| `brightness` | Dimmer | To adjust the brightness value (Percent, `ON`, `OFF`) | R/W | +| `shutter` | Rollershutter | To activate roller shutters (`UP`, `DOWN`, `STOP`, Percent - [see Shutter position](#shutter-position)) | R/W | ### Notes on channels @@ -151,36 +151,47 @@ It's possible to enter a value manually or set `shutterRun=AUTO` (default) to ca ### openwebnet.things: +BUS gateway and things configuration: + ```xtend Bridge openwebnet:bus_gateway:mybridge "MyHOMEServer1" [ host="192.168.1.35", passwd="abcde", port=20000, discoveryByActivation=false ] { - bus_on_off_switch LR_switch "Living Room Light" [ where="51" ] - bus_dimmer LR_dimmer "Living Room Dimmer" [ where="25#4#01" ] - bus_dimmer LR_dalidimmer "Living Room Dali-Dimmer" [ where="0311#4#01" ] - bus_automation LR_shutter "Living Room Shutter" [ where="93", shutterRun="10050"] + bus_on_off_switch LR_switch "Living Room Light" [ where="51" ] + bus_dimmer LR_dimmer "Living Room Dimmer" [ where="0311#4#01" ] + bus_automation LR_shutter "Living Room Shutter" [ where="93", shutterRun="10050"] } -``` +``` +ZigBee USB Gateway and things configuration - for radio devices: + ```xtend -// ZigBee USB Gateway configuration for radio devices Bridge openwebnet:zb_gateway:myZBgateway [serialPort="COM3"] { - zb_dimmer myzigbeedimmer [ where="123456700#9"] - zb_on_off_switch myzigbeeswitch [ where="765432200#9"] + zb_dimmer myZB_dimmer [ where="765432101#9"] + zb_on_off_switch myZB_switch [ where="765432201#9"] + zb_on_off_switch2u myZB_2U_switch [ where="765432300#9"] } ``` ### openwebnet.items: -Items (Light, Dimmer, etc.) will be discovered by Google Assistant/Alexa/HomeKit if their tags are configured like in the example. +Items (Light, Dimmer, etc.) will be discovered by Google Assistant/Alexa/HomeKit if their tags are configured like in the example: ```xtend Switch iLR_switch "Light" (gLivingRoom) [ "Lighting" ] { channel="openwebnet:bus_on_off_switch:mybridge:LR_switch:switch" } Dimmer iLR_dimmer "Dimmer [%.0f %%]" (gLivingRoom) [ "Lighting" ] { channel="openwebnet:bus_dimmer:mybridge:LR_dimmer:brightness" } -Dimmer iLR_dalidimmer "Dali-Dimmer [%.0f %%]" (gLivingRoom) [ "Lighting" ] { channel="openwebnet:bus_dimmer:mybridge:LR_dalidimmer:brightness" } /* For Dimmers, use category DimmableLight to have Off/On switch in addition to the Percent slider in PaperUI */ Rollershutter iLR_shutter "Shutter [%.0f %%]" (gShutters, gLivingRoom) [ "Blinds" ] { channel="openwebnet:bus_automation:mybridge:LR_shutter:shutter" } ``` +Example items linked to ZigBee devices: + +```xtend +Dimmer iDimmer "Dimmer [%.0f %%]" (gKitchen) [ "Lighting" ] { channel="openwebnet:zb_dimmer:myZBgateway:myZB_dimmer:brightness" } +Switch iSimpleSwitch "Kitchen Switch" (gKitchen) [ "Lighting" ] { channel="openwebnet:zb_on_off_switch:myZBgateway:myZB_switch:switch_01" } +Switch iSwitch_01 "2U first light" (gKitchen) [ "Lighting" ] { channel="openwebnet:zb_on_off_switch2u:myZBgateway:myZB_2U_switch:switch_01" } +Switch iSwitch_02 "2U second light" (gKitchen) [ "Lighting" ] { channel="openwebnet:zb_on_off_switch2u:myZBgateway:myZB_2U_switch:switch_02" } +``` + ### openwebnet.sitemap ```xtend @@ -190,7 +201,6 @@ sitemap openwebnet label="OpenWebNet Binding Example Sitemap" { Default item=iLR_switch icon="light" Default item=iLR_dimmer icon="light" - Default item=iLR_dalidimmer icon="light" Default item=iLR_shutter } } diff --git a/bundles/org.openhab.binding.openwebnet/pom.xml b/bundles/org.openhab.binding.openwebnet/pom.xml index a779114839..813d09a307 100644 --- a/bundles/org.openhab.binding.openwebnet/pom.xml +++ b/bundles/org.openhab.binding.openwebnet/pom.xml @@ -23,7 +23,7 @@ com.github.openwebnet4j openwebnet4j - 0.3.1 + 0.3.2-1 compile diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetAutomationHandler.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetAutomationHandler.java index 1eb469c29d..cdb84a5fd4 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetAutomationHandler.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetAutomationHandler.java @@ -329,8 +329,9 @@ public class OpenWebNetAutomationHandler extends OpenWebNetThingHandler { updateMovingState(MOVING_STATE_STOPPED); logger.debug("& {} & CALIBRATION - reached UP, now sending DOWN command...", deviceWhere); calibrating = CALIBRATION_ACTIVATED; - if (deviceWhere != null) { - String w = deviceWhere.value(); + Where dw = deviceWhere; + if (dw != null) { + String w = dw.value(); try { send(Automation.requestMoveDown(w)); } catch (OWNException e) { diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetBridgeHandler.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetBridgeHandler.java index 3187de37e3..e0a1d51bdd 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetBridgeHandler.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetBridgeHandler.java @@ -49,7 +49,9 @@ import org.openwebnet4j.message.FrameException; import org.openwebnet4j.message.GatewayMgmt; import org.openwebnet4j.message.Lighting; import org.openwebnet4j.message.OpenMessage; +import org.openwebnet4j.message.What; import org.openwebnet4j.message.Where; +import org.openwebnet4j.message.WhereZigBee; import org.openwebnet4j.message.Who; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,7 +72,8 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement // ConcurrentHashMap of devices registered to this BridgeHandler // association is: ownId (String) -> OpenWebNetThingHandler, with ownId = WHO.WHERE - private Map registeredDevices = new ConcurrentHashMap<>(); + private Map registeredDevices = new ConcurrentHashMap<>(); + private Map discoveringDevices = new ConcurrentHashMap<>(); protected @Nullable OpenGateway gateway; private boolean isBusGateway = false; @@ -119,6 +122,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement "Could not connect to gateway before " + GATEWAY_ONLINE_TIMEOUT_SEC + "s"); } }, GATEWAY_ONLINE_TIMEOUT_SEC, TimeUnit.SECONDS); + logger.debug("bridge {} initialization completed", thing.getUID()); } catch (OWNException e) { logger.debug("gw.connect() returned OWNException: {}", e.getMessage()); // status is updated by callback onConnectionError() @@ -131,11 +135,11 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement * Init a ZigBee gateway based on config */ private @Nullable OpenGateway initZigBeeGateway() { - logger.debug("Initializing ZigBee USB gateway"); + logger.debug("Initializing ZigBee USB Gateway"); OpenWebNetZigBeeBridgeConfig zbBridgeConfig = getConfigAs(OpenWebNetZigBeeBridgeConfig.class); String serialPort = zbBridgeConfig.getSerialPort(); if (serialPort == null || serialPort.isEmpty()) { - logger.warn("Cannot connect to gateway. No serial port has been provided in Bridge configuration."); + logger.info("Cannot connect ZigBee USB Gateway. No serial port has been provided in Bridge configuration."); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.conf-error-no-serial-port"); return null; @@ -152,7 +156,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement OpenWebNetBusBridgeConfig busBridgeConfig = getConfigAs(OpenWebNetBusBridgeConfig.class); String host = busBridgeConfig.getHost(); if (host == null || host.isEmpty()) { - logger.warn("Cannot connect to gateway. No host/IP has been provided in Bridge configuration."); + logger.info("Cannot connect to BUS Gateway. No host/IP has been provided in Bridge configuration."); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.conf-error-no-ip-address"); return null; @@ -177,7 +181,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement logger.debug("handleCommand (command={} - channel={})", command, channelUID); OpenGateway gw = gateway; if (gw != null && !gw.isConnected()) { - logger.warn("Gateway is NOT connected, skipping command"); + logger.info("Gateway is NOT connected, skipping command"); return; } else { logger.warn("Channel not supported: channel={}", channelUID); @@ -206,7 +210,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement if (gw != null) { gw.closeConnection(); gw.unsubscribe(this); - logger.debug("gateway {} connection closed and unsubscribed", gw.toString()); + logger.debug("Gateway {} connection closed and unsubscribed", gw.toString()); gateway = null; } reconnecting = false; @@ -276,23 +280,54 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement } private void discoverByActivation(BaseOpenMessage baseMsg) { - logger.debug("BridgeHandler.discoverByActivation() msg={}", baseMsg); + logger.debug("discoverByActivation: msg={}", baseMsg); OpenWebNetDeviceDiscoveryService discService = deviceDiscoveryService; if (discService == null) { logger.warn("discoverByActivation: null OpenWebNetDeviceDiscoveryService, ignoring msg={}", baseMsg); return; } - if (baseMsg instanceof Lighting) { + if (baseMsg instanceof Lighting || baseMsg instanceof Automation) { // we support these types only + BaseOpenMessage bmsg = baseMsg; + if (baseMsg instanceof Lighting) { + What what = baseMsg.getWhat(); + if (Lighting.WHAT.OFF.equals(what)) { // skipping OFF msg: cannot distinguish dimmer/switch + logger.debug("discoverByActivation: skipping OFF msg: cannot distinguish dimmer/switch"); + return; + } + if (Lighting.WHAT.ON.equals(what)) { // if not already done just now, request light status to + // distinguish dimmer from switch + if (discoveringDevices.containsKey(ownIdFromMessage(baseMsg))) { + logger.debug( + "discoverByActivation: we just requested status for this device and it's ON -> it's a switch"); + } else { + OpenGateway gw = gateway; + if (gw != null) { + try { + discoveringDevices.put(ownIdFromMessage(baseMsg), + Long.valueOf(System.currentTimeMillis())); + gw.send(Lighting.requestStatus(baseMsg.getWhere().value())); + return; + + } catch (OWNException e) { + logger.warn("discoverByActivation: Exception while requesting light state: {}", + e.getMessage()); + return; + } + } + } + } + discoveringDevices.remove(ownIdFromMessage(baseMsg)); + } OpenDeviceType type = null; try { - type = baseMsg.detectDeviceType(); + type = bmsg.detectDeviceType(); } catch (FrameException e) { logger.warn("Exception while detecting device type: {}", e.getMessage()); } if (type != null) { - discService.newDiscoveryResult(baseMsg.getWhere(), type, baseMsg); + discService.newDiscoveryResult(bmsg.getWhere(), type, bmsg); } else { - logger.debug("discoverByActivation: no device type detected from msg: {}", baseMsg); + logger.debug("discoverByActivation: no device type detected from msg: {}", bmsg); } } } @@ -354,7 +389,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement // let's try to get the Thing associated with this message... if (baseMsg instanceof Lighting || baseMsg instanceof Automation) { String ownId = ownIdFromMessage(baseMsg); - logger.debug("ownId={}", ownId); + logger.debug("ownIdFromMessage({}) --> {}", baseMsg, ownId); OpenWebNetThingHandler deviceHandler = registeredDevices.get(ownId); if (deviceHandler == null) { OpenGateway gw = gateway; @@ -384,7 +419,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement return; } if (gw instanceof USBGateway) { - logger.info("------------------- CONNECTED to USB (ZigBee) gateway - USB port: {}", + logger.info("------------------- CONNECTED to ZigBee USB gateway - USB port: {}", ((USBGateway) gw).getSerialPortName()); } else { logger.info("------------------- CONNECTED to BUS gateway '{}' ({}:{})", thing.getUID(), @@ -482,25 +517,24 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement } /** - * Return a ownId string (=WHO.WHERE) from a deviceWhere thing config parameter (already normalized) and its - * handler. + * Return a ownId string (=WHO.WHERE) from the device Where address and handler * - * @param deviceWhere the device WHERE config parameter - * @param handler the thing handler - * @return the ownId + * @param where the Where address (to be normalized) + * @param handler the device handler + * @return the ownId String */ - protected String ownIdFromDeviceWhere(@Nullable String deviceWhere, OpenWebNetThingHandler handler) { - return handler.ownIdPrefix() + "." + deviceWhere; + protected String ownIdFromDeviceWhere(Where where, OpenWebNetThingHandler handler) { + return handler.ownIdPrefix() + "." + normalizeWhere(where); } /** - * Returns a ownId string (=WHO.WHERE) from a Where address and Who + * Returns a ownId string (=WHO.WHERE) from a Who and Where address * - * @param where the Where address (to be normalized) * @param who the Who - * @return the ownId + * @param where the Where address (to be normalized) + * @return the ownId String */ - public String ownIdFromWhoWhere(Where where, Who who) { + public String ownIdFromWhoWhere(Who who, Where where) { return who.value() + "." + normalizeWhere(where); } @@ -510,45 +544,39 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement * @param baseMsg the BaseOpenMessage * @return the ownId String */ - private String ownIdFromMessage(BaseOpenMessage baseMsg) { + public String ownIdFromMessage(BaseOpenMessage baseMsg) { return baseMsg.getWho().value() + "." + normalizeWhere(baseMsg.getWhere()); } /** - * Transform a Where address into a Thing id string based on bridge type (BUS/USB ZigBee). - * '#' in WHERE are changed to 'h' + * Transform a Where address into a Thing id string * * @param where the Where address - * @return the thing Id + * @return the thing Id string */ public String thingIdFromWhere(Where where) { - return normalizeWhere(where).replace('#', 'h'); // '#' cannot be used in ThingUID; + return normalizeWhere(where); // '#' cannot be used in ThingUID; } /** - * Normalize a Where address for Thermo and Zigbee devices + * Normalize a Where address * * @param where the Where address - * @return the normalized address + * @return the normalized address as String */ public String normalizeWhere(Where where) { - String str = ""; - if (isBusGateway) { - if (where.value().indexOf('#') < 0) { // no hash present - str = where.value(); - } else if (where.value().indexOf("#4#") > 0) { // local bus: APL#4#bus - str = where.value(); - } else if (where.value().indexOf('#') == 0) { // thermo zone via central unit: #0 or #Z (Z=[1-99]) --> Z - str = where.value().substring(1); - } else if (where.value().indexOf('#') > 0) { // thermo zone and actuator N: Z#N (Z=[1-99], N=[1-9]) -- > Z - str = where.value().substring(0, where.value().indexOf('#')); - } else { - logger.warn("normalizeWhere() unexpected WHERE: {}", where); - str = where.value(); - } - return str; + String str = where.value(); + if (where instanceof WhereZigBee) { + str = ((WhereZigBee) where).valueWithUnit(WhereZigBee.UNIT_ALL); // 76543210X#9 --> 765432100#9 } else { - return where.value(); + if (str.indexOf("#4#") > 0) { // local bus: APL#4#bus + // no change needed + } else if (str.indexOf('#') == 0) { // Thermo zone via central unit: #0 or #Z (Z=[1-99]) --> Z + str = str.substring(1); + } else if (str.indexOf('#') > 0) { // Thermo zone and actuator N: Z#N (Z=[1-99], N=[1-9]) --> Z + str = str.substring(0, str.indexOf('#')); + } } + return str.replace('#', 'h'); } } diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetThingHandler.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetThingHandler.java index 3badddd04f..d69da78f07 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetThingHandler.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetThingHandler.java @@ -72,17 +72,22 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler { if (!(deviceWhereConfig instanceof String)) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "WHERE parameter in configuration is null or invalid"); - return; } else { String deviceWhereStr = (String) getConfig().get(CONFIG_PROPERTY_WHERE); Where w; - if (brH.isBusGateway()) { - w = new WhereLightAutom(deviceWhereStr); - } else { - w = new WhereZigBee(deviceWhereStr); + try { + if (brH.isBusGateway()) { + w = new WhereLightAutom(deviceWhereStr); + } else { + w = new WhereZigBee(deviceWhereStr); + } + } catch (IllegalArgumentException ia) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "WHERE parameter in configuration is invalid"); + return; } deviceWhere = w; - final String oid = brH.ownIdFromDeviceWhere(w.value(), this); + final String oid = brH.ownIdFromDeviceWhere(w, this); ownId = oid; Map properties = editProperties(); properties.put(PROPERTY_OWNID, oid); @@ -91,11 +96,11 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler { logger.debug("associated thing to bridge with ownId={}", ownId); updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "waiting state update..."); } - return; } + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "No bridge associated, please assign a bridge in thing configuration."); } - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, - "No bridge associated, please assign a bridge in thing configuration."); } @Override @@ -105,8 +110,12 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler { if (handler != null) { OpenGateway gw = handler.gateway; if (gw != null && !gw.isConnected()) { - logger.info("Cannot handle command {}:{} for {}: gateway is not connected", channel, command, - getThing().getUID()); + logger.info("Cannot handle {} command for {}: gateway is not connected", command, getThing().getUID()); + return; + } + if (deviceWhere == null) { + logger.info("Cannot handle {} command for {}: 'where' parameter is not configured or is invalid", + command, getThing().getUID()); return; } if (command instanceof RefreshType) { diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/OpenWebNetDeviceDiscoveryService.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/OpenWebNetDeviceDiscoveryService.java index 3668722bda..5e68b956e7 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/OpenWebNetDeviceDiscoveryService.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/OpenWebNetDeviceDiscoveryService.java @@ -139,7 +139,7 @@ public class OpenWebNetDeviceDiscoveryService extends AbstractDiscoveryService } } - String ownId = bridgeHandler.ownIdFromWhoWhere(where, deviceWho); + String ownId = bridgeHandler.ownIdFromWhoWhere(deviceWho, where); if (thingTypeUID == OpenWebNetBindingConstants.THING_TYPE_BUS_ON_OFF_SWITCH) { if (bridgeHandler.getRegisteredDevice(ownId) != null) { logger.debug("dimmer/switch with WHERE={} already registered, skipping this discovery result", where); @@ -152,27 +152,26 @@ public class OpenWebNetDeviceDiscoveryService extends AbstractDiscoveryService DiscoveryResult discoveryResult = null; - String whereLabel = where.value(); + String whereConfig = where.value(); if (where instanceof WhereZigBee && WhereZigBee.UNIT_02.equals(((WhereZigBee) where).getUnit())) { - logger.debug("UNIT=02 found (WHERE={})", where); - logger.debug("will remove previous result if exists"); + logger.debug("UNIT=02 found (WHERE={}) -> will remove previous result if exists", where); thingRemoved(thingUID); // remove previously discovered thing // re-create thingUID with new type thingTypeUID = OpenWebNetBindingConstants.THING_TYPE_ZB_ON_OFF_SWITCH_2UNITS; thingLabel = OpenWebNetBindingConstants.THING_LABEL_ZB_ON_OFF_SWITCH_2UNITS; thingUID = new ThingUID(thingTypeUID, bridgeUID, tId); - whereLabel = whereLabel.replace("02#", "00#"); // replace unit '02' with all unit '00' + whereConfig = ((WhereZigBee) where).valueWithUnit(WhereZigBee.UNIT_ALL); // replace unit '02' with '00' logger.debug("UNIT=02, switching type from {} to {}", OpenWebNetBindingConstants.THING_TYPE_ZB_ON_OFF_SWITCH, OpenWebNetBindingConstants.THING_TYPE_ZB_ON_OFF_SWITCH_2UNITS); } Map properties = new HashMap<>(2); - properties.put(OpenWebNetBindingConstants.CONFIG_PROPERTY_WHERE, bridgeHandler.normalizeWhere(where)); + properties.put(OpenWebNetBindingConstants.CONFIG_PROPERTY_WHERE, whereConfig); properties.put(OpenWebNetBindingConstants.PROPERTY_OWNID, ownId); if (thingTypeUID == OpenWebNetBindingConstants.THING_TYPE_GENERIC_DEVICE) { - thingLabel = thingLabel + " (WHO=" + deviceWho + ", WHERE=" + whereLabel + ")"; + thingLabel = thingLabel + " (WHO=" + deviceWho + ", WHERE=" + whereConfig + ")"; } else { - thingLabel = thingLabel + " (WHERE=" + whereLabel + ")"; + thingLabel = thingLabel + " (WHERE=" + whereConfig + ")"; } discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID).withProperties(properties) .withRepresentationProperty(OpenWebNetBindingConstants.PROPERTY_OWNID).withBridge(bridgeUID) diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusAutomation.xml b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusAutomation.xml index a41fd43727..4ba3d5392f 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusAutomation.xml +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusAutomation.xml @@ -38,8 +38,8 @@ - - Example: A/PL address: A=1 PL=3 --> WHERE=13. On local bus: WHERE=13#4#01 + + Example: A/PL address: A=1 PL=3 --> where=13. On local bus: where=13#4#01 diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusDimmer.xml b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusDimmer.xml index 44fce13feb..58f5013e98 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusDimmer.xml +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusDimmer.xml @@ -27,8 +27,8 @@ - - Example: A/PL address: A=1 PL=3 --> WHERE=13. On local bus: WHERE=13#4#01 + + Example: A/PL address: A=1 PL=3 --> where=13. On local bus: where=13#4#01 diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusOnOffSwitch.xml b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusOnOffSwitch.xml index e86818027e..805cc0dc6b 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusOnOffSwitch.xml +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusOnOffSwitch.xml @@ -27,8 +27,8 @@ - - Example: A/PL address: A=1 PL=3 --> WHERE=13. On local bus: WHERE=13#4#01 + + Example: A/PL address: A=1 PL=3 --> where=13. On local bus: where=13#4#01 diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/GenericDevice.xml b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/GenericDevice.xml index 771cd016f0..c5589c9088 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/GenericDevice.xml +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/GenericDevice.xml @@ -24,7 +24,7 @@ - + It identifies one OpenWebNet device diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBAutomation.xml b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBAutomation.xml index 6306f3f284..b84f3c4a9e 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBAutomation.xml +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBAutomation.xml @@ -38,9 +38,8 @@ AUTO - - It identifies one ZigBee device. Use decimal format address without the UNIT part and network: ZigBee - WHERE=414122201#9 -> OpenWebNet Device Address = 4141222 + + It identifies one ZigBee device. Example: 765432101#9 true diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBDimmer.xml b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBDimmer.xml index b4b04a8872..98b07e81a5 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBDimmer.xml +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBDimmer.xml @@ -27,9 +27,8 @@ - - It identifies one ZigBee device. Use decimal format address without the UNIT part and network: ZigBee - WHERE=414122201#9 -> OpenWebNet Device Address = 4141222 + + It identifies one ZigBee device. Example: 765432101#9 diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBOnOffSwitch.xml b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBOnOffSwitch.xml index 6165974a34..f741b72403 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBOnOffSwitch.xml +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBOnOffSwitch.xml @@ -27,9 +27,8 @@ - - It identifies one ZigBee device. Use decimal format address without the UNIT part and network: ZigBee - WHERE=414122201#9 -> OpenWebNet Device Address = 4141222 + + It identifies one ZigBee device. Example: 765432101#9 diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBOnOffSwitch2Units.xml b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBOnOffSwitch2Units.xml index 4ace7056d6..6de61f7f7f 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBOnOffSwitch2Units.xml +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBOnOffSwitch2Units.xml @@ -28,9 +28,8 @@ - - It identifies one ZigBee device. Use decimal format address without the UNIT part and network: ZigBee - WHERE=414122201#9 -> OpenWebNet Device Address = 4141222 + + It identifies one ZigBee device. Example: 765432100#9 (use unit=00 at the end) diff --git a/bundles/org.openhab.binding.openwebnet/src/test/java/org/openhab/binding/openwebnet/handler/OwnIdTest.java b/bundles/org.openhab.binding.openwebnet/src/test/java/org/openhab/binding/openwebnet/handler/OwnIdTest.java new file mode 100644 index 0000000000..8769dbfbc4 --- /dev/null +++ b/bundles/org.openhab.binding.openwebnet/src/test/java/org/openhab/binding/openwebnet/handler/OwnIdTest.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2010-2020 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.openwebnet.handler; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.core.thing.Bridge; +import org.openwebnet4j.message.Lighting; +import org.openwebnet4j.message.Where; +import org.openwebnet4j.message.WhereLightAutom; +import org.openwebnet4j.message.WhereZigBee; +import org.openwebnet4j.message.Who; + +/** + * Test class for {@link OpenWebNetBridgeHandler#ownID} and ThingID calculation using {@link OpenWebNetBridgeHandler} + * methods: normalizeWhere(), ownIdFromWhoWhere(), ownIdFromMessage(), thingIdFromWhere() + * + * @author Massimo Valla - Initial contribution + */ +@NonNullByDefault +public class OwnIdTest { + + // @formatter:off + /** + * + * deviceWhere + * (DevAddrParam) + * TYPE WHERE = normalizeWhere() ownId ThingID + * --------------------------------------------------------------------------------- + * Zigbee Switch 789309801#9 789309800h9 1.789309800h9 789309800h9 + * Zigbee Switch_2u u1 789301201#9 789301200h9 1.789309800h9 789309800h9 + * Zigbee Switch_2u u2 789301202#9 789301200h9 1.789309800h9 789309800h9 + * BUS Switch 51 51 1.51 51 + * BUS Local Bus 25#4#01 25h4h01 1.25h4h01 25h4h01 + * BUS Autom 93 93 2.93 93 + * BUS Thermo #1 or 1 1 4.1 1 + * BUS TempSensor 500 500 4.500 500 + * BUS Energy 51 51 18.51 51 + * BUS CEN 51 51 15.51 51 + * BUS CEN+ 212 212 25.212 212 + * BUS DryContact 399 399 25.399 399 + * + */ +// @formatter:on + + public enum TEST { + zb_switch(new WhereZigBee("789309801#9"), Who.fromValue(1), "789309800h9", "1.789309800h9", "789309800h9"), + zb_switch_2u_1(new WhereZigBee("789301201#9"), Who.fromValue(1), "789301200h9", "1.789301200h9", "789301200h9"), + zb_switch_2u_2(new WhereZigBee("789301202#9"), Who.fromValue(1), "789301200h9", "1.789301200h9", "789301200h9"), + bus_switch(new WhereLightAutom("51"), Who.fromValue(1), "51", "1.51", "51"), + bus_localbus(new WhereLightAutom("25#4#01"), Who.fromValue(1), "25h4h01", "1.25h4h01", "25h4h01"); + // bus_thermo("#1", "4", "1", "4.1", "1"), + // bus_tempSensor("500", "4", "500", "4.500", "500"), + // bus_energy("51", "18", "51", "18.51", "51"); + + public final Where where; + public final Who who; + public final String norm, ownId, thingId; + + private TEST(Where where, Who who, String norm, String ownId, String thingId) { + this.where = where; + this.who = who; + this.norm = norm; + this.ownId = ownId; + this.thingId = thingId; + } + } + + @Test + public void testOwnId() { + Bridge mockBridge = mock(Bridge.class); + OpenWebNetBridgeHandler brH = new OpenWebNetBridgeHandler(mockBridge); + + for (int i = 0; i < TEST.values().length; i++) { + TEST test = TEST.values()[i]; + // System.out.println("testing where=" + test.where); + assertEquals(test.norm, brH.normalizeWhere(test.where)); + assertEquals(test.ownId, brH.ownIdFromWhoWhere(test.who, test.where)); + assertEquals(test.ownId, brH.ownIdFromMessage(Lighting.requestTurnOn(test.where.value()))); + assertEquals(test.thingId, brH.thingIdFromWhere(test.where)); + } + } +}