π€ Automation
Presets, JSON output and watch mode β the things a terminal can do with your fan that a phone app can't.
The CLI and the Duux app send the same commands, so neither can outreach the
other on raw capability. The difference is what can trigger a command: the
app needs a finger, while duux can be run by anything your machine knows β
the time, your calendar, a temperature reading, a shell alias, an SSH session
from the other side of the world.
These three features exist to make that practical.
Presets
A named combination applied in one go.
$ duux preset
sleep power true, speed 3, mode natural, night true, horosc 0, timer 8
quiet power true, speed 5, mode natural, night false, horosc 1
boost power true, speed 30, mode normal, night false, horosc 2
away power false
$ duux preset sleep
β Applied sleep β power true, speed 3, mode natural, night true, horosc 0, timer 8Build your own by getting the fan how you like it and naming that:
$ duux preset save reading
β Saved reading β power true, speed 8, mode natural, horosc 1, verosc 0Yours override built-ins of the same name; duux preset delete <name> removes
them. Commands are ordered so the fan powers on before anything is set on it,
and the timer is applied last.
JSON output
$ duux status --json
{"device":"Whisper","id":373883,"mac":"28:05:a5:43:1f:c0","mode":"natural",
"power":true,"speed":15,"horosc":1,"verosc":1,"night":false,"lock":false,
"battery":null,"timer":0,"sensor":"28:05:a5:43:1f:c0"}Pipe it anywhere:
# Is the fan on?
duux status --json | jq -e '.power' >/dev/null && echo "running"
# Log speed every minute
* * * * * duux status --json | jq -r '[now, .speed] | @csv' >> ~/fan.csvbattery is null unless the optional battery pack is fitted, in which case
it reports { "level": 80, "charging": true }.
Watch mode
Streams changes as they happen, printing only what actually changed:
$ duux watch
Watching Whisper β Ctrl-C to stop.
19:16:20 connected on
19:16:26 mode normal
19:16:26 speed 30
19:16:29 horosc 2With --json it emits one object per line, so it can be consumed
incrementally:
duux watch --json | while read -r line; do
echo "$line" | jq -r 'select(.changes.power == false) | "fan turned off"'
doneWatch polls every 3 seconds rather than the 30 the TUI uses β it trades API calls for seeing things promptly. Changes made from the Duux app show up here too, so it's a way to observe the fan regardless of what drove it.
Ideas
The point is the trigger, not the command:
# Wind down with your evening
0 23 * * * duux preset sleep
# Cool the room when the Mac is working hard
[ "$(osx-cpu-temp | tr -dc '0-9.')" \> 80 ] && duux preset boost
# Off when you leave the house, via whatever knows that
duux preset awayNone of these are things the app can do, and none of them needed a new feature in the fan β only somewhere to hang a command.
β¨οΈ Commands
Full reference for every duux-cli subcommand β auth, discover, devices, switch, status, watch, preset, broker, doctor, and debug.
π Local control
Optional β run duux-cli against a broker on your own network instead of Duux's cloud, for control that works offline and outlives the service.