Distinguish Actual Button Presses in LUA Device Script Topic is solved

Post Reply
Daiii
Posts: 4
Joined: Saturday 12 August 2017 0:38
Target OS: Raspberry Pi
Domoticz version: Beta
Location: New Hampshire, USA
Contact:

Distinguish Actual Button Presses in LUA Device Script

Post by Daiii » Saturday 12 August 2017 1:05

Is it possible in a LUA device script to tell the difference between a Z-Wave switch being manually pressed On/Off, versus that switch changing state as a result of some command that was sent by the controller? Both cases seem to generate the same devicechanged[MySwitch] trigger event. It would be useful to distinguish these two types of change because in the manual case we can infer that a person is physically present and perhaps take different action in the script.

Thank You! I have been using Domoticz for just a month now and love both the product and the community. This is my first post, so I apologize for any noob blundering.

Nautilus
Posts: 616
Joined: Friday 02 October 2015 12:12
Target OS: Raspberry Pi
Domoticz version: beta
Location: Finland
Contact:

Re: Distinguish Actual Button Presses in LUA Device Script

Post by Nautilus » Saturday 12 August 2017 23:53

No, to my understanding that is not possible. But what you can do is to add e.g. a user variable and on you event scripts where you need to change the switch status then also update the variable. This way you could distinguish between the two on some level at least (depends of you usage). I'm using this kind of approach with outdoor sockets that are also used for car block heaters. If they are turned of by the block heater script they will stay on a time calculated by the script (depends on the leave time and outside temperature). If they are pushed manually they will stay on for two hours.

Daiii
Posts: 4
Joined: Saturday 12 August 2017 0:38
Target OS: Raspberry Pi
Domoticz version: Beta
Location: New Hampshire, USA
Contact:

Re: Distinguish Actual Button Presses in LUA Device Script

Post by Daiii » Sunday 13 August 2017 9:30

Thank you Nautilus -- I wasn't sure if Domoticz already provided some built-in solution, but your suggestion of storing state in a user variable is a good one. I've gone ahead and implemented this in a very general way and it works REALLY WELL! The LUA routines are attached below if perhaps useful to others:

Code: Select all

-- ==================================================
--  Support for Distinguishing Manual Switch Presses
-- ==================================================

-- These routines allow LUA code to distinguish manual switch presses
-- from identical looking device events that were initiated by the
-- controller.  For each device that needs such help simply create a
-- string user variable having the exact same name prefixed with
-- 'MSW-' to hold the state info that will be needed to discern the
-- two events.  If you have a switch named 'MySwitch' then create a
-- user variable named 'MSW-MySwitch'.
--
-- The newly created user variable can be empty at first and will be
-- filled in with a single letter flag ('m' or 'a') indicating when a
-- controller activation was just requested, followed by the os.time
-- of the last manual switch press that was seen.

-- Helper function to get (flag,time) contents of user variable that
-- is paired with a given device name.  Returns (nil,nil) if the user
-- variable either is not defined or is not yet formatted properly.
--
local mswPrefix  = 'MSW-'
local mswOneYear = 31536000
local function mswGetVariableContents( device )
   local flag, time
   local userVar = uservariables[ mswPrefix..device ]
   if( userVar ) then
      _,_,flag,time = string.find( userVar, "(%a)(%d+)" )
   end
   return flag,time
end

-- ------------------------------
-- Return TRUE if the switch device was just manually pressed
--
function mswSwitchWasManuallyPressed( device )
   if( devicechanged and devicechanged[device] ) then
      local flag,time = mswGetVariableContents( device )
      if( flag and time and flag == 'm' ) then return true end
   end
   return false
end

-- ------------------------------
-- Return number of seconds since we last saw a manual switch press on
-- the given device, or one year if we haven't seen one at all.
--
function mswAgeOfLastManualPress( device )
   local flag,time = mswGetVariableContents( device )
   if( flag and time ) then return ( os.time() - time ) end
   return mswOneYear
end

-- ------------------------------
-- Function to be called at the end of every LUA script that might be
-- commanding a switch transition whose manual status we later want to
-- check.  The global commandArray{} is both read and modified here in
-- order to possibly modify the associated user variables.
--
function mswUpdateDetectionVars()

   local device, command

   -- First update the user variables for every tracked device that
   -- has just changed.  The flag is always set back to 'manual'
   -- (since it has done its work already), and the time will either
   -- be updated to the present if we just saw a manual push, else
   -- left unchanged.
   --
   if( devicechanged ) then
      for device,command in pairs( devicechanged ) do      
	 if( uservariables[ mswPrefix..device ] ) then
	    local flag,time = mswGetVariableContents( device )
	    if( flag and time ) then
	       if( flag == 'm' ) then time = os.time() ; end
	    else
	       time = os.time() - mswOneYear -- Initialize new Var
	    end
	    commandArray['Variable:'..mswPrefix..device] = string.format( "m%d", time )
	 end
      end
   end

   -- Then update the user variables for every tracked device whose
   -- state is about to change as a result of a controller-based
   -- (non-manual) command.  Set the 'auto' flag and preserve whatever
   -- previous time was there already.
   --
   for device,command in pairs( commandArray ) do
      if( uservariables[ mswPrefix..device ] ) then
	 local flag,time = mswGetVariableContents( device )
	 if( time == nil ) then
	    time = os.time() - mswOneYear -- Initialize new Var
	 end
	 commandArray['Variable:'..mswPrefix..device] = string.format( "a%d", time )
      end
   end
end
Simply define a string user variable named 'MSW-MySwitch' for each 'MySwitch' device you want to monitor, and put the update routine at the very end of every script that might control such switches. You can then call mswSwitchWasManuallyPressed() to detect manual button presses in your device scripts, or mswAgeOfLastManualPress() in any script to tell how long it's been since a person last pressed the button with their finger.

I've already put this to several uses. It allows a dumb switch to function as a poor man's scene controller by LUA doing something different when you physically enter/leave the room versus other automated things that might be happening with that same switch. The following code now turns on a secondary light when we enter our bedroom, and turns off both lights plus a fan upon exiting. Meanwhile, our MiniMote still functions as always as a general scene controller while we're in the room.

Code: Select all

-- Wall switch at the door turns on extra light upon entry, and turns
-- everything off upon exit.
--
if( mswSwitchWasManuallyPressed( 'BED3-WallSwitch' ) ) then
   local swState = otherdevices[ 'BED3-WallSwitch' ]
   commandArray['BED3-FloorLamp'] = swState
   if( swState == 'Off' ) then
      commandArray['BED3-FloorFan'] = 'Off'
   end
end
Another application is a light that is turned On by a PIR sensor in a device script, and Off by a timeout in a time script. When you leave the room and manually turn off the light you can now inhibit the PIR sensor for perhaps 20 seconds so that the light won't turn back on a moment later before you make it out. I had originally been testing the lastupdate globals associated with the switch to allow time to leave, but the problem is that those times get updated by the automatic turn-Off -- so if the lights turn Off while you're still in the room you have to wait 20-seconds before waving your hands will turn them back on. With the new setup you get free passage out of the room plus instant-On if they happen to turn Off while you're still in there.

One Bug/Feature is that switch transitions initiated from the Domoticz floorplan (or through the JSON interface) now count as manual button presses. This is desirable or not, depending on how you think of it.

Post Reply

Who is online

Users browsing this forum: Wob76 and 2 guests