[hue] Support dynamic add/delete of scenes (#17302)

Signed-off-by: AndrewFG <software@whitebear.ch>
This commit is contained in:
Andrew Fiddian-Green 2024-08-24 11:34:56 +01:00 committed by GitHub
parent 247d2d3216
commit ecdb30ec50
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -50,6 +50,7 @@ import org.openhab.binding.hue.internal.api.dto.clip2.ResourceReference;
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;
@ -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
@ -667,36 +676,71 @@ public class Clip2ThingHandler extends BaseThingHandler {
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);
@ -1197,6 +1241,14 @@ public class Clip2ThingHandler extends BaseThingHandler {
}
}
/**
* 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)}
@ -1249,9 +1301,7 @@ public class Clip2ThingHandler extends BaseThingHandler {
}
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());