From 7626a88cabbc5337106cc0a8373be57d6fdfc711 Mon Sep 17 00:00:00 2001 From: Jacob Laursen Date: Mon, 24 Jan 2022 23:40:55 +0100 Subject: [PATCH 1/2] Optimize initialization of shades. Fixes #12071 Signed-off-by: Jacob Laursen --- .../handler/HDPowerViewHubHandler.java | 69 +++++++++++++++---- .../handler/HDPowerViewShadeHandler.java | 7 +- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java index ebe36df33a162..4874d946dcf7a 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -57,6 +58,7 @@ import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.ThingUID; import org.openhab.core.thing.binding.BaseBridgeHandler; import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.builder.ChannelBuilder; @@ -77,8 +79,6 @@ @NonNullByDefault public class HDPowerViewHubHandler extends BaseBridgeHandler { - private static final long INITIAL_SOFT_POLL_DELAY_MS = 5_000; - private final Logger logger = LoggerFactory.getLogger(HDPowerViewHubHandler.class); private final HttpClient httpClient; private final HDPowerViewTranslationProvider translationProvider; @@ -92,6 +92,7 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler { private @Nullable ScheduledFuture hardRefreshPositionFuture; private @Nullable ScheduledFuture hardRefreshBatteryLevelFuture; + private ConcurrentHashMap pendingShadeInitializations = new ConcurrentHashMap<>(); private List sceneCache = new CopyOnWriteArrayList<>(); private List sceneCollectionCache = new CopyOnWriteArrayList<>(); private List scheduledEventCache = new CopyOnWriteArrayList<>(); @@ -135,11 +136,11 @@ public void handleCommand(ChannelUID channelUID, Command command) { if (sceneChannelTypeUID.equals(channel.getChannelTypeUID()) && OnOffType.ON == command) { webTargets.activateScene(id); // Reschedule soft poll for immediate shade position update. - scheduleSoftPoll(0); + scheduleSoftPoll(); } else if (sceneGroupChannelTypeUID.equals(channel.getChannelTypeUID()) && OnOffType.ON == command) { webTargets.activateSceneCollection(id); // Reschedule soft poll for immediate shade position update. - scheduleSoftPoll(0); + scheduleSoftPoll(); } else if (automationChannelTypeUID.equals(channel.getChannelTypeUID())) { webTargets.enableScheduledEvent(id, OnOffType.ON == command); } @@ -162,6 +163,7 @@ public void initialize() { return; } + pendingShadeInitializations = new ConcurrentHashMap<>(); webTargets = new HDPowerViewWebTargets(httpClient, host); refreshInterval = config.refresh; hardRefreshPositionInterval = config.hardRefresh; @@ -193,21 +195,42 @@ public void handleRemoval() { public void dispose() { super.dispose(); stopPoll(); + pendingShadeInitializations.clear(); + } + + @Override + public void childHandlerInitialized(final ThingHandler childHandler, final Thing childThing) { + logger.debug("Child handler initialized: {}", childThing.getUID()); + if (childHandler instanceof HDPowerViewShadeHandler) { + ShadeData shadeData = pendingShadeInitializations.remove(childThing.getUID()); + if (shadeData != null) { + updateShadeThing(shadeData.id, childThing, shadeData); + } + } + super.childHandlerInitialized(childHandler, childThing); + } + + @Override + public void childHandlerDisposed(ThingHandler childHandler, Thing childThing) { + logger.debug("Child handler disposed: {}", childThing.getUID()); + if (childHandler instanceof HDPowerViewShadeHandler) { + pendingShadeInitializations.remove(childThing.getUID()); + } + super.childHandlerDisposed(childHandler, childThing); } private void schedulePoll() { - scheduleSoftPoll(INITIAL_SOFT_POLL_DELAY_MS); + scheduleSoftPoll(); scheduleHardPoll(); } - private void scheduleSoftPoll(long initialDelay) { + private void scheduleSoftPoll() { ScheduledFuture future = this.pollFuture; if (future != null) { future.cancel(false); } - logger.debug("Scheduling poll for {} ms out, then every {} ms", initialDelay, refreshInterval); - this.pollFuture = scheduler.scheduleWithFixedDelay(this::poll, initialDelay, refreshInterval, - TimeUnit.MILLISECONDS); + logger.debug("Scheduling poll every {} ms", refreshInterval); + this.pollFuture = scheduler.scheduleWithFixedDelay(this::poll, 0, refreshInterval, TimeUnit.MILLISECONDS); } private void scheduleHardPoll() { @@ -336,17 +359,35 @@ private void pollShades() throws HubInvalidResponseException, HubProcessingExcep } private void updateShadeThing(int shadeId, Thing thing, @Nullable ShadeData shadeData) { + if (shadeData == null) { + logger.debug("Shade '{}' has no data in hub", shadeId); + return; + } HDPowerViewShadeHandler thingHandler = ((HDPowerViewShadeHandler) thing.getHandler()); if (thingHandler == null) { logger.debug("Shade '{}' handler not initialized", shadeId); + pendingShadeInitializations.put(thing.getUID(), shadeData); return; } - if (shadeData == null) { - logger.debug("Shade '{}' has no data in hub", shadeId); - } else { - logger.debug("Updating shade '{}'", shadeId); + ThingStatus thingStatus = thingHandler.getThing().getStatus(); + switch (thingStatus) { + case UNKNOWN: + case ONLINE: + case OFFLINE: + logger.debug("Updating shade '{}'", shadeId); + thingHandler.onReceiveUpdate(shadeData); + break; + case UNINITIALIZED: + case INITIALIZING: + logger.debug("Shade '{}' handler not yet ready; status: {}", shadeId, thingStatus); + pendingShadeInitializations.put(thing.getUID(), shadeData); + break; + case REMOVING: + case REMOVED: + default: + logger.debug("Ignoring shade update for shade '{}' in status {}", shadeId, thingStatus); + break; } - thingHandler.onReceiveUpdate(shadeData); } private List fetchScenes() diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java index b8bc477732243..701cf480547d9 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java @@ -107,12 +107,7 @@ public void initialize() { "@text/offline.conf-error.invalid-bridge-handler"); return; } - ThingStatus bridgeStatus = bridge.getStatus(); - if (bridgeStatus == ThingStatus.ONLINE) { - updateStatus(ThingStatus.UNKNOWN); - } else { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); - } + updateStatus(ThingStatus.UNKNOWN); } @Override From d0b53e82cf3e4a1487ac8bcfa07fe3ab144eab4f Mon Sep 17 00:00:00 2001 From: Jacob Laursen Date: Tue, 25 Jan 2022 18:48:53 +0100 Subject: [PATCH 2/2] Avoid hashmap reallocation during initialization. Signed-off-by: Jacob Laursen --- .../hdpowerview/internal/handler/HDPowerViewHubHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java index 4874d946dcf7a..3f6d1747515c3 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java @@ -82,6 +82,7 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler { private final Logger logger = LoggerFactory.getLogger(HDPowerViewHubHandler.class); private final HttpClient httpClient; private final HDPowerViewTranslationProvider translationProvider; + private final ConcurrentHashMap pendingShadeInitializations = new ConcurrentHashMap<>(); private long refreshInterval; private long hardRefreshPositionInterval; @@ -92,7 +93,6 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler { private @Nullable ScheduledFuture hardRefreshPositionFuture; private @Nullable ScheduledFuture hardRefreshBatteryLevelFuture; - private ConcurrentHashMap pendingShadeInitializations = new ConcurrentHashMap<>(); private List sceneCache = new CopyOnWriteArrayList<>(); private List sceneCollectionCache = new CopyOnWriteArrayList<>(); private List scheduledEventCache = new CopyOnWriteArrayList<>(); @@ -163,7 +163,7 @@ public void initialize() { return; } - pendingShadeInitializations = new ConcurrentHashMap<>(); + pendingShadeInitializations.clear(); webTargets = new HDPowerViewWebTargets(httpClient, host); refreshInterval = config.refresh; hardRefreshPositionInterval = config.hardRefresh;