Channel Templates

You go to Channels → Add Channel then you define the channel.
Or go to Code and type in the channels yourself.

Example:

version: 1
things:
  mqtt:topic:testdefault:
    config:
      availabilityTopic: asdf
    channels:
      xxx:
        type: string
        label: 'xxxxx '
        description: ""
        config:
          formatBeforePublish: '%s'
          retained: false
          postCommand: false
      blah-channel:
        type: string
        description: ""
        config:
          stateTopic: blah/blah
          commandTopic: blah/blah

Cool! I didn’t know / never looked at that before!

But, what is the vision with the template system? You pick a template somewhere, and then the channels are partially filled out for you? Can the template fill out everything, I would assume that user input would be needed, and how would that look? Using ConfigDescriptionParameters like rule templates do?

I’d imagine, it’s just a pre-typed list of channels for you.

Imagine you’re adding a coloured light, you’d have channels for

  • power
  • color mode
  • color
  • color temperature
  • brightness
  • availability
  • rssi

For each channel you’d have to define stateTopic / commandTopic and possibly in/out transformations.

Typing all that (or even adding via UI) is quite long and tedious especially when you have to do it on 20+ Things over and over again.

If someone had pre-typed it for you, you’d just copy paste and replace the relevant parts (device id).

There is a generic syntax for them but what properties there are for the Thing and Channels are necessarily different between the bindings.

I only know how it appears from the user side of things. And from that side the user creates the Channels manually. You do select the type of the Channel in the process.

If you operate at the Thing DSL/YAML/JSON level, absolutely. Just like with rule templates it’s a simple string substitution. It doesn’t matter how the binding handles it internally.

Very similar actually but that shouldn’t matter.

The same system that works for rule templates.

That’s the problem. The Zigbee binding absolutely supports all standard Zigbee devices. But stuff from Hue, Ikea, Xaiomi, Aquara, etc add their own crap to the Zigbee protocol. So for the binding to support those, special processing needs to be added. So many use Zigbee2MQTT because they have a much larger set of contributors that are better able to keep up with the non-standard stuff all these vendors throw out there.

I can do HTTP and MQTT.

version: 1
things:
  http:url:adguard:
    label: AdGuard
    location: Global
    config:
      baseURL: http://charybdis:3000/control
      refresh: 30
      timeout: 3000
      delay: 0
      bufferSize: 2048
      username: me
      password: password
      authMode: BASIC_PREEMPTIVE
      stateMethod: GET
      commandMethod: POST
      contentType: application/json
      headers:
        - ""
      ignoreSSLErrors: true
    channels:
      protection_status:
        type: switch
        label: Protection Status
        description: ""
        config:
          stateTransformation:
            - JSONPATH:$.protection_enabled
          commandTransformation:
            - "JINJA:{\"protection_enabled\": {{value}}}"
          stateExtension: /status
          commandExtension: /dns_config
          onValue: "true"
          offValue: "false"
          mode: READWRITE
      last-success:
        type: request-date-time
        label: Last Success
      last-failure:
        type: request-date-time
        label: Last Failure

If I were to make this a tempalte, the baseURL, username, and password properties would be parameters. The rest would be part of the template.

Here’s an MQTT one:

version: 1
things:
  mqtt:topic:broker:basement_waveplus:
    bridge: mqtt:broker:broker
    label: Basement Airthings Wave Plus
    location: Den
    config:
      availabilityTopic: waveplus_bridge/basement/status
      transformationPattern:
        - MAP:config:map:waveplus
    channels:
      radon_st:
        type: number
        label: Short Term Radon Average
        description: ""
        config:
          stateTopic: waveplus_bridge/basement/radon_st
      radon_lt:
        type: number
        label: Long Term Radon Average
        description: ""
        config:
          stateTopic: waveplus_bridge/basement/radon_lt
      co2:
        type: number
        label: CO2
        description: ""
        config:
          stateTopic: waveplus_bridge/basement/co2
          postCommand: false
          unit: ppm
      temperature:
        type: number
        label: Temperature
        description: ""
        config:
          stateTopic: waveplus_bridge/basement/temperature
          unit: °C
      pressure:
        type: number
        label: Barometric Pressure
        description: ""
        config:
          stateTopic: waveplus_bridge/basement/pressure
          unit: hPa
      humidity:
        type: number
        label: Humidity
        description: ""
        config:
          stateTopic: waveplus_bridge/basement/humidity
          unit: '%'
      voc:
        type: number
        label: Volatile Organic Chemicals
        description: ""
        config:
          stateTopic: waveplus_bridge/basement/voc
          unit: ppb
      illuminance:
        type: number
        label: Illuminance
        description: Amount of light
        config:
          stateTopic: waveplus_bridge/basement/illuminance
          unit: lx
      battery:
        type: number
        label: Battery
        description: ""
        config:
          stateTopic: waveplus_bridge/basement/battery
          unit: '%'

For this one, the “waveplus_bridge/basement” part of each Channel config would be defined in the template and the rest would remain, though I might change the map transformation to something inline instead of a separate config.

In both cases these are generic bindings used to access some third party’s API. If you are using AdGuard Home or WavePlus_Bridge and these were published as templates, all a user would have to do is instantiate the Thing and supply a couple of parameters and they too can integrate these third party tools with OH with much less configuration.

Me too.

What I’m really thinking is a lot fo third party stuff have a relatively simple REST API. Heck, even NOAA’s weather service has a pretty simple REST API. One could support these with Thing templates instead of needing to build a brand new binding.

This could be particularly powerful for modbus I think based on what I know about how that works.

Yes, it’ll need it’s own category. I can’t see these going anywhere in the existing categories. And we should try to support defining more than one Thing per posting. That works for rule templates now so I don’t think it’ll be too hard for Thing templates.

I like how rule templates work now with the list of installed templates collapsed by default. But you can click through to get the list.

I can see the follwoing workflow.

  1. Go to Things and click +
  2. Still select the binding
  3. Under Add Manually you can get a list of all the templates for that binding to choose from if you are creating a Thing from a template. But it only shows templates for that binding.

For installation, to be consistent with widgets, block libraries, and rule templates there would be a new section under the bindings category in the Add-on store. That’s where you would browse, add or remove the tempaltes.

That would certainly work and require no changes to OH itself. One would just need to create a dedicated category in the forum to post them to.

But we already have all these others supported. It doesn’t see too much of a stretch to support Thing templates the same way.

You’d create each Thing individually but that’s no worse that it is now. And you probably wouldn’t do this for Zigbee in the first place (see discussion above about bindings that already support discovery). And this use case isn’t really the main use case these templates would be used for.

The main use case, as I see it, is someone somewhere figured out how to access all the data from NOAA (for example) using just HTTP Things, no rules no binding (Note, I did this myself a couple years ago and posted a tutorial about it somewhere). They can post a rule template to the forum and now any user can create the Things that can do this to with a few clicks. In the case of NOAA.

However, if there is a change needed, if it works like rule templates, we could have a regenerate button. So if we install an update to the template, or work with a local template, applying changes would just be a matter of selecting all the Things created with that template and hitting “regenerate”.

The full work flow to create a Thing from a template would be (assuming the template is already installed):

  1. Go to Things and click +
  2. Select the binding
  3. Under “Add manually” select the template you want to use
  4. Fill out the two-four properties defined by the template to make that Thing uinique (including ID, label and description)
  5. Hit save
  6. Repeat for the remaining Thing.

This is already a whole lot less work than manually creating each one fully individually and less error prone than copy/paste/edit or using “duplicate thing” because error checking is built in to the properties (e.g. if you need to select a Bridge Thing like you would for a Generic MQTT Thing, that property gives you a list of only MQTT Bridge Things to choose from. But most of the time, only one or two Things would be created from each template.

Updates would be:

  1. Go to Things and select all the Things created with the template(s) that were updated
  2. click “regenerate”

See above for how I see it working.

Here is what I would expect my HTTP thing to look like as a template:

version: 1
thingTemplates:
  adGuardHome:
    configDescriptions:
      host:
        # property config for a hostname and port number
      user:
        # plain text property config
      password:
        # password property config    config:
    baseURL: {{host}}/control
    refresh: 30
    timeout: 3000
    delay: 0
    bufferSize: 2048
    username: {{user}}
    password: {{password}}
    authMode: BASIC_PREEMPTIVE
    stateMethod: GET
    commandMethod: POST
    contentType: application/json
    headers:
      - ""
    ignoreSSLErrors: true
    channels:
      protection_status:
        type: switch
        label: Protection Status
        description: ""
        config:
          stateTransformation:
            - JSONPATH:$.protection_enabled
          commandTransformation:
            - "JINJA:{\"protection_enabled\": {{value}}}"
          stateExtension: /status
          commandExtension: /dns_config
          onValue: "true"
          offValue: "false"
          mode: READWRITE
      last-success:
        type: request-date-time
        label: Last Success
      last-failure:
        type: request-date-time
        label: Last Failure

Completely filled out for you, and the custom parts are asked for in a parameter.

Same as for rule templates and widgets.

See Parameter Playground for a mostly comprehensive example of all we can do with configDescription parameters.

Those with “Map” actually bring up a map to select a location.

The Item selectors only bring up a list of Items of the defined type.

Exactly.

That sounds great @rlkoshak.

By the way, with rule templates, is there a way to see when the template:

  • has a new version on the marketplace that we can download
  • after the new version downloaded, the rules themselves shows that a new template is available for regeneration?

You’re basically envisioning the same system that exists for rule templates :+1:

Still, I think there is something that has to be figured out about the link to ThingTypes/ChannelTypes, because I believe that all the parameters are already defined as ConfigDescriptionParameters there. So, if one could figure this out, there might not be a need to actually define any of that in the template, just to somehow indicate what parameters should be entered by the user.

No, this falls under the same “project” I worked on previously, trying to make the marketplace versioned. Currently, there is no versioning on the marketplace, so the concepts of “updated” or “new version” don’t exist. But, if versioning is ever implemented on the marketplace, they would benefit like everything else.

The way it is for rule templates is that you Ctrl+click the “template badge” to automatically select all rules that use that template. Then you just press “Regenerate”. There is no “automatic warning” that the currently installed version of the rule template is different from the version you used to generate the rule, because - they aren’t versioned.

Could we simply (or in addition to future version number) use last updated timestamp?

Have a look in this file:

I think you’ll find that any parameter that exists for that ThingType is already defined:

It would be possible, but quite pointless as I see it. There would be no way for the user to check what has changed and to decide if he/she wants to update or not.

We’d need to replace part of the MQTT Topic, e.g.

zigbee2mqtt/{{device-id}}/blah/blah

Ok - but I’d still imagine that some of the information could be recycled. Perhaps some of the settings would need to be set in their entirety?

The reason I’m focusing on that, is that the “worst part” of creating a rule template is, in my opinion, to create the config descriptions. Any manual work that could be avoided in that regard, I’m sure would be appreciated.

Pretty much. It’s the same problem as I see it, why not use the same solution?

But you may only want to replace part of a parameter like I showed with the baseURL parameter in the example above.

If the poster of the template is doing it correctly, there should be a change log under “Versions” that list what’s changed.

Not many would be able to do much with more than that (e.g. code diff between versions).

This assumes everyone posting a tempalte does it correctly but if we start to police it we end up back with the same things that were rejected before regarding too much policing.

Yes, and I don’t see “clearly” how this could be done, but let’s say that you could find a way to either only list the name of the property, and if it matches something in the thing/channel type it would use those definitions, or you could specify the whole thing manually. Or even some kind of “inheritance” system where, if the name matched, it would populate it with what’s from the thing/channel type, and then let your setting override those. So, you could get away with just filling in what’s differet.

The thing/channel type definitions are already pre-filled with all kind of “goodies”, like option values, labels, descriptions, the correct context, the type, etc.

That’s not what I meant - this is how it would work with versioning support, where you would know which version you have installed, and which version is offered. This was about using a timestamp for when the post was last updated (or something like that) to trigger some kind of “update available” notification, and my point here is that it would be pretty futile as long as you have no idea what version you have installed. The “update available” would be activated if you corrected a typo in the post, not only when you actually release a new version, and since the user has no way of knowing what he/she has installed, most would probably believe that this meant that they didn’t have the latest one installed, when there’s not really any correlation between the notification and the version.

The focus of a Thing template should be first and foremost to make things easier for the user of the template. Anything that makes the job of the author of the template easier at the expense of the user should be avoided.

Which will not be correct and relevant or understandable taken out of context much of the time. Even if those “goodies” are there, they often will need to be overridden to make the vastly reduced form presented to the user make sense.

And the context may not always be correct for the specific parameter being filled in so that needs to be overridden too some times.

But you could know when you installed it. If you installed it before the update you can assume there’s a new version. It’s not perfect but it is servicable.

What’s the harm here though? The user ends up updating to the exact same version they have now. I’m not saying it’s ideal but if it’s a choice between never knowing an update is available and needing to manually check and do everything compared to needlessly updating a little more often than otherwise would be required because updates to the text of the post were made but not the code, needlessly updating is a far better end user experience over all and a great improvement of what exists now.

In practice, these posts are not updated very frequently.

I don’t see those as opposing things, if it’s easier for the author to make it “properly”, it’s easier for the user to use it as well.

I was just saying that I think it would be beneficial if a way to utilize the existing information was found. I’m not sure how this would be linked, but say for example that the name of the parameter was the link. For fields that should be specified in their entirety, like username, password, hostname etc., only the names would need to be specified in the template, and the info would be populated. When you need partial field information, there could be a “convention” that you prefixed the name with part or something like that, or just that you chose another name, and nothing would be inherited and the entry would be “completely manual”.

How would you know? This isn’t currently stored anywhere as far as I know, and there are major problems with the “installed add-ons” entry in the JSONDB as I’ve mentioned many times before, where it keeps getting wiped out for various reasons.

I know something about this, because it’s basically the same challenge that I’ve been trying to solve in my marketplace versioning branch. There currently is nowhere to store the information, and add-ons of different types are handled very different, so it’s very hard to find some way that can apply to all. Storing it in the JSONDB entry that is created for marketplace add-ons is basically pointless, because it is wiped out for a number of reasons, and a lot of refactorings would be required to rectify that so that this information could actually be something you could depend on.

I’m probably not aligned with most people here, I’m aware, but to me this goes straight to “integrity”. You’ll basically lie and say that there’s an update when there might not be, and you’d leave the confusion of figuring this out to the user. Even if doing a “double update” has no real harm, it’s a waste of the user’s time, to first update the add-on, and then regenerate all the things, when nothing has really changed. To me, “honesty” always comes first, and you should not say that “there is an update” if there isn’t.

And, you still have the same challenge as mentioned above. Where would you store the information about the timestamp of your currently installed add-on/template? The only “logical” place would be in the JSONDB marketplace table, but it would be futile, because it is regularly wiped. I bet that if you open up the JSONDB marketplace table on pretty much any installation, and compare the contents with what marketplace add-ons are actually installed, it will only be correct if you have nothing from the marketplace installed, or before you’ve restarted OH after installing them.

Not if the user has to figure out every topic manually. One of the main uses for this would be to provide, for example, the root part of a URL or an MQTT topic and the tempalte supplies the rest. If the end user is limited to filling out in total only those properties that are predefined by the binding tha’s not possible.

And the perfect wins out over the good and the end users suffer because it can’t be made perfect.

We could always show what’s different, and if programmatically there’s no difference then exclude them from the list of “new updates”.

But, this isn’t what I suggested. What I suggested was to try to find a way to reuse these when the whole field is substituted, like for a username, hostname/IP address, password etc. I never suggested preventing a manual definition in the template, or just replacing part of the value.

I’m just expressing my opinion, and shedding light on some obstacles. To me, lying/misleading and “the perfect” is on opposite sides of the scale though, integrity is on the “the absolute basics that have to be fulfilled”, not on the “perfect” end.

How can you show a diff when you don’t know what version or date is installed on the system? This is what I’m trying to tell you guys, that information doesn’t exist.

Then make it exist?

Please read what I wrote above, this is one of the major challenges with making things versioned in the first place. It’s not a small challenge to get this to work reliably. Sure, it’s easy to just slam it in somewhere and call it a day, but it will fail, and it will cause just more user frustration and long-standing bugs with no easy fix.