r/o

README.md

a1d

Light-weight fan and power controller for the Argon ONE V3 for Raspberry Pi 5.

This does what the OEM one does:

  • Monitors system thermals and adjusts the fan speed accordingly.
  • Responds to a double-press of the power button by rebooting the system.
  • Responds to a 3-5s press of the power button by initiating clean shutdown.
  • Ensures that any clean shutdown instructs the case to remove power correctly.

motivation

The OEM software is a bit garbo. DarkElvenAngel’s argononed is thousands of lines of C. This is less than 200 lines of Rust.

usage

Add the flake to your own (or otherwise fetch it!):

inputs.a1d.url = "git+https://nossa.ee/~talya/a1d";

Add the NixOS module:

nixpkgs.lib.nixosSystem {
# ...
modules = [
# ...
a1d.nixosModules.${system}.default
];
}

Enable it in your config!

services.a1d.enable = true;

Done. Temperature zones aren’t configurable at the moment. Note that this enables Polkit to grant reboot/poweroff permissions.

notes

The power button seems to work this way:

  • If you press it twice rapidly, the case raises its GPIO line for 20ms, and does nothing else.
  • If you press and hold it for more than 5 seconds, it shuts off all power immediately.
  • If you press and hold it for between 3 to 5 seconds, the case raises its GPIO line for 40ms, and then kills power after 15-ish seconds. This is meant to be enough time to halt the system.

The same power-cut timer is also used when a 1 is written to the control register over I2C, so we write that out with systemd-shutdown when the system is powered off for any reason.

nix is scary

Sowwy. You can cargo build --release and get target/release/a1d running somehow. Here’s an a1d.service for you:

[Unit]
Description=a1d Argon ONE V3 fan/power daemon
[Service]
ExecStart=/path/to/a1d
User=a1d
ProtectSystem=strict
PrivateTmp=true
Restart=on-failure
RestartSec=10s
[Install]
WantedBy=multi-user.target

You’ll need an a1d user, belonging to the groups i2c and gpio (assuming they’re the groups that /dev/i2c-1 and /dev/gpiochip0 belong to). a1d uses systemctl to issue reboot/poweroff commands, and dbus-daemon doesn’t seem to like DynamicUsers doing that.

You’ll also need a 99-a1d.rules for /etc/polkit-1/rules.d or /usr/share/polkit-1/rules.d:

polkit.addRule(function(action, subject) {
if (subject.user !== "a1d")
return;
if (action.id === "org.freedesktop.login1.power-off" ||
action.id === "org.freedesktop.login1.power-off-multiple-sessions" ||
action.id === "org.freedesktop.login1.power-off-ignore-inhibit" ||
action.id === "org.freedesktop.login1.reboot" ||
action.id === "org.freedesktop.login1.reboot-multiple-sessions" ||
action.id === "org.freedesktop.login1.reboot-ignore-inhibit") {
return polkit.Result.YES;
}
});

You’ll also want to symlink the a1d binary into your systemd-shutdown directory, perhaps /usr/lib/systemd/system-shutdown.

On the other hand, maybe it’d be easier to learn Nix?

todo

  • Expose used temperature/fan speed on prometheus.

license

Copyright © 2025 Asherah Connor <ashe@kivikakk.ee>

This work is free. You can redistribute it and/or modify it under the terms of the Do What The Fuck You Want To Public License, Version 2, as published by Sam Hocevar. See the COPYING file for more details.