diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetAutomationHandler.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetAutomationHandler.java index 48d25715fb8..e4eb81d6e24 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetAutomationHandler.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetAutomationHandler.java @@ -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 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 + } } } diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetBridgeHandler.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetBridgeHandler.java index 46366d60073..5b0dfb104c6 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetBridgeHandler.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetBridgeHandler.java @@ -12,15 +12,14 @@ */ 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 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); } } diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetEnergyHandler.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetEnergyHandler.java index f73a98b20b7..b847d5eeda0 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetEnergyHandler.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetEnergyHandler.java @@ -49,7 +49,7 @@ public class OpenWebNetEnergyHandler extends OpenWebNetThingHandler { private final Logger logger = LoggerFactory.getLogger(OpenWebNetEnergyHandler.class); - public final static Set SUPPORTED_THING_TYPES = OpenWebNetBindingConstants.ENERGY_MANAGEMENT_SUPPORTED_THING_TYPES; + public static final Set 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); diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetGenericHandler.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetGenericHandler.java index d0ced83efea..374dd20d7c0 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetGenericHandler.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetGenericHandler.java @@ -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!"); } } diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetLightingHandler.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetLightingHandler.java index f6eda3fc086..b45695e654e 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetLightingHandler.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetLightingHandler.java @@ -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; diff --git a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetThingHandler.java b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetThingHandler.java index 0d646df7ff6..03d94a71db4 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetThingHandler.java +++ b/bundles/org.openhab.binding.openwebnet/src/main/java/org/openhab/binding/openwebnet/handler/OpenWebNetThingHandler.java @@ -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). diff --git a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet.properties b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet.properties index d7db24c8efa..be9950b25e8 100644 --- a/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet.properties +++ b/bundles/org.openhab.binding.openwebnet/src/main/resources/OH-INF/i18n/openwebnet.properties @@ -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... 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 index f1adad386b8..992e6f10c2c 100644 --- 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 @@ -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;