#!/usr/bin/env bash # LVX6048 → Home Assistant monitoring — reproducible installer. # # Installs powermon + our patches, drops in udev rule / systemd units / resolver # script / powermon configs, and starts the services. Idempotent: safe to re-run. # # Assumptions: # - Debian-family Linux (Raspberry Pi OS, Ubuntu) with systemd # - `uv` is installed and on $PATH (https://docs.astral.sh/uv/) # - User has sudo # - MQTT broker reachable (edit config/powermon/*.yaml first if the broker IP / # credentials aren't yet in place) # # After install, finish by editing: # ~/.config/powermon/powermon{,2}.yaml — MQTT broker + credentials # /usr/local/sbin/lvx-resolve-links — SERIAL_UNIT_1 / SERIAL_UNIT_2 # lvx-flash/flash.py — SERIAL_UNIT_1 / SERIAL_UNIT_2 # then: # sudo systemctl restart lvx-resolve-links powermon.service powermon2.service set -euo pipefail PINNED_POWERMON="1.0.18" # version we developed/tested patches against BASE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" msg() { printf '\n\033[1;36m== %s ==\033[0m\n' "$*"; } # --- 1. powermon ----------------------------------------------------------- msg "Installing powermon ${PINNED_POWERMON} via uv" command -v uv >/dev/null || { echo "uv not found — install from https://docs.astral.sh/uv/"; exit 1; } uv tool install --with bleak "powermon==${PINNED_POWERMON}" POWERMON_VENV="${HOME}/.local/share/uv/tools/powermon" POWERMON_SITE="$(ls -d "${POWERMON_VENV}"/lib/python*/site-packages/powermon)" POWERMON_PY="${POWERMON_VENV}/bin/python" [ -d "$POWERMON_SITE" ] || { echo "could not locate powermon site-packages under ${POWERMON_VENV}"; exit 1; } # --- 2. powermon patches --------------------------------------------------- msg "Applying powermon patches into ${POWERMON_SITE}" install -m 644 "${BASE}/powermon-patches/pi18.py" "${POWERMON_SITE}/protocols/pi18.py" install -m 644 "${BASE}/powermon-patches/port_config_model.py" "${POWERMON_SITE}/configmodel/port_config_model.py" install -m 644 "${BASE}/powermon-patches/ports_init.py" "${POWERMON_SITE}/ports/__init__.py" install -m 644 "${BASE}/powermon-patches/usbport.py" "${POWERMON_SITE}/ports/usbport.py" install -m 644 "${BASE}/powermon-patches/mqttbroker.py" "${POWERMON_SITE}/libs/mqttbroker.py" # --- 3. udev (LVX6048 hidraw → dialout perms) ------------------------------ msg "Installing udev rule" sudo install -m 644 "${BASE}/etc/udev/rules.d/99-lvx6048.rules" /etc/udev/rules.d/99-lvx6048.rules sudo udevadm control --reload-rules sudo udevadm trigger --subsystem-match=hidraw # --- 4. resolver script (serial → /dev/lvx6048-N symlinks) ----------------- msg "Installing /usr/local/sbin/lvx-resolve-links (shebang → ${POWERMON_PY})" TMP_RESOLVER="$(mktemp)" trap 'rm -f "$TMP_RESOLVER"' EXIT awk -v py="${POWERMON_PY}" 'NR==1 { print "#!" py; next } { print }' \ "${BASE}/bin/lvx-resolve-links" > "$TMP_RESOLVER" sudo install -m 755 "$TMP_RESOLVER" /usr/local/sbin/lvx-resolve-links # --- 5. systemd units + drop-ins ------------------------------------------- msg "Installing systemd units" sudo install -m 644 "${BASE}/etc/systemd/system/lvx-resolve-links.service" /etc/systemd/system/ sudo install -m 644 "${BASE}/etc/systemd/system/powermon.service" /etc/systemd/system/ sudo install -m 644 "${BASE}/etc/systemd/system/powermon2.service" /etc/systemd/system/ sudo mkdir -p /etc/systemd/system/powermon.service.d /etc/systemd/system/powermon2.service.d sudo install -m 644 "${BASE}/etc/systemd/system/powermon.service.d/10-resolver.conf" \ /etc/systemd/system/powermon.service.d/10-resolver.conf sudo install -m 644 "${BASE}/etc/systemd/system/powermon2.service.d/10-resolver.conf" \ /etc/systemd/system/powermon2.service.d/10-resolver.conf sudo systemctl daemon-reload # --- 6. user configs (only if not already deployed; don't clobber creds) --- msg "Installing powermon configs (skipping existing files — edit creds manually if new)" mkdir -p "${HOME}/.config/powermon" for f in powermon.yaml powermon2.yaml; do dest="${HOME}/.config/powermon/${f}" if [ -e "$dest" ]; then echo " $dest already exists — not overwriting" else install -m 600 "${BASE}/config/powermon/${f}" "$dest" echo " wrote $dest (mode 600) — edit MQTT credentials before enabling services" fi done # --- 7. enable services ---------------------------------------------------- msg "Enabling services" sudo systemctl enable --now lvx-resolve-links.service # Only auto-start powermon services if credentials look real (no placeholder present) if grep -q '' "${HOME}/.config/powermon/powermon.yaml" 2>/dev/null; then cat <