Hi everyone,
I’m in a bit of a struggle about how to model certain things which may be dynamic in nature. To give a bit of an overview (it’s about the Solax binding).
We’re having an API call which returns a flat array of numeric data which is parsed in a separate channels. The problem is that some data depends on the models and also on the installation. For example:
The inverter has channels like voltage, current, power, etc
Most inverters support multiple photovoltaic arrays (PVs) and depending on the installation they may vary 1…n. Each PV has also counters like voltage, current, power.
Most inverters support battery and now some of the newer inverters started to support multiple batteries which also depend from installation. (in most use-cases 1 battery is sufficient).
So far everything is having a flat, statically defined channels based on the inverter type but with the coming multiple batteries, PVs I think this is no longer sustainable.
I wonder what is the proper way to model this? In the parsing part it’s easy and I will make collections of PVs and Batteries but how about the Thing part - in the openhab layer. Is there a way to create dynamic channels based on the channel type (for example PV1Voltage, PV2Voltage, etc…)?
I don’t know what the proper way but I think a situation like this would usually be represented using multuple Things. If there’s only one battery, well you’d have one battery Thing but if you’ve two you’d have a separate Thing to represent each Thing. Same for the PVs.
This works best if the existence of these can be autodiscovered so your binding can just add them to the Inbox as separate Things.
Yeah… that’s one of the issues. It always returns the same array and just sometimes the values are different. There is no any flag or model in the response which says what you have installed, so the parser probably needs to parse all the capabilities and the user has to choose what he has installed by pointing to the right channels as of now (and maybe to create the necessary things in the future model)
It mioght be possible to just discover the Things as they are discovered in the array. So the first time you get an array create Things in the inbox for every device represented in that array. For future arrays, if there’s stuff in it from a device that doesn’t already have a Thing, create a new Thing for the newly discovered stuff and put that in the Inbox.
It might take some time for all the Things to be discovered but you’ll get them all eventually. And it won’t take any more time than it would for the Items linked to a single Thing to get updated with values.
Each thing or bridge handler can declare additional services which will be registered on behalf of it. By doing so you can implement discovery of children things based on connection handled by its parent.
An example where things are discovered based on incoming connection:
For inverter which is probably modbus or another API call its a bit more complicated to arrange things, but I hope it will help you with some aspects of it. Personally I don’t like much nested things, but sometimes they are needed to properly model dynamic set of channels.
Yes, you can and it’s officially documented. You can find several examples in the present binding implementations. Just search for ChannelBuilder.create in java files in openhab-addons/bundles directory.
I am not 100% sure, but I think that in case of thing provisioned through a thing file above code may lead to an error in the log. Not a big issue, as memory representation should be updated anyway.
The .thing file holds the configuration, not the structure.
The structure is provided by the binding in general by the resources/OH-INF/thing files which are static, but as described above the structure can be changed during runtime.
This will update jsondb with new/removed channels but keep your textual .thing configuration untouched.
No doubt on the configuration part, but thing file can also ship channels. This is one of edge conditions within framework - you can add them through xtext, and as far I know, thing parser will just swallow them and push into runtime. Not sure of most recent core behavior, but with 3.x-4.x jsondb was partially used in such cases:
You may want to look at what I did with the Growatt binding (which is also for a solar inverter).
The Growatt logger can potentially provide data for up to 120 possible field names, whereby in reality different models provide a different subset of those. (e.g. my own inverter provides data for about 30 of the 120 possible field names).
The way I handled it in the Growatt binding is to initially create all 120 possible Channels when the inverter Thing is first instantiated. Then when the first actual data arrives from the logger, all those Channels which did not receive any live data are dynamically deleted gain from the Thing.
Correct, sure you can define channels on well defined protocols like mqtt (if you know the topics) and also modbus (if you know the registers). In this particular case with the mentioned Solax binding …
… I don’t see that you can define the channels on your own without knowing Solax API (flat array).