[SOLVED] How to use XML Channel Groups in own ThingTypeProvider?

I’ve solved the issue. It turns out I’ve made a bug in XML definitions, so they didn’t show in ChannelGroupTypeRegistry. After I’ve fixed XMLs it’s all working now

[Original message here]
Hi,

I am trying to create my own binding with dynamic Thing Types, but the Channel Groups I want to use in them I want to define in XMLs. How do I create ChannelGroupDefinition to pass into ThingType constructor to make it use channel groups from XML?

Thanks a lot,
~Kamilos

Hi Kamilos,

You can have a look into the code of the OpenWeatherMap binding to get a clue how it works (see OpenWeatherMapWeatherAndForecastHandler.java).

Does it fit? If not please ask again or share your existing code for research.

1 Like

Hi Christoph,

If I understand example you provided correctly, it just creates things dynamically and pushes channels as is without creating any new type. I was thinking more about less brutal way with creating ThingTypes with ThingTypeProvider.

My use-case is - I have devices providing REST API in form of Components which implement Interfaces (like Switch or Dimmer). So I want to have each Component contained in device as single Thing, and each Interface would be a ChannelGroup in it. I have Channels and ChannelGroups defined in XMLs, but want to create new ThingTypes during Discovery (and re-use it if necessary).

So I have a method that gets list of interfaces on the input, and returns ThingTypeUID of existing type if it matches one of existing ThingTypes or creates new if one does not exist yet.

public ThingTypeUID getThingTypeUIDForInterfaces(ArrayList<String> interfaces) {
    for (CXSmartHomeThingType type : availableThingTypes) {
        if (type.getInterfaces().equals(interfaces)) {
            return type.getThingTypeUID();
        }
    }

    // If we are here that means we do not yet have ThingType for component with those interfaces\
    String newTypeName = randomString.nextString();
    ArrayList<ChannelGroupDefinition> channelGroupDefinitions = new ArrayList<>();

    for (String interfaceName : interfaces) {
        channelGroupDefinitions
                .add(new ChannelGroupDefinition(interfaceName.toLowerCase() + "-interface", new ChannelGroupTypeUID(
                        CXSmartHomeBindingConstants.BINDING_ID, interfaceName.toLowerCase() + "-interface")));
    }

    ThingType newType = ThingTypeBuilder
            .instance(CXSmartHomeBindingConstants.BINDING_ID, newTypeName,
                    "CXSmartHome Dynamic Thing " + newTypeName)
            .withDescription("CXSmartHome Component supporting interfaces: " + interfaces)
            .withChannelGroupDefinitions(channelGroupDefinitions).build();

    availableThingTypes.add(new CXSmartHomeThingType(newType, interfaces));

    return newType.getUID();
}

Channel groups in XML follow convention of “-interface” naming. Creation of new ThingType I have figured out yet, but I am not sure how to implement the part with ChannelGroupDefinitions to get them from XML, because so far I have new types, but they have no Channels. After discovery when I try to add discovered Thing I get this error

2019-03-11 10:56:05.406 [DEBUG] [r.JSONResponse$ExceptionMapper:200  ] - exception during REST Handlingjava.lang.NullPointerException: null
	at org.eclipse.smarthome.io.rest.core.internal.thing.ThingTypeResource.convertToChannelGroupDefinitionDTOs(ThingTypeResource.java:220)
	at org.eclipse.smarthome.io.rest.core.internal.thing.ThingTypeResource.convertToThingTypeDTO(ThingTypeResource.java:203)
	at org.eclipse.smarthome.io.rest.core.internal.thing.ThingTypeResource.getByUID(ThingTypeResource.java:168)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:144)
	at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
	at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)

Alright. Even better. I am glad you foud a solution for it.