Skip to content

Instantly share code, notes, and snippets.

@marcelstoer
Last active October 3, 2018 14:31
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save marcelstoer/75ba30a4aec56d1b3810 to your computer and use it in GitHub Desktop.
Debounce with NodeMCU with two separate functions for down/up trigger
-- inspired by: http://www.esp8266-projects.com/2015/03/buttons-pushbuttons-and-debouncing-story.html
local GPIO14 = 5
local debounceDelay = <however-many-ms-your-sensor-requires>
local debounceAlarmId = <0-6>
gpio.mode(GPIO14, gpio.INT, gpio.PULLUP)
gpio.trig(GPIO14, "down", doorLocked)
function doorLocked()
-- don't react to any interupts from now on and wait 50ms until the interrupt for the up event is enabled
-- within that 50ms the switch may bounce to its heart's content
gpio.trig(GPIO14, "none")
tmr.alarm(debounceAlarmId, debounceDelay, tmr.ALARM_SINGLE, function()
gpio.trig(GPIO14, "up", doorUnlocked)
end)
-- finally react to the down event
end
function doorUnlocked()
-- don't react to any interupts from now on and wait 50ms until the interrupt for the down event is enabled
-- within that 50ms the switch may bounce to its heart's content
gpio.trig(GPIO14, "none")
tmr.alarm(debounceAlarmId, debounceDelay, tmr.ALARM_SINGLE, function()
gpio.trig(GPIO14, "down", doorLocked)
end)
-- finally react to the up event
end
Copy link

ghost commented Mar 7, 2017

It seems you miss to fill the local variable here:

local debounceDelay
local debounceAlarmId

@marcelstoer
Copy link
Author

You need to give those two meaningful values, yes. I'll make that a little more clear with the next revision.

Copy link

ghost commented Mar 8, 2017

I've even tried it out... something weird is happening... i got anyway TWO execution of the "react to the XXX event" each one... i mean two for the down and two for the up if i set the delay to something like 250ms

@Thyristor66
Copy link

Works perfectly for me, thanks! It's the only "debouncing" among many others which I found working - on both edges just one XXX action. From my observation it seems that all "bounced" interrupts are buffered and no matter whether there are any delays inside int routine or not. The "magic" is probably in the deactivation of triggering ( gpio.trig(GPIO14, "none")) and its activating after delay. Many other "debouncers" without it just make multiple delayed actions.

@marcelstoer
Copy link
Author

@Thyristor66, glad you like it but personally I prefer https://gist.github.com/marcelstoer/59563e791effa4acb65f because it's generically applicable.

@shinji2009
Copy link

not working anymore. PANIC: unprotected error in call to Lua API (magic.lua:6: bad argument #3 to 'trig' (invalid callback type))

@Bop4yN
Copy link

Bop4yN commented May 27, 2018

This is what I was looking for. Great.
@shinji2009, just move lines
gpio.mode(GPIO14, gpio.INT, gpio.PULLUP) gpio.trig(GPIO14, "down", doorLocked)
to the end. Functions doorLocked() and doorUnlocked() must be defined before calling them.

@marcelstoer
I had
PANIC: unprotected error in call to Lua API (attempt to call a nil value)
with "up" and "down" events. But with "low" and "high" levels it's working great.
gpio.trig(GPIO14, "low", doorLocked)
and
gpio.trig(GPIO14, "high", doorUnlocked)

Thank you for that code. This is the only one which works as it supposed to (as I want).

@ChrisTBarnes
Copy link

ChrisTBarnes commented Oct 2, 2018

Hi I am new to this site so please forgive me for a very poor looking post.
I have written several lua interrupt handlers using OO timers and they make
coding easier and future proof. Please see badly pasted example lua code below...
(It has lost all it's formating. Cut and paste into Visual Studio, save to a *.lua file and reformat)

-- Example Code using OOP Timer
-- Create Object Timers to handle deboucing hardware interrupts
-- Use the Object-oriented programming (OOP) API with tmr.create().
-- Old lua timers with numbers are going to be depreciated!!!!!!!!

local gpioGarageDoorState = 2   -- Pin 2 on nodemcu and GPIO04
local bounce = 50               -- Debounce period. 50ms time used to debounce switches

-- Interrupt vector routine for garagedoor
function GarageDoor()
    -- Debounce sense switch and set door state. 
    -- The state is based on reading the gpio at it's settled hardware state
    GaragedoorTimer:start()
end

-- Create a timer to debounce Garage door strated in by interrupt routine
-- ALARM_SEMI will only fire once.  No need to execute GaragedoorTimer:stop().  
-- Timer will fire again when another interrupt starts it.
GaragedoorTimer = tmr.create()
GaragedoorTimer:register(bounce, tmr.ALARM_SEMI, function()
        -- Now check the switch state again as it should have settled down
        if gpio.read(gpioGarageDoorState) == gpio.LOW then
            -- Publish State of Garage Door Closed
            mqttBroker:publish(topicQueue .. "/state", "Closed", 1, 1)-- publish and retain
        else
            -- Publish State of Garage Door Open
            mqttBroker:publish(topicQueue .. "/state", "Open", 1, 1)-- publish and retain
        end
end)

-- Set up Door Switch pin for Interrupt, (Hardware switches between open circuit and Gnd)
gpio.mode(gpioGarageDoorState, gpio.INT, gpio.PULLUP)

-- Set hardware interrupt handler for garage door.  
-- (Triggered when hardware switch state changes)
gpio.trig(gpioGarageDoorState, "both", GarageDoor)

--  additional code here

@ChrisTBarnes
Copy link

Thank you marcelstoer for formatting my post.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment