[homekit] fix for battery charging state (#12959)
* fix for battery charging state Signed-off-by: Eugen Freiter <freiter@gmx.de>
This commit is contained in:
parent
cf94687ad6
commit
565dc19508
@ -473,6 +473,7 @@ For example, ceiling fans often include lighting functionality. Such fans can be
|
|||||||
- two separate HomeKit accessories - fan **and** light.
|
- two separate HomeKit accessories - fan **and** light.
|
||||||
|
|
||||||
iOS home app would show them as **two tiles** that can be controlled directly from home screen.
|
iOS home app would show them as **two tiles** that can be controlled directly from home screen.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- one complex accessory - fan **with** light.
|
- one complex accessory - fan **with** light.
|
||||||
@ -517,12 +518,17 @@ Group FanWithLight "Fan with Light" {
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
Similarly, you can create a sensor with battery
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
However, home app does not support changing of tiles for already added accessory.
|
However, home app does not support changing of tiles for already added accessory.
|
||||||
If you want to change the tile after the accessory was added, you need either to rename the group, if you use textual item configuration, or to delete and to create a new group with a different name, if you use UI for configuration.
|
If you want to change the tile after the accessory was added, you need either to rename the group, if you use textual item configuration, or to delete and to create a new group with a different name, if you use UI for configuration.
|
||||||
|
|
||||||
You can combine more than two accessories as well as accessories linked to different physical devices.
|
You can combine more than two accessories as well as accessories linked to different physical devices.
|
||||||
You can also do unusually combinations, e.g. you can combine temperature sensor with blinds and light.
|
You can also do unusually combinations, e.g. you can combine temperature sensor with blinds and light.
|
||||||
It will be represented by home app as follows
|
It will be represented by home app as follows
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
|||||||
BIN
bundles/org.openhab.io.homekit/doc/ui_sensor_with_battery.png
Normal file
BIN
bundles/org.openhab.io.homekit/doc/ui_sensor_with_battery.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 131 KiB |
@ -153,4 +153,9 @@ public enum HomekitCharacteristicType {
|
|||||||
public static Optional<HomekitCharacteristicType> valueOfTag(String tag) {
|
public static Optional<HomekitCharacteristicType> valueOfTag(String tag) {
|
||||||
return Optional.ofNullable(TAG_MAP.get(tag));
|
return Optional.ofNullable(TAG_MAP.get(tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -282,7 +282,7 @@ public class HomekitTaggedItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Item:" + proxyItem.getItem() + " HomeKit type:" + homekitAccessoryType + " HomeKit characteristic:"
|
return "Item:" + proxyItem.getItem() + " HomeKit type: '" + homekitAccessoryType.getTag()
|
||||||
+ homekitCharacteristicType;
|
+ "' characteristic: '" + homekitCharacteristicType.getTag() + "'";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -141,8 +141,21 @@ public class HomekitAccessoryFactory {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static List<HomekitCharacteristicType> getRequiredCharacteristics(HomekitTaggedItem taggedItem) {
|
||||||
|
if (taggedItem.getAccessoryType() == BATTERY) {
|
||||||
|
final String isChargeable = taggedItem.getConfiguration(HomekitBatteryImpl.BATTERY_TYPE, "false");
|
||||||
|
if ("true".equalsIgnoreCase(isChargeable) || "yes".equalsIgnoreCase(isChargeable)) {
|
||||||
|
final List<HomekitCharacteristicType> characteristics = new ArrayList<>();
|
||||||
|
characteristics.addAll(Arrays.asList(MANDATORY_CHARACTERISTICS.get(taggedItem.getAccessoryType())));
|
||||||
|
characteristics.add(BATTERY_CHARGING_STATE);
|
||||||
|
return characteristics;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Arrays.asList(MANDATORY_CHARACTERISTICS.get(taggedItem.getAccessoryType()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates HomeKit accessory for a openhab item.
|
* creates HomeKit accessory for an openhab item.
|
||||||
*
|
*
|
||||||
* @param taggedItem openhab item tagged as HomeKit item
|
* @param taggedItem openhab item tagged as HomeKit item
|
||||||
* @param metadataRegistry openhab metadata registry required to get item meta information
|
* @param metadataRegistry openhab metadata registry required to get item meta information
|
||||||
@ -158,12 +171,12 @@ public class HomekitAccessoryFactory {
|
|||||||
HomekitAccessoryUpdater updater, HomekitSettings settings) throws HomekitException {
|
HomekitAccessoryUpdater updater, HomekitSettings settings) throws HomekitException {
|
||||||
final HomekitAccessoryType accessoryType = taggedItem.getAccessoryType();
|
final HomekitAccessoryType accessoryType = taggedItem.getAccessoryType();
|
||||||
logger.trace("Constructing {} of accessory type {}", taggedItem.getName(), accessoryType.getTag());
|
logger.trace("Constructing {} of accessory type {}", taggedItem.getName(), accessoryType.getTag());
|
||||||
final List<HomekitTaggedItem> requiredCharacteristics = getMandatoryCharacteristics(taggedItem,
|
final List<HomekitTaggedItem> foundCharacteristics = getMandatoryCharacteristicsFromItem(taggedItem,
|
||||||
metadataRegistry);
|
metadataRegistry);
|
||||||
final HomekitCharacteristicType[] mandatoryCharacteristics = MANDATORY_CHARACTERISTICS.get(accessoryType);
|
final List<HomekitCharacteristicType> mandatoryCharacteristics = getRequiredCharacteristics(taggedItem);
|
||||||
if ((mandatoryCharacteristics != null) && (requiredCharacteristics.size() < mandatoryCharacteristics.length)) {
|
if (foundCharacteristics.size() < mandatoryCharacteristics.size()) {
|
||||||
logger.warn("Accessory of type {} must have following characteristics {}. Found only {}",
|
logger.warn("Accessory of type {} must have following characteristics {}. Found only {}",
|
||||||
accessoryType.getTag(), mandatoryCharacteristics, requiredCharacteristics);
|
accessoryType.getTag(), mandatoryCharacteristics, foundCharacteristics);
|
||||||
throw new HomekitException("Missing mandatory characteristics");
|
throw new HomekitException("Missing mandatory characteristics");
|
||||||
}
|
}
|
||||||
AbstractHomekitAccessoryImpl accessoryImpl;
|
AbstractHomekitAccessoryImpl accessoryImpl;
|
||||||
@ -171,10 +184,9 @@ public class HomekitAccessoryFactory {
|
|||||||
final @Nullable Class<? extends AbstractHomekitAccessoryImpl> accessoryImplClass = SERVICE_IMPL_MAP
|
final @Nullable Class<? extends AbstractHomekitAccessoryImpl> accessoryImplClass = SERVICE_IMPL_MAP
|
||||||
.get(accessoryType);
|
.get(accessoryType);
|
||||||
if (accessoryImplClass != null) {
|
if (accessoryImplClass != null) {
|
||||||
accessoryImpl = accessoryImplClass
|
accessoryImpl = accessoryImplClass.getConstructor(HomekitTaggedItem.class, List.class,
|
||||||
.getConstructor(HomekitTaggedItem.class, List.class, HomekitAccessoryUpdater.class,
|
HomekitAccessoryUpdater.class, HomekitSettings.class)
|
||||||
HomekitSettings.class)
|
.newInstance(taggedItem, foundCharacteristics, updater, settings);
|
||||||
.newInstance(taggedItem, requiredCharacteristics, updater, settings);
|
|
||||||
addOptionalCharacteristics(taggedItem, accessoryImpl, metadataRegistry);
|
addOptionalCharacteristics(taggedItem, accessoryImpl, metadataRegistry);
|
||||||
return accessoryImpl;
|
return accessoryImpl;
|
||||||
} else {
|
} else {
|
||||||
@ -255,7 +267,7 @@ public class HomekitAccessoryFactory {
|
|||||||
* @param metadataRegistry meta data registry
|
* @param metadataRegistry meta data registry
|
||||||
* @return list of mandatory
|
* @return list of mandatory
|
||||||
*/
|
*/
|
||||||
private static List<HomekitTaggedItem> getMandatoryCharacteristics(HomekitTaggedItem taggedItem,
|
private static List<HomekitTaggedItem> getMandatoryCharacteristicsFromItem(HomekitTaggedItem taggedItem,
|
||||||
MetadataRegistry metadataRegistry) {
|
MetadataRegistry metadataRegistry) {
|
||||||
List<HomekitTaggedItem> collectedCharacteristics = new ArrayList<>();
|
List<HomekitTaggedItem> collectedCharacteristics = new ArrayList<>();
|
||||||
if (taggedItem.isGroup()) {
|
if (taggedItem.isGroup()) {
|
||||||
@ -265,8 +277,7 @@ public class HomekitAccessoryFactory {
|
|||||||
} else {
|
} else {
|
||||||
addMandatoryCharacteristics(taggedItem, collectedCharacteristics, taggedItem.getItem(), metadataRegistry);
|
addMandatoryCharacteristics(taggedItem, collectedCharacteristics, taggedItem.getItem(), metadataRegistry);
|
||||||
}
|
}
|
||||||
logger.trace("Mandatory characteristics for item {} characteristics {}", taggedItem.getName(),
|
logger.trace("Mandatory characteristics: {}", collectedCharacteristics);
|
||||||
collectedCharacteristics);
|
|
||||||
return collectedCharacteristics;
|
return collectedCharacteristics;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,9 +296,8 @@ public class HomekitAccessoryFactory {
|
|||||||
private static void addMandatoryCharacteristics(HomekitTaggedItem mainItem, List<HomekitTaggedItem> characteristics,
|
private static void addMandatoryCharacteristics(HomekitTaggedItem mainItem, List<HomekitTaggedItem> characteristics,
|
||||||
Item item, MetadataRegistry metadataRegistry) {
|
Item item, MetadataRegistry metadataRegistry) {
|
||||||
// get list of mandatory characteristics
|
// get list of mandatory characteristics
|
||||||
HomekitCharacteristicType[] mandatoryCharacteristics = MANDATORY_CHARACTERISTICS
|
List<HomekitCharacteristicType> mandatoryCharacteristics = getRequiredCharacteristics(mainItem);
|
||||||
.get(mainItem.getAccessoryType());
|
if (mandatoryCharacteristics.isEmpty()) {
|
||||||
if ((mandatoryCharacteristics == null) || (mandatoryCharacteristics.length == 0)) {
|
|
||||||
// no mandatory characteristics linked to accessory type of mainItem. we are done
|
// no mandatory characteristics linked to accessory type of mainItem. we are done
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -299,13 +309,12 @@ public class HomekitAccessoryFactory {
|
|||||||
for (Entry<HomekitAccessoryType, HomekitCharacteristicType> accessory : getAccessoryTypes(item,
|
for (Entry<HomekitAccessoryType, HomekitCharacteristicType> accessory : getAccessoryTypes(item,
|
||||||
metadataRegistry)) {
|
metadataRegistry)) {
|
||||||
// if the item has only accessory tag, e.g. TemperatureSensor,
|
// if the item has only accessory tag, e.g. TemperatureSensor,
|
||||||
// the we will link all mandatory characteristic to this item,
|
// then we will link all mandatory characteristic to this item,
|
||||||
// e.g. we will link CurrentTemperature in case of TemperatureSensor.
|
// e.g. we will link CurrentTemperature in case of TemperatureSensor.
|
||||||
if (isRootAccessory(accessory)) {
|
if (isRootAccessory(accessory)) {
|
||||||
Arrays.stream(mandatoryCharacteristics)
|
mandatoryCharacteristics.forEach(c -> characteristics.add(new HomekitTaggedItem(itemProxy,
|
||||||
.forEach(c -> characteristics.add(new HomekitTaggedItem(itemProxy, accessory.getKey(), c,
|
accessory.getKey(), c, mainItem.isGroup() ? (GroupItem) mainItem.getItem() : null,
|
||||||
mainItem.isGroup() ? (GroupItem) mainItem.getItem() : null,
|
HomekitAccessoryFactory.getItemConfiguration(item, metadataRegistry))));
|
||||||
HomekitAccessoryFactory.getItemConfiguration(item, metadataRegistry))));
|
|
||||||
} else {
|
} else {
|
||||||
// item has characteristic tag on it, so, adding it as that characteristic.
|
// item has characteristic tag on it, so, adding it as that characteristic.
|
||||||
|
|
||||||
@ -313,7 +322,7 @@ public class HomekitAccessoryFactory {
|
|||||||
|
|
||||||
// check whether it is a mandatory characteristic. optional will be added later by another method.
|
// check whether it is a mandatory characteristic. optional will be added later by another method.
|
||||||
if (belongsToType(mainItem.getAccessoryType(), accessory)
|
if (belongsToType(mainItem.getAccessoryType(), accessory)
|
||||||
&& isMandatoryCharacteristic(mainItem.getAccessoryType(), characteristic)) {
|
&& isMandatoryCharacteristic(mainItem, characteristic)) {
|
||||||
characteristics.add(new HomekitTaggedItem(itemProxy, accessory.getKey(), characteristic,
|
characteristics.add(new HomekitTaggedItem(itemProxy, accessory.getKey(), characteristic,
|
||||||
mainItem.isGroup() ? (GroupItem) mainItem.getItem() : null,
|
mainItem.isGroup() ? (GroupItem) mainItem.getItem() : null,
|
||||||
HomekitAccessoryFactory.getItemConfiguration(item, metadataRegistry)));
|
HomekitAccessoryFactory.getItemConfiguration(item, metadataRegistry)));
|
||||||
@ -373,30 +382,28 @@ public class HomekitAccessoryFactory {
|
|||||||
GroupItem groupItem = (GroupItem) taggedItem.getItem();
|
GroupItem groupItem = (GroupItem) taggedItem.getItem();
|
||||||
groupItem.getMembers().forEach(item -> getAccessoryTypes(item, metadataRegistry).stream()
|
groupItem.getMembers().forEach(item -> getAccessoryTypes(item, metadataRegistry).stream()
|
||||||
.filter(c -> !isRootAccessory(c)).filter(c -> belongsToType(taggedItem.getAccessoryType(), c))
|
.filter(c -> !isRootAccessory(c)).filter(c -> belongsToType(taggedItem.getAccessoryType(), c))
|
||||||
.filter(c -> !isMandatoryCharacteristic(taggedItem.getAccessoryType(), c.getValue()))
|
.filter(c -> !isMandatoryCharacteristic(taggedItem, c.getValue()))
|
||||||
.forEach(characteristic -> characteristicItems.put(characteristic.getValue(), (GenericItem) item)));
|
.forEach(characteristic -> characteristicItems.put(characteristic.getValue(), (GenericItem) item)));
|
||||||
} else {
|
} else {
|
||||||
getAccessoryTypes(taggedItem.getItem(), metadataRegistry).stream().filter(c -> !isRootAccessory(c))
|
getAccessoryTypes(taggedItem.getItem(), metadataRegistry).stream().filter(c -> !isRootAccessory(c))
|
||||||
.filter(c -> !isMandatoryCharacteristic(taggedItem.getAccessoryType(), c.getValue()))
|
.filter(c -> !isMandatoryCharacteristic(taggedItem, c.getValue()))
|
||||||
.forEach(characteristic -> characteristicItems.put(characteristic.getValue(),
|
.forEach(characteristic -> characteristicItems.put(characteristic.getValue(),
|
||||||
(GenericItem) taggedItem.getItem()));
|
(GenericItem) taggedItem.getItem()));
|
||||||
}
|
}
|
||||||
logger.trace("Optional characteristics for item {} characteristics {}", taggedItem.getName(),
|
logger.trace("Optional characteristics for item {}: {}", taggedItem.getName(), characteristicItems.values());
|
||||||
characteristicItems);
|
|
||||||
return Collections.unmodifiableMap(characteristicItems);
|
return Collections.unmodifiableMap(characteristicItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return true is characteristic is a mandatory characteristic for the accessory.
|
* return true is characteristic is a mandatory characteristic for the accessory.
|
||||||
*
|
*
|
||||||
* @param accessory accessory
|
* @param item item
|
||||||
* @param characteristic characteristic
|
* @param characteristic characteristic
|
||||||
* @return true if characteristic is mandatory, false if not mandatory
|
* @return true if characteristic is mandatory, false if not mandatory
|
||||||
*/
|
*/
|
||||||
private static boolean isMandatoryCharacteristic(HomekitAccessoryType accessory,
|
private static boolean isMandatoryCharacteristic(HomekitTaggedItem item, HomekitCharacteristicType characteristic) {
|
||||||
HomekitCharacteristicType characteristic) {
|
return MANDATORY_CHARACTERISTICS.containsKey(item.getAccessoryType())
|
||||||
return MANDATORY_CHARACTERISTICS.containsKey(accessory)
|
&& getRequiredCharacteristics(item).contains(characteristic);
|
||||||
&& Arrays.asList(MANDATORY_CHARACTERISTICS.get(accessory)).contains(characteristic);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -37,7 +37,7 @@ import io.github.hapjava.services.impl.BatteryService;
|
|||||||
* @author Eugen Freiter - Initial contribution
|
* @author Eugen Freiter - Initial contribution
|
||||||
*/
|
*/
|
||||||
public class HomekitBatteryImpl extends AbstractHomekitAccessoryImpl implements BatteryAccessory {
|
public class HomekitBatteryImpl extends AbstractHomekitAccessoryImpl implements BatteryAccessory {
|
||||||
private static final String BATTERY_TYPE = "chargeable";
|
public static final String BATTERY_TYPE = "chargeable";
|
||||||
|
|
||||||
private final BooleanItemReader lowBatteryReader;
|
private final BooleanItemReader lowBatteryReader;
|
||||||
private BooleanItemReader chargingBatteryReader;
|
private BooleanItemReader chargingBatteryReader;
|
||||||
@ -87,7 +87,9 @@ public class HomekitBatteryImpl extends AbstractHomekitAccessoryImpl implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void subscribeBatteryChargingState(final HomekitCharacteristicChangeCallback callback) {
|
public void subscribeBatteryChargingState(final HomekitCharacteristicChangeCallback callback) {
|
||||||
subscribe(BATTERY_CHARGING_STATE, callback);
|
if (isChargeable) {
|
||||||
|
subscribe(BATTERY_CHARGING_STATE, callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -102,6 +104,8 @@ public class HomekitBatteryImpl extends AbstractHomekitAccessoryImpl implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unsubscribeBatteryChargingState() {
|
public void unsubscribeBatteryChargingState() {
|
||||||
unsubscribe(BATTERY_CHARGING_STATE);
|
if (isChargeable) {
|
||||||
|
unsubscribe(BATTERY_CHARGING_STATE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -184,13 +184,14 @@ public class HomekitCharacteristicFactory {
|
|||||||
public static Characteristic createCharacteristic(HomekitTaggedItem item, HomekitAccessoryUpdater updater)
|
public static Characteristic createCharacteristic(HomekitTaggedItem item, HomekitAccessoryUpdater updater)
|
||||||
throws HomekitException {
|
throws HomekitException {
|
||||||
final @Nullable HomekitCharacteristicType type = item.getCharacteristicType();
|
final @Nullable HomekitCharacteristicType type = item.getCharacteristicType();
|
||||||
logger.trace("CreateCharacteristic, type {} item {}", type, item);
|
logger.trace("Create characteristic {}", item);
|
||||||
if (optional.containsKey(type)) {
|
if (optional.containsKey(type)) {
|
||||||
return optional.get(type).apply(item, updater);
|
return optional.get(type).apply(item, updater);
|
||||||
}
|
}
|
||||||
logger.warn("Unsupported optional characteristic. Accessory type {}, characteristic type {}",
|
logger.warn("Unsupported optional characteristic. Accessory type {}, characteristic type {}",
|
||||||
item.getAccessoryType(), type);
|
item.getAccessoryType(), type.getTag());
|
||||||
throw new HomekitException("Unsupported optional characteristic. Characteristic type \"" + type + "\"");
|
throw new HomekitException(
|
||||||
|
"Unsupported optional characteristic. Characteristic type \"" + type.getTag() + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
// METHODS TO CREATE SINGLE CHARACTERISTIC FROM OH ITEM
|
// METHODS TO CREATE SINGLE CHARACTERISTIC FROM OH ITEM
|
||||||
|
|||||||
@ -24,7 +24,7 @@ public class IncompleteAccessoryException extends Exception {
|
|||||||
private static final long serialVersionUID = 8595808359805444177L;
|
private static final long serialVersionUID = 8595808359805444177L;
|
||||||
|
|
||||||
public IncompleteAccessoryException(HomekitCharacteristicType missingType) {
|
public IncompleteAccessoryException(HomekitCharacteristicType missingType) {
|
||||||
super(String.format("Missing accessory type %s", missingType.getTag()));
|
super(String.format("Missing accessory characteristic %s", missingType.getTag()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IncompleteAccessoryException(String message) {
|
public IncompleteAccessoryException(String message) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user