Good Evening one and all!
Just a quick overview - I have been using openHAB 1.x for around a year now mainly focusing on zwave, hue, harmony hub, xbmc and python wrappers to interface to things like Honeywell Evohome. Having read the post from Kai around the openHAB 2 beta 4 rules engine being as good as 1.8.3 I thought it was time to take the plunge and upgrade, warts and all.
Whilst I was at it I thought I may try and help out, I would love to code and have written lots of python scripts and the like but know full well that my coding is…well…terrible! I make it work but if anyone with a clue had a look they would laugh.
Anyway - to the problem (I have spotted a couple but want to raise one now, get shouted at for doing it wrong, learn, raise the rest in the correct manner). I have successfully run the openHAB 2 installation following the docs and have made the leap from entirely text based configuration to semi UI, semi text based and actually it is pretty cool. (All those nay-sayers should embrace this change…once you get your head around it, it really does work well) I have created python scripts to convert a house layout into rules files, sitemaps, items files, etc. so complete rebuilds / updates are very quick and easy. As part of the migration to openHAB 2 I went through all the rules and updated to reflect the changes in the core. One issue keeps coming up;
When a rule contains the line (as an example)
var ColorItem colourControl = GROUPNAME.allMembers.findFirst[name.equals(ITEMNAME_AS_STRING)]
I occasionally get the error
[ERROR] [.script.engine.ScriptExecutionThread] - Rule ‘RULE_NAME’: null
This does not happen every time the rules fire but it does happen intermittently for every rule that contains such a group iteration. It does not matter which group is being iterated over.
Has anyone else experienced this? Has the syntax changed? How can I debug this further to help identify the problem?
Apologies for the long post, poor formatting and probably vague information but I really do mean to help this project forward (however much it may seem otherwise)
What, if anything else is going on when you see the error. Is it soon after a restart or a change to rules files, items files etc?
To debug I’d add some logging and break the command apart to see where the error occurs? Does it fail on GROUPNAME, allMembers, findFirst, or name.equals? That might provide a clue.
Thanks for the reply. It is not linked to any event such as startup, config change, etc. If a rule fails I can trigger it again and it will complete without issue. I will see if I can deconstruct the command and report back if I get any different behaviour. Is this still the best way to get the item from its name?
Its as good a way as any. you could filter
Group.members.filter[i|i.name == "name"].head
OK, as promised a quick report back.
It seems the group iterations are not thread safe. The scenario I had was a cron rule firing to setup various room characteristics for different times of day, light colours, brightness, heating, etc. This cron rule would fire and set several string items which in turn would fire off “on changed” rules for these items. Within these rules (now running under separate threads I believe) there were a couple of group iterations to get access to items and it was these that were failing every so often and seemingly randomly.
I did try both the filter and find first variants and the same behaviour was exhibited so can only suggest that the iteration through the group is causing the issue and not the mechanism by which you select the required item.
I have now rewritten these rules to work in different ways and work around the issue but it would be good to know if the group iteration is supposed to be thread safe. In fact, is there any reference material which can be used to find which native openhab function calls are thread safe and which are not? Also under which circumstances they should be used?
I know this is not a fix but hopefully someone will find the information useful. Thanks for your help and suggestions with this.
You can pretty much assume that nothing is thread safe in the Rules. This is an important gotcha indeed. However, I iterate over and send commands to Items in a Group all the time. Though when I send a command it usually only is to that one Item. It does not trigger another rule that triggers another command on the Group.
I doubt it in this case because of the way OH is architected. When you send a command or post an update it goes out on the Event Bus where a new thread is created (really a thread is pulled off of the pool) for any Rules that trigger on that event and instances of all your Items and Groups are provided. But the instances of Items and Groups in one running Rule are not the same instance as the same Group in another rule. So even if the Groups were thread safe, since they are separate instances of the Group class the do not share a lock.
I discovered this when I was naively using Items as keys in HashMaps (use the Item’s name instead).
I think for the most part assume no calls are thread safe. These data structures may be natively thread safe (e.g. I don’t know if the underlying Collection for members is ArrayList or Vector) but because each running Rule gets their own instance of the Group that thread safeness buys you nothing. So if you have complicated cascading Rules logic you need to be very careful to write it so you don’t conflict or add your own ReentrantLocks around the conflicting logic.
This is absolutely an important gotcha to be aware of for complex rules. Thanks for reporting back.