diff --git a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseBindingConstants.java b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseBindingConstants.java index 274e527861f61..278c17bf046d3 100644 --- a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseBindingConstants.java +++ b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseBindingConstants.java @@ -12,11 +12,7 @@ */ package org.openhab.binding.plugwise.internal; -import static java.util.stream.Collectors.*; - -import java.util.Collections; import java.util.Set; -import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.thing.ThingTypeUID; @@ -65,8 +61,6 @@ public class PlugwiseBindingConstants { public static final ThingTypeUID THING_TYPE_STICK = new ThingTypeUID(BINDING_ID, "stick"); public static final ThingTypeUID THING_TYPE_SWITCH = new ThingTypeUID(BINDING_ID, "switch"); - public static final Set SUPPORTED_THING_TYPES_UIDS = Stream - .of(THING_TYPE_CIRCLE, THING_TYPE_CIRCLE_PLUS, THING_TYPE_SCAN, THING_TYPE_SENSE, THING_TYPE_STEALTH, - THING_TYPE_STICK, THING_TYPE_SWITCH) - .collect(collectingAndThen(toSet(), Collections::unmodifiableSet)); + public static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_CIRCLE, THING_TYPE_CIRCLE_PLUS, + THING_TYPE_SCAN, THING_TYPE_SENSE, THING_TYPE_STEALTH, THING_TYPE_STICK, THING_TYPE_SWITCH); } diff --git a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseHandlerFactory.java b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseHandlerFactory.java index bd4670565fd97..8b52be589d3df 100644 --- a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseHandlerFactory.java +++ b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseHandlerFactory.java @@ -14,10 +14,6 @@ import static org.openhab.binding.plugwise.internal.PlugwiseBindingConstants.*; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Map; - import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.plugwise.internal.handler.PlugwiseRelayDeviceHandler; @@ -25,16 +21,13 @@ import org.openhab.binding.plugwise.internal.handler.PlugwiseSenseHandler; import org.openhab.binding.plugwise.internal.handler.PlugwiseStickHandler; import org.openhab.binding.plugwise.internal.handler.PlugwiseSwitchHandler; -import org.openhab.core.config.discovery.DiscoveryService; import org.openhab.core.io.transport.serial.SerialPortManager; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; -import org.openhab.core.thing.ThingUID; import org.openhab.core.thing.binding.BaseThingHandlerFactory; import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandlerFactory; -import org.osgi.framework.ServiceRegistration; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @@ -48,8 +41,6 @@ @Component(service = ThingHandlerFactory.class, configurationPid = "binding.plugwise") public class PlugwiseHandlerFactory extends BaseThingHandlerFactory { - private final Map> discoveryServiceRegistrations = new HashMap<>(); - private final SerialPortManager serialPortManager; @Activate @@ -67,9 +58,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (thingTypeUID.equals(THING_TYPE_STICK)) { - PlugwiseStickHandler handler = new PlugwiseStickHandler((Bridge) thing, serialPortManager); - registerDiscoveryService(handler); - return handler; + return new PlugwiseStickHandler((Bridge) thing, serialPortManager); } else if (thingTypeUID.equals(THING_TYPE_CIRCLE) || thingTypeUID.equals(THING_TYPE_CIRCLE_PLUS) || thingTypeUID.equals(THING_TYPE_STEALTH)) { return new PlugwiseRelayDeviceHandler(thing); @@ -83,23 +72,4 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { return null; } - - private void registerDiscoveryService(PlugwiseStickHandler handler) { - PlugwiseThingDiscoveryService discoveryService = new PlugwiseThingDiscoveryService(handler); - discoveryService.activate(); - this.discoveryServiceRegistrations.put(handler.getThing().getUID(), - bundleContext.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>())); - } - - @Override - protected void removeHandler(ThingHandler thingHandler) { - ServiceRegistration registration = this.discoveryServiceRegistrations.get(thingHandler.getThing().getUID()); - if (registration != null) { - PlugwiseThingDiscoveryService discoveryService = (PlugwiseThingDiscoveryService) bundleContext - .getService(registration.getReference()); - discoveryService.deactivate(); - registration.unregister(); - discoveryServiceRegistrations.remove(thingHandler.getThing().getUID()); - } - } } diff --git a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseThingDiscoveryService.java b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseThingDiscoveryService.java index 4bcd9937c8a78..4907150b90877 100644 --- a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseThingDiscoveryService.java +++ b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseThingDiscoveryService.java @@ -15,6 +15,8 @@ import static java.util.stream.Collectors.*; import static org.openhab.binding.plugwise.internal.PlugwiseBindingConstants.*; +import java.time.Duration; +import java.time.Instant; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -44,6 +46,8 @@ import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.ThingHandler; +import org.openhab.core.thing.binding.ThingHandlerService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,13 +60,13 @@ */ @NonNullByDefault public class PlugwiseThingDiscoveryService extends AbstractDiscoveryService - implements PlugwiseMessageListener, PlugwiseStickStatusListener { + implements PlugwiseMessageListener, PlugwiseStickStatusListener, ThingHandlerService { private static class CurrentRoleCall { private boolean isRoleCalling; private int currentNodeID; private int attempts; - private long lastRequestMillis; + private Instant lastRequest = Instant.MIN; } private static class DiscoveredNode { @@ -70,7 +74,7 @@ private static class DiscoveredNode { private final Map properties = new HashMap<>(); private DeviceType deviceType = DeviceType.UNKNOWN; private int attempts; - private long lastRequestMillis; + private Instant lastRequest = Instant.MIN; public DiscoveredNode(MACAddress macAddress) { this.macAddress = macAddress; @@ -87,16 +91,16 @@ public boolean isDataComplete() { private static final int MIN_NODE_ID = 0; private static final int MAX_NODE_ID = 63; - private static final int DISCOVERY_INTERVAL = 180; - private static final int WATCH_INTERVAL = 1; - - private static final int MESSAGE_TIMEOUT = 15; private static final int MESSAGE_RETRY_ATTEMPTS = 5; + private static final Duration DISCOVERY_INTERVAL = Duration.ofMinutes(3); + private static final Duration MESSAGE_TIMEOUT = Duration.ofSeconds(15); + private static final Duration WATCH_INTERVAL = Duration.ofSeconds(1); + private final Logger logger = LoggerFactory.getLogger(PlugwiseThingDiscoveryService.class); - private final PlugwiseStickHandler stickHandler; + private @NonNullByDefault({}) PlugwiseStickHandler stickHandler; private @Nullable ScheduledFuture discoveryJob; private @Nullable ScheduledFuture watchJob; @@ -104,10 +108,8 @@ public boolean isDataComplete() { private final Map discoveredNodes = new ConcurrentHashMap<>(); - public PlugwiseThingDiscoveryService(PlugwiseStickHandler stickHandler) throws IllegalArgumentException { + public PlugwiseThingDiscoveryService() throws IllegalArgumentException { super(DISCOVERED_THING_TYPES_UIDS, 1, true); - this.stickHandler = stickHandler; - this.stickHandler.addStickStatusListener(this); } @Override @@ -118,6 +120,7 @@ public synchronized void abortScan() { stopDiscoveryWatchJob(); } + @Override public void activate() { super.activate(new HashMap<>()); } @@ -138,7 +141,7 @@ private void createDiscoveryResult(DiscoveredNode node) { } @Override - protected void deactivate() { + public void deactivate() { super.deactivate(); stickHandler.removeMessageListener(this); stickHandler.removeStickStatusListener(this); @@ -147,8 +150,10 @@ protected void deactivate() { private void discoverNewNodeDetails(MACAddress macAddress) { if (!isAlreadyDiscovered(macAddress)) { logger.debug("Discovered new node ({})", macAddress); - discoveredNodes.put(macAddress, new DiscoveredNode(macAddress)); + DiscoveredNode node = new DiscoveredNode(macAddress); + discoveredNodes.put(macAddress, node); updateInformation(macAddress); + node.lastRequest = Instant.now(); } else { logger.debug("Already discovered node ({})", macAddress); } @@ -184,6 +189,11 @@ private ThingStatus getStickStatus() { return stickHandler.getThing().getStatus(); } + @Override + public @Nullable ThingHandler getThingHandler() { + return stickHandler; + } + private void handleAnnounceAwakeRequest(AnnounceAwakeRequestMessage message) { discoverNewNodeDetails(message.getMACAddress()); } @@ -267,7 +277,7 @@ private void roleCall(int nodeID) { currentRoleCall.attempts++; } currentRoleCall.currentNodeID = nodeID; - currentRoleCall.lastRequestMillis = System.currentTimeMillis(); + currentRoleCall.lastRequest = Instant.now(); } else { logger.warn("Invalid node ID for role call: {}", nodeID); } @@ -277,6 +287,14 @@ private void sendMessage(Message message) { stickHandler.sendMessage(message, PlugwiseMessagePriority.UPDATE_AND_DISCOVERY); } + @Override + public void setThingHandler(ThingHandler handler) { + if (handler instanceof PlugwiseStickHandler) { + stickHandler = (PlugwiseStickHandler) handler; + stickHandler.addStickStatusListener(this); + } + } + @Override protected void startBackgroundDiscovery() { logger.debug("Starting Plugwise device background discovery"); @@ -288,7 +306,8 @@ protected void startBackgroundDiscovery() { ScheduledFuture localDiscoveryJob = discoveryJob; if (localDiscoveryJob == null || localDiscoveryJob.isCancelled()) { - discoveryJob = scheduler.scheduleWithFixedDelay(discoveryRunnable, 0, DISCOVERY_INTERVAL, TimeUnit.SECONDS); + discoveryJob = scheduler.scheduleWithFixedDelay(discoveryRunnable, 0, DISCOVERY_INTERVAL.toMillis(), + TimeUnit.MILLISECONDS); } } @@ -297,7 +316,8 @@ private void startDiscoveryWatchJob() { Runnable watchRunnable = () -> { if (currentRoleCall.isRoleCalling) { - if ((System.currentTimeMillis() - currentRoleCall.lastRequestMillis) > (MESSAGE_TIMEOUT * 1000) + Duration durationSinceLastRequest = Duration.between(currentRoleCall.lastRequest, Instant.now()); + if (durationSinceLastRequest.compareTo(MESSAGE_TIMEOUT) > 0 && currentRoleCall.attempts < MESSAGE_RETRY_ATTEMPTS) { logger.debug("Resending timed out role call message for node with ID {} on Circle+ ({})", currentRoleCall.currentNodeID, getCirclePlusMAC()); @@ -313,10 +333,11 @@ private void startDiscoveryWatchJob() { while (it.hasNext()) { Entry entry = it.next(); DiscoveredNode node = entry.getValue(); - if (System.currentTimeMillis() - node.lastRequestMillis > (MESSAGE_TIMEOUT * 1000) - && node.attempts < MESSAGE_RETRY_ATTEMPTS) { + Duration durationSinceLastRequest = Duration.between(node.lastRequest, Instant.now()); + if (durationSinceLastRequest.compareTo(MESSAGE_TIMEOUT) > 0 && node.attempts < MESSAGE_RETRY_ATTEMPTS) { logger.debug("Resending timed out information request message to node ({})", node.macAddress); updateInformation(node.macAddress); + node.lastRequest = Instant.now(); node.attempts++; } else if (node.attempts >= MESSAGE_RETRY_ATTEMPTS) { logger.debug("Giving up on information request for node ({})", node.macAddress); @@ -332,8 +353,8 @@ private void startDiscoveryWatchJob() { ScheduledFuture localWatchJob = watchJob; if (localWatchJob == null || localWatchJob.isCancelled()) { - watchJob = scheduler.scheduleWithFixedDelay(watchRunnable, WATCH_INTERVAL, WATCH_INTERVAL, - TimeUnit.SECONDS); + watchJob = scheduler.scheduleWithFixedDelay(watchRunnable, WATCH_INTERVAL.toMillis(), + WATCH_INTERVAL.toMillis(), TimeUnit.MILLISECONDS); } } diff --git a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseUtils.java b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseUtils.java index ea459fc6c7bcf..076a22b1463a5 100644 --- a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseUtils.java +++ b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/PlugwiseUtils.java @@ -43,17 +43,17 @@ private PlugwiseUtils() { } public static DeviceType getDeviceType(ThingTypeUID uid) { - if (uid.equals(THING_TYPE_CIRCLE)) { + if (THING_TYPE_CIRCLE.equals(uid)) { return CIRCLE; - } else if (uid.equals(THING_TYPE_CIRCLE_PLUS)) { + } else if (THING_TYPE_CIRCLE_PLUS.equals(uid)) { return CIRCLE_PLUS; - } else if (uid.equals(THING_TYPE_SCAN)) { + } else if (THING_TYPE_SCAN.equals(uid)) { return SCAN; - } else if (uid.equals(THING_TYPE_SENSE)) { + } else if (THING_TYPE_SENSE.equals(uid)) { return SENSE; - } else if (uid.equals(THING_TYPE_STEALTH)) { + } else if (THING_TYPE_STEALTH.equals(uid)) { return STEALTH; - } else if (uid.equals(THING_TYPE_SWITCH)) { + } else if (THING_TYPE_SWITCH.equals(uid)) { return SWITCH; } else { return UNKNOWN; @@ -106,7 +106,6 @@ public static String upperUnderscoreToLowerCamel(String text) { return upperCamel.substring(0, 1).toLowerCase() + upperCamel.substring(1); } - @SuppressWarnings("null") public static boolean updateProperties(Map properties, InformationResponseMessage message) { boolean update = false; diff --git a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/handler/PlugwiseRelayDeviceHandler.java b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/handler/PlugwiseRelayDeviceHandler.java index 57ff70f0baa40..907e98d058dc5 100644 --- a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/handler/PlugwiseRelayDeviceHandler.java +++ b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/handler/PlugwiseRelayDeviceHandler.java @@ -12,16 +12,13 @@ */ package org.openhab.binding.plugwise.internal.handler; -import static java.util.stream.Collectors.*; import static org.openhab.binding.plugwise.internal.PlugwiseBindingConstants.*; import static org.openhab.core.thing.ThingStatus.*; import java.time.Duration; import java.time.LocalDateTime; -import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -222,10 +219,8 @@ public boolean shouldBeScheduled() { } }; - private final List recurringTasks = Stream - .of(clockUpdateTask, currentPowerUpdateTask, energyUpdateTask, informationUpdateTask, - realTimeClockUpdateTask, setClockTask) - .collect(collectingAndThen(toList(), Collections::unmodifiableList)); + private final List recurringTasks = List.of(clockUpdateTask, currentPowerUpdateTask, + energyUpdateTask, informationUpdateTask, realTimeClockUpdateTask, setClockTask); private final Logger logger = LoggerFactory.getLogger(PlugwiseRelayDeviceHandler.class); private final DeviceType deviceType; diff --git a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/handler/PlugwiseStickHandler.java b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/handler/PlugwiseStickHandler.java index f51766be084e4..9de91cca0a70d 100644 --- a/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/handler/PlugwiseStickHandler.java +++ b/bundles/org.openhab.binding.plugwise/src/main/java/org/openhab/binding/plugwise/internal/handler/PlugwiseStickHandler.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.time.Duration; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; @@ -28,6 +29,7 @@ import org.openhab.binding.plugwise.internal.PlugwiseDeviceTask; import org.openhab.binding.plugwise.internal.PlugwiseInitializationException; import org.openhab.binding.plugwise.internal.PlugwiseMessagePriority; +import org.openhab.binding.plugwise.internal.PlugwiseThingDiscoveryService; import org.openhab.binding.plugwise.internal.PlugwiseUtils; import org.openhab.binding.plugwise.internal.config.PlugwiseStickConfig; import org.openhab.binding.plugwise.internal.listener.PlugwiseMessageListener; @@ -48,6 +50,7 @@ import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.binding.BaseBridgeHandler; +import org.openhab.core.thing.binding.ThingHandlerService; import org.openhab.core.types.Command; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -122,6 +125,11 @@ public void dispose() { return circlePlusMAC; } + @Override + public Collection> getServices() { + return List.of(PlugwiseThingDiscoveryService.class); + } + public @Nullable MACAddress getStickMAC() { return stickMAC; }