While fixing my air conditioner, I needed to frequently debug what HTTP requests my ESP32 was sending to my hue bridge's API when it activates or deactivates my 3d printed dremel-based pump to prevent excess condensate from flooding my flat and jeopardizing my housing situation. If you use nix/home-manager, then my approach could be of perverse interest to you. If not, then feel free to gawk at how complicated I can implement a single alias command.
When my ESP32 detects a pulled-down voltage at GPIO4
, this means that the water level has reached the upper limit in my condensation collection container. This is because i have GND
ran out to the bottom of the bin, and GPIO4
is set to INPUT_PULLUP
. GPIO3
is set to the same but I do not turn on the pump for this pin. Instead, i use that pin to know when to turn off the pump once the pump has been turned on at the upper limit.
When the ESP32
sends a request to my local hue bridge to activate the smartplug where I have my dremel pump plugged in, and nothing happens, I need to figure out what HTTP request is actually going out. I use requestbin for this. The publicly available service became sporadically available many years back, but you can still run it via docker. Once its running, it gives me a URL i can substitute for the Hue bridge API endpoint, I ca inspect
The command for this is
docker run --rm -it -p 8000:8000 weshigbee/requestbin
That's just a little too unwieldy to remember, so I'd like to make a permanent utility to run it. While writing this, i realize i could have just aliased it and added it to my zsh config inside my home-manager config under programs.zsh.shellAliases
However, in my early-morning sleepy haze, I opted to create a solution as arguably over-engineered as it may be forgivingly considered succinctly practical. I have ~/.local/bin
in my home.sessionPath
. I have slowly been evolving how I manage these utilities for the last few months. The primary difference between files in ~/.local/bin
and a shell alias is that files in that directory can be shell scripts. For example ~/.local/bin/update
used to be a shell alias bound to NIXPKGS\_ALLOW\_INSECURE=1 darwin-rebuild switch --flake "$HOME/.nixpkgs#$(hostname)" --impure
Today, it's a shell script:
cd ~/.nixpkgs
# capture local binary utilities
for file in `find ~/.local/bin/ -maxdepth 1 -type f`; do
mv $file ~/.nixpkgs/user-specific/sdevol/.local/bin/
done
git add user-specific/sdevol/.local/bin
# capture the espanso configuration
cp -R ~/.config/espanso/* ~/.nixpkgs/user-specific/sdevol/.config/espanso/
git add ~/.nixpkgs/user-specific/sdevol/.config/espanso
# do the thing
NIXPKGS_ALLOW_INSECURE=1 darwin-rebuild switch --flake "$HOME/.nixpkgs#$(hostname)" --impure
My nix configuration lives in ~/.nixpkgs
. Notice that we are moving files from ~/.local/bin
into the nix repo under ~/.nixpkgs/user-specific/sdevol/.local/bin
. As you might have began to suspect, there's some plumbing inside ~/.nixpkgs/user-specific/sdevol/home.nix
that connects some more dots.
# let
localBinDir = ./.local/bin; # this is relative to the current file, so this is ~/.nixpkgs/user-specific/sdevol/.local/bin
localBinFiles = builtins.attrNames (builtins.readDir localBinDir);
mkLocalBin = name: {
source = ./.local/bin/${name};
recursive = true;
};
in rec {
manual.manpages.enable = false;
home = {
username = "tastycode";
file =
builtins.listToAttrs (map (name: {
name = ".local/bin/${name}";
value = mkLocalBin name;
})
localBinFiles)
// {
".config/zed/settings.json" = {
source = ./zed.settings.json;
recursive = true;
};
".config/espanso" = {
source = config.lib.file.mkOutOfStoreSymlink .config/espanso;
recursive = true;
};
So, when I type update
.
- Any non-symlinks are moved into the nix configuration
- My nix configuration is rebuilt, within which the nix configuration iterates through all files in its local directory
user-specific/sdevol/.local/bin
- A
home.file.\*
reference is generated with a symlink configuration for each.
This sequence thus replaces non-symlinked files in ~/.local/bin
with symlinks to version-controlled references to the same. Therefore, once i have decided i want to make a permanent command for docker run --rm -it -p 8000:8000 weshigbee/requestbin
. All I need to do is , press up on my keyboard so that the docker command is at the prompt and modify the command to read. echo docker run --rm -it -p 8000:8000 weshigbee/requestbin > ~/.local/bin/requestbin
then ls ~/.local/bin
reads
ls -l ~/.local/bin ✔ 26ms 18.1.0 10:24:11
lrwxr-xr-x - tastycode 16 Aug 09:49 readlinks -> /nix/store/m2aiz6gszyk3i4hbqn93dpwpsi6f805p-home-manager-files/.local/bin/readlinks
.rw-r--r-- 54 tastycode 16 Aug 10:24 requestbin
lrwxr-xr-x - tastycode 16 Aug 09:49 screensnap -> /nix/store/m2aiz6gszyk3i4hbqn93dpwpsi6f805p-home-manager-files/.local/bin/screensnap
lrwxr-xr-x - tastycode 16 Aug 09:49 tastyspace -> /nix/store/m2aiz6gszyk3i4hbqn93dpwpsi6f805p-home-manager-files/.local/bin/tastyspace
lrwxr-xr-x - tastycode 16 Aug 09:49 update -> /nix/store/m2aiz6gszyk3i4hbqn93dpwpsi6f805p-home-manager-files/.local/bin/update
Now, i just run update
Now, requestbin
is in ~/.local/bin/requestbin
but it has been swapped out with a symlink to my nix config's manifested version of the script.
lrwxr-xr-x - tastycode 16 Aug 10:26 requestbin -> /nix/store/vgrdrcnjyhykkx1xq29kg6g2jhbqg0hx-home-manager-files/.local/bin/requestbin
Honestly, that's less keystrokes than adding a shellAlias. If you aren't sold on using nix to manage your system's configuration, this seems overcomplicated. If you use nix, then you are already probably frustrated at keeping your nix configuration in sync with quick little optimizations you do on a regular basis. With nix, everything is source controlled. If you are a dotfiler, then you would still have to commit your changes. I guess that's true in my solution as well. The git add
in my update
is probably the most dubious element of this entire schrade. That is unless, you are using jj.