Widget - Check if item exists

Hi,

I’ve seen a few old posts asking this question, sort of. But no relevant solutions.

I am creating a widget that populates various fields based on a single item.

This is a light widget that can control a number of different light types: on/off only, CCT, RGBWW, some have illuminance threshold and motion on/off controls, some have auto off timers etc etc.

“Lamp” is the only prop that is set.

Then various list-items and sliders etc use an expression similar to

=props.lightItem + "_Brightness"

This is working well and everything is doing the right thing.
The problem I have is that there are various parts that will only sometimes have an item to refer to.

I think this is slowing down the page load where I have 14 of these widgets. Feels like it is fully searching everything before erroring, and my log is filled with all the items that cannot be referred to. Everything is snappy and functional once loaded.

When you create a new widget, the default code has an example that checks if a prop is present,

title: '=(props.item) ? "prop exists " : "prop doesn't exist"'

But I can’t make it work when referring to an item that isn’t a defined prop. The following (and variations that I tried) doesn’t work

title: '=(items[props.lightItem + "_Brightness"])  ? "item exists " : "item doesn't exist"'

I could probably solve this by having more things to set in the props, but I really like how the entire widget functions with just one reference to the main light item.

Any ideas??

If I were doing something like this in a rule, I might define each “multi purpose Item” as a Group, which could have more or less members of different function.
A rule can then work on the Group, examine if it has a “X” type member and only do X type things if so. It’s getting the member list to examine, rather than inducing a “failure” by trying to retrieve Item “X” which may not exist.

I’ve no idea if such an idea is useful in widget work.

Thanks,

I have a few methods for doing this in a rule, but it’s the widget and yaml that I need to solve

I’m pretty sure that items is a JavaScript dict so you should be able to test if it contains a key using

'=(props.lightItem +"_Brightness" in items) ? "item exists" : "item doesn't exist"'

There are other ways to test if a key is in a dict too if that doesn’t work. Search Google for lots of examples.

NOTE: I moved this to a more appropriate category. Tutorials and Solutions is a place to post these, not request them.

Not exactly, it is actually a Proxy - JavaScript | MDN. These allow you to have custom handler functions for operations like “get” or “set”, so while it acts like a dict with syntaxes like items.MyItemName or items["MyItemName"], the getter & setter operations are redefined.

It uses a real pure object underneath along with a “tracking list” so when you require the state of an item that isn’t currently on the tracking list, it will involve an API call that will update said tracking list for the associated SSE connection. This happens automatically and in batches within the same “tick” (like when upon a page change requests several items’ states are requested at once).
This allows to keep the network traffic for state updates to a minimum - only the state update events for the items in the tracking list that are actually needed are sent.

So in short, you can’t really check whether an item exists by examining the keys in that object because it’s not a real dictionary and doesn’t contain keys for every item, rather it builds itself dynamically depending on the keys that are accessed.

The code for that is here:

2 Likes

I was wondering about that since trying to get at an Item that doesn’t exist generates an error in OH so I figured there had to be some sort of communication going on.

Since this is a proxy and OP’s use case seems reasonable, would it make sense to open an issue to add an “exists” method to the underlying Object?

I typically achieve this as follows:

"=(items['ItemName'].state != '-') ? 'Item exists' : 'Item doesn't exist'"

Null and Undef items do return 'NULL' and 'UNDEF' strings, so it appears that '-' is reserved for the times when the widget just plain cannot get a state (which now makes sense thanks to Yannick’s explanation), and for most cases that situation is because the item doesn’t exist.

There’s a lot that can be done with Proxy objects, but it can be a two-edged sword since every operation could be more costly than expected. But in some cases this can be a good solution since these costly operations would only be carried out if they are actually requested. The “does it exist?” operation could be one the these, but it would be one of these costlier operations since it would involve an API call.

For example I pretty much buried Expose full item info to widgets by asmigala · Pull Request #1180 · openhab/openhab-webui · GitHub because while it’s a good (and often requested) idea, its suggested implementation involves calling the API for every item that is being included in the tracking list. I suggested the author to consider using Proxy objects for the item states objects themselves, so that when you request item.MyItem.category or items.MyItem.label it will gather the info from the API - but as needed, not as a general principle. I have learned from making HABPanel and HABot that when you request too much info (like a blanket /rest/events SSE connection) this will potentially kill your battery in 2 hours if you happen to be on a phone or tablet.

1 Like

I admit I’m naive on a lot of aspects of this but it seems to be that it would only involve one API call sometimes.

If the Item has already been cached in the tracking list by the proxy because it’s already in use somewhere else on the page no API call would be needed.

If the Item truly doesn’t exist, the first time an API call would be used and then the fact that the Item doesn’t exist could be cached in the tracking list as well. So there’s only be the one API call for each non-existing Item (until the page is reloaded again).

That doesn’t seem like too much of an impact over the long term, though I could see it slowing down the page when it’s first loaded which could be too much. It would also require a page refresh to pick up changes (e.g. a non-existant Item is created after the page was loaded). But I don’t know what I don’t know.-

Since the non-existing Item isn’t in the tracking list, would not this approach have the same problem with causing an API call each time the widget refreshes?

Thanks for all the input here.
Checking for ‘-’ works functionally and is neat in the code, but I still get item undefined errors in the logs.

Doesn’t seem like there is an obvious way to do this.
I either live with the log errors, or I have rewrite the widget to use more props, which can be checked for existence.

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.