Simulate "button pressed" an rise an event in gpiozero - python

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
>>>

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')

how to update tkinter gui label with a thread?

I am new to Python tkinter . I have written the following code for my gui . I want to update my label 1 with received body message from rabbitmq . But i am facing issue once my gui get populate after that even i receive different message in body ,but its not able to update . Once i am closing the gui then again its coming with new value. I want my gui tkinter window to be constant and label should be refreshed on receiving new message in body.
import tkinter
from PIL import ImageTk, Image as PILImage
import datetime as dt
from tkinter import *
import pika
connection = pika.BlockingConnection(
pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='hello')
def callback(ch, method, properties, body):
global myval
print(" [x] Received %r" % body)
window=Tk()
window.attributes('-fullscreen',True)
window.bind("<F11>", lambda event: window.attributes("-fullscreen",
not window.attributes("-fullscreen")))
window.bind("<Escape>", lambda event: window.attributes("-fullscreen",False))
top_left=Frame(window,width=200,height=200)
top_middle=Frame(window,width=550,height=200)
top_right=Frame(window,width=250,height=200)
middle_left=Frame(window,width=200,height=300)
middle_middle=Frame(window,width=300,height=300)
middle_right=Frame(window,width=300,height=300)
bottom_left=Frame(window,width=0,height=200)
bottom_middle=Frame(window,width=300,height=200)
bottom_right=Frame(window,width=300,height=200)
top_left.grid(row=0,column=0)
top_middle.grid(row=0,column=1)
top_right.grid(row=0,column=2,sticky=E+W)
middle_left.grid(row=1,column=0,padx=100,pady=100)
middle_middle.grid(row=1,column=1)
middle_right.grid(row=1,column=2)
bottom_left.grid(row=2,column=0)
bottom_middle.grid(row=2,column=1)
bottom_right.grid(row=2,column=2)
dte=Label(top_left, text="Date: "f"{dt.datetime.now():%a,%d/ %m/ %Y}",fg="black",font=("Arial Bold ",12 ))
dte.place(x=0,y=40)
lbl=Label(top_middle, text="Welcome to Smartcards Division",fg='#3333ff',font=("Arial Bold Italic",24 ))
lbl.place(x=0,y=30)
logo_path="logo.jpg"
logo = ImageTk.PhotoImage((PILImage.open(logo_path)).resize((280,100),PILImage.ANTIALIAS))
logo_panel = Label(top_right,image = logo)
logo_panel.place(x=10,y=30)
string_clsname=str(body.decode())
lblxt=StringVar()
lbl1=Label(middle_left, textvariable=lblxt,fg='#ff6600',font=("Arial Bold Italic",16))
lblxt.set("Hello "+string_clsname+" Sir")
lbl1.place(x=0,y=100)
path = "NewPicture_Copy.jpg"
image = ImageTk.PhotoImage((PILImage.open(path)).resize((250,250),PILImage.ANTIALIAS))
panel = Label(middle_middle,image = image,borderwidth=5, relief="ridge")
panel.pack()
lbl2=Label(bottom_middle, text="\u00a9"+"2020-Smartcards Division",fg='black',font=("Helvetica",8))
lbl2.place(x=0,y=0)
window.title('Image Classification')
window.mainloop()
channel.basic_consume(
queue='hello', on_message_callback=callback, auto_ack=True)
print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()
At a base level, you need:
Separate threads of execution,
for separate tasks (that must run concurrently).
A way for the threads to communicate with each other;
while avoiding race conditions
(like modifying a variable in one thread,
while another thread is reading it).
Here you can e.g. use mutexes/locks, message-passing, etc.
import tkinter as tk
from collections import deque
from threading import Thread
from random import randint
from time import sleep
# Starting out (this is the main/gui thread).
root = tk.Tk()
label = tk.Label(root, text='Original text')
label.pack()
# Means of communication, between the gui & update threads:
messageQueue = deque()
# Create a thread, that will periodically emit text updates.
def emitText(): # The task to be called from the thread.
while(True): # Normally should check some condition here.
messageQueue.append(f'Random number: {randint(0, 100)}')
sleep(1) # Simulated delay (of 1 sec) between updates.
# Create a separate thread, for the emitText task:
thread = Thread(target=emitText)
# Cheap way to avoid blocking # program exit: run as daemon:
thread.setDaemon(True)
thread.start() # "thread" starts running independently.
# Moving on (this is still the main/gui thread).
# Periodically check for text updates, in the gui thread.
# Where 'gui thread' is the main thread,
# that is running the gui event-loop.
# Should only access the gui, in the gui thread/event-loop.
def consumeText():
try: label['text'] = messageQueue.popleft()
except IndexError: pass # Ignore, if no text available.
# Reschedule call to consumeText.
root.after(ms=1000, func=consumeText)
consumeText() # Start the consumeText 'loop'.
root.mainloop() # Enter the gui event-loop.
See also:
queue.Queue
"collections.deque is an alternative implementation of
unbounded queues with fast atomic append() and popleft()
operations that do not require locking."
collections.deque
threading.Thread

Python program disregards button input

I'm new to python and linux, and I recently set up a twitter bot with my Raspberry Pi to mess around and have fun with. I want to set up a system where my RasPi sends a tweet every time I press a button. I followed the instructions on https://raspberrypihq.com/use-a-push-button-with-raspberry-pi-gpio to set up the basic input.
I have two .py files, tweet_test.py and buttonPress.py
tweet_test:
#!/usr/bin/env python
import os
import random
from twython import Twython
# your twitter consumer and access information goes here
apiKey = ''
apiSecret = ''
accessToken = ''
accessTokenSecret = ''
api = Twython(apiKey,apiSecret,accessToken,accessTokenSecret)
messages = [
"A button was pressed!!",
"My creator pressed a button.",
"This tweet was triggered by a button press.",
]
message = random.choice(messages)
api.update_status(status=message)
print("Tweeted: " + message)
buttonPress:
import tweet_test
import RPi.GPIO as GPIO #Import Raspberry Pi GPIO library
def button_callback(channel):
tweet_test
print("Button was pushed!")
GPIO.setwarnings(False) #Ignore warning for now
GPIO.setmode(GPIO.BOARD) #Use physical pin numbering
GPIO.setup(10, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) #Set pin 10 to be an
input pin and set initial value to be pulled low (off)
GPIO.add_event_detect(10,GPIO.RISING,callback=button_callback) #Set up
event on pin 10 rising edge
message = input("Press enter to quit\n\n") #Run until someone presses
enter
GPIO.cleanup() #Clean Up
However, when I run buttonPress.py in the command line, the first thing it does is tweet, without even having received any input from the button. Then, it begins receiving button inputs, but doesn't tweet anything. Please help!
Sample output:
user1#raspberrypi:~/TwitterBot $ sudo python buttonPress.py
Tweeted: A button was pressed!!
Press enter to quit
Button was pushed!
Button was pushed!
Button was pushed!
You import tweet_test.py at the very beginning and it will run first, which will run as exactly it is supposed to do, i.e. to send a tweet. You need to wrap the tweeting part as a function so that it only run when it is called:
In tweet_test.py
def tweet():
message = random.choice(messages)
api.update_status(status=message)
print("Tweeted: " + message)
In buttonPress.py
Call the tweet() function in your button_callback like this:
def button_callback(channel):
tweet()
print("Button was pushed!")
Alternatively, just move the tweeting part to the button_call function, and combined both into your button_callback:
def button_callback(channel):
message = random.choice(messages)
api.update_status(status=message)
print("Button was pushed! Tweeted: %s" % message)
Update
Please also change the line import tweet_test to from tweet_test import *

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

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.

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