14 May 2026

📌 Thursday evening in Gourock. Simone Simons' Vermillion in the headphones - that voice I've known across twelve Epica records, finally on its own, no longer sharing the room with a wall of guitars. On the desk a 2014 LG G Watch, awake, alive, with a night-themed wallpaper I just pushed onto it by hand over adb and a heartbeat icon pulsing as though it hadn't been sitting in a drawer for six months doing nothing.

This watch - codename dory - gave up on me some days ago. The battery wouldn't hold more than an hour, then it stopped powering on at all. Nothing dramatic: it's from 2014, it's twelve years old, and LG stopped treating it as a product something like eight years ago. But it kept showing up in the drawer, and every so often I'd pick it up thinking sooner or later.

Sooner or later turned out to be today. A new battery from an eBay seller with decent feedback, eight quid, a fortnight in the post, half an hour with a suction cup and a spudger. It powers on. It stays on. There's still an old AsteroidOS build on it from years ago that I'd forgotten flashing. Might as well update it.

the flash

AsteroidOS publishes nightly builds for dory. Userdata as an ext4 image, kernel as a zImage-dtb to be written to the boot partition. The routine is the classic one: bootloader, fastboot, two images, continue.

$ adb shell
/ # reboot bootloader

$ fastboot flash userdata ~/Downloads/asteroid-image-dory.rootfs.ext4
Sending sparse 'userdata' 1/3 (252989 KB)          OKAY [  9.445s]
Writing 'userdata'                                 OKAY [ 34.494s]
Sending sparse 'userdata' 2/3 (262140 KB)          OKAY [  9.734s]
Writing 'userdata'                                 OKAY [ 19.316s]
Sending sparse 'userdata' 3/3 (102120 KB)          OKAY [  3.868s]
Writing 'userdata'                                 OKAY [ 82.985s]
Finished. Total time: 159.989s

$ fastboot flash boot ~/Downloads/zImage-dtb-dory.fastboot
Sending 'boot' (19134 KB)                          OKAY [  0.803s]
Writing 'boot'                                     OKAY [  1.417s]
Finished. Total time: 2.257s

$ fastboot continue
Resuming boot                                      OKAY [  0.002s]

The warning about the AVB footer on the userdata image - userdata partition size: 3258974208, userdata image size: 140724244382328 - is cosmetic, it's just how fastboot reads the sparse header. The image is written correctly across three 256 MB chunks. After continue the boot resumes, the AsteroidOS logo comes up, and we're in.

adb shell

The moment I always wait for. Not because I've never done it before - I've flashed AsteroidOS onto this same watch in the past. But it's a moment that keeps giving me satisfaction, every time.

$ adb push /home/jolek78/Pictures/Wallpaper/wallpaper/mystical-night-in-town.jpg \
    /usr/share/asteroid-launcher/wallpapers/
pushed, 0 skipped. 529.1 MB/s (1650164 bytes in 0.003s)

$ adb shell
sh-5.2# cd /usr/share/asteroid-launcher/wallpapers
sh-5.2# ls -lha
total 1.7M
drwxr-xr-x 8 root root 4.0K May 14 19:54 .
drwxr-xr-x 7 root root 4.0K Apr  6  2011 ..
drwxr-xr-x 2 root root 4.0K Apr  6  2011 140
drwxr-xr-x 2 root root 4.0K Apr  6  2011 160
drwxr-xr-x 2 root root 4.0K Apr  6  2011 180
drwxr-xr-x 2 root root 4.0K Apr  6  2011 200
drwxr-xr-x 2 root root 4.0K Apr  6  2011 227
drwxr-xr-x 2 root root 4.0K Apr  6  2011 full
-rw-rw-rw- 1 root root 1.6M Mar 31 19:40 mystical-night-in-town.jpg

sh-5.2# mv mystical-night-in-town.jpg full/

That sh-5.2# prompt is bash on a watch. /usr/share/asteroid-launcher/wallpapers/full is a normal filesystem path, with normal POSIX permissions, where mv does exactly what you'd expect mv to do. There's no Wallpaper Manager app. There's no store. There's no companion app that has to be running on the phone to mediate the operation of moving a file from one directory to another. There's a shell, there's a filesystem, and there's mv.

The numbered subdirectories - 140, 160, 180, 200, 227 - are the launcher's DPI buckets for devices at different resolutions. full/ is the full-resolution fallback. The dory has a 280x280 screen at 224 DPI, so it lands naturally on the 227 bucket, but the launcher will pick from full/ when it finds a suitable image there. It's documented. It's readable. It's a QML launcher doing QDir::entryList() on a known directory.

this is not Android

Everyone knows this, but it's worth lining a few things up again.

Wear OS - what runs on Pixel Watches today, and in earlier incarnations ran on this G Watch when it was new - is an operating system that lives on top of a platform. What you get to do with the watch is bounded by what the platform's developers have chosen to expose. Changing a wallpaper is an API. Syncing a file is an API. Installing an application is a store. If the vendor decides not to support your model any more - LG stopped, Google stopped, Motorola same story - the watch becomes a brick with a strap.

AsteroidOS doesn't work that way. AsteroidOS is Yocto, Qt, Wayland. Underneath there's systemd. There's BlueZ for Bluetooth, ConnMan for networking, oFono for bridging notifications from the phone. It's the same kind of Linux stack that runs on a laptop forgotten in a closet, or a Raspberry Pi taped behind a router. The launcher is a QML application that reads wallpapers from a directory. The directory is a directory. If you put a file in it, it's in.

This is the difference between a device and an appliance. You own a device. You use an appliance for as long as somebody else gives you permission.

the point

I keep coming back to the same pattern. Every time I pick up something the manufacturer has declared done - the Fairphone 3 with LineageOS still in my pocket, this resurrected G Watch, the old ThinkPad running as a container host in the rack - I notice that end of life isn't a property of the device. It's a commercial choice they'd like to pass off as a law of physics.

The hardware still works. The display is still a display. The Snapdragon 400 in this watch does exactly the same operations it did in 2014. It didn't break. It didn't get tired. It was just declared no longer worthy of software by the company that sold you the object, so that you'd buy a new one. The battery, too - it didn't die because batteries die; it died because it ran for a decade, and it's a replaceable component for anyone with a T5 Torx and half an hour.

The answer to all of this is free software, and it's also, frankly, the physical pleasure of swapping a battery with three quid of plastic and a screwdriver. The pleasure of seeing bash answer back on a 1.4-inch screen. The pleasure of knowing that the full/ directory is a full/ directory, and that if tomorrow I decide I want wallpapers in HEIF rather than JPG I'll convert them with imagemagick on the laptop, adb push them across, done.

This is SolarPunk applied. It isn't a vertical garden on a skyscraper, it's a 2014 watch still working in 2026, on an operating system maintained by a community of maybe twenty people, with a battery I replaced myself.


The album has finished. Simone Simons made a delicate record, much less operatic than Epica, voice and synths in the foreground - a direction I wasn't expecting and that I'm enjoying a lot. It's gone past midnight. The watch on my wrist reads 20:16 in white on a dark background, and that suits me fine.