Skip to content

Commit

Permalink
[hue] Support dynamic add/delete of scenes (openhab#17302)
Browse files Browse the repository at this point in the history
Signed-off-by: AndrewFG <[email protected]>
  • Loading branch information
andrewfg authored Aug 24, 2024
1 parent 247d2d3 commit ecdb30e
Showing 1 changed file with 59 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.openhab.binding.hue.internal.api.dto.clip2.Resources;
import org.openhab.binding.hue.internal.api.dto.clip2.TimedEffects;
import org.openhab.binding.hue.internal.api.dto.clip2.enums.ActionType;
import org.openhab.binding.hue.internal.api.dto.clip2.enums.ContentType;
import org.openhab.binding.hue.internal.api.dto.clip2.enums.EffectType;
import org.openhab.binding.hue.internal.api.dto.clip2.enums.ResourceType;
import org.openhab.binding.hue.internal.api.dto.clip2.enums.SceneRecallAction;
Expand Down Expand Up @@ -114,6 +115,14 @@ public class Clip2ThingHandler extends BaseThingHandler {

private final Logger logger = LoggerFactory.getLogger(Clip2ThingHandler.class);

// flag values for logging resource consumption
private static final int FLAG_PROPERTIES_UPDATE = 1;
private static final int FLAG_DEPENDENCIES_UPDATE = 2;
private static final int FLAG_CACHE_UPDATE = 4;
private static final int FLAG_CHANNELS_UPDATE = 8;
private static final int FLAG_SCENE_ADD = 16;
private static final int FLAG_SCENE_DELETE = 32;

/**
* A map of service Resources whose state contributes to the overall state of this thing. It is a map between the
* resource ID (string) and a Resource object containing the last known state. e.g. a DEVICE thing may support a
Expand Down Expand Up @@ -667,36 +676,71 @@ private void onResource(Resource resource, boolean updateChannels) {
if (disposing) {
return;
}
boolean resourceConsumed = false;
int resourceConsumedFlags = 0;
if (resourceId.equals(resource.getId())) {
if (resource.hasFullState()) {
thisResource = resource;
if (!updatePropertiesDone) {
updateProperties(resource);
resourceConsumed = updatePropertiesDone;
resourceConsumedFlags = updatePropertiesDone ? FLAG_PROPERTIES_UPDATE : 0;
}
}
if (!updateDependenciesDone) {
resourceConsumed = true;
resourceConsumedFlags |= FLAG_DEPENDENCIES_UPDATE;
cancelTask(updateDependenciesTask, false);
updateDependenciesTask = scheduler.submit(() -> updateDependencies());
}
} else {
if (SUPPORTED_SCENE_TYPES.contains(resource.getType())) {
resourceConsumedFlags = checkSceneResourceAddDelete(resource);
}
Resource cachedResource = getResourceFromCache(resource);
if (cachedResource != null) {
Setters.setResource(resource, cachedResource);
resourceConsumed = updateChannels && updateChannels(resource);
resourceConsumedFlags |= FLAG_CACHE_UPDATE;
resourceConsumedFlags |= updateChannels && updateChannels(resource) ? FLAG_CHANNELS_UPDATE : 0;
putResourceToCache(resource);
if (ResourceType.LIGHT == resource.getType() && !updateLightPropertiesDone) {
updateLightProperties(resource);
}
}
}
if (resourceConsumed) {
logger.debug("{} -> onResource() consumed resource {}", resourceId, resource);
if (resourceConsumedFlags != 0) {
logger.debug("{} -> onResource() consumed resource {}, flags:{}", resourceId, resource,
resourceConsumedFlags);
}
}

/**
* Check if a scene resource is of type 'ADD or 'DELETE' and either add it to, or delete it from, the two scene
* resource caches; and refresh the scene channel state description selection options.
*
* @param sceneResource the respective scene resource
* @return a flag value indicating if the scene was added or deleted
*/
private int checkSceneResourceAddDelete(Resource sceneResource) {
switch (sceneResource.getContentType()) {
case ADD:
if (getResourceReference().equals(sceneResource.getGroup())) {
sceneResource.setContentType(ContentType.FULL_STATE);
sceneContributorsCache.put(sceneResource.getId(), sceneResource);
sceneResourceEntries.put(sceneResource.getName(), sceneResource);
updateSceneChannelStateDescription();
return FLAG_SCENE_ADD;
}
break;
case DELETE:
Resource deletedScene = sceneContributorsCache.remove(sceneResource.getId());
if (Objects.nonNull(deletedScene)) {
sceneResourceEntries.remove(deletedScene.getName());
updateSceneChannelStateDescription();
return FLAG_SCENE_DELETE;
}
default:
}
return 0;
}

private void putResourceToCache(Resource resource) {
if (SUPPORTED_SCENE_TYPES.contains(resource.getType())) {
sceneContributorsCache.put(resource.getId(), resource);
Expand Down Expand Up @@ -1197,6 +1241,14 @@ private void updateResource(ResourceReference reference)
}
}

/**
* Update the scene channel state description selection options
*/
private void updateSceneChannelStateDescription() {
stateDescriptionProvider.setStateOptions(new ChannelUID(thing.getUID(), CHANNEL_2_SCENE),
sceneResourceEntries.keySet().stream().map(n -> new StateOption(n, n)).collect(Collectors.toList()));
}

/**
* Fetch the full list of normal resp. smart scenes from the bridge, and call
* {@code updateSceneContributors(List<Resource> allScenes)}
Expand Down Expand Up @@ -1249,9 +1301,7 @@ public synchronized boolean updateSceneContributors(List<Resource> allScenes) {
}

updateState(CHANNEL_2_SCENE, state, true);

stateDescriptionProvider.setStateOptions(new ChannelUID(thing.getUID(), CHANNEL_2_SCENE), scenes
.stream().map(s -> s.getName()).map(n -> new StateOption(n, n)).collect(Collectors.toList()));
updateSceneChannelStateDescription();

logger.debug("{} -> updateSceneContributors() found {} normal resp. smart scenes", resourceId,
scenes.size());
Expand Down

0 comments on commit ecdb30e

Please sign in to comment.