]> git.basschouten.com Git - openhab-addons.git/commitdiff
[openwebnet] Fix Things synchronization at boot / reconnect (#11975)
authorM Valla <12682715+mvalla@users.noreply.github.com>
Sat, 26 Feb 2022 18:38:49 +0000 (19:38 +0100)
committerGitHub <noreply@github.com>
Sat, 26 Feb 2022 18:38:49 +0000 (19:38 +0100)
* [openwebnet] Fixes #11972: shutters are not refreshed at boot
* [openwebnet] added refreshDelay property
* [openwebnet] updated openwebnet4j to 0.7.1
* [openwebnet] improved where parameter description
* [openwebnet] updated to own4j 0.7.1 release
* [openwebnet] improved synch at boot
* [openwebnet] cleaned up refreshChannelState() and refreshDevice(), moved code to base class.
Added supportsRefreshAllDevices()
* [openwebnet] moved lastAllDevicesRefreshTS to sub-classes.
Set CEN/CEN+ things to ONLINE automatically.
* [openwebnet] improved comments/javadocs. Added connectSchedule to dispose()

Signed-off-by: Massimo Valla <mvcode00@gmail.com>
12 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/internal/OpenWebNetBindingConstants.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/OpenWebNetHandlerFactory.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetAutomationHandler.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetBridgeHandler.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetEnergyHandler.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetLightingHandler.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetScenarioHandler.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetThermoregulationHandler.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/internal/handler/OpenWebNetThingHandler.java
bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet.properties

index 734e86658adde57c65eaab9159eccb98c6c2b043..9587f36530e863e1e07043351e141cea3a38fae9 100644 (file)
@@ -123,13 +123,13 @@ Devices can be discovered automatically using an Inbox Scan after a gateway has
 
 For any manually added device, you must configure:
 
-- the associated gateway (`Parent Bridge` menu)
-- the `where` configuration parameter (`OpenWebNet Address`):
-    - example for BUS/SCS:
-        - light device with WHERE address Point to Point `A=2 PL=4` --> `where="24"`
-        - light device with WHERE address Point to Point `A=03 PL=11` on local bus --> `where="0311#4#01"`
-        - CEN scenario with WHERE address Point to Point `A=05 PL=12` --> `where="0512"`
-        - CEN+ configured scenario `5`: add a `2` before --> `where="25"`
+- the associated gateway Thing (`Parent Bridge` menu)
+- the `where` configuration parameter (`OpenWebNet Address`): this is the OpenWebNet address configured for the device in the BTicino/Legrand system. This address can be found either on the device itself (Physical configuration, using jumpers in case of BUS) or through the MyHOME_Suite software (Virtual configuration). The address can have several formats depending on the device/system:
+    - example for BUS/SCS system, address Point-to-point with Area (A) and Light-point (PL):
+        - light device A=`2` (Area 2), PL=`4` (Light-point 4) --> `where="24"`
+        - light device A=`03`, PL=`11` on local bus --> `where="0311#4#01"`
+        - CEN scenario A=`05`, PL=`12` --> `where="0512"`
+        - CEN+ scenario `5`: add a `2` before --> `where="25"`
         - Dry Contact or IR Interface `99`: add a `3` before --> `where="399"`
     - 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`.
  
@@ -141,7 +141,7 @@ In BTicino MyHOME Thermoregulation (WHO=4) each **zone** has associated a thermo
 Thermo zones can be configured defining a `bus_thermo_zone` Thing for each zone with the following parameters:
 
 - the `where` configuration parameter (`OpenWebNet Address`):
-    - example BUS/SCS Thermo zone `1` --> `where="1"` 
+    - example BUS/SCS zone `1` --> `where="1"` 
 - the `standAlone` configuration parameter (`boolean`, default: `true`): identifies if the zone is managed or not by a Central Unit (4 or 99 zones). `standAlone=true` means no Central Unit is present in the system.
 
 Temperature sensors can be configured defining a `bus_thermo_sensor` Thing with the following parameters:
index a46c8481d007203e0098314990503903cff12b26..24b732b7287d31ddfeeea588c9a2a95df5c28172 100644 (file)
@@ -23,7 +23,7 @@
     <dependency>
       <groupId>io.github.openwebnet4j</groupId>
       <artifactId>openwebnet4j</artifactId>
-      <version>0.6.0</version>
+      <version>0.7.1</version>
       <scope>compile</scope>
     </dependency>
 
index f689241668d0b2a9dfa905d8f6ac2f0f40902fbc..997f743188da5fcff974513058c084560111e5d7 100644 (file)
@@ -138,7 +138,7 @@ public class OpenWebNetBindingConstants {
     public static final String CONFIG_PROPERTY_WHERE = "where";
     public static final String CONFIG_PROPERTY_SHUTTER_RUN = "shutterRun";
     public static final String CONFIG_PROPERTY_SCENARIO_BUTTONS = "buttons";
-    // BUS gw config properties
+    // gw config properties
     public static final String CONFIG_PROPERTY_HOST = "host";
     public static final String CONFIG_PROPERTY_SERIAL_PORT = "serialPort";
     // properties
index c92242d308892c7401fb90be3fdedcdd8374d4fe..08077109bfb19846ba9e571d71bae5b0969116d7 100644 (file)
@@ -54,25 +54,25 @@ public class OpenWebNetHandlerFactory extends BaseThingHandlerFactory {
     @Override
     protected @Nullable ThingHandler createHandler(Thing thing) {
         if (OpenWebNetBridgeHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
-            logger.debug("creating NEW BRIDGE Handler");
+            logger.debug("creating NEW BRIDGE Handler --- {}", thing.getUID());
             return new OpenWebNetBridgeHandler((Bridge) thing);
         } else if (OpenWebNetGenericHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
-            logger.debug("creating NEW GENERIC Handler");
+            logger.debug("creating NEW GENERIC Handler --- {}", thing.getUID());
             return new OpenWebNetGenericHandler(thing);
         } else if (OpenWebNetLightingHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
-            logger.debug("creating NEW LIGHTING Handler");
+            logger.debug("creating NEW LIGHTING Handler --- {}", thing.getUID());
             return new OpenWebNetLightingHandler(thing);
         } else if (OpenWebNetAutomationHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
-            logger.debug("creating NEW AUTOMATION Handler");
+            logger.debug("creating NEW AUTOMATION Handler --- {}", thing.getUID());
             return new OpenWebNetAutomationHandler(thing);
         } else if (OpenWebNetEnergyHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
-            logger.debug("creating NEW ENERGY Handler");
+            logger.debug("creating NEW ENERGY Handler --- {}", thing.getUID());
             return new OpenWebNetEnergyHandler(thing);
         } else if (OpenWebNetThermoregulationHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
-            logger.debug("creating NEW THERMO Handler");
+            logger.debug("creating NEW THERMO Handler --- {}", thing.getUID());
             return new OpenWebNetThermoregulationHandler(thing);
         } else if (OpenWebNetScenarioHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
-            logger.debug("creating NEW SCENARIO Handler");
+            logger.debug("creating NEW SCENARIO Handler --- {}", thing.getUID());
             return new OpenWebNetScenarioHandler(thing);
         }
         logger.warn("ThingType {} is not supported by this binding", thing.getThingTypeUID());
index ecb00fcb735e4f900f6a57be8f6d7aa307621222..43437d580adbac8ae65efa2b4e49a9cde5cb15a9 100644 (file)
@@ -59,12 +59,10 @@ public class OpenWebNetAutomationHandler extends OpenWebNetThingHandler {
 
     private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("ss.SSS");
 
-    private static long lastAllDevicesRefreshTS = -1; // timestamp when the last request for all device refresh was sent
-    protected static final int ALL_DEVICES_REFRESH_INTERVAL_MSEC = 60000; // interval in msec before sending another all
-                                                                          // devices refresh request
-
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.AUTOMATION_SUPPORTED_THING_TYPES;
 
+    private static long lastAllDevicesRefreshTS = 0; // ts when last all device refresh was sent for this handler
+
     // moving states
     public static final int MOVING_STATE_STOPPED = 0;
     public static final int MOVING_STATE_MOVING_UP = 1;
@@ -141,38 +139,36 @@ public class OpenWebNetAutomationHandler extends OpenWebNetThingHandler {
 
     @Override
     protected void requestChannelState(ChannelUID channel) {
-        logger.debug("requestChannelState() thingUID={} channel={}", thing.getUID(), channel.getId());
+        super.requestChannelState(channel);
         Where w = deviceWhere;
         if (w != null) {
             try {
                 send(Automation.requestStatus(w.value()));
             } catch (OWNException e) {
-                logger.debug("Exception while requesting channel {} state: {}", channel, e.getMessage(), e);
+                logger.debug("Exception while requesting state for channel {}: {} ", channel, e.getMessage());
+                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
             }
-        } else {
-            logger.warn("Could not requestChannelState(): deviceWhere is null");
         }
     }
 
+    @Override
+    protected long getRefreshAllLastTS() {
+        return lastAllDevicesRefreshTS;
+    };
+
     @Override
     protected void refreshDevice(boolean refreshAll) {
-        OpenWebNetBridgeHandler brH = bridgeHandler;
-        if (brH != null) {
-            if (brH.isBusGateway() && refreshAll) {
-                long now = System.currentTimeMillis();
-                if (now - lastAllDevicesRefreshTS > ALL_DEVICES_REFRESH_INTERVAL_MSEC) {
-                    try {
-                        send(Automation.requestStatus(WhereLightAutom.GENERAL.value()));
-                        lastAllDevicesRefreshTS = now;
-                    } catch (OWNException e) {
-                        logger.warn("Excpetion while requesting all devices refresh: {}", e.getMessage());
-                    }
-                } else {
-                    logger.debug("Refresh all devices just sent...");
-                }
-            } else {
-                requestChannelState(new ChannelUID("any")); // channel here does not make any difference
+        if (refreshAll) {
+            logger.debug("--- refreshDevice() : refreshing GENERAL... ({})", thing.getUID());
+            try {
+                send(Automation.requestStatus(WhereLightAutom.GENERAL.value()));
+                lastAllDevicesRefreshTS = System.currentTimeMillis();
+            } catch (OWNException e) {
+                logger.warn("Excpetion while requesting all devices refresh: {}", e.getMessage());
             }
+        } else {
+            logger.debug("--- refreshDevice() : refreshing SINGLE... ({})", thing.getUID());
+            requestChannelState(new ChannelUID(thing.getUID(), CHANNEL_SHUTTER));
         }
     }
 
index a06b03d3ead5893c2e3c2cc73395516f938884fb..e0b06291627c5a9bd58339115469cbb1cb2a925d 100644 (file)
@@ -16,6 +16,7 @@ import static org.openhab.binding.openwebnet.internal.OpenWebNetBindingConstants
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -79,6 +80,9 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
 
     private static final int REFRESH_ALL_DEVICES_DELAY_MSEC = 500; // Delay to wait before sending all devices refresh
                                                                    // request after a connect/reconnect
+    private static final int REFRESH_ALL_CHECK_DELAY_SEC = 20;
+
+    private static long lastRegisteredDeviceTS = -1; // timestamp when the last device has been associated to the bridge
 
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.BRIDGE_SUPPORTED_THING_TYPES;
 
@@ -94,7 +98,8 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
 
     public @Nullable OpenWebNetDeviceDiscoveryService deviceDiscoveryService;
     private boolean reconnecting = false; // we are trying to reconnect to gateway
-    private @Nullable ScheduledFuture<?> refreshSchedule;
+    private @Nullable ScheduledFuture<?> refreshAllSchedule;
+    private @Nullable ScheduledFuture<?> connectSchedule;
 
     private boolean scanIsActive = false; // a device scan has been activated by OpenWebNetDeviceDiscoveryService;
     private boolean discoveryByActivation;
@@ -128,8 +133,8 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
                 logger.debug("Trying to connect gateway {}... ", gw);
                 try {
                     gw.connect();
-                    scheduler.schedule(() -> {
-                        // if status is still UNKNOWN after timer ends, set the device as OFFLINE
+                    connectSchedule = scheduler.schedule(() -> {
+                        // if status is still UNKNOWN after timer ends, set the device OFFLINE
                         if (thing.getStatus().equals(ThingStatus.UNKNOWN)) {
                             logger.info("status still UNKNOWN. Setting device={} to OFFLINE", thing.getUID());
                             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
@@ -167,6 +172,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
      */
     private @Nullable OpenGateway initBusGateway() {
         logger.debug("Initializing BUS gateway");
+
         OpenWebNetBusBridgeConfig busBridgeConfig = getConfigAs(OpenWebNetBusBridgeConfig.class);
         String host = busBridgeConfig.getHost();
         if (host == null || host.isEmpty()) {
@@ -199,7 +205,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
             return;
         } else {
             if (command instanceof RefreshType) {
-                refreshAllDevices();
+                refreshAllBridgeDevices();
             } else {
                 logger.warn("Command or channel not supported: channel={} command={}", channelUID, command);
             }
@@ -219,10 +225,14 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
 
     @Override
     public void dispose() {
-        ScheduledFuture<?> rSc = refreshSchedule;
+        ScheduledFuture<?> rSc = refreshAllSchedule;
         if (rSc != null) {
             rSc.cancel(true);
         }
+        ScheduledFuture<?> cs = connectSchedule;
+        if (cs != null) {
+            cs.cancel(true);
+        }
         disconnectGateway();
         super.dispose();
     }
@@ -366,6 +376,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
             logger.warn("registering device with an existing ownId={}", ownId);
         }
         registeredDevices.put(ownId, thingHandler);
+        lastRegisteredDeviceTS = System.currentTimeMillis();
         logger.debug("registered device ownId={}, thing={}", ownId, thingHandler.getThing().getUID());
     }
 
@@ -392,13 +403,62 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
         return registeredDevices.get(ownId);
     }
 
-    private void refreshAllDevices() {
-        logger.debug("Refreshing all devices for bridge {}", thing.getUID());
-        for (Thing ownThing : getThing().getThings()) {
-            OpenWebNetThingHandler hndlr = (OpenWebNetThingHandler) ownThing.getHandler();
-            if (hndlr != null) {
-                hndlr.refreshDevice(true);
+    private void refreshAllBridgeDevices() {
+        logger.debug("--- --- ABOUT TO REFRESH ALL devices for bridge {}", thing.getUID());
+        int howMany = 0;
+        final List<Thing> things = getThing().getThings();
+        int total = things.size();
+        logger.debug("--- FOUND {} things by getThings()", total);
+        if (total > 0) {
+            if (registeredDevices.isEmpty()
+                    || (System.currentTimeMillis() - lastRegisteredDeviceTS < REFRESH_ALL_DEVICES_DELAY_MSEC)) {
+                // if a device has been registered with the bridge just now, let's wait for other devices: re-schedule
+                // refreshAllDevices
+                logger.debug(
+                        "--- REGISTER device not started or just called... re-scheduling refreshAllBridgeDevices()");
+                refreshAllSchedule = scheduler.schedule(this::refreshAllBridgeDevices, REFRESH_ALL_DEVICES_DELAY_MSEC,
+                        TimeUnit.MILLISECONDS);
+            } else {
+                for (Thing ownThing : things) {
+                    OpenWebNetThingHandler hndlr = (OpenWebNetThingHandler) ownThing.getHandler();
+                    if (hndlr != null) {
+                        howMany++;
+                        logger.debug("--- REFRESHING ALL DEVICES FOR thing #{}/{}: {}", howMany, total,
+                                ownThing.getUID());
+                        hndlr.refreshAllDevices();
+                    } else {
+                        logger.warn("--- No handler for thing {}", ownThing.getUID());
+                    }
+                }
+                logger.debug("--- --- COMPLETED REFRESH all devices for bridge {}", thing.getUID());
+
+                // set a check that all things are Online
+                refreshAllSchedule = scheduler.schedule(() -> checkAllRefreshed(things), REFRESH_ALL_CHECK_DELAY_SEC,
+                        TimeUnit.SECONDS);
             }
+        } else {
+            logger.debug("--- --- NO CHILD DEVICE to REFRESH for bridge {}", thing.getUID());
+        }
+    }
+
+    private void checkAllRefreshed(List<Thing> things) {
+        int howMany = 0;
+        int total = things.size();
+        boolean allOnline = true;
+        for (Thing ownThing : things) {
+            howMany++;
+            ThingStatus ts = ownThing.getStatus();
+            if (ThingStatus.ONLINE == ts) {
+                logger.debug("--- CHECKED ONLINE thing #{}/{}: {}", howMany, total, ownThing.getUID());
+            } else {
+                logger.debug("--- CHECKED ^^^OFFLINE^^^ thing #{}/{}: {}", howMany, total, ownThing.getUID());
+                allOnline = false;
+            }
+        }
+        if (allOnline) {
+            logger.debug("--- --- REFRESH CHECK COMPLETED: all things ONLINE for bridge {}", thing.getUID());
+        } else {
+            logger.debug("--- --- REFRESH CHECK COMPLETED: NOT all things ONLINE for bridge {}", thing.getUID());
         }
     }
 
@@ -476,7 +536,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
         }
         updateStatus(ThingStatus.ONLINE);
         // schedule a refresh for all devices
-        refreshSchedule = scheduler.schedule(this::refreshAllDevices, REFRESH_ALL_DEVICES_DELAY_MSEC,
+        refreshAllSchedule = scheduler.schedule(this::refreshAllBridgeDevices, REFRESH_ALL_DEVICES_DELAY_MSEC,
                 TimeUnit.MILLISECONDS);
     }
 
@@ -532,7 +592,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
                             "@text/offline.conf-error-auth" + " (" + e + ")");
                 }
             } else {
-                logger.debug("---- reconnecting=true");
+                logger.debug("---- already reconnecting");
             }
         } else {
             logger.warn("---- cannot start RECONNECT, gateway is null");
@@ -550,9 +610,8 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
                 this.updateProperty(PROPERTY_FIRMWARE_VERSION, gw.getFirmwareVersion());
                 logger.debug("gw firmware version: {}", gw.getFirmwareVersion());
             }
-
             // schedule a refresh for all devices
-            refreshSchedule = scheduler.schedule(this::refreshAllDevices, REFRESH_ALL_DEVICES_DELAY_MSEC,
+            refreshAllSchedule = scheduler.schedule(this::refreshAllBridgeDevices, REFRESH_ALL_DEVICES_DELAY_MSEC,
                     TimeUnit.MILLISECONDS);
         }
     }
index d0e1c67948d5e042c67f36ac713b297cac44f8a6..59c68e5d17f6619e096edace6c3e29f3400a9f83 100644 (file)
@@ -28,6 +28,7 @@ import org.openhab.core.library.unit.Units;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
 import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
 import org.openhab.core.thing.ThingStatusInfo;
 import org.openhab.core.thing.ThingTypeUID;
 import org.openhab.core.types.Command;
@@ -146,22 +147,22 @@ public class OpenWebNetEnergyHandler extends OpenWebNetThingHandler {
 
     @Override
     protected void requestChannelState(ChannelUID channel) {
-        logger.debug("requestChannelState() thingUID={} channel={}", thing.getUID(), channel.getId());
+        super.requestChannelState(channel);
         Where w = deviceWhere;
         if (w != null) {
             try {
                 send(EnergyManagement.requestActivePower(w.value()));
             } catch (OWNException e) {
-                logger.debug("Exception while requesting channel {} state: {}", channel, e.getMessage(), e);
+                logger.debug("Exception while requesting state for channel {}: {} ", channel, e.getMessage());
+                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
             }
-        } else {
-            logger.warn("Could not requestChannelState(): deviceWhere is null");
         }
     }
 
     @Override
     protected void refreshDevice(boolean refreshAll) {
-        requestChannelState(new ChannelUID("any:any:any:any"));
+        logger.debug("--- refreshDevice() : refreshing SINGLE... ({})", thing.getUID());
+        requestChannelState(new ChannelUID(thing.getUID(), CHANNEL_POWER));
     }
 
     @Override
index 2236c123a5d04d27e4b0a167a08494908327632b..c8f2b61a5732862a30603626943d1e7ff7f00ae7 100644 (file)
@@ -26,10 +26,10 @@ import org.openhab.core.library.types.PercentType;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
 import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
 import org.openhab.core.thing.ThingTypeUID;
 import org.openhab.core.types.Command;
 import org.openwebnet4j.communication.OWNException;
-import org.openwebnet4j.communication.Response;
 import org.openwebnet4j.message.BaseOpenMessage;
 import org.openwebnet4j.message.FrameException;
 import org.openwebnet4j.message.Lighting;
@@ -63,16 +63,12 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
 
     private static final int UNKNOWN_STATE = 1000;
 
-    private static long lastAllDevicesRefreshTS = -1; // timestamp when the last request for all device refresh was sent
-                                                      // for this handler
-
-    protected static final int ALL_DEVICES_REFRESH_INTERVAL_MSEC = 60000; // interval in msec before sending another all
-                                                                          // devices refresh request
-
     private long lastBrightnessChangeSentTS = 0; // timestamp when last brightness change was sent to the device
 
     private long lastStatusRequestSentTS = 0; // timestamp when last status request was sent to the device
 
+    private static long lastAllDevicesRefreshTS = 0; // ts when last all device refresh was sent for this handler
+
     private int brightness = UNKNOWN_STATE; // current brightness percent value for this device
 
     private int brightnessBeforeOff = UNKNOWN_STATE; // latest brightness before device was set to off
@@ -85,58 +81,43 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
 
     @Override
     protected void requestChannelState(ChannelUID channel) {
-        logger.debug("requestChannelState() thingUID={} channel={}", thing.getUID(), channel.getId());
-        requestStatus(channel.getId());
-    }
-
-    /** helper method to request light status based on channel */
-    private void requestStatus(String channelId) {
-        Where w = deviceWhere;
-        if (w != null) {
+        super.requestChannelState(channel);
+        if (deviceWhere != null) {
             try {
                 lastStatusRequestSentTS = System.currentTimeMillis();
-                Response res = send(Lighting.requestStatus(toWhere(channelId)));
-                if (res != null && res.isSuccess()) {
-                    // set thing online, if not already
-                    ThingStatus ts = getThing().getStatus();
-                    if (ThingStatus.ONLINE != ts && ThingStatus.REMOVING != ts && ThingStatus.REMOVED != ts) {
-                        updateStatus(ThingStatus.ONLINE);
-                    }
-                }
+                send(Lighting.requestStatus(toWhere(channel.getId())));
             } catch (OWNException e) {
-                logger.warn("requestStatus() Exception while requesting light state: {}", e.getMessage());
+                logger.debug("Exception while requesting state for channel {}: {} ", channel, e.getMessage());
+                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
             }
-        } else {
-            logger.warn("Could not requestStatus(): deviceWhere is null");
         }
     }
 
+    @Override
+    protected long getRefreshAllLastTS() {
+        return lastAllDevicesRefreshTS;
+    };
+
     @Override
     protected void refreshDevice(boolean refreshAll) {
-        OpenWebNetBridgeHandler brH = bridgeHandler;
-        if (brH != null) {
-            if (brH.isBusGateway() && refreshAll) {
-                long now = System.currentTimeMillis();
-                if (now - lastAllDevicesRefreshTS > ALL_DEVICES_REFRESH_INTERVAL_MSEC) {
-                    try {
-                        send(Lighting.requestStatus(WhereLightAutom.GENERAL.value()));
-                        lastAllDevicesRefreshTS = now;
-                    } catch (OWNException e) {
-                        logger.warn("Excpetion while requesting all devices refresh: {}", e.getMessage());
-                    }
-                } else {
-                    logger.debug("Refresh all devices just sent...");
-                }
-            } else { // USB or BUS-single device
-                ThingTypeUID thingType = thing.getThingTypeUID();
-                if (THING_TYPE_ZB_ON_OFF_SWITCH_2UNITS.equals(thingType)) {
-                    // Unfortunately using USB Gateway OpenWebNet both switch endpoints cannot be requested at the same
-                    // time using UNIT 00 because USB stick returns NACK, so we need to send a request status for both
-                    // endpoints
-                    requestStatus(CHANNEL_SWITCH_02);
-                }
-                requestStatus(""); // channel here does not make any difference, see {@link #toWhere()}
+        if (refreshAll) {
+            logger.debug("--- refreshDevice() : refreshing GENERAL... ({})", thing.getUID());
+            try {
+                send(Lighting.requestStatus(WhereLightAutom.GENERAL.value()));
+                lastAllDevicesRefreshTS = System.currentTimeMillis();
+            } catch (OWNException e) {
+                logger.warn("Excpetion while requesting all devices refresh: {}", e.getMessage());
+            }
+        } else {
+            logger.debug("--- refreshDevice() : refreshing SINGLE... ({})", thing.getUID());
+            ThingTypeUID thingType = thing.getThingTypeUID();
+            if (THING_TYPE_ZB_ON_OFF_SWITCH_2UNITS.equals(thingType)) {
+                // Unfortunately using USB Gateway OpenWebNet both switch endpoints cannot be requested at the same
+                // time using UNIT 00 because USB stick returns NACK, so we need to send a request status for both
+                // endpoints
+                requestChannelState(new ChannelUID(thing.getUID(), CHANNEL_SWITCH_02));
             }
+            requestChannelState(new ChannelUID(thing.getUID(), CHANNEL_SWITCH_01));
         }
     }
 
@@ -291,7 +272,7 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
                     logger.debug("  $BRI 'ON' is new notification from network, scheduling requestStatus...");
                     // we must wait BRIGHTNESS_STATUS_REQUEST_DELAY_MSEC to be sure dimmer has reached its final level
                     scheduler.schedule(() -> {
-                        requestStatus(CHANNEL_BRIGHTNESS);
+                        requestChannelState(new ChannelUID(thing.getUID(), CHANNEL_BRIGHTNESS));
                     }, BRIGHTNESS_STATUS_REQUEST_DELAY_MSEC, TimeUnit.MILLISECONDS);
                     return;
                 } else {
index 25547cbb954ce4cf5117dcd18497c7585549d97b..33b61005f8a708ba0d8d392aef07511c1f9abe47 100644 (file)
@@ -30,6 +30,8 @@ import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.thing.Channel;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
+import org.openhab.core.thing.ThingStatus;
+import org.openhab.core.thing.ThingStatusDetail;
 import org.openhab.core.thing.ThingTypeUID;
 import org.openhab.core.thing.binding.ThingHandlerService;
 import org.openhab.core.thing.binding.builder.ChannelBuilder;
@@ -117,10 +119,8 @@ public class OpenWebNetScenarioHandler extends OpenWebNetThingHandler {
 
     private boolean isDryContactIR = false;
     private boolean isCENPlus = false;
-    private static long lastAllDevicesRefreshTS = -1; // timestamp when the last request for all device refresh was sent
-    // for this handler
-    protected static final int ALL_DEVICES_REFRESH_INTERVAL_MSEC = 10000; // interval in msec before sending another all
-    // devices refresh request
+
+    private static long lastAllDevicesRefreshTS = 0; // ts when last all device refresh was sent for this handler
 
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.SCENARIO_SUPPORTED_THING_TYPES;
 
@@ -361,49 +361,50 @@ public class OpenWebNetScenarioHandler extends OpenWebNetThingHandler {
     }
 
     @Override
-    protected void refreshDevice(boolean refreshAll) {
+    protected void requestChannelState(ChannelUID channel) {
         if (isDryContactIR) {
-            if (refreshAll) {
-                long now = System.currentTimeMillis();
-                if (now - lastAllDevicesRefreshTS > ALL_DEVICES_REFRESH_INTERVAL_MSEC) {
-                    try {
-                        send(CENPlusScenario.requestStatus("30"));
-                        lastAllDevicesRefreshTS = now;
-                    } catch (OWNException e) {
-                        logger.warn("Excpetion while requesting all DryContact/IR devices refresh: {}", e.getMessage());
-                    }
-                } else {
-                    logger.debug("Refresh all devices just sent...");
+            super.requestChannelState(channel);
+            Where w = deviceWhere;
+            if (w != null) {
+                try {
+                    send(CENPlusScenario.requestStatus(w.value()));
+                } catch (OWNException e) {
+                    logger.debug("Exception while requesting state for channel {}: {} ", channel, e.getMessage());
+                    updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
                 }
-            } else {
-                requestState();
             }
         } else {
-            logger.debug("CEN/CEN+ channels are trigger channels and do not have state");
+            logger.debug("requestChannelState() CEN/CEN+ channels are trigger channels and do not have state.");
         }
     }
 
     @Override
-    protected void requestChannelState(ChannelUID channel) {
-        if (isDryContactIR) {
-            requestState();
-        } else {
-            logger.debug("CEN/CEN+ channels are trigger channels and do not have state");
-        }
-    }
+    protected long getRefreshAllLastTS() {
+        return lastAllDevicesRefreshTS;
+    };
 
-    /* helper method to request DryContact/IR device state */
-    private void requestState() {
-        Where w = deviceWhere;
-        if (w != null) {
-            try {
-                send(CENPlusScenario.requestStatus(w.value()));
-            } catch (OWNException e) {
-                logger.warn("requestState() Exception while requesting device state: {} for thing {}", e.getMessage(),
-                        thing.getUID());
+    @Override
+    protected void refreshDevice(boolean refreshAll) {
+        if (isDryContactIR) {
+            if (refreshAll) {
+                logger.debug("--- refreshDevice() : refreshing GENERAL... ({})", thing.getUID());
+                try {
+                    send(CENPlusScenario.requestStatus("30"));
+                    lastAllDevicesRefreshTS = System.currentTimeMillis();
+                } catch (OWNException e) {
+                    logger.warn("Excpetion while requesting all devices refresh: {}", e.getMessage());
+                }
+            } else {
+                logger.debug("--- refreshDevice() : refreshing SINGLE... ({})", thing.getUID());
+                requestChannelState(new ChannelUID(thing.getUID(), CHANNEL_DRY_CONTACT_IR));
             }
         } else {
-            logger.warn("Could not requestState(): deviceWhere is null");
+            logger.debug("CEN/CEN+ channels are trigger channels and do not have state. Setting it ONLINE");
+            // put CEN/CEN+ scenario things to ONLINE automatically as they do not have state
+            ThingStatus ts = getThing().getStatus();
+            if (ThingStatus.ONLINE != ts && ThingStatus.REMOVING != ts && ThingStatus.REMOVED != ts) {
+                updateStatus(ThingStatus.ONLINE);
+            }
         }
     }
 
index 42c7fd4133a314423b4272642f6d87b3618c4905..4dba0b938e088fee60213fab4c258916071082d6 100644 (file)
@@ -97,9 +97,31 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
 
     @Override
     protected void requestChannelState(ChannelUID channel) {
+        super.requestChannelState(channel);
         refreshDevice(false);
     }
 
+    @Override
+    protected void refreshDevice(boolean refreshAll) {
+        logger.debug("--- refreshDevice() : refreshing SINGLE... ({})", thing.getUID());
+        if (deviceWhere != null) {
+            String w = deviceWhere.value();
+            try {
+                send(Thermoregulation.requestTemperature(w));
+                if (!this.isTempSensor) {
+                    // for bus_thermo_zone request also other single channels updates
+                    send(Thermoregulation.requestSetPointTemperature(w));
+                    send(Thermoregulation.requestFanCoilSpeed(w));
+                    send(Thermoregulation.requestMode(w));
+                    send(Thermoregulation.requestValvesStatus(w));
+                    send(Thermoregulation.requestActuatorsStatus(w));
+                }
+            } catch (OWNException e) {
+                logger.warn("refreshDevice() where='{}' returned OWNException {}", w, e.getMessage());
+            }
+        }
+    }
+
     @Override
     protected Where buildBusWhere(String wStr) throws IllegalArgumentException {
         WhereThermo wt = new WhereThermo(wStr);
@@ -233,17 +255,17 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
 
         Thermoregulation.WhatThermo w = Thermoregulation.WhatThermo.fromValue(tmsg.getWhat().value());
 
-        if (w.mode() == null) {
+        if (w.getMode() == null) {
             logger.debug("updateModeAndFunction() Could not parse Mode from: {}", tmsg.getFrameValue());
             return;
         }
-        if (w.function() == null) {
+        if (w.getFunction() == null) {
             logger.debug("updateModeAndFunction() Could not parse Function from: {}", tmsg.getFrameValue());
             return;
         }
 
-        Thermoregulation.OperationMode mode = w.mode();
-        Thermoregulation.Function function = w.function();
+        Thermoregulation.OperationMode mode = w.getMode();
+        Thermoregulation.Function function = w.getFunction();
 
         if (w == Thermoregulation.WhatThermo.HEATING) {
             function = Thermoregulation.Function.HEATING;
@@ -314,24 +336,4 @@ public class OpenWebNetThermoregulationHandler extends OpenWebNetThingHandler {
             updateState(CHANNEL_ACTUATORS, UnDefType.UNDEF);
         }
     }
-
-    @Override
-    protected void refreshDevice(boolean refreshAll) {
-        if (deviceWhere != null) {
-            String w = deviceWhere.value();
-            try {
-                send(Thermoregulation.requestTemperature(w));
-                if (!this.isTempSensor) {
-                    // for bus_thermo_zone request also other single channels updates
-                    send(Thermoregulation.requestSetPointTemperature(w));
-                    send(Thermoregulation.requestFanCoilSpeed(w));
-                    send(Thermoregulation.requestMode(w));
-                    send(Thermoregulation.requestValvesStatus(w));
-                    send(Thermoregulation.requestActuatorsStatus(w));
-                }
-            } catch (OWNException e) {
-                logger.warn("refreshDevice() where='{}' returned OWNException {}", w, e.getMessage());
-            }
-        }
-    }
 }
index 1cc076890cc5dda0055c358052bc462f1fea39e7..3ab7523eb9a97c2fa873043cbd30b4e9bfc523e7 100644 (file)
@@ -29,6 +29,7 @@ import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
 import org.openhab.core.thing.ThingStatus;
 import org.openhab.core.thing.ThingStatusDetail;
+import org.openhab.core.thing.ThingStatusInfo;
 import org.openhab.core.thing.binding.BaseThingHandler;
 import org.openhab.core.types.Command;
 import org.openhab.core.types.RefreshType;
@@ -58,10 +59,14 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler {
 
     protected @Nullable OpenWebNetBridgeHandler bridgeHandler;
     protected @Nullable String ownId; // OpenWebNet identifier for this device: WHO.WHERE
-    protected @Nullable Where deviceWhere; // this device Where address
+    protected @Nullable Where deviceWhere; // this device WHERE address
 
+    protected @Nullable ScheduledFuture<?> requestChannelStateTimeout;
     protected @Nullable ScheduledFuture<?> refreshTimeout;
 
+    private static final int ALL_DEVICES_REFRESH_INTERVAL_MSEC = 60_000; // interval before sending another
+                                                                         // refreshAllDevices request
+
     public OpenWebNetThingHandler(Thing thing) {
         super(thing);
     }
@@ -108,6 +113,15 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler {
         }
     }
 
+    @Override
+    public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
+        if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) {
+            updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "@text/unknown.waiting-state");
+        } else if (bridgeStatusInfo.getStatus() == ThingStatus.OFFLINE) {
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
+        }
+    }
+
     @Override
     public void handleCommand(ChannelUID channel, Command command) {
         logger.debug("handleCommand() (command={} - channel={})", command, channel);
@@ -115,23 +129,16 @@ 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", command, getThing().getUID());
+                logger.info("Cannot handle {} command for {}: gateway is not connected", command, thing.getUID());
                 return;
             }
             if (deviceWhere == null) {
                 logger.info("Cannot handle {} command for {}: 'where' parameter is not configured or is invalid",
-                        command, getThing().getUID());
+                        command, thing.getUID());
                 return;
             }
             if (command instanceof RefreshType) {
                 requestChannelState(channel);
-                // set a schedule to put device OFFLINE if no answer is received after THING_STATE_REQ_TIMEOUT_SEC
-                refreshTimeout = scheduler.schedule(() -> {
-                    if (thing.getStatus().equals(ThingStatus.UNKNOWN)) {
-                        updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
-                                "Could not get channel state (timer expired)");
-                    }
-                }, THING_STATE_REQ_TIMEOUT_SEC, TimeUnit.SECONDS);
             } else {
                 handleChannelCommand(channel, command);
             }
@@ -142,16 +149,16 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler {
 
     /**
      * Handles a command for the specific channel for this thing.
-     * It must be implemented by each specific OpenWebNet category of device (WHO), based on channel
+     * It must be further implemented by each specific device handler.
      *
-     * @param channel specific ChannleUID
+     * @param channel the {@link ChannelUID}
      * @param command the Command to be executed
      */
     protected abstract void handleChannelCommand(ChannelUID channel, Command command);
 
     /**
-     * Handle incoming message from OWN network via bridge Thing, directed to this device. It should be further
-     * implemented by each specific device handler.
+     * Handle incoming message from OWN network via bridge Thing, directed to this device.
+     * It should be further implemented by each specific device handler.
      *
      * @param msg the message to handle
      */
@@ -163,7 +170,9 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler {
     }
 
     /**
-     * Helper method to send OWN messages from ThingHandlers
+     * Helper method to send OWN messages from handler.
+     *
+     * @param msg the OpenMessage to be sent
      */
     public @Nullable Response send(OpenMessage msg) throws OWNException {
         OpenWebNetBridgeHandler bh = bridgeHandler;
@@ -178,7 +187,9 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler {
     }
 
     /**
-     * Helper method to send with high priority OWN messages from ThingsHandlers
+     * Helper method to send with high priority OWN messages from handler.
+     *
+     * @param msg the OpenMessage to be sent
      */
     protected @Nullable Response sendHighPriority(OpenMessage msg) throws OWNException {
         OpenWebNetBridgeHandler handler = bridgeHandler;
@@ -192,19 +203,87 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler {
     }
 
     /**
-     * Request the state for the specified channel
+     * Request the state for the specified channel. If no answer is received within THING_STATE_REQ_TIMEOUT_SEC, it is
+     * put OFFLINE.
+     * The method must be further implemented by each specific handler.
      *
      * @param channel the {@link ChannelUID} to request the state for
      */
-    protected abstract void requestChannelState(ChannelUID channel);
+    protected void requestChannelState(ChannelUID channel) {
+        logger.debug("requestChannelState() {}", channel);
+        Where w = deviceWhere;
+        if (w == null) {
+            logger.warn("Could not requestChannelState(): deviceWhere is null for thing {}", thing.getUID());
+            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.conf-error-where");
+            return;
+        }
+        // set a schedule to put device OFFLINE if no answer is received after THING_STATE_REQ_TIMEOUT_SEC
+        requestChannelStateTimeout = scheduler.schedule(() -> {
+            if (thing.getStatus().equals(ThingStatus.UNKNOWN)) {
+                logger.debug("requestChannelState() TIMEOUT for thing {}", thing.getUID());
+                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+                        "@text/offline.comm-error-state");
+            }
+        }, THING_STATE_REQ_TIMEOUT_SEC, TimeUnit.SECONDS);
+    }
 
     /**
-     * Refresh the device
+     * Refresh a device, possibly using a single OWN command if refreshAll=true and if supported.
+     * The method must be further implemented by each specific handler.
      *
-     * @param refreshAll set true if all devices of the binding should be refreshed with one command, if possible
+     * @param refreshAll true if all devices for this handler must be refreshed with a single OWN command, if supported,
+     *            otherwise just refresh the single device.
      */
     protected abstract void refreshDevice(boolean refreshAll);
 
+    /**
+     * If the subclass supports refreshing all devices with a single OWN command, returns the last TS when a refreshAll
+     * was requested, or 0 if not requested yet. If not supported return -1 (default).
+     * It must be implemented by each subclass that supports all devices refresh.
+     *
+     * @return timestamp when last refreshAll command was sent, 0 if not requested yet, or -1 if it's not supported by
+     *         subclass.
+     */
+    protected long getRefreshAllLastTS() {
+        return -1;
+    };
+
+    /**
+     * Refresh all devices for this handler
+     */
+    protected void refreshAllDevices() {
+        logger.debug("--- refreshAllDevices() for device {}", thing.getUID());
+        OpenWebNetBridgeHandler brH = bridgeHandler;
+        if (brH != null) {
+            long refAllTS = getRefreshAllLastTS();
+            logger.debug("{} support = {}", thing.getUID(), refAllTS >= 0);
+            if (brH.isBusGateway() && refAllTS >= 0) {
+                long now = System.currentTimeMillis();
+                if (now - refAllTS > ALL_DEVICES_REFRESH_INTERVAL_MSEC) {
+                    logger.debug("--- refreshAllDevices() : refreshing ALL devices... ({})", thing.getUID());
+                    refreshDevice(true);
+                } else {
+                    logger.debug("--- refreshAllDevices() : refresh all devices just sent... ({})", thing.getUID());
+                }
+                // sometimes GENERAL (e.g. #*1*0##) refresh requests do not return state for all devices, so let's
+                // schedule another single refresh device, just in case
+                refreshTimeout = scheduler.schedule(() -> {
+                    if (thing.getStatus().equals(ThingStatus.UNKNOWN)) {
+                        logger.debug(
+                                "--- refreshAllDevices() : schedule expired: --UNKNOWN-- status for {}. Refreshing it...",
+                                thing.getUID());
+                        refreshDevice(false);
+                    } else {
+                        logger.debug("--- refreshAllDevices() : schedule expired: ONLINE status for {}",
+                                thing.getUID());
+                    }
+                }, THING_STATE_REQ_TIMEOUT_SEC, TimeUnit.SECONDS);
+            } else { // USB device or AllDevicesRefresh not supported
+                refreshDevice(false);
+            }
+        }
+    }
+
     /**
      * Abstract builder for device Where address, to be implemented by each subclass to choose the right Where subclass
      * (the method is used only if the Thing is associated to a BUS gateway).
@@ -220,9 +299,13 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler {
         if (bh != null && oid != null) {
             bh.unregisterDevice(oid);
         }
-        ScheduledFuture<?> sc = refreshTimeout;
-        if (sc != null) {
-            sc.cancel(true);
+        ScheduledFuture<?> rcst = requestChannelStateTimeout;
+        if (rcst != null) {
+            rcst.cancel(true);
+        }
+        ScheduledFuture<?> rt = refreshTimeout;
+        if (rt != null) {
+            rt.cancel(true);
         }
         super.dispose();
     }
index bf3bac400e37d616aaf79efacc2df91d353707d6..dd528e28700bf221ee9b4442fbf0ee39adda1158 100644 (file)
@@ -14,5 +14,6 @@ offline.conf-error-auth = Authentication failed. Check gateway password in confi
 offline.comm-error-disconnected = Disconnected from gateway.
 offline.comm-error-timeout = Connection to gateway timed out.
 offline.comm-error-connection = Could not connect to gateway.
+offline.comm-error-state = Could not get channel state. 
 
 unknown.waiting-state = Waiting state update...