[homekit] Sort optional characteristics before adding them to the service (#18329)

So that they'll always be added in a consistent order. Otherwise we might
accidentally change the order (and thus the IID) of a characteristic, but
not actually detect that it's different and signal Home to reload accessory
structures.

Signed-off-by: Cody Cutrer <cody@cutrer.us>
pull/18333/head
Cody Cutrer 2025-02-26 13:33:36 -07:00 committed by GitHub
parent c57f833e31
commit 80d64ccd06
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 38 additions and 38 deletions

View File

@ -242,19 +242,20 @@ public abstract class AbstractHomekitAccessoryImpl implements HomekitAccessory {
services.add(service); services.add(service);
var serviceClass = service.getClass(); var serviceClass = service.getClass();
rawCharacteristics.values().forEach(characteristic -> { rawCharacteristics.values().stream().sorted((lhs, rhs) -> lhs.getType().compareTo(rhs.getType()))
// belongs on the accessory information service .forEach(characteristic -> {
if (characteristic.getClass() == NameCharacteristic.class) { // belongs on the accessory information service
return; if (characteristic.getClass() == NameCharacteristic.class) {
} return;
try { }
// if the service supports adding this characteristic as optional, add it! try {
serviceClass.getMethod("addOptionalCharacteristic", characteristic.getClass()).invoke(service, // if the service supports adding this characteristic as optional, add it!
characteristic); serviceClass.getMethod("addOptionalCharacteristic", characteristic.getClass()).invoke(service,
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { characteristic);
// the service doesn't support this optional characteristic; ignore it } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
} // the service doesn't support this optional characteristic; ignore it
}); }
});
} }
protected HomekitAccessoryUpdater getUpdater() { protected HomekitAccessoryUpdater getUpdater() {
@ -565,33 +566,32 @@ public abstract class AbstractHomekitAccessoryImpl implements HomekitAccessory {
serviceBuilder.add("type", service.getType()); serviceBuilder.add("type", service.getType());
var characteristics = Json.createArrayBuilder(); var characteristics = Json.createArrayBuilder();
service.getCharacteristics().stream().sorted((l, r) -> l.getClass().getName().compareTo(r.getClass().getName())) service.getCharacteristics().forEach(c -> {
.forEach(c -> { try {
try { var cJson = c.toJson(0).get();
var cJson = c.toJson(0).get(); var cBuilder = Json.createObjectBuilder();
var cBuilder = Json.createObjectBuilder(); // Need to copy over everything except the current value, which we instead
// Need to copy over everything except the current value, which we instead // reach in and get the default value
// reach in and get the default value cJson.forEach((k, v) -> {
cJson.forEach((k, v) -> { if ("value".equals(k)) {
if ("value".equals(k)) { Object defaultValue = ((BaseCharacteristic) c).getDefault();
Object defaultValue = ((BaseCharacteristic) c).getDefault(); if (defaultValue instanceof Boolean) {
if (defaultValue instanceof Boolean) { cBuilder.add("value", (boolean) defaultValue);
cBuilder.add("value", (boolean) defaultValue); } else if (defaultValue instanceof Integer) {
} else if (defaultValue instanceof Integer) { cBuilder.add("value", (int) defaultValue);
cBuilder.add("value", (int) defaultValue); } else if (defaultValue instanceof Double) {
} else if (defaultValue instanceof Double) { cBuilder.add("value", (double) defaultValue);
cBuilder.add("value", (double) defaultValue); } else {
} else { cBuilder.add("value", defaultValue.toString());
cBuilder.add("value", defaultValue.toString()); }
} } else {
} else { cBuilder.add(k, v);
cBuilder.add(k, v);
}
});
characteristics.add(cBuilder.build());
} catch (InterruptedException | ExecutionException e) {
} }
}); });
characteristics.add(cBuilder.build());
} catch (InterruptedException | ExecutionException e) {
}
});
serviceBuilder.add("c", characteristics); serviceBuilder.add("c", characteristics);
if (!service.getLinkedServices().isEmpty()) { if (!service.getLinkedServices().isEmpty()) {