The previous page shows the somewhat inconsistent output from these rotary encoders, here I’ll show how I dealt with this and add associated counters to enumerate the switch being operated.
Firstly these switches appear to be capable of producing very weird results – at their detent position the switch contacts should be both open, and thus the signal lines are pulled high by virtue of the internal 100KΩ pull-up enabled in the GPIO chip but in practice I’ve seen either one or both at logical level ‘0’.
So given that the initial state of the switches cannot be guaranteed we need to store their current state in a variable and compare that to any new values read and so be able to accurately interpret the new values. The final line in the ISR updates that variable with the new values ready for the next cycle of changes.
With regard enumerating the switch numbers I am assuming that we can determine them from the bit position given that (by choice) the switch a/b/ lines will match the GPIO port numbers such as –
The code below shows how to enumerate the switch number and provide an indication of the direction of travel –
The observant will have noticed that I have used a global variable ‘Saved’ to store the lastest GPIO values, I know this is frowned upon by some as being non-pythonic however AFAIKT the only way to pass additional arguments to the GPIO library function (and thereby obviate the need for a global) is to use a lambda function, and to my mind that’s just plain horrible!
As we shall see later, if we re-write this as a python class to make it simpler to launch multiple instances the problem goes way!
So now the function outputs a value per switch detent and a ± to indicate direction. To illustrate where the code is detecting this lets add some a print statement to display the binary reads too.
Note: Each line represents rotating the switch one detent at a time and I moved the rotary switch to GPIO pins GPB6-7 just to illustrate that the switch enumeration code works!
So now we have the rudiments of a method to reliably read the rotary encoders, now lets focus on how to use the outputs to control the pulse width and hence brightness of our LED’s.
Given that we don’t want to perform any more complex code within our ISR (so that it is fast) we need to somehow communicate the outputs to another program.
We could from bare-bones use a Unix socket to do this, however there are frameworks around that can simplify this task, i.e. messaging systems and there many to choose from but the most obvious ones to look at are MQTT and ZMQ.
I chose the latter since I couldn’t see the need and complexity of deploying a broker, and I liked the fact that ZMQ supports multiple transport layer choices – e.g. inter-process communication -IPC and is also very flexible as to whether publisher or subscriber either bind or listen. – E.g. by binding the listener to a known port/address multiple ‘clients’ could send commands to control lights- e.g. mobile phones, IoT devices etc.
I’ll not dwell on the s/w configuration options that are available- these are well documented online here. but given the simplicity of the task at hand setting this up is a trivial task
The ZMQ library is easily installed via Pip – ‘pip3 install zmq’
Here is the code to transmit via ZMQ, and all we need to do in our previous example is add the initialisation code and replace the print statement with a ‘socket.send…’