Wondering how to approach this automation problem for ceiling fans

Currently using NodeRed for all automations.

We have 4 ceiling fans all on 3 speed Z-Wave switches. Naturally, our goal is to never need to use the switches.

Currently, we have a fan threshold input that is compared to the current outdoor Darksky temperature.

If the outside temperature exceeds our threshold temperature, all 4 ceiling fans turn on at medium speed.

UNLESS (And here’s where we start to customize)…

In NodeRed, I’ve defined a global boolean variable for each fan that represents whether or not the fan is in auto mode, or manual override mode. The value of this boolean is set based upon the context value of userid which comes through any time any fan switch state is changed.

What I noticed about the ZWave messages, is that if the paddle is depressed at the switch, the userid context value in the message is null. All other activity (through lovelace, google, alexa, etc.) assigns a value to userid.

Using that, I’m able to use a switch node to change the value of the global variable, but only if someone physically presses the fan button.

This in turn is used to ignore automations, thereby putting the fan back into stupid mode.

Here’s the Challenge and QUESTION:

What node could I use to watch messages coming from the fan switch that would follow this logic: if two messages come from X device within a period of X seconds with [this condition], do this

The result would be re-activation of automation mode. If I double press the fan switch within a period of 3 seconds, for example, it would reset the global variable.

Right now, we have it resetting every 12 hours, so if we touch the fan switch any time in that time-frame, we lose automation for that fan.



I figured out a way to do it.

Here is the flow:

[{"id":"8af7c471.af83c8","type":"server-state-changed","z":"9fa967ab.9b4a38","name":"Guest Bedroom Ceiling Fan","server":"c7cbc76b.fd06a8","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"fan.jasco_products_14287_fan_control_switch_level_2","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"x":340,"y":1020,"wires":[["450f1b0b.4fe754"]]},{"id":"600b29f1.4bd508","type":"change","z":"9fa967ab.9b4a38","name":"Add a reset flag","rules":[{"t":"set","p":"status.fanAutoReset","pt":"global","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":800,"y":1020,"wires":[["dcb76551.dd4768"]]},{"id":"146089fe.23c1a6","type":"switch","z":"9fa967ab.9b4a38","name":"Are we resetting to Auto?","property":"status.fanAutoReset","propertyType":"global","rules":[{"t":"null"},{"t":"eq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":2,"x":590,"y":1080,"wires":[["600b29f1.4bd508"],["6d56dec4.c6bd8"]]},{"id":"dcb76551.dd4768","type":"stoptimer","z":"9fa967ab.9b4a38","duration":"2","units":"Second","payloadtype":"num","payloadval":"0","name":"Start a 2 second timer","x":1020,"y":1020,"wires":[["d3fbb636.8481c8"],["9521547.5803aa8"]]},{"id":"d3fbb636.8481c8","type":"change","z":"9fa967ab.9b4a38","name":"Remove Reset Value","rules":[{"t":"delete","p":"status.fanAutoReset","pt":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":1300,"y":1020,"wires":[["c282f75a.654f58"]]},{"id":"6d56dec4.c6bd8","type":"change","z":"9fa967ab.9b4a38","name":"Re-Enable Automation","rules":[{"t":"set","p":"status.fanGuestBedroomManualOverride","pt":"global","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":840,"y":1080,"wires":[["2c7f779.d2b9888"]]},{"id":"2c7f779.d2b9888","type":"change","z":"9fa967ab.9b4a38","name":"Stop Timer","rules":[{"t":"set","p":"payload","pt":"msg","to":"stop","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1050,"y":1080,"wires":[["dcb76551.dd4768"]]},{"id":"c282f75a.654f58","type":"change","z":"9fa967ab.9b4a38","name":"Enable Manual Override","rules":[{"t":"set","p":"status.fanGuestBedroomManualOverride","pt":"global","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":1310,"y":1080,"wires":[[]]},{"id":"450f1b0b.4fe754","type":"switch","z":"9fa967ab.9b4a38","name":"Manual Action?","property":"data.new_state.context.user_id","propertyType":"msg","rules":[{"t":"null"}],"checkall":"true","repair":false,"outputs":1,"x":580,"y":1020,"wires":[["146089fe.23c1a6"]]},{"id":"9521547.5803aa8","type":"change","z":"9fa967ab.9b4a38","name":"Remove Reset Value","rules":[{"t":"delete","p":"status.fanAutoReset","pt":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":1300,"y":980,"wires":[[]]},{"id":"c7cbc76b.fd06a8","type":"server","z":"","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]

And here’s an explanation:

The first node that I setup, which is not included here, was a function node to initialize an array of global variables, one for each fan, with a simple boolean value.

At midnight every night, all 4 variables are set to false. “Are the fans in manual mode?” No.

Here is the function:

var status = { 
    "fanKitchenManualOverride" : false,
    "fanLivingRoomManualOverride" : false,
    "fanGuestBedroomManualOverride" : false,
    "fanMasterBedroomManualOverride" : false,
global.set("status", status);
return msg;

Whether or not fans are included in any automations is dependent upon previous conditions set through other flows, so we’re not running fans when fans shouldn’t be running anyway.

Now that we have that variable in place, we can create the individual fan flows to be able to set and unset manual mode based upon actions at the Zwave switch.

Any time someone touches a fan paddle, a flow begins. Here is the logic:

Was this a manual action? If yes, do we have a global reset variable set, or is it null? If it’s null, create a reset variable, then start a timer. If another state change occurs before the timer expires, using the reset variable as a condition, we’ll reset the manual override value to true, stop the timer, and remove the reset variable. If another state change doesn’t occur before the timer expires, we set the manual override status to true for that zwave switch, and remove the reset variable.

So far it seems to work. The next step is to write this up as a single flow instead of duplicating it for each zwave device. After that, figuring out how to manage two potential problems:

  1. What if HA triggers a fan action while the timer is running?
  2. What if two people attempt to switch devices to auto mode at the same time?