How should I upgrade existing things when I update my binding?

I have recently started making my first openHAB binding in which I declare thing type descriptions in XML.

I have noticed while developing it that if I create a new version of my binding with new channels that existing things do not get updated with these new channels unless I remove them and add them again.
This has been ok for initial development but isn’t ideal for day-to-day use and seems like an unnecessary burden for people who are testing it.

I know you can update the structure of a thing programmatically but if I am doing that I might as well abandon the XML files and do everything programmatically.

I guess another way would be to give things a “version” property and to recreate the thing in my ThingHandlerFactory if I get passed a thing that is out of date but this seems a bit complex when I just want things to match their XML definition.

Is there a way from inside my binding that I can tell openHAB I want it to make sure things match their XML definitions?

I know for zwave, we are told to delete & rediscover the Things to get the new binding information.

I like that idea

1 Like

Looking into that PR it seems like it has been a known problem for a while.

I guess that means I will have to roll my own update mechanism after all for now. At least it confirms that I am not missing something simple.

Thanks! :slight_smile:

I suggested something similar in the past but it was rejected.

Sadly on closer inspection it looks like that idea is not possible.

I had that idea when I saw that BaseThingHandlerFactory had the methods createThing(...) and removeThing(...) and assumed I could use them to perform the upgrade.

It turns out that removeThing(...) is used to inform a ThingHandlerFactory that a thing has been removed, not to cause a thing to be removed.
createThing(...) weirdly does not seem to have any point at all, it creates a new thing using ThingFactory but does not register it so I can’t think of any good reason to use it instead of using ThingFactory directly.

To remove & recreate a thing it looks like I would need access to the ThingRegistry but it seems that its use in bindings has been deprecated. The few bindings that use a little bit of OSGi magic to get a reference to it all have the following warning:

    // Bindings should not use the ThingRegistry! See https://github.com/openhab/openhab-addons/pull/6080 and
    // https://github.com/eclipse/smarthome/issues/5182

From reading those links it looks like you are only meant to access the ThingRegistry through a ThingHandlerCallback which has thingUpdated(...) but no create/remove methods to force the thing to be recreated from XML.

For now I’ll probably just live with needing to manually remove & re-add things when I update the binding instead of switching over to programmatically updating the structure of things.

1 Like

In the sony one - I implemented my own thing type provider with a listener. A thing will then listen for changes to the thing type. When a new thing type is found (ie new version) by the thing type provider, I create a new thing type (with a new UID) and notify the listener that a new thing type was found (with the new UID). The thing will then call changeThingType on the base thing handler with the new UID to cause it to reload everything.

Doesn’t fully solve what you want - but can give you a good lead on how to do something similar that applies to you…

1 Like

Thanks for telling me about your approach. It is an interesting way of solving the problem that I could see working for me.

My issue is that the things that I am dealing with are all static. No configuration of things can result in new channels needing to be created on-the-fly. I only need to update them when I add capabilities to binding itself.

I was hoping for something very simple because it is probably not really worth investing too much time on a custom thing update system.

I might come back and have a go at it later but for now I think I will focus on other parts of my binding.

Ah - but you can do a simplier approach if you’re static. Simply adopt a thing type UID that ends in a number (like “myId-{nbr}”). Then when you release a new version - simply update the number to the next one.

Now - when your thing is being created, get the current thing type UID, extract the number and then check to see if the “myId-{nbr+1}” exists in the thing type registry and if so, call changeThingType with the new UID.

I’d personally do a loop and take the maximum number found in case someone is a few versions behind…

I doubt this will be merged. As I said: I already implemented something like that and was asked to remove it for a more generic version in core that was never implemented.

I realize this may not be the kind of thing that would be accepted into openhab/openhab-addons @J-N-K as it is a bit of a silly trick but I thought I would post this anyway as I find it quite amusing in its simplicity.

I got an idea after reading your second post @tmrobert8 and decided to check how changeThingType(...) works. It turns out you don’t even need to create versioned ThingTypes.

It turns out that changeThingType(ThingTypeUID, Configuration) only checks that the ThingTypeUID is not null.

This means that it is totally valid to call it like this:

changeThingType(this.thing.getThingTypeUID(), this.thing.getConfiguration());

i.e. “I want you to change my thing into the thing it already is” :stuck_out_tongue:

And the ThingManager will happily recreate your thing for you using the default XML parsing ThingTypeProvider.

Add in a version property to stop you from looping forever and this is all it takes inside your ThingHandler#initialize() to make a thing self-updating:

final @Nullable String thingVersion = this.thing.getProperties().get(BindingConstants.PROPERTY_THING_VERSION);
if (!BindingConstants.CURRENT_THING_VERSION.equals(thingVersion)) {
	final Map<String, String> newProperties = new HashMap<>(thing.getProperties());
	newProperties.put(BindingConstants.PROPERTY_THING_VERSION, BindingConstants.CURRENT_THING_VERSION);

	final ThingBuilder thingBuilder = editThing();
	thingBuilder.withProperties(newProperties);
	updateThing(thingBuilder.build());

	changeThingType(this.thing.getThingTypeUID(), this.thing.getConfiguration());

	return;
}

I’ve tried it out and it works.

2 Likes

It took me a little fiddling to get the scheduling right so I wasn’t trying to update disposed things, but once I got that settled, this worked really nicely.

For the binding for the Bond Bridge used to control ceiling fans, there are a ton of possible channels a fan could have depending on the number of speeds, lighting capabilities, etc. Since the bridge can tell you what channels actually apply, I really wanted to use only those channels and delete everything else. I also really wanted the channels to be nicely grouped - so a fan “thing” could have fan related channels separated from fan-light related channels. I’d spent a bunch of time (too much!!) playing with dynamically adding channels or creating a channel description provider and other tricks the documentation mentions, but nothing I was trying actually worked to make channels disappear and appear in any sort of dynamic way. I’m a total Java novice - I wanted to create a binding and thought “how hard can Java really be?” - and there were essentially no other bindings attempting the same functionality. The MQTT binding is nearly the only one that attempts truly dynamic channels, and even that doesn’t group them. I’d at least figured out how to delete channels and had given up and said, well, if you program a new function to your bridge or anything similar, you’ll have to delete everything in OpenHab and recreate it from scratch. This works so much better.

I’m glad you find it useful. It is a fun little trick.

I’m wary that the method is called changeThingType(…) so it would be totally reasonable for that method to be refactored in the future to do nothing if the new ThingTypeUID matches the current ThingTypeUID.

I still don’t know if I’m going to use it myself or not.

Hopefully some official update mechanism will be introduced in the near future.

That’s very true - I think many of the other “change” methods already have a check so that nothing happens if the change doesn’t actually change anything.

For now, I’m adding it anyway to my bindings. Having to delete things and recreate them is an enormous PITA and it seems totally un-necessary. Every time I’ve updated one of my bindings (my own or ones I’ve downloaded) I’m always questioning “do I really care about these new channels enough to bother?”.

I think I might add it if I do an annoying enough change to thing structure while I am still having people test it and then just remove it again before creating a pull request.
Or who knows maybe just give it a go and see if the openhab-addons maintainers are ok with it until an official mechanism is added.

For personal use you could still pull a silly trick if they updated changeThingType(…).
Just do MyThingUIDDummyThingUIDMyThingUID
But that is starting to get very silly.

I have PR’s outstanding. I’ll let you know if the maintainers let it by.


1 Like

I also want to try to dynamically add/remove Channels in a Discovered Device.
So any hint or advice where to look at would be really welcome :slight_smile:

But nothing I have tried so far worked. I am not a Java Beginner, but I have never worked with OSGI so far. It looks like I am missing on little thing to get it working. I get the xxxxTypeProvider Bean initialized. But then they are never used(Functions defined in there are never called).
What I am trying to write is a Tasmota Binding. Since Tasmota always has > 50 values (wifi, ssid, Powersupply, IP, …) which are available in all Tasmota Devices I thought about implementing these with the ./org.openhab.binding.mqtt.tasmota/src/main/resources/OH-INF/thing/thing-types.xml. But then depending on the Sensors/Actors attached you have o lot channels which only make sense if really this sensor/Actor is attached to the Device.
So my Idea was to add these channels when the Thing is discovered or even later when the thing is created and I see Values for a specific sensor (e.g. Temperature, Humidity, CO2, Voltage, Wattage, …)
With the updateThing trick it looks like I can only change the properties. But I want to change the channels.

As said: Any hint is welcome.

Look here:

This is a very sophisticated example, but I think you can get the idea:

Get a ThingBuilder via editThing, create a Channel via ChannelBuilder and use withChannel (or withoutChannel) on the ThingBuilder. Finally build the thing and use that with updateThing.

Great! … I’ll give it a try :slight_smile: