Offline as a State or a Channel, or both?

I am currently doing some work on the Neohub binding. The binding talks to the hub via TCP over Ethernet, and the hub talks to the devices via a Mesh RF Zigbee connection.

If a device loses its mesh RF connection to the hub, it remains “in” the hub. And the hub continues to provide the last known Channel values (albeit out of date). The hub also provides an OFFLINE flag that reflects the status of the RF mesh connection.

Currently the binding follows this OFFLINE flag, and it updates the device’s Thing Status On/Offline. I am wondering if this is the right thing to do? Another alternative option would be for the device Thing to have an On/Offline Channel? In addition to Thing.Status, or instead of it?

I can see the value of having a Channel since users can then link an Item to it. Which makes it easier to use in rules, sitemaps, or other UI.

What do you think? Is there some official preference or guidance on this?

I seem to recall previous discussions recommending against using a channel to represent the thing status. I think the argument is that channels are intended for thing functionality.

OTOH, I’m not a big fan of the current method, as you need to explicitly check (poll) for the status to find out the thing status. I’d much prefer something that could be put in the when condition of a rule (e.g. Thing status changed to OFFLINE). I’m just not sure how you would deal with all the status changes during startup and shutdown…

Like this?

Almost. :wink: You still have the issue of having to explicitly identify each Thing UID. There’s just too much maintenance overhead when you have lots of Things.

It would be better if you could say

Member of Things received update [<status>]
Member of Things changed [from <status>] [to <status>]

And then have an implicit variable (e.g. triggeringThing) that you could reference the thing that was updated, or whose status changed.

1 Like

This is not available using the rules DSL, but it has been available in the new rule engine for a few years. With the Jython helper libraries, you’d use event.thingUID to get the triggering Thing UID… https://openhab-scripters.github.io/openhab-helper-libraries/Guides/Event%20Object%20Attributes.html.

1 Like

Many bindings treat a Thing as representative of the pathway to a device.
That might be because some technologies being unable to determine if an end device is “broken” until you try to talk to it.
Example ; a temp sensor polled in some way over IP, the Thing remains online unless the host ethernet port is broken, indicating that you can try to communicate.

It is possible to indicate a failed poll by setting UNDEF state, or by a separate channel with a last error timestamp etc.

Which is all to say, the right thing to do with a Thing depends on the technology - and your Thing structure.
It sounds like your binding would be a candidate for a simple hierarchy - a Bridge type Thing representing the hub, subsidiary “ordinary” Things and channels for end devices.

It’s not obvious what the “best” way to handle is when the remote hub can report the status of end devices.

Another reason to speed up my rate of conversion over to the new rule engine. :wink:

2 Likes

but it is not just power users being able to use a more powerful rules engine, V3 must include a simpler interface for noobs

@rossko57 — I agree fully with the above three points.

The binding is indeed a Bridge/Thing hierarchy.

It is clear that if the LAN link to the Bridge fails, then every-Thing is Offline. But if the RF link from the Bridge to one of its Things is lost, the Bridge is still providing data for that Thing (including a parameter called Offline).

So in sitemap or UI you still see data for the Offline Thing, and you may not realise that the data has no reality…

Maybe the answer is to replace the data read from the hub by UNDEF if the Offline parameter is set. ??

The trouble is that some user will want to still see the last good data. Maybe it’s a room temperature - you don’t really care if there is a few minutes of RF interference. You can’t please everybody … at the same time.

If you went the UNDEF route, consider making it an user selectable option on the channel. postundefinedonerror=true or something.
Or possibly an option on the Thing for all related channels.

I like UNDEF myself, it fits the openHAB model of Item abstraction - the Item doesn’t care in the least about what devices are doing what in detail, it just wants to know some value. UNDEF says nope, not now.

Indeed. And that just for read only values. It is further complicated for writeable ones: you can change a switch position in (say) sitemap, and on the next poll the hub will send back data confirming the change. Even though it has not actually been able to push the command to the device. I’m not sure, but I think the hub may be buffering such commands so they can be pushed as soon as the RF drop out recovers…

Hmm. I know how to set config parameters at Thing level. But is there really a way to set config parameters on a Channel level? One might want to use UNDEF on one channel, and last known value on another…

You can only use what this hub tells you. If it doesn’t flag an error for a write command to a broken device, then there’s no error for you to deal with in the binding. Technologies differ in behaviour, and we just have to accept that.

My terminology is probably wrong but most channels have configuration parameters.

I just found the extreme case: the Neohub system landscape includes an RF Mesh repeater device; its sole function is to extend the range of the RF mesh. Basically this is the same as a regular NeoStat thermostat or other device but with no external control functionality. So in other words it is represented in OH as a Thing which can have an On/Offline State but which has no Channels!

Okay. If it has no channels “we” don’t care about it, where “we” is openHABs primary task of orchestrating Items.
Put another way, users don’t care about it either … until it has an impact on an ordinary remote device. And that device has its own means of fault reporting, UNDEF or error flag channel or whatever you decide.

Maybe the way to look at this that your bridge Thing represents the mesh, not just the hub. Repeaters are just part of the mesh, and not visible to OH. Rather like it treats TCP/IP … it doesn’t know or need to know about switches, routers, bridges, WAPs, blah.

Hmm. Many thanks for your inputs. So perhaps the solution is as follows…

  1. the hub / Bridge Thing status goes offline in OH when no communication is possible a) with the hub itself, or b) all of the child devices.

and,

  1. the hub / Bridge Thing has a technical/advanced Channel that indicates a degraded communication level with some (but not all) of it’s child devices; perhaps like a bar chart — all device’s online / one device missing / several devices missing / all devices missing…

@rossko57 I’m sorry to be stupid, but could you give me some tips on configuration parameters for channels (what, where, how, etc.), since this is a concept that seems beyond me. I know how to do configuration on Things, Bridges, and Items, but not on Channels…

I have noidea how these are implemented, but user configurable channels -

Ok. Many thanks @rossko57. I will have a look into the inner workings of those bindings. It may take me a day or two though…

@rossko57 let me answer my own question: To add a Configuration Parameter to a Channel, you do it in basically the same way as adding one to a Thing. Just add a config-description block to your thing-types.xml as shown below.

<channel-type id="contactState">
    	<item-type>Switch</item-type>
    	<label>Contact State</label>
    	<description>The state of the contact, Off or On</description>
    	<category>Window</category>
    	<state readOnly="true"/>
    	<config-description>
    		<parameter name="keepLastOnlineState" type="boolean" required="false">
    			<label>Keep Last Known Online State</label>
    			<description>If the device loses its RF mesh connection, keep displaying the last known state</description>
    			<default>false</default>
    			<advanced>true</advanced>
    		</parameter>
    	</config-description>
</channel-type>

And then in your binding you can access this Configuration Parameter via code such as the following.

       if (isDeviceOffline) {
            ChannelUID channelUID = new ChannelUID(thing.getUID(), channelId);
            Channel channel = thing.getChannel(channelUID);

            if (channel != null) {
                Configuration config = channel.getConfiguration();
                Object keepLastOnlineState = config.get("keepLastOnlineState");
                if (keepLastOnlineState == null || !(keepLastOnlineState instanceof Boolean)
                        || !((Boolean) keepLastOnlineState).booleanValue()) {
                    state = UnDefType.UNDEF;
                }
            }
            updateState(channelUID, state);

        } else  {
            updateState(channelId, state);
        }
1 Like

This might work but, as far as I remember, a binding should not store a channel state. If you want to retreive the last known state at startup, use persistence instead.