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