I have designed and built a hardware controller which connects to the Raspberry Pi via I2C (2 wires), interrupt (1 wire) and power (2 wires). It provides up to 30 rotary encoders, 50 switches and 64 potentiometer inputs. (Can be simplified to provide 8 potentiometer inputs.) The interrupt signal asserts when there are unread value changes. Rotary encoders provide relative offset from previous read and scaled rotation increments, i.e. rotate fast to increment in larger steps. There are some snags to resolve (particularly around the potentiometer multiplexing) but it seems to work quite well. It uses a STM32F103 microcontroller (actually a Maple Mini but could be adapted to Blue Pill or similar).
I have written a zyncoder library to interface with the I2C HWC and changes to incorporate with the Zynthian web configuration. (Pull requests pending…) There is an occasional issue with one of the buttons that I need to resolve (could be construction or possibly GPI conflict) but it is working quite well providing the four rotary encoder and push switches required for Zynthian.
The I2C HWC off loads processing from the Raspberry Pi, doing all the scanning and measuring. The RPi just needs to monitor for a single interrupt signal then read which controller has changed and what its new value is. The interrupt line remains asserted until all value changes have been read.
Currently the quantity of each type of controller may be limited at compile time but I have a task to add a feature to configure the device via I2C messaging. The GitHub project code is mostly complete but the schematics and PCB are still being worked on.