Newbie: Yet another non-blocking delay: delay LED turn-on without sleep() - python

I have a Raspberry Pi running the Flask framework to make a very application-specific http server. Doing an HTTP GET of a particular page on the Pi server triggers a GPIO action (e.g.: check if button is pressed, LED on, LED off and so on). Because I will poll the /status page to see if the button is pressed at 250ms intervals, I do not want the polling of the /unlock page to use timer.sleep(0.25) to close a relay for 250ms.
I want to set up an action that when called, will wait 250ms, turn the LED off then quietly go away. I tried both threading and sched. Threading works ONCE and throws an error when I pass through the code a second time (raise RuntimeError("threads can only be started once")).
#
# lots of other defines and includes
#
import threading
# set up function to turn de-energize relay (and Green LED)
def LED_Off_Wait():
GPIO.output(GREEN, False)
# set up timed thread
LED_Off = threading.Timer(0.25, LED_Off_Wait)
#
# flask framework page definitions go here
#
# unlock page where we energize and de-energize a lock
#app.route('/unlock')
def thing_unlock():
GPIO.output(GREEN, True) # energize the relay (and green LED)
# time.sleep(0.25) # don't want to do this
# GPIO.output(GREEN, False) #don't want to do this
LED_Off.start() # trigger the non-blocking thread to turn off
# the GPIO pin in 0.25s
# more flask stuff...
response = make_response(render_template('body.html', response='unlocked'))
response.headers['Access-Control-Allow-Origin'] = '*'
return response
I tried sched as well and it does not work for me, although it may be because I'm programming from the inside-out, learning by doing:
import sched
def LED_Off():
GPIO.output(GREEN, False)
# set up scheduled action, as nearly as I can determine from my reading
LED_ON_Delay = sched.scheduler(time.time, time.sleep) # set up scheduler (no sleep!)
LED_ON_Delay.enter( 1, 1, LED_Off,()) # schedule LED_Off for 0.25s in the future
#
# again, more Flask stuff here
#
#app.route('/unlock')
def thing_unlock():
GPIO.output(GREEN, True)
# time.sleep(0.25) # don't want to do this
# GPIO.output(GREEN, False) # don't want to do this
LED_ON_Delay.run() #trigger "non-blocking sleep"
response = make_response(render_template('body.html', response='unlocked'))
response.headers['Access-Control-Allow-Origin'] = '*'
return response
# more Flask stuff...
Bottom Line: how do I spin off a task that will turn the GPIO off after a certain time (or do anything else for that matter) without an error if I try to do it twice?

With the help of a friend, the answer was simpler than I expected: Lambda functions. First, import threading then declare the function that will do what you want (turn off the LED) after a time interval using threading.Timer():
def LED_Off_Wait( wait_time,IO_port ):
threading.Timer(wait_time, lambda: GPIO.output(IO_port, False)).start()
In this case, I need to use it in more than one place so I pass it the delay time and the GPIO pin it needs to act on.
When I need to turn the LED off after a delay inside another function, I call it like this:
#app.route('/unlock')
def prop_unlock():
GPIO.output(GREEN, True)
LED_Off_Wait( 0.5, GREEN )
response = make_response(render_template('body.html', response='unlocked'))
response.headers['Access-Control-Allow-Origin'] = '*'
return response
For completeness, GREEN has been previously defined like this:
GREEN = 24
# Use GPIO pin numbers
GPIO.setmode(GPIO.BCM)
GPIO.setup(GREEN, GPIO.OUT)
Works like a charm.

Related

Python Block Keyboard / Mouse Input

i am currently trying to write a short script that will rickroll (open a youtube link) while the user is watching and can't interfere.
I have managed to open insert the link slowly letter by letter and am now trying to block user inputs.
I have tried using the ctypes import to block all inputs, run the script and then unblock again, but it somehow won't block the input. I'm just receiving my RuntimeError message.
How do i fix it, so the inputs get blocked?
Thanks in advance!
Heres the code:
import subprocess
import pyautogui
import time
import ctypes
from ctypes import wintypes
BlockInput = ctypes.windll.user32.BlockInput
BlockInput.argtypes = [wintypes.BOOL]
BlockInput.restype = wintypes.BOOL
blocked = BlockInput(True)
if blocked:
try:
subprocess.Popen(["C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",])
time.sleep(3)
pyautogui.write('www.youtube.com/watch?v=DLzxrzFCyOs', interval= 0.5)
pyautogui.hotkey('enter')
finally:
unblocked = BlockInput(False)
else:
raise RuntimeError('Input is already blocked by another thread')
You can use the keyboard module to block all keyboard inputs and the mouse module to constantly move the mouse, preventing the user from moving it.
See these links for more details:
https://github.com/boppreh/keyboard
https://github.com/boppreh/mouse
This blocks all the keys on the keyboard (the 150 is large enough to ensure all keys are blocked).
#### Blocking Keyboard ####
import keyboard
#blocks all keys of keyboard
for i in range(150):
keyboard.block_key(i)
This effectively blocks mouse-movement by constantly moving the mouse to position (1,0).
#### Blocking Mouse-movement ####
import threading
import mouse
import time
global executing
executing = True
def move_mouse():
#until executing is False, move mouse to (1,0)
global executing
while executing:
mouse.move(1,0, absolute=True, duration=0)
def stop_infinite_mouse_control():
#stops infinite control of mouse after 10 seconds if program fails to execute
global executing
time.sleep(10)
executing = False
threading.Thread(target=move_mouse).start()
threading.Thread(target=stop_infinite_mouse_control).start()
#^failsafe^
And then your original code here (the if statement and try/catch block are no longer necessary).
#### opening the video ####
import subprocess
import pyautogui
import time
subprocess.Popen(["C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",])
time.sleep(3)
pyautogui.write('www.youtube.com/watch?v=DLzxrzFCyOs', interval = 0.5)
pyautogui.hotkey('enter')
#### stops moving mouse to (1,0) after video has been opened
executing = False
Just a few notes:
The mouse-moving is hard to stop from outside of the program (it's basically impossible to close the program when it is executing, especially as the keyboard is also being blocked), that's why I put in the failsafe, which stops moving the mouse to (1,0) after 10 seconds.
(On Windows) Control-Alt-Delete does allow Task Manager to be opened and then the program can be force-stopped from there.
This doesn't stop the user from clicking the mouse, which can sometimes prevent the YouTube link from being typed in full (i.e. a new tab can be opened)
See a full version of the code here:
https://pastebin.com/WUygDqbG
you could do something like this to block both keyboard and mouse input
from ctypes import windll
from time import sleep
windll.user32.BlockInput(True) #this will block the keyboard input
sleep(15) #input will be blocked for 15 seconds
windll.user32.BlockInput(False) #now the keyboard will be unblocked
Here's a function for blocking keyboard and mouse input. You can pass a number to the blockMouseAndKeys function to adjust the timeout period:
import os
import time
import pyautogui
from threading import Thread
from keyboard import block_key
def blockMouseAndKeys(timeout=5):
global blocking
blockStartTime = time.time()
pyautogui.FAILSAFE = False
blocking = True
try: float(timeout)
except: timeout = 5
def blockKeys(timeout):
global blocking
while blocking:
if timeout:
if time.time()-blockStartTime > timeout:
print(f'Keyboard block timed out after {timeout}s.')
return
for i in range(150):
try: block_key(i)
except: pass
def blockMouse(timeout):
global blocking
while blocking:
def resetMouse(): pyautogui.moveTo(5,5)
Thread(target=resetMouse).start()
if timeout:
if time.time()-blockStartTime > timeout:
print(f'Mouse block timed out after {timeout}s.')
return
def blockTimeout(timeout):
global blocking
time.sleep(timeout)
blocking = False
pyautogui.FAILSAFE = False
print('Done blocking inputs!')
print('Blocking inputs...')
Thread(target=blockKeys, args=[timeout]).start()
Thread(target=blockMouse, args=[timeout]).start()
Thread(target=blockTimeout, args=[timeout]).start()
blockMouseAndKeys(timeout=10)
os.startfile('https://www.youtube.com/watch?v=DLzxrzFCyOs')

Tkinter GUI updating depending on serial connection

Good afternoon thank you all who look at my issue,
I am building a script to do initial configuration on switches through console port, I can make a connection to the console port the issue comes when building a GUI in TKINTER.
I want the gui to connect through a specified some port when the button is pressed and when the connection is made make a light(using canvas) go green showing a successful connection went through.
My issue is getting the light to change to green and stay when a connection is made I have tried
my initally also tried to use global then realized the window loop constantly set it back to red
nested while loop--- breaks Tkinker
importing a file I created called variableset which stores variable to set green but since it constantly has a new instance it just sets the variable in tinker back to red.
any help would be greatly appreciated
GUI CODE
import tkinter as tk
from tkinter import *
import connect
import variableset
setting = variableset.setting
window = tk.Tk()
window.title("Network Wizard 1")
window.geometry('300x500')
# setting =tk.IntVar()
# setting.set(variableset.setting)
#serial port pick the right one
serialportlabel = tk.Label(text="COM Number")
serialport = tk.Entry(width= 7)
serialportlabel.pack()
serialport.pack()
#color alerting!! red bad
alert = Canvas(window, width=50, height=20)
alert.pack()
if setting == 0:
a=alert.create_rectangle(5, 0, 50, 50, fill='red')
else:
a=alert.create_rectangle(5, 0, 50, 50, fill='green')
# #connection part woop woop
connection = tk.Button(text="connect", command = lambda: bus())
connection.pack()
# #firmwarecheck
# firmwarecheck = tk.Button(text="Firmware check")
# firmwarecheck.pack()
# #firmware update
# firmwareupdate= tk.Button(text="Firmware update")
# firmwareupdate.pack()
# #software update
# software = tk.Button(text="software update")
# connect.pack()
# #vmlans
# vlanupdate = tk.Button(text="Vlanupdate")
# vlanupdate.pack()
# disconnect = tk.Button(text="disconnect")
# disconnect.pack()
# qut = tk.Button(text="quite")
# qut.pack()
def bus():
global ser
ser = connect.connect(serialport.get())
global setting
setting = variableset.initial
# def firmware(ser):
# if ser.isOpen() == true :
window.mainloop()
Connect code
import serial
import time
import sys
#connect
def connect(com):
ser = serial.Serial(
port = com, #COM
baudrate=9600,
parity='N',
stopbits=1,
bytesize=8,
timeout=8
)
ser.isOpen()
print(ser.name)
#set variables
enter = str.encode('\r\n') #enter
user = str.encode('admin#sytem\r\n') #default user name
pwd = str.encode('\r\n') #defualt password
qut = str.encode('quit\r')
time.sleep(1.0)
# ser.inWaiting()
ser.write(enter) #promt login
time.sleep(0.5)
ser.write(user) #enter user name
time.sleep(0.5)
ser.write(pwd) #enter password
time.sleep(0.5)
ser.write(enter)
time.sleep(0.5)
ser.write(enter)
time.sleep(0.5)
ser.write(str.encode("sytem\r\n"))
time.sleep(0.5)
ser.write(qut)
ser.write(qut)
input_read = ser.read(500)
input_read = input_read.decode("utf-8","ignore")
print(input_read)
ser.close()
return ser
def write(ser):
ser.write(str.encode(''+'\r\n'))
def disconnect(ser):
ser.write(str.encode('quit\r\n'))
time.sleep(.2)
ser.write(str.encode('quit\r\n'))
time.sleep(.2)
ser.write(str.encode('quit\r\n'))
time.sleep(.2)
ser.close()
Variableset Code
global setting
setting = 0
def initial():
global setting
setting = 1
return setting
def unset():
global setting
setting = 0
return setting
Any help greatly appreciated
Your if-else statement only runs once, before the setting variable has been set, as far as we can tell. It's not in a loop or a function that gets called from somewhere else. What exactly is the problem you're having with the code that you posted? The issues you described seem to relate to a loop setting it back to red in a different version of the code.
In any event, I suspect that your problem is trying to use infinite loops to keep checking the setting, which prevents the tkinter mainloop() from running, and therefore blocks the GUI from updating. If so, the best method to fix it is probably to change your code for "check the setting and then change the color" into its own function, which gets called for the first time at the end of your connect function. Then, the end of the check setting function should schedule itself to be run after a time delay using the tkinter after() method, which is non-blocking (asnychronous) and allows the mainloop() to keep running. Alternative methods include a separate thread to run the check-setting code, or using the tkinter update() method, but after() is easiest.
Note that your sleep() functions in the connect code will also block the mainloop while they're running. I'm also not clear what you're trying to do with the variableset code; it appears to set the setting to 1 (aka green light) when you call initial(), regardless of the actual status on the serial port.

Simulate "button pressed" an rise an event in gpiozero

I try to develop some code on a machine without GPIO. As GPIO library I selected a gpiozero to be able to write my code without access to gpio of raspberry pi.
My problem, I cant get ride of .when_pressed event in the code.
I simulate state change of the button, but the function is not called.
Device.pin_factory = MockFactory()
def interrupt_Event(channel):
print("%s puted in the queue", channel)
InputPin.Device.pin_factory.pin(channel)
InputPin.when_pressed = interrupt_Event
def main():
try:
while True:
time.sleep(1)
InputPins[channel].pull=drive_high()
time.sleep(0.1)
print("State CHANNEL %s" % channel)
print(InputPins[channel].state)
InputPins[channel].drive_low()
Till now I have no Idea what is wrong.
when_pressed function should not have arguments (see 2.7 in https://gpiozero.readthedocs.io/en/stable/recipes.html).
You could define the callback using a loop :Creating functions in a loop
(use channel=channel to force early binding of channel value as in example below)
for channel in channels:
def onpress(channel=channel):
print("%s puted in the queue", channel)
InputPins[channel].when_pressed = onpress
I am not convinced that you are using drive_high and drive_low to simulate the button pushing.
I have a almost identical problem. using Mock pins to develop a Pi program on windows, I find that the callback routines are not called.
from gpiozero.pins.mock import MockFactory
from gpiozero import Device, Button, LED
from time import sleep
Device.pin_factory = MockFactory() # set default pin
factory
btn = Button(16)
# Get a reference to mock pin 16 (used by the button)
btn_pin = Device.pin_factory.pin(16)
def pressed(): # callback
print('pressed')
def released(): # callback
print('released')
btn.when_pressed = pressed
btn.when_released = released # callback routine
for i in range(3): # now try to signal sensor
print('pushing the button')
btn_pin.drive_high
sleep(0.1)
btn_pin.drive_low
sleep(0.2)
The output has no callbacks, just
pushing the button
pushing the button
pushing the button
>>>

Python threading class for GPIO Led blink

I come here after after trying in all directions to come out of this problem without any results, unfortunately.
What I have in mind:
I need a class, named Led, that in the constructor simply accept a GPIO pin and offer method for:
Light On
Light Off
Blinking
What I do:
I have build this class in this way:
import RPi.GPIO as GPIO
import time
import threading
from threading import Thread
class Led(Thread):
def __init__(self, led_pin):
Thread.__init__(self)
self.pin_stop = threading.Event()
self.__led_pin = led_pin
GPIO.setmode(GPIO.BCM)
GPIO.setup(self.__led_pin, GPIO.OUT)
def low(self, pin):
GPIO.setup(pin, GPIO.OUT)
GPIO.output(pin, GPIO.LOW)
def blink(self, time_on=0.050, time_off=1):
pin = threading.Thread(name='ledblink',target=self.__blink_pin, args=(time_on, time_off, self.pin_stop))
pin.start()
def __blink_pin(self, time_on, time_off, pin_stop):
while not pin_stop.is_set():
GPIO.output(self.__led_pin, GPIO.HIGH)
time.sleep(time_on)
GPIO.output(self.__led_pin, GPIO.LOW)
time.sleep(time_off)
def __stop(self):
self.pin_stop.set()
def reset(self):
GPIO.cleanup()
def off(self):
self.__stop()
def on(self):
self.__stop()
GPIO.output(self.__led_pin, GPIO.LOW)
GPIO.output(self.__led_pin, GPIO.HIGH)
where the blink method is responsible to indefinitely blink the led until an Off or On method call.
And run this simple code:
from classes.leds import Led
import time
from random import randint
Led16 = Led(16)
def main():
while True:
if (randint(0, 1) == 1):
Led16.blink()
else:
Led16.off()
time.sleep(2)
if __name__ == "__main__":
main()
What happens:
The Led object seem to spawn a new thread every time that a method is called with the effect that GPIO line become shared between multiple threads.
What is my wish:
I want to keep blinking led asynchronous (obviously) and have the control on Led16() object status, maybe without creating new threads each time I cal its method, but at reached this point I am bit confused.
Thank to help me understanding how to reach this goal.
You are creating lots of threads because your blink() creates a new thread every time it is called and the old one isn't stopped.
I suppose there are a couple of options with the thread:
Create the thread just once - for example in __init__() - and it runs continuously on the blinking time intervals (i.e. sleeping most of the time) reading an instance variable and setting the LED correspondingly. To change the led state, the blink(), on() and off() control the led by setting this instance variable to on/off/blinking.
In the blink routine, if the thread is already running either don't create a new thread, or stop the old thread (and wait for it to finish) and then start a new one.
Things you will have to handle are that you want the behaviour to be that:
If the led is off then the led turns on as soon as on() or blink() is called
If the led is blinking and blink() is called again the blinking on/off sequence is not disturbed
If blinking and off() is called I would want the on-cycle if it has started to run to completion, i.e. the led should not be turned off immediately because that might be a very short flash which would look odd.
The catch with creating a new thread is waiting for the old one to finish, and it just feels simplest to create the thread just once in __init__() and have it running continuously. When the led is on or off, the time period is shortened (to value FAST_CYCLE) so that when the led is turned off or on it reacts quickly because the sleep() is for a short time.
Some other points about your code:
I don't think you need to make your class inherit from Thread - you are creating a new thread in the pin=... line.
If you add comments as you write the code, usually makes it easier to understand what is going on when reading the code.
If you keep a reference to the thread (i.e. self.pin = threading.Thread not pin = threading.Thread) then in the reset() you can use join() to make sure it has exited before you continue
As the blink time periods can change and the thread has to use the latest values, use self to read them every time rather than pass them as arguments to the __blink_pin() routine, and if doing that you might as well use self to get the pin_stop semaphore too.
Something like this (untested):
import RPi.GPIO as GPIO
import time
import threading
from threading import Thread
class Led(object):
LED_OFF = 0
LED_ON = 1
LED_FLASHING = 2
# the short time sleep to use when the led is on or off to ensure the led responds quickly to changes to blinking
FAST_CYCLE = 0.05
def __init__(self, led_pin):
# create the semaphore used to make thread exit
self.pin_stop = threading.Event()
# the pin for the LED
self.__led_pin = led_pin
# initialise the pin and turn the led off
GPIO.setmode(GPIO.BCM)
GPIO.setup(self.__led_pin, GPIO.OUT)
# the mode for the led - off/on/flashing
self.__ledmode = Led.LED_OFF
# make sure the LED is off (this also initialises the times for the thread)
self.off()
# create the thread, keep a reference to it for when we need to exit
self.__thread = threading.Thread(name='ledblink',target=self.__blink_pin)
# start the thread
self.__thread.start()
def blink(self, time_on=0.050, time_off=1):
# blinking will start at the next first period
# because turning the led on now might look funny because we don't know
# when the next first period will start - the blink routine does all the
# timing so that will 'just work'
self.__ledmode = Led.LED_FLASHING
self.__time_on = time_on
self.__time_off = time_off
def off(self):
self.__ledmode = LED_OFF
# set the cycle times short so changes to ledmode are picked up quickly
self.__time_on = Led.FAST_CYCLE
self.__time_off = Led.FAST_CYCLE
# could turn the LED off immediately, might make for a short flicker on if was blinking
def on(self):
self.__ledmode = LED_ON
# set the cycle times short so changes to ledmode are picked up quickly
self.__time_on = Led.FAST_CYCLE
self.__time_off = Led.FAST_CYCLE
# could turn the LED on immediately, might make for a short flicker off if was blinking
def reset(self):
# set the semaphore so the thread will exit after sleep has completed
self.pin_stop.set()
# wait for the thread to exit
self.__thread.join()
# now clean up the GPIO
GPIO.cleanup()
############################################################################
# below here are private methods
def __turnledon(self, pin):
GPIO.output(pin, GPIO.LOW)
def __turnledoff(self, pin):
GPIO.output(pin, GPIO.HIGH)
# this does all the work
# If blinking, there are two sleeps in each loop
# if on or off, there is only one sleep to ensure quick response to blink()
def __blink_pin(self):
while not self.pin_stop.is_set():
# the first period is when the LED will be on if blinking
if self.__ledmode == Led.LED_ON or self.__ledmode == Led.LED_FLASHING:
self.__turnledon()
else:
self.__turnledoff()
# this is the first sleep - the 'on' time when blinking
time.sleep(self.__time_on)
# only if blinking, turn led off and do a second sleep for the off time
if self.__ledmode == Led.LED_FLASHING:
self.__turnledoff()
# do an extra check that the stop semaphore hasn't been set before the off-time sleep
if not self.pin_stop.is_set():
# this is the second sleep - off time when blinking
time.sleep(self.__time_off)
For who need this in the future I have do some little adjustment to the proposed code and seem to work fine as expected.
Again thanks to #barny
import RPi.GPIO as GPIO
import time
import threading
class Led(object):
LED_OFF = 0
LED_ON = 1
LED_FLASHING = 2
# the short time sleep to use when the led is on or off to ensure the led responds quickly to changes to blinking
FAST_CYCLE = 0.05
def __init__(self, led_pin):
# create the semaphore used to make thread exit
self.pin_stop = threading.Event()
# the pin for the LED
self.__led_pin = led_pin
# initialise the pin and turn the led off
GPIO.setmode(GPIO.BCM)
GPIO.setup(self.__led_pin, GPIO.OUT)
# the mode for the led - off/on/flashing
self.__ledmode = Led.LED_OFF
# make sure the LED is off (this also initialises the times for the thread)
self.off()
# create the thread, keep a reference to it for when we need to exit
self.__thread = threading.Thread(name='ledblink',target=self.__blink_pin)
# start the thread
self.__thread.start()
def blink(self, time_on=0.050, time_off=1):
# blinking will start at the next first period
# because turning the led on now might look funny because we don't know
# when the next first period will start - the blink routine does all the
# timing so that will 'just work'
self.__ledmode = Led.LED_FLASHING
self.__time_on = time_on
self.__time_off = time_off
def off(self):
self.__ledmode = self.LED_OFF
# set the cycle times short so changes to ledmode are picked up quickly
self.__time_on = Led.FAST_CYCLE
self.__time_off = Led.FAST_CYCLE
# could turn the LED off immediately, might make for a short flicker on if was blinking
def on(self):
self.__ledmode = self.LED_ON
# set the cycle times short so changes to ledmode are picked up quickly
self.__time_on = Led.FAST_CYCLE
self.__time_off = Led.FAST_CYCLE
# could turn the LED on immediately, might make for a short flicker off if was blinking
def reset(self):
# set the semaphore so the thread will exit after sleep has completed
self.pin_stop.set()
# wait for the thread to exit
self.__thread.join()
# now clean up the GPIO
GPIO.cleanup()
I'm not sure it will be helpfull, but I came up with that (using gpiozero)
from gpiozero import LED
import time
import threading
class LEDplus():
def __init__(self,pinnumber):
self.led = LED(pinnumber)
self.__loop = True
self.__threading = threading.Thread(target=self.__blink)
def on(self,):
self.__loop = False
self.maybejoin()
self.led.on()
def off(self, ):
self.__loop = False
self.maybejoin()
self.led.off()
def maybejoin(self,):
if self.__threading.isAlive():
self.__threading.join()
def blink(self, pitch):
self.__threading = threading.Thread(target=self.__blink, args=(pitch, ))
self.__threading.start()
def __blink(self, pitch=.25):
self.__loop = True
while self.__loop:
self.led.toggle()
time.sleep(pitch/2)
self.led.off()
green = LEDplus(18)
green.blink(1)
On the answer of Alessandro Mendolia, just missing the private methods of the class. Added below with some fixes. The __turnledon() does not need an argument - it can access the self.__led_pin already stored in initialization.
############################################################################
# below here are private methods
def __turnledon(self):
GPIO.output(self.__led_pin, GPIO.LOW)
def __turnledoff(self):
GPIO.output(self.__led_pin , GPIO.HIGH)
# this does all the work
# If blinking, there are two sleeps in each loop
# if on or off, there is only one sleep to ensure quick response to blink()
def __blink_pin(self):
while not self.pin_stop.is_set():
# the first period is when the LED will be on if blinking
if self.__ledmode == BlinkerLed.LED_ON or self.__ledmode == BlinkerLed.LED_FLASHING:
self.__turnledon()
else:
self.__turnledoff()
# this is the first sleep - the 'on' time when blinking
time.sleep(self.__time_on)
# only if blinking, turn led off and do a second sleep for the off time
if self.__ledmode == BlinkerLed.LED_FLASHING:
self.__turnledoff()
# do an extra check that the stop semaphore hasn't been set before the off-time sleep
if not self.pin_stop.is_set():
# this is the second sleep - off time when blinking
time.sleep(self.__time_off)

Async / Multi-Threading with blinker

I have a raspberry pi which I have hooked up with a 4 button keypad. Using the signal stuff from blinker I hooked it up to run some methods.
#sender
while True:
if buttonIsDown == True: signal.send()
#reciever
#signal.connect
def sayHI():
print("1")
time.sleep(10)
print("2")
This works fine, however when I push the button for the second time (Within 10 seconds of the previous button press) it does not fire the method as the thread is paused in the time.sleep(10).
How can I get it to fire the method again while the it is still paused(possibly in another thread)
It is an old question, but still it may be useful for someone else.
You can start a new thread every time the signal is emitted, in that way you will be able to catch all the events as soon as they happen. Remember that in your code, since you have a while True, the signal is never connected to the function, you should have defined them in the opposite order.
Here is a working example, based on your code:
import threading
from blinker import signal
from time import sleep
custom_signal = signal(name='custom')
#custom_signal.connect
def slot(sender):
def say_hello():
print("1")
sleep(10)
print("2")
threading.Thread(target=say_hello).start()
while True:
value = int(input('Press 1 to continue: '))
if value == 1:
custom_signal.send()
else:
break

Categories

Resources