Skip to content

Configuration

The odio installer generates ~/.config/odio-api/config.yaml automatically. The configuration shown below documents all available options — you only need to edit the file if you want to customize the defaults.

For standalone installations, the config file can also be specified with --config <path>.

bind: lo
logLevel: info
api:
enabled: true
port: 8018
ui:
enabled: true
cors:
origins: ["https://pwa.odio.love", "https://odio-pwa.vercel.app"]

api.cors.origins lists the origins allowed to call the API from a browser. The defaults cover the hosted odio application; add your own origin here if you self-host it on a different address.

bind controls which network interfaces the API listens on.

bind: lo # loopback only (default)
# bind: enp2s0 # single LAN interface
# bind: [lo, enp2s0] # loopback + LAN
# bind: [lo, enp2s0, wlan0] # loopback + ethernet + wifi
# bind: all # all interfaces (Docker, remote access)

Each backend can be enabled or disabled independently. Disabling a backend removes all its routes from the API.

See Systemd for endpoint details.

systemd:
enabled: true
timeout: 90s
system:
- bluetooth.service
user:
- mpd.service
- shairport-sync.service
- snapclient.service
- spotifyd.service
- upmpdcli.service

See Bluetooth for endpoint details.

bluetooth:
enabled: true
timeout: 5s
pairingTimeout: 60s
idleTimeout: 30m

Since odio doesn’t run as root, a few system configuration steps are required.

The user running odio must belong to the bluetooth group:

Terminal window
sudo usermod -a -G bluetooth <username>

PulseAudio or PipeWire must be configured to handle Bluetooth audio:

Terminal window
# PulseAudio
sudo apt install pulseaudio-module-bluetooth
# PipeWire
sudo apt install libspa-0.2-bluetooth

Edit /etc/bluetooth/main.conf to identify the node as an audio receiver:

[General]
Name = odio
Class = 0x240428
[Policy]
AutoEnable=false

Class of Device (0x240428) breakdown:

  • 0x24 — Major Device Class: Audio/Video
  • 0x0428 — Minor + services: Audio Sink, Loudspeaker, Rendering device

This makes the node appear as a standard Bluetooth speaker. Phones and computers will show a headphone icon and route media audio to it.

AutoEnable=false keeps the adapter off at boot — power is managed by the API (or Home Assistant).

After modifying the configuration, restart the Bluetooth service:

Terminal window
sudo systemctl restart bluetooth

BlueZ provides mpris-proxy, a systemd user service that creates an MPRIS player for each connected Bluetooth device. This is what allows the odio API to discover and control Bluetooth playback alongside all other sources.

Terminal window
systemctl --user status mpris-proxy.service

See Power for endpoint details.

power:
enabled: true
capabilities:
poweroff: true
reboot: true

On headless systems, logind requires a polkit rule to allow the odio user to reboot and power off without a graphical session:

/etc/polkit-1/rules.d/10-allow-shutdown.rules
polkit.addRule(function(action, subject) {
if ((action.id == "org.freedesktop.login1.power-off" ||
action.id == "org.freedesktop.login1.power-off-multiple-sessions" ||
action.id == "org.freedesktop.login1.reboot" ||
action.id == "org.freedesktop.login1.reboot-multiple-sessions") &&
subject.user == "odio") {
return polkit.Result.YES;
}
});

On desktop systems with a graphical session, this rule is not needed — logind already grants these permissions.

See Zeroconf for details. Requires bind to be set to a real network interface.

bind: enp2s0
zeroconf:
enabled: true