I’m working on a component for the Elk M1 Gold (and related) alarm / integration panels. I started with building a stand alone bit of Python which seemed to work reasonably well (at least with limited testing of processing Elk messages and so on, not everything implemented yet by far), and I used the serial.threaded version of PySerial, which worked fine - when new messages come in, they get parsed and put into a deque to be processed later whenever the main code gets around to it.
However, this breaks when I try to turn it into a HA component, and I’m wondering if it’s related to whatever special sauce HA is using with threading and coroutines and all that. https://home-assistant.io/developers/asyncio/ implies that you can still make non-async stuff, and that’s what I was going to do at first (since my existing code wasn’t using async / coroutines, and async PySerial is still experimental, apparently).
However, when I spin up the PySerial thread to make the connection to the Elk (in my case via TCP socket, but using PySerial means RS-232 can be supported with no changes other than setting the ‘host’ accordingly to a device), and call it’s connect method, I get an error that the thread has already stopped.
I’m not sure if this is specific to trying to use some other threaded thing from within HA, and there’s some other way of handling it without going to asyncio, or … ? I also don’t entirely understand how HA handles giving time to the various components to do things yet, so perhaps going serial.threaded is overkill and just plain serial would work (but this might preclude me from being able to use async methods elsewhere in the component/sensors/etc?).
This is my first time doing anything interesting in Python, I’ve dabbled in the past but nothing involving threads and such.
This is on the current (?) docker image from 9 days ago, image id b2eb6220af84
2017-05-17 19:59:18 ERROR (MainThread) [homeassistant.setup] Error during setup of component elkm1
Traceback (most recent call last):
File "/usr/src/app/homeassistant/setup.py", line 188, in _async_setup_component
None, component.setup, hass, processed_config)
File "uvloop/future.pyx", line 230, in __iter__ (uvloop/loop.c:110600)
File "uvloop/future.pyx", line 432, in uvloop.loop.BaseTask._fast_wakeup (uvloop/loop.c:113980)
File "uvloop/future.pyx", line 101, in uvloop.loop.BaseFuture._result_impl (uvloop/loop.c:108900)
File "/usr/local/lib/python3.5/concurrent/futures/thread.py", line 55, in run
result = self.fn(*self.args, **self.kwargs)
File "/config/custom_components/elkm1.py", line 1275, in setup
ELK = PyElk(address=host, usercode=code, log=_LOGGER)
File "/config/custom_components/elkm1.py", line 1018, in __init__
self.connect(address)
File "/config/custom_components/elkm1.py", line 1050, in connect
self._connectionTransport, self._connectionProtocol = self._connectionThread.connect()
File "/usr/local/lib/python3.5/site-packages/serial/threaded/__init__.py", line 238, in connect
raise RuntimeError('already stopped')
RuntimeError: already stopped
Here’s the relevant code that it’s erroring at:
1046 def connect(self, address):
1047 self._connection = serial.serial_for_url(address, timeout=1)
1048 self._connectionThread = serial.threaded.ReaderThread(self._connection, LineHandler)
1049 self._connectionThread.start()
1050 self._connectionTransport, self._connectionProtocol = self._connectionThread.connect()