[homekit] remove support for legacy tags and fix issue with semantic tags (#9277)

Signed-off-by: Eugen Freiter <freiter@gmx.de>
This commit is contained in:
eugen 2020-12-07 17:04:59 +01:00 committed by GitHub
parent ac6f08908f
commit 91f05f0ea3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 26 additions and 232 deletions

View File

@ -33,8 +33,6 @@ HomeKit integration supports following accessory types:
- Carbon Dioxide Sensor
- Carbon Monoxide Sensor
**Attention: Some tags have been renamed. Old style may not be supported in future versions. See below for details.**
## Global Configuration
Your first step will be to create the `homekit.cfg` in your `$OPENHAB_CONF/services` folder.
@ -93,23 +91,13 @@ A complex accessory will be made up of multiple openHAB items, e.g. HomeKit Ther
Complex accessories require a tag on a Group Item indicating the accessory type, as well as tags on the items it composes.
A HomeKit accessory has mandatory and optional characteristics (listed below in the table).
The mapping between openHAB items and HomeKit accessory and characteristics is done by means of tagging.
You can tag openHAB items using:
- [tags](https://www.openhab.org/docs/configuration/items.html#tags) (deprecated)
- [metadata](https://www.openhab.org/docs/concepts/items.html#item-metadata)
The mapping between openHAB items and HomeKit accessory and characteristics is done by means of [metadata](https://www.openhab.org/docs/concepts/items.html#item-metadata)
e.g.
```xtend
Switch leaksensor_tag "Leak Sensor with Tag" [ "LeakSensor" ]
Switch leaksensor_metadata "Leak Sensor" {homekit="LeakSensor"}
```
The HomeKit integration currently supports both options. You can mix both options in the same configuration file.
If an openHAB item has both, tags and metadata, then HomeKit integration will use only metadata and ignore tags.
In general, the `tag` way is considered legacy and may be removed in future releases.
You can link one openHAB item to one or more HomeKit accessory, e.g.
```xtend
@ -132,15 +120,7 @@ Rollershutter window_covering "Window Rollershutter" {homekit="WindowCoverin
If the shorthand version has only a characteristic then it must be a part of a group which has a HomeKit accessory type.
You can use openHAB group to define complex accessories. The group item must indicate the HomeKit accessory type,
e.g. LeakSensor definition using tags
```xtend
Group gLegacy_leaksensor "Legacy Leak sensor Group" [ "LeakSensor" ]
Switch legacy_leaksensor "Legacy Leak sensor" (gLegacy_Leaksensor) [ "LeakDetectedState" ]
Switch legacy_leaksensor_battery "Legacy Leak sensor battery status" (gLegacy_Leaksensor) [ "homekit:BatteryLowStatus" ]
```
using metadata
e.g. LeakSensor definition
```xtend
Group gLeakSensor "Leak Sensor Group" {homekit="LeakSensor"}
@ -344,72 +324,11 @@ Switch light2 "Light 2" (gLight) {homekit="Lighting.OnState"}
| | | LockCurrentState | Switch | current states of lock mechanism (OFF=SECURED, ON=UNSECURED) |
| | | LockTargetState | Switch | target states of lock mechanism (OFF=SECURED, ON=UNSECURED) |
### Legacy tags
Following tags are still supported but could be removed in the future releases. Please consider replacing them with the new style.
| Old (tag style) | New (metadata style) |
|:---------------------------------|:------------------------------------------------|
| homekit:HeatingCoolingMode | CurrentHeatingCoolingMode |
| homekit:TargetHeatingCoolingMode | TargetHeatingCoolingMode |
| homekit:TargetTemperature | TargetTemperature |
| homekit:BatteryLowStatus | BatteryLowStatus |
| homekit:BatteryLevel | mapping to BatteryLowStatus |
| CurrentHumidity | RelativeHumidity |
| Blinds | WindowCovering |
| DimmableLighting | Lighting with characteristic Brightness |
| ColorfulLighting | Lighting with characteristic Brightness and Hue |
### Examples
See the sample below for example items:
#### Using "tag"
```xtend
Color legacy_color_light_single "Legacy Color Light Single" [ "Lighting" ]
Color legacy_color_light_dimmable "Legacy Color Light Dimmable" [ "DimmableLighting" ]
Color legacy_color_light_hue "Legacy Color Light Hue" [ "ColorfulLighting" ]
Rollershutter legacy_window_covering "Legacy Window Rollershutter" [ "WindowCovering" ]
Switch legacy_switch_single "Legacy Switch single" [ "Switchable" ]
Switch legacy_contactsensor_single "Legacy Contact Sensor single" [ "ContactSensor" ]
Switch legacy_leaksensor_single "Legacy Leak Sensor single" [ "LeakSensor" ]
Switch legacy_leaksensor_single2 "Legacy Leak Sensor single 2" [ "LeakSensor", "LeakSensor.LeakDetectedState" ]
Switch legacy_motionsensor_single "Legacy Motion Sensor" [ "MotionSensor" ]
Switch legacy_occupancy_single "Legacy Occupanncy Sensor" [ "OccupancySensor" ]
Switch legacy_smoke_single "Legacy Smoke Sensor" [ "SmokeSensor" ]
Number legacy_humidity_single "Legacy Humidity Sensor" [ "CurrentHumidity" ]
Number legacy_temperature_sensor "Temperature Sensor" ["TemperatureSensor"]
Switch legacy_lock "Legacy Lock single" [ "Lock" ]
Switch legacy_valve_single "Legacy Valve Single" [ "Valve" ]
Group gLegacy_Valve "Legacy Valve Group" [ "Valve" ]
Switch legacy_valve_active "Legacy Valve active" (gLegacy_Valve) [ "Active" ]
Number legacy_valve_duration "Legacy Valve duration" (gLegacy_Valve) [ "Duration" ]
Number legacy_valve_remaining_duration "Legacy Valve remaining duration" (gLegacy_Valve) [ "RemainingDuration" ]
Group gLegacy_Thermo "Legacy Thermostat" [ "Thermostat" ]
Number legacy_thermostat_current_temp "L Therm. Cur. Temp. [%.1f C]" (gLegacy_Thermo) [ "CurrentTemperature" ]
Number legacy_thermostat_target_temp "L Therm. Target Temp.[%.1f C]" (gLegacy_Thermo) [ "homekit:TargetTemperature" ]
String legacy_thermostat_current_mode "Legacy Thermostat Current Mode" (gLegacy_Thermo) [ "homekit:CurrentHeatingCoolingMode" ]
String legacy_thermostat_target_mode "Thermostat Target Mode" (gLegacy_Thermo) [ "homekit:TargetHeatingCoolingMode" ]
Group gLegacy_Leaksensor "Legacy Leak Sensor Group" [ "LeakSensor" ]
Switch legacy_leaksensor "Legacy Leak Sensor" (gLegacy_Leaksensor) [ "LeakSensor" ]
Switch legacy_leaksensor_bat "Legacy Leak sensor battery status" (gLegacy_Leaksensor) [ "homekit:BatteryLowStatus" ]
Switch legacy_leaksensor_fault "Legacy Leak sensor fault" (gLegacy_Leaksensor) [ "FaultStatus" ]
Group gLegacy_Security "Legacy Security System Group" [ "SecuritySystem" ]
String legacy_SecurityCurrentState "Security Current State" (gLegacy_Security) [ "CurrentSecuritySystemState" ]
String legacy_SecurityTargetState "Security Target State" (gLegacy_Security) [ "TargetSecuritySystemState" ]
```
#### Using "metadata"
```xtend
Color color_light_single "Color Light Single" {homekit="Lighting"}
Color color_light_dimmable "Legacy Color Light Dimmable" {homekit="Lighting, Lighting.Brightness"}

View File

@ -48,15 +48,7 @@ public enum HomekitAccessoryType {
HEATER_COOLER("HeaterCooler"),
LIGHT_SENSOR("LightSensor"),
AIR_QUALITY_SENSOR("AirQualitySensor"),
DUMMY("Dummy"),
@Deprecated()
BLINDS("Blinds"),
@Deprecated()
OLD_DIMMABLE_LIGHTBULB("DimmableLighting"),
@Deprecated()
OLD_HUMIDITY_SENSOR("CurrentHumidity"),
@Deprecated()
OLD_COLORFUL_LIGHTBULB("ColorfulLighting");
DUMMY("Dummy");
private static final Map<String, HomekitAccessoryType> TAG_MAP = new HashMap<>();

View File

@ -107,20 +107,7 @@ public enum HomekitCharacteristicType {
SULPHUR_DIOXIDE_DENSITY("SulphurDioxideDensity"),
PM25_DENSITY("PM25Density"),
PM10_DENSITY("PM10Density"),
VOC_DENSITY("VOCDensity"),
@Deprecated()
OLD_BATTERY_LEVEL("homekit:BatteryLevel"),
@Deprecated()
OLD_BATTERY_LOW_STATUS("homekit:BatteryLowStatus"),
@Deprecated()
VERY_OLD_TARGET_HEATING_COOLING_MODE("homekit:HeatingCoolingMode"),
@Deprecated()
OLD_TARGET_HEATING_COOLING_MODE("homekit:TargetHeatingCoolingMode"),
@Deprecated()
OLD_CURRENT_HEATING_COOLING_STATE("homekit:CurrentHeatingCoolingMode"),
@Deprecated()
OLD_TARGET_TEMPERATURE("homekit:TargetTemperature");
VOC_DENSITY("VOCDensity");
private static final Map<String, HomekitCharacteristicType> TAG_MAP = new HashMap<>();

View File

@ -38,10 +38,6 @@ public class HomekitCommandExtension extends AbstractConsoleCommandExtension {
private static final String SUBCMD_LIST_ACCESSORIES = "list";
private static final String SUBCMD_PRINT_ACCESSORY = "show";
private static final String SUBCMD_ALLOW_UNAUTHENTICATED = "allowUnauthenticated";
@Deprecated
private static final String LEGACY_SUBCMD_LIST_ACCESSORIES = "listAccessories";
@Deprecated
private static final String LEGACY_SUBCMD_PRINT_ACCESSORY = "printAccessory";
private final Logger logger = LoggerFactory.getLogger(HomekitCommandExtension.class);
@ -69,24 +65,14 @@ public class HomekitCommandExtension extends AbstractConsoleCommandExtension {
}
break;
case SUBCMD_LIST_ACCESSORIES:
case LEGACY_SUBCMD_LIST_ACCESSORIES:
listAccessories(console);
if (subCommand.equalsIgnoreCase(LEGACY_SUBCMD_LIST_ACCESSORIES)) {
console.println("");
console.println("Hey, you can use the shorter command 'homekit list'");
}
break;
case SUBCMD_PRINT_ACCESSORY:
case LEGACY_SUBCMD_PRINT_ACCESSORY:
if (args.length > 1) {
printAccessory(args[1], console);
} else {
console.println("accessory id or name is required as an argument");
}
if (subCommand.equalsIgnoreCase(LEGACY_SUBCMD_PRINT_ACCESSORY)) {
console.println("");
console.println("Hey, you can use the shorter command 'homekit show <accessory_id|name>'");
}
break;
default:
console.println("Unknown command '" + subCommand + "'");

View File

@ -81,7 +81,6 @@ public class HomekitImpl implements Homekit {
private HomekitSettings processConfig(Map<String, Object> config) {
HomekitSettings settings = (new Configuration(config)).as(HomekitSettings.class);
settings.process();
if (settings.networkInterface == null) {
settings.networkInterface = networkAddressService.getPrimaryIpv4HostAddress();
}

View File

@ -21,7 +21,7 @@ public class HomekitSettings {
public static final String MANUFACTURER = "openHAB Community";
public static final String SERIAL_NUMBER = "none";
public static final String MODEL = "openHAB";
public static final String HARDWARE_REVISION = "2.5";
public static final String HARDWARE_REVISION = "3.0";
public String name = "openHAB";
public int port = 9123;
@ -46,30 +46,6 @@ public class HomekitSettings {
public String doorTargetStateOpen = "OPEN";
public String networkInterface;
@Deprecated
public String thermostatHeatMode;
@Deprecated
public String thermostatCoolMode;
@Deprecated
public String thermostatAutoMode;
@Deprecated
public String thermostatOffMode;
public void process() {
if (thermostatHeatMode /* legacy setting */ != null) {
this.thermostatTargetModeHeat = thermostatHeatMode;
}
if (thermostatCoolMode /* legacy setting */ != null) {
this.thermostatTargetModeCool = thermostatCoolMode;
}
if (thermostatAutoMode /* legacy setting */ != null) {
this.thermostatTargetModeAuto = thermostatAutoMode;
}
if (thermostatOffMode /* legacy setting */ != null) {
this.thermostatTargetModeOff = thermostatOffMode;
}
}
@Override
public int hashCode() {
final int prime = 31;

View File

@ -31,8 +31,6 @@ import org.openhab.core.items.ItemRegistry;
import org.openhab.core.items.Metadata;
import org.openhab.core.items.MetadataKey;
import org.openhab.core.items.MetadataRegistry;
import org.openhab.core.library.items.ColorItem;
import org.openhab.core.library.items.DimmerItem;
import org.openhab.io.homekit.internal.HomekitAccessoryType;
import org.openhab.io.homekit.internal.HomekitAccessoryUpdater;
import org.openhab.io.homekit.internal.HomekitCharacteristicType;
@ -54,7 +52,6 @@ import io.github.hapjava.services.Service;
* @author Eugen Freiter - refactoring for optional characteristics
*/
@NonNullByDefault
@SuppressWarnings("deprecation")
public class HomekitAccessoryFactory {
private static final Logger logger = LoggerFactory.getLogger(HomekitAccessoryFactory.class);
public final static String METADATA_KEY = "homekit"; // prefix for HomeKit meta information in items.xml
@ -89,14 +86,8 @@ public class HomekitAccessoryFactory {
new HomekitCharacteristicType[] { CURRENT_DOOR_STATE, TARGET_DOOR_STATE, OBSTRUCTION_STATUS });
put(HEATER_COOLER, new HomekitCharacteristicType[] { ACTIVE_STATUS, CURRENT_HEATER_COOLER_STATE,
TARGET_HEATER_COOLER_STATE, CURRENT_TEMPERATURE });
// LEGACY
put(BLINDS, new HomekitCharacteristicType[] { TARGET_POSITION, CURRENT_POSITION, POSITION_STATE });
put(WINDOW, new HomekitCharacteristicType[] { CURRENT_POSITION, TARGET_POSITION, POSITION_STATE });
put(DOOR, new HomekitCharacteristicType[] { CURRENT_POSITION, TARGET_POSITION, POSITION_STATE });
put(OLD_HUMIDITY_SENSOR, new HomekitCharacteristicType[] { RELATIVE_HUMIDITY });
put(OLD_DIMMABLE_LIGHTBULB, new HomekitCharacteristicType[] { ON_STATE });
put(OLD_COLORFUL_LIGHTBULB, new HomekitCharacteristicType[] { ON_STATE });
}
};
@ -125,33 +116,9 @@ public class HomekitAccessoryFactory {
put(OUTLET, HomekitOutletImpl.class);
put(SPEAKER, HomekitSpeakerImpl.class);
put(GARAGE_DOOR_OPENER, HomekitGarageDoorOpenerImpl.class);
put(BLINDS, HomekitWindowCoveringImpl.class);
put(DOOR, HomekitDoorImpl.class);
put(WINDOW, HomekitWindowImpl.class);
put(HEATER_COOLER, HomekitHeaterCoolerImpl.class);
put(OLD_HUMIDITY_SENSOR, HomekitHumiditySensorImpl.class);
put(OLD_DIMMABLE_LIGHTBULB, HomekitLightbulbImpl.class);
put(OLD_COLORFUL_LIGHTBULB, HomekitLightbulbImpl.class);
}
};
/** mapping of legacy attributes to new attributes. **/
private final static Map<HomekitCharacteristicType, HomekitCharacteristicType> LEGACY_CHARACTERISTICS_MAPPING = new HashMap<HomekitCharacteristicType, HomekitCharacteristicType>() {
{
put(OLD_CURRENT_HEATING_COOLING_STATE, CURRENT_HEATING_COOLING_STATE);
put(OLD_TARGET_HEATING_COOLING_MODE, TARGET_HEATING_COOLING_STATE);
put(OLD_TARGET_TEMPERATURE, TARGET_TEMPERATURE);
put(OLD_BATTERY_LOW_STATUS, BATTERY_LOW_STATUS);
put(VERY_OLD_TARGET_HEATING_COOLING_MODE, CURRENT_HEATING_COOLING_STATE);
}
};
/** list of optional implicit optional characteristics. mainly used for legacy accessory type */
private final static Map<HomekitAccessoryType, HomekitCharacteristicType[]> IMPLICIT_OPTIONAL_CHARACTERISTICS = new HashMap<HomekitAccessoryType, HomekitCharacteristicType[]>() {
{
put(OLD_DIMMABLE_LIGHTBULB, new HomekitCharacteristicType[] { BRIGHTNESS });
put(OLD_COLORFUL_LIGHTBULB, new HomekitCharacteristicType[] { HUE, SATURATION, BRIGHTNESS });
}
};
@ -213,32 +180,24 @@ public class HomekitAccessoryFactory {
MetadataRegistry metadataRegistry) {
final List<Entry<HomekitAccessoryType, HomekitCharacteristicType>> accessories = new ArrayList<>();
final @Nullable Metadata metadata = metadataRegistry.get(new MetadataKey(METADATA_KEY, item.getUID()));
boolean legacyMode = metadata == null;
String[] tags = !legacyMode ? metadata.getValue().split(",") : item.getTags().toArray(new String[0]); // fallback
for (String tag : tags) {
final String[] meta = tag.split("\\.");
Optional<HomekitAccessoryType> accessoryType = HomekitAccessoryType.valueOfTag(meta[0].trim());
if (accessoryType.isPresent()) { // it accessory, check for characteristic
HomekitAccessoryType type = accessoryType.get();
if ((legacyMode) && (type.equals(LIGHTBULB))) { // support old smart logic to convert Lighting to
// DimmableLighting or ColorfulLighting depending on
// item type
if (item instanceof ColorItem) {
type = OLD_COLORFUL_LIGHTBULB;
} else if (item instanceof DimmerItem) {
type = OLD_DIMMABLE_LIGHTBULB;
if (metadata != null) {
String[] tags = metadata.getValue().split(",");
for (String tag : tags) {
final String[] meta = tag.split("\\.");
Optional<HomekitAccessoryType> accessoryType = HomekitAccessoryType.valueOfTag(meta[0].trim());
if (accessoryType.isPresent()) { // it accessory, check for characteristic
HomekitAccessoryType type = accessoryType.get();
if (meta.length > 1) {
// it has characteristic as well
accessories.add(new SimpleEntry<>(type,
HomekitCharacteristicType.valueOfTag(meta[1].trim()).orElse(EMPTY)));
} else {// it has no characteristic
accessories.add(new SimpleEntry<>(type, EMPTY));
}
} else { // it is no accessory, so, maybe it is a characteristic
HomekitCharacteristicType.valueOfTag(meta[0].trim())
.ifPresent(c -> accessories.add(new SimpleEntry<>(DUMMY, c)));
}
if (meta.length > 1) {
// it has characteristic as well
accessories.add(new SimpleEntry<>(type,
HomekitCharacteristicType.valueOfTag(meta[1].trim()).orElse(EMPTY)));
} else {// it has no characteristic
accessories.add(new SimpleEntry<>(type, EMPTY));
}
} else { // it is no accessory, so, maybe it is a characteristic
HomekitCharacteristicType.valueOfTag(meta[0].trim())
.ifPresent(c -> accessories.add(new SimpleEntry<>(DUMMY, c)));
}
}
return accessories;
@ -331,8 +290,7 @@ public class HomekitAccessoryFactory {
} else {
// item has characteristic tag on it, so, adding it as that characteristic.
// check whether it is a legacy characteristic, i.e. old tag was used, and replaced by a new one
final HomekitCharacteristicType characteristic = legacyCheck(accessory.getValue());
final HomekitCharacteristicType characteristic = accessory.getValue();
// check whether it is a mandatory characteristic. optional will be added later by another method.
if (isMandatoryCharacteristic(mainItem.getAccessoryType(), characteristic)) {
@ -395,22 +353,13 @@ public class HomekitAccessoryFactory {
GroupItem groupItem = (GroupItem) taggedItem.getItem();
groupItem.getMembers().forEach(item -> getAccessoryTypes(item, metadataRegistry).stream()
.filter(c -> !isRootAccessory(c))
.filter(c -> !isMandatoryCharacteristic(taggedItem.getAccessoryType(), legacyCheck(c.getValue())))
.forEach(characteristic -> characteristicItems.put(legacyCheck(characteristic.getValue()),
(GenericItem) item)));
.filter(c -> !isMandatoryCharacteristic(taggedItem.getAccessoryType(), c.getValue()))
.forEach(characteristic -> characteristicItems.put(characteristic.getValue(), (GenericItem) item)));
} else {
getAccessoryTypes(taggedItem.getItem(), metadataRegistry).stream().filter(c -> !isRootAccessory(c))
.filter(c -> !isMandatoryCharacteristic(taggedItem.getAccessoryType(), legacyCheck(c.getValue())))
.forEach(characteristic -> characteristicItems.put(legacyCheck(characteristic.getValue()),
.filter(c -> !isMandatoryCharacteristic(taggedItem.getAccessoryType(), c.getValue()))
.forEach(characteristic -> characteristicItems.put(characteristic.getValue(),
(GenericItem) taggedItem.getItem()));
final HomekitCharacteristicType[] implicitOptionalCharacteristics = IMPLICIT_OPTIONAL_CHARACTERISTICS
.get(taggedItem.getAccessoryType());
if (implicitOptionalCharacteristics != null) {
Arrays.stream(implicitOptionalCharacteristics)
.filter(c -> !isMandatoryCharacteristic(taggedItem.getAccessoryType(), c))
.forEach(characteristic -> characteristicItems.put(legacyCheck(characteristic),
(GenericItem) taggedItem.getItem()));
}
}
logger.trace("Optional characteristics for item {} characteristics {}", taggedItem.getName(),
characteristicItems);
@ -439,15 +388,4 @@ public class HomekitAccessoryFactory {
private static boolean isRootAccessory(Entry<HomekitAccessoryType, HomekitCharacteristicType> accessory) {
return ((accessory.getValue() == null) || (accessory.getValue() == EMPTY));
}
/**
* check whether it is legacy characteristic and return new name in such case. otherwise return the input parameter
* unchanged.
*
* @param characteristicType characteristic to check
* @return new characteristic type
*/
private static HomekitCharacteristicType legacyCheck(HomekitCharacteristicType characteristicType) {
return LEGACY_CHARACTERISTICS_MAPPING.getOrDefault(characteristicType, characteristicType);
}
}

View File

@ -90,7 +90,6 @@ import io.github.hapjava.characteristics.impl.windowcovering.TargetVerticalTiltA
* @author Eugen Freiter - Initial contribution
*/
@NonNullByDefault
@SuppressWarnings("deprecation")
public class HomekitCharacteristicFactory {
private static final Logger logger = LoggerFactory.getLogger(HomekitCharacteristicFactory.class);
@ -136,8 +135,6 @@ public class HomekitCharacteristicFactory {
put(PM25_DENSITY, HomekitCharacteristicFactory::createPM25DensityCharacteristic);
put(PM10_DENSITY, HomekitCharacteristicFactory::createPM10DensityCharacteristic);
put(VOC_DENSITY, HomekitCharacteristicFactory::createVOCDensityCharacteristic);
// LEGACY
put(OLD_BATTERY_LOW_STATUS, HomekitCharacteristicFactory::createStatusLowBatteryCharacteristic);
}
};