]> git.basschouten.com Git - openhab-addons.git/commitdiff
[homekit] sort characteristics in HomekitCharacteristicFactory (#17033)
authorCody Cutrer <cody@cutrer.us>
Wed, 10 Jul 2024 14:54:29 +0000 (08:54 -0600)
committerGitHub <noreply@github.com>
Wed, 10 Jul 2024 14:54:29 +0000 (16:54 +0200)
there are so many shared characteristics now, and so many accessories they belong
to, there is no longer any groupings that make sense. so just sort solely by
characteristic/method name

Signed-off-by: Cody Cutrer <cody@cutrer.us>
bundles/org.openhab.io.homekit/src/main/java/org/openhab/io/homekit/internal/accessories/HomekitCharacteristicFactory.java

index e4105859a0564c721c5dd83d3a78cb95e13e98cb..cd5126887c69bc882d8ad6ce5f2d4345ebdad278 100644 (file)
@@ -170,75 +170,75 @@ public class HomekitCharacteristicFactory {
     // List of optional characteristics and corresponding method to create them.
     private static final Map<HomekitCharacteristicType, BiFunction<HomekitTaggedItem, HomekitAccessoryUpdater, Characteristic>> OPTIONAL = new HashMap<>() {
         {
-            put(NAME, HomekitCharacteristicFactory::createNameCharacteristic);
-            put(MODEL, HomekitCharacteristicFactory::createModelCharacteristic);
-            put(MANUFACTURER, HomekitCharacteristicFactory::createManufacturerCharacteristic);
-            put(SERIAL_NUMBER, HomekitCharacteristicFactory::createSerialNumberCharacteristic);
-            put(FIRMWARE_REVISION, HomekitCharacteristicFactory::createFirmwareRevisionCharacteristic);
-            put(HARDWARE_REVISION, HomekitCharacteristicFactory::createHardwareRevisionCharacteristic);
-            put(BATTERY_LOW_STATUS, HomekitCharacteristicFactory::createStatusLowBatteryCharacteristic);
-            put(FAULT_STATUS, HomekitCharacteristicFactory::createStatusFaultCharacteristic);
-            put(TAMPERED_STATUS, HomekitCharacteristicFactory::createStatusTamperedCharacteristic);
+            put(ACTIVE, HomekitCharacteristicFactory::createActiveCharacteristic);
+            put(ACTIVE_IDENTIFIER, HomekitCharacteristicFactory::createActiveIdentifierCharacteristic);
             put(ACTIVE_STATUS, HomekitCharacteristicFactory::createStatusActiveCharacteristic);
-            put(CARBON_MONOXIDE_LEVEL, HomekitCharacteristicFactory::createCarbonMonoxideLevelCharacteristic);
-            put(CARBON_MONOXIDE_PEAK_LEVEL, HomekitCharacteristicFactory::createCarbonMonoxidePeakLevelCharacteristic);
+            put(BATTERY_LOW_STATUS, HomekitCharacteristicFactory::createStatusLowBatteryCharacteristic);
+            put(BRIGHTNESS, HomekitCharacteristicFactory::createBrightnessCharacteristic);
             put(CARBON_DIOXIDE_LEVEL, HomekitCharacteristicFactory::createCarbonDioxideLevelCharacteristic);
             put(CARBON_DIOXIDE_PEAK_LEVEL, HomekitCharacteristicFactory::createCarbonDioxidePeakLevelCharacteristic);
-            put(HOLD_POSITION, HomekitCharacteristicFactory::createHoldPositionCharacteristic);
-            put(OBSTRUCTION_STATUS, HomekitCharacteristicFactory::createObstructionDetectedCharacteristic);
+            put(CARBON_MONOXIDE_LEVEL, HomekitCharacteristicFactory::createCarbonMonoxideLevelCharacteristic);
+            put(CARBON_MONOXIDE_PEAK_LEVEL, HomekitCharacteristicFactory::createCarbonMonoxidePeakLevelCharacteristic);
+            put(CLOSED_CAPTIONS, HomekitCharacteristicFactory::createClosedCaptionsCharacteristic);
+            put(COLOR_TEMPERATURE, HomekitCharacteristicFactory::createColorTemperatureCharacteristic);
+            put(CONFIGURED, HomekitCharacteristicFactory::createIsConfiguredCharacteristic);
+            put(CONFIGURED_NAME, HomekitCharacteristicFactory::createConfiguredNameCharacteristic);
+            put(COOLING_THRESHOLD_TEMPERATURE, HomekitCharacteristicFactory::createCoolingThresholdCharacteristic);
+            put(CURRENT_FAN_STATE, HomekitCharacteristicFactory::createCurrentFanStateCharacteristic);
             put(CURRENT_HORIZONTAL_TILT_ANGLE,
                     HomekitCharacteristicFactory::createCurrentHorizontalTiltAngleCharacteristic);
+            put(CURRENT_MEDIA_STATE, HomekitCharacteristicFactory::createCurrentMediaStateCharacteristic);
+            put(CURRENT_TILT_ANGLE, HomekitCharacteristicFactory::createCurrentTiltAngleCharacteristic);
             put(CURRENT_VERTICAL_TILT_ANGLE,
                     HomekitCharacteristicFactory::createCurrentVerticalTiltAngleCharacteristic);
-            put(TARGET_HORIZONTAL_TILT_ANGLE,
-                    HomekitCharacteristicFactory::createTargetHorizontalTiltAngleCharacteristic);
-            put(TARGET_VERTICAL_TILT_ANGLE, HomekitCharacteristicFactory::createTargetVerticalTiltAngleCharacteristic);
-            put(CURRENT_TILT_ANGLE, HomekitCharacteristicFactory::createCurrentTiltAngleCharacteristic);
-            put(TARGET_TILT_ANGLE, HomekitCharacteristicFactory::createTargetTiltAngleCharacteristic);
-            put(HUE, HomekitCharacteristicFactory::createHueCharacteristic);
-            put(BRIGHTNESS, HomekitCharacteristicFactory::createBrightnessCharacteristic);
-            put(SATURATION, HomekitCharacteristicFactory::createSaturationCharacteristic);
-            put(COLOR_TEMPERATURE, HomekitCharacteristicFactory::createColorTemperatureCharacteristic);
-            put(CURRENT_FAN_STATE, HomekitCharacteristicFactory::createCurrentFanStateCharacteristic);
-            put(TARGET_FAN_STATE, HomekitCharacteristicFactory::createTargetFanStateCharacteristic);
-            put(ROTATION_DIRECTION, HomekitCharacteristicFactory::createRotationDirectionCharacteristic);
-            put(ROTATION_SPEED, HomekitCharacteristicFactory::createRotationSpeedCharacteristic);
-            put(SWING_MODE, HomekitCharacteristicFactory::createSwingModeCharacteristic);
-            put(LOCK_CONTROL, HomekitCharacteristicFactory::createLockPhysicalControlsCharacteristic);
+            put(CURRENT_VISIBILITY, HomekitCharacteristicFactory::createCurrentVisibilityStateCharacteristic);
             put(DURATION, HomekitCharacteristicFactory::createDurationCharacteristic);
-            put(VOLUME, HomekitCharacteristicFactory::createVolumeCharacteristic);
-            put(COOLING_THRESHOLD_TEMPERATURE, HomekitCharacteristicFactory::createCoolingThresholdCharacteristic);
+            put(FAULT_STATUS, HomekitCharacteristicFactory::createStatusFaultCharacteristic);
+            put(FIRMWARE_REVISION, HomekitCharacteristicFactory::createFirmwareRevisionCharacteristic);
+            put(FILTER_LIFE_LEVEL, HomekitCharacteristicFactory::createFilterLifeLevelCharacteristic);
+            put(FILTER_RESET_INDICATION, HomekitCharacteristicFactory::createFilterResetCharacteristic);
+            put(HARDWARE_REVISION, HomekitCharacteristicFactory::createHardwareRevisionCharacteristic);
             put(HEATING_THRESHOLD_TEMPERATURE, HomekitCharacteristicFactory::createHeatingThresholdCharacteristic);
-            put(RELATIVE_HUMIDITY, HomekitCharacteristicFactory::createRelativeHumidityCharacteristic);
-            put(REMAINING_DURATION, HomekitCharacteristicFactory::createRemainingDurationCharacteristic);
-            put(OZONE_DENSITY, HomekitCharacteristicFactory::createOzoneDensityCharacteristic);
+            put(HOLD_POSITION, HomekitCharacteristicFactory::createHoldPositionCharacteristic);
+            put(HUE, HomekitCharacteristicFactory::createHueCharacteristic);
+            put(IDENTIFIER, HomekitCharacteristicFactory::createIdentifierCharacteristic);
+            put(IDENTIFY, HomekitCharacteristicFactory::createIdentifyCharacteristic);
+            put(INPUT_DEVICE_TYPE, HomekitCharacteristicFactory::createInputDeviceTypeCharacteristic);
+            put(INPUT_SOURCE_TYPE, HomekitCharacteristicFactory::createInputSourceTypeCharacteristic);
+            put(LOCK_CONTROL, HomekitCharacteristicFactory::createLockPhysicalControlsCharacteristic);
+            put(MANUFACTURER, HomekitCharacteristicFactory::createManufacturerCharacteristic);
+            put(MODEL, HomekitCharacteristicFactory::createModelCharacteristic);
+            put(MUTE, HomekitCharacteristicFactory::createMuteCharacteristic);
+            put(NAME, HomekitCharacteristicFactory::createNameCharacteristic);
             put(NITROGEN_DIOXIDE_DENSITY, HomekitCharacteristicFactory::createNitrogenDioxideDensityCharacteristic);
-            put(SULPHUR_DIOXIDE_DENSITY, HomekitCharacteristicFactory::createSulphurDioxideDensityCharacteristic);
-            put(PM25_DENSITY, HomekitCharacteristicFactory::createPM25DensityCharacteristic);
+            put(OBSTRUCTION_STATUS, HomekitCharacteristicFactory::createObstructionDetectedCharacteristic);
+            put(OZONE_DENSITY, HomekitCharacteristicFactory::createOzoneDensityCharacteristic);
+            put(PICTURE_MODE, HomekitCharacteristicFactory::createPictureModeCharacteristic);
             put(PM10_DENSITY, HomekitCharacteristicFactory::createPM10DensityCharacteristic);
-            put(VOC_DENSITY, HomekitCharacteristicFactory::createVOCDensityCharacteristic);
-            put(FILTER_LIFE_LEVEL, HomekitCharacteristicFactory::createFilterLifeLevelCharacteristic);
-            put(FILTER_RESET_INDICATION, HomekitCharacteristicFactory::createFilterResetCharacteristic);
-            put(ACTIVE, HomekitCharacteristicFactory::createActiveCharacteristic);
-            put(CONFIGURED_NAME, HomekitCharacteristicFactory::createConfiguredNameCharacteristic);
-            put(ACTIVE_IDENTIFIER, HomekitCharacteristicFactory::createActiveIdentifierCharacteristic);
+            put(PM25_DENSITY, HomekitCharacteristicFactory::createPM25DensityCharacteristic);
+            put(POWER_MODE, HomekitCharacteristicFactory::createPowerModeCharacteristic);
+            put(REMAINING_DURATION, HomekitCharacteristicFactory::createRemainingDurationCharacteristic);
             put(REMOTE_KEY, HomekitCharacteristicFactory::createRemoteKeyCharacteristic);
+            put(RELATIVE_HUMIDITY, HomekitCharacteristicFactory::createRelativeHumidityCharacteristic);
+            put(ROTATION_DIRECTION, HomekitCharacteristicFactory::createRotationDirectionCharacteristic);
+            put(ROTATION_SPEED, HomekitCharacteristicFactory::createRotationSpeedCharacteristic);
+            put(SATURATION, HomekitCharacteristicFactory::createSaturationCharacteristic);
+            put(SERIAL_NUMBER, HomekitCharacteristicFactory::createSerialNumberCharacteristic);
             put(SLEEP_DISCOVERY_MODE, HomekitCharacteristicFactory::createSleepDiscoveryModeCharacteristic);
-            put(POWER_MODE, HomekitCharacteristicFactory::createPowerModeCharacteristic);
-            put(CLOSED_CAPTIONS, HomekitCharacteristicFactory::createClosedCaptionsCharacteristic);
-            put(PICTURE_MODE, HomekitCharacteristicFactory::createPictureModeCharacteristic);
-            put(CONFIGURED, HomekitCharacteristicFactory::createIsConfiguredCharacteristic);
-            put(INPUT_SOURCE_TYPE, HomekitCharacteristicFactory::createInputSourceTypeCharacteristic);
-            put(CURRENT_VISIBILITY, HomekitCharacteristicFactory::createCurrentVisibilityStateCharacteristic);
-            put(IDENTIFIER, HomekitCharacteristicFactory::createIdentifierCharacteristic);
-            put(INPUT_DEVICE_TYPE, HomekitCharacteristicFactory::createInputDeviceTypeCharacteristic);
+            put(SULPHUR_DIOXIDE_DENSITY, HomekitCharacteristicFactory::createSulphurDioxideDensityCharacteristic);
+            put(SWING_MODE, HomekitCharacteristicFactory::createSwingModeCharacteristic);
+            put(TAMPERED_STATUS, HomekitCharacteristicFactory::createStatusTamperedCharacteristic);
+            put(TARGET_FAN_STATE, HomekitCharacteristicFactory::createTargetFanStateCharacteristic);
+            put(TARGET_HORIZONTAL_TILT_ANGLE,
+                    HomekitCharacteristicFactory::createTargetHorizontalTiltAngleCharacteristic);
+            put(TARGET_MEDIA_STATE, HomekitCharacteristicFactory::createTargetMediaStateCharacteristic);
+            put(TARGET_TILT_ANGLE, HomekitCharacteristicFactory::createTargetTiltAngleCharacteristic);
+            put(TARGET_VERTICAL_TILT_ANGLE, HomekitCharacteristicFactory::createTargetVerticalTiltAngleCharacteristic);
             put(TARGET_VISIBILITY_STATE, HomekitCharacteristicFactory::createTargetVisibilityStateCharacteristic);
-            put(VOLUME_SELECTOR, HomekitCharacteristicFactory::createVolumeSelectorCharacteristic);
+            put(VOC_DENSITY, HomekitCharacteristicFactory::createVOCDensityCharacteristic);
+            put(VOLUME, HomekitCharacteristicFactory::createVolumeCharacteristic);
             put(VOLUME_CONTROL_TYPE, HomekitCharacteristicFactory::createVolumeControlTypeCharacteristic);
-            put(CURRENT_MEDIA_STATE, HomekitCharacteristicFactory::createCurrentMediaStateCharacteristic);
-            put(TARGET_MEDIA_STATE, HomekitCharacteristicFactory::createTargetMediaStateCharacteristic);
-            put(MUTE, HomekitCharacteristicFactory::createMuteCharacteristic);
-            put(IDENTIFY, HomekitCharacteristicFactory::createIdentifyCharacteristic);
+            put(VOLUME_SELECTOR, HomekitCharacteristicFactory::createVolumeSelectorCharacteristic);
         }
     };
 
@@ -398,8 +398,6 @@ public class HomekitCharacteristicFactory {
                 });
     }
 
-    // METHODS TO CREATE SINGLE CHARACTERISTIC FROM OH ITEM
-
     // supporting methods
 
     public static boolean useFahrenheit() {
@@ -589,121 +587,62 @@ public class HomekitCharacteristicFactory {
         return () -> updater.unsubscribe((GenericItem) taggedItem.getItem(), key.getTag());
     }
 
-    // create method for characteristic
-    private static StatusLowBatteryCharacteristic createStatusLowBatteryCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        BigDecimal lowThreshold = taggedItem.getConfiguration(HomekitTaggedItem.BATTERY_LOW_THRESHOLD,
-                BigDecimal.valueOf(20));
-        BooleanItemReader lowBatteryReader = new BooleanItemReader(taggedItem.getItem(),
-                OnOffType.from(!taggedItem.isInverted()),
-                taggedItem.isInverted() ? OpenClosedType.CLOSED : OpenClosedType.OPEN, lowThreshold, true);
-        return new StatusLowBatteryCharacteristic(
-                () -> CompletableFuture.completedFuture(
-                        lowBatteryReader.getValue() ? StatusLowBatteryEnum.LOW : StatusLowBatteryEnum.NORMAL),
-                getSubscriber(taggedItem, BATTERY_LOW_STATUS, updater),
-                getUnsubscriber(taggedItem, BATTERY_LOW_STATUS, updater));
-    }
-
-    private static StatusFaultCharacteristic createStatusFaultCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, StatusFaultEnum.class);
-        return new StatusFaultCharacteristic(() -> getEnumFromItem(taggedItem, map, StatusFaultEnum.NO_FAULT),
-                getSubscriber(taggedItem, FAULT_STATUS, updater), getUnsubscriber(taggedItem, FAULT_STATUS, updater));
-    }
-
-    private static StatusTamperedCharacteristic createStatusTamperedCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, StatusTamperedEnum.class);
-        return new StatusTamperedCharacteristic(() -> getEnumFromItem(taggedItem, map, StatusTamperedEnum.NOT_TAMPERED),
-                getSubscriber(taggedItem, TAMPERED_STATUS, updater),
-                getUnsubscriber(taggedItem, TAMPERED_STATUS, updater));
-    }
-
-    private static ObstructionDetectedCharacteristic createObstructionDetectedCharacteristic(
-            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
-        return new ObstructionDetectedCharacteristic(
-                () -> CompletableFuture.completedFuture(taggedItem.getItem().getState() == OnOffType.ON
-                        || taggedItem.getItem().getState() == OpenClosedType.OPEN),
-                getSubscriber(taggedItem, OBSTRUCTION_STATUS, updater),
-                getUnsubscriber(taggedItem, OBSTRUCTION_STATUS, updater));
-    }
-
-    private static StatusActiveCharacteristic createStatusActiveCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        return new StatusActiveCharacteristic(
-                () -> CompletableFuture.completedFuture(taggedItem.getItem().getState() == OnOffType.ON
-                        || taggedItem.getItem().getState() == OpenClosedType.OPEN),
-                getSubscriber(taggedItem, ACTIVE_STATUS, updater), getUnsubscriber(taggedItem, ACTIVE_STATUS, updater));
-    }
-
-    private static NameCharacteristic createNameCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        return new NameCharacteristic(() -> {
-            final State state = taggedItem.getItem().getState();
-            return CompletableFuture.completedFuture(state instanceof UnDefType ? "" : state.toString());
-        });
-    }
-
-    private static ModelCharacteristic createModelCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        return new ModelCharacteristic(() -> {
-            final State state = taggedItem.getItem().getState();
-            return CompletableFuture.completedFuture(state instanceof UnDefType ? "" : state.toString());
-        });
-    }
+    // METHODS TO CREATE SINGLE CHARACTERISTIC FROM OPENHAB ITEM
 
-    private static ManufacturerCharacteristic createManufacturerCharacteristic(HomekitTaggedItem taggedItem,
+    private static ActiveCharacteristic createActiveCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new ManufacturerCharacteristic(() -> {
-            final State state = taggedItem.getItem().getState();
-            return CompletableFuture.completedFuture(state instanceof UnDefType ? "" : state.toString());
-        });
+        var map = createMapping(taggedItem, ActiveEnum.class, false);
+        return new ActiveCharacteristic(() -> getEnumFromItem(taggedItem, map, ActiveEnum.INACTIVE),
+                (value) -> setValueFromEnum(taggedItem, value, map), getSubscriber(taggedItem, ACTIVE, updater),
+                getUnsubscriber(taggedItem, ACTIVE, updater));
     }
 
-    private static SerialNumberCharacteristic createSerialNumberCharacteristic(HomekitTaggedItem taggedItem,
+    private static ActiveIdentifierCharacteristic createActiveIdentifierCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new SerialNumberCharacteristic(() -> {
-            final State state = taggedItem.getItem().getState();
-            return CompletableFuture.completedFuture(state instanceof UnDefType ? "" : state.toString());
-        });
+        return new ActiveIdentifierCharacteristic(getIntSupplier(taggedItem, 1), setIntConsumer(taggedItem),
+                getSubscriber(taggedItem, ACTIVE_IDENTIFIER, updater),
+                getUnsubscriber(taggedItem, ACTIVE_IDENTIFIER, updater));
     }
 
-    private static FirmwareRevisionCharacteristic createFirmwareRevisionCharacteristic(HomekitTaggedItem taggedItem,
+    private static BrightnessCharacteristic createBrightnessCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new FirmwareRevisionCharacteristic(() -> {
+        return new BrightnessCharacteristic(() -> {
+            int value = 0;
             final State state = taggedItem.getItem().getState();
-            return CompletableFuture.completedFuture(state instanceof UnDefType ? "" : state.toString());
-        });
+            if (state instanceof HSBType stateAsHSBType) {
+                value = stateAsHSBType.getBrightness().intValue();
+            } else if (state instanceof PercentType stateAsPercentType) {
+                value = stateAsPercentType.intValue();
+            }
+            return CompletableFuture.completedFuture(value);
+        }, (brightness) -> {
+            if (taggedItem.getBaseItem() instanceof DimmerItem) {
+                taggedItem.sendCommandProxy(HomekitCommandType.BRIGHTNESS_COMMAND, new PercentType(brightness));
+            } else {
+                LOGGER.warn("Item type {} is not supported for {}. Only ColorItem and DimmerItem are supported.",
+                        taggedItem.getBaseItem().getType(), taggedItem.getName());
+            }
+        }, getSubscriber(taggedItem, BRIGHTNESS, updater), getUnsubscriber(taggedItem, BRIGHTNESS, updater));
     }
 
-    private static HardwareRevisionCharacteristic createHardwareRevisionCharacteristic(HomekitTaggedItem taggedItem,
+    private static CarbonDioxideLevelCharacteristic createCarbonDioxideLevelCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new HardwareRevisionCharacteristic(() -> {
-            final State state = taggedItem.getItem().getState();
-            return CompletableFuture.completedFuture(state instanceof UnDefType ? "" : state.toString());
-        });
+        return new CarbonDioxideLevelCharacteristic(
+                getDoubleSupplier(taggedItem,
+                        taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
+                                CarbonDioxideLevelCharacteristic.DEFAULT_MIN_VALUE)),
+                getSubscriber(taggedItem, CARBON_MONOXIDE_LEVEL, updater),
+                getUnsubscriber(taggedItem, CARBON_MONOXIDE_LEVEL, updater));
     }
 
-    private static HoldPositionCharacteristic createHoldPositionCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        final Item item = taggedItem.getBaseItem();
-        if (!(item instanceof SwitchItem || item instanceof RollershutterItem)) {
-            LOGGER.warn(
-                    "Item {} cannot be used for the HoldPosition characteristic; only SwitchItem and RollershutterItem are supported. Hold requests will be ignored.",
-                    item.getName());
-        }
-
-        return new HoldPositionCharacteristic(value -> {
-            if (!value) {
-                return;
-            }
-
-            if (item instanceof SwitchItem switchItem) {
-                switchItem.send(OnOffType.ON);
-            } else if (item instanceof RollershutterItem rollerShutterItem) {
-                rollerShutterItem.send(StopMoveType.STOP);
-            }
-        });
+    private static CarbonDioxidePeakLevelCharacteristic createCarbonDioxidePeakLevelCharacteristic(
+            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
+        return new CarbonDioxidePeakLevelCharacteristic(
+                getDoubleSupplier(taggedItem,
+                        taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
+                                CarbonDioxidePeakLevelCharacteristic.DEFAULT_MIN_VALUE)),
+                getSubscriber(taggedItem, CARBON_MONOXIDE_PEAK_LEVEL, updater),
+                getUnsubscriber(taggedItem, CARBON_MONOXIDE_PEAK_LEVEL, updater));
     }
 
     private static CarbonMonoxideLevelCharacteristic createCarbonMonoxideLevelCharacteristic(
@@ -726,128 +665,13 @@ public class HomekitCharacteristicFactory {
                 getUnsubscriber(taggedItem, CARBON_DIOXIDE_PEAK_LEVEL, updater));
     }
 
-    private static CarbonDioxideLevelCharacteristic createCarbonDioxideLevelCharacteristic(HomekitTaggedItem taggedItem,
+    private static ClosedCaptionsCharacteristic createClosedCaptionsCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new CarbonDioxideLevelCharacteristic(
-                getDoubleSupplier(taggedItem,
-                        taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
-                                CarbonDioxideLevelCharacteristic.DEFAULT_MIN_VALUE)),
-                getSubscriber(taggedItem, CARBON_MONOXIDE_LEVEL, updater),
-                getUnsubscriber(taggedItem, CARBON_MONOXIDE_LEVEL, updater));
-    }
-
-    private static CarbonDioxidePeakLevelCharacteristic createCarbonDioxidePeakLevelCharacteristic(
-            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
-        return new CarbonDioxidePeakLevelCharacteristic(
-                getDoubleSupplier(taggedItem,
-                        taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
-                                CarbonDioxidePeakLevelCharacteristic.DEFAULT_MIN_VALUE)),
-                getSubscriber(taggedItem, CARBON_MONOXIDE_PEAK_LEVEL, updater),
-                getUnsubscriber(taggedItem, CARBON_MONOXIDE_PEAK_LEVEL, updater));
-    }
-
-    private static CurrentHorizontalTiltAngleCharacteristic createCurrentHorizontalTiltAngleCharacteristic(
-            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
-        return new CurrentHorizontalTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0),
-                getSubscriber(taggedItem, CURRENT_HORIZONTAL_TILT_ANGLE, updater),
-                getUnsubscriber(taggedItem, CURRENT_HORIZONTAL_TILT_ANGLE, updater));
-    }
-
-    private static CurrentVerticalTiltAngleCharacteristic createCurrentVerticalTiltAngleCharacteristic(
-            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
-        return new CurrentVerticalTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0),
-                getSubscriber(taggedItem, CURRENT_VERTICAL_TILT_ANGLE, updater),
-                getUnsubscriber(taggedItem, CURRENT_VERTICAL_TILT_ANGLE, updater));
-    }
-
-    private static TargetHorizontalTiltAngleCharacteristic createTargetHorizontalTiltAngleCharacteristic(
-            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
-        return new TargetHorizontalTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0),
-                setAngleConsumer(taggedItem), getSubscriber(taggedItem, TARGET_HORIZONTAL_TILT_ANGLE, updater),
-                getUnsubscriber(taggedItem, TARGET_HORIZONTAL_TILT_ANGLE, updater));
-    }
-
-    private static TargetVerticalTiltAngleCharacteristic createTargetVerticalTiltAngleCharacteristic(
-            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
-        return new TargetVerticalTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0), setAngleConsumer(taggedItem),
-                getSubscriber(taggedItem, TARGET_HORIZONTAL_TILT_ANGLE, updater),
-                getUnsubscriber(taggedItem, TARGET_HORIZONTAL_TILT_ANGLE, updater));
-    }
-
-    private static CurrentTiltAngleCharacteristic createCurrentTiltAngleCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        return new CurrentTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0),
-                getSubscriber(taggedItem, CURRENT_TILT_ANGLE, updater),
-                getUnsubscriber(taggedItem, CURRENT_TILT_ANGLE, updater));
-    }
-
-    private static TargetTiltAngleCharacteristic createTargetTiltAngleCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        return new TargetTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0), setAngleConsumer(taggedItem),
-                getSubscriber(taggedItem, TARGET_TILT_ANGLE, updater),
-                getUnsubscriber(taggedItem, TARGET_TILT_ANGLE, updater));
-    }
-
-    private static HueCharacteristic createHueCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        return new HueCharacteristic(() -> {
-            double value = 0.0;
-            State state = taggedItem.getItem().getState();
-            if (state instanceof HSBType stateAsHSBType) {
-                value = stateAsHSBType.getHue().doubleValue();
-            }
-            return CompletableFuture.completedFuture(value);
-        }, (hue) -> {
-            if (taggedItem.getBaseItem() instanceof ColorItem) {
-                taggedItem.sendCommandProxy(HomekitCommandType.HUE_COMMAND, new DecimalType(hue));
-            } else {
-                LOGGER.warn("Item type {} is not supported for {}. Only Color type is supported.",
-                        taggedItem.getBaseItem().getType(), taggedItem.getName());
-            }
-        }, getSubscriber(taggedItem, HUE, updater), getUnsubscriber(taggedItem, HUE, updater));
-    }
-
-    private static BrightnessCharacteristic createBrightnessCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        return new BrightnessCharacteristic(() -> {
-            int value = 0;
-            final State state = taggedItem.getItem().getState();
-            if (state instanceof HSBType stateAsHSBType) {
-                value = stateAsHSBType.getBrightness().intValue();
-            } else if (state instanceof PercentType stateAsPercentType) {
-                value = stateAsPercentType.intValue();
-            }
-            return CompletableFuture.completedFuture(value);
-        }, (brightness) -> {
-            if (taggedItem.getBaseItem() instanceof DimmerItem) {
-                taggedItem.sendCommandProxy(HomekitCommandType.BRIGHTNESS_COMMAND, new PercentType(brightness));
-            } else {
-                LOGGER.warn("Item type {} is not supported for {}. Only ColorItem and DimmerItem are supported.",
-                        taggedItem.getBaseItem().getType(), taggedItem.getName());
-            }
-        }, getSubscriber(taggedItem, BRIGHTNESS, updater), getUnsubscriber(taggedItem, BRIGHTNESS, updater));
-    }
-
-    private static SaturationCharacteristic createSaturationCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        return new SaturationCharacteristic(() -> {
-            double value = 0.0;
-            State state = taggedItem.getItem().getState();
-            if (state instanceof HSBType stateAsHSBType) {
-                value = stateAsHSBType.getSaturation().doubleValue();
-            } else if (state instanceof PercentType stateAsPercentType) {
-                value = stateAsPercentType.doubleValue();
-            }
-            return CompletableFuture.completedFuture(value);
-        }, (saturation) -> {
-            if (taggedItem.getBaseItem() instanceof ColorItem) {
-                taggedItem.sendCommandProxy(HomekitCommandType.SATURATION_COMMAND,
-                        new PercentType(saturation.intValue()));
-            } else {
-                LOGGER.warn("Item type {} is not supported for {}. Only Color type is supported.",
-                        taggedItem.getBaseItem().getType(), taggedItem.getName());
-            }
-        }, getSubscriber(taggedItem, SATURATION, updater), getUnsubscriber(taggedItem, SATURATION, updater));
+        var map = createMapping(taggedItem, ClosedCaptionsEnum.class);
+        return new ClosedCaptionsCharacteristic(() -> getEnumFromItem(taggedItem, map, ClosedCaptionsEnum.DISABLED),
+                (value) -> setValueFromEnum(taggedItem, value, map),
+                getSubscriber(taggedItem, CLOSED_CAPTIONS, updater),
+                getUnsubscriber(taggedItem, CLOSED_CAPTIONS, updater));
     }
 
     private static ColorTemperatureCharacteristic createColorTemperatureCharacteristic(HomekitTaggedItem taggedItem,
@@ -913,6 +737,30 @@ public class HomekitCharacteristicFactory {
                 getUnsubscriber(taggedItem, COLOR_TEMPERATURE, updater));
     }
 
+    private static ConfiguredNameCharacteristic createConfiguredNameCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        return new ConfiguredNameCharacteristic(() -> {
+            final State state = taggedItem.getItem().getState();
+            return CompletableFuture
+                    .completedFuture(state instanceof UnDefType ? taggedItem.getName() : state.toString());
+        }, (value) -> ((StringItem) taggedItem.getItem()).send(new StringType(value)),
+                getSubscriber(taggedItem, CONFIGURED_NAME, updater),
+                getUnsubscriber(taggedItem, CONFIGURED_NAME, updater));
+    }
+
+    private static CoolingThresholdTemperatureCharacteristic createCoolingThresholdCharacteristic(
+            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
+        double minValue = HomekitCharacteristicFactory.convertToCelsius(taggedItem.getConfigurationAsDouble(
+                HomekitTaggedItem.MIN_VALUE, CoolingThresholdTemperatureCharacteristic.DEFAULT_MIN_VALUE));
+        double maxValue = HomekitCharacteristicFactory.convertToCelsius(taggedItem.getConfigurationAsDouble(
+                HomekitTaggedItem.MAX_VALUE, CoolingThresholdTemperatureCharacteristic.DEFAULT_MAX_VALUE));
+        double step = getTemperatureStep(taggedItem, CoolingThresholdTemperatureCharacteristic.DEFAULT_STEP);
+        return new CoolingThresholdTemperatureCharacteristic(minValue, maxValue, step,
+                getTemperatureSupplier(taggedItem, minValue), setTemperatureConsumer(taggedItem),
+                getSubscriber(taggedItem, COOLING_THRESHOLD_TEMPERATURE, updater),
+                getUnsubscriber(taggedItem, COOLING_THRESHOLD_TEMPERATURE, updater));
+    }
+
     private static CurrentFanStateCharacteristic createCurrentFanStateCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
         var map = createMapping(taggedItem, CurrentFanStateEnum.class);
@@ -921,52 +769,43 @@ public class HomekitCharacteristicFactory {
                 getUnsubscriber(taggedItem, CURRENT_FAN_STATE, updater));
     }
 
-    private static TargetFanStateCharacteristic createTargetFanStateCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, TargetFanStateEnum.class);
-        return new TargetFanStateCharacteristic(() -> getEnumFromItem(taggedItem, map, TargetFanStateEnum.AUTO),
-                (targetState) -> setValueFromEnum(taggedItem, targetState, map),
-                getSubscriber(taggedItem, TARGET_FAN_STATE, updater),
-                getUnsubscriber(taggedItem, TARGET_FAN_STATE, updater));
+    private static CurrentHorizontalTiltAngleCharacteristic createCurrentHorizontalTiltAngleCharacteristic(
+            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
+        return new CurrentHorizontalTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0),
+                getSubscriber(taggedItem, CURRENT_HORIZONTAL_TILT_ANGLE, updater),
+                getUnsubscriber(taggedItem, CURRENT_HORIZONTAL_TILT_ANGLE, updater));
     }
 
-    private static RotationDirectionCharacteristic createRotationDirectionCharacteristic(HomekitTaggedItem taggedItem,
+    private static CurrentMediaStateCharacteristic createCurrentMediaStateCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, RotationDirectionEnum.class);
-        return new RotationDirectionCharacteristic(
-                () -> getEnumFromItem(taggedItem, map, RotationDirectionEnum.CLOCKWISE),
-                (value) -> setValueFromEnum(taggedItem, value, map),
-                getSubscriber(taggedItem, ROTATION_DIRECTION, updater),
-                getUnsubscriber(taggedItem, ROTATION_DIRECTION, updater));
+        var map = createMapping(taggedItem, CurrentMediaStateEnum.class);
+        return new CurrentMediaStateCharacteristic(
+                () -> getEnumFromItem(taggedItem, map, CurrentMediaStateEnum.UNKNOWN),
+                getSubscriber(taggedItem, CURRENT_MEDIA_STATE, updater),
+                getUnsubscriber(taggedItem, CURRENT_MEDIA_STATE, updater));
     }
 
-    private static SwingModeCharacteristic createSwingModeCharacteristic(HomekitTaggedItem taggedItem,
+    private static CurrentTiltAngleCharacteristic createCurrentTiltAngleCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, SwingModeEnum.class);
-        return new SwingModeCharacteristic(() -> getEnumFromItem(taggedItem, map, SwingModeEnum.SWING_DISABLED),
-                (value) -> setValueFromEnum(taggedItem, value, map), getSubscriber(taggedItem, SWING_MODE, updater),
-                getUnsubscriber(taggedItem, SWING_MODE, updater));
+        return new CurrentTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0),
+                getSubscriber(taggedItem, CURRENT_TILT_ANGLE, updater),
+                getUnsubscriber(taggedItem, CURRENT_TILT_ANGLE, updater));
     }
 
-    private static LockPhysicalControlsCharacteristic createLockPhysicalControlsCharacteristic(
+    private static CurrentVerticalTiltAngleCharacteristic createCurrentVerticalTiltAngleCharacteristic(
             HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, LockPhysicalControlsEnum.class);
-        return new LockPhysicalControlsCharacteristic(
-                () -> getEnumFromItem(taggedItem, map, LockPhysicalControlsEnum.CONTROL_LOCK_DISABLED),
-                (value) -> setValueFromEnum(taggedItem, value, map), getSubscriber(taggedItem, LOCK_CONTROL, updater),
-                getUnsubscriber(taggedItem, LOCK_CONTROL, updater));
+        return new CurrentVerticalTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0),
+                getSubscriber(taggedItem, CURRENT_VERTICAL_TILT_ANGLE, updater),
+                getUnsubscriber(taggedItem, CURRENT_VERTICAL_TILT_ANGLE, updater));
     }
 
-    private static RotationSpeedCharacteristic createRotationSpeedCharacteristic(HomekitTaggedItem item,
-            HomekitAccessoryUpdater updater) {
-        return new RotationSpeedCharacteristic(
-                item.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
-                        RotationSpeedCharacteristic.DEFAULT_MIN_VALUE),
-                item.getConfigurationAsDouble(HomekitTaggedItem.MAX_VALUE,
-                        RotationSpeedCharacteristic.DEFAULT_MAX_VALUE),
-                item.getConfigurationAsDouble(HomekitTaggedItem.STEP, RotationSpeedCharacteristic.DEFAULT_STEP),
-                getDoubleSupplier(item, 0), setDoubleConsumer(item), getSubscriber(item, ROTATION_SPEED, updater),
-                getUnsubscriber(item, ROTATION_SPEED, updater));
+    private static CurrentVisibilityStateCharacteristic createCurrentVisibilityStateCharacteristic(
+            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
+        var map = createMapping(taggedItem, CurrentVisibilityStateEnum.class, true);
+        return new CurrentVisibilityStateCharacteristic(
+                () -> getEnumFromItem(taggedItem, map, CurrentVisibilityStateEnum.HIDDEN),
+                getSubscriber(taggedItem, CURRENT_VISIBILITY, updater),
+                getUnsubscriber(taggedItem, CURRENT_VISIBILITY, updater));
     }
 
     private static SetDurationCharacteristic createDurationCharacteristic(HomekitTaggedItem taggedItem,
@@ -988,31 +827,33 @@ public class HomekitCharacteristicFactory {
                 getUnsubscriber(taggedItem, DURATION, updater));
     }
 
-    private static RemainingDurationCharacteristic createRemainingDurationCharacteristic(HomekitTaggedItem taggedItem,
+    private static FilterLifeLevelCharacteristic createFilterLifeLevelCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new RemainingDurationCharacteristic(getIntSupplier(taggedItem, 0),
-                getSubscriber(taggedItem, REMAINING_DURATION, updater),
-                getUnsubscriber(taggedItem, REMAINING_DURATION, updater));
+        return new FilterLifeLevelCharacteristic(getDoubleSupplier(taggedItem, 0),
+                getSubscriber(taggedItem, FILTER_LIFE_LEVEL, updater),
+                getUnsubscriber(taggedItem, FILTER_LIFE_LEVEL, updater));
     }
 
-    private static VolumeCharacteristic createVolumeCharacteristic(HomekitTaggedItem taggedItem,
+    private static ResetFilterIndicationCharacteristic createFilterResetCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new VolumeCharacteristic(getIntSupplier(taggedItem, 0),
-                (volume) -> ((NumberItem) taggedItem.getItem()).send(new DecimalType(volume)),
-                getSubscriber(taggedItem, DURATION, updater), getUnsubscriber(taggedItem, DURATION, updater));
+        return new ResetFilterIndicationCharacteristic(
+                (value) -> ((SwitchItem) taggedItem.getBaseItem()).send(OnOffType.ON));
     }
 
-    private static CoolingThresholdTemperatureCharacteristic createCoolingThresholdCharacteristic(
-            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
-        double minValue = HomekitCharacteristicFactory.convertToCelsius(taggedItem.getConfigurationAsDouble(
-                HomekitTaggedItem.MIN_VALUE, CoolingThresholdTemperatureCharacteristic.DEFAULT_MIN_VALUE));
-        double maxValue = HomekitCharacteristicFactory.convertToCelsius(taggedItem.getConfigurationAsDouble(
-                HomekitTaggedItem.MAX_VALUE, CoolingThresholdTemperatureCharacteristic.DEFAULT_MAX_VALUE));
-        double step = getTemperatureStep(taggedItem, CoolingThresholdTemperatureCharacteristic.DEFAULT_STEP);
-        return new CoolingThresholdTemperatureCharacteristic(minValue, maxValue, step,
-                getTemperatureSupplier(taggedItem, minValue), setTemperatureConsumer(taggedItem),
-                getSubscriber(taggedItem, COOLING_THRESHOLD_TEMPERATURE, updater),
-                getUnsubscriber(taggedItem, COOLING_THRESHOLD_TEMPERATURE, updater));
+    private static FirmwareRevisionCharacteristic createFirmwareRevisionCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        return new FirmwareRevisionCharacteristic(() -> {
+            final State state = taggedItem.getItem().getState();
+            return CompletableFuture.completedFuture(state instanceof UnDefType ? "" : state.toString());
+        });
+    }
+
+    private static HardwareRevisionCharacteristic createHardwareRevisionCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        return new HardwareRevisionCharacteristic(() -> {
+            final State state = taggedItem.getItem().getState();
+            return CompletableFuture.completedFuture(state instanceof UnDefType ? "" : state.toString());
+        });
     }
 
     private static HeatingThresholdTemperatureCharacteristic createHeatingThresholdCharacteristic(
@@ -1028,20 +869,122 @@ public class HomekitCharacteristicFactory {
                 getUnsubscriber(taggedItem, HEATING_THRESHOLD_TEMPERATURE, updater));
     }
 
-    private static CurrentRelativeHumidityCharacteristic createRelativeHumidityCharacteristic(
-            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
-        return new CurrentRelativeHumidityCharacteristic(getDoubleSupplier(taggedItem, 0.0),
-                getSubscriber(taggedItem, RELATIVE_HUMIDITY, updater),
-                getUnsubscriber(taggedItem, RELATIVE_HUMIDITY, updater));
-    }
-
-    private static OzoneDensityCharacteristic createOzoneDensityCharacteristic(final HomekitTaggedItem taggedItem,
+    private static HoldPositionCharacteristic createHoldPositionCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new OzoneDensityCharacteristic(
-                getDoubleSupplier(taggedItem,
-                        taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
-                                OzoneDensityCharacteristic.DEFAULT_MIN_VALUE)),
-                getSubscriber(taggedItem, OZONE_DENSITY, updater), getUnsubscriber(taggedItem, OZONE_DENSITY, updater));
+        final Item item = taggedItem.getBaseItem();
+        if (!(item instanceof SwitchItem || item instanceof RollershutterItem)) {
+            LOGGER.warn(
+                    "Item {} cannot be used for the HoldPosition characteristic; only SwitchItem and RollershutterItem are supported. Hold requests will be ignored.",
+                    item.getName());
+        }
+
+        return new HoldPositionCharacteristic(value -> {
+            if (!value) {
+                return;
+            }
+
+            if (item instanceof SwitchItem switchItem) {
+                switchItem.send(OnOffType.ON);
+            } else if (item instanceof RollershutterItem rollershutterItem) {
+                rollershutterItem.send(StopMoveType.STOP);
+            }
+        });
+    }
+
+    private static HueCharacteristic createHueCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        return new HueCharacteristic(() -> {
+            double value = 0.0;
+            State state = taggedItem.getItem().getState();
+            if (state instanceof HSBType stateAsHSBType) {
+                value = stateAsHSBType.getHue().doubleValue();
+            }
+            return CompletableFuture.completedFuture(value);
+        }, (hue) -> {
+            if (taggedItem.getBaseItem() instanceof ColorItem) {
+                taggedItem.sendCommandProxy(HomekitCommandType.HUE_COMMAND, new DecimalType(hue));
+            } else {
+                LOGGER.warn("Item type {} is not supported for {}. Only Color type is supported.",
+                        taggedItem.getBaseItem().getType(), taggedItem.getName());
+            }
+        }, getSubscriber(taggedItem, HUE, updater), getUnsubscriber(taggedItem, HUE, updater));
+    }
+
+    private static IdentifierCharacteristic createIdentifierCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        return new IdentifierCharacteristic(getIntSupplier(taggedItem, 1));
+    }
+
+    private static IdentifyCharacteristic createIdentifyCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        return new IdentifyCharacteristic((value) -> ((SwitchItem) taggedItem.getBaseItem()).send(OnOffType.ON));
+    }
+
+    private static InputDeviceTypeCharacteristic createInputDeviceTypeCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        var map = createMapping(taggedItem, InputDeviceTypeEnum.class);
+        return new InputDeviceTypeCharacteristic(() -> getEnumFromItem(taggedItem, map, InputDeviceTypeEnum.OTHER),
+                getSubscriber(taggedItem, INPUT_DEVICE_TYPE, updater),
+                getUnsubscriber(taggedItem, INPUT_DEVICE_TYPE, updater));
+    }
+
+    private static InputSourceTypeCharacteristic createInputSourceTypeCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        var map = createMapping(taggedItem, InputSourceTypeEnum.class);
+        return new InputSourceTypeCharacteristic(() -> getEnumFromItem(taggedItem, map, InputSourceTypeEnum.OTHER),
+                getSubscriber(taggedItem, INPUT_SOURCE_TYPE, updater),
+                getUnsubscriber(taggedItem, INPUT_SOURCE_TYPE, updater));
+    }
+
+    private static IsConfiguredCharacteristic createIsConfiguredCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        var map = createMapping(taggedItem, IsConfiguredEnum.class);
+        return new IsConfiguredCharacteristic(() -> getEnumFromItem(taggedItem, map, IsConfiguredEnum.NOT_CONFIGURED),
+                (value) -> setValueFromEnum(taggedItem, value, map), getSubscriber(taggedItem, CONFIGURED, updater),
+                getUnsubscriber(taggedItem, CONFIGURED, updater));
+    }
+
+    private static LockPhysicalControlsCharacteristic createLockPhysicalControlsCharacteristic(
+            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
+        var map = createMapping(taggedItem, LockPhysicalControlsEnum.class);
+        return new LockPhysicalControlsCharacteristic(
+                () -> getEnumFromItem(taggedItem, map, LockPhysicalControlsEnum.CONTROL_LOCK_DISABLED),
+                (value) -> setValueFromEnum(taggedItem, value, map), getSubscriber(taggedItem, LOCK_CONTROL, updater),
+                getUnsubscriber(taggedItem, LOCK_CONTROL, updater));
+    }
+
+    private static ManufacturerCharacteristic createManufacturerCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        return new ManufacturerCharacteristic(() -> {
+            final State state = taggedItem.getItem().getState();
+            return CompletableFuture.completedFuture(state instanceof UnDefType ? "" : state.toString());
+        });
+    }
+
+    private static ModelCharacteristic createModelCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        return new ModelCharacteristic(() -> {
+            final State state = taggedItem.getItem().getState();
+            return CompletableFuture.completedFuture(state instanceof UnDefType ? "" : state.toString());
+        });
+    }
+
+    private static MuteCharacteristic createMuteCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        BooleanItemReader muteReader = new BooleanItemReader(taggedItem.getItem(),
+                OnOffType.from(!taggedItem.isInverted()),
+                taggedItem.isInverted() ? OpenClosedType.CLOSED : OpenClosedType.OPEN);
+        return new MuteCharacteristic(() -> CompletableFuture.completedFuture(muteReader.getValue()),
+                (value) -> taggedItem.send(OnOffType.from(value)), getSubscriber(taggedItem, MUTE, updater),
+                getUnsubscriber(taggedItem, MUTE, updater));
+    }
+
+    private static NameCharacteristic createNameCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        return new NameCharacteristic(() -> {
+            final State state = taggedItem.getItem().getState();
+            return CompletableFuture.completedFuture(state instanceof UnDefType ? "" : state.toString());
+        });
     }
 
     private static NitrogenDioxideDensityCharacteristic createNitrogenDioxideDensityCharacteristic(
@@ -1054,23 +997,22 @@ public class HomekitCharacteristicFactory {
                 getUnsubscriber(taggedItem, NITROGEN_DIOXIDE_DENSITY, updater));
     }
 
-    private static SulphurDioxideDensityCharacteristic createSulphurDioxideDensityCharacteristic(
-            final HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
-        return new SulphurDioxideDensityCharacteristic(
-                getDoubleSupplier(taggedItem,
-                        taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
-                                SulphurDioxideDensityCharacteristic.DEFAULT_MIN_VALUE)),
-                getSubscriber(taggedItem, SULPHUR_DIOXIDE_DENSITY, updater),
-                getUnsubscriber(taggedItem, SULPHUR_DIOXIDE_DENSITY, updater));
+    private static ObstructionDetectedCharacteristic createObstructionDetectedCharacteristic(
+            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
+        return new ObstructionDetectedCharacteristic(
+                () -> CompletableFuture.completedFuture(taggedItem.getItem().getState() == OnOffType.ON
+                        || taggedItem.getItem().getState() == OpenClosedType.OPEN),
+                getSubscriber(taggedItem, OBSTRUCTION_STATUS, updater),
+                getUnsubscriber(taggedItem, OBSTRUCTION_STATUS, updater));
     }
 
-    private static PM25DensityCharacteristic createPM25DensityCharacteristic(final HomekitTaggedItem taggedItem,
+    private static OzoneDensityCharacteristic createOzoneDensityCharacteristic(final HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new PM25DensityCharacteristic(
+        return new OzoneDensityCharacteristic(
                 getDoubleSupplier(taggedItem,
                         taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
-                                PM25DensityCharacteristic.DEFAULT_MIN_VALUE)),
-                getSubscriber(taggedItem, PM25_DENSITY, updater), getUnsubscriber(taggedItem, PM25_DENSITY, updater));
+                                OzoneDensityCharacteristic.DEFAULT_MIN_VALUE)),
+                getSubscriber(taggedItem, OZONE_DENSITY, updater), getUnsubscriber(taggedItem, OZONE_DENSITY, updater));
     }
 
     private static PM10DensityCharacteristic createPM10DensityCharacteristic(final HomekitTaggedItem taggedItem,
@@ -1082,63 +1024,99 @@ public class HomekitCharacteristicFactory {
                 getSubscriber(taggedItem, PM10_DENSITY, updater), getUnsubscriber(taggedItem, PM10_DENSITY, updater));
     }
 
-    private static VOCDensityCharacteristic createVOCDensityCharacteristic(final HomekitTaggedItem taggedItem,
+    private static PM25DensityCharacteristic createPM25DensityCharacteristic(final HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new VOCDensityCharacteristic(
-                taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
-                        VOCDensityCharacteristic.DEFAULT_MIN_VALUE),
-                taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MAX_VALUE,
-                        VOCDensityCharacteristic.DEFAULT_MAX_VALUE),
-                taggedItem.getConfigurationAsDouble(HomekitTaggedItem.STEP, VOCDensityCharacteristic.DEFAULT_STEP),
+        return new PM25DensityCharacteristic(
                 getDoubleSupplier(taggedItem,
                         taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
-                                VOCDensityCharacteristic.DEFAULT_MIN_VALUE)),
-                getSubscriber(taggedItem, VOC_DENSITY, updater), getUnsubscriber(taggedItem, VOC_DENSITY, updater));
+                                PM25DensityCharacteristic.DEFAULT_MIN_VALUE)),
+                getSubscriber(taggedItem, PM25_DENSITY, updater), getUnsubscriber(taggedItem, PM25_DENSITY, updater));
     }
 
-    private static FilterLifeLevelCharacteristic createFilterLifeLevelCharacteristic(HomekitTaggedItem taggedItem,
+    private static CurrentRelativeHumidityCharacteristic createRelativeHumidityCharacteristic(
+            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
+        return new CurrentRelativeHumidityCharacteristic(getDoubleSupplier(taggedItem, 0.0),
+                getSubscriber(taggedItem, RELATIVE_HUMIDITY, updater),
+                getUnsubscriber(taggedItem, RELATIVE_HUMIDITY, updater));
+    }
+
+    private static PictureModeCharacteristic createPictureModeCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new FilterLifeLevelCharacteristic(getDoubleSupplier(taggedItem, 0),
-                getSubscriber(taggedItem, FILTER_LIFE_LEVEL, updater),
-                getUnsubscriber(taggedItem, FILTER_LIFE_LEVEL, updater));
+        var map = createMapping(taggedItem, PictureModeEnum.class);
+        return new PictureModeCharacteristic(() -> getEnumFromItem(taggedItem, map, PictureModeEnum.OTHER),
+                (value) -> setValueFromEnum(taggedItem, value, map), getSubscriber(taggedItem, PICTURE_MODE, updater),
+                getUnsubscriber(taggedItem, PICTURE_MODE, updater));
     }
 
-    private static ResetFilterIndicationCharacteristic createFilterResetCharacteristic(HomekitTaggedItem taggedItem,
+    private static PowerModeCharacteristic createPowerModeCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new ResetFilterIndicationCharacteristic(
-                (value) -> ((SwitchItem) taggedItem.getBaseItem()).send(OnOffType.ON));
+        var map = createMapping(taggedItem, PowerModeEnum.class, true);
+        return new PowerModeCharacteristic((value) -> setValueFromEnum(taggedItem, value, map));
     }
 
-    private static ActiveCharacteristic createActiveCharacteristic(HomekitTaggedItem taggedItem,
+    private static RemainingDurationCharacteristic createRemainingDurationCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, ActiveEnum.class, false);
-        return new ActiveCharacteristic(() -> getEnumFromItem(taggedItem, map, ActiveEnum.INACTIVE),
-                (value) -> setValueFromEnum(taggedItem, value, map), getSubscriber(taggedItem, ACTIVE, updater),
-                getUnsubscriber(taggedItem, ACTIVE, updater));
+        return new RemainingDurationCharacteristic(getIntSupplier(taggedItem, 0),
+                getSubscriber(taggedItem, REMAINING_DURATION, updater),
+                getUnsubscriber(taggedItem, REMAINING_DURATION, updater));
     }
 
-    private static ConfiguredNameCharacteristic createConfiguredNameCharacteristic(HomekitTaggedItem taggedItem,
+    private static RemoteKeyCharacteristic createRemoteKeyCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new ConfiguredNameCharacteristic(() -> {
-            final State state = taggedItem.getItem().getState();
-            return CompletableFuture
-                    .completedFuture(state instanceof UnDefType ? taggedItem.getName() : state.toString());
-        }, (value) -> ((StringItem) taggedItem.getItem()).send(new StringType(value)),
-                getSubscriber(taggedItem, CONFIGURED_NAME, updater),
-                getUnsubscriber(taggedItem, CONFIGURED_NAME, updater));
+        var map = createMapping(taggedItem, RemoteKeyEnum.class);
+        return new RemoteKeyCharacteristic((value) -> setValueFromEnum(taggedItem, value, map));
     }
 
-    private static ActiveIdentifierCharacteristic createActiveIdentifierCharacteristic(HomekitTaggedItem taggedItem,
+    private static RotationDirectionCharacteristic createRotationDirectionCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new ActiveIdentifierCharacteristic(getIntSupplier(taggedItem, 1), setIntConsumer(taggedItem),
-                getSubscriber(taggedItem, ACTIVE_IDENTIFIER, updater),
-                getUnsubscriber(taggedItem, ACTIVE_IDENTIFIER, updater));
+        var map = createMapping(taggedItem, RotationDirectionEnum.class);
+        return new RotationDirectionCharacteristic(
+                () -> getEnumFromItem(taggedItem, map, RotationDirectionEnum.CLOCKWISE),
+                (value) -> setValueFromEnum(taggedItem, value, map),
+                getSubscriber(taggedItem, ROTATION_DIRECTION, updater),
+                getUnsubscriber(taggedItem, ROTATION_DIRECTION, updater));
     }
 
-    private static RemoteKeyCharacteristic createRemoteKeyCharacteristic(HomekitTaggedItem taggedItem,
+    private static RotationSpeedCharacteristic createRotationSpeedCharacteristic(HomekitTaggedItem item,
             HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, RemoteKeyEnum.class);
-        return new RemoteKeyCharacteristic((value) -> setValueFromEnum(taggedItem, value, map));
+        return new RotationSpeedCharacteristic(
+                item.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
+                        RotationSpeedCharacteristic.DEFAULT_MIN_VALUE),
+                item.getConfigurationAsDouble(HomekitTaggedItem.MAX_VALUE,
+                        RotationSpeedCharacteristic.DEFAULT_MAX_VALUE),
+                item.getConfigurationAsDouble(HomekitTaggedItem.STEP, RotationSpeedCharacteristic.DEFAULT_STEP),
+                getDoubleSupplier(item, 0), setDoubleConsumer(item), getSubscriber(item, ROTATION_SPEED, updater),
+                getUnsubscriber(item, ROTATION_SPEED, updater));
+    }
+
+    private static SaturationCharacteristic createSaturationCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        return new SaturationCharacteristic(() -> {
+            double value = 0.0;
+            State state = taggedItem.getItem().getState();
+            if (state instanceof HSBType stateAsHSBType) {
+                value = stateAsHSBType.getSaturation().doubleValue();
+            } else if (state instanceof PercentType stateAsPercentType) {
+                value = stateAsPercentType.doubleValue();
+            }
+            return CompletableFuture.completedFuture(value);
+        }, (saturation) -> {
+            if (taggedItem.getBaseItem() instanceof ColorItem) {
+                taggedItem.sendCommandProxy(HomekitCommandType.SATURATION_COMMAND,
+                        new PercentType(saturation.intValue()));
+            } else {
+                LOGGER.warn("Item type {} is not supported for {}. Only Color type is supported.",
+                        taggedItem.getBaseItem().getType(), taggedItem.getName());
+            }
+        }, getSubscriber(taggedItem, SATURATION, updater), getUnsubscriber(taggedItem, SATURATION, updater));
+    }
+
+    private static SerialNumberCharacteristic createSerialNumberCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        return new SerialNumberCharacteristic(() -> {
+            final State state = taggedItem.getItem().getState();
+            return CompletableFuture.completedFuture(state instanceof UnDefType ? "" : state.toString());
+        });
     }
 
     private static SleepDiscoveryModeCharacteristic createSleepDiscoveryModeCharacteristic(HomekitTaggedItem taggedItem,
@@ -1150,65 +1128,98 @@ public class HomekitCharacteristicFactory {
                 getUnsubscriber(taggedItem, SLEEP_DISCOVERY_MODE, updater));
     }
 
-    private static PowerModeCharacteristic createPowerModeCharacteristic(HomekitTaggedItem taggedItem,
+    private static StatusActiveCharacteristic createStatusActiveCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, PowerModeEnum.class, true);
-        return new PowerModeCharacteristic((value) -> setValueFromEnum(taggedItem, value, map));
+        return new StatusActiveCharacteristic(
+                () -> CompletableFuture.completedFuture(taggedItem.getItem().getState() == OnOffType.ON
+                        || taggedItem.getItem().getState() == OpenClosedType.OPEN),
+                getSubscriber(taggedItem, ACTIVE_STATUS, updater), getUnsubscriber(taggedItem, ACTIVE_STATUS, updater));
     }
 
-    private static ClosedCaptionsCharacteristic createClosedCaptionsCharacteristic(HomekitTaggedItem taggedItem,
+    private static StatusFaultCharacteristic createStatusFaultCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, ClosedCaptionsEnum.class);
-        return new ClosedCaptionsCharacteristic(() -> getEnumFromItem(taggedItem, map, ClosedCaptionsEnum.DISABLED),
-                (value) -> setValueFromEnum(taggedItem, value, map),
-                getSubscriber(taggedItem, CLOSED_CAPTIONS, updater),
-                getUnsubscriber(taggedItem, CLOSED_CAPTIONS, updater));
+        var map = createMapping(taggedItem, StatusFaultEnum.class);
+        return new StatusFaultCharacteristic(() -> getEnumFromItem(taggedItem, map, StatusFaultEnum.NO_FAULT),
+                getSubscriber(taggedItem, FAULT_STATUS, updater), getUnsubscriber(taggedItem, FAULT_STATUS, updater));
     }
 
-    private static PictureModeCharacteristic createPictureModeCharacteristic(HomekitTaggedItem taggedItem,
+    private static StatusLowBatteryCharacteristic createStatusLowBatteryCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, PictureModeEnum.class);
-        return new PictureModeCharacteristic(() -> getEnumFromItem(taggedItem, map, PictureModeEnum.OTHER),
-                (value) -> setValueFromEnum(taggedItem, value, map), getSubscriber(taggedItem, PICTURE_MODE, updater),
-                getUnsubscriber(taggedItem, PICTURE_MODE, updater));
+        BigDecimal lowThreshold = taggedItem.getConfiguration(HomekitTaggedItem.BATTERY_LOW_THRESHOLD,
+                BigDecimal.valueOf(20));
+        BooleanItemReader lowBatteryReader = new BooleanItemReader(taggedItem.getItem(),
+                OnOffType.from(!taggedItem.isInverted()),
+                taggedItem.isInverted() ? OpenClosedType.CLOSED : OpenClosedType.OPEN, lowThreshold, true);
+        return new StatusLowBatteryCharacteristic(
+                () -> CompletableFuture.completedFuture(
+                        lowBatteryReader.getValue() ? StatusLowBatteryEnum.LOW : StatusLowBatteryEnum.NORMAL),
+                getSubscriber(taggedItem, BATTERY_LOW_STATUS, updater),
+                getUnsubscriber(taggedItem, BATTERY_LOW_STATUS, updater));
     }
 
-    private static IsConfiguredCharacteristic createIsConfiguredCharacteristic(HomekitTaggedItem taggedItem,
+    private static StatusTamperedCharacteristic createStatusTamperedCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, IsConfiguredEnum.class);
-        return new IsConfiguredCharacteristic(() -> getEnumFromItem(taggedItem, map, IsConfiguredEnum.NOT_CONFIGURED),
-                (value) -> setValueFromEnum(taggedItem, value, map), getSubscriber(taggedItem, CONFIGURED, updater),
-                getUnsubscriber(taggedItem, CONFIGURED, updater));
+        var map = createMapping(taggedItem, StatusTamperedEnum.class);
+        return new StatusTamperedCharacteristic(() -> getEnumFromItem(taggedItem, map, StatusTamperedEnum.NOT_TAMPERED),
+                getSubscriber(taggedItem, TAMPERED_STATUS, updater),
+                getUnsubscriber(taggedItem, TAMPERED_STATUS, updater));
     }
 
-    private static InputSourceTypeCharacteristic createInputSourceTypeCharacteristic(HomekitTaggedItem taggedItem,
+    private static SulphurDioxideDensityCharacteristic createSulphurDioxideDensityCharacteristic(
+            final HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
+        return new SulphurDioxideDensityCharacteristic(
+                getDoubleSupplier(taggedItem,
+                        taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
+                                SulphurDioxideDensityCharacteristic.DEFAULT_MIN_VALUE)),
+                getSubscriber(taggedItem, SULPHUR_DIOXIDE_DENSITY, updater),
+                getUnsubscriber(taggedItem, SULPHUR_DIOXIDE_DENSITY, updater));
+    }
+
+    private static SwingModeCharacteristic createSwingModeCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, InputSourceTypeEnum.class);
-        return new InputSourceTypeCharacteristic(() -> getEnumFromItem(taggedItem, map, InputSourceTypeEnum.OTHER),
-                getSubscriber(taggedItem, INPUT_SOURCE_TYPE, updater),
-                getUnsubscriber(taggedItem, INPUT_SOURCE_TYPE, updater));
+        var map = createMapping(taggedItem, SwingModeEnum.class);
+        return new SwingModeCharacteristic(() -> getEnumFromItem(taggedItem, map, SwingModeEnum.SWING_DISABLED),
+                (value) -> setValueFromEnum(taggedItem, value, map), getSubscriber(taggedItem, SWING_MODE, updater),
+                getUnsubscriber(taggedItem, SWING_MODE, updater));
     }
 
-    private static CurrentVisibilityStateCharacteristic createCurrentVisibilityStateCharacteristic(
+    private static TargetFanStateCharacteristic createTargetFanStateCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        var map = createMapping(taggedItem, TargetFanStateEnum.class);
+        return new TargetFanStateCharacteristic(() -> getEnumFromItem(taggedItem, map, TargetFanStateEnum.AUTO),
+                (targetState) -> setValueFromEnum(taggedItem, targetState, map),
+                getSubscriber(taggedItem, TARGET_FAN_STATE, updater),
+                getUnsubscriber(taggedItem, TARGET_FAN_STATE, updater));
+    }
+
+    private static TargetHorizontalTiltAngleCharacteristic createTargetHorizontalTiltAngleCharacteristic(
             HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, CurrentVisibilityStateEnum.class, true);
-        return new CurrentVisibilityStateCharacteristic(
-                () -> getEnumFromItem(taggedItem, map, CurrentVisibilityStateEnum.HIDDEN),
-                getSubscriber(taggedItem, CURRENT_VISIBILITY, updater),
-                getUnsubscriber(taggedItem, CURRENT_VISIBILITY, updater));
+        return new TargetHorizontalTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0),
+                setAngleConsumer(taggedItem), getSubscriber(taggedItem, TARGET_HORIZONTAL_TILT_ANGLE, updater),
+                getUnsubscriber(taggedItem, TARGET_HORIZONTAL_TILT_ANGLE, updater));
     }
 
-    private static IdentifierCharacteristic createIdentifierCharacteristic(HomekitTaggedItem taggedItem,
+    private static TargetMediaStateCharacteristic createTargetMediaStateCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        return new IdentifierCharacteristic(getIntSupplier(taggedItem, 1));
+        var map = createMapping(taggedItem, TargetMediaStateEnum.class);
+        return new TargetMediaStateCharacteristic(() -> getEnumFromItem(taggedItem, map, TargetMediaStateEnum.STOP),
+                (value) -> setValueFromEnum(taggedItem, value, map),
+                getSubscriber(taggedItem, TARGET_MEDIA_STATE, updater),
+                getUnsubscriber(taggedItem, TARGET_MEDIA_STATE, updater));
     }
 
-    private static InputDeviceTypeCharacteristic createInputDeviceTypeCharacteristic(HomekitTaggedItem taggedItem,
+    private static TargetTiltAngleCharacteristic createTargetTiltAngleCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, InputDeviceTypeEnum.class);
-        return new InputDeviceTypeCharacteristic(() -> getEnumFromItem(taggedItem, map, InputDeviceTypeEnum.OTHER),
-                getSubscriber(taggedItem, INPUT_DEVICE_TYPE, updater),
-                getUnsubscriber(taggedItem, INPUT_DEVICE_TYPE, updater));
+        return new TargetTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0), setAngleConsumer(taggedItem),
+                getSubscriber(taggedItem, TARGET_TILT_ANGLE, updater),
+                getUnsubscriber(taggedItem, TARGET_TILT_ANGLE, updater));
+    }
+
+    private static TargetVerticalTiltAngleCharacteristic createTargetVerticalTiltAngleCharacteristic(
+            HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
+        return new TargetVerticalTiltAngleCharacteristic(getAngleSupplier(taggedItem, 0), setAngleConsumer(taggedItem),
+                getSubscriber(taggedItem, TARGET_HORIZONTAL_TILT_ANGLE, updater),
+                getUnsubscriber(taggedItem, TARGET_HORIZONTAL_TILT_ANGLE, updater));
     }
 
     private static TargetVisibilityStateCharacteristic createTargetVisibilityStateCharacteristic(
@@ -1221,6 +1232,27 @@ public class HomekitCharacteristicFactory {
                 getUnsubscriber(taggedItem, TARGET_VISIBILITY_STATE, updater));
     }
 
+    private static VOCDensityCharacteristic createVOCDensityCharacteristic(final HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        return new VOCDensityCharacteristic(
+                taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
+                        VOCDensityCharacteristic.DEFAULT_MIN_VALUE),
+                taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MAX_VALUE,
+                        VOCDensityCharacteristic.DEFAULT_MAX_VALUE),
+                taggedItem.getConfigurationAsDouble(HomekitTaggedItem.STEP, VOCDensityCharacteristic.DEFAULT_STEP),
+                getDoubleSupplier(taggedItem,
+                        taggedItem.getConfigurationAsDouble(HomekitTaggedItem.MIN_VALUE,
+                                VOCDensityCharacteristic.DEFAULT_MIN_VALUE)),
+                getSubscriber(taggedItem, VOC_DENSITY, updater), getUnsubscriber(taggedItem, VOC_DENSITY, updater));
+    }
+
+    private static VolumeCharacteristic createVolumeCharacteristic(HomekitTaggedItem taggedItem,
+            HomekitAccessoryUpdater updater) {
+        return new VolumeCharacteristic(getIntSupplier(taggedItem, 0),
+                (volume) -> ((NumberItem) taggedItem.getItem()).send(new DecimalType(volume)),
+                getSubscriber(taggedItem, DURATION, updater), getUnsubscriber(taggedItem, DURATION, updater));
+    }
+
     private static VolumeSelectorCharacteristic createVolumeSelectorCharacteristic(HomekitTaggedItem taggedItem,
             HomekitAccessoryUpdater updater) {
         if (taggedItem.getItem() instanceof DimmerItem) {
@@ -1240,37 +1272,4 @@ public class HomekitCharacteristicFactory {
                 getSubscriber(taggedItem, VOLUME_CONTROL_TYPE, updater),
                 getUnsubscriber(taggedItem, VOLUME_CONTROL_TYPE, updater));
     }
-
-    private static CurrentMediaStateCharacteristic createCurrentMediaStateCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, CurrentMediaStateEnum.class);
-        return new CurrentMediaStateCharacteristic(
-                () -> getEnumFromItem(taggedItem, map, CurrentMediaStateEnum.UNKNOWN),
-                getSubscriber(taggedItem, CURRENT_MEDIA_STATE, updater),
-                getUnsubscriber(taggedItem, CURRENT_MEDIA_STATE, updater));
-    }
-
-    private static TargetMediaStateCharacteristic createTargetMediaStateCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        var map = createMapping(taggedItem, TargetMediaStateEnum.class);
-        return new TargetMediaStateCharacteristic(() -> getEnumFromItem(taggedItem, map, TargetMediaStateEnum.STOP),
-                (value) -> setValueFromEnum(taggedItem, value, map),
-                getSubscriber(taggedItem, TARGET_MEDIA_STATE, updater),
-                getUnsubscriber(taggedItem, TARGET_MEDIA_STATE, updater));
-    }
-
-    private static MuteCharacteristic createMuteCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        BooleanItemReader muteReader = new BooleanItemReader(taggedItem.getItem(),
-                OnOffType.from(!taggedItem.isInverted()),
-                taggedItem.isInverted() ? OpenClosedType.CLOSED : OpenClosedType.OPEN);
-        return new MuteCharacteristic(() -> CompletableFuture.completedFuture(muteReader.getValue()),
-                (value) -> taggedItem.send(OnOffType.from(value)), getSubscriber(taggedItem, MUTE, updater),
-                getUnsubscriber(taggedItem, MUTE, updater));
-    }
-
-    private static IdentifyCharacteristic createIdentifyCharacteristic(HomekitTaggedItem taggedItem,
-            HomekitAccessoryUpdater updater) {
-        return new IdentifyCharacteristic((value) -> ((SwitchItem) taggedItem.getBaseItem()).send(OnOffType.ON));
-    }
 }