]> git.basschouten.com Git - openhab-addons.git/commitdiff
[hue] Support dynamic add/delete of scenes (#17302)
authorAndrew Fiddian-Green <software@whitebear.ch>
Sat, 24 Aug 2024 10:34:56 +0000 (11:34 +0100)
committerGitHub <noreply@github.com>
Sat, 24 Aug 2024 10:34:56 +0000 (12:34 +0200)
Signed-off-by: AndrewFG <software@whitebear.ch>
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/Clip2ThingHandler.java

index 7944e5085f2abab1f315a154806606cf9a9194cd..e4dcc2c5e35f08279450a6c166cfafe70e84f309 100644 (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());