mirror of
https://github.com/danieldemus/openhab-addons
synced 2026-07-29 12:34:21 +02:00
[homekit] Support bridges with hardware embedded accessory things (#19965)
Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
This commit is contained in:
@@ -17,6 +17,7 @@ There are three types of Things supported:
|
||||
|
||||
Things of type `bridge` and `accessory` both communicate directly with their HomeKit accessory device via the LAN.
|
||||
Whereas `bridged-accessory` Things communicate via their respective `bridge` Thing.
|
||||
Sometimes a `bridge` may contain a `bridged-accessory` that is physically embedded within the same hardware.
|
||||
|
||||
## Discovery
|
||||
|
||||
@@ -55,6 +56,7 @@ The following table shows the Thing configuration parameters for `bridged-access
|
||||
As a general rule `accessoryID` is set by the auto-discovery process.
|
||||
However you can configure it manually if you wish.
|
||||
It must be the ID of the `bridged-accessory` within the `bridge`.
|
||||
The `accessoryID` is probably "1" for a `bridged-accessory` that is physically embedded within the same hardware as its `bridge`.
|
||||
|
||||
## Thing Pairing
|
||||
|
||||
|
||||
+22
-9
@@ -15,16 +15,21 @@ package org.openhab.binding.homekit.internal.discovery;
|
||||
import static org.openhab.binding.homekit.internal.HomekitBindingConstants.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.homekit.internal.dto.Accessory;
|
||||
import org.openhab.binding.homekit.internal.dto.Content;
|
||||
import org.openhab.binding.homekit.internal.handler.HomekitBridgeHandler;
|
||||
import org.openhab.core.config.discovery.AbstractThingHandlerDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
@@ -60,27 +65,35 @@ public class HomekitBridgedAccessoryDiscoveryService
|
||||
@Override
|
||||
public void startScan() {
|
||||
if (thingHandler instanceof HomekitBridgeHandler handler) {
|
||||
discoverBridgedAccessories(handler.getThing(), handler.getAccessories().values());
|
||||
discoverBridgedAccessories(handler.getThing(), handler.getAccessories().values(),
|
||||
handler.getTranslationProvider(), handler.getBundle());
|
||||
}
|
||||
}
|
||||
|
||||
private void discoverBridgedAccessories(Thing bridge, Collection<Accessory> accessories) {
|
||||
private void discoverBridgedAccessories(Thing bridge, Collection<Accessory> accessories,
|
||||
TranslationProvider i18nProvider, Bundle bundle) {
|
||||
String bridgeUniqueId = thingHandler.getThing().getConfiguration()
|
||||
.get(CONFIG_UNIQUE_ID) instanceof String uniqueId ? uniqueId : null;
|
||||
if (bridgeUniqueId == null) {
|
||||
return;
|
||||
}
|
||||
accessories.forEach(accessory -> {
|
||||
if (accessory.aid instanceof Long aid && aid != 1L && accessory.services != null) {
|
||||
if (accessory.aid instanceof Long aid && accessory.services != null) {
|
||||
ThingUID uid = new ThingUID(THING_TYPE_BRIDGED_ACCESSORY, bridge.getUID(), aid.toString());
|
||||
String uniqueId = STRING_AID_FMT.formatted(bridgeUniqueId, aid);
|
||||
String label = THING_LABEL_FMT.formatted(accessory.getAccessoryInstanceLabel(), uniqueId);
|
||||
thingDiscovered(DiscoveryResultBuilder.create(uid) //
|
||||
.withBridge(bridge.getUID()) //
|
||||
.withLabel(label) //
|
||||
.withProperty(CONFIG_ACCESSORY_ID, aid.toString()) //
|
||||
.withProperty(PROPERTY_UNIQUE_ID, uniqueId).withRepresentationProperty(PROPERTY_UNIQUE_ID)
|
||||
.build());
|
||||
if (aid != 1L || Optional.ofNullable(accessory.services).stream().flatMap(List::stream)
|
||||
.flatMap(service -> Optional.ofNullable(service.characteristics).stream()).flatMap(List::stream)
|
||||
.map(characteristic -> characteristic.getContent(uid, null, i18nProvider, bundle))
|
||||
.anyMatch(Content.ChannelDefinition.class::isInstance)) {
|
||||
// if aid #1 yields at least one channel definition then also discover an embedded thing for it
|
||||
thingDiscovered(DiscoveryResultBuilder.create(uid) //
|
||||
.withBridge(bridge.getUID()) //
|
||||
.withLabel(label) //
|
||||
.withProperty(CONFIG_ACCESSORY_ID, aid.toString()) //
|
||||
.withProperty(PROPERTY_UNIQUE_ID, uniqueId).withRepresentationProperty(PROPERTY_UNIQUE_ID)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+14
-8
@@ -79,13 +79,16 @@ public class Characteristic {
|
||||
* whereas characteristics with dynamic values return a {@code ChannelDefinition} record.
|
||||
* Examines the characteristic type, data format, permissions, and other properties to determine the appropriate
|
||||
* Content type and, where relevant, the channel type, item type, tags, category, and attributes. In the case of a
|
||||
* 'ChannelDefinition' the method also builds a ChannelType and registers it with the provided HomekitTypeProvider.
|
||||
* 'ChannelDefinition' the method also builds a ChannelType and if a HomekitTypeProvider is provided then registers
|
||||
* it with that provider.
|
||||
*
|
||||
* @param thingUID the ThingUID to associate the ChannelDefinition with.
|
||||
* @param typeProvider the HomekitTypeProvider to register the channel type with.
|
||||
* @param typeProvider the HomekitTypeProvider to register the channel type with; may be null.
|
||||
* @param i18nProvider the TranslationProvider for localizing option labels.
|
||||
* @param bundle the Bundle for localization context.
|
||||
* @return the {@link Content} or null if it cannot be mapped.
|
||||
*/
|
||||
public @Nullable Content getContent(ThingUID thingUID, HomekitTypeProvider typeProvider,
|
||||
public @Nullable Content getContent(ThingUID thingUID, @Nullable HomekitTypeProvider typeProvider,
|
||||
TranslationProvider i18nProvider, Bundle bundle) {
|
||||
CharacteristicType characteristicType = getCharacteristicType();
|
||||
DataFormatType dataFormatType;
|
||||
@@ -833,9 +836,10 @@ public class Characteristic {
|
||||
String channelTypeLabel = characteristicType.toString();
|
||||
|
||||
if (!isStateChannel) {
|
||||
ChannelType channelType = ChannelTypeBuilder.trigger(channelTypeUid, channelTypeLabel).build();
|
||||
typeProvider.putChannelType(channelType);
|
||||
|
||||
if (typeProvider != null) {
|
||||
ChannelType channelType = ChannelTypeBuilder.trigger(channelTypeUid, channelTypeLabel).build();
|
||||
typeProvider.putChannelType(channelType);
|
||||
}
|
||||
} else {
|
||||
if (itemType == null) {
|
||||
return null;
|
||||
@@ -911,8 +915,10 @@ public class Characteristic {
|
||||
}
|
||||
|
||||
// persist the (state) channel TYPE
|
||||
ChannelType channelType = chanTypBldr.build();
|
||||
typeProvider.putChannelType(channelType);
|
||||
if (typeProvider != null) {
|
||||
ChannelType channelType = chanTypBldr.build();
|
||||
typeProvider.putChannelType(channelType);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+8
@@ -162,4 +162,12 @@ public class HomekitBridgeHandler extends HomekitBaseAccessoryHandler implements
|
||||
// a bridge requires all enabled bridged-accessories to be ready
|
||||
notReadyThings.addAll(getThing().getThings().stream().filter(thing -> thing.isEnabled()).toList());
|
||||
}
|
||||
|
||||
public TranslationProvider getTranslationProvider() {
|
||||
return i18nProvider;
|
||||
}
|
||||
|
||||
public Bundle getBundle() {
|
||||
return bundle;
|
||||
}
|
||||
}
|
||||
|
||||
+1057
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user