Hi all, I have a question related to the modbus TCP integration home assistant has, specifically how to improve the speed at which inputs can be read.
TL;DR: how to optimize I/O for a master / slave setup that inherently requires polling, such as modbus TCP? Should I create an asyncio-like pymodbus library?
update Jan 2020; the unipi platform provides a suite of services called evok that exposes the events via a websocket. From that point, I could easily write my own websocket-to-mqtt translation, see https://github.com/mhemeryck/evok2mqtt
Background: Unipi – PLCs and modbus TCP
Some background: I am currently in the middle of the process of constructing a new house. I will do the wiring of the electricity myself; the idea is to have all wiring coming together at a central point, where I can add my own controller running home assistant.
I will specifically be using a (number of) unipi neuron modules, as controllers, which are essentially a raspberry pi with added hardware to interface with I/O at 24V (pretty much the standard for wired home automation).
See the figure for the involved hardware.
The CPU on the figure is effectively a raspberry pi, which can run raspbian (or HASS OS); the ARM processors are slave devices that can be read through SPI. The I/O values can be read from the CPU device via modbus RTU or modbus TCP via their unipi Neuron modbus TCP overlay
Anyway, my question isn’t really unipi-specific – it involves any device that exposes I/O over modbus TCP, most notably PLC-like devices.
I already found out that the existing home assistant modbus integration is able to directly poll the modbus TCP server with minimum configuration, based on the pymodbus library for this. I actually made a forum post about this at the unipi community. As it’s a master / slave setup based on SPI, there’s no real other way than polling the slave device (reading through some docs, SPI does support an interrupt-mode, but I would probably not even know how start here ). The response time in home assistant does however seem quite slow for my setup (e.g. toggling light switches). I also fear that it will not scale that well when adding more inputs as this would mean just more polling as it seems the current implementation tries to poll for each I/O individually.
I did some experiments yesterday with the pymodus library on the unipi to figure out the bottlenecks in the setup; doing continuous polling on the modbus TCP server revealed it pretty much directly exposes the changed input state (so the obvious delay is at the side of home assistant). Given that the protocol itself did turn out to not be that complex, I am thinking of cooking up a more optimized way of polling the modbus TCP server.
Ideas for speedup
Asyncio: reading through the developer docs, it seems pretty much all of the core of home assistant shifted its behavior to use asyncio. Given that the pymodbus library does not have this behavior, I could try building an async version of it. Home assistant would still need to poll it though, but at least, it would not be blocking anymore.
Reading multiple inputs at once: home assistant seems to treat input individually, leading me to believe that each of them are polled separately – whereas the modbus protocol itself allows for multiple values to be read at the same time (!). I am not sure what would be the best way to integrate this into home assistant again though, as I think the binary_sensor / switch (component) abstractions are great.
Translate to MQTT first: I could also just write a separate abstraction layer that would do the polling and then push out (e.g. MQTT) events in case it detects a change. I would not be a big fan of this though, as it would just add another layer in between.
My own evaluation at this point: create an async modbus TCP client, check its performance and see whether polling multiple inputs is still a requirement then.
My question really is how big of speedup I should expect from asyncio part; whether it’s really worth investing time.
Additionally, any other suggestions / ideas / … are also welcome!