]> git.basschouten.com Git - openhab-addons.git/commitdiff
[hdpowerview] Channels are visible depending on shade capabilities (#13275)
authorAndrew Fiddian-Green <software@whitebear.ch>
Tue, 23 Aug 2022 20:03:43 +0000 (21:03 +0100)
committerGitHub <noreply@github.com>
Tue, 23 Aug 2022 20:03:43 +0000 (22:03 +0200)
* [hdpowerview] create channels dynamically
* [hdpowerview] revert from channel creation to channel removal
* [hdpowerview] add category

Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
bundles/org.openhab.binding.hdpowerview/README.md
bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java
bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/thing/channels.xml

index 146813ec5be4fac94cf657f17e5009205229681f..e4ed9a98a8762caf2ec5f65ce3fe4aef67907af5 100644 (file)
@@ -91,9 +91,9 @@ All of these channels appear in the binding, but only those which have a physica
 
 | Channel        | Item Type                | Description |
 |----------------|--------------------------|-------------|
-| position       | Rollershutter            | The vertical position of the shade's rail -- see [next chapter](#Roller-Shutter-Up/Down-Position-vs.-Open/Close-State). Up/Down commands will move the rail completely up or completely down. Percentage commands will move the rail to an intermediate position. Stop commands will halt any current movement of the rail. |
-| secondary      | Rollershutter            | The vertical position of the secondary rail (if any). Its function is similar to the `position` channel above -- but see [next chapter](#Roller-Shutter-Up/Down-Position-vs.-Open/Close-State). |
-| vane           | Dimmer                   | The degree of opening of the slats or vanes. Setting this to a non-zero value will first move the shade `position` fully down, since the slats or vanes can only have a defined state if the shade is in its down position -- see [Interdependency between Channel positions](#Interdependency-between-Channel-positions). |
+| position       | Rollershutter            | The vertical position of the shade's rail (if any). -- See [next chapter](#Roller-Shutter-Up/Down-Position-vs.-Open/Close-State). Up/Down commands will move the rail completely up or completely down. Percentage commands will move the rail to an intermediate position. Stop commands will halt any current movement of the rail. |
+| secondary      | Rollershutter            | The vertical position of the secondary rail (if any). Its function is similar to the `position` channel above. -- But see [next chapter](#Roller-Shutter-Up/Down-Position-vs.-Open/Close-State). |
+| vane           | Dimmer                   | The degree of opening of the slats or vanes (if any). On some shade types, setting this to a non-zero value might first move the shade `position` fully down, since the slats or vanes can only have a defined state if the shade is in its down position. See [Interdependency between Channel positions](#Interdependency-between-Channel-positions). |
 | command        | String                   | Send a command to the shade. Valid values are: `CALIBRATE`, `IDENTIFY` |
 | lowBattery     | Switch                   | Indicates ON when the battery level of the shade is low, as determined by the hub's internal rules. |
 | batteryLevel   | Number                   | Battery level (10% = low, 50% = medium, 100% = high)
@@ -102,7 +102,9 @@ All of these channels appear in the binding, but only those which have a physica
 | hubRssi        | Number:Power             | Received Signal Strength Indicator for Hub |
 | repeaterRssi   | Number:Power             | Received Signal Strength Indicator for Repeater |
 
-Please note that RSSI values will only be updated upon manual request by a `REFRESH` command (e.g. in a rule).
+Notes:
+- The channels `position`, `secondary` and `vane` only exist if the shade physically supports such channels.
+- The RSSI values will only be updated upon manual request by a `REFRESH` command (e.g. in a rule).
 
 ### Channels for Repeaters (Thing type `repeater`)
 
index 391cfaf448f3cd91db3e51a402666be011dd7179..fb0d76e643da5176fb692cd5b1b50b53a7784ea8 100644 (file)
@@ -15,6 +15,7 @@ package org.openhab.binding.hdpowerview.internal.handler;
 import static org.openhab.binding.hdpowerview.internal.HDPowerViewBindingConstants.*;
 import static org.openhab.binding.hdpowerview.internal.api.CoordinateSystem.*;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -50,6 +51,7 @@ import org.openhab.core.library.types.StringType;
 import org.openhab.core.library.types.UpDownType;
 import org.openhab.core.library.unit.Units;
 import org.openhab.core.thing.Bridge;
+import org.openhab.core.thing.Channel;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
 import org.openhab.core.thing.ThingStatus;
@@ -80,10 +82,10 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
 
     private static final String DETECTED_SECONDARY_RAIL = "secondaryRailDetected";
     private static final String DETECTED_TILT_ANYWHERE = "tiltAnywhereDetected";
-    private final Map<String, String> detectedCapabilities = new HashMap<>();
+    private static final ShadeCapabilitiesDatabase DB = new ShadeCapabilitiesDatabase();
 
+    private final Map<String, String> detectedCapabilities = new HashMap<>();
     private final Logger logger = LoggerFactory.getLogger(HDPowerViewShadeHandler.class);
-    private final ShadeCapabilitiesDatabase db = new ShadeCapabilitiesDatabase();
 
     private @Nullable ScheduledFuture<?> refreshPositionFuture = null;
     private @Nullable ScheduledFuture<?> refreshSignalFuture = null;
@@ -107,7 +109,6 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
                     "@text/offline.conf-error.invalid-bridge-handler");
             return;
         }
-
         updateStatus(ThingStatus.UNKNOWN);
     }
 
@@ -265,13 +266,15 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
             // Already cached.
             return;
         }
-        Capabilities capabilities = db.getCapabilities(shade.type, shade.capabilities);
+        Capabilities capabilities = DB.getCapabilities(shade.type, shade.capabilities);
         if (capabilities.getValue() < 0) {
             logger.debug("Unable to set capabilities for shade {}", shade.id);
             return;
         }
         logger.debug("Caching capabilities {} for shade {}", capabilities.getValue(), shade.id);
         this.capabilities = capabilities;
+
+        updateDynamicChannels(capabilities);
     }
 
     private Capabilities getCapabilitiesOrDefault() {
@@ -298,17 +301,17 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
         final int type = shadeData.type;
         String propKey = HDPowerViewBindingConstants.PROPERTY_SHADE_TYPE;
         String propOldVal = properties.getOrDefault(propKey, "");
-        String propNewVal = db.getType(type).toString();
+        String propNewVal = DB.getType(type).toString();
         if (!propNewVal.equals(propOldVal)) {
             propChanged = true;
             getThing().setProperty(propKey, propNewVal);
-            if ((type > 0) && !db.isTypeInDatabase(type)) {
-                db.logTypeNotInDatabase(type);
+            if ((type > 0) && !DB.isTypeInDatabase(type)) {
+                DB.logTypeNotInDatabase(type);
             }
         }
 
         // update 'capabilities' property
-        Capabilities capabilities = db.getCapabilities(shadeData.capabilities);
+        Capabilities capabilities = DB.getCapabilities(shadeData.capabilities);
         final int capabilitiesVal = capabilities.getValue();
         propKey = HDPowerViewBindingConstants.PROPERTY_SHADE_CAPABILITIES;
         propOldVal = properties.getOrDefault(propKey, "");
@@ -316,14 +319,14 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
         if (!propNewVal.equals(propOldVal)) {
             propChanged = true;
             getThing().setProperty(propKey, propNewVal);
-            if ((capabilitiesVal >= 0) && !db.isCapabilitiesInDatabase(capabilitiesVal)) {
-                db.logCapabilitiesNotInDatabase(type, capabilitiesVal);
+            if ((capabilitiesVal >= 0) && !DB.isCapabilitiesInDatabase(capabilitiesVal)) {
+                DB.logCapabilitiesNotInDatabase(type, capabilitiesVal);
             }
         }
 
-        if (propChanged && db.isCapabilitiesInDatabase(capabilitiesVal) && db.isTypeInDatabase(type)
-                && (capabilitiesVal != db.getType(type).getCapabilities()) && (shadeData.capabilities != null)) {
-            db.logCapabilitiesMismatch(type, capabilitiesVal);
+        if (propChanged && DB.isCapabilitiesInDatabase(capabilitiesVal) && DB.isTypeInDatabase(type)
+                && (capabilitiesVal != DB.getType(type).getCapabilities()) && (shadeData.capabilities != null)) {
+            DB.logCapabilitiesMismatch(type, capabilitiesVal);
         }
     }
 
@@ -364,7 +367,7 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
         if (!capsNewVal.equals(capsOldVal)) {
             detectedCapabilities.put(capsKey, capsNewVal);
             if (capsNewBool != capabilities.supportsSecondary()) {
-                db.logPropertyMismatch(capsKey, shadeData.type, capabilities.getValue(), capsNewBool);
+                DB.logPropertyMismatch(capsKey, shadeData.type, capabilities.getValue(), capsNewBool);
             }
         }
 
@@ -376,7 +379,7 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
         if (!capsNewVal.equals(capsOldVal)) {
             detectedCapabilities.put(capsKey, capsNewVal);
             if (capsNewBool != capabilities.supportsTiltAnywhere()) {
-                db.logPropertyMismatch(capsKey, shadeData.type, capabilities.getValue(), capsNewBool);
+                DB.logPropertyMismatch(capsKey, shadeData.type, capabilities.getValue(), capsNewBool);
             }
         }
     }
@@ -596,4 +599,45 @@ public class HDPowerViewShadeHandler extends AbstractHubbedThingHandler {
             }
         }
     }
+
+    /**
+     * If the given channel exists in the thing, but is NOT required in the thing, then add it to a list of channels to
+     * be removed. Or if the channel does NOT exist in the thing, but is required in the thing, then log a warning.
+     *
+     * @param removeList the list of channels to be removed from the thing.
+     * @param channelId the id of the channel to be (eventually) removed.
+     * @param channelRequired true if the thing requires this channel.
+     */
+    private void removeListProcessChannel(List<Channel> removeList, String channelId, boolean channelRequired) {
+        Channel channel = thing.getChannel(channelId);
+        if (!channelRequired && channel != null) {
+            removeList.add(channel);
+        } else if (channelRequired && channel == null) {
+            logger.warn("Shade {} does not have a '{}' channel => please reinitialize the thing", shadeId, channelId);
+        }
+    }
+
+    /**
+     * Remove previously statically created channels if the shade does not support them.
+     */
+    private void updateDynamicChannels(Capabilities capabilities) {
+        List<Channel> removeList = new ArrayList<>();
+
+        removeListProcessChannel(removeList, CHANNEL_SHADE_POSITION, capabilities.supportsPrimary());
+
+        removeListProcessChannel(removeList, CHANNEL_SHADE_SECONDARY_POSITION,
+                capabilities.supportsSecondary() || capabilities.supportsSecondaryOverlapped());
+
+        removeListProcessChannel(removeList, CHANNEL_SHADE_VANE,
+                capabilities.supportsTiltAnywhere() || capabilities.supportsTiltOnClosed());
+
+        if (!removeList.isEmpty()) {
+            if (logger.isDebugEnabled()) {
+                StringJoiner joiner = new StringJoiner(", ");
+                removeList.forEach(c -> joiner.add(c.getUID().getId()));
+                logger.debug("Removing unsupported channels for {}: {}", shadeId, joiner.toString());
+            }
+            updateThing(editThing().withoutChannels(removeList).build());
+        }
+    }
 }
index 8ec5e9c5a15475abc6faff941a2025c17f0647b2..914bedbb35ae528ffb7628acf4c4ab9ae1551f83 100644 (file)
@@ -8,6 +8,7 @@
                <item-type>Rollershutter</item-type>
                <label>Position</label>
                <description>The vertical position of the shade</description>
+               <category>blinds</category>
        </channel-type>
 
        <channel-type id="shade-vane">