Reliable rotary encoder (100%) using dtoverlay and python-evdev?

  • I am trying to find a solution for a 100% reliable rotary encoder interface to control KODI running under LibreElec. My code (see below add-on.py code) is run as a simple add-on.

    As the interface for my switches I used GPIO and later changed this to GPIOZERO in which I read the state of a select button and rotary encoder to navigate through the menu. The rotary encoder code sometimes gives a wrong direction (UP or DOWN) and the button sometimes gives a double SELECT. I have debounced all keys with external R-C filters and checked with my oscilloscope the quality of the signal which is stable. It seems to me that the overall timing and interrupt latency cannot be guaranteed maybe because of some higher (interrupt or process) priorities. I was looking into a alternative solution by using a rotary-encoder dtoverlay, which seems to be available as a standard part of LibreElec, but I do not have any experience on this yet. Examples on the Internet use dtoverlay in combination with python-evdev, but I am not sure if this is supported by LibreElec. Is there anyone who has experience with this on LibreElec?

    As yet I do not believe I will find a good solution under LibreElec with my limited system and software knowledge. But I want to solve this problem and so I will also continue exploring external hardware implementations, in which the rotation direction is determined by means of a schmitt trigger and D-flip flop to identify the rotation direction; thereby making it less dependant on SW response and SW timing.

    However should anyone of you have good experiences with a 100% reliable rotary encoder implementation in SW under LibreElec, then I look forward to your recommendations.

    #!/usr/bin/python

    #coding: utf8

    import sys

    import xbmcaddon

    import xbmcgui

    sys.path.append('/storage/.kodi/addons/virtual.rpi-tools/lib')

    from gpiozero import LED

    from gpiozero import Button

    from signal import pause

    from time import sleep

    addon = xbmcaddon.Addon()

    addonname = addon.getAddonInfo('name')

    blue = LED(27)

    btn = Button(17)

    pin_a = Button(23,pull_up=True) # Rotary encoder pin A connected to GPIO23

    pin_b = Button(24,pull_up=True) # Rotary encoder pin B connected to GPIO24

    def pin_a_rising(): # Pin A event handler

    if pin_b.is_pressed:

    xbmc.executebuiltin('Action(Up)')

    def pin_b_rising(): # Pin B event handler

    if pin_a.is_pressed:

    xbmc.executebuiltin('Action(Down)')

    Button.was_held = False

    Button.hold_time = 0.5

    def held(btn):

    Button.was_held = True

    xbmc.executebuiltin('Action(ParentDir)') # Select was held for a long time

    def released(btn):

    if not Button.was_held:

    pressed()

    Button.was_held = False

    def pressed():

    xbmc.executebuiltin('Action(Select)') # Select was pressed shortly


    while True:

    btn.when_held = held

    btn.when_released = released

    pin_a.when_pressed = pin_a_rising # Register the event handler for pin A

    pin_b.when_pressed = pin_b_rising # Register the event handler for pin B

    Edited 2 times, last by RebornLoophole (December 27, 2019 at 11:09 AM).

  • Hi,

    just saw this. I do not have a 100% reliable solution, but maybe some enhancements:

    1) You can use "bounce_time" on our btn, which will do software debouncing.

    2) I tried around with that topic for some time and ended up using a queue in which the events are written to and read again.

    Check out my code below, I am trying to do basically the same stuff (with added horiztontal scrolling). Also take a look at the while loop - the way it is done it will close down properly and not hang on shutdown or so.

  • adarmalik,

    I know this is an old thread, but I want to thank you for this add-on. I have a question, and I ask it here for the benefit of anyone else who is interested in adding a rotary encoder to a LibreELEC installation.

    I find that with each pulse out of the encoder the sound seems to mute before it resumes at the new level. Is this expected behavior? Is there a fix for this? I probably can live with this for my own use, but others may find this objectionable.

    edit: I fixed it. Again, for the benefit of anyone else: I'm using a HiFiBerry Amp2, and the use of GPIO 4 will result in the symptom I described above, since that pin will mute the power stage when pulled low. The solution was to use GPIO 14 instead. The addon works beautifully.

    tobor

    Edited once, last by tobor: new info (March 22, 2022 at 10:40 PM).