Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Network UPS Tools to support Uninterruptable Power Supplies #1759

Merged
merged 4 commits into from
Feb 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions build-image/openhabian.conf
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ storagecapacity=1024
# smarthost=smtp.gmail.com
# smartport=587

# Network UPS Tools
# nutmode=netserver
# Settings for netserver:
# nutupsdriver=usbhid-ups
# nutupsdescr=""
# Settings for netclient:
# nutupsname=ups
# nutupshost=xxx.xxx.xxx.xx
# nutupsuser=monuser
# nutupspw=secret

# Tailscale VPN
# preauthkey=tskey-xxxxxxxxxxxxxxxxx
# tstags=tag:client
Expand Down
11 changes: 11 additions & 0 deletions build-image/openhabian.pi-raspios32.conf
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ storagecapacity=1024
# smarthost=smtp.gmail.com
# smartport=587

# Network UPS Tools
# nutmode=netserver
# Settings for netserver:
# nutupsdriver=usbhid-ups
# nutupsdescr=""
# Settings for netclient:
# nutupsname=ups
# nutupshost=xxx.xxx.xxx.xx
# nutupsuser=monuser
# nutupspw=secret

# Tailscale VPN
# preauthkey=tskey-xxxxxxxxxxxxxxxxx
# tstags=tag:client
Expand Down
11 changes: 11 additions & 0 deletions build-image/openhabian.pi-raspios64.conf
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ storagecapacity=1024
# smarthost=smtp.gmail.com
# smartport=587

# Network UPS Tools
# nutmode=netserver
# Settings for netserver:
# nutupsdriver=usbhid-ups
# nutupsdescr=""
# Settings for netclient:
# nutupsname=ups
# nutupshost=xxx.xxx.xxx.xx
# nutupsuser=monuser
# nutupspw=secret

# Tailscale VPN
# preauthkey=tskey-xxxxxxxxxxxxxxxxx
# tstags=tag:client
Expand Down
18 changes: 10 additions & 8 deletions functions/menu.bash
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ show_main_menu() {
local choice
local version

choice=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "Setup Options" 19 116 12 --cancel-button Exit --ok-button Execute \
choice=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "Setup Options" 24 118 16 --cancel-button Exit --ok-button Execute \
"00 | About openHABian" "Information about the openHABian project and this tool" \
"" "" \
"01 | Select Branch" "Select the openHABian config tool version (\"branch\") to run" \
Expand Down Expand Up @@ -70,7 +70,7 @@ show_main_menu() {
import_openhab_config

elif [[ "$choice" == "10"* ]]; then
choice2=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "Apply Improvements" 13 116 6 --cancel-button Back --ok-button Execute \
choice2=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "Apply Improvements" 24 118 16 --cancel-button Back --ok-button Execute \
"11 | Packages" "Install needed and recommended system packages" \
"12 | Bash&Vim Settings" "Update customized openHABian settings for bash, vim and nano" \
"13 | System Tweaks" "Add /srv mounts and update settings typical for openHAB" \
Expand All @@ -92,7 +92,7 @@ show_main_menu() {
esac

elif [[ "$choice" == "20"* ]]; then
choice2=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "Optional Components" 25 118 18 --cancel-button Back --ok-button Execute \
choice2=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "Optional Components" 24 118 16 --cancel-button Back --ok-button Execute \
"21 | Log Viewer" "openHAB Log Viewer webapp (frontail)" \
" | Add log to viewer" "Add a custom log to openHAB Log Viewer (frontail)" \
" | Remove log from viewer" "Remove a custom log from openHAB Log Viewer (frontail)" \
Expand Down Expand Up @@ -142,7 +142,7 @@ show_main_menu() {
esac

elif [[ "$choice" == "30"* ]]; then
choice2=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "System Settings" 26 118 19 --cancel-button Back --ok-button Execute \
choice2=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "System Settings" 24 118 16 --cancel-button Back --ok-button Execute \
"31 | Change hostname" "Change the name of this system, currently '$(hostname)'" \
"32 | Set system locale" "Change system language, currently '$(env | grep "^[[:space:]]*LANG=" | sed 's|LANG=||g')'" \
"33 | Set system timezone" "Change your timezone, execute if it's not '$(printf "%(%H:%M)T\\n" "-1")' now" \
Expand All @@ -163,6 +163,7 @@ show_main_menu() {
" | Remove Tailscale VPN" "Remove the Tailscale VPN service" \
" | Install WireGuard" "Setup WireGuard to enable secure remote access to this openHABian system" \
" | Remove WireGuard" "Remove WireGuard VPN from this system" \
"3C | Setup UPS (nut)" "Setup a Uninterruptable Power Supply for this system using Network UPS Tools" \
3>&1 1>&2 2>&3)
if [ $? -eq 1 ] || [ $? -eq 255 ]; then return 0; fi
wait_for_apt_to_finish_update
Expand All @@ -187,12 +188,13 @@ show_main_menu() {
*Remove\ Tailscale*) install_tailscale remove;;
*Install\ WireGuard*) if install_wireguard install; then setup_wireguard; fi;;
*Remove\ WireGuard*) install_wireguard remove;;
3C\ *) nut_setup ;;
"") return 0 ;;
*) whiptail --msgbox "An unsupported option was selected (probably a programming error):\\n \"$choice2\"" 8 80 ;;
esac

elif [[ "$choice" == "40"* ]]; then
choice2=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "openHAB Related" 22 126 15 --cancel-button Back --ok-button Execute \
choice2=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "openHAB Related" 24 118 16 --cancel-button Back --ok-button Execute \
"41 | openHAB Release" "Install or switch to the latest openHAB Release" \
" | openHAB Milestone" "Install or switch to the latest openHAB Milestone Build" \
" | openHAB Snapshot" "Install or switch to the latest openHAB Snapshot Build" \
Expand All @@ -204,8 +206,8 @@ show_main_menu() {
" | OpenJDK 17" "Install and activate OpenJDK 17 as Java provider" \
" | Zulu 11 OpenJDK 32-bit" "Install Zulu 11 32-bit OpenJDK as Java provider" \
" | Zulu 11 OpenJDK 64-bit" "Install Zulu 11 64-bit OpenJDK as Java provider" \
"46 | Install openhab-js" "JS Scripting: Upgrade to the latest version of the openHAB JavaScript library" \
" | Uninstall openhab-js" "JS Scripting: Switch back to the included version of the openHAB JavaScript library" \
"46 | Install openhab-js" "JS Scripting: Upgrade to latest version of openHAB JavaScript library (advanced)" \
" | Uninstall openhab-js" "JS Scripting: Switch back to included version of openHAB JavaScript library" \
"47 | Install openhab_rules_tools" "JS Scripting: Manually install openhab_rules_tools (auto-installed)" \
" | Uninstall openhab_rules_tools" "JS Scripting: Uninstall openhab_rules_tools" \
3>&1 1>&2 2>&3)
Expand Down Expand Up @@ -234,7 +236,7 @@ show_main_menu() {
esac

elif [[ "$choice" == "50"* ]]; then
choice2=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "Backup/Restore" 15 116 8 --cancel-button Back --ok-button Execute \
choice2=$(whiptail --title "openHABian Configuration Tool — $(get_git_revision)" --menu "Backup/Restore" 24 118 16 --cancel-button Back --ok-button Execute \
"50 | Backup openHAB config" "Backup (export) the current active openHAB configuration" \
"51 | Restore an openHAB config" "Restore an openHAB configuration from backup zipfile" \
" | Restore text only config" "Restore text only configuration without restarting" \
Expand Down
120 changes: 120 additions & 0 deletions functions/nut.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env bash
# shellcheck disable=SC2154,SC2155

## Check if Network UPS Tools is installed
##
## nut_is_installed()
##
nut_is_installed() {
if dpkg -s 'nut' &> /dev/null; then return 0; fi
return 1
}

## (Un)Install Network UPS Tools
## Supports both INTERACTIVE and UNATTENDED mode
##
## Valid arguments: "install" or "remove"
##
## nut_install(String action)
##
nut_install() {
if [[ $1 == "remove" ]]; then
if [[ -n $INTERACTIVE ]]; then
whiptail --title "nut removal" --msgbox "This will remove Network UPS Tools (nut)." 7 80
fi
echo -n "$(timestamp) [openHABian] Removing Network UPS Tools... "
if cond_redirect apt purge -y nut; then echo "OK"; else echo "FAILED"; return 1; fi
return;
fi

if [[ $1 != "install" ]]; then return 1; fi
if [[ -n $INTERACTIVE ]]; then
whiptail --title "nut installation" --msgbox "This will install Network UPS Tools (nut)." 8 80
fi

echo -n "$(timestamp) [openHABian] Installing Network UPS Tools... "
if cond_redirect apt install -y nut; then echo "OK"; else echo "FAILED (package installation)"; return 1; fi

## Do service activation later as nut-server & nut-client depend on the setup!
}

## Configure Network UPS Tools
## Supports both INTERACTIVE and UNATTENDED mode
##
## Variables used:
## - "nutmode": "netserver" or "netclient"
## for "netserver":
## - "nutupsdriver": driver for local UPS
## - "nutupsdescr": description for local UPS
## for "netclient":
## - "nutupsname": name of network UPS
## - "nutupshost": host of network UPS
## - "nutupsuser": username for network UPS
## - "nutupspw": password for network UPS
##
## nut_setup()
##
nut_setup() {
if [[ -n $UNATTENDED ]] && [[ -z $nutmode ]]; then
echo "$(timestamp) [openHABian] Beginning Network UPS Tools setup... SKIPPED (no configuration provided)"
return 0
fi

local upsmasterpw="$(openssl rand -base64 12)"
local upsslavepw="$(openssl rand -base64 12)"
local upsmonitor="MONITOR ups@localhost 1 upsmaster ${upsmasterpw} master"

local whiptailTitle="Network UPS Tools"
local introText="Network UPS Tools (nut) adds an Uniterruptable Power Supply (UPS) to your openHABian system.\\nIn case of a power outage, it protects your system from data loss by ensuring a safe shutdown.\\n\\nWe will guide you through the setup."

if ! nut_is_installed; then nut_install "install"; fi
florian-h05 marked this conversation as resolved.
Show resolved Hide resolved

if [[ -n $INTERACTIVE ]]; then
if ! whiptail --title "${whiptailTitle}" --yes-button "Begin" --no-button "Cancel" --yesno "${introText}\\n\\nDo you want to continue?" 14 100; then echo "CANCELED"; return 0; fi
if ! nutmode=$(whiptail --title "${whiptailTitle}" --menu "Choose mode:" 14 100 2 --cancel-button "Cancel" --ok-button "Continue" \
"netserver" "The UPS is directly connected to this computer. Currently, only USB UPS are supported." \
"netclient" "The UPS is connected to another computer on the network." \
3>&1 1>&2 2>&3); then echo "CANCELED"; return 0; fi
if [[ $nutmode == "netclient" ]]; then
if ! nutupsname=$(whiptail --title "${whiptailTitle}" --inputbox "\\nEnter name of network UPS (default for openHABian & Synology):" 10 80 "ups" 3>&1 1>&2 2>&3); then echo "CANCELED"; return 0; fi
if ! nutupshost=$(whiptail --title "${whiptailTitle}" --inputbox "\\nEnter IP address (or hostname) of network UPS:" 10 80 3>&1 1>&2 2>&3); then echo "CANCELED"; return 0; fi
if ! nutupsuser=$(whiptail --title "${whiptailTitle}" --inputbox "\\nEnter username for network UPS (default for openHABian & Synology):" 10 80 "monuser" 3>&1 1>&2 2>&3); then echo "CANCELED"; return 0; fi
if ! nutupspw=$(whiptail --title "${whiptailTitle}" --passwordbox "\\nEnter password for network UPS (default for openHABian & Synology):" 10 80 "secret" 3>&1 1>&2 2>&3); then echo "CANCELED"; return 0; fi
fi
fi

echo -n "$(timestamp) [openHABian] Setting up nut... "
if [[ -z $nutmode ]]; then echo "FAILED (nutmode is not set)"; return 1; fi
if ! (sed -e "s|%NUTMODE|${nutmode}|g" "${BASEDIR:-/opt/openhabian}"/includes/nut/nut.conf > /etc/nut/nut.conf); then echo "FAILED (nut.conf file update)"; return 1; fi

# Setup local host as nut server; therefore UPS is attached to the local host
if [[ $nutmode == "netserver" ]]; then
# Setup nut-server
if ! (sed -e "s|%NUTUPSDRIVER|${nutupsdriver:-usbhid-ups}|g" -e "s|%NUTUPSDESCR|${nutupsdescr:-UPS on ${hostname}}|g" "${BASEDIR:-/opt/openhabian}"/includes/nut/ups.conf > /etc/nut/ups.conf); then echo "FAILED (ups.conf file update)"; return 1; fi
if ! cond_redirect upsdrvctl start; then echo "FAILED (connection test)"; return 1; fi
if ! cp "${BASEDIR:-/opt/openhabian}/includes/nut/upsd.conf" "/etc/nut/upsd.conf"; then echo "FAILED (upsd.conf file update)"; return 1; fi
if ! (sed -e "s|%NUTUPSMASTERPW|${upsmasterpw}|g" -e "s|%NUTUPSSLAVEPW|${upsslavepw}|g" "${BASEDIR:-/opt/openhabian}"/includes/nut/upsd.users > /etc/nut/upsd.users); then echo "FAILED (upsd.users file update)"; return 1; fi
# Enable and start nut-server.service
if ! cond_redirect systemctl enable nut-server.service; then echo "FAILED (enable nut-server.service)"; return 1; fi
if ! cond_redirect systemctl restart nut-server.service; then echo "FAILED (restart nut-server.service)"; return 1; fi

# Setup nut-client for local server
if ! (sed -e "s|%NUTMONITOR|${upsmonitor}|g" "${BASEDIR:-/opt/openhabian}"/includes/nut/upsmon.conf > /etc/nut/upsmon.conf); then echo "FAILED (upsmon.conf file update)"; return 1; fi
fi

# Setup local host as nut client; therefore monitor an UPS on the network
if [[ $nutmode == "netclient" ]]; then
if [[ -z $nutupshost ]]; then echo "FAILED (nutupshost is not set)"; return 1; fi

# Disable nut-server.service
if ! cond_redirect systemctl disable --now nut-server.service; then echo "FAILED (disable & stop nut-server.service)"; return 1; fi

# Setup nut-client for remote server
upsmonitor="MONITOR ${nutupsname:-ups}@${nutupshost} 1 ${nutupsuser:-monuser} ${nutupspw:-secret} slave"
if ! (sed -e "s|%NUTMONITOR|${upsmonitor}|g" "${BASEDIR:-/opt/openhabian}"/includes/nut/upsmon.conf > /etc/nut/upsmon.conf); then echo "FAILED (upsmon.conf file update)"; return 1; fi
fi

if ! cond_redirect systemctl enable nut-client.service; then echo "FAILED (enable nut-client.service)"; return 1; fi
if ! cond_redirect systemctl restart nut-client.service; then echo "FAILED (restart nut-client.service)"; return 1; fi
echo "OK"
}
32 changes: 32 additions & 0 deletions includes/nut/nut.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Network UPS Tools: example nut.conf
#
##############################################################################
# General section
##############################################################################
# The MODE determines which part of the NUT is to be started, and which
# configuration files must be modified.
#
# This file try to standardize the various files being found in the field, like
# /etc/default/nut on Debian based systems, /etc/sysconfig/ups on RedHat based
# systems, ... Distribution's init script should source this file to see which
# component(s) has to be started.
#
# The values of MODE can be:
# - none: NUT is not configured, or use the Integrated Power Management, or use
# some external system to startup NUT components. So nothing is to be started.
# - standalone: This mode address a local only configuration, with 1 UPS
# protecting the local system. This implies to start the 3 NUT layers (driver,
# upsd and upsmon) and the matching configuration files. This mode can also
# address UPS redundancy.
# - netserver: same as for the standalone configuration, but also need
# some more network access controls (firewall, tcp-wrappers) and possibly a
# specific LISTEN directive in upsd.conf.
# Since this MODE is opened to the network, a special care should be applied
# to security concerns.
# - netclient: this mode only requires upsmon.
#
# IMPORTANT NOTE:
# This file is intended to be sourced by shell scripts.
# You MUST NOT use spaces around the equal sign!

MODE=%NUTMODE
Loading