Dynamic Channels not working

Hello,

I want to add some more features to my binding on user requests. I am trying to add channels dynamic during runtime. I looked on other bindings how to do that, however it is not working out as expected.
I have a JSON call which retrieves an array of similar objects just with different values. I deserialize them and based on the result I would like to create channels for it. I used the following code to do that

The direction is different for every object, so I use it as identifier by adding the channels:

 protected List<Channel> createDynamicChannels() {
        SonnenJsonPowerMeterDataDTO[] dataArray = serviceCommunication.getPowerMeterDatas();
        List<Channel> channels = new ArrayList<>();
        for (SonnenJsonPowerMeterDataDTO data : dataArray) {
            String direction = data.getDirection();
            channels.add(buildChannel(direction + "_" + SonnenBindingConstants.DIRECTIONSTATE, "String"));
            channels.add(buildChannel(direction + "_" + SonnenBindingConstants.AL1STATE, "Number:Power"));
            channels.add(buildChannel(direction + "_" + SonnenBindingConstants.AL2STATE, "Number:Power"));
            channels.add(buildChannel(direction + "_" + SonnenBindingConstants.AL3STATE, "Number:Power"));
...

This I use to create the channel:

 private Channel buildChannel(String channelType, String itemType) {
        return ChannelBuilder.create(new ChannelUID(getThing().getUID(), channelType), itemType).build();
    }

In the initialization is used:

List<Channel> channels = createDynamicChannels();
            ThingBuilder builder = editThing();
            builder.withChannels(channels);
            updateThing(builder.build());

The effect is that the static channels I have configured in the things.xml are after disappearing and the dynamically created channels are not appearing.

I also tried, which seems to be the better solution, but I never hit changed part:

 List<Channel> channels = createDynamicChannels();
            ThingBuilder builder = editThing();
            boolean changed = false;
            for (Channel channel : channels) {
                // we only want to add each channel, not replace all of them
                if (getThing().getChannel(channel.getUID()) == null) {
                    builder.withChannel(channel);
                    changed = true;
                }
            }
            if (changed) {
                updateThing(builder.build());
            }

As you may see, I am not quite familiar yet with the concept of dynamic channels. Do I need to define the possible channels in the things.xml like I did with the static ones? I tried, did not work either.

Any hints what I am doing wrong or miss?

Your static channels are disappearing in your first code because .withChannels replaces the current channels with the provided list of channels. You need to use .withChannel instead.

Do I need to have something defined in the things.xml or is this not needed? I used in my second approach withChannel, but it does not work either as you may see above.

I found the problem, however when I update the Thing I don’t see the channels in the OpenHab UI. Why so? I still see my old static ones, but not the new dynmic added ones.

You should probably use the channel builder from the callback, like I do it here: addons/OwBaseThingHandler.java at 813a17163dcd1c52ba11fe4dc8755f3bfd899b70 · smarthomej/addons · GitHub. I didn’t look up if a ChannelTypeUID is necessary. In that case you should define the channel types either in the XML or dynamically with a ChannelTypeProvider.

I used the code snippets out ot the Bluetooth Binding. It should work though. However I will try your solution. Lets see if it works.

According to Documentation here Updating Thing Structure my implementation is correct and should work. I wonder why it does not show the channels afterwards.

As far I remember using dynamic channels might require thing or bridge XML declaration to have extensible attribute with list of channels possible to define. However in your case it seems to be a meter with channels which might or might not be present or linked. If so, then you can try using channelLinked/channelUnlinked methods in ThingHandler.

One thing I noticed while working on various bindings - its best if you could model channels in a way where you place variable parts into configuration instead of declaring new channel type. Most of cases where I saw dynamic channel types needed is when number of channel permutations is large enough to spam XML declarations. Then having a custom ThingTypeProvider and ChannelTypeProvider allows to calculate first predefined channel types and return extensible thing type.

My own experiences with appended channels also told me that it might be troublesome when thing is not “editable” because it is defined in text configuration. Reasonable practice I found useful is building channels from discovered device properties but only if channel list is empty or dedicated config “switch” is activated. By this way end user can write down discovered channels and its configuration into text configuration.

Good luck & cheers,
Łukasz