Discovery overwrites configuration of existing things

Hello, I’m having problems with discovery service of Nuki binding I’m updating. The discovery process for discovering Nuki bridges works like this:

  • User starts discovery, the binding calls API for obtaining list of Nuki bridges on the same network
  • Binding attemps to obtain API token for each bridge by calling HTTP endpoint on the bridge
  • If user then presses button on the bridge, that HTTP call succeedes and returns valid API token. Binding then creates bridge with token as a discovery result
  • If user fails to press button within 30s, the HTTP call fails, binding then creates discovery result wihtout token (and user must supply it manually)

Every time discovery is started, it will discover the same bridge which was already previously configured. User does not expect this and won’t press the button on bridge again and thus after the 30s interval bridge is discovered without API token. But since the id of bridge is the same as the id of existing bridge, it is not displayed in inbox as a new thing.

Now the problem - every time bridge discovery result is created without token, it will call initialize() method on existing bridge, but now getConfigAs method returns configuration without API token - the discovery result rewrites configuration of existing thing.

Is there a way to prevent this? Maybe somehow get list of existing things when starting discovery and skip discovering already configured bridges?

This sounds like something unique to the Nuki binding. If there is no other advice here, I recommend opening a new issue on the openhab-addons repo. See How to file an Issue.

I’ve moved your post to a more appropriate category.

I don’t think we understand each other. I’m the one implementing discovery service in nuki binding and I’m having problems with openHab API.

I’ll try to rephrase it:

  • The binding has a Thing with “apiToken” configuration property and unique identifier.
  • The discovery service I’m implementing will always discover the Thing with specific id, even if it was already discovered and is configured, but sometimes without “apiToken”

The problem is that when i call thingDiscovered on DiscoveryService with DiscoveryResult that has same id as the one that already exists but without “apiToken”, the existing already configured Thing will have it’s “apiToken” overwritten and set to null.

I’d like to know if there’s some way to solve this. Perhaps some API I can use to get list of existing things to check if thing with same id already exists, so I can skip creating DiscoveryResult.

In that case this thread is better placed in the Development categories. I’ll move it so the developers are more likely to see it.

You better post a link to your code, so others can have a look and try to help.

The full source code for the discovery service is here - openhab-addons/NukiBridgeDiscoveryService.java at main · janvyb/openhab-addons · GitHub

The code which creates discovery result looks like this:

private void discoverBridge(WebApiBridgeDto bridgeData, String token) {
        String name;
        if (token.isBlank()) {
            logger.debug("Nuki bridge {}({}) discovered without api token", bridgeData.getIp(),
                    bridgeData.getBridgeId());
            name = "Nuki Bridge (no API token)";
        } else {
            logger.info("Nuki bridge {}({}) discovered and initialized", bridgeData.getIp(), bridgeData.getBridgeId());
            name = "Nuki Bridge";
        }

        DiscoveryResult result = DiscoveryResultBuilder
                .create(new ThingUID(NukiBindingConstants.THING_TYPE_BRIDGE,
                        generateBridgeId(bridgeData.getBridgeId())))
                .withLabel(name).withProperty(NukiBindingConstants.PROPERTY_BRIDGE_ID, bridgeData.getBridgeId())
                .withProperty(NukiBindingConstants.CONFIG_IP, bridgeData.getIp())
                .withProperty(NukiBindingConstants.CONFIG_PORT, bridgeData.getPort())
                .withProperty(NukiBindingConstants.CONFIG_API_TOKEN, token)
                .withRepresentationProperty(NukiBindingConstants.PROPERTY_BRIDGE_ID).build();
        thingDiscovered(result);
    }

Ok, since apparently there is no API which I can query to check if some thing already exists or not, I’ve created my own service which keeps track of created things (using createHandler and removeThing on ThingHandlerFactory). I then check it during bridge discovery and skip bridges which already exist.

1 Like

I have understood that we have withRepresentationProperty exactly for this purpose. See corresponding documentation Thing Descriptions | openHAB

The representation property is used to auto-ignore discovery results of Things that already exist in the system.

Is the id you use here unique always?

Yes, it is computed from nukiId and is unique for each device.
What I find weird is that discovery result with same representation property is ignored from inbox, but at the same time it overwrites all the properties user configured on the existing thing.

Do I understand correctly, that discovery modifys an existing thing only by discovering a thing with the same representation property? Are you sure about that?

In general, the usage of the representation property is the correct way to go.

Yes, that’s exactly what’s happening. Every time the discovery finishes, api_token of existing bridge gets overwritten to null and it gets offline. That’s why I created this thread, this seems like a weird behavior but I don’t think I’m doing anything unusual with the discovery result.

That doesn’t sound like intended behavior. Can you file an issue here Issues · openhab/openhab-core · GitHub

I’m not sure, looking at PersistentInbox:258 source code that’s exactly what it’s meant to be doing:

logger.debug(
		"Discovery result with thing '{}' not added as inbox entry. It is already present as thing in the ThingRegistry.",
		thingUID);

boolean updated = synchronizeConfiguration(result.getThingTypeUID(), result.getProperties(),
		thing.getConfiguration());

It takes properties from discovered thing and replaces existing thing configuration with them.

Interesting. It indeed seems intended.

Is the discovery result usable at all, if the API token is empty? If not, you could skip the invocation of thingDiscovered() for that Thing during discovery.

I believe it is, you still get ip address and port of the bridge filled in automatically, so you don’t have to look it up.

Anyway, all that looking through openHAB core wasn’t for nothing. I found ThingRegistry which is exactly what I was looking for. I’ve injected it into bridge discovery service and use it to check if bridge with the same uuid already exists. Seems like a better solution than rolling my own service.