Skip to content

Commit

Permalink
[homekit] support actual booleans in metadata config (openhab#13228)
Browse files Browse the repository at this point in the history
as well as strings, too.

reduces confusion, if someone doesn't know it needed to be a string

Signed-off-by: Cody Cutrer <cody@cutrer.us>
  • Loading branch information
ccutrer authored and nemerdaud committed Feb 28, 2023
1 parent 2b26006 commit 1103e88
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 23 deletions.
26 changes: 13 additions & 13 deletions bundles/org.openhab.io.homekit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,12 @@ In contrast, HomeKit window covering/door/window have inverted mapping
- CLOSED if position is 0%

Therefore, HomeKit integration inverts by default the values between openHAB and HomeKit, e.g. if openHAB current position is 30% then it will send 70% to HomeKit app.
In case you need to disable this logic you can do it with configuration parameter inverted="false", e.g.
In case you need to disable this logic you can do it with configuration parameter inverted=false, e.g.

```xtend
Rollershutter window_covering "Window Rollershutter" {homekit = "WindowCovering" [inverted="false"]}
Rollershutter window "Window" {homekit = "Window" [inverted="false"]}
Rollershutter door "Door" {homekit = "Door" [inverted="false"]}
Rollershutter window_covering "Window Rollershutter" {homekit = "WindowCovering" [inverted=false]}
Rollershutter window "Window" {homekit = "Window" [inverted=false]}
Rollershutter door "Door" {homekit = "Door" [inverted=false]}
```

Expand Down Expand Up @@ -425,7 +425,7 @@ Following table summarizes the optional characteristics supported by sensors.
| BatteryLowStatus | Switch, Contact | Accessory battery status. "ON"/"OPEN" indicates that the battery level of the accessory is low. Value should return to "OFF"/"CLOSED" when the battery charges to a level thats above the low threshold. |

Switch and Contact items support inversion of the state mapping, e.g. by default the openHAB switch state "ON" is mapped to HomeKit contact sensor state "Open", and "OFF" to "Closed".
The configuration "inverted='true'" inverts this mapping, so that "ON" will be mapped to "Closed" and "OFF" to "Open".
The configuration "inverted=true" inverts this mapping, so that "ON" will be mapped to "Closed" and "OFF" to "Open".

Examples of sensor definitions.
Sensors without optional characteristics:
Expand All @@ -435,7 +435,7 @@ Switch leaksensor_single "Leak Sensor" {homekit="LeakSenso
Number light_sensor "Light Sensor" {homekit="LightSensor"}
Number temperature_sensor "Temperature Sensor [%.1f °C]" {homekit="TemperatureSensor"}
Contact contact_sensor "Contact Sensor" {homekit="ContactSensor"}
Contact contact_sensor "Contact Sensor" {homekit="ContactSensor" [inverted="true"]}
Contact contact_sensor "Contact Sensor" {homekit="ContactSensor" [inverted=true]}
Switch occupancy_sensor "Occupancy Sensor" {homekit="OccupancyDetectedState"}
Switch motion_sensor "Motion Sensor" {homekit="MotionSensor"}
Expand All @@ -448,13 +448,13 @@ Sensors with optional characteristics:
Group gLeakSensor "Leak Sensor" {homekit="LeakSensor"}
Switch leaksensor "Leak Sensor State" (gLeakSensor) {homekit="LeakDetectedState"}
Switch leaksensor_bat "Leak Sensor Battery" (gLeakSensor) {homekit="BatteryLowStatus" }
Switch leaksensor_active "Leak Sensor Active" (gLeakSensor) {homekit="ActiveStatus" [inverted="true"]}
Switch leaksensor_active "Leak Sensor Active" (gLeakSensor) {homekit="ActiveStatus" [inverted=true]}
Switch leaksensor_fault "Leak Sensor Fault" (gLeakSensor) {homekit="FaultStatus"}
Switch leaksensor_tampered "Leak Sensor Tampered" (gLeakSensor) {homekit="TamperedStatus"}
Group gMotionSensor "Motion Sensor" {homekit="MotionSensor"}
Switch motionsensor "Motion Sensor State" (gMotionSensor) {homekit="MotionDetectedState"}
Switch motionsensor_bat "Motion Sensor Battery" (gMotionSensor) {homekit="BatteryLowStatus" [inverted="true"]}
Switch motionsensor_bat "Motion Sensor Battery" (gMotionSensor) {homekit="BatteryLowStatus" [inverted=true]}
Switch motionsensor_active "Motion Sensor Active" (gMotionSensor) {homekit="ActiveStatus"}
Switch motionsensor_fault "Motion Sensor Fault" (gMotionSensor) {homekit="FaultStatus"}
Switch motionsensor_tampered "Motion Sensor Tampered" (gMotionSensor) {homekit="TamperedStatus"}
Expand Down Expand Up @@ -676,11 +676,11 @@ Support for this is planned for the future release of openHAB HomeKit binding.
| Fan | | | | Fan |
| | ActiveStatus | | Switch | Accessory current working status. A value of "ON"/"OPEN" indicates that the accessory is active and is functioning without any errors. |
| | | CurrentFanState | Number | Current fan state. values: 0=INACTIVE, 1=IDLE, 2=BLOWING AIR |
| | | TargetFanState | Number, Switch | Target fan state. values: 0/OFF=MANUAL, 1/ON=AUTO. Flag [inverted="true"] swaps the default mapping |
| | | RotationDirection | Number, Switch | Rotation direction. values: 0/OFF=CLOCKWISE, 1/ON=COUNTER CLOCKWISE. Flag [inverted="true"] swaps the default mapping |
| | | TargetFanState | Number, Switch | Target fan state. values: 0/OFF=MANUAL, 1/ON=AUTO. Flag [inverted=true] swaps the default mapping |
| | | RotationDirection | Number, Switch | Rotation direction. values: 0/OFF=CLOCKWISE, 1/ON=COUNTER CLOCKWISE. Flag [inverted=true] swaps the default mapping |
| | | RotationSpeed | Number, Dimmer | Fan rotation speed in % (1-100) |
| | | SwingMode | Number, Switch | Swing mode. values: 0/OFF=SWING DISABLED, 1/ON=SWING ENABLED. Flag [inverted="true"] swaps the default mapping |
| | | LockControl | Number, Switch | Status of physical control lock. values: 0/OFF=CONTROL LOCK DISABLED, 1/ON=CONTROL LOCK ENABLED.Flag [inverted="true"] swaps the default mapping |
| | | SwingMode | Number, Switch | Swing mode. values: 0/OFF=SWING DISABLED, 1/ON=SWING ENABLED. Flag [inverted=true] swaps the default mapping |
| | | LockControl | Number, Switch | Status of physical control lock. values: 0/OFF=CONTROL LOCK DISABLED, 1/ON=CONTROL LOCK ENABLED.Flag [inverted=true] swaps the default mapping |
| Thermostat | | | | A thermostat requires all mandatory characteristics defined below |
| | CurrentTemperature | | Number | Current temperature. supported configuration: minValue, maxValue, step |
| | TargetTemperature | | Number | Target temperature. supported configuration: minValue, maxValue, step |
Expand All @@ -700,7 +700,7 @@ Support for this is planned for the future release of openHAB HomeKit binding.
| | | LockControl | Number, Switch | Status of physical control lock. values: 0/OFF=CONTROL LOCK DISABLED, 1/ON=CONTROL LOCK ENABLED |
| | | CoolingThresholdTemperature | Number | Maximum temperature that must be reached before cooling is turned on. min/max/step can configured at item level, e.g. minValue=10.5, maxValue=50, step=2] |
| | | HeatingThresholdTemperature | Number | Minimum temperature that must be reached before heating is turned on. min/max/step can configured at item level, e.g. minValue=10.5, maxValue=50, step=2] |
| Lock | | | | A Lock Mechanism. with flag [inverted="true"] the default mapping to switch ON/OFF can be inverted. |
| Lock | | | | A Lock Mechanism. with flag [inverted=true] the default mapping to switch ON/OFF can be inverted. |
| | LockCurrentState | | Switch, Number | Current state of lock mechanism (1/ON=SECURED, 0/OFF=UNSECURED, 2=JAMMED, 3=UNKNOWN) |
| | LockTargetState | | Switch | Target state of lock mechanism (ON=SECURED, OFF=UNSECURED) |
| | | Name | String | Name of the lock |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,38 @@ public <T> T getConfiguration(String key, T defaultValue) {
return defaultValue;
}

/**
* Returns configuration value as boolean if its exists otherwise returns defaultValue
*
* @param key configuration key
* @param defaultValue default value
* @return configuration value as boolean
*/
public boolean getConfigurationAsBoolean(String key, boolean defaultValue) {
if (configuration == null) {
return defaultValue;
}
final @Nullable Object value = configuration.get(key);
if (value == null) {
return defaultValue;
}
if (value instanceof Boolean) {
return (Boolean) value;
}
if (value instanceof String) {
final String valueString = (String) value;
return valueString.equalsIgnoreCase("yes") || valueString.equalsIgnoreCase("true");
}
return defaultValue;
}

/**
* returns true if inverted flag is set, i.e. item has the configuration "inverted=true"
*
* @return true if inverted flag is set to true
*/
public boolean isInverted() {
final String invertedConfig = getConfiguration(HomekitTaggedItem.INVERTED, "false");
return invertedConfig.equalsIgnoreCase("yes") || invertedConfig.equalsIgnoreCase("true");
return getConfigurationAsBoolean(HomekitTaggedItem.INVERTED, false);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,18 @@ protected <T> T getAccessoryConfiguration(String key, T defaultValue) {
return accessory.getConfiguration(key, defaultValue);
}

/**
* return configuration attached to the root accessory, e.g. groupItem.
*
* @param key configuration key
* @param defaultValue default value
* @return configuration value
*/
@NonNullByDefault
protected boolean getAccessoryConfigurationAsBoolean(String key, boolean defaultValue) {
return accessory.getConfigurationAsBoolean(key, defaultValue);
}

/**
* return configuration of the characteristic item, e.g. currentTemperature.
* Note: result will be casted to the type of the default value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ public AbstractHomekitPositionAccessoryImpl(HomekitTaggedItem taggedItem,
List<HomekitTaggedItem> mandatoryCharacteristics, HomekitAccessoryUpdater updater,
HomekitSettings settings) {
super(taggedItem, mandatoryCharacteristics, updater, settings);
final String invertedConfig = getAccessoryConfiguration(HomekitTaggedItem.INVERTED, "true");
final boolean inverted = invertedConfig.equalsIgnoreCase("yes") || invertedConfig.equalsIgnoreCase("true");
final boolean inverted = getAccessoryConfigurationAsBoolean(HomekitTaggedItem.INVERTED, true);
closedPosition = inverted ? 0 : 100;
openPosition = inverted ? 100 : 0;
positionStateMapping = new EnumMap<>(PositionStateEnum.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ private static List<HomekitCharacteristicType> getRequiredCharacteristics(Homeki
characteristics.addAll(Arrays.asList(MANDATORY_CHARACTERISTICS.get(taggedItem.getAccessoryType())));
}
if (taggedItem.getAccessoryType() == BATTERY) {
final String isChargeable = taggedItem.getConfiguration(HomekitBatteryImpl.BATTERY_TYPE, "false");
if ("true".equalsIgnoreCase(isChargeable) || "yes".equalsIgnoreCase(isChargeable)) {
final boolean isChargeable = taggedItem.getConfigurationAsBoolean(HomekitBatteryImpl.BATTERY_TYPE, false);
if (isChargeable) {
characteristics.add(BATTERY_CHARGING_STATE);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ public HomekitBatteryImpl(HomekitTaggedItem taggedItem, List<HomekitTaggedItem>
HomekitAccessoryUpdater updater, HomekitSettings settings) throws IncompleteAccessoryException {
super(taggedItem, mandatoryCharacteristics, updater, settings);
lowBatteryReader = createBooleanReader(BATTERY_LOW_STATUS);
final String batteryTypeConfig = getAccessoryConfiguration(BATTERY_TYPE, "false");
isChargeable = "true".equalsIgnoreCase(batteryTypeConfig) || "yes".equalsIgnoreCase(batteryTypeConfig);
isChargeable = getAccessoryConfigurationAsBoolean(BATTERY_TYPE, false);
if (isChargeable) {
chargingBatteryReader = createBooleanReader(BATTERY_CHARGING_STATE);
}
Expand Down
Loading

0 comments on commit 1103e88

Please sign in to comment.