Make a fan use only OFF, Low, Medium, ON

Tags: #<Tag:0x00007f745048d408>

I am missing something here, and can’t figure this out.
I have a fan controller, 39358 Z-Wave In-Wall Smart Fan Control.
The manual paddle user experience is terrible. I want to make it more intuitive. If a person clicks up, then the fan speed is incremented to the next setting, so from low->medium, for example. It seems simple, but the unit reports back current values that sometimes re-trigger my rule, and resets the displayed value to the previous value. For example, this occasionally happens: Fan at OFF, paddle up to 1%, the fan gets the command to go to 33%, then a status is returned of 1%, which triggers my rule again, them another notification of fan at 33%.

rule "Make a Fan High Medium Low" 
when 
    Member of gThreeSpeed changed
then
    try {
        if (!suppressLock.isLocked()) {
            suppressLock.lock()
            var Number p = previousState as Number
            var Number n = triggeringItem.state as Number
            var Number toSend = 0;
            if (n > p) {    // up paddle was clicked
                if      (p==0) {toSend = 33}
                else if (p==33){toSend = 66}
                else if (p==66){toSend = 100}
                else           {toSend = 100}
            } 
            if (n < p) {    // down paddle was clicked
                if      (p==100){toSend = 66}
                else if (p==66) {toSend = 33}
                else if (p==33) {toSend = 0}
                else            {toSend = 0}
            } 
            triggeringItem.postUpdate(toSend)
            triggeringItem.sendCommand(toSend)
            Thread.sleep(1000)
            suppressLock.unlock()
        }
    } catch(Throwable t) { 
        suppressLock.unlock()
    } finally {
    }
end

Log file:
2019-09-29 20:28:23.659 [vent.ItemStateChangedEvent] - FanHallBack_Dimmer changed from 0 to 16
2019-09-29 20:28:23.704 [vent.ItemStateChangedEvent] - FanHallBack_Dimmer changed from 16 to 33
2019-09-29 20:28:23.734 [ome.event.ItemCommandEvent] - Item ‘FanHallBack_Dimmer’ received command 33
2019-09-29 20:28:25.454 [vent.ItemStateChangedEvent] - FanHallBack_Dimmer changed from 33 to 16
2019-09-29 20:28:25.541 [ome.event.ItemCommandEvent] - Item ‘FanHallBack_Dimmer’ received command 0
2019-09-29 20:28:25.544 [vent.ItemStateChangedEvent] - FanHallBack_Dimmer changed from 16 to 0

Does your item have autoupdate=“false” set?

there’s no need running postUpdate and sendCommand, use sendCommand only. Don’t think you need the sleep statement either as long as the lock works.

Alternatively create a “anti-flapping” logic in your script, there are lots of examples if you search the forum :slight_smile:

Locks are pretty dangerous. Locks with a long thread sleep are doubly so. The big problem is there are some errors/exceptions that will be caught outside the Rule leaving your lock locked forever. And there are only five rules that can run at a time by default. So if this Rule triggers five times in that one second than none of your other Rules will be able to run because all of your available rule threads are stuck waiting for that lock.

So the first question is what are you trying to accomplish with the lock and the sleep? If you are trying to debounce then see Design Pattern: Rule Latching. If you are trying to rate limit so the up/down events are processed a certain amount of time apart, see Design Pattern: Gate Keeper. Both approaches are far safer. If you are using JSR223 Python, both of these have been implemented as library modules you can just download and use. See the PRs at https://github.com/openhab-scripters/openhab-helper-libraries/pulls.

Indeed, you do not need to run postUpdate and sendCommand. Just call sendCommand.

If you do need a sleep, you might need the sleep before you send the command rather than after, in which case please use a Timer instead of sleep.

What are the channels on this device? I had a look at it in the zwave database and am not knowledgeable enough about the command classes to know how they translate to Thing Channels. I assume it links to a Dimmer?

Okay, I added another minor check to see if the new value is 0,33,66,100, and to exit if true.

I did notice this odd behavior:

Starting at OFF
2019-09-30 10:00:35.763 Item ‘FanHallFront_Dimmer’ received command 87
2019-09-30 10:00:37.510 FanHallFront_Dimmer changed from 0 to 87
2019-09-30 10:00:37.562 Item ‘FanHallFront_Dimmer’ received command 33
Me puzzled for 21 seconds: control panel shows 78, not 33.
I slide the slider to zero.
2019-09-30 10:00:58.022 Item ‘FanHallFront_Dimmer’ received command 78
2019-09-30 10:00:59.766 FanHallFront_Dimmer changed from 87 to 78
2019-09-30 10:00:59.832 Item ‘FanHallFront_Dimmer’ received command 0
2019-09-30 10:01:01.556 FanHallFront_Dimmer changed from 78 to 0

I think this is a display problem, that I’m not that interested in dealing with. I’m going to have H/M/L/OFF buttons on the computer display, and those won’t trigger this rule. The physical button needs to behave like normal without any display. I believe this is working now.

fan:
Dimmer FanHallFront_Dimmer "Dance Floor Fans closest to Stage" <fan> (gThreeSpeed,gHallFan) {channel="zwave:device:e8358de4:node10:switch_dimmer", autoupdate="false"}

rule:

when 
    Member of gThreeSpeed changed
then
    try {
        if (!suppressLock.isLocked()) {
            suppressLock.lock()
            var Number p = previousState as Number
            var Number n = triggeringItem.state as Number
            var Number toSend = 0;
            if (!(n==0||n==33||n==66||n==100)) {
                if (n > p) {    // up paddle was clicked
                    if      (p==0) {toSend = 33}
                    else if (p==33){toSend = 66}
                    else if (p==66){toSend = 100}
                    else           {toSend = 100}
                } 
                if (n < p) {    // down paddle was clicked
                    if      (p==100){toSend = 66}
                    else if (p==66) {toSend = 33}
                    else if (p==33) {toSend = 0}
                    else            {toSend = 0}
                }
                triggeringItem.sendCommand(toSend)
            }
            //Thread.sleep(1000)
            suppressLock.unlock()
        }
    } catch(Throwable t) { 
        suppressLock.unlock()
    } finally {
    }
end

Thanks. I did look into anti-flapping. I’ll look at your references.
This is the Honeywell 39358 Z-Wave In-Wall Smart Fan Control, with only dimmer and Scene number channels. It must be very new, because I had to upgrade to the 2.5 binding to get a database that included it.
The channel is a Dimmer channel.

Hey Rich,

I wasn’t aware of this fact; is there a place to change this? I have a pretty big OH installation running (2k lines of items, 25k lines of rules). I do see that my MQTT WiFi Roomba rule is triggering all the time which brings me down to 4 rules at a time.

Thanks in advance . . .

Best, Jay

1 Like

As long as you are not doing something a little off, there is no need to increase it. By a little off I mean:

  • Using Thread::sleep with a sleep time of more than 200. This increases the amount of time that a thread remains unavailable.
  • Reentrant Locks which have two risks. First it runs the risk of breaking which will force all the threads to become consumed awaiting access to the lock. Second and related is it consumes a thread while it is awaiting the lock instead of allowing some other Rule that can actually do something from using it.
  • Long running Actions like the sendHttp*Request actions and executeCommandLine for the same reasons as Thread::sleep. Long running Rules block other Rules from access to the threads.

If you are not doing any of the above, than you are probably fine. A Rule not doing the above typically only takes 100-200 msec to start, run and complete, returning the thread back to the pool. That means you can run up to 50 Rules a second with a thread pool of 5 without any delays in Rule processing. And you would have to move up to 500 rules per second before you might notice a delay of 1 second between when an event occurs and a starved Rule executes because you’ve used up all your thread pool.

I doubt your Roomba is triggering that often.

If you are not noticing any delays in Rules triggering, you are fine. If you are seeing delays on when Rules start, first review Why have my Rules stopped running? Why Thread::sleep is a bad idea for alternative approaches you can use to get your existing Rules to behave better. Only then if you’ve determined that you need more threads you can add org.eclipse.smarthome.threadpool:RuleEngine=5 to runtime.cfg and increase the number to something larger.

Thank you Rich, I always read you posts when I can. I am doing a lot of stuff that is a little off (doesn’t mean it’s right or ideal though).

My general rule with thread sleep with my setup which seems to been working is:

500 = setting now variables (I do a lot of this with in rules, wish there was a “gosub” like back in the day)
1000 = postUpdate
2000 = sendCommand

I have a lot of Alexa speaking and running Alexa routines in my setup and anything less than 2000 it causes the Amazon to reject the request with “Too Many Requests at one time”.

I did set this variable you mentioned quite along time ago from another post.

org.eclipse.smarthome.threadpool:thingHandler=50
org.eclipse.smarthome.threadpool:discovery=20
org.eclipse.smarthome.threadpool:safeCall=50
org.eclipse.smarthome.threadpool:ruleEngine=50

org.eclipse.smarthome.webclient:minThreadsShared=10
org.eclipse.smarthome.webclient:maxThreadsShared=60
org.eclipse.smarthome.webclient:minThreadsCustom=10
org.eclipse.smarthome.webclient:maxThreadsCustom=30

I’m running OH on a Synology HA Pair with 8 GB of RAM.

The reason I say my MQTT Roomba WiFi is executing its rule so many times is when I reload my items/rules; I have systemStarted logic on all my rules so they don’t execute during the startup and the MQTT Roomba rule tells me over 50+ times that it can’t execute due to systemStarted = ON.

I am also using Reentrant Locks for the 13 Sonos THINGS that do a lot of coordination of who is the master and grouping of units which is very dynamic in nature. Found the Reentrant Locks code on the OH Sonos forums which works pretty good.

I’m also doing A LOT of long running actions like the sendHttp*Request actions and executeCommandLine with 8 cameras tied to OH grabbing and sending images based on events.

I do understand that these 500,1000 and 2000 are NOT ideal and I’ve read many times this is a bad thing for how large these numbers are. It’s working for me (right now) and I will try to reduce these numbers slowly in a global sub/replace over time.

Bottom line; I’m doing everything you mentioned that is little off ;-(

Best, Jay

You shouldn’t have to sleep to set up variables. Assigning a variable blocks. When the next line runs the variable is already set.

You shouldn’t have to sleep after sending a postUpdate. If you do than just keep what ever it was you posted to the Item and use that. Don’t sleep waiting for an Item to update to a value you already have. If you want to wait before you post the update, use a Timer. Then you won’t be blocking a thread doing nothing.

Same as with postUpdate.

See my link to the Gatekeeper Design pattern for a better and safer approach.

Locks are really really dangerous. I cannot recommend their use under any circumstance and would go to extreme lengths to avoid them up to and including moving to JSR223 Rules (which don’t have this problem) or moving the task outside of OH itself.

Don’t reduce, replace with a better option/approach.

1 Like

I know there’s no real plan to OpenHab, but is there any talk about adding some metadata to state? Something like previousState, for example? A call stack seems sort of what I’m looking for, but I don’t know how one would go about bridging the Z-wave(or other binding gap). I believe Z-wave would need to track a sessionId, for each communication so software could know the true provenance of an event. And for something like RTL433, forget about it. But, I’m wondering if this could be synthesized with state. Send a command to a remote device, and a response is received. If both happen within a short time, and other information matches, then the event was initiated by OpenHab. This would seems like a good feature to have in core, and not added on with a design pattern. I see many similar posts, and it’s invariably around resolving race conditions.

Previous state is solved by persistence I believe.

In the open world of openHAB, that is more difficult than you think. “a short time” is dependent on the technology used, and could be “never”.
As is “response”. If you send ON to some devices that are already ON, you might get a response. Or you might not.
Then we have devices like blinds, where you can send UP and get a “response” 60% before anything happens. Maybe later another message will come for 50% which is the real result.

This concept would fall in the bindings area of responsibility, really.

This would be a device firmware issue, not a binding one IMO.

I’m not sure why you think that. But manufacturers are not going to change firmware of 10,000 different products to suit the idea.
What would you say is the “correct” behavior of a blind device, regardless of technology involved?

If it reports incorrect status information, that is a firmware issue.

Uh, in the case of a blind, everything takes a finite time. Send whatever passes for “move up”, get a response of “OK I’m at 60%” . Is that incorrect? A few seconds later, get an update of “I’ve moved, now I’m at 50%”. Is that incorrect? A few seconds after that. another update “I’ve come to the end and stopped at 0%”.

In the case of the previousState “detecting who dunnit” idea, it is arguable which of these / all of these / any of these are relevant. And it is device dependent, because there is no standard for what gets reported when, however much you might want one.

I do think the bindings would be the first place to look, because they have knowledge of the underlying technology. This could be the first place to synthesize the call stack.
But, if this were to be reliable, for something like ZWave, then perhaps we could make a recommendation to the foundation to add support for a session ID? Seems like an eight bit incremented value would work. That’s 256 messages, so rollover shouldn’t be a big problem.
At the device, for each message received, respond with the same sessionID. If someone pushes a button on the device, increment the sessionID.
This is simplistic, but my point is I wonder if the foundation is open to these kind of suggestions, or even if they have been discussed? This would sure help close a lot of holes with how devices are all implemented differently, causing problems with the controller.

I’m looking at the specification here:
https://www.itu.int/rec/T-REC-G.9959-201501-I/en
Section 8.1.3.3.7 defines a sequence number that should be passed to higher layers. I don’t know how this is created. It’s either 4 or eight bits, but if it is assigned sequentially, that may be a place to look. It is supposed to be used for tracking frames, but may help with the session ID idea.

We can’t change the end devices.

The foundation has no influence over development of OH. You need to convince the developers and maintainers to make the changes. A PR that actually implements the change would be most convincing. File an issue and see what they say.

Personally, I’m not convinced that what you propose is even feasible for most if any supported technology. And if it is somehow supported by it than it will require an implementation hopelessly tied to the way that technology works and not generalizable, meaning it doesn’t belong in the core but in the binding. In which case the information would be exposed as a Channel, not as State on an Item.