]> git.basschouten.com Git - openhab-addons.git/commitdiff
[openwebnet] Added refresh of devices after reboot or disconnect (#10508)
authorM Valla <12682715+mvalla@users.noreply.github.com>
Sat, 24 Apr 2021 10:26:58 +0000 (12:26 +0200)
committerGitHub <noreply@github.com>
Sat, 24 Apr 2021 10:26:58 +0000 (12:26 +0200)
* Refresh devices after reboot or disconnect

Signed-off-by: Massimo Valla <mvcode00@gmail.com>
* Cancel refreshSchdule in dispose. updateStatus messages @text cleanup.

Signed-off-by: Massimo Valla <mvcode00@gmail.com>
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/OpenWebNetEnergyHandler.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetGenericHandler.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetLightingHandler.java
bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetThingHandler.java
bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet.properties
bundles/org.openhab.binding.openwebnet/src/test/java/org/openhab/binding/openwebnet/handler/OwnIdTest.java

index 48d25715fb85d0c194a53f4e4c9b70eb2b735acd..e4eb81d6e24c4086dbac2b2f2b6202267352e4b8 100644 (file)
@@ -59,6 +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 = 2000; // interval in msec before sending another all
+                                                                         // devices refresh request
+
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.AUTOMATION_SUPPORTED_THING_TYPES;
 
     // moving states
@@ -145,6 +149,30 @@ public class OpenWebNetAutomationHandler extends OpenWebNetThingHandler {
             } catch (OWNException e) {
                 logger.debug("Exception while requesting channel {} state: {}", channel, e.getMessage(), e);
             }
+        } else {
+            logger.warn("Could not requestChannelState(): deviceWhere is null");
+        }
+    }
+
+    @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
+            }
         }
     }
 
index 46366d60073a04f7e1e8b363fdce29f84f894d22..5b0dfb104c635f3ee40a680caaa0753d1e623af3 100644 (file)
  */
 package org.openhab.binding.openwebnet.handler;
 
-import static org.openhab.binding.openwebnet.OpenWebNetBindingConstants.PROPERTY_FIRMWARE_VERSION;
-import static org.openhab.binding.openwebnet.OpenWebNetBindingConstants.PROPERTY_SERIAL_NO;
-import static org.openhab.binding.openwebnet.OpenWebNetBindingConstants.THING_TYPE_ZB_GATEWAY;
+import static org.openhab.binding.openwebnet.OpenWebNetBindingConstants.*;
 
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -32,12 +31,14 @@ import org.openhab.binding.openwebnet.internal.discovery.OpenWebNetDeviceDiscove
 import org.openhab.core.config.core.status.ConfigStatusMessage;
 import org.openhab.core.thing.Bridge;
 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.ConfigStatusBridgeHandler;
 import org.openhab.core.thing.binding.ThingHandlerService;
 import org.openhab.core.types.Command;
+import org.openhab.core.types.RefreshType;
 import org.openwebnet4j.BUSGateway;
 import org.openwebnet4j.GatewayListener;
 import org.openwebnet4j.OpenDeviceType;
@@ -72,6 +73,9 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
 
     private static final int GATEWAY_ONLINE_TIMEOUT_SEC = 20; // Time to wait for the gateway to become connected
 
+    private static final int REFRESH_ALL_DEVICES_DELAY_MSEC = 500; // Delay to wait before sending all devices refresh
+                                                                   // request after a connect/reconnect
+
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.BRIDGE_SUPPORTED_THING_TYPES;
 
     // ConcurrentHashMap of devices registered to this BridgeHandler
@@ -86,6 +90,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 boolean scanIsActive = false; // a device scan has been activated by OpenWebNetDeviceDiscoveryService;
     private boolean discoveryByActivation;
 
@@ -123,7 +129,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
                         if (thing.getStatus().equals(ThingStatus.UNKNOWN)) {
                             logger.info("status still UNKNOWN. Setting device={} to OFFLINE", thing.getUID());
                             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
-                                    "Could not connect to gateway before " + GATEWAY_ONLINE_TIMEOUT_SEC + "s");
+                                    "@text/offline.comm-error-timeout");
                         }
                     }, GATEWAY_ONLINE_TIMEOUT_SEC, TimeUnit.SECONDS);
                     logger.debug("bridge {} initialization completed", thing.getUID());
@@ -184,11 +190,15 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
     public void handleCommand(ChannelUID channelUID, Command command) {
         logger.debug("handleCommand (command={} - channel={})", command, channelUID);
         OpenGateway gw = gateway;
-        if (gw != null && !gw.isConnected()) {
+        if (gw == null || !gw.isConnected()) {
             logger.warn("Gateway is NOT connected, skipping command");
             return;
         } else {
-            logger.warn("Channel not supported: channel={}", channelUID);
+            if (command instanceof RefreshType) {
+                refreshAllDevices();
+            } else {
+                logger.warn("Command or channel not supported: channel={} command={}", channelUID, command);
+            }
         }
     }
 
@@ -205,6 +215,10 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
 
     @Override
     public void dispose() {
+        ScheduledFuture<?> rSc = refreshSchedule;
+        if (rSc != null) {
+            rSc.cancel(true);
+        }
         disconnectGateway();
         super.dispose();
     }
@@ -376,6 +390,16 @@ 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);
+            }
+        }
+    }
+
     @Override
     public void onEventMessage(@Nullable OpenMessage msg) {
         logger.trace("RECEIVED <<<<< {}", msg);
@@ -448,6 +472,9 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
             logger.info("properties updated for bridge '{}'", thing.getUID());
         }
         updateStatus(ThingStatus.ONLINE);
+        // schedule a refresh for all devices
+        refreshSchedule = scheduler.schedule(this::refreshAllDevices, REFRESH_ALL_DEVICES_DELAY_MSEC,
+                TimeUnit.MILLISECONDS);
     }
 
     @Override
@@ -460,7 +487,8 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
         }
         logger.info("---- ON CONNECTION ERROR for gateway {}: {}", gateway, errMsg);
         isGatewayConnected = false;
-        updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, errMsg);
+        updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
+                "@text/offline.comm-error-connection" + " (onConnectionError - " + errMsg + ")");
         tryReconnectGateway();
     }
 
@@ -482,7 +510,7 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
         }
         logger.info("---- DISCONNECTED from gateway {}. OWNException: {}", gateway, errMsg);
         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
-                "Disconnected from gateway (onDisconnected - " + errMsg + ")");
+                "@text/offline.comm-error-disconnected" + " (onDisconnected - " + errMsg + ")");
         tryReconnectGateway();
     }
 
@@ -498,11 +526,10 @@ public class OpenWebNetBridgeHandler extends ConfigStatusBridgeHandler implement
                     logger.info("---- AUTH error from gateway. Stopping re-connect");
                     reconnecting = false;
                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
-                            "Authentication error. Check gateway password in Thing Configuration Parameters (" + e
-                                    + ")");
+                            "@text/offline.conf-error-auth" + " (" + e + ")");
                 }
             } else {
-                logger.debug("---- reconnecting=true, do nothing");
+                logger.debug("---- reconnecting=true");
             }
         } else {
             logger.warn("---- cannot start RECONNECT, gateway is null");
@@ -520,6 +547,10 @@ 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,
+                    TimeUnit.MILLISECONDS);
         }
     }
 
index f73a98b20b7bda5d51bc3edb5944a6069c7f36b1..b847d5eeda023bbaca3e5c402008d6de62016fb6 100644 (file)
@@ -49,7 +49,7 @@ public class OpenWebNetEnergyHandler extends OpenWebNetThingHandler {
 
     private final Logger logger = LoggerFactory.getLogger(OpenWebNetEnergyHandler.class);
 
-    public final static Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.ENERGY_MANAGEMENT_SUPPORTED_THING_TYPES;
+    public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.ENERGY_MANAGEMENT_SUPPORTED_THING_TYPES;
 
     public OpenWebNetEnergyHandler(Thing thing) {
         super(thing);
@@ -63,14 +63,23 @@ public class OpenWebNetEnergyHandler extends OpenWebNetThingHandler {
     @Override
     protected void requestChannelState(ChannelUID channel) {
         logger.debug("requestChannelState() thingUID={} channel={}", thing.getUID(), channel.getId());
-        try {
-            bridgeHandler.gateway.send(EnergyManagement.requestActivePower(deviceWhere.value()));
-        } catch (OWNException e) {
-            logger.warn("requestChannelState() OWNException thingUID={} channel={}: {}", thing.getUID(),
-                    channel.getId(), e.getMessage());
+        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);
+            }
+        } else {
+            logger.warn("Could not requestChannelState(): deviceWhere is null");
         }
     }
 
+    @Override
+    protected void refreshDevice(boolean refreshAll) {
+        requestChannelState(new ChannelUID("any:any:any:any"));
+    }
+
     @Override
     protected void handleChannelCommand(ChannelUID channel, Command command) {
         logger.warn("handleChannelCommand() Read only channel, unsupported command {}", command);
index d0ced83efea8b381a5a38ec1296cecce538069fa..374dd20d7c0ab66c1f8173577102b930f1def15e 100644 (file)
@@ -53,13 +53,19 @@ public class OpenWebNetGenericHandler extends OpenWebNetThingHandler {
     @Override
     protected void requestChannelState(ChannelUID channel) {
         // do nothing
-        logger.warn("There are no channels");
+        logger.warn("Generic: there are no channels");
+    }
+
+    @Override
+    protected void refreshDevice(boolean refreshAll) {
+        // do nothing
+        logger.warn("Generic: nothing to refresh");
     }
 
     @Override
     protected void handleChannelCommand(ChannelUID channel, Command command) {
         // do nothing
-        logger.warn("There are no channels");
+        logger.warn("Generic: there are no channels");
     }
 
     @Override
@@ -76,6 +82,6 @@ public class OpenWebNetGenericHandler extends OpenWebNetThingHandler {
     protected void handleMessage(BaseOpenMessage msg) {
         super.handleMessage(msg);
         // do nothing
-        logger.warn("handleMessage(): Nothing to do!");
+        logger.warn("Generic: handleMessage() nothing to do!");
     }
 }
index f6eda3fc086b02901c23a853aa41103f649d1a6c..b45695e654ed32556abbf271b5aa19a901dab872 100644 (file)
@@ -63,6 +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 = 2000; // 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
@@ -91,7 +97,7 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
                 lastStatusRequestSentTS = System.currentTimeMillis();
                 Response res = send(Lighting.requestStatus(toWhere(channelId)));
                 if (res != null && res.isSuccess()) {
-                    // set thing online if not already
+                    // set thing online, if not already
                     ThingStatus ts = getThing().getStatus();
                     if (ThingStatus.ONLINE != ts && ThingStatus.REMOVING != ts && ThingStatus.REMOVED != ts) {
                         updateStatus(ThingStatus.ONLINE);
@@ -100,6 +106,37 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
             } catch (OWNException e) {
                 logger.warn("requestStatus() Exception while requesting light state: {}", e.getMessage());
             }
+        } else {
+            logger.warn("Could not requestStatus(): deviceWhere is null");
+        }
+    }
+
+    @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()}
+            }
         }
     }
 
@@ -372,7 +409,7 @@ public class OpenWebNetLightingHandler extends OpenWebNetThingHandler {
      * @param channelId the channelId string
      **/
     @Nullable
-    protected String toWhere(String channelId) {
+    private String toWhere(String channelId) {
         Where w = deviceWhere;
         if (w != null) {
             OpenWebNetBridgeHandler brH = bridgeHandler;
index 0d646df7ff6eb4e3f31b9576fd92a070f983c710..03d94a71db48e76b7ae7f4f6c0aa72d88c9c8689 100644 (file)
@@ -67,22 +67,22 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler {
             OpenWebNetBridgeHandler brH = (OpenWebNetBridgeHandler) bridge.getHandler();
             if (brH != null) {
                 bridgeHandler = brH;
-                Object deviceWhereConfig = getConfig().get(CONFIG_PROPERTY_WHERE);
-                if (!(deviceWhereConfig instanceof String)) {
+
+                final String configDeviceWhere = (String) getConfig().get(CONFIG_PROPERTY_WHERE);
+                if (configDeviceWhere == null) {
                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
-                            "WHERE parameter in configuration is null or invalid");
+                            "@text/offline.conf-error-where");
                 } else {
-                    String deviceWhereStr = (String) getConfig().get(CONFIG_PROPERTY_WHERE);
                     Where w;
                     try {
                         if (brH.isBusGateway()) {
-                            w = buildBusWhere(deviceWhereStr);
+                            w = buildBusWhere(configDeviceWhere);
                         } else {
-                            w = new WhereZigBee(deviceWhereStr);
+                            w = new WhereZigBee(configDeviceWhere);
                         }
                     } catch (IllegalArgumentException ia) {
                         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
-                                "WHERE parameter in configuration is invalid");
+                                "@text/offline.conf-error-where");
                         return;
                     }
                     deviceWhere = w;
@@ -93,12 +93,12 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler {
                     updateProperties(properties);
                     brH.registerDevice(oid, this);
                     logger.debug("associated thing to bridge with ownId={}", ownId);
-                    updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "waiting state update...");
+                    updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "@text/unknown.waiting-state");
                 }
             }
         } else {
             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
-                    "No bridge associated, please assign a bridge in thing configuration.");
+                    "@text/offline.conf-error-no-bridge");
         }
     }
 
@@ -157,16 +157,17 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler {
     }
 
     /**
-     * Helper method to send OWN messages from ThingsHandlers
+     * Helper method to send OWN messages from ThingHandlers
      */
     protected @Nullable Response send(OpenMessage msg) throws OWNException {
-        OpenWebNetBridgeHandler handler = bridgeHandler;
-        if (handler != null) {
-            OpenGateway gw = handler.gateway;
+        OpenWebNetBridgeHandler bh = bridgeHandler;
+        if (bh != null) {
+            OpenGateway gw = bh.gateway;
             if (gw != null) {
                 return gw.send(msg);
             }
         }
+        logger.warn("Couldn't send message {}: handler or gateway is null", msg);
         return null;
     }
 
@@ -185,12 +186,19 @@ public abstract class OpenWebNetThingHandler extends BaseThingHandler {
     }
 
     /**
-     * Request to gateway state for thing channel. It must be implemented by each specific device handler.
+     * Request the state for the specified channel
      *
-     * @param channel the channel to request the state for
+     * @param channel the {@link ChannelUID} to request the state for
      */
     protected abstract void requestChannelState(ChannelUID channel);
 
+    /**
+     * Refresh the device
+     *
+     * @param refreshAll set true if all devices of the binding should be refreshed with one command, if possible
+     */
+    protected abstract void refreshDevice(boolean refreshAll);
+
     /**
      * 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).
index d7db24c8efabbcd338ac302091295ca1d10fce80..be9950b25e8f591bf37550190cdff185dc3afdb8 100644 (file)
@@ -1,4 +1,12 @@
 # Thing status descriptions
 offline.conf-error-no-ip-address = Cannot connect to gateway. No host/IP has been provided in Bridge configuration.
 offline.conf-error-no-serial-port = Cannot connect to gateway. No serial port has been provided in Bridge configuration.
-offline.wrong-configuration = Invalid configuration. Check Thing configuration parameters.
+offline.conf-error-where = WHERE parameter in Thing configuration is null or invalid
+offline.conf-error-no-bridge = No bridge associated, please assign a bridge in Thing configuration.
+offline.conf-error-auth = Authentication error. Check gateway password in Thing Configuration Parameters
+
+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 
+
+unknown.waiting-state = Waiting state update...
index f1adad386b8d940542d0e47e3ee4b7d742b92b5d..992e6f10c2c9476d83e82c1e662d9ec6cdf8c00b 100644 (file)
@@ -93,7 +93,8 @@ public class OwnIdTest {
             try {
                 bmsg = (BaseOpenMessage) BaseOpenMessage.parse(msg);
             } catch (FrameException e) {
-                logger.warn("something is wrong in the test table. ownIdFromMessage test will be skipped");
+                logger.warn("something is wrong in the test table ({}). ownIdFromMessage test will be skipped",
+                        e.getMessage());
             }
             this.msg = bmsg;
             this.norm = norm;