How to control odio with a remote control
A remote can drive the node directly, with no application or browser in between: a key press becomes play/pause, next, volume or mute on the active player and the default output. The odio API reads the remote itself, through its input backend.
What works
Section titled “What works”| Remote | How it is picked up |
|---|---|
Infrared receiver (gpio-ir, MCE USB receiver) | Automatically |
| TV remote over HDMI-CEC | With input.cec, which the odio installer turns on |
GPIO buttons (gpio-keys) | Automatically |
| Bluetooth or USB remote | By name |
Media keys need no configuration: play/pause, play, pause, stop, next, previous, fast forward, rewind, volume up, volume down and mute. Any other key can be bound to an action.
Enable it
Section titled “Enable it”On a headless odio node, remote controls are enabled by default: there is nothing to do. The installer also puts the odio user in the input group, which reading a remote requires.
On a node with a graphical desktop they are off. Enable them in a drop-in, for example ~/.config/odio-api/conf.d/50-input.yml:
input: enabled: true cec: true # only for the TV remote over HDMI-CECthen restart the API:
systemctl --user restart odio-apiThe same drop-in with enabled: false turns them off on a headless node, and cec: false alone leaves the HDMI-CEC adapter out. For a standalone go-odio-api, see the system setup.
Infrared receivers and GPIO buttons are handled from there. HDMI-CEC has its own switch, cec, because a Raspberry Pi always has the adapter, listed as vc4-hdmi, whether a TV is plugged in or not. With it on, a TV that forwards its remote keys over CEC can drive odio.
Check the devices
Section titled “Check the devices”GET /input lists what is handled:
curl http://localhost:8018/input{ "devices": [ { "path": "/dev/input/event0", "name": "vc4-hdmi", "kind": "cec", "state": "active" } ], "bindings": [ { "key": "KEY_MUTE", "action": "volume.mute" }, { "key": "KEY_PLAYPAUSE", "action": "player.playpause" } ]}A device in state active is being read. denied means the user running the API cannot read the device, see the system setup. A remote that is not listed at all is not picked up automatically, and has to be added by name.
Add a Bluetooth or USB remote
Section titled “Add a Bluetooth or USB remote”These remotes look like any keyboard to the system, so odio only handles the ones you name. Find the name with the remote plugged in or connected:
grep -H . /sys/class/input/event*/device/name/sys/class/input/event0/device/name:vc4-hdmi/sys/class/input/event2/device/name:Logitech K400Add it to the drop-in, then restart the API:
input: enabled: true devices: - "Logitech K400"The whole name must match, case aside. Some remotes show up as several devices, for instance one for the regular keys and a Consumer Control one for the media keys: list each one you need.
A remote that is unplugged, or a Bluetooth remote that goes to sleep, is picked up again when it comes back, without a restart.
Bind other keys
Section titled “Bind other keys”To find what a key is called, set logLevel: debug in the drop-in, restart the API and follow its log while pressing the key:
journalctl --user -u odio-api -f[input] unmapped KEY_RED (gpio_ir_recv)Then bind it:
input: enabled: true bindings: - { key: KEY_POWER, action: power.poweroff } - { key: KEY_RED, action: service.restart, unit: mpd.service } - { key: KEY_MUTE, action: none }none unmaps a default key. A service.* action needs a unit from the systemd whitelist, power.* needs the power backend enabled, and bluetooth.* the Bluetooth backend. The full list of actions is in the input reference.
Set logLevel back to info once the keys are found.
Wiring to the GPIO header
Section titled “Wiring to the GPIO header”On a Raspberry Pi, an infrared receiver or push buttons wired to the GPIO header need an overlay in /boot/firmware/config.txt, one line each, then a reboot. odio-api picks them up from there, nothing else to configure.
Pins are given in BCM numbering, and always given: the overlays’ own defaults collide with a DAC. With an I2S audio HAT, keep clear of GPIO 2 and 3 (I2C) and GPIO 18 to 21 (I2S), which leaves:
4 5 6 7 8 9 10 11 12 13 14 15 16 17 22 23 24 25 26 27Infrared receiver
Section titled “Infrared receiver”The gpio-ir overlay, with the pin after gpio_pin:
dtoverlay=gpio-ir,gpio_pin=25Its default pin, GPIO 18, is the bit clock of an I2S DAC.
The kernel decodes infrared itself, and needs the keymap of your remote loaded to turn its codes into key names. ir-keytable lists the receiver, loads a keymap and, with -t, shows the keys as they are received. Without the right keymap, the receiver is handled but its key presses produce nothing.
Push buttons
Section titled “Push buttons”The gpio-key overlay, once per button, with its pin after gpio and the key it sends after keycode:
dtoverlay=gpio-key,gpio=17,keycode=164dtoverlay=gpio-key,gpio=27,keycode=163dtoverlay=gpio-key,gpio=22,keycode=115,autorepeatdtoverlay=gpio-key,gpio=23,keycode=114,autorepeatWire each button between its pin and ground: the overlay turns the pin’s pull-up on and reads a press as the pin going low. autorepeat lets a held button repeat, which odio acts on for volume, fast forward and rewind.
The key codes are the kernel’s input event codes, as numbers. The media keys odio handles by default:
| Code | Key |
|---|---|
| 164 | Play/pause |
| 207 | Play |
| 119 | Pause |
| 166 | Stop |
| 163 | Next |
| 165 | Previous |
| 208 | Fast forward |
| 168 | Rewind |
| 115 | Volume up |
| 114 | Volume down |
| 113 | Mute |
Any other code can be bound to an action. Always give both parameters: the overlay defaults to GPIO 3, an I2C pin, and to code 116, the power key.