[hdpowerview] Optimize initialization of shades (#12113)

* Optimize initialization of shades.

Fixes #12071

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>

* Avoid hashmap reallocation during initialization.

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
This commit is contained in:
Jacob Laursen 2022-01-28 07:47:32 +01:00 committed by GitHub
parent 608d0ae23a
commit dab48ddd95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 20 deletions

View File

@ -17,6 +17,7 @@ import java.util.HashMap;
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.ChannelUID;
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,11 +79,10 @@ import org.slf4j.LoggerFactory;
@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;
private final ConcurrentHashMap<ThingUID, ShadeData> pendingShadeInitializations = new ConcurrentHashMap<>();
private long refreshInterval;
private long hardRefreshPositionInterval;
@ -135,11 +136,11 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
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 class HDPowerViewHubHandler extends BaseBridgeHandler {
return;
}
pendingShadeInitializations.clear();
webTargets = new HDPowerViewWebTargets(httpClient, host);
refreshInterval = config.refresh;
hardRefreshPositionInterval = config.hardRefresh;
@ -193,21 +195,42 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
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 @@ public class HDPowerViewHubHandler extends BaseBridgeHandler {
}
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<Scene> fetchScenes()

View File

@ -107,12 +107,7 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
"@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