Clash Royale CLAN TAG#URR8PPP
Threading Timer - NoneType error on raspberry pi - passing variable to another thread
I'm junior python dev, mainly backend Django. One of my first tasks in work to write program on raspberry pi that set state to LOW
and after 5 sec to HIGH
.
LOW
HIGH
Seems not a problem but.... I think the proper way of waiting 5 sec to change to HIGH
is not via time.sleep()
but via threading.Timer
(I found it on stackoverflow)... It will be connected via web socket so I think one thread must listen and another must change states
HIGH
time.sleep()
threading.Timer
My problem is half pythonic, half raspberrian... this is my code:
import RPi.GPIO as GPIO
from threading import Timer
from time import sleep
pin = 22
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin, GPIO.OUT)
def set_high():
GPIO.output(pin, GPIO.HIGH)
def web_socket_loop():
GPIO.output(pin, GPIO.LOW)
t = Timer(5, set_high(GPIO))
t.start()
web_socket_loop()
GPIO.cleanup()
When I run this code states are changing, but after few sec I also got an error:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/usr/local/lib/python3.7/threading.py", line 1158, in run
self.function(*self.args, **self.kwargs)
TypeError: 'NoneType' object is not callable
I found on stack that I have to do something like this: (but it does not work properly): ;/
t = Timer(5, set_high, args=[GPIO])
And it does repair error about NoneType... but I got another error:
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/usr/local/lib/python3.7/threading.py", line 1158, in run
self.function(*self.args, **self.kwargs)
RuntimeError: Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)
I probably know why this error is but have no idea how to deal with it. I think that on another thread RPi.GPIO
is not configured (GPIO.setmode(GPIO.BCM), GPIO.setup(pin, GPIO.OUT))
RPi.GPIO
(GPIO.setmode(GPIO.BCM), GPIO.setup(pin, GPIO.OUT))
Thats why I pass GPIO
as a variable to the function set_high(GPIO)
, without it on another thread it thinks that RPi
is not configured... passing this variable is cool but... I got an NoneType
error... ;/
GPIO
set_high(GPIO)
RPi
NoneType
When I try second way with Timer(5, set_high, args=[GPIO])
the NoneType
error disappears but another occurs (RuntimeError with info about pin setup
)... this is the same error which I get when I don't pass GPIO
to the function like this:
Timer(5, set_high, args=[GPIO])
NoneType
RuntimeError with info about pin setup
GPIO
def set_high(#i_dont_pass_GPIO):
#things
pass
What is the proper way of passing the GPIO variable to another thread? So that it will recognize this variable properly and set pin 22 to HIGH.
Or maybe you recommend to try do it another way? Maybe sleep is better? But it will be connected via web socket so I think one must listen and another must change states?
I appreciate any help!!
t = Timer(5, set_high(GPIO)
set_high(GPIO)
None
Timer
None
t = Timer(5, set_high, args=[GPIO])
1 Answer
1
Your first problem, and your third one, really aren't relevant, because you've already correctly solved them.
When you call Timer(5, set_high(GPIO))
, that calls set_high(GPIO)
right now, and passes whatever it returns as the target function for the Timer
to call. Since it returns None
, 5 seconds later, your Timer
tries to call None
as a function, hence the TypeError
.
Timer(5, set_high(GPIO))
set_high(GPIO)
Timer
None
Timer
None
TypeError
The fix is exactly what you already did:
Timer(5, set_high, [GPIO])
Now, once you've fixed that, think through the flow of control you're asking for.
First, you do this:
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin, GPIO.OUT)
Then you call web_socket_loop
, and it does this:
web_socket_loop
GPIO.output(pin, GPIO.LOW)
And then it creates and starts a Timer
, and returns. And you do this:
Timer
GPIO.cleanup()
Then, 5 seconds later, the timer does off and calls your set_high
function, which does this:
set_high
GPIO.output(pin, GPIO.HIGH)
You can't set the pin high after you've cleaned up the GPIO.
The error message is a bit misleading:
RuntimeError: Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)
This is because the state post-cleanup is the same as the state pre-initialization, so it assumes your problem is that you haven't initialized things by calling setmode
yet.
setmode
How can you fix that? Your main thread shouldn't try to clean up until you're done.
Normally, you have other stuff for the main thread to do. That's why you use a Timer
, or a Thread
, or some other form of concurrency. But when you do that, you need to give your main thread some way to wait on that background work to finish, or you need to find some way to chain things up so that the cleanup
happens only after the last thread is done using GPIO.
Timer
Thread
cleanup
When you add the code that deals with communicating over a websocket, you'll need to do one of those things. But it's impossible to show you what you should do without knowing how you plan to organize that code.
Meanwhile, you really have nothing else to do but wait for 5 seconds, so you don't need any concurrency; just sleep
:
sleep
def web_socket_loop():
GPIO.output(pin, GPIO.LOW)
time.sleep(5)
set_high(GPIO)
join
asyncio
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
The problem with
t = Timer(5, set_high(GPIO)
is that it's callingset_high(GPIO)
right now, then passing the result of that call (which isNone
) as the target function toTimer
. And you can't callNone
as a function. But your fix to callt = Timer(5, set_high, args=[GPIO])
solves that. If you get a different error, please edit your question to be about the problem you want help with, instead of being about the problem you already solved and only mentioning your actual problem two thirds of the way down.– abarnert
yesterday