PaperUI Rule bug? State with decimal

  • Platform information: Debian Linux on Skylake based server
    • openHAB version: 2.4.0

I have created a simple rule to detect changes in my Aeotec Wallmote Scene (taps on button).
The Aeotec reports buttons back in x.0, x.1 and x.2.
If I create a rule to check when state is updated to 2.0 everything works.
If I then re-open the rule, the State is no longer 2.0 but 2 - no decimal. If I then Cancel or save the rule, it no longer works as it has removed the “.0” from the State match.

I have multiple rules (two for each button, with if statements to alter between on/off states) and they all work - so long as I don’t re-open them and don’t refresh any rules.

I am assuming this is a bug, but didn’t know where to report it :slight_smile:

This is created in PaperUI. I tried to replicate using .rules files but I had no luck getting my rules to parse correctly and couldn’t figure out why.

Verify this. Open the rules file in /var/lib/openhab2/jsondb. Look at the Rule before reopening it in PaperUI. Then open it and save it or cancel it and look at the Rule again. Did it strip off the decimal?

If there is a bug here, it is most likely in PaperUI and unfortunately not likely to get fixed. The “Experimental” in the name is there for a purpose. It isn’t really quite yet ready for prime time. And PaperUI will be replaced with something else for OH 3.

You can file an issue on the https://github.com/openhab/openhab-webui repo as this is almost certainly a PaperUI issue.

Huh, interesting.
Thanks for pointing out the jsondb btw, I’ve been going crazy trying to figure out some things :slight_smile:
But, on topic. It actually changes the state to “2.0” from 2.0 and the quotes break the rule.

cat /var/lib/openhab2/jsondb/automation_rules.json | grep 2.0
“state”: 2.0
“state”: “2.0”
(first entry works)

I’ll post it on the github page and await eagerly for OH3 :smiley:

Don’t hold your breath. It’s at least a year away.

If you want this to work, I do recommend revisiting writing Rules, or look into JSR223 Rules and write them in Jython. The latter will be more future proof as the execution engine that PaperUI Rules and JSR223 Rules use is the same. .rules files will likely become deprecated in OH 3.

Very interesting though. It looks like for some reason it’s converting the entry from a number value to a String value. You have confirmed this happens even when you cancel out of the Rule without saving?

I’m all but positive this is a PaperUI issue. @5iver, are you aware of any issue like this?

No, I’ve never seen this, but I’ll try to reproduce. If it’s a bug, it’s likely in Paper UI, and could only happen if saving the file. Nothing changes in the rule if you cancel.

If you’re using if/then, then you must be using a scripted Action. I suggest you combine all of your rules into one, and deal with the possible states within the Action. This should work around your issue, and you’ll have less rules to maintain.

Yeah, the problem though is that PaperUI (when saving the rule) inserts the quotes and in the UI the .0 is removed. I’m guessing there’s a trim or something there.

Combining the rules in the UI doesn’t seem possible, so I will take rikoshak’s advice and revisit writing the rules myself.

I noted that I have to do this anyway if I want multiple states for each item and using loops would solve some other issues I’m looking at for timing… :slight_smile:

As posted in this part of the docs?

I will take a look and start on that :slight_smile:

When using scripting with the new rule engine, you first need to decide whether to use Jython or Javascript. You can use both, but you probably will want to learn one language at a time. Here are some instructions and helper libraries for Jython…

But it is, and you can use the same script, at least the Action portion of it, in the UI that you’d use in a script file. But only Javascript is supported until this is accepted/merged. By “if statements” you must have meant that you are using Conditions… I thought you meant scripted Actions, which are in the Actions dropdown.

An actual script will let you have a single rule that would cover multiple Wallmotes too, which isn’t possible in the UI yet, since a TriggerType hasn’t been built for ‘Member of’. So in the UI, you’d need a separate rule for each wallmote.

There are plenty of options to choose from!

BTW, I have reproduced what you have reported, and have created an issue. This does appear to be in the UI.

Fantastic.
Thanks.

I will look into the UI and Jython then.
I do quite a bit of Python regularly, so it shouldn’t be too much hassle to work it out :wink:

In that case, this script may be useful for you. It’s highly personalized for my implementation, but a rule for your wallmote would be similar. My minimotes use the older version of SCENE_ACTIVATION (no decimals), but that should be easily adapted.

from core.rules import rule
from core.triggers import when

rooms = {
    "Minimote_1": {"device": "gDS_FamilyRoom_Bulb", "level": 0},# family room
    "Minimote_2": {"device": "US_MasterBedroom_Dimmer", "level": 0},# bedroom
    "Minimote_3": {"device": "DS_MasterBedroom_Dimmer", "level": 0}# guest bedroom
}
brightness = {
    0 : "0",
    1 : "1",
    2 : "25",
    3 : "98"
}

@rule("Minimote: Minimote")
@when("Member of gMinimote received update")
def minimote(event):
    minimote.log.info("{0}: Scene {1}".format(event.itemName,event.itemState))
    if event.itemState == DecimalType(1):
        if event.itemName in ["Minimote_1", "Minimote_2", "Minimote_3"]:
            if items["Wakeup_Alarm"] == ON:
                events.sendCommand("Wakeup_Alarm_Snooze","ON")
                minimote.log.info("{}: Scene 1: Button 1 (pressed): Turned on snooze".format(event.itemName))
            else:
                rooms[event.itemName]["level"] = rooms[event.itemName]["level"] + 1 if rooms[event.itemName]["level"] < 3 else 0
                events.sendCommand(rooms[event.itemName]["device"], brightness[rooms[event.itemName]["level"]])
                minimote.log.info("{}: Scene 1: Button 1 (pressed): brightness [{}]".format(event.itemName, brightness[rooms[event.itemName]["level"]]))
        elif event.itemName == "Minimote_4":
            events.sendCommand("GarageDetached_Door","OFF" if items["GarageDetached_Door"] == "ON" else "ON")
            minimote.log.info("Minimote 4: Scene 1: Button 1 (pressed): Toggle detached garage door")
    elif event.itemState == DecimalType(2):
        if event.itemName == "Minimote_1":
            events.sendCommand("Outlet6","OFF" if items["Outlet6"] == ON else "ON")
            minimote.log.info("Minimote 1: Scene 2: Button 1 (held): Toggle family room TV outlet")
        elif event.itemName == "Minimote_2":
            events.sendCommand("Outlet2","OFF" if items["Outlet2"] == ON else "ON")
            minimote.log.info("Minimote 2: Scene 2: Button 1 (held): Toggle bedroom TV outlet")
        elif event.itemName == "Minimote_3":
            events.sendCommand("Outlet5","OFF" if items["Outlet5"] == ON else "ON")
            minimote.log.info("Minimote 3: Scene 2: Button 1 (held): Toggle guest bedroom TV outlet")
        elif event.itemName == "Minimote_4":
            events.sendCommand("GarageAttached_Door","OFF" if items["GarageAttached_Door"] == ON else "ON")
            minimote.log.info("Minimote 4: Scene 2: Button 1 (held): Toggle attached garage door")
    elif event.itemState == DecimalType(3):
        if items["Wakeup_Alarm"] == ON:
            events.sendCommand("Wakeup_Alarm_Snooze","ON")
            minimote.log.info("Minimote: Scene 3: Button 2 (pressed): Turned on snooze")
        else:
            events.sendCommand("gBackLight","98" if items["gBackLight"] == DecimalType(0) else "0")
            minimote.log.info("Minimote: Scene 3: Button 2 (pressed): Toggle Back patio lights")
    elif event.itemState == DecimalType(4):
        events.sendCommand("Audio_Notification","Beer is being requested. Repeat, beer is being requested... PLEASE!")
        minimote.log.info("Minimote: Scene 4: Button 2 (held): Request beer")
    elif event.itemState == DecimalType(5):
        if items["Wakeup_Alarm"] == ON:
            events.sendCommand("Wakeup_Alarm_Snooze","ON")
            minimote.log.info("Minimote: Scene 5: Button 3 (pressed): Turned on snooze")
        else:
            events.sendCommand("gOutsideLight","98" if items["gOutsideLight"] == DecimalType(0) else "0")
            minimote.log.info("Minimote: Scene 5: Button 3 (pressed): Toggle outside lights")
    elif event.itemState == DecimalType(6):
        if items["gSiren"] == ON:
            events.sendCommand("gSiren","OFF")
        elif items["gSiren"] == OFF:
            events.sendCommand("gSiren","ON")
            events.sendCommand("SMS_Notification","WARNING! Sirens turned on with Minimote!")
        minimote.log.info("Minimote: Scene 6: Button 3 (held): Toggle sirens")
    elif event.itemState == DecimalType(7):
        if event.itemName == "Minimote_1":
            if items["Wakeup_Alarm"] == ON:
                events.sendCommand("DS_FamilyRoom_Speaker_Volume", "25" if items["DS_FamilyRoom_Speaker_Volume"] == "0" else "0")
            elif items["DS_FamilyRoom_Speaker_Stop"] == ON:
                events.sendCommand("DS_FamilyRoom_Speaker_PlayURI", "HouseShuffle")
            else:
                events.sendCommand("DS_FamilyRoom_Speaker_Stop", "ON")
            minimote.log.info("Minimote 1: Scene 7: Button 4 (pressed): Family Room Mute/unmute Wakeup_Alarm, play house shuffle, or stop")
        elif event.itemName == "Minimote_2":
            if items["Wakeup_Alarm"] == ON:
                events.sendCommand("US_MasterBathroom_Speaker_Volume", "25" if items["US_MasterBathroom_Speaker_Volume"] == "0" else "0")
            elif items["US_MasterBathroom_Speaker_Stop"] == ON:
                events.sendCommand("US_MasterBathroom_Speaker_PlayURI", "HouseShuffle")
            else:
                events.sendCommand("US_MasterBathroom_Speaker_Stop", "ON")
            minimote.log.info("Minimote 2: Scene 7: Button 4 (pressed): Bedroom Mute/unmute Wakeup_Alarm, play house shuffle, or stop")
        elif event.itemName == "Minimote_3":
            if items["Wakeup_Alarm"] == ON:
                events.sendCommand("DS_MasterBathroom_Speaker_Volume", "25" if items["DS_MasterBathroom_Speaker_Volume"] == "0" else "0")
            elif items["DS_MasterBathroom_Speaker_Stop"] == ON:
                events.sendCommand("DS_MasterBathroom_Speaker_PlayURI", "HouseShuffle")
            else:
                events.sendCommand("DS_MasterBathroom_Speaker_Stop", "ON")
            minimote.log.info("Minimote 3: Scene 7: Button 4 (pressed): Guest bedroom Mute/unmute Wakeup_Alarm, play house shuffle, or stop")
        elif event.itemName == "Minimote_4":
            events.sendCommand("Audio_Notification","Your assistance is being requested outside.")
            minimote.log.info("Minimote 4: Scene 7: Button 4 (pressed)")
    elif event.itemState == DecimalType(8):
        if event.itemName in ["Minimote_1", "Minimote_2", "Minimote_3"]:
            events.sendCommand("HouseShuffle_Advance","ON")
            minimote.log.info("Minimote 1,2,3: Scene 8: Button 4 (held): Advanced house shuffle")
        elif event.itemName == "Minimote_4":
            events.sendCommand("Audio_Notification","WARNING! Your assistance is being urgently requested outside. WARNING! Your assistance is being urgently requested outside.")
            minimote.log.info("Minimote 4: Scene 8: Button 4 (held)")

I’m not a great Python coder but when I see that set of nested if statements I can’t help thinking “there’s got to be a better way.”

I wonder if something like some dictionaries of functions would read cleaner. I don’t know, like I said, I’m not the best in Python. Maybe something like Bartus’ Scene approach could be adopted to Python and used here.

I do think structuring it first on Minimote and then on the button pressed might help as then the functions for each minimote would be colocated instead of spread across the whole function. Though I do see why you organized it like you did as some of the cases are the same regardless of which minimote the button press came from.

DecimalType(5) is my favorite. :wink:

I don’t have time to mess with it right now but I think I’ll come back and see what I can do, as some sort of challenge to myself.

There’s no switch/case in Python, so you need to use if/thens. This was my first Python rule too, so it might need some cleanup! The funcitonality of the minimotes has pretty much been replaced with Dots, except for the one I carry on the lawn mower.

I bet you meant 4… which is hands down my favorite! Defintely a lawn mower thing! Although I should put in options for the type of beer…

I ran across this a week or so ago. There are ways to do switch like things in Python.

The Dictionary Mappings for Functions approach looks like it could be used here. But I don’t have enough experience to tell if it actually makes it easier to read than the nested if/else statements or if it just moves everything around without improving things.

Yep, that’s the one I meant. But I’d need a whole minimote dedicated to just beer types. Colorado is bursting with microbreweries. “Local beer” around here means the brewery down the road.

For this I just use Google Assistant’s Broadcast feature. “Hey Google, broadcast Bring to me a can of Gold Camp!”. I usually get a a response “Get it yourself”. :wink: I just can’t figure out how to automate the family, and the dog is too short (welsh corgi) to reach the beer shelf so I can’t train her. :slight_smile:

I’ve tried this early on, but preferred using if/then. I don’t recall exactly what turned me off, but IIRC, there was a showstopper… maybe something with multiline…

I have a friend that lives near the Academy… lots to choose from when I visit! Always seem to end up at Colorado Mountain Brewery for the food though. We have several in our back yard too, but I homebrew, so never need to go very far! Ah… beer…

Well now you have two. :slight_smile: I can see the AFA from my front yard.

Next time you come you should give Cerberos a try. Great food and decent brews. Parking is a pain though.

And drop me a note. Maybe we can meet face-to-face.

1 Like

I ran into exactly the same issue recently when I switched from Domoticz to Openhab2 (Ubuntu 16.04 / OH2.4).
The ZRC-90 Scene Master 8 also triggers on “x.0” for one-tap actions. Using Paper UI to program my scenes I noticed the UI writes “1.0” as “1” and for example “2.0” as “2”. Strange enough it did not affect the rules because triggering in the background still works on the “x.0” item state UNTIL you:

  • disable / enable a rule
    or
  • starts / stops OH2.4

In both cases the “x.0” triggering stops working. After re-typing “x.0” in the state-fields and click save everything works again. This is my work-arround for the moment. Triggering on double-taps ("x.3) for this device will avoid this issue but this is not the desired situation for me.

PS. I know this is out of topic but I have a similar issue with Astro binding which triggers on “END” or “START”. When disable / enable a rule or starts / stops OH2.4 those rules stop working. Then again I need to re-type “END” or “START” in the state-fields and click save before getting those rules alive.

I’m curious if what you are reporting is the same as…

Short version… try disabling all of your rules, restarting OH, and see if the rules execute properly. I will try to reproduce this, and open an issue if this is different.

Looks like the same BUG because when I do the following my Astro rules work again even without changing anything:

“By editing a rule and saving it, without making any changes, the rules will work again”

I will try your work-arround but I need to enable my Astro rules after the restart I assume…

“Short version… try disabling all of your rules, restarting OH, and see if the rules execute properly. I will try to reproduce this, and open an issue if this is different”

In my testing, the rules reenabled themselves after the restart. The issue has more details.