]> git.basschouten.com Git - openhab-addons.git/commitdiff
[openwebnet] Fixed handling of ZigBee USB gateway and devices (fixes #8915 #8917...
authorM Valla <12682715+mvalla@users.noreply.github.com>
Mon, 23 Nov 2020 18:21:55 +0000 (19:21 +0100)
committerGitHub <noreply@github.com>
Mon, 23 Nov 2020 18:21:55 +0000 (19:21 +0100)
* [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 <mvcode00@gmail.com>
15 files changed:
bundles/org.openhab.binding.openwebnet/README.md
bundles/org.openhab.binding.openwebnet/pom.xml
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetAutomationHandler.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetBridgeHandler.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetThingHandler.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/discovery/OpenWebNetDeviceDiscoveryService.java
bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusAutomation.xml
bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusDimmer.xml
bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/BusOnOffSwitch.xml
bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/GenericDevice.xml
bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBAutomation.xml
bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBDimmer.xml
bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBOnOffSwitch.xml
bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/thing/ZBOnOffSwitch2Units.xml
bundles/org.openhab.binding.openwebnet/src/test/java/org/openhab/binding/openwebnet/handler/OwnIdTest.java [new file with mode: 0644]

index 32c56977c2398f70b603e9b2a42c7c50cc5dd93a..0acd60016f236853a329faf1352e60ee0b45d121 100644 (file)
@@ -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 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"                             <light>          (gLivingRoom)                [ "Lighting" ]  { channel="openwebnet:bus_on_off_switch:mybridge:LR_switch:switch" }
 Dimmer          iLR_dimmer          "Dimmer [%.0f %%]"                  <DimmableLight>  (gLivingRoom)                [ "Lighting" ]  { channel="openwebnet:bus_dimmer:mybridge:LR_dimmer:brightness" }
-Dimmer          iLR_dalidimmer      "Dali-Dimmer [%.0f %%]"             <DimmableLight>  (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 %%]"                 <rollershutter>  (gShutters, gLivingRoom)     [ "Blinds"   ]  { channel="openwebnet:bus_automation:mybridge:LR_shutter:shutter" }
 ```
 
+Example items linked to ZigBee devices:
+
+```xtend
+Dimmer          iDimmer             "Dimmer [%.0f %%]"                  <DimmableLight>  (gKitchen)                   [ "Lighting" ]  { channel="openwebnet:zb_dimmer:myZBgateway:myZB_dimmer:brightness" }
+Switch          iSimpleSwitch       "Kitchen Switch"                    <light>          (gKitchen)                   [ "Lighting" ]  { channel="openwebnet:zb_on_off_switch:myZBgateway:myZB_switch:switch_01" }
+Switch          iSwitch_01          "2U first light"                    <light>          (gKitchen)                   [ "Lighting" ]  { channel="openwebnet:zb_on_off_switch2u:myZBgateway:myZB_2U_switch:switch_01" }
+Switch          iSwitch_02          "2U second light"                   <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
     }
 }
index a779114839d846844cf24fe87c010f5415645922..813d09a307d27f59a205b8daf446e81dfd145f63 100644 (file)
@@ -23,7 +23,7 @@
     <dependency>
       <groupId>com.github.openwebnet4j</groupId>
       <artifactId>openwebnet4j</artifactId>
-      <version>0.3.1</version>
+      <version>0.3.2-1</version>
       <scope>compile</scope>
     </dependency>
 
index 1eb469c29d775faa9af0e82efa45fdb580b541c8..cdb84a5fd4eb349db411f344c4d6d97108e547b3 100644 (file)
@@ -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) {
index 3187de37e3b65d8f9a3b8937e56b00b1d149c8b8..e0a1d51bdd9c607d6a45b1dbe1ca244c64db2fef 100644 (file)
@@ -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<String, OpenWebNetThingHandler> registeredDevices = new ConcurrentHashMap<>();
+    private Map<String, @Nullable OpenWebNetThingHandler> registeredDevices = new ConcurrentHashMap<>();
+    private Map<String, Long> 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');
     }
 }
index 3badddd04fc7fde29f67627948781a33f99f59b8..d69da78f07eba6d818dda4050bdca8a2819bd1c1 100644 (file)
@@ -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<String, String> 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) {
index 3668722bdaef130451d6a3d5ea047ace5eabcb12..5e68b956e7360ffb803ef188dd5147b90aca57fc 100644 (file)
@@ -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<String, Object> 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)
index a41fd43727ff54383dea6ebc962bacc3169a51c3..4ba3d5392ff7cf258b0b389708946719a75e7c87 100644 (file)
@@ -38,8 +38,8 @@
                        </parameter>
 
                        <parameter name="where" type="text" required="true">
-                               <label>OpenWebNet Device Address (WHERE)</label>
-                               <description>Example: A/PL address: A=1 PL=3 --> WHERE=13. On local bus: WHERE=13#4#01</description>
+                               <label>OpenWebNet Device Address (where)</label>
+                               <description>Example: A/PL address: A=1 PL=3 --> where=13. On local bus: where=13#4#01</description>
                        </parameter>
                </config-description>
        </thing-type>
index 44fce13feb764d0bc7955f2618d2408c0fe5e78c..58f5013e98b5d59f49e8966d3703c8e8023b474c 100644 (file)
@@ -27,8 +27,8 @@
 
                <config-description>
                        <parameter name="where" type="text" required="true">
-                               <label>OpenWebNet Device Address (WHERE)</label>
-                               <description>Example: A/PL address: A=1 PL=3 --> WHERE=13. On local bus: WHERE=13#4#01</description>
+                               <label>OpenWebNet Device Address (where)</label>
+                               <description>Example: A/PL address: A=1 PL=3 --> where=13. On local bus: where=13#4#01</description>
                        </parameter>
                </config-description>
 
index e86818027e28c9a42d26a60ff838283b177a976c..805cc0dc6ba5d41145b15ed60979a0c641058b4a 100644 (file)
@@ -27,8 +27,8 @@
 
                <config-description>
                        <parameter name="where" type="text" required="true">
-                               <label>OpenWebNet Device Address (WHERE)</label>
-                               <description>Example: A/PL address: A=1 PL=3 --> WHERE=13. On local bus: WHERE=13#4#01</description>
+                               <label>OpenWebNet Device Address (where)</label>
+                               <description>Example: A/PL address: A=1 PL=3 --> where=13. On local bus: where=13#4#01</description>
                        </parameter>
                </config-description>
 
index 771cd016f044e902e1c15eb1397684651318fc4d..c5589c9088d8ae34f401508e380aa9afd6d7d38e 100644 (file)
@@ -24,7 +24,7 @@
 
                <config-description>
                        <parameter name="where" type="text" required="true">
-                               <label>OpenWebNet Device Address (WHERE)</label>
+                               <label>OpenWebNet Device Address (where)</label>
                                <description>It identifies one OpenWebNet device</description>
                        </parameter>
                </config-description>
index 6306f3f2842dceb91db1625571787bda2173afe6..b84f3c4a9e63d1358a033205c98ddcca8315efcb 100644 (file)
@@ -38,9 +38,8 @@
                                <default>AUTO</default>
                        </parameter>
                        <parameter name="where" type="text">
-                               <label>OpenWebNet Device Address</label>
-                               <description>It identifies one ZigBee device. Use decimal format address without the UNIT part and network: ZigBee
-                                       WHERE=414122201#9 -> OpenWebNet Device Address = 4141222</description>
+                               <label>OpenWebNet Device Address (where)</label>
+                               <description>It identifies one ZigBee device. Example: 765432101#9</description>
                                <required>true</required>
                        </parameter>
                </config-description>
index b4b04a8872dd940242d0bedb9086f07ae73072b0..98b07e81a5f54aeabc771ac765aa3d445b616074 100644 (file)
@@ -27,9 +27,8 @@
 
                <config-description>
                        <parameter name="where" type="text" required="true">
-                               <label>OpenWebNet Device Address</label>
-                               <description>It identifies one ZigBee device. Use decimal format address without the UNIT part and network: ZigBee
-                                       WHERE=414122201#9 -> OpenWebNet Device Address = 4141222</description>
+                               <label>OpenWebNet Device Address (where)</label>
+                               <description>It identifies one ZigBee device. Example: 765432101#9</description>
                        </parameter>
                </config-description>
 
index 6165974a3450daba5400b53a707bd221f3262b05..f741b72403d353bdd0179549ad7141d5cf871cda 100644 (file)
@@ -27,9 +27,8 @@
 
                <config-description>
                        <parameter name="where" type="text" required="true">
-                               <label>OpenWebNet Device Address</label>
-                               <description>It identifies one ZigBee device. Use decimal format address without the UNIT part and network: ZigBee
-                                       WHERE=414122201#9 -> OpenWebNet Device Address = 4141222</description>
+                               <label>OpenWebNet Device Address (where)</label>
+                               <description>It identifies one ZigBee device. Example: 765432101#9</description>
                        </parameter>
                </config-description>
 
index 4ace7056d6d751ae58a47463b1bd8014751fa800..6de61f7f7ff5b2af6351f86a4545dcb6305e01d0 100644 (file)
@@ -28,9 +28,8 @@
 
                <config-description>
                        <parameter name="where" type="text" required="true">
-                               <label>OpenWebNet Device Address</label>
-                               <description>It identifies one ZigBee device. Use decimal format address without the UNIT part and network: ZigBee
-                                       WHERE=414122201#9 -> OpenWebNet Device Address = 4141222</description>
+                               <label>OpenWebNet Device Address (where)</label>
+                               <description>It identifies one ZigBee device. Example: 765432100#9 (use unit=00 at the end)</description>
                        </parameter>
                </config-description>
 
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 (file)
index 0000000..8769dbf
--- /dev/null
@@ -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));
+        }
+    }
+}