Set PYTHONUNBUFFERED=1 in the three service files. Python buffers its output if it does not write to a terminal, so log lines reached the journal late.
bmspy-ups selected its device from the devices that had data at startup, and exited with status 0 if the selection failed. One failed first read ended the monitor or made it select the wrong device.
The server has a new DEVICES command that lists the configured names, and client.list_devices calls it. bmspy-ups selects from that list and then waits for the first data of its device. A wrong or missing --device now exits with status 2. The service file does not restart on that status, because a restart cannot correct it.
An older server ends on the unknown DEVICES command, so update the server first.
Use standard project metadata, dependency groups, and the uv build backend. The new lock preserves the previous dependency versions. Documentation and services use uv, and services leave their shared environment unchanged at startup.
Remove the entry point for the empty USB HID prototype. Exclude local prototypes, captures, and the external Type 7 lookup table from version control and distributions.