gpiozero
gpiozero copied to clipboard
'NoneType' object has no attribute 'holding'
Operating system: Ubuntu 18.04 Python version: 3.8 Pi model: e.g. Pi 1B GPIO Zero version: 1.5.1 Pin factory used: e.g. RPiGPIO See http://rpf.io/gpzissue for information on how to find out these details
Please give us as much information about your issue as possible. Write your code inside code blocks like so:
In 'Home Assistant' we use RPiGPIO for reading remote state of a GPIO pin. But sometimes the creation seems to fail.
I check the code, but it seems fine to me on Home Assistant side: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/remote_rpi_gpio/init.py
But sometimes it fails:
2019-10-16 20:02:45 ERROR (MainThread) [homeassistant.components.binary_sensor] Error while setting up platform remote_rpi_gpio
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 150, in _async_setup_platform
await asyncio.wait_for(asyncio.shield(task), SLOW_SETUP_MAX_WAIT)
File "/usr/local/lib/python3.7/asyncio/tasks.py", line 442, in wait_for
return fut.result()
File "/usr/local/lib/python3.7/concurrent/futures/thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "/usr/src/homeassistant/homeassistant/components/remote_rpi_gpio/binary_sensor.py", line 52, in setup_platform
address, port_num, pull_mode, bouncetime
File "/usr/src/homeassistant/homeassistant/components/remote_rpi_gpio/__init__.py", line 48, in setup_input
pin_factory=PiGPIOFactory(address),
File "/usr/local/lib/python3.7/site-packages/gpiozero/devices.py", line 124, in __call__
self = super(GPIOMeta, cls).__call__(*args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/gpiozero/input_devices.py", line 432, in __init__
bounce_time=bounce_time, pin_factory=pin_factory)
File "/usr/local/lib/python3.7/site-packages/gpiozero/mixins.py", line 383, in __init__
super(HoldMixin, self).__init__(*args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/gpiozero/input_devices.py", line 188, in __init__
self._fire_events(self.pin_factory.ticks(), self.is_active)
File "/usr/local/lib/python3.7/site-packages/gpiozero/mixins.py", line 368, in _fire_events
self._fire_activated()
File "/usr/local/lib/python3.7/site-packages/gpiozero/mixins.py", line 398, in _fire_activated
self._hold_thread.holding.set()
AttributeError: 'NoneType' object has no attribute 'holding'
See also https://github.com/home-assistant/home-assistant/issues/27724
Any idea what could be wrong here?
It seems like some race condition somewhere by the way, cause it happens randomly.
You mean pigpio not RPiGPIO :)
@waveform80 any idea?
From the link you posted:
try:
return Button(
port,
pull_up=pull_gpio_up,
bounce_time=bouncetime,
pin_factory=PiGPIOFactory(address),
)
except (ValueError, IndexError, KeyError, OSError):
return None
So if the creation of the Button fails for any reason, you silently swallow the error and just return None :confused:
Maybe the remote PiGPIOFactory(address) can't be connected to?
BTW, given that your functions are named setup_output and setup_input, maybe you'd be better off using DigitalOutputDevice and DigitalInputDevice rather than LED and Button ?
I also had this exception when running a very small gpiozero test I had written
Operating system: Raspbian GNU/Linux 10 (buster) Python version: 3.7.3 Pi model: model 1B rev 2 GPIO Zero version: 1.5.1 (from the python3-gpiozero package) Pin factory used: RPiGPIO
I happened when I was turning the rotary knob while the program was starting. It doesn't happen every time I do this, but fairly regularly.
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/gpiozero/pins/rpigpio.py", line 244, in _call_when_changed
super(RPiGPIOPin, self)._call_when_changed()
File "/usr/lib/python3/dist-packages/gpiozero/pins/local.py", line 143, in _call_when_changed
self.state if state is None else state)
File "/usr/lib/python3/dist-packages/gpiozero/pins/pi.py", line 293, in _call_when_changed
method(ticks, state)
File "/usr/lib/python3/dist-packages/gpiozero/input_devices.py", line 197, in _pin_changed
self._fire_events(ticks, bool(self._state_to_value(state)))
File "/usr/lib/python3/dist-packages/gpiozero/mixins.py", line 368, in _fire_events
self._fire_activated()
File "/usr/lib/python3/dist-packages/gpiozero/mixins.py", line 398, in _fire_activated
self._hold_thread.holding.set()
AttributeError: 'NoneType' object has no attribute 'holding'
The program I wrote:
import asyncio
import gpiozero as gpio
PIN_A = 17
PIN_B = 18
PIN_ENT = 27
PIN_BUZZ = 4
class Knob:
def __init__(self):
self.state = 0
self.dir_count = 0
self.a = 0
self.b = 0
self.loop = asyncio.get_running_loop()
self.on_rotate_cw = None
self.on_rotate_ccw = None
self.button_a = gpio.Button(PIN_A)
self.button_a.when_pressed = self.__set_a
self.button_a.when_released = self.__clear_a
self.button_b = gpio.Button(PIN_B)
self.button_b.when_pressed = self.__set_b
self.button_b.when_released = self.__clear_b
def __set_a(self):
self.a = 1
self.__rotate()
def __clear_a(self):
self.a = 0
self.__rotate()
def __set_b(self):
self.b = 1
self.__rotate()
def __clear_b(self):
self.b = 0
self.__rotate()
def __rotate(self):
new_state = self.b << 1 | (self.a ^ self.b)
if new_state == self.state:
return
d = (new_state - self.state) % 4 - 2
self.state = new_state
self.dir_count += d
if self.state == 0:
if self.dir_count < 0:
if self.on_rotate_ccw is not None:
self.loop.call_soon_threadsafe(self.on_rotate_ccw, -1)
elif self.dir_count > 0:
if self.on_rotate_cw is not None:
self.loop.call_soon_threadsafe(self.on_rotate_cw, 1)
self.dir_count = 0
async def main():
k = Knob()
k.on_rotate_cw = lambda d: print(d)
k.on_rotate_ccw = lambda d: print(d)
await asyncio.sleep(10)
if __name__ == '__main__':
try:
asyncio.run(main())
except asyncio.CancelledError:
pass
@JohanAR in your case I'm guessing (from a quick skim of the code, and the fact the class is called Knob :) that you're building something for a rotary encoder. In this case, Button isn't an ideal thing to use as there's a whole pile of machinery for dealing with held situations that you just don't need (i.e. you're likely running into a race-condition somewhere with multiple overlapping threads that've been started with the rapid pulses from the encoder). I'd suggest either using the base InputDevice class, or try the new RotaryEncoder class from 1.6.0.
Still, rapid button mashing shouldn't lead to this sort of exception so there's definitely a race condition somewhere in the HoldMixin code. I'll take a look at some point.
@waveform80 thanks! It is indeed a rotary encoder, I'll check out the new release and InputDevice
I've had exceptions fairly often on both startup and termination of the program, but I've never seen anything while the program is running. Occasionally when I start the program none of gpiozero works and I'm getting no input at all (and no error messages).. But that's with the old version available in raspbians repo, so it might have been fixed already