"In het verleden behaalde resultaten bieden geen garanties voor de toekomst"

These are the ramblings of Matthijs Kooijman, concerning the software he hacks on, hobbies he has and occasionally his personal life.

Questions? Praise? Blame? Feel free to contact me.

My old blog (pre-2006) is also still available.

Sun Mon Tue Wed Thu Fri Sat
4

Tag Cloud
&
(With plugins: config, extensionless, hide, tagging, Markdown, macros, breadcrumbs, calendar, directorybrowse, entries_index, feedback, flavourdir, include, interpolate_fancy, listplugins, menu, pagetype, preview, seemore, storynum, storytitle, writeback_recent, moreentries)
Valid XHTML 1.0 Strict & CSS
Repurposing the "Ecobutton" to skip spotify songs using Linux udev/hwdb key remapping

When sorting out some stuff today I came across an "Ecobutton". When you attach it through USB to your computer and press the button, your computer goes to sleep (at least that is the intention).

The idea is that it makes things more sustainable because you can more easily put your computer to sleep when you walk away from it. As this tweakers poster (Dutch) eloquently argues, having more plastic and electronics produced in China, shipped to Europe and sold here for €18 or so probably does not have a net positive effect on the environment or your wallet, but well, given this button found its way to me, I might as well see if I can make it do something useful.

I had previously started a project to make a "Next" button for spotify that you could carry around and would (wirelessly - with an ESP8266 inside) skip to the next song using the Spotify API whenever you pressed it. I had a basic prototype working, but then the project got stalled on figuring out an enclosure and finding sufficiently low-power addressable RGB LEDs (documentation about this is lacking, so I resorted to testing two dozen different types of LEDs and creating a website to collect specs and test results for adressable LEDs, which then ended up with the big collection of other Yak-shaving projects waiting for this magical moment where I suddenly have a lot of free time).

In any case, it seemed interesting to see if this Ecobutton could be used as poor-man's spotify next button. Not super useful, but at least now I can keep the button around knowing I can actually use it for something in the future. I also produced some useful (and not readily available) documentation about remapping keys with hwdb in the process, so it was at least not a complete waste of time... Anyway, into the technical details...

How does it work?

I expected this to be an USB device that advertises itself as a keyboard, and then whenever you press the button, sends the "sleep" key to put the computer to sleep.

Turns out the first part was correct, but instead of sending a sleep keypress, it sends Meta-R, ecobutton (it types each of these letters after each other), enter. Seems you need to install a tool on your pc that is executed by using the windows-key+R shortcut. Pragmatic, but quite ugly, especially given a sleep key exists... But maybe Windows does not implement the key (or maybe this tool also changes some settings for deeper sleep, at least that's what was suggested in the tweakers post linked above).

Replacing the firmware?

I considered I could maybe replace the firmware to make the device send whatever keystroke I wanted, but writing firmware from scratch for existing hardware is not the easiest project (even for a simple device like this). After opening the device I decided this was not a feasible route.

The (I presume) microcontroller in there is hidden in a blob, so no indication as to its type, pin connections, programming ports (if it actually has flash and is not ROM only).

I did notice some solder jumpers that I figured could influence behavior (maybe the same PCB is used for differently branded buttons), but shorting S1 or S5 did not seem to change behavior (maybe I should have unsoldered S3, but well...).

Remap keys, then?

The next alternative is to remap keys on the computer. Running Linux, this should certainly be possible in a couple of dozen ways. This does need to be device-specific remapping, so my normal keyboard still works as normal, but if I can unmap all keys except for the meta key that it presses first, and map that to someting like the KEY_NEXTSONG (which is handled by spotify and/or Gnome already), that might work.

I first saw some remapping solutions for X, but those probably will not work - I'm running wayland and I prefer something more low-level. I also found cool remapping daemons (like keyd) that grab events from a keyboard and then synthesise new events on a virtual keyboard, allowing cool things like multiple layers or tapping shift and then another key to get uppercase instead of having to hold shift and the key together, but that is way more complicated than what I need here.

Then I found that udev has a thing called "hwdb", which allows putting files in /etc/udev/hwdb.d that match specific input devices and can specify arbitrary scancode-to-keycode mappings for them. Exactly what I needed - works out of the box, just drop a file into /etc.

Understanding and taming udev and hwdb

The challenge turned out to be to figure out how to match against my specific keyboard identifier, what scancodes and keycodes to use, and in general figure out how the ecosystem around this works (In short: when plugging in a device, udev rules consults the hwdb for extra device properties, which a udev builtin keyboard command then uses to apply key remappings in the kernel using an ioctl on the /dev/input/eventxx device). In case you're wondering - this means you do not need to use hwdb, you can also apply this from udev rules directly, but then you need a bit more care.

I've written down everything I figured about hwdb in a post on Unix stackexchange, so I'l not repeat everything here.

Using what I had learnt, getting the button to play nice was a matter of creating /etc/udev/hwdb.d/99-ecobutton.hwdb containing:

evdev:input:b????v3412p7856e*
KEYBOARD_KEY_700e3=nextsong # LEFTMETA
KEYBOARD_KEY_70015=reserved # R
KEYBOARD_KEY_70008=reserved # E
KEYBOARD_KEY_70006=reserved # C
KEYBOARD_KEY_70012=reserved # O
KEYBOARD_KEY_70005=reserved # B
KEYBOARD_KEY_70018=reserved # U
KEYBOARD_KEY_70017=reserved # T
KEYBOARD_KEY_70011=reserved # N
KEYBOARD_KEY_70028=reserved # ENTER


This matches the keyboard based on its usb vendor and product id (3412:7856) and then disables all keys that are used by the button, except for the first, and remaps that to KEY_NEXTSONG.

To apply this new file, run sudo systemd-hwdb update to recompile the database and then replug the button to apply it (you can also re-apply with udevadm trigger, but it seems then Gnome does not pick up the change, I suspect because the gnome-settings media-keys module checks only once whether a keyboard supports media keys at all and ignores it otherwise).

With that done, it now produces KEY_NEXTSONG events as expected:

\$ sudo evtest --grab /dev/input/by-id/usb-3412_7856-event-if00
Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x3412 product 0x7856 version 0x100
Input device name: "HID 3412:7856"

[ ... Snip more output ...]

Event: time 1675514344.256255, type 4 (EV_MSC), code 4 (MSC_SCAN), value 700e3
Event: time 1675514344.256255, type 1 (EV_KEY), code 163 (KEY_NEXTSONG), value 1
Event: time 1675514344.256255, -------------- SYN_REPORT ------------
Event: time 1675514344.264251, type 4 (EV_MSC), code 4 (MSC_SCAN), value 700e3
Event: time 1675514344.264251, type 1 (EV_KEY), code 163 (KEY_NEXTSONG), value 0
Event: time 1675514344.264251, -------------- SYN_REPORT ------------


More importantly, I can now skip annoying songs (or duplicate songs - spotify really messes this up) with a quick butttonpress!