This tutorial was put together with the help of Claude (Anthropic’s AI); the commands were tested successfully on my own JP2601, but I make no guarantees for other setups — follow at your own risk, and always double-check what a command does before running it as root.
Tested on the JP2601, recent Sailfish OS build. Uses sf-button-monitor to toggle the flashlight with a double-press of Volume Down while the screen is locked.
Note: this is a double-press, not a true long-press — the tool detects button sequences, not hold duration.
Requirements
-
Developer mode + SSH, or root over local terminal
-
perlanddbus-send(present by default)
1. Get and install the script
git clone https://github.com/teleshoes/sf-button-monitor
cd sf-button-monitor
cp src/sf-button-monitor /usr/local/bin/
chmod +x /usr/local/bin/sf-button-monitor
(Ignore install.sh, it uses sudo which doesn’t exist on Sailfish.)
2. Add JP2601 to the device table
The script picks input devices from a hardcoded table keyed on ssu mo output, and JP2601 isn’t in it by default. Edit the script:
nano src/sf-button-monitor
Add this line inside the $INPUT_DEVICES_BY_MODEL_NAME block:
perl
jp2601 => ['/dev/input/event0', '/dev/input/event2'],
(On JP2601: Volume Down = event0, Volume Up = event2.)
Reinstall:
cp src/sf-button-monitor /usr/local/bin/sf-button-monitor
3. Config file
Find your defaultuser UID (should be 100000 on stock setups — confirm with id defaultuser):
mkdir -p /root/.config
nano /root/.config/sf-button-monitor.conf
action=cmd(env DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/100000/dbus/user_bus_socket dbus-send --print-reply --dest=org.sailfish.flashlight.provider /org/sailfish/flashlight/provider org.sailfish.flashlight.provider.toggleFlashlight),vd vd,screenLocked
If you prefer Volume + button :
action=cmd(env DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/100000/dbus/user_bus_socket dbus-send --print-reply --dest=org.sailfish.flashlight.provider /org/sailfish/flashlight/provider org.sailfish.flashlight.provider.toggleFlashlight),vu vu,screenLocked
On JP2601, the flashlight D-Bus service is org.sailfish.flashlight.provider (not the older com.jolla.settings.system.flashlight some guides reference) — this is on defaultuser’s session bus, hence the explicit DBUS_SESSION_BUS_ADDRESS.
Quick test in foreground:
sf-button-monitor
Lock the screen, double-press Volume Down, confirm the flashlight toggles, Ctrl+C.
4. systemd service
nano /etc/systemd/system/sf-button-monitor.service
ini
[Unit]
Description=Sailfish Button Monitor (volume/camera hardware button actions)
After=user@100000.service
Wants=user@100000.service
[Service]
Type=simple
Environment=HOME=/root
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/100000/dbus/user_bus_socket
ExecStartPre=/bin/sh -c 'while [ ! -S /run/user/100000/dbus/user_bus_socket ]; do sleep 1; done'
ExecStart=/usr/local/bin/sf-button-monitor
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now sf-button-monitor.service
Two things this fixes that will otherwise break it silently on JP2601:
-
$HOMEisn’t set under systemd, so the script can’t find its own config and falls back to a broken default — henceEnvironment=HOME=/root. -
On boot, the service can start before
defaultuser’s session D-Bus socket exists, breaking the internal MPRIS listener — hence theExecStartPrewait loop.
Reboot and test without launching anything manually:
reboot
Lock screen, double-press Volume Down. Should just work.
Debugging
journalctl -u sf-button-monitor.service -f
watch this while testing if something’s off.