From 6790205976e6cb401a76db462cb0008c2a059949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20H=C3=B6fling?= Date: Wed, 3 Jun 2026 11:57:01 +0200 Subject: [PATCH] add bluewalker vfi icr series --- bluewalker-vfi-icr/README.md | 63 ++++++++++++++++++ bluewalker-vfi-icr/install-client.sh | 45 +++++++++++++ bluewalker-vfi-icr/install-master.sh | 52 +++++++++++++++ .../nut-powerwalker-vfi-icr-iot.tar.gz | Bin 0 -> 3099 bytes bluewalker-vfi-icr/ups.conf | 16 +++++ 5 files changed, 176 insertions(+) create mode 100644 bluewalker-vfi-icr/README.md create mode 100644 bluewalker-vfi-icr/install-client.sh create mode 100644 bluewalker-vfi-icr/install-master.sh create mode 100644 bluewalker-vfi-icr/nut-powerwalker-vfi-icr-iot.tar.gz create mode 100644 bluewalker-vfi-icr/ups.conf diff --git a/bluewalker-vfi-icr/README.md b/bluewalker-vfi-icr/README.md new file mode 100644 index 0000000..5b5c512 --- /dev/null +++ b/bluewalker-vfi-icr/README.md @@ -0,0 +1,63 @@ +# NUT config: PowerWalker VFI ICR IoT + +Network UPS Tools setup for a PowerWalker VFI ICR IoT UPS. + +- **Master**: one host connected to the UPS via **USB** (`nutdrv_qx`), runs + `upsd` + `upsmon`, and serves status to the network on port `3493/tcp`. +- **Clients**: any other Linux hosts run `upsmon` as network slaves and shut + down gracefully when the master signals a power failure (FSD). + +This avoids the undocumented Modbus TCP register map entirely. If you ever +want a pure-network (no USB) setup, you would need the Modbus register map +from PowerWalker support plus the `nutdrv_modbus` driver -- not used here. + +## Layout + +``` +master/etc/nut/ config for the USB-connected host +client/etc/nut/ config for each network slave +install-master.sh deploy + permissions on the master +install-client.sh deploy on a client: sudo ./install-client.sh +``` + +## Quick start + +### Master (USB host) + +``` +sudo ./install-master.sh +# edit /etc/nut/upsd.users -> set monmaster / monslave passwords +# edit /etc/nut/upsmon.conf -> set the same monmaster password +sudo nutdrv_qx -a test -DD -x port=auto # confirm the driver reads values +sudo systemctl enable --now nut-server nut-monitor +upsc ups@localhost +``` + +If the test shows no/garbled values, retry with: + +``` +sudo nutdrv_qx -a test -DD -x port=auto -x protocol=voltronic -x novendor +``` + +and uncomment the matching lines in `master/etc/nut/ups.conf`. + +### Each client + +``` +sudo ./install-client.sh +# edit /etc/nut/upsmon.conf -> set the monslave password +sudo systemctl enable --now nut-monitor +upsc ups@ +``` + +## Notes + +- Open `3493/tcp` on the master firewall for your client subnets. +- `runtimecal` in `ups.conf`: these UPS models may not report runtime; + NUT then estimates it. Format: `sec_at_full,full_pct,sec_at_half,half_pct`. + Adjust to your battery / EBM configuration. +- `upsd.users` holds plaintext credentials and is gitignored. Keep the real + file off the repo; distribute it out of band (or via your secrets tooling). +- To also cut UPS output power after the master shuts down, look into + `upsdrvctl shutdown` / the `POWERDOWNFLAG` mechanism -- intentionally left + out here to keep the first deployment simple. diff --git a/bluewalker-vfi-icr/install-client.sh b/bluewalker-vfi-icr/install-client.sh new file mode 100644 index 0000000..0a0fe26 --- /dev/null +++ b/bluewalker-vfi-icr/install-client.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# install-client.sh -- deploy NUT network-slave config +# Usage: sudo ./install-client.sh +# ASCII only. + +set -euo pipefail + +SRC="$(cd "$(dirname "$0")" && pwd)/client/etc/nut" +DST="/etc/nut" + +if [ "$(id -u)" -ne 0 ]; then + echo "ERROR: run as root (sudo)." >&2 + exit 1 +fi + +MASTER_IP="${1:-}" +if [ -z "$MASTER_IP" ]; then + echo "Usage: sudo $0 " >&2 + exit 1 +fi + +echo "== Installing NUT (if missing) ==" +if command -v apt-get >/dev/null 2>&1; then + apt-get update && apt-get install -y nut +elif command -v dnf >/dev/null 2>&1; then + dnf install -y nut +else + echo "WARN: unknown package manager, install 'nut' manually." >&2 +fi + +echo "== Copying client config to ${DST} ==" +install -d "$DST" +cp -v "$SRC/nut.conf" "$DST/nut.conf" +sed "s/MASTER_IP/${MASTER_IP}/" "$SRC/upsmon.conf" > "$DST/upsmon.conf" + +chown root:nut "$DST/upsmon.conf" 2>/dev/null || true +chmod 640 "$DST/upsmon.conf" + +echo +echo "NEXT STEPS (manual):" +echo " 1. Edit ${DST}/upsmon.conf -- replace CHANGE_ME_SLAVE with the master's monslave password." +echo " 2. Enable the monitor service:" +echo " systemctl enable --now nut-monitor" +echo " 3. Verify connectivity to the master:" +echo " upsc ups@${MASTER_IP}" diff --git a/bluewalker-vfi-icr/install-master.sh b/bluewalker-vfi-icr/install-master.sh new file mode 100644 index 0000000..147f08d --- /dev/null +++ b/bluewalker-vfi-icr/install-master.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# install-master.sh -- deploy NUT master config for PowerWalker VFI ICR IoT +# Run as root on the USB-connected host. ASCII only. + +set -euo pipefail + +SRC="$(cd "$(dirname "$0")" && pwd)/master/etc/nut" +DST="/etc/nut" + +if [ "$(id -u)" -ne 0 ]; then + echo "ERROR: run as root (sudo)." >&2 + exit 1 +fi + +echo "== Installing NUT (if missing) ==" +if command -v apt-get >/dev/null 2>&1; then + apt-get update && apt-get install -y nut +elif command -v dnf >/dev/null 2>&1; then + dnf install -y nut +else + echo "WARN: unknown package manager, install 'nut' manually." >&2 +fi + +echo "== Copying config files to ${DST} ==" +install -d "$DST" +cp -v "$SRC/ups.conf" "$DST/ups.conf" +cp -v "$SRC/nut.conf" "$DST/nut.conf" +cp -v "$SRC/upsd.conf" "$DST/upsd.conf" +cp -v "$SRC/upsmon.conf" "$DST/upsmon.conf" + +if [ ! -f "$DST/upsd.users" ]; then + cp -v "$SRC/upsd.users.example" "$DST/upsd.users" + echo "NOTE: created upsd.users from example -- edit the passwords now." +else + echo "NOTE: upsd.users already exists, left untouched." +fi + +echo "== Setting ownership and permissions ==" +chown root:nut "$DST"/*.conf "$DST/upsd.users" 2>/dev/null || true +chmod 640 "$DST/upsd.users" "$DST/upsmon.conf" + +echo +echo "NEXT STEPS (manual):" +echo " 1. Edit ${DST}/upsd.users and ${DST}/upsmon.conf -- replace CHANGE_ME_* passwords." +echo " 2. Plug in the UPS via USB and test the driver:" +echo " nutdrv_qx -a test -DD -x port=auto" +echo " (add -x protocol=voltronic -x novendor if values are missing)" +echo " 3. Enable services:" +echo " systemctl enable --now nut-server nut-monitor" +echo " 4. Verify:" +echo " upsc ups@localhost" +echo " 5. Open 3493/tcp in the firewall for your client subnets." diff --git a/bluewalker-vfi-icr/nut-powerwalker-vfi-icr-iot.tar.gz b/bluewalker-vfi-icr/nut-powerwalker-vfi-icr-iot.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..1ee879dbb65bed3357cd4d61f362e5883332c958 GIT binary patch literal 3099 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 literal 0 HcmV?d00001 diff --git a/bluewalker-vfi-icr/ups.conf b/bluewalker-vfi-icr/ups.conf new file mode 100644 index 0000000..3bc8089 --- /dev/null +++ b/bluewalker-vfi-icr/ups.conf @@ -0,0 +1,16 @@ +# /etc/nut/ups.conf -- MASTER (USB-connected host) +# PowerWalker VFI ICR IoT via nutdrv_qx over USB. +# +# Uncomment the protocol/novendor/runtimecal lines only if the bare +# config does not return clean values. See README for the test command. + +[ups] + driver = nutdrv_qx + port = auto + desc = "PowerWalker VFI ICR IoT" + pollinterval = 5 + + # Fallbacks (enable if needed): + # protocol = voltronic + # novendor + # runtimecal = 600,100,1200,50