Tastaturblock LogiLink ID0120 einfach auslesen

Ausgangssituation

Im Projekt Raspi-Ansteuerung Bose Soundbar (Link folgt) werden die einzelnen Webradiosender über jeweils einen separaten Taster umgeschaltet bzw. der Webradioempfang komplett ausgeschaltet. So man zwei Lieblingssender hat, kommt man mit drei Tastern incl. dem für das Ausschalten aus. Diese können im Raspberry-Gehäuse direkt integriert werden. Sollen jedoch mehrere Sender ausgewählt werden, empfiehlt sich u. a. der Tastaturblock LogiLink ID0120 (Abbildung 1) für die Umsetzung.

Abbildung1-Tastaturblock-LogiLink ID0120
Abbildung 1: Tastaturblock LogiLink ID0120

Der Block verfügt über 18 Tasten, die in einem Proof of Concept beispielhaft LEDs ansteuern sollen. Der ID120 ist kabellos und wird mit einem 2,4-GHz-Receiver an einer USB-Schnittstelle angeschlossen, Stand 07/2026 ist er z. B. bei Conrad für 9,24 € zu bestellen. Wird das Gerät in einem Terminal abgefragt, antwortet es als Wireless Keyboard/Mouse.

lsusb

   Bus 001 Device 003: ID 062a:4101 MosArt Semiconductor Corp. Wireless Keyboard Mouse

Da der Ziffernblock als USB-Tastatur (HID-Gerät) erkannt wird, sendet er beim Drücken oder Loslassen einer Taste jeweils einen standardisierten Key Code an das Betriebssystem. Im ersten Schritt ist es damit notwendig, diese Key Codes auszulesen, hierfür wird ein Raspberry Pi 3B mit einem Python-Script genutzt. Eine kurze Recherche im Netz empfiehlt für die Umsetzung dieses Vorhabens die Python-Bibliothek evdev.

Installation der Python-Bibliothek evdev

Die Python-Bibliothek evdev bietet Schnittstellen zum Linux-Eingabeereignis-Subsystem. Es ist der direkte Zugriff auf Eingabegeräte möglich, also auch auf den hier genutzten Ziffernblock, die sich unter /dev/input befinden. Von Interesse ist das Auslesen von Kernel-Ereignissen, sprich dem Drücken und Loslassen von Tasten. Möglich ist auch das Blockieren (grab) von Geräten, sodass die Ereignisse nicht an den Kernel weitergeleitet werden, sondern im aufrufenden Script auflaufen und hier verarbeitet werden. [PED]
Zunächst wird die Python-Bibliothek installiert, zum Aktivieren ist das System einmal durchzustarten:

sudo apt install -y python3-evdev
sudo reboot

Mit dem nachfolgenden Python-Einzeiler werden alle angeschlossenen USB-Geräte auf dem Linuxsystem ausgelesen. Neben dem Ziffernblock sind aktuell keine weiteren Mäuse oder Tastaturen angeschlossen:

sudo python3 -c "import evdev; [print(f'{d.path}: {d.name}') \
   for d in [evdev.InputDevice(p) for p in evdev.list_devices()]]"

   /dev/input/event4: MOSART Semi. 2.4G Keyboard Mouse
   /dev/input/event3: MOSART Semi. 2.4G Keyboard Mouse System Control
   /dev/input/event2: MOSART Semi. 2.4G Keyboard Mouse Consumer Control
   /dev/input/event1: MOSART Semi. 2.4G Keyboard Mouse
   /dev/input/event0: MOSART Semi. 2.4G Keyboard Mouse

Linux-Systemtool evtest

Neben der Python-Bibliothek evdev gibt es das Linux-Systemtool evtest, das ebenfalls angeschlossene USB-Geräte erfassen kann. Mit evtest ist es dann auch in einem Zug möglich, die Key Codes des Ziffernblocks auszulesen und zu erfassen.

Nach dem Eingeben des Kommandos werden selbst für den einen Ziffernblock fünf Geräte angezeigt, das relevante Gerät ist i. d. R. das Gerät mit der kleinsten Nummer, hier /dev/input/event0. Dies ist auch im Terminal daran zu erkennen, dass nur hier mögliche Key Codes angezeigt werden.

Noch eine Kleinigkeit für einen komfortableren Zugriff, diesen aber nur in sicheren Umgebungen anwenden: Damit ein Non-root-Benutzer (bei mir der Benutzer installer) auf die Eingabegeräte zugreifen kann, ist er der Gruppe input hinzuzufügen, damit müssen Kommandos nicht mehr mit sudo aufgerufen werden. Der Benutzer muss sich zum Aktivieren aber einmal neu anmelden.

sudo apt update && sudo apt install evtest -y
sudo usermod -aG input $USER

evtest

   No device specified, trying to scan all of /dev/input/event*
   Available devices:
   /dev/input/event0: MOSART Semi. 2.4G Keyboard Mouse
   /dev/input/event1: MOSART Semi. 2.4G Keyboard Mouse
   /dev/input/event2: MOSART Semi. 2.4G Keyboard Mouse Consumer Control
   /dev/input/event3: MOSART Semi. 2.4G Keyboard Mouse System Control
   /dev/input/event4: MOSART Semi. 2.4G Keyboard Mouse
   Select the device event number [0-4]: 0

   ...
   Input device name: "MOSART Semi. 2.4G Keyboard Mouse"
   Supported events:
     Event type 0 (EV_SYN)
     Event type 1 (EV_KEY)
      Event code 1 (KEY_ESC)
      Event code 2 (KEY_1)
      Event code 3 (KEY_2)
      ...
   Properties:
   Testing ... (interrupt to exit) --> <z.B. Betätigen der Taste 1>

   Event: time 1783774059.581544, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70059
   Event: time 1783774059.581544, type 1 (EV_KEY), code 79 (KEY_KP1), value 1
   Event: time 1783774059.581544, -------------- SYN_REPORT ------------
   Event: time 1783774059.663554, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70059
   Event: time 1783774059.663554, type 1 (EV_KEY), code 79 (KEY_KP1), value 0
   Event: time 1783774059.663554, -------------- SYN_REPORT ------------

Jeweils drei Zeilen liefern die Informationen für ein Event, also das Drücken oder das Loslassen einer Taste. Beim Drücken der Taste 1 wird der Key Code 79 mit value 1 geliefert. Die zweiten drei Zeilen stehen für das Loslassen der Taste 1 und liefern ebenfalls den Key Code 79, aber mit value 0. Das Script im Abschnitt Python-Script zum Auslesen von ID0120 liest die Key Codes etwas komfortabler aus.

Python-Script zum Auslesen von Tastaturblock LogiLink

In meiner Umgebung verwende ich den Non-root-Benutzer installer, in seinem Home-Verzeichnis werden alle Scripte im Unterordner id0120 gespeichert. Die Shebang-Zeile #!/usr/bin/python3 in Zusammenhang mit den Rechten 755 auf das Script ermöglicht es, dass das Python-Script direkt aufgerufen werden kann.

cat /home/installer/id0120/check-id0120-poc#01.py

   #!/usr/bin/python3
   from evdev import InputDevice, categorize, ecodes
   # eintragen des ermittelten device-pfads
   dev_path = '/dev/input/event0'

   try:
       device = InputDevice(dev_path)
       # exklusiver zugriff, damit eingaben nicht im terminal landen
       device.grab()

       print(f"Erfolgreich verbunden mit: {device.name}")
       print("Taste auf dem Ziffernblock druecken (Strg+C zum Beenden)...")

       for event in device.read_loop():
           if event.type == ecodes.EV_KEY:
               key_event = categorize(event)
               # nur auf das druecken der taste reagieren (keystate 1)
               if key_event.keystate == 1:
                   print(f"Taste: {key_event.keycode} | Code: {key_event.scancode}")

   except KeyboardInterrupt:
       print("\nProgramm beendet.")
   finally:
       # Gibt das Gerät beim Beenden wieder für das System frei
       try:
           device.ungrab()
       except:
           pass

chmod 755 /home/installer/id0120/check-id0120-poc#01.py

Das nächste Listing zeigt alle 18 ausgelesenen Key Codes des Ziffernblocks an:

/home/installer/id0120/check-id0120-poc#01.py

   Erfolgreich verbunden mit: MOSART Semi. 2.4G Keyboard Mouse
   Taste auf dem Ziffernblock druecken (Strg+C zum Beenden)...
   Taste: KEY_KP0 | Code: 82
   Taste: KEY_KP1 | Code: 79
   Taste: KEY_KP2 | Code: 80
   Taste: KEY_KP3 | Code: 81
   Taste: KEY_KP4 | Code: 75
   Taste: KEY_KP5 | Code: 76
   Taste: KEY_KP6 | Code: 77
   Taste: KEY_KP7 | Code: 71
   Taste: KEY_KP8 | Code: 72
   Taste: KEY_KP9 | Code: 73
   Taste: KEY_NUMLOCK | Code: 69
   Taste: KEY_KPSLASH | Code: 98
   Taste: KEY_KPASTERISK | Code: 55
   Taste: KEY_BACKSPACE | Code: 14
   Taste: KEY_KPMINUS | Code: 74
   Taste: KEY_KPPLUS | Code: 78
   Taste: KEY_KPENTER | Code: 96
   ^C
   Programm beendet.

Abfangen weiterer angeschlossener USB-Devices

Im Abschnitt Linux-Systemtool evtest wurde davon ausgegangen, dass kein weiteres USB-Device angeschlossen ist und damit der Ziffernblock als erstes Device mit /dev/input/event0 Key Codes sendet. Bei meinen Tests und der Inbetriebnahme habe ich aber festgestellt, dass diese Annahme nicht immer zutreffend ist, dass Anschließen einer Maus oder Standardtastatur verändert die Eventnummer des Ziffernblocks. Tatsache ist aber, dass die kleinste Eventnummer des Ziffernblocks die Key-Codes sendet. Damit ist es sinnvoll, die statische Codezeile dev_path = '/dev/input/event0' dynamisch auf das erste Event des Namensstrings MOSART Semi. 2.4G Keyboard Mouse (Name des verwendeten Ziffernblocks) anzupassen. Das Python-Script search-device.py dient nur dazu, diese kleinste Eventnummer zu bestimmen, um sie dann im Script aus Abschnitt Python-Script zum Auslesen von ID0120 zum Auslesen einzubauen und zu verwenden.

Die Version des Scripts search-device-kurzfassung.py gibt nur die zwingend notwendigen Kommandos an:

cat /home/installer/id0120/search-device-kurzfassung.py

   #!/usr/bin/python3
   from evdev import InputDevice, list_devices
   usb_devices = [InputDevice(p) for p in list_devices() if "MOSART" in ↱<br>InputDevice(p).name]
   kleinstes_ziffernblock_device = min(usb_devices, key=lambda d: int(d.path.split ("event")[1]))
   print(kleinstes_ziffernblock_device.path)

chmod 755 /home/installer/id0120/search-device-kurzfassung.py

evtest

   ...
   Available devices:
   /dev/input/event0: Telink Wireless Receiver Mouse
   /dev/input/event1: Telink Wireless Receiver Consumer Control
   /dev/input/event10: vc4-hdmi HDMI Jack
   /dev/input/event2: Telink Wireless Receiver System Control
   /dev/input/event3: Telink Wireless Receiver
   /dev/input/event4: MOSART Semi. 2.4G Keyboard Mouse
   /dev/input/event5: MOSART Semi. 2.4G Keyboard Mouse
   /dev/input/event6: MOSART Semi. 2.4G Keyboard Mouse Consumer Control
   /dev/input/event7: MOSART Semi. 2.4G Keyboard Mouse System Control
   /dev/input/event8: MOSART Semi. 2.4G Keyboard Mouse
   /dev/input/event9: vc4-hdmi
   Select the device event number [0-10]: ^C

/home/installer/id0120/search-device-kurzfassung.py

   /dev/input/event4

Die Version search-device.py enthält auch Kommentare:

cat /home/installer/id0120/search-device.py

   #!/usr/bin/python3
   from evdev import InputDevice, list_devices

   # ausgeben aller eingabegeraete mit dem string mosart im namen
   [print(f'{d.path}: {d.name}') for d in [InputDevice(p) for p in list_devices()] if "MOSART" in d.name ]
   # schreiben dieser eingabegerate in ein array
   usb_devices = [InputDevice(p) for p in list_devices() if "MOSART" in InputDevice(p).name]
   # ausgeben des arrays
   print(usb_devices)
   # ausgeben nur der eventpfade
   for d in usb_devices:
       print(d.path)
   # min() greift auf d.path zu, splittet bei 'event' und wandelt den rest in eine zahl um
   kleinstes_ziffernblock_device = min(usb_devices, key=lambda d: int(d.path.split ("event")[1]))
   # gibt das komplette objekt des events aus
   print(kleinstes_ziffernblock_device)
   # gibt nur den pfad des events aus
   print(kleinstes_ziffernblock_device.path)

Das Suchergebnis aus search-device.py wird jetzt in check-id0120-poc#02.py eingebaut, dies ist eine Kopie von check-id0120-poc#01.py. Damit funktioniert jetzt das Auslesen der Key Codes auch, wenn weitere USB-Geräte angeschlossen sind:

cp check-id0120-poc#01.py check-id0120-poc#02.py

Austauschen:
   from evdev import InputDevice, categorize, ecodes

gegen:
   from evdev import InputDevice, categorize, ecodes, list_devices

Austauschen:
   dev_path = '/dev/input/event0'

gegen:
   usb_devices = [InputDevice(p) for p in list_devices() if "MOSART" in InputDevice(p).name]
   kleinstes_ziffernblock_device = min(usb_devices, key=lambda d: int(d.path.split ("event")[1]))
   print(kleinstes_ziffernblock_device.path)
   dev_path = kleinstes_ziffernblock_device.path

Vorbereitung Tastaturblock LogiLink für Webradio-Ansteuerung

Der Ziffernblock soll wie am Anfang des Artikels geschrieben für die erweiterte Senderumschaltung einer Raspberry-Bose-Soundbar-Kombination dienen. An dieser Stelle soll bereits die Zuordnung der Radiostreams der einzelnen Sender zu den Tasten erfolgen, vorgesehen sind auch eine Lautstärkesteuerung (VOL+/VOL-). Hierzu wurde der Ziffernblock entsprechend umgelabelt (Abbildung 2):

Abbildung2-Tastaturblock-LogiLink-ID0120 mit Senderbeschriftungen
Abbildung 2: Tastaturblock LogiLink ID0120 mit Senderbeschriftungen

Die Tasten NumLook, /, *, BackSpace, . und Enter sind noch frei belegbar.

Quellenangaben

[PED] – https://python-evdev.readthedocs.io/en/latest/tutorial.html#getting-currently-active-keys

Schreibe einen Kommentar