[homekit] implement StatelessProgrammableSwitch (#17129)

also supports adding multiple of them in a group, by supporting ServiceIndex
as an optional characteristic

refs #9969

Signed-off-by: Cody Cutrer <cody@cutrer.us>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
Cody Cutrer 2024-07-23 00:22:27 -06:00 committed by Ciprian Pascu
parent cc6757dd24
commit 665729437f
11 changed files with 428 additions and 239 deletions

View File

@ -694,6 +694,19 @@ or using UI
![sensor_ui_config.png](doc/sensor_ui_config.png)
### Stateless Programmable Switch Groups
To expose multiple Stateless Programmable Switches as a single accessory with multiple buttons (aka a scene controller), you need to configure ServiceLabel on the accessory group and ServiceIndex on each switch.
Note that in the Home app, the individual switch names will be ignored, and will simply be displayed as "Button 1", "Button 2", etc. (for ARABIC_NUMERALS style).
```java
Group gSceneController "Scene Controller" { homekit="AccessoryGroup"[ServiceLabel="ARABIC_NUMERALS"] }
Switch Button1 "Switch A" (gSceneController) { homekit="StatelessProgrammableSwitch"[ServiceIndex=1] }
Switch Button2 "Switch B" (gSceneController) { homekit="StatelessProgrammableSwitch"[ServiceIndex=2] }
Switch Button3 "Switch C" (gSceneController) { homekit="StatelessProgrammableSwitch"[ServiceIndex=3] }
Switch Button4 "Switch D" (gSceneController) { homekit="StatelessProgrammableSwitch"[ServiceIndex=4] }
```
## Supported accessory types
For configuration options, the default values are in parentheses.
@ -716,228 +729,231 @@ Note that even though these characteristics can be linked to an item, they are n
All accessories also support the following optional characteristic that can be linked to a Switch item:
* Identify (receives `ON` command when the user wishes to identify the accessory)
| Accessory Tag | Mandatory Characteristics | Optional Characteristics | Supported openHAB item types | Description | Configuration Options | Valid Enum Values |
|----------------------|-----------------------------|-----------------------------|-----------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|
| AirQualitySensor | | | | Air Quality Sensor which can measure different parameters | | |
| | AirQuality | | Number, String, Switch | Air quality state | | UNKNOWN (0, OFF), EXCELLENT (1, ON), GOOD (2), FAIR (3), INFERIOR (4), POOR (5) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | NitrogenDioxideDensity | Number | NO2 density in micrograms/m3, max 1000 | | |
| | | OzoneDensity | Number | Ozone density in micrograms/m3, max 1000 | | |
| | | PM10Density | Number | PM10 micrometer particulate density in micrograms/m3, max 1000 | | |
| | | PM25Density | Number | PM2.5 micrometer particulate density in micrograms/m3, max 1000 | | |
| | | SulphurDioxideDensity | Number | SO2 density in micrograms/m3, max 1000 | | |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| | | VOCDensity | Number | VOC Density in micrograms/m3, default max 1000 | minValue (0), maxValue (100), step (1) | |
| BasicFan | | | | Fan. A BasicFan is a subset of Fan, but the Home app allows you to customize the icon of the accessory to show a ceiling fan. | | |
| | OnState | | Dimmer, Switch | Accessory current working status. A value of "ON"/"OPEN" indicates that the accessory is active and is functioning without any errors. | inverted (false) | |
| | | RotationDirection | Number, Switch | Rotation direction. | inverted (false) | CLOCKWISE (0, OFF), COUNTER_CLOCKWISE (1, ON) |
| | | RotationSpeed | Dimmer, Number | Fan rotation speed in % (1-100) | | |
| Battery | | | | Accessory with battery. Battery can be chargeable (configuration chargeable:true) and non-chargeable (configuration chargeable:false) | | |
| | BatteryLevel | | Number | Battery level 0% to 100% | | |
| | BatteryChargingState | | Contact, Dimmer, Switch | Mandatory only for chargeable battery. ON/OPEN = battery is charging | | |
| | BatteryLowStatus | | Contact, Number, Switch | Battery low indicator. ON/OPEN = battery level is low; for number if the value is below the lowThreshold, then it is low. Default is 20. | inverted (false), lowThreshold (20) | |
| CarbonDioxideSensor | | | | Carbon Dioxide Sensor | | |
| | CarbonDioxideDetectedState | | Contact, Dimmer, Switch, Number, String | carbon dioxide sensor state | inverted (false) | NORMAL (0, OFF, CLOSED), ABNORMAL (1, ON, OPEN) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | CarbonDioxideLevel | Number | Carbon dioxide level in ppm, max 100000 | | |
| | | CarbonDioxidePeakLevel | Number | highest detected level (ppm) of carbon dioxide detected by a sensor, max 100000 | | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| CarbonMonoxideSensor | | | | Carbon monoxide Sensor | | |
| | CarbonMonoxideDetectedState | | Contact, Dimmer, Switch, Number, String | Carbon monoxide sensor state | inverted (false) | NORMAL (0, OFF, CLOSED), ABNORMAL (1, ON, OPEN) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | CarbonMonoxideLevel | Number | Carbon monoxide level in ppm, max 100 | | |
| | | CarbonMonoxidePeakLevel | Number | highest detected level (ppm) of carbon monoxide detected by a sensor, max 100 | | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| ContactSensor | | | | Contact Sensor, An accessory with on/off state that can be viewed in HomeKit but not changed such as a contact sensor for a door or window | | |
| | ContactSensorState | | Contact, Dimmer, Number, String, Switch | Contact sensor state | inverted (false) | DETECTED (0, OFF, CLOSED), NOT_DETECTED (1, ON, OPEN) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| Door | | | | Motorized door. One Rollershutter item covers all mandatory characteristics. see examples below. | | |
| | CurrentPosition | | Dimmer, Number, Rollershutter | Current position of motorized door | | |
| | PositionState | | Number, Rollershutter, String | Position state. If no state is provided, "STOPPED" is used. | | DECREASING (0), INCREASING (1), STOPPED (2) |
| | TargetPosition | | Dimmer, Number, Rollershutter | Target position of motorized door | | |
| | | HoldPosition | Rollershutter, Switch | Motorized door should stop at its current position. ON is sent to Switch items. STOP is sent to Rollershutter items. Only supported by 3rd party Home apps (such as Elgato Eve) | | |
| | | ObstructionStatus | Contact, Dimmer, Switch | Current status of obstruction sensor. ON-obstruction detected, OFF - no obstruction | | |
| Fan | | | | Fan | | |
| | ActiveStatus | | Dimmer, Switch | Accessory current working status. A value of "ON"/"OPEN" indicates that the accessory is active and is functioning without any errors. | | |
| | | CurrentFanState | Number, String | Current fan state. | | INACTIVE (0), IDLE (1), BLOWING_AIR (2) |
| | | LockControl | Number, Switch, String | Status of physical control lock | inverted (false) | CONTROL_LOCK_DISABLED (0, OFF), CONTROL_LOCK_ENABLED (1, ON) |
| | | RotationDirection | Number, Switch, String | Rotation direction | inverted (false) | CLOCKWISE (0, OFF), COUNTER_CLOCKWISE (1, ON) |
| | | RotationSpeed | Dimmer, Number | Fan rotation speed in % (1-100) | | |
| | | SwingMode | Number, Switch, String | Swing mode | inverted (false) | SWING_DISABLED (0, OFF), SWING_ENABLED (1, ON) |
| | | TargetFanState | Number, Switch, String | Target fan state | inverted (false) | MANUAL (0, OFF), AUTO (1, ON) |
| Faucet | | | | Faucet or shower. It should be used in combination with Valve or/and HeaterCooler. | | |
| | Active | | Contact, Dimmer, Switch | Accessory current working status | inverted (false) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| Filter | | | | Accessory with filter maintenance indicator | | |
| | FilterChangeIndication | | Contact, Dimmer, Number, String, Switch | Filter change indicator | inverted (false) | NO_CHANGED_NEEDED (0, OFF, CLOSED), CHANGE_NEEDED (1, ON, OPEN) |
| | | FilterLifeLevel | Number | Current filter life level. 0% to 100% | | |
| | | FilterResetIndication | Switch | Send "filter reset" action triggered by user in iOS Home app to openHAB ("ON" = reset requested by user). | | |
| GarageDoorOpener | | | | A garage door opener. | | |
| | CurrentDoorState | | Contact, Switch, Number, String | Current door state. | inverted (false) | OPEN (0, ON, OPEN), CLOSED (1, OFF, CLOSED), OPENING (2), CLOSING (3), STOPPED (4) |
| | ObstructionStatus | | Contact, Switch | Current status of obstruction sensor. ON-obstruction detected, OFF - no obstruction | inverted (false) | |
| | TargetDoorState | | Contact, Switch, Number, String | Target door state. | inverted (false) | OPEN (0, ON, OPEN), CLOSED (1, OFF, CLOSED) |
| HeaterCooler | | | | Heater or/and cooler device | | |
| | ActiveStatus | | Dimmer, Switch | Accessory current working status. A value of "ON"/"OPEN" indicates that the accessory is active and is functioning without any errors. | | |
| | CurrentHeaterCoolerState | | Number, String | Current heater/cooler mode. | | INACTIVE (0), IDLE (1), HEATING (2), COOLING (3) |
| | CurrentTemperature | | Number | Current temperature | minValue (0), maxValue (100), step (0.1) | |
| | TargetHeaterCoolerState | | Number, String | Target heater/cooler mode. | | AUTO (0, OFF), HEAT (1, ON), COOL (2) [*](#customizable-enum) |
| | | CoolingThresholdTemperature | Number | Maximum temperature that must be reached before cooling is turned on | minValue (10), maxValue (35), step (0.1) | |
| | | HeatingThresholdTemperature | Number | Minimum temperature that must be reached before heating is turned on | minValue (0), maxValue (25), step (0.1) | |
| | | LockControl | Number, Switch, String | Status of physical control lock | inverted (false) | CONTROL_LOCK_DISABLED (0, OFF), CONTROL_LOCK_ENABLED (1, ON) |
| | | RotationSpeed | Number | Fan rotation speed in % (1-100) | | |
| | | SwingMode | Number, Switch, String | Swing mode | inverted (false) | SWING_DISABLED (0, OFF), SWING_ENABLED (1, ON) |
| HumiditySensor | | | | Relative Humidity Sensor providing read-only values | | |
| | RelativeHumidity | | Number | Relative humidity in % between 0 and 100 | homekitMultiplicator = {number to multiply result with} | |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| InputSource | | | | Input source linked service. Can only be used with Television. | | |
| | | ConfiguredName | String | Name of the input source configured in the iOS Home app. User can rename the source in iOS Home app and this characteristic can be used to reflect change in openHAB and sync name changes from openHAB to Home app. | | |
| | | Configured | Contact, Dimmer, Switch | If the source is configured on the device. Non-configured inputs will not show up in the Home app. - ON/OPEN = show, OFF/CLOSED = hide. Default is ON. Can also be configured via metadata, e.g. [Configured=true] | | |
| | | CurrentVisibility | Contact, Dimmer, Number, String, Switch | If the source has been hidden by the user. Can also be configured via metadata, e.g. [CurrentVisibility=false] | inverted (false) | SHOWN (0, ON), HIDDEN (1, OFF) |
| | | Identifier | Number | The identifier of the source, to be used with the ActiveIdentifier characteristic. Can also be configured via metadata, e.g. [Identifier=1] | | |
| | | InputDeviceType | String | Type of the input device. possible values (OTHER, TV, RECORDING, TUNER, PLAYBACK, AUDIO_SYSTEM). Custom mapping can be defined at item level. Can also be configured via metadata, e.g. [InputDeviceType="OTHER"]. | | |
| | | InputSourceType | String | Type of the input source. possible values (OTHER, HOME_SCREEN, TUNER, HDMI, COMPOSITE_VIDEO, S_VIDEO, COMPONENT_VIDEO, DVI, AIRPLAY, USB, APPLICATION). Custom mapping can be defined at item level. Can also be configured via metadata, e.g. [InputSourceType="OTHER"]. | | |
| | | TargetVisibilityState | Switch, Number, String | The desired visibility state of the input source. | inverted (false) | SHOWN (0, ON), HIDDEN (1, OFF) |
| IrrigationSystem | | | | An accessory that represents multiple water valves and accommodates a programmed scheduled. | | |
| | Active | | Contact, Dimmer, Number, String, Switch | If the irrigation system as a whole is enabled. This must be ON if any of the valves are also enabled. | inverted (false) | INACTIVE (0, OFF), ACTIVE (1, ON) |
| | InUseStatus | | Contact, Dimmer, Number, String, Switch | If the irrigation system as a whole is running. This must be ON if any of the valves are ON. | inverted (false) | NOT_IN_USE (0, OFF, CLOSED), IN_USE (1, ON, OPEN) |
| | ProgramMode | | String | The current program mode of the irrigation system. Possible values (NO_SCHEDULED - no programs scheduled, SCHEDULED - program scheduled, SCHEDULED_MANUAL - program scheduled, currently overriden to manual mode). | | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | RemainingDuration | Number | The remaining duration for all scheduled valves in the current program in seconds. | | |
| LeakSensor | | | | Leak Sensor | | |
| | LeakDetectedState | | Contact, Dimmer, Number, String, Switch | Leak sensor state | inverted (false) | LEAK_NOT_DETECTED (0, OFF, CLOSED), LEAK_DETECTED (1, ON, OPEN) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| LightSensor | | | | Light sensor | | |
| | LightLevel | | Number | Light level in lux | minValue (0.0001), maxValue (100000) | |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| Lighting | | | | A lightbulb, can have further optional parameters for brightness, hue, etc | | |
| | OnState | | Switch | State of the light - ON/OFF | | |
| | | Brightness | Dimmer, Color | Brightness in % (1-100). See "Usage of dimmer modes" for configuration details. | | |
| | | ColorTemperature | Dimmer, Number | Color temperature. If the item is a Number with no units, it is represented in mireds. The default value range is from 50 to 400 (2500 K to 20,000 K). If the item is a Dimmer, it will be transformed linearly to mireds. Color temperature should not be used in combination with hue, saturation and brightness. | minValue (50), maxValue (400), inverted | |
| | | Hue | Dimmer, Color | Hue | | |
| | | Saturation | Dimmer, Color | Saturation in % (1-100) | | |
| Lock | | | | A Lock Mechanism | inverted (false) | |
| | LockCurrentState | | Contact, Number, String, Switch | Current state of lock mechanism | inverted (false) | UNSECURED (0, OFF, CLOSED), SECURED (1, ON, OPEN), JAMMED (2), UNKNOWN (3) |
| | LockTargetState | | Number, String, Switch | Target state of lock mechanism | inverted (false) | UNSECURED (0, OFF), SECURED (1, ON) |
| Microphone | | | | Microphone accessory | | |
| | Mute | | Contact, Dimmer, Switch | Mute indication. ON/OPEN = microphone is muted | inverted (false) | |
| | | Volume | Number | Microphone volume from 0% to 100% | | |
| MotionSensor | | | | Motion Sensor | | |
| | MotionDetectedState | | Contact, Dimmer, Switch | Motion sensor state (ON=motion detected, OFF=no motion) | inverted (false) | |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| OccupancySensor | | | | Occupancy Sensor | | |
| | OccupancyDetectedState | | Contact, Dimmer, Number, String, Switch | Occupancy sensor state | inverted (false) | NOT_DETECTED (0, OFF, CLOSED), DETECTED (1, ON, OPEN) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| Outlet | | | | An accessory that can be turned off and on. While similar to a lightbulb, this will be presented differently in the Siri grammar and iOS apps | | |
| | InUseStatus | | Contact, Dimmer, Switch | Indicates whether the outlet has an appliance e.g., a floor lamp, physically plugged in. This characteristic is set to True even if the plugged-in appliance is off. | inverted (false) | |
| | OnState | | Dimmer, Switch | State of the outlet - ON/OFF | | |
| SecuritySystem | | | | Security system. | | |
| | CurrentSecuritySystemState | | Number, String | Current state of the security system | | STAY_ARM (0), AWAY_ARM (1), NIGHT_ARM (2), DISARMED (3), TRIGGERED (4) |
| | TargetSecuritySystemState | | Number, String | Requested state of the security system. While the requested state is not DISARM, and the current state is DISARMED, HomeKit will display "Arming...", for example during an exit delay. | | STAY_ARM (0), AWAY_ARM (1), NIGHT_ARM (2), DISARM (3) [*](#customizable-enum) |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| Slat | | | | Slat which tilts on a vertical or a horizontal axis. Configuration "type:horizontal" or "type:vertical" | | |
| | CurrentSlatState | | Number, String | Current slat state. | | FIXED (0), JAMMED (1), SWINGING (2) |
| | | CurrentTiltAngle | Dimmer, Number | Number Item = current angle of slats. values -90 to 90. A value of 0 indicates that the slats are rotated to a fully open position. Dimmer Item = the percentage of openness (0%-100%) | | |
| | | SwingMode | Number, Switch, String | Swing mode | inverted (false) | SWING_DISABLED (0, OFF), SWING_ENABLED (1, ON) |
| | | TargetTiltAngle | Dimmer, Number | Number Item = target angle of slats (-90 to +90). Dimmer Item = the percentage of openness (0%-100%) | | |
| SmartSpeaker | | | | Smart speaker accessory with Play/Stop/Pause control | | |
| | CurrentMediaState | | Number, String | Current smart speaker state | | PLAY (0), PAUSE (1), STOP (2), UNKNOWN (3) |
| | TargetMediaState | | Number, String | Target smart speaker state | | PLAY (0), PAUSE (1), STOP (2) |
| | | ConfiguredName | String | Name of the speaker accessory configured in iOS Home app. User can rename the speaker in iOS Home app and this characteristic can be used to reflect change in openHAB and sync name changes from openHAB to Home app. | | |
| | | Mute | Contact, Switch | Mute indication. ON/OPEN = speaker is muted | inverted (false) | |
| | | Volume | Number | Speaker volume from 0% to 100% | | |
| SmokeSensor | | | | Smoke Sensor | | |
| | SmokeDetectedState | | Contact, Dimmer, Number, String, Switch | Smoke sensor state | inverted (false) | NOT_DETECTED (0, OFF, CLOSED), DETECTED (1, ON, OPEN) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| Speaker | | | | Speaker accessory | | |
| | Mute | | Contact, Dimmer, Switch | Mute indication. ON/OPEN = speaker is muted | inverted (false) | |
| | | Active | Contact, Dimmer, Number, String, Switch | Accessory current working status | inverted (false) | INACTIVE (0, OFF), ACTIVE (1, ON) |
| | | Volume | Number | Speaker volume from 0% to 100% | | |
| Switchable | | | | An accessory that can be turned off and on. While similar to a lightbulb, this will be presented differently in the Siri grammar and iOS apps | | |
| | OnState | | Dimmer, Switch | State of the switch - ON/OFF | | |
| Television | | | | Television accessory with inputs | | |
| | Active | | Contact, Dimmer, Number, String, Switch | State of the television (on/off) | inverted (false) | INACTIVE (0, OFF), ACTIVE (1, ON) |
| | | ActiveIdentifier | Number | The input that is currently active (based on its identifier). Can also be configured via metadata, e.g. [ActiveIdentifier=1] | | |
| | | Brightness | Dimmer | Screen brightness in % (1-100). | | |
| | | ClosedCaptions | Contact, Dimmer, Number, String, Switch | Indicates closed captions are enabled. Can also be configured via metadata, e.g. [ClosedCaptions=true] | inverted (false) | DISABLED (0, OFF), ENABLED (1, ON) |
| | | ConfiguredName | String | Name of the television accessory configured in the iOS Home app. User can rename the television in iOS Home app and this characteristic can be used to reflect change in openHAB and sync name changes from openHAB to Home app. | | |
| | | CurrentMediaState | Number, String | Current television state. | | PLAY (0), PAUSE (1), STOP (2), UNKNOWN (3) |
| | | PictureMode | Number, String | Selected picture mode. | | OTHER (0), STANDARD (1), CALIBRATED (2), CALIBRATED_DARK (3), VIVID (4), GAME (5), COMPUTER (6), CUSTOM (7) |
| | | PowerMode | Switch, Number, String | This oddly named characteristic will receive an ON command when the user requests to open the TV's menu. | inverted (false) | SHOW (0, ON), HIDE (1, OFF) |
| | | RemoteKey | String | Receives a keypress event. | | |
| | | SleepDiscoveryMode | Contact, Dimmer, Number, String, Switch | Indicates if the television is discoverable while in standby mode. Can also be configured via metadata, e.g. [SleepDiscoveryMode=true] | inverted (false) | NOT_DISCOVERABLE (0, OFF), ALWAYS_DISCOVERABLE (1, ON) |
| | | TargetMediaState | Number, String | Target television state. | | PLAY (0), PAUSE (1), STOP (2) |
| TelevisionSpeaker | | | | An accessory that can be added to a Television in order to control the speaker associated with it. | | |
| | Mute | | Switch | If the television is muted. ON = muted, OFF = not muted. | | |
| | | Active | Contact, Dimmer, Number, String, Switch | Unknown. This characteristic is undocumented by Apple, but is still available. | inverted (false) | INACTIVE (0, OFF), ACTIVE (1, ON) |
| | | Volume | Dimmer, Number | Current volume. | | |
| | | VolumeControlType | String | The type of control available. This will default to infer based on what other items are linked. NONE = status only, no control; RELATIVE = INCREMENT/DECREMENT only, no status; RELATIVE_WITH_CURRENT = INCREMENT/DECREMENT only with status; ABSOLUTE = direct status and control. Can also be configured via metadata, e.g. [VolumeControlType="ABSOLUTE"]. | | |
| | | VolumeSelector | Dimmer, String | If linked to a dimmer item, will send INCREASE/DECREASE commands. If linked to a string item, will send INCREMENT and DECREMENT. | | |
| TemperatureSensor | | | | Temperature sensor | | |
| | CurrentTemperature | | Number | current temperature | minValue (0), maxValue (100), step (0.1) | |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| Thermostat | | | | A thermostat requires at least one of TargetTemperature, CoolingThresholdTemperature, or HeatingThresholdTemperature must be provided. | | |
| | CurrentHeatingCoolingMode | | Number, String | Current heating cooling mode | | OFF (0, OFF), HEAT (1, ON), COOL (2) |
| | CurrentTemperature | | Number | Current temperature. | minValue (0), maxValue (100), step (0.1) | |
| | TargetHeatingCoolingMode | | Number, String | Target heating cooling mode | | OFF (0, OFF), HEAT (1, ON), COOL (2), AUTO (3) [*](#customizable-enum) |
| | | TargetTemperature | Number | Target temperature. If CoolingThresholdTemperature and HeatingThresholdTemperature are also provided, this characteristic is used when the thermostat is in HEAT or COOL mode. In AUTO mode, this characteristic receives the average of the two thresholds. | minValue (10), maxValue (38), step (0.1) | |
| | | CoolingThresholdTemperature | Number | Maximum temperature that must be reached before cooling is turned on. If TargetTemperature is not provided, this characteristic will also be used in COOL mode. | minValue (10), maxValue (35), step (0.1) | |
| | | HeatingThresholdTemperature | Number | Minimum temperature that must be reached before heating is turned on. If TargetTemperature is not provided, this characteristic will also be used in HEAT mode. | minValue (0), maxValue (25), step (0.1) | |
| | | RelativeHumidity | Number | Relative humidity in % between 0 and 100. | | |
| | | TargetRelativeHumidity | Number | Target relative humidity in % between 0 and 100. | | |
| | | TemperatureUnit | Number, String, Switch | The units the accessory itself uses to display the temperature. Can also be configured via metadata, e.g. [TemperatureUnit="CELSIUS"] | | CELSIUS (0, OFF), FAHRENHEIT (1, ON) |
| Valve | | | | Valve | ValveType = ["Generic", "Irrigation", "Shower", "Faucet"] ("Generic") | |
| | ActiveStatus | | Dimmer, Switch | Accessory current working status. A value of "ON"/"OPEN" indicates that the accessory is active and is functioning without any errors. | | |
| | InUseStatus | | Contact, Dimmer, Switch | Indicates whether fluid flowing through the valve. A value of "ON"/"OPEN" indicates that fluid is flowing. | inverted (false) | |
| | | Duration | Number | Defines how long a valve should be set to ʼIn Useʼ in second. | homekitDefaultDuration = {default duration in seconds} | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | RemainingDuration | Number | Describes the remaining duration on the accessory. the remaining duration increases/decreases from the accessoryʼs usual countdown. i.e. changes from 90 to 80 in a second. | | |
| Window | | | | Motorized window. One Rollershutter item covers all mandatory characteristics. see examples below. | | |
| | CurrentPosition | | Dimmer, Number, Rollershutter | Current position of motorized window | | |
| | PositionState | | Number, Rollershutter, String | Position state. If no state is provided, "STOPPED" is used. | | DECREASING (0), INCREASING (1), STOPPED (2) |
| | TargetPosition | | Dimmer, Number, Rollershutter | Target position of motorized window | | |
| | | HoldPosition | Rollershutter, Switch | Motorized door should stop at its current position. ON is sent to Switch items. STOP is sent to Rollershutter items. Only supported by 3rd party Home apps (such as Elgato Eve) | | |
| | | ObstructionStatus | Contact, Dimmer, Switch | Current status of obstruction sensor. ON-obstruction detected, OFF - no obstruction | | |
| WindowCovering | | | | Window covering / blinds. One Rollershutter item covers all mandatory characteristics. see examples below. | | |
| | CurrentPosition | | Dimmer, Number, Rollershutter | Current position of window covering | | |
| | PositionState | | Number, Rollershutter, String | Position state. If no state is provided, "STOPPED" is used. | | DECREASING (0), INCREASING (1), STOPPED (2) |
| | TargetPosition | | Dimmer, Number, Rollershutter | Target position of window covering | | |
| | | CurrentHorizontalTiltAngle | Dimmer, Number | Number Item = current angle of horizontal slats. values -90 to 90. A value of 0 indicates that the slats are rotated to a fully open position. A value of -90 indicates that the slats are rotated all the way in a direction where the user-facing edge is higher than the window-facing edge. Dimmer Item = the percentage of openness (0%-100%) | | |
| | | CurrentVerticalTiltAngle | Dimmer, Number | Number Item = current angle of vertical slats (-90 to +90) . Dimmer Item = the percentage of openness (0%-100%) | | |
| | | HoldPosition | Rollershutter, Switch | Motorized door should stop at its current position. ON is sent to Switch items. STOP is sent to Rollershutter items. Only supported by 3rd party Home apps (such as Elgato Eve) | | |
| | | ObstructionStatus | Contact, Dimmer, Switch | Current status of obstruction sensor. ON-obstruction detected, OFF - no obstruction | | |
| | | TargetHorizontalTiltAngle | Dimmer, Number | Number Item = target angle of horizontal slats (-90 to +90). Dimmer Item = the percentage of openness (0%-100%) | | |
| | | TargetVerticalTiltAngle | Dimmer, Number | Number Item = target angle of vertical slats. Dimmer Item = the percentage of openness (0%-100%) | | |
| Accessory Tag | Mandatory Characteristics | Optional Characteristics | Supported openHAB item types | Description | Configuration Options | Valid Enum Values |
|-----------------------------|-----------------------------|-----------------------------|-----------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|
| AirQualitySensor | | | | Air Quality Sensor which can measure different parameters | | |
| | AirQuality | | Number, String, Switch | Air quality state | | UNKNOWN (0, OFF), EXCELLENT (1, ON), GOOD (2), FAIR (3), INFERIOR (4), POOR (5) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | NitrogenDioxideDensity | Number | NO2 density in micrograms/m3, max 1000 | | |
| | | OzoneDensity | Number | Ozone density in micrograms/m3, max 1000 | | |
| | | PM10Density | Number | PM10 micrometer particulate density in micrograms/m3, max 1000 | | |
| | | PM25Density | Number | PM2.5 micrometer particulate density in micrograms/m3, max 1000 | | |
| | | SulphurDioxideDensity | Number | SO2 density in micrograms/m3, max 1000 | | |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| | | VOCDensity | Number | VOC Density in micrograms/m3, default max 1000 | minValue (0), maxValue (100), step (1) | |
| BasicFan | | | | Fan. A BasicFan is a subset of Fan, but the Home app allows you to customize the icon of the accessory to show a ceiling fan. | | |
| | OnState | | Dimmer, Switch | Accessory current working status. A value of "ON"/"OPEN" indicates that the accessory is active and is functioning without any errors. | inverted (false) | |
| | | RotationDirection | Number, Switch | Rotation direction. | inverted (false) | CLOCKWISE (0, OFF), COUNTER_CLOCKWISE (1, ON) |
| | | RotationSpeed | Dimmer, Number | Fan rotation speed in % (1-100) | | |
| Battery | | | | Accessory with battery. Battery can be chargeable (configuration chargeable:true) and non-chargeable (configuration chargeable:false) | | |
| | BatteryLevel | | Number | Battery level 0% to 100% | | |
| | BatteryChargingState | | Contact, Dimmer, Switch | Mandatory only for chargeable battery. ON/OPEN = battery is charging | | |
| | BatteryLowStatus | | Contact, Number, Switch | Battery low indicator. ON/OPEN = battery level is low; for number if the value is below the lowThreshold, then it is low. Default is 20. | inverted (false), lowThreshold (20) | |
| CarbonDioxideSensor | | | | Carbon Dioxide Sensor | | |
| | CarbonDioxideDetectedState | | Contact, Dimmer, Switch, Number, String | carbon dioxide sensor state | inverted (false) | NORMAL (0, OFF, CLOSED), ABNORMAL (1, ON, OPEN) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | CarbonDioxideLevel | Number | Carbon dioxide level in ppm, max 100000 | | |
| | | CarbonDioxidePeakLevel | Number | highest detected level (ppm) of carbon dioxide detected by a sensor, max 100000 | | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| CarbonMonoxideSensor | | | | Carbon monoxide Sensor | | |
| | CarbonMonoxideDetectedState | | Contact, Dimmer, Switch, Number, String | Carbon monoxide sensor state | inverted (false) | NORMAL (0, OFF, CLOSED), ABNORMAL (1, ON, OPEN) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | CarbonMonoxideLevel | Number | Carbon monoxide level in ppm, max 100 | | |
| | | CarbonMonoxidePeakLevel | Number | highest detected level (ppm) of carbon monoxide detected by a sensor, max 100 | | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| ContactSensor | | | | Contact Sensor, An accessory with on/off state that can be viewed in HomeKit but not changed such as a contact sensor for a door or window | | |
| | ContactSensorState | | Contact, Dimmer, Number, String, Switch | Contact sensor state | inverted (false) | DETECTED (0, OFF, CLOSED), NOT_DETECTED (1, ON, OPEN) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| Door | | | | Motorized door. One Rollershutter item covers all mandatory characteristics. see examples below. | | |
| | CurrentPosition | | Dimmer, Number, Rollershutter | Current position of motorized door | | |
| | PositionState | | Number, Rollershutter, String | Position state. If no state is provided, "STOPPED" is used. | | DECREASING (0), INCREASING (1), STOPPED (2) |
| | TargetPosition | | Dimmer, Number, Rollershutter | Target position of motorized door | | |
| | | HoldPosition | Rollershutter, Switch | Motorized door should stop at its current position. ON is sent to Switch items. STOP is sent to Rollershutter items. Only supported by 3rd party Home apps (such as Elgato Eve) | | |
| | | ObstructionStatus | Contact, Dimmer, Switch | Current status of obstruction sensor. ON-obstruction detected, OFF - no obstruction | | |
| Fan | | | | Fan | | |
| | ActiveStatus | | Dimmer, Switch | Accessory current working status. A value of "ON"/"OPEN" indicates that the accessory is active and is functioning without any errors. | | |
| | | CurrentFanState | Number, String | Current fan state. | | INACTIVE (0), IDLE (1), BLOWING_AIR (2) |
| | | LockControl | Number, Switch, String | Status of physical control lock | inverted (false) | CONTROL_LOCK_DISABLED (0, OFF), CONTROL_LOCK_ENABLED (1, ON) |
| | | RotationDirection | Number, Switch, String | Rotation direction | inverted (false) | CLOCKWISE (0, OFF), COUNTER_CLOCKWISE (1, ON) |
| | | RotationSpeed | Dimmer, Number | Fan rotation speed in % (1-100) | | |
| | | SwingMode | Number, Switch, String | Swing mode | inverted (false) | SWING_DISABLED (0, OFF), SWING_ENABLED (1, ON) |
| | | TargetFanState | Number, Switch, String | Target fan state | inverted (false) | MANUAL (0, OFF), AUTO (1, ON) |
| Faucet | | | | Faucet or shower. It should be used in combination with Valve or/and HeaterCooler. | | |
| | Active | | Contact, Dimmer, Switch | Accessory current working status | inverted (false) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| Filter | | | | Accessory with filter maintenance indicator | | |
| | FilterChangeIndication | | Contact, Dimmer, Number, String, Switch | Filter change indicator | inverted (false) | NO_CHANGED_NEEDED (0, OFF, CLOSED), CHANGE_NEEDED (1, ON, OPEN) |
| | | FilterLifeLevel | Number | Current filter life level. 0% to 100% | | |
| | | FilterResetIndication | Switch | Send "filter reset" action triggered by user in iOS Home app to openHAB ("ON" = reset requested by user). | | |
| GarageDoorOpener | | | | A garage door opener. | | |
| | CurrentDoorState | | Contact, Switch, Number, String | Current door state. | inverted (false) | OPEN (0, ON, OPEN), CLOSED (1, OFF, CLOSED), OPENING (2), CLOSING (3), STOPPED (4) |
| | ObstructionStatus | | Contact, Switch | Current status of obstruction sensor. ON-obstruction detected, OFF - no obstruction | inverted (false) | |
| | TargetDoorState | | Contact, Switch, Number, String | Target door state. | inverted (false) | OPEN (0, ON, OPEN), CLOSED (1, OFF, CLOSED) |
| HeaterCooler | | | | Heater or/and cooler device | | |
| | ActiveStatus | | Dimmer, Switch | Accessory current working status. A value of "ON"/"OPEN" indicates that the accessory is active and is functioning without any errors. | | |
| | CurrentHeaterCoolerState | | Number, String | Current heater/cooler mode. | | INACTIVE (0), IDLE (1), HEATING (2), COOLING (3) |
| | CurrentTemperature | | Number | Current temperature | minValue (0), maxValue (100), step (0.1) | |
| | TargetHeaterCoolerState | | Number, String | Target heater/cooler mode. | | AUTO (0, OFF), HEAT (1, ON), COOL (2) [*](#customizable-enum) |
| | | CoolingThresholdTemperature | Number | Maximum temperature that must be reached before cooling is turned on | minValue (10), maxValue (35), step (0.1) | |
| | | HeatingThresholdTemperature | Number | Minimum temperature that must be reached before heating is turned on | minValue (0), maxValue (25), step (0.1) | |
| | | LockControl | Number, Switch, String | Status of physical control lock | inverted (false) | CONTROL_LOCK_DISABLED (0, OFF), CONTROL_LOCK_ENABLED (1, ON) |
| | | RotationSpeed | Number | Fan rotation speed in % (1-100) | | |
| | | SwingMode | Number, Switch, String | Swing mode | inverted (false) | SWING_DISABLED (0, OFF), SWING_ENABLED (1, ON) |
| HumiditySensor | | | | Relative Humidity Sensor providing read-only values | | |
| | RelativeHumidity | | Number | Relative humidity in % between 0 and 100 | homekitMultiplicator = {number to multiply result with} | |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| InputSource | | | | Input source linked service. Can only be used with Television. | | |
| | | ConfiguredName | String | Name of the input source configured in the iOS Home app. User can rename the source in iOS Home app and this characteristic can be used to reflect change in openHAB and sync name changes from openHAB to Home app. | | |
| | | Configured | Contact, Dimmer, Switch | If the source is configured on the device. Non-configured inputs will not show up in the Home app. - ON/OPEN = show, OFF/CLOSED = hide. Default is ON. Can also be configured via metadata, e.g. [Configured=true] | | |
| | | CurrentVisibility | Contact, Dimmer, Number, String, Switch | If the source has been hidden by the user. Can also be configured via metadata, e.g. [CurrentVisibility=false] | inverted (false) | SHOWN (0, ON), HIDDEN (1, OFF) |
| | | Identifier | Number | The identifier of the source, to be used with the ActiveIdentifier characteristic. Can also be configured via metadata, e.g. [Identifier=1] | | |
| | | InputDeviceType | String | Type of the input device. possible values (OTHER, TV, RECORDING, TUNER, PLAYBACK, AUDIO_SYSTEM). Custom mapping can be defined at item level. Can also be configured via metadata, e.g. [InputDeviceType="OTHER"]. | | |
| | | InputSourceType | String | Type of the input source. possible values (OTHER, HOME_SCREEN, TUNER, HDMI, COMPOSITE_VIDEO, S_VIDEO, COMPONENT_VIDEO, DVI, AIRPLAY, USB, APPLICATION). Custom mapping can be defined at item level. Can also be configured via metadata, e.g. [InputSourceType="OTHER"]. | | |
| | | TargetVisibilityState | Switch, Number, String | The desired visibility state of the input source. | inverted (false) | SHOWN (0, ON), HIDDEN (1, OFF) |
| IrrigationSystem | | | | An accessory that represents multiple water valves and accommodates a programmed scheduled. | | |
| | Active | | Contact, Dimmer, Number, String, Switch | If the irrigation system as a whole is enabled. This must be ON if any of the valves are also enabled. | inverted (false) | INACTIVE (0, OFF), ACTIVE (1, ON) |
| | InUseStatus | | Contact, Dimmer, Number, String, Switch | If the irrigation system as a whole is running. This must be ON if any of the valves are ON. | inverted (false) | NOT_IN_USE (0, OFF, CLOSED), IN_USE (1, ON, OPEN) |
| | ProgramMode | | String | The current program mode of the irrigation system. Possible values (NO_SCHEDULED - no programs scheduled, SCHEDULED - program scheduled, SCHEDULED_MANUAL - program scheduled, currently overriden to manual mode). | | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | RemainingDuration | Number | The remaining duration for all scheduled valves in the current program in seconds. | | |
| LeakSensor | | | | Leak Sensor | | |
| | LeakDetectedState | | Contact, Dimmer, Number, String, Switch | Leak sensor state | inverted (false) | LEAK_NOT_DETECTED (0, OFF, CLOSED), LEAK_DETECTED (1, ON, OPEN) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| LightSensor | | | | Light sensor | | |
| | LightLevel | | Number | Light level in lux | minValue (0.0001), maxValue (100000) | |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| Lighting | | | | A lightbulb, can have further optional parameters for brightness, hue, etc | | |
| | OnState | | Switch | State of the light - ON/OFF | | |
| | | Brightness | Dimmer, Color | Brightness in % (1-100). See "Usage of dimmer modes" for configuration details. | | |
| | | ColorTemperature | Dimmer, Number | Color temperature. If the item is a Number with no units, it is represented in mireds. The default value range is from 50 to 400 (2500 K to 20,000 K). If the item is a Dimmer, it will be transformed linearly to mireds. Color temperature should not be used in combination with hue, saturation and brightness. | minValue (50), maxValue (400), inverted | |
| | | Hue | Dimmer, Color | Hue | | |
| | | Saturation | Dimmer, Color | Saturation in % (1-100) | | |
| Lock | | | | A Lock Mechanism | inverted (false) | |
| | LockCurrentState | | Contact, Number, String, Switch | Current state of lock mechanism | inverted (false) | UNSECURED (0, OFF, CLOSED), SECURED (1, ON, OPEN), JAMMED (2), UNKNOWN (3) |
| | LockTargetState | | Number, String, Switch | Target state of lock mechanism | inverted (false) | UNSECURED (0, OFF), SECURED (1, ON) |
| Microphone | | | | Microphone accessory | | |
| | Mute | | Contact, Dimmer, Switch | Mute indication. ON/OPEN = microphone is muted | inverted (false) | |
| | | Volume | Number | Microphone volume from 0% to 100% | | |
| MotionSensor | | | | Motion Sensor | | |
| | MotionDetectedState | | Contact, Dimmer, Switch | Motion sensor state (ON=motion detected, OFF=no motion) | inverted (false) | |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| OccupancySensor | | | | Occupancy Sensor | | |
| | OccupancyDetectedState | | Contact, Dimmer, Number, String, Switch | Occupancy sensor state | inverted (false) | NOT_DETECTED (0, OFF, CLOSED), DETECTED (1, ON, OPEN) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| Outlet | | | | An accessory that can be turned off and on. While similar to a lightbulb, this will be presented differently in the Siri grammar and iOS apps | | |
| | InUseStatus | | Contact, Dimmer, Switch | Indicates whether the outlet has an appliance e.g., a floor lamp, physically plugged in. This characteristic is set to True even if the plugged-in appliance is off. | inverted (false) | |
| | OnState | | Dimmer, Switch | State of the outlet - ON/OFF | | |
| SecuritySystem | | | | Security system. | | |
| | CurrentSecuritySystemState | | Number, String | Current state of the security system | | STAY_ARM (0), AWAY_ARM (1), NIGHT_ARM (2), DISARMED (3), TRIGGERED (4) |
| | TargetSecuritySystemState | | Number, String | Requested state of the security system. While the requested state is not DISARM, and the current state is DISARMED, HomeKit will display "Arming...", for example during an exit delay. | | STAY_ARM (0), AWAY_ARM (1), NIGHT_ARM (2), DISARM (3) [*](#customizable-enum) |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| Slat | | | | Slat which tilts on a vertical or a horizontal axis. Configuration "type:horizontal" or "type:vertical" | | |
| | CurrentSlatState | | Number, String | Current slat state. | | FIXED (0), JAMMED (1), SWINGING (2) |
| | | CurrentTiltAngle | Dimmer, Number | Number Item = current angle of slats. values -90 to 90. A value of 0 indicates that the slats are rotated to a fully open position. Dimmer Item = the percentage of openness (0%-100%) | | |
| | | SwingMode | Number, Switch, String | Swing mode | inverted (false) | SWING_DISABLED (0, OFF), SWING_ENABLED (1, ON) |
| | | TargetTiltAngle | Dimmer, Number | Number Item = target angle of slats (-90 to +90). Dimmer Item = the percentage of openness (0%-100%) | | |
| SmartSpeaker | | | | Smart speaker accessory with Play/Stop/Pause control | | |
| | CurrentMediaState | | Number, String | Current smart speaker state | | PLAY (0), PAUSE (1), STOP (2), UNKNOWN (3) |
| | TargetMediaState | | Number, String | Target smart speaker state | | PLAY (0), PAUSE (1), STOP (2) |
| | | ConfiguredName | String | Name of the speaker accessory configured in iOS Home app. User can rename the speaker in iOS Home app and this characteristic can be used to reflect change in openHAB and sync name changes from openHAB to Home app. | | |
| | | Mute | Contact, Switch | Mute indication. ON/OPEN = speaker is muted | inverted (false) | |
| | | Volume | Number | Speaker volume from 0% to 100% | | |
| SmokeSensor | | | | Smoke Sensor | | |
| | SmokeDetectedState | | Contact, Dimmer, Number, String, Switch | Smoke sensor state | inverted (false) | NOT_DETECTED (0, OFF, CLOSED), DETECTED (1, ON, OPEN) |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| Speaker | | | | Speaker accessory | | |
| | Mute | | Contact, Dimmer, Switch | Mute indication. ON/OPEN = speaker is muted | inverted (false) | |
| | | Active | Contact, Dimmer, Number, String, Switch | Accessory current working status | inverted (false) | INACTIVE (0, OFF), ACTIVE (1, ON) |
| | | Volume | Number | Speaker volume from 0% to 100% | | |
| StatelessProgrammableSwitch | | | | A stateless programmable switch is a button or scene controller that simply sends an event to Home when it is pressed, allowing automations to occur. See [Stateless Programmable Switch Groups](#Stateless-Programmable-Switch-Groups) for configuring multiple in one accessory. | | |
| | ProgrammableSwitchEvent | | Contact, Number, String, Switch | The button press event. Note that the event will be forwarded to Home for every _update_ of the item, not just on change. | inverted (false) | SINGLE_PRESS (0, ON, OPEN), DOUBLE_PRESS (1), LONG_PRESS (2) [*](#customizable-enum) |
| | | Volume | Number | Speaker volume from 0% to 100% | | |
| Switchable | | | | An accessory that can be turned off and on. While similar to a lightbulb, this will be presented differently in the Siri grammar and iOS apps | | |
| | OnState | | Dimmer, Switch | State of the switch - ON/OFF | | |
| Television | | | | Television accessory with inputs | | |
| | Active | | Contact, Dimmer, Number, String, Switch | State of the television (on/off) | inverted (false) | INACTIVE (0, OFF), ACTIVE (1, ON) |
| | | ActiveIdentifier | Number | The input that is currently active (based on its identifier). Can also be configured via metadata, e.g. [ActiveIdentifier=1] | | |
| | | Brightness | Dimmer | Screen brightness in % (1-100). | | |
| | | ClosedCaptions | Contact, Dimmer, Number, String, Switch | Indicates closed captions are enabled. Can also be configured via metadata, e.g. [ClosedCaptions=true] | inverted (false) | DISABLED (0, OFF), ENABLED (1, ON) |
| | | ConfiguredName | String | Name of the television accessory configured in the iOS Home app. User can rename the television in iOS Home app and this characteristic can be used to reflect change in openHAB and sync name changes from openHAB to Home app. | | |
| | | CurrentMediaState | Number, String | Current television state. | | PLAY (0), PAUSE (1), STOP (2), UNKNOWN (3) |
| | | PictureMode | Number, String | Selected picture mode. | | OTHER (0), STANDARD (1), CALIBRATED (2), CALIBRATED_DARK (3), VIVID (4), GAME (5), COMPUTER (6), CUSTOM (7) |
| | | PowerMode | Switch, Number, String | This oddly named characteristic will receive an ON command when the user requests to open the TV's menu. | inverted (false) | SHOW (0, ON), HIDE (1, OFF) |
| | | RemoteKey | String | Receives a keypress event. | | |
| | | SleepDiscoveryMode | Contact, Dimmer, Number, String, Switch | Indicates if the television is discoverable while in standby mode. Can also be configured via metadata, e.g. [SleepDiscoveryMode=true] | inverted (false) | NOT_DISCOVERABLE (0, OFF), ALWAYS_DISCOVERABLE (1, ON) |
| | | TargetMediaState | Number, String | Target television state. | | PLAY (0), PAUSE (1), STOP (2) |
| TelevisionSpeaker | | | | An accessory that can be added to a Television in order to control the speaker associated with it. | | |
| | Mute | | Switch | If the television is muted. ON = muted, OFF = not muted. | | |
| | | Active | Contact, Dimmer, Number, String, Switch | Unknown. This characteristic is undocumented by Apple, but is still available. | inverted (false) | INACTIVE (0, OFF), ACTIVE (1, ON) |
| | | Volume | Dimmer, Number | Current volume. | | |
| | | VolumeControlType | String | The type of control available. This will default to infer based on what other items are linked. NONE = status only, no control; RELATIVE = INCREMENT/DECREMENT only, no status; RELATIVE_WITH_CURRENT = INCREMENT/DECREMENT only with status; ABSOLUTE = direct status and control. Can also be configured via metadata, e.g. [VolumeControlType="ABSOLUTE"]. | | |
| | | VolumeSelector | Dimmer, String | If linked to a dimmer item, will send INCREASE/DECREASE commands. If linked to a string item, will send INCREMENT and DECREMENT. | | |
| TemperatureSensor | | | | Temperature sensor | | |
| | CurrentTemperature | | Number | current temperature | minValue (0), maxValue (100), step (0.1) | |
| | | ActiveStatus | Contact, Switch | Working status | | |
| | | BatteryLowStatus | Contact, Number, Switch | Battery status | inverted (false), lowThreshold (20) | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | TamperedStatus | Contact, Number, String, Switch | Tampered status | inverted (false) | NOT_TAMPERED (0, OFF, CLOSED), TAMPERED (1, ON, OPEN) |
| Thermostat | | | | A thermostat requires at least one of TargetTemperature, CoolingThresholdTemperature, or HeatingThresholdTemperature must be provided. | | |
| | CurrentHeatingCoolingMode | | Number, String | Current heating cooling mode | | OFF (0, OFF), HEAT (1, ON), COOL (2) |
| | CurrentTemperature | | Number | Current temperature. | minValue (0), maxValue (100), step (0.1) | |
| | TargetHeatingCoolingMode | | Number, String | Target heating cooling mode | | OFF (0, OFF), HEAT (1, ON), COOL (2), AUTO (3) [*](#customizable-enum) |
| | | TargetTemperature | Number | Target temperature. If CoolingThresholdTemperature and HeatingThresholdTemperature are also provided, this characteristic is used when the thermostat is in HEAT or COOL mode. In AUTO mode, this characteristic receives the average of the two thresholds. | minValue (10), maxValue (38), step (0.1) | |
| | | CoolingThresholdTemperature | Number | Maximum temperature that must be reached before cooling is turned on. If TargetTemperature is not provided, this characteristic will also be used in COOL mode. | minValue (10), maxValue (35), step (0.1) | |
| | | HeatingThresholdTemperature | Number | Minimum temperature that must be reached before heating is turned on. If TargetTemperature is not provided, this characteristic will also be used in HEAT mode. | minValue (0), maxValue (25), step (0.1) | |
| | | RelativeHumidity | Number | Relative humidity in % between 0 and 100. | | |
| | | TargetRelativeHumidity | Number | Target relative humidity in % between 0 and 100. | | |
| | | TemperatureUnit | Number, String, Switch | The units the accessory itself uses to display the temperature. Can also be configured via metadata, e.g. [TemperatureUnit="CELSIUS"] | | CELSIUS (0, OFF), FAHRENHEIT (1, ON) |
| Valve | | | | Valve | ValveType = ["Generic", "Irrigation", "Shower", "Faucet"] ("Generic") | |
| | ActiveStatus | | Dimmer, Switch | Accessory current working status. A value of "ON"/"OPEN" indicates that the accessory is active and is functioning without any errors. | | |
| | InUseStatus | | Contact, Dimmer, Switch | Indicates whether fluid flowing through the valve. A value of "ON"/"OPEN" indicates that fluid is flowing. | inverted (false) | |
| | | Duration | Number | Defines how long a valve should be set to ʼIn Useʼ in second. | homekitDefaultDuration = {default duration in seconds} | |
| | | FaultStatus | Contact, Number, String, Switch | Fault status | inverted (false) | NO_FAULT (0, OFF, CLOSED), GENERAL_FAULT (1, ON, OPEN) |
| | | RemainingDuration | Number | Describes the remaining duration on the accessory. the remaining duration increases/decreases from the accessoryʼs usual countdown. i.e. changes from 90 to 80 in a second. | | |
| Window | | | | Motorized window. One Rollershutter item covers all mandatory characteristics. see examples below. | | |
| | CurrentPosition | | Dimmer, Number, Rollershutter | Current position of motorized window | | |
| | PositionState | | Number, Rollershutter, String | Position state. If no state is provided, "STOPPED" is used. | | DECREASING (0), INCREASING (1), STOPPED (2) |
| | TargetPosition | | Dimmer, Number, Rollershutter | Target position of motorized window | | |
| | | HoldPosition | Rollershutter, Switch | Motorized door should stop at its current position. ON is sent to Switch items. STOP is sent to Rollershutter items. Only supported by 3rd party Home apps (such as Elgato Eve) | | |
| | | ObstructionStatus | Contact, Dimmer, Switch | Current status of obstruction sensor. ON-obstruction detected, OFF - no obstruction | | |
| WindowCovering | | | | Window covering / blinds. One Rollershutter item covers all mandatory characteristics. see examples below. | | |
| | CurrentPosition | | Dimmer, Number, Rollershutter | Current position of window covering | | |
| | PositionState | | Number, Rollershutter, String | Position state. If no state is provided, "STOPPED" is used. | | DECREASING (0), INCREASING (1), STOPPED (2) |
| | TargetPosition | | Dimmer, Number, Rollershutter | Target position of window covering | | |
| | | CurrentHorizontalTiltAngle | Dimmer, Number | Number Item = current angle of horizontal slats. values -90 to 90. A value of 0 indicates that the slats are rotated to a fully open position. A value of -90 indicates that the slats are rotated all the way in a direction where the user-facing edge is higher than the window-facing edge. Dimmer Item = the percentage of openness (0%-100%) | | |
| | | CurrentVerticalTiltAngle | Dimmer, Number | Number Item = current angle of vertical slats (-90 to +90) . Dimmer Item = the percentage of openness (0%-100%) | | |
| | | HoldPosition | Rollershutter, Switch | Motorized door should stop at its current position. ON is sent to Switch items. STOP is sent to Rollershutter items. Only supported by 3rd party Home apps (such as Elgato Eve) | | |
| | | ObstructionStatus | Contact, Dimmer, Switch | Current status of obstruction sensor. ON-obstruction detected, OFF - no obstruction | | |
| | | TargetHorizontalTiltAngle | Dimmer, Number | Number Item = target angle of horizontal slats (-90 to +90). Dimmer Item = the percentage of openness (0%-100%) | | |
| | | TargetVerticalTiltAngle | Dimmer, Number | Number Item = target angle of vertical slats. Dimmer Item = the percentage of openness (0%-100%) | | |
### Examples

View File

@ -54,6 +54,7 @@ public enum HomekitAccessoryType {
SMART_SPEAKER("SmartSpeaker"),
SMOKE_SENSOR("SmokeSensor"),
SPEAKER("Speaker"),
STATELESS_PROGRAMMABLE_SWITCH("StatelessProgrammableSwitch"),
SWITCH("Switchable"),
TELEVISION("Television"),
TELEVISION_SPEAKER("TelevisionSpeaker"),

View File

@ -14,6 +14,7 @@ package org.openhab.io.homekit.internal;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Consumer;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.items.GenericItem;
@ -35,7 +36,7 @@ import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
*/
public class HomekitAccessoryUpdater {
private final Logger logger = LoggerFactory.getLogger(HomekitAccessoryUpdater.class);
private final ConcurrentMap<ItemKey, Subscription> subscriptionsByName = new ConcurrentHashMap<>();
private final ConcurrentMap<ItemKey, StateChangeListener> subscriptionsByName = new ConcurrentHashMap<>();
public void subscribe(GenericItem item, HomekitCharacteristicChangeCallback callback) {
subscribe(item, null, callback);
@ -63,6 +64,28 @@ public class HomekitAccessoryUpdater {
});
}
public void subscribeToUpdates(GenericItem item, String key, Consumer<State> callback) {
logger.trace("Received subscription request for {} / {}", item, key);
if (item == null) {
return;
}
if (callback == null) {
logger.trace("The received subscription contains a null callback, skipping");
return;
}
ItemKey itemKey = new ItemKey(item, key);
subscriptionsByName.compute(itemKey, (k, v) -> {
if (v != null) {
logger.debug("Received duplicate subscription for {} / {}", item, key);
unsubscribe(item, key);
}
logger.trace("Adding subscription for {} / {}", item, key);
UpdateSubscription subscription = (changedItem, newState) -> callback.accept(newState);
item.addStateChangeListener(subscription);
return subscription;
});
}
public void unsubscribe(GenericItem item) {
unsubscribe(item, null);
}
@ -91,6 +114,19 @@ public class HomekitAccessoryUpdater {
}
}
@FunctionalInterface
@NonNullByDefault
private interface UpdateSubscription extends StateChangeListener {
@Override
default void stateChanged(Item item, State oldState, State newState) {
// Do nothing on change update
}
@Override
void stateUpdated(Item item, State state);
}
private static class ItemKey {
public final GenericItem item;
public final String key;

View File

@ -97,6 +97,7 @@ public enum HomekitCharacteristicType {
POSITION_STATE("PositionState"),
POWER_MODE("PowerMode"),
PROGRAM_MODE("ProgramMode"),
PROGRAMMABLE_SWITCH_EVENT("ProgrammableSwitchEvent"),
RELATIVE_HUMIDITY("RelativeHumidity"),
REMAINING_DURATION("RemainingDuration"),
REMOTE_KEY("RemoteKey"),

View File

@ -420,7 +420,8 @@ public abstract class AbstractHomekitAccessoryImpl implements HomekitAccessory {
T defaultValue) {
final Optional<HomekitTaggedItem> c = getCharacteristic(characteristicType);
if (c.isPresent()) {
return HomekitCharacteristicFactory.getKeyFromMapping(c.get(), mapping, defaultValue);
return HomekitCharacteristicFactory.getKeyFromMapping(c.get(), c.get().getItem().getState(), mapping,
defaultValue);
}
return defaultValue;
}

View File

@ -100,6 +100,7 @@ public class HomekitAccessoryFactory {
put(SMOKE_SENSOR, new HomekitCharacteristicType[] { SMOKE_DETECTED_STATE });
put(SLAT, new HomekitCharacteristicType[] { CURRENT_SLAT_STATE });
put(SPEAKER, new HomekitCharacteristicType[] { MUTE });
put(STATELESS_PROGRAMMABLE_SWITCH, new HomekitCharacteristicType[] { PROGRAMMABLE_SWITCH_EVENT });
put(SWITCH, new HomekitCharacteristicType[] { ON_STATE });
put(TELEVISION, new HomekitCharacteristicType[] { ACTIVE });
put(TELEVISION_SPEAKER, new HomekitCharacteristicType[] { MUTE });
@ -145,6 +146,7 @@ public class HomekitAccessoryFactory {
put(SMART_SPEAKER, HomekitSmartSpeakerImpl.class);
put(SMOKE_SENSOR, HomekitSmokeSensorImpl.class);
put(SPEAKER, HomekitSpeakerImpl.class);
put(STATELESS_PROGRAMMABLE_SWITCH, HomekitStatelessProgrammableSwitchImpl.class);
put(SWITCH, HomekitSwitchImpl.class);
put(TELEVISION, HomekitTelevisionImpl.class);
put(TELEVISION_SPEAKER, HomekitTelevisionSpeakerImpl.class);

View File

@ -16,10 +16,13 @@ import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
import org.openhab.io.homekit.internal.HomekitException;
import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.impl.common.ServiceLabelNamespaceCharacteristic;
import io.github.hapjava.services.impl.ServiceLabelService;
/**
* Bare accessory (for being the root of a multi-service accessory).
@ -33,4 +36,12 @@ public class HomekitAccessoryGroupImpl extends AbstractHomekitAccessoryImpl {
throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
@Override
public void init() throws HomekitException {
super.init();
getCharacteristic(ServiceLabelNamespaceCharacteristic.class)
.ifPresent(c -> getServices().add(new ServiceLabelService(c)));
}
}

View File

@ -99,6 +99,8 @@ import io.github.hapjava.characteristics.impl.common.IsConfiguredCharacteristic;
import io.github.hapjava.characteristics.impl.common.IsConfiguredEnum;
import io.github.hapjava.characteristics.impl.common.NameCharacteristic;
import io.github.hapjava.characteristics.impl.common.ObstructionDetectedCharacteristic;
import io.github.hapjava.characteristics.impl.common.ProgrammableSwitchEnum;
import io.github.hapjava.characteristics.impl.common.ProgrammableSwitchEventCharacteristic;
import io.github.hapjava.characteristics.impl.common.StatusActiveCharacteristic;
import io.github.hapjava.characteristics.impl.common.StatusFaultCharacteristic;
import io.github.hapjava.characteristics.impl.common.StatusFaultEnum;
@ -231,6 +233,7 @@ public class HomekitCharacteristicFactory {
put(PM10_DENSITY, HomekitCharacteristicFactory::createPM10DensityCharacteristic);
put(PM25_DENSITY, HomekitCharacteristicFactory::createPM25DensityCharacteristic);
put(POWER_MODE, HomekitCharacteristicFactory::createPowerModeCharacteristic);
put(PROGRAMMABLE_SWITCH_EVENT, HomekitCharacteristicFactory::createProgrammableSwitchEventCharacteristic);
put(REMAINING_DURATION, HomekitCharacteristicFactory::createRemainingDurationCharacteristic);
put(REMOTE_KEY, HomekitCharacteristicFactory::createRemoteKeyCharacteristic);
put(RELATIVE_HUMIDITY, HomekitCharacteristicFactory::createRelativeHumidityCharacteristic);
@ -391,8 +394,7 @@ public class HomekitCharacteristicFactory {
* @param <T> type of the result derived from
* @return key for the value
*/
public static <T> T getKeyFromMapping(HomekitTaggedItem item, Map<T, String> mapping, T defaultValue) {
final State state = item.getItem().getState();
public static <T> T getKeyFromMapping(HomekitTaggedItem item, State state, Map<T, String> mapping, T defaultValue) {
LOGGER.trace("getKeyFromMapping: characteristic {}, state {}, mapping {}", item.getAccessoryType().getTag(),
state, mapping);
@ -448,7 +450,8 @@ public class HomekitCharacteristicFactory {
private static <T extends CharacteristicEnum> CompletableFuture<T> getEnumFromItem(HomekitTaggedItem item,
Map<T, String> mapping, T defaultValue) {
return CompletableFuture.completedFuture(getKeyFromMapping(item, mapping, defaultValue));
return CompletableFuture
.completedFuture(getKeyFromMapping(item, item.getItem().getState(), mapping, defaultValue));
}
public static <T extends Enum<T>> void setValueFromEnum(HomekitTaggedItem taggedItem, T value, Map<T, String> map) {
@ -1160,6 +1163,80 @@ public class HomekitCharacteristicFactory {
return new PowerModeCharacteristic((value) -> setValueFromEnum(taggedItem, value, map));
}
// this characteristic is unique in a few ways, so we can't use the "normal" helpers:
// * you don't return a "current" value, just the value of the most recent event
// * NULL/invalid values are very much expected, and should silently _not_ trigger an event
// * every update to the item should trigger an event, not just changes
private static ProgrammableSwitchEventCharacteristic createProgrammableSwitchEventCharacteristic(
HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater) {
// have to build the map custom, since SINGLE_PRESS starts at 0
Map<ProgrammableSwitchEnum, String> map = new EnumMap(ProgrammableSwitchEnum.class);
List<ProgrammableSwitchEnum> validValues = new ArrayList<>();
if (taggedItem.getBaseItem().getAcceptedDataTypes().contains(OnOffType.class)) {
map.put(ProgrammableSwitchEnum.SINGLE_PRESS, OnOffType.ON.toString());
validValues.add(ProgrammableSwitchEnum.SINGLE_PRESS);
} else if (taggedItem.getBaseItem().getAcceptedDataTypes().contains(OpenClosedType.class)) {
map.put(ProgrammableSwitchEnum.SINGLE_PRESS, OpenClosedType.OPEN.toString());
validValues.add(ProgrammableSwitchEnum.SINGLE_PRESS);
} else {
map = createMapping(taggedItem, ProgrammableSwitchEnum.class, validValues, false);
}
var helper = new ProgrammableSwitchEventCharacteristicHelper(taggedItem, updater, map);
return new ProgrammableSwitchEventCharacteristic(validValues.toArray(new ProgrammableSwitchEnum[0]),
helper::getValue, helper::subscribe, getUnsubscriber(taggedItem, PROGRAMMABLE_SWITCH_EVENT, updater));
}
private static class ProgrammableSwitchEventCharacteristicHelper {
private @Nullable ProgrammableSwitchEnum lastValue = null;
private final HomekitTaggedItem taggedItem;
private final Map<ProgrammableSwitchEnum, String> map;
private final HomekitAccessoryUpdater updater;
ProgrammableSwitchEventCharacteristicHelper(HomekitTaggedItem taggedItem, HomekitAccessoryUpdater updater,
Map<ProgrammableSwitchEnum, String> map) {
this.taggedItem = taggedItem;
this.map = map;
this.updater = updater;
}
public CompletableFuture<ProgrammableSwitchEnum> getValue() {
return CompletableFuture.completedFuture(lastValue);
}
public void subscribe(HomekitCharacteristicChangeCallback cb) {
updater.subscribeToUpdates((GenericItem) taggedItem.getItem(), PROGRAMMABLE_SWITCH_EVENT.getTag(),
state -> {
// perform inversion here, so logic below only needs to deal with the
// canonical style
if (state instanceof OnOffType && taggedItem.isInverted()) {
if (state.equals(OnOffType.ON)) {
state = OnOffType.OFF;
} else {
state = OnOffType.ON;
}
} else if (state instanceof OpenClosedType && taggedItem.isInverted()) {
if (state.equals(OpenClosedType.OPEN)) {
state = OpenClosedType.CLOSED;
} else {
state = OpenClosedType.OPEN;
}
}
// if "not pressed", don't send an event
if (state instanceof UnDefType || (state instanceof OnOffType && state.equals(OnOffType.OFF))
|| (state instanceof OpenClosedType && state.equals(OpenClosedType.CLOSED))) {
lastValue = null;
return;
}
lastValue = getKeyFromMapping(taggedItem, state, map, ProgrammableSwitchEnum.SINGLE_PRESS);
cb.changed();
});
}
}
private static RemainingDurationCharacteristic createRemainingDurationCharacteristic(HomekitTaggedItem taggedItem,
HomekitAccessoryUpdater updater) {
return new RemainingDurationCharacteristic(getIntSupplier(taggedItem, 0),

View File

@ -48,7 +48,6 @@ import io.github.hapjava.services.impl.ServiceLabelService;
public class HomekitIrrigationSystemImpl extends AbstractHomekitAccessoryImpl implements IrrigationSystemAccessory {
private Map<InUseEnum, String> inUseMapping;
private Map<ProgramModeEnum, String> programModeMap;
private static final String SERVICE_LABEL = "ServiceLabel";
public HomekitIrrigationSystemImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem> mandatoryCharacteristics,
List<Characteristic> mandatoryRawCharacteristics, HomekitAccessoryUpdater updater, HomekitSettings settings)
@ -64,17 +63,9 @@ public class HomekitIrrigationSystemImpl extends AbstractHomekitAccessoryImpl im
public void init() throws HomekitException {
super.init();
String serviceLabelNamespaceConfig = getAccessoryConfiguration(SERVICE_LABEL, "ARABIC_NUMERALS");
ServiceLabelNamespaceEnum serviceLabelEnum;
try {
serviceLabelEnum = ServiceLabelNamespaceEnum.valueOf(serviceLabelNamespaceConfig.toUpperCase());
} catch (IllegalArgumentException e) {
serviceLabelEnum = ServiceLabelNamespaceEnum.ARABIC_NUMERALS;
}
final var finalEnum = serviceLabelEnum;
var serviceLabelNamespace = getCharacteristic(ServiceLabelNamespaceCharacteristic.class).orElseGet(
() -> new ServiceLabelNamespaceCharacteristic(() -> CompletableFuture.completedFuture(finalEnum)));
var serviceLabelNamespace = getCharacteristic(ServiceLabelNamespaceCharacteristic.class)
.orElseGet(() -> new ServiceLabelNamespaceCharacteristic(
() -> CompletableFuture.completedFuture(ServiceLabelNamespaceEnum.ARABIC_NUMERALS)));
addService(new ServiceLabelService(serviceLabelNamespace));
}

View File

@ -43,6 +43,8 @@ import io.github.hapjava.characteristics.impl.common.IsConfiguredCharacteristic;
import io.github.hapjava.characteristics.impl.common.IsConfiguredEnum;
import io.github.hapjava.characteristics.impl.common.NameCharacteristic;
import io.github.hapjava.characteristics.impl.common.ServiceLabelIndexCharacteristic;
import io.github.hapjava.characteristics.impl.common.ServiceLabelNamespaceCharacteristic;
import io.github.hapjava.characteristics.impl.common.ServiceLabelNamespaceEnum;
import io.github.hapjava.characteristics.impl.heatercooler.CurrentHeaterCoolerStateCharacteristic;
import io.github.hapjava.characteristics.impl.heatercooler.CurrentHeaterCoolerStateEnum;
import io.github.hapjava.characteristics.impl.heatercooler.TargetHeaterCoolerStateCharacteristic;
@ -101,6 +103,7 @@ public class HomekitMetadataCharacteristicFactory {
put(PICTURE_MODE, HomekitMetadataCharacteristicFactory::createPictureModeCharacteristic);
put(SERIAL_NUMBER, HomekitMetadataCharacteristicFactory::createSerialNumberCharacteristic);
put(SERVICE_INDEX, HomekitMetadataCharacteristicFactory::createServiceIndexCharacteristic);
put(SERVICE_LABEL, HomekitMetadataCharacteristicFactory::createServiceLabelNamespaceCharacteristic);
put(SLEEP_DISCOVERY_MODE, HomekitMetadataCharacteristicFactory::createSleepDiscoveryModeCharacteristic);
put(TARGET_HEATER_COOLER_STATE,
HomekitMetadataCharacteristicFactory::createTargetHeaterCoolerStateCharacteristic);
@ -292,6 +295,10 @@ public class HomekitMetadataCharacteristicFactory {
return new ServiceLabelIndexCharacteristic(getInteger(value));
}
private static Characteristic createServiceLabelNamespaceCharacteristic(Object value) {
return new ServiceLabelNamespaceCharacteristic(getEnum(value, ServiceLabelNamespaceEnum.class));
}
private static Characteristic createSleepDiscoveryModeCharacteristic(Object value) {
return new SleepDiscoveryModeCharacteristic(getEnum(value, SleepDiscoveryModeEnum.class,
SleepDiscoveryModeEnum.ALWAYS_DISCOVERABLE, SleepDiscoveryModeEnum.NOT_DISCOVERABLE), v -> {

View File

@ -0,0 +1,46 @@
/**
* Copyright (c) 2010-2024 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.io.homekit.internal.accessories;
import java.util.List;
import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
import org.openhab.io.homekit.internal.HomekitException;
import org.openhab.io.homekit.internal.HomekitSettings;
import org.openhab.io.homekit.internal.HomekitTaggedItem;
import io.github.hapjava.characteristics.Characteristic;
import io.github.hapjava.characteristics.impl.common.ProgrammableSwitchEventCharacteristic;
import io.github.hapjava.services.impl.StatelessProgrammableSwitchService;
/**
* Implements a HomeKit Stateless Programmable Switch
*
* @author Cody Cutrer - Initial contribution
*/
class HomekitStatelessProgrammableSwitchImpl extends AbstractHomekitAccessoryImpl {
public HomekitStatelessProgrammableSwitchImpl(HomekitTaggedItem taggedItem,
List<HomekitTaggedItem> mandatoryCharacteristics, List<Characteristic> mandatoryRawCharacteristics,
HomekitAccessoryUpdater updater, HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, mandatoryRawCharacteristics, updater, settings);
}
@Override
public void init() throws HomekitException {
super.init();
addService(new StatelessProgrammableSwitchService(
getCharacteristic(ProgrammableSwitchEventCharacteristic.class).get()));
}
}