]> git.basschouten.com Git - openhab-addons.git/commitdiff
[homekit] fix for battery charging state (#12959)
authoreugen <freiter@gmail.com>
Wed, 22 Jun 2022 09:20:36 +0000 (11:20 +0200)
committerGitHub <noreply@github.com>
Wed, 22 Jun 2022 09:20:36 +0000 (11:20 +0200)
* fix for battery charging state

Signed-off-by: Eugen Freiter <freiter@gmx.de>
bundles/org.openhab.io.homekit/README.md
bundles/org.openhab.io.homekit/doc/ui_sensor_with_battery.png [new file with mode: 0644]
bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitCharacteristicType.java
bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/HomekitTaggedItem.java
bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/accessories/HomekitAccessoryFactory.java
bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/accessories/HomekitBatteryImpl.java
bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/accessories/HomekitCharacteristicFactory.java
bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/accessories/IncompleteAccessoryException.java

index 1747eea56664bdd874e0aa5c3b7a2625220813d4..17d8c83a2654ac534d9e013e665ef9b2a916eff6 100644 (file)
@@ -473,6 +473,7 @@ For example, ceiling fans often include lighting functionality. Such fans can be
 - two separate HomeKit accessories - fan **and** light. 
   
   iOS home app would show them as **two tiles** that can be controlled directly from home screen.
+  
   ![ios_fan_and_light_home_screen.png](doc/ios_fan_and_light_home_screen.png)
   
 - one complex accessory - fan **with** light. 
@@ -517,12 +518,17 @@ Group           FanWithLight        "Fan with Light"                           {
 
 ![ui_fan_with_light_primary.png](doc/ui_fan_with_light_primary.png)
 
+Similarly, you can create a sensor with battery
+
+![ui_sensor_with_battery.png](doc/ui_sensor_with_battery.png)
+
 However, home app does not support changing of tiles for already added accessory. 
 If you want to change the tile after the accessory was added, you need either to rename the group, if you use textual item configuration, or to delete and to create a new group with a different name, if you use UI for configuration.
 
 You can combine more than two accessories as well as accessories linked to different physical devices. 
 You can also do unusually combinations, e.g. you can combine temperature sensor with blinds and light. 
 It will be represented by home app as follows
+
 ![ios_complex_accessory_detail_screen.png](doc/ios_complex_accessory_detail_screen.png)
 
 
diff --git a/bundles/org.openhab.io.homekit/doc/ui_sensor_with_battery.png b/bundles/org.openhab.io.homekit/doc/ui_sensor_with_battery.png
new file mode 100644 (file)
index 0000000..d984a0a
Binary files /dev/null and b/bundles/org.openhab.io.homekit/doc/ui_sensor_with_battery.png differ
index c20cfa15092fca31633b86df50638730e71d2812..048f140e2e632387a8f89b91543d4c1bf312f095 100644 (file)
@@ -153,4 +153,9 @@ public enum HomekitCharacteristicType {
     public static Optional<HomekitCharacteristicType> valueOfTag(String tag) {
         return Optional.ofNullable(TAG_MAP.get(tag));
     }
+
+    @Override
+    public String toString() {
+        return tag;
+    }
 }
index 224e7169d3c3d6e2c65ae1b843af1b7b495da309..f212839be533fb5dbd2db9efba3dee9ada037553 100644 (file)
@@ -282,7 +282,7 @@ public class HomekitTaggedItem {
     }
 
     public String toString() {
-        return "Item:" + proxyItem.getItem() + "  HomeKit type:" + homekitAccessoryType + " HomeKit characteristic:"
-                + homekitCharacteristicType;
+        return "Item:" + proxyItem.getItem() + "  HomeKit type: '" + homekitAccessoryType.getTag()
+                + "' characteristic: '" + homekitCharacteristicType.getTag() + "'";
     }
 }
index 356497f5e8b06ee661a4977a29d72d97a0c4676e..7cd25e2ee00f30c7cce664268ceeb4664850d194 100644 (file)
@@ -141,8 +141,21 @@ public class HomekitAccessoryFactory {
         }
     };
 
+    private static List<HomekitCharacteristicType> getRequiredCharacteristics(HomekitTaggedItem taggedItem) {
+        if (taggedItem.getAccessoryType() == BATTERY) {
+            final String isChargeable = taggedItem.getConfiguration(HomekitBatteryImpl.BATTERY_TYPE, "false");
+            if ("true".equalsIgnoreCase(isChargeable) || "yes".equalsIgnoreCase(isChargeable)) {
+                final List<HomekitCharacteristicType> characteristics = new ArrayList<>();
+                characteristics.addAll(Arrays.asList(MANDATORY_CHARACTERISTICS.get(taggedItem.getAccessoryType())));
+                characteristics.add(BATTERY_CHARGING_STATE);
+                return characteristics;
+            }
+        }
+        return Arrays.asList(MANDATORY_CHARACTERISTICS.get(taggedItem.getAccessoryType()));
+    }
+
     /**
-     * creates HomeKit accessory for a openhab item.
+     * creates HomeKit accessory for an openhab item.
      *
      * @param taggedItem openhab item tagged as HomeKit item
      * @param metadataRegistry openhab metadata registry required to get item meta information
@@ -158,12 +171,12 @@ public class HomekitAccessoryFactory {
             HomekitAccessoryUpdater updater, HomekitSettings settings) throws HomekitException {
         final HomekitAccessoryType accessoryType = taggedItem.getAccessoryType();
         logger.trace("Constructing {} of accessory type {}", taggedItem.getName(), accessoryType.getTag());
-        final List<HomekitTaggedItem> requiredCharacteristics = getMandatoryCharacteristics(taggedItem,
+        final List<HomekitTaggedItem> foundCharacteristics = getMandatoryCharacteristicsFromItem(taggedItem,
                 metadataRegistry);
-        final HomekitCharacteristicType[] mandatoryCharacteristics = MANDATORY_CHARACTERISTICS.get(accessoryType);
-        if ((mandatoryCharacteristics != null) && (requiredCharacteristics.size() < mandatoryCharacteristics.length)) {
+        final List<HomekitCharacteristicType> mandatoryCharacteristics = getRequiredCharacteristics(taggedItem);
+        if (foundCharacteristics.size() < mandatoryCharacteristics.size()) {
             logger.warn("Accessory of type {} must have following characteristics {}. Found only {}",
-                    accessoryType.getTag(), mandatoryCharacteristics, requiredCharacteristics);
+                    accessoryType.getTag(), mandatoryCharacteristics, foundCharacteristics);
             throw new HomekitException("Missing mandatory characteristics");
         }
         AbstractHomekitAccessoryImpl accessoryImpl;
@@ -171,10 +184,9 @@ public class HomekitAccessoryFactory {
             final @Nullable Class<? extends AbstractHomekitAccessoryImpl> accessoryImplClass = SERVICE_IMPL_MAP
                     .get(accessoryType);
             if (accessoryImplClass != null) {
-                accessoryImpl = accessoryImplClass
-                        .getConstructor(HomekitTaggedItem.class, List.class, HomekitAccessoryUpdater.class,
-                                HomekitSettings.class)
-                        .newInstance(taggedItem, requiredCharacteristics, updater, settings);
+                accessoryImpl = accessoryImplClass.getConstructor(HomekitTaggedItem.class, List.class,
+                        HomekitAccessoryUpdater.class, HomekitSettings.class)
+                        .newInstance(taggedItem, foundCharacteristics, updater, settings);
                 addOptionalCharacteristics(taggedItem, accessoryImpl, metadataRegistry);
                 return accessoryImpl;
             } else {
@@ -255,7 +267,7 @@ public class HomekitAccessoryFactory {
      * @param metadataRegistry meta data registry
      * @return list of mandatory
      */
-    private static List<HomekitTaggedItem> getMandatoryCharacteristics(HomekitTaggedItem taggedItem,
+    private static List<HomekitTaggedItem> getMandatoryCharacteristicsFromItem(HomekitTaggedItem taggedItem,
             MetadataRegistry metadataRegistry) {
         List<HomekitTaggedItem> collectedCharacteristics = new ArrayList<>();
         if (taggedItem.isGroup()) {
@@ -265,8 +277,7 @@ public class HomekitAccessoryFactory {
         } else {
             addMandatoryCharacteristics(taggedItem, collectedCharacteristics, taggedItem.getItem(), metadataRegistry);
         }
-        logger.trace("Mandatory characteristics for item {} characteristics {}", taggedItem.getName(),
-                collectedCharacteristics);
+        logger.trace("Mandatory characteristics: {}", collectedCharacteristics);
         return collectedCharacteristics;
     }
 
@@ -285,9 +296,8 @@ public class HomekitAccessoryFactory {
     private static void addMandatoryCharacteristics(HomekitTaggedItem mainItem, List<HomekitTaggedItem> characteristics,
             Item item, MetadataRegistry metadataRegistry) {
         // get list of mandatory characteristics
-        HomekitCharacteristicType[] mandatoryCharacteristics = MANDATORY_CHARACTERISTICS
-                .get(mainItem.getAccessoryType());
-        if ((mandatoryCharacteristics == null) || (mandatoryCharacteristics.length == 0)) {
+        List<HomekitCharacteristicType> mandatoryCharacteristics = getRequiredCharacteristics(mainItem);
+        if (mandatoryCharacteristics.isEmpty()) {
             // no mandatory characteristics linked to accessory type of mainItem. we are done
             return;
         }
@@ -299,13 +309,12 @@ public class HomekitAccessoryFactory {
         for (Entry<HomekitAccessoryType, HomekitCharacteristicType> accessory : getAccessoryTypes(item,
                 metadataRegistry)) {
             // if the item has only accessory tag, e.g. TemperatureSensor,
-            // the we will link all mandatory characteristic to this item,
+            // then we will link all mandatory characteristic to this item,
             // e.g. we will link CurrentTemperature in case of TemperatureSensor.
             if (isRootAccessory(accessory)) {
-                Arrays.stream(mandatoryCharacteristics)
-                        .forEach(c -> characteristics.add(new HomekitTaggedItem(itemProxy, accessory.getKey(), c,
-                                mainItem.isGroup() ? (GroupItem) mainItem.getItem() : null,
-                                HomekitAccessoryFactory.getItemConfiguration(item, metadataRegistry))));
+                mandatoryCharacteristics.forEach(c -> characteristics.add(new HomekitTaggedItem(itemProxy,
+                        accessory.getKey(), c, mainItem.isGroup() ? (GroupItem) mainItem.getItem() : null,
+                        HomekitAccessoryFactory.getItemConfiguration(item, metadataRegistry))));
             } else {
                 // item has characteristic tag on it, so, adding it as that characteristic.
 
@@ -313,7 +322,7 @@ public class HomekitAccessoryFactory {
 
                 // check whether it is a mandatory characteristic. optional will be added later by another method.
                 if (belongsToType(mainItem.getAccessoryType(), accessory)
-                        && isMandatoryCharacteristic(mainItem.getAccessoryType(), characteristic)) {
+                        && isMandatoryCharacteristic(mainItem, characteristic)) {
                     characteristics.add(new HomekitTaggedItem(itemProxy, accessory.getKey(), characteristic,
                             mainItem.isGroup() ? (GroupItem) mainItem.getItem() : null,
                             HomekitAccessoryFactory.getItemConfiguration(item, metadataRegistry)));
@@ -373,30 +382,28 @@ public class HomekitAccessoryFactory {
             GroupItem groupItem = (GroupItem) taggedItem.getItem();
             groupItem.getMembers().forEach(item -> getAccessoryTypes(item, metadataRegistry).stream()
                     .filter(c -> !isRootAccessory(c)).filter(c -> belongsToType(taggedItem.getAccessoryType(), c))
-                    .filter(c -> !isMandatoryCharacteristic(taggedItem.getAccessoryType(), c.getValue()))
+                    .filter(c -> !isMandatoryCharacteristic(taggedItem, c.getValue()))
                     .forEach(characteristic -> characteristicItems.put(characteristic.getValue(), (GenericItem) item)));
         } else {
             getAccessoryTypes(taggedItem.getItem(), metadataRegistry).stream().filter(c -> !isRootAccessory(c))
-                    .filter(c -> !isMandatoryCharacteristic(taggedItem.getAccessoryType(), c.getValue()))
+                    .filter(c -> !isMandatoryCharacteristic(taggedItem, c.getValue()))
                     .forEach(characteristic -> characteristicItems.put(characteristic.getValue(),
                             (GenericItem) taggedItem.getItem()));
         }
-        logger.trace("Optional characteristics for item {} characteristics {}", taggedItem.getName(),
-                characteristicItems);
+        logger.trace("Optional characteristics for item {}: {}", taggedItem.getName(), characteristicItems.values());
         return Collections.unmodifiableMap(characteristicItems);
     }
 
     /**
      * return true is characteristic is a mandatory characteristic for the accessory.
      *
-     * @param accessory accessory
+     * @param item item
      * @param characteristic characteristic
      * @return true if characteristic is mandatory, false if not mandatory
      */
-    private static boolean isMandatoryCharacteristic(HomekitAccessoryType accessory,
-            HomekitCharacteristicType characteristic) {
-        return MANDATORY_CHARACTERISTICS.containsKey(accessory)
-                && Arrays.asList(MANDATORY_CHARACTERISTICS.get(accessory)).contains(characteristic);
+    private static boolean isMandatoryCharacteristic(HomekitTaggedItem item, HomekitCharacteristicType characteristic) {
+        return MANDATORY_CHARACTERISTICS.containsKey(item.getAccessoryType())
+                && getRequiredCharacteristics(item).contains(characteristic);
     }
 
     /**
index 9c1d9becbc8d19883cc679282b0d2e85239e0c43..9d4c323e89780c93e0faa7e1eba7676432d663bf 100644 (file)
@@ -37,7 +37,7 @@ import io.github.hapjava.services.impl.BatteryService;
  * @author Eugen Freiter - Initial contribution
  */
 public class HomekitBatteryImpl extends AbstractHomekitAccessoryImpl implements BatteryAccessory {
-    private static final String BATTERY_TYPE = "chargeable";
+    public static final String BATTERY_TYPE = "chargeable";
 
     private final BooleanItemReader lowBatteryReader;
     private BooleanItemReader chargingBatteryReader;
@@ -87,7 +87,9 @@ public class HomekitBatteryImpl extends AbstractHomekitAccessoryImpl implements
 
     @Override
     public void subscribeBatteryChargingState(final HomekitCharacteristicChangeCallback callback) {
-        subscribe(BATTERY_CHARGING_STATE, callback);
+        if (isChargeable) {
+            subscribe(BATTERY_CHARGING_STATE, callback);
+        }
     }
 
     @Override
@@ -102,6 +104,8 @@ public class HomekitBatteryImpl extends AbstractHomekitAccessoryImpl implements
 
     @Override
     public void unsubscribeBatteryChargingState() {
-        unsubscribe(BATTERY_CHARGING_STATE);
+        if (isChargeable) {
+            unsubscribe(BATTERY_CHARGING_STATE);
+        }
     }
 }
index fc90a45de830f2ce6d8e32fbdf4ee07d7a4b5537..d6729f7f027347016f1f4805032de1915e5ce4fd 100644 (file)
@@ -184,13 +184,14 @@ public class HomekitCharacteristicFactory {
     public static Characteristic createCharacteristic(HomekitTaggedItem item, HomekitAccessoryUpdater updater)
             throws HomekitException {
         final @Nullable HomekitCharacteristicType type = item.getCharacteristicType();
-        logger.trace("CreateCharacteristic, type {} item {}", type, item);
+        logger.trace("Create characteristic {}", item);
         if (optional.containsKey(type)) {
             return optional.get(type).apply(item, updater);
         }
         logger.warn("Unsupported optional characteristic. Accessory type {}, characteristic type {}",
-                item.getAccessoryType(), type);
-        throw new HomekitException("Unsupported optional characteristic. Characteristic type \"" + type + "\"");
+                item.getAccessoryType(), type.getTag());
+        throw new HomekitException(
+                "Unsupported optional characteristic. Characteristic type \"" + type.getTag() + "\"");
     }
 
     // METHODS TO CREATE SINGLE CHARACTERISTIC FROM OH ITEM
index 221a5b42e87d97ee4e004e9c48bf78ae9c7af591..6203a4979442f4ff729255efee0a2e1c09f10d86 100644 (file)
@@ -24,7 +24,7 @@ public class IncompleteAccessoryException extends Exception {
     private static final long serialVersionUID = 8595808359805444177L;
 
     public IncompleteAccessoryException(HomekitCharacteristicType missingType) {
-        super(String.format("Missing accessory type %s", missingType.getTag()));
+        super(String.format("Missing accessory characteristic %s", missingType.getTag()));
     }
 
     public IncompleteAccessoryException(String message) {