Initial commit
This commit is contained in:
11
.env.example
Normal file
11
.env.example
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# OpenWrt UPS SNMP configuration
|
||||||
|
# Copy to .env and fill in your values
|
||||||
|
|
||||||
|
# UPS SNMP host
|
||||||
|
SNMP_HOST=192.168.1.1
|
||||||
|
SNMP_COMMUNITY=public
|
||||||
|
|
||||||
|
# OpenWrt host
|
||||||
|
OPENWRT_HOST=192.168.1.1
|
||||||
|
OPENWRT_USER=root
|
||||||
|
OPENWRT_PASSWORD=change_me
|
||||||
23
.gitignore
vendored
Normal file
23
.gitignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Environment variables
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
node_modules/
|
||||||
|
vendor/
|
||||||
|
|
||||||
|
# Build output
|
||||||
|
.next/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
*.pyc
|
||||||
|
__pycache__/
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
|
||||||
53
backup/etc/config/dhcp
Normal file
53
backup/etc/config/dhcp
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
config dnsmasq
|
||||||
|
option domainneeded '1'
|
||||||
|
option boguspriv '1'
|
||||||
|
option filterwin2k '0'
|
||||||
|
option localise_queries '1'
|
||||||
|
option rebind_protection '1'
|
||||||
|
option rebind_localhost '1'
|
||||||
|
option local '/lan/'
|
||||||
|
option domain 'lan'
|
||||||
|
option expandhosts '1'
|
||||||
|
option nonegcache '0'
|
||||||
|
option cachesize '1000'
|
||||||
|
option authoritative '1'
|
||||||
|
option readethers '1'
|
||||||
|
option leasefile '/tmp/dhcp.leases'
|
||||||
|
option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
|
||||||
|
option nonwildcard '1'
|
||||||
|
option localservice '1'
|
||||||
|
option ednspacket_max '1232'
|
||||||
|
option filter_aaaa '0'
|
||||||
|
option filter_a '0'
|
||||||
|
|
||||||
|
config dhcp 'lan'
|
||||||
|
option interface 'lan'
|
||||||
|
option start '100'
|
||||||
|
option limit '150'
|
||||||
|
option leasetime '12h'
|
||||||
|
option dhcpv4 'server'
|
||||||
|
option dhcpv6 'server'
|
||||||
|
option ra 'server'
|
||||||
|
option ra_slaac '1'
|
||||||
|
list ra_flags 'managed-config'
|
||||||
|
list ra_flags 'other-config'
|
||||||
|
option ignore '1'
|
||||||
|
|
||||||
|
config dhcp 'wan'
|
||||||
|
option interface 'wan'
|
||||||
|
option ignore '1'
|
||||||
|
|
||||||
|
config odhcpd 'odhcpd'
|
||||||
|
option maindhcp '0'
|
||||||
|
option leasefile '/tmp/hosts/odhcpd'
|
||||||
|
option leasetrigger '/usr/sbin/odhcpd-update'
|
||||||
|
option loglevel '4'
|
||||||
|
option piofolder '/tmp/odhcpd-piofolder'
|
||||||
|
|
||||||
|
config dhcp 'wifi_ap'
|
||||||
|
option interface 'wifi_ap'
|
||||||
|
option start '100'
|
||||||
|
option limit '100'
|
||||||
|
option leasetime '12h'
|
||||||
|
|
||||||
60
backup/etc/config/network
Normal file
60
backup/etc/config/network
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
config interface 'loopback'
|
||||||
|
option device 'lo'
|
||||||
|
option proto 'static'
|
||||||
|
option ipaddr '127.0.0.1'
|
||||||
|
option netmask '255.0.0.0'
|
||||||
|
|
||||||
|
config globals 'globals'
|
||||||
|
option ula_prefix 'fd6b:e811:df87::/48'
|
||||||
|
option packet_steering '1'
|
||||||
|
|
||||||
|
config device
|
||||||
|
option name 'br-lan'
|
||||||
|
option type 'bridge'
|
||||||
|
list ports 'eth0.1'
|
||||||
|
list ports 'eth1'
|
||||||
|
|
||||||
|
config device
|
||||||
|
option name 'eth0.1'
|
||||||
|
option macaddr '4c:5e:0c:b5:35:f3'
|
||||||
|
|
||||||
|
config interface 'lan'
|
||||||
|
option device 'br-lan'
|
||||||
|
option proto 'static'
|
||||||
|
option ipaddr '20.0.0.26'
|
||||||
|
option netmask '255.255.255.0'
|
||||||
|
option gateway '20.0.0.1'
|
||||||
|
list dns '64.126.133.1'
|
||||||
|
|
||||||
|
config switch
|
||||||
|
option name 'switch0'
|
||||||
|
option reset '1'
|
||||||
|
option enable_vlan '1'
|
||||||
|
|
||||||
|
config switch_vlan
|
||||||
|
option device 'switch0'
|
||||||
|
option vlan '1'
|
||||||
|
option ports '1 2 3 4 0t'
|
||||||
|
|
||||||
|
config interface 'wifi_ap'
|
||||||
|
option proto 'static'
|
||||||
|
option ipaddr '192.168.88.1'
|
||||||
|
option netmask '255.255.255.0'
|
||||||
|
|
||||||
|
config device 'br_lan_dev'
|
||||||
|
option name 'br-lan'
|
||||||
|
option type 'bridge'
|
||||||
|
list ports 'eth0.1'
|
||||||
|
list ports 'eth1'
|
||||||
|
|
||||||
|
config switch 'switch'
|
||||||
|
option name 'switch0'
|
||||||
|
option reset '1'
|
||||||
|
option enable_vlan '1'
|
||||||
|
|
||||||
|
config switch_vlan 'switch_vlan1'
|
||||||
|
option device 'switch0'
|
||||||
|
option vlan '1'
|
||||||
|
option ports '1 2 3 4 0t'
|
||||||
|
|
||||||
8
backup/etc/config/nut_cgi
Normal file
8
backup/etc/config/nut_cgi
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
config upsset
|
||||||
|
|
||||||
|
config host 'tripplite'
|
||||||
|
option upsname 'tripplite'
|
||||||
|
option hostname 'localhost'
|
||||||
|
option displayname 'Local UPS'
|
||||||
|
|
||||||
17
backup/etc/config/nut_monitor
Normal file
17
backup/etc/config/nut_monitor
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
config upsmon 'upsmon'
|
||||||
|
option minsupplies '1'
|
||||||
|
option shutdowncmd '/sbin/halt'
|
||||||
|
option pollfreq '5'
|
||||||
|
option pollfreqalert '5'
|
||||||
|
option hostsync '15'
|
||||||
|
option deadtime '15'
|
||||||
|
option finaldelay '5'
|
||||||
|
|
||||||
|
config master 'tripplite'
|
||||||
|
option upsname 'tripplite'
|
||||||
|
option hostname 'localhost'
|
||||||
|
option powervalue '1'
|
||||||
|
option username 'upsmon'
|
||||||
|
option password 'nutlocal'
|
||||||
|
|
||||||
24
backup/etc/config/nut_server
Normal file
24
backup/etc/config/nut_server
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
config driver 'tripplite'
|
||||||
|
option driver 'usbhid-ups'
|
||||||
|
option port 'auto'
|
||||||
|
option desc 'Local UPS'
|
||||||
|
option pollinterval '5'
|
||||||
|
option vendorid '09ae'
|
||||||
|
option productid '3015'
|
||||||
|
|
||||||
|
config listen_address 'listen1'
|
||||||
|
option address '127.0.0.1'
|
||||||
|
|
||||||
|
config user 'upsmon_user'
|
||||||
|
option username 'upsmon'
|
||||||
|
option password 'nutlocal'
|
||||||
|
option upsmon 'master'
|
||||||
|
|
||||||
|
config user
|
||||||
|
option username 'monitor'
|
||||||
|
option upsmon 'slave'
|
||||||
|
|
||||||
|
config listen_address
|
||||||
|
option address '0.0.0.0'
|
||||||
|
|
||||||
139
backup/etc/config/snmpd
Normal file
139
backup/etc/config/snmpd
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
|
||||||
|
config agent
|
||||||
|
option agentaddress 'UDP:161,UDP6:161'
|
||||||
|
|
||||||
|
config agentx
|
||||||
|
option agentxsocket '/var/run/agentx.sock'
|
||||||
|
|
||||||
|
config com2sec 'public'
|
||||||
|
option secname 'ro'
|
||||||
|
option source 'default'
|
||||||
|
option community 'fsr'
|
||||||
|
|
||||||
|
config com2sec 'private'
|
||||||
|
option secname 'rw'
|
||||||
|
option source 'localhost'
|
||||||
|
option community 'private'
|
||||||
|
|
||||||
|
config com2sec6 'public6'
|
||||||
|
option secname 'ro'
|
||||||
|
option source 'default'
|
||||||
|
option community 'fsr'
|
||||||
|
|
||||||
|
config com2sec6 'private6'
|
||||||
|
option secname 'rw'
|
||||||
|
option source 'localhost'
|
||||||
|
option community 'private'
|
||||||
|
|
||||||
|
config group 'public_v1'
|
||||||
|
option group 'public'
|
||||||
|
option version 'v1'
|
||||||
|
option secname 'ro'
|
||||||
|
|
||||||
|
config group 'public_v2c'
|
||||||
|
option group 'public'
|
||||||
|
option version 'v2c'
|
||||||
|
option secname 'ro'
|
||||||
|
|
||||||
|
config group 'public_usm'
|
||||||
|
option group 'public'
|
||||||
|
option version 'usm'
|
||||||
|
option secname 'ro'
|
||||||
|
|
||||||
|
config group 'private_v1'
|
||||||
|
option group 'private'
|
||||||
|
option version 'v1'
|
||||||
|
option secname 'rw'
|
||||||
|
|
||||||
|
config group 'private_v2c'
|
||||||
|
option group 'private'
|
||||||
|
option version 'v2c'
|
||||||
|
option secname 'rw'
|
||||||
|
|
||||||
|
config group 'private_usm'
|
||||||
|
option group 'private'
|
||||||
|
option version 'usm'
|
||||||
|
option secname 'rw'
|
||||||
|
|
||||||
|
config view 'all'
|
||||||
|
option viewname 'all'
|
||||||
|
option type 'included'
|
||||||
|
option oid '.1'
|
||||||
|
|
||||||
|
config access 'public_access'
|
||||||
|
option group 'public'
|
||||||
|
option context 'none'
|
||||||
|
option version 'any'
|
||||||
|
option level 'noauth'
|
||||||
|
option prefix 'exact'
|
||||||
|
option read 'all'
|
||||||
|
option write 'none'
|
||||||
|
option notify 'none'
|
||||||
|
|
||||||
|
config access 'private_access'
|
||||||
|
option group 'private'
|
||||||
|
option context 'none'
|
||||||
|
option version 'any'
|
||||||
|
option level 'noauth'
|
||||||
|
option prefix 'exact'
|
||||||
|
option read 'all'
|
||||||
|
option write 'all'
|
||||||
|
option notify 'all'
|
||||||
|
|
||||||
|
config system
|
||||||
|
option sysLocation 'office'
|
||||||
|
option sysContact 'bofh@example.com'
|
||||||
|
option sysName 'HeartOfGold'
|
||||||
|
|
||||||
|
config exec
|
||||||
|
option name 'filedescriptors'
|
||||||
|
option prog '/bin/cat'
|
||||||
|
option args '/proc/sys/fs/file-nr'
|
||||||
|
|
||||||
|
config engineid
|
||||||
|
option engineidtype '3'
|
||||||
|
option engineidnic 'eth0'
|
||||||
|
|
||||||
|
config snmpd 'general'
|
||||||
|
option enabled '1'
|
||||||
|
|
||||||
|
config extend 'battery_charge'
|
||||||
|
option name 'battery_charge'
|
||||||
|
option prog '/usr/bin/upsc'
|
||||||
|
option args 'tripplite@localhost battery.charge'
|
||||||
|
|
||||||
|
config extend 'battery_runtime'
|
||||||
|
option name 'battery_runtime'
|
||||||
|
option prog '/usr/bin/upsc'
|
||||||
|
option args 'tripplite@localhost battery.runtime'
|
||||||
|
|
||||||
|
config extend 'ups_load'
|
||||||
|
option name 'ups_load'
|
||||||
|
option prog '/usr/bin/upsc'
|
||||||
|
option args 'tripplite@localhost ups.load'
|
||||||
|
|
||||||
|
config extend 'input_voltage'
|
||||||
|
option name 'input_voltage'
|
||||||
|
option prog '/usr/bin/upsc'
|
||||||
|
option args 'tripplite@localhost input.voltage'
|
||||||
|
|
||||||
|
config extend 'output_voltage'
|
||||||
|
option name 'output_voltage'
|
||||||
|
option prog '/usr/bin/upsc'
|
||||||
|
option args 'tripplite@localhost output.voltage'
|
||||||
|
|
||||||
|
config extend 'ups_status'
|
||||||
|
option name 'ups_status'
|
||||||
|
option prog '/usr/bin/upsc'
|
||||||
|
option args 'tripplite@localhost ups.status'
|
||||||
|
|
||||||
|
config extend 'battery_temp'
|
||||||
|
option name 'battery_temp'
|
||||||
|
option prog '/usr/bin/upsc'
|
||||||
|
option args 'tripplite@localhost battery.temperature'
|
||||||
|
|
||||||
|
config extend 'battery_voltage'
|
||||||
|
option name 'battery_voltage'
|
||||||
|
option prog '/usr/bin/upsc'
|
||||||
|
option args 'tripplite@localhost battery.voltage'
|
||||||
|
|
||||||
17
backup/etc/config/wireless
Normal file
17
backup/etc/config/wireless
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
config wifi-device 'radio0'
|
||||||
|
option type 'mac80211'
|
||||||
|
option path 'platform/ahb/18100000.wmac'
|
||||||
|
option band '2g'
|
||||||
|
option channel '1'
|
||||||
|
option htmode 'HT20'
|
||||||
|
option disabled '0'
|
||||||
|
|
||||||
|
config wifi-iface 'default_radio0'
|
||||||
|
option device 'radio0'
|
||||||
|
option network 'wifi_ap'
|
||||||
|
option mode 'ap'
|
||||||
|
option ssid 'First Step Internet'
|
||||||
|
option encryption 'psk2'
|
||||||
|
option key '12345678'
|
||||||
|
|
||||||
21
backup/etc/hotplug.d/usb/99-nut-ups
Normal file
21
backup/etc/hotplug.d/usb/99-nut-ups
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Auto-restart NUT when Tripp Lite UPS is plugged/unplugged
|
||||||
|
UPS_VENDOR="09ae"
|
||||||
|
|
||||||
|
case "$ACTION" in
|
||||||
|
add)
|
||||||
|
if echo "$PRODUCT" | grep -qi "^${UPS_VENDOR}"; then
|
||||||
|
# Fix USB device permissions so NUT driver (nut user) can access it
|
||||||
|
[ -n "$DEVNAME" ] && chmod 0660 "/dev/$DEVNAME" && chown root:nut "/dev/$DEVNAME"
|
||||||
|
logger -t NUT "Tripp Lite UPS connected (PRODUCT=$PRODUCT) - restarting NUT"
|
||||||
|
sleep 3
|
||||||
|
/etc/init.d/nut-server restart
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
remove)
|
||||||
|
if echo "$PRODUCT" | grep -qi "^${UPS_VENDOR}"; then
|
||||||
|
logger -t NUT "Tripp Lite UPS disconnected - restarting NUT"
|
||||||
|
/etc/init.d/nut-server restart
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
8
backup/etc/rc.local
Normal file
8
backup/etc/rc.local
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Put your custom commands here that should be executed once
|
||||||
|
# the system init finished. By default this file does nothing.
|
||||||
|
|
||||||
|
mkdir -p /var/etc/nut
|
||||||
|
chgrp nut /var/etc/nut
|
||||||
|
chmod 750 /var/etc/nut
|
||||||
|
|
||||||
|
exit 0
|
||||||
BIN
backup/openwrt-backup.tar.gz
Normal file
BIN
backup/openwrt-backup.tar.gz
Normal file
Binary file not shown.
100
backup/www/cgi-bin/wifi.cgi
Executable file
100
backup/www/cgi-bin/wifi.cgi
Executable file
@@ -0,0 +1,100 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
urldecode() {
|
||||||
|
echo -e "$(echo "$1" | sed "s/+/ /g; s/%\([0-9A-Fa-f][0-9A-Fa-f]\)/\\\\x\1/g")"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||||
|
read -n "$CONTENT_LENGTH" POST_DATA 2>/dev/null
|
||||||
|
action=$(echo "$POST_DATA" | tr "&" "\n" | grep "^action=" | cut -d= -f2-)
|
||||||
|
new_ssid=$(echo "$POST_DATA" | tr "&" "\n" | grep "^ssid=" | cut -d= -f2-)
|
||||||
|
new_key=$(echo "$POST_DATA" | tr "&" "\n" | grep "^key=" | cut -d= -f2-)
|
||||||
|
new_ssid=$(urldecode "$new_ssid")
|
||||||
|
new_key=$(urldecode "$new_key")
|
||||||
|
|
||||||
|
case "$action" in
|
||||||
|
toggle)
|
||||||
|
disabled=$(uci get wireless.radio0.disabled 2>/dev/null || echo 0)
|
||||||
|
if [ "$disabled" = "1" ]; then
|
||||||
|
uci set wireless.radio0.disabled="0"
|
||||||
|
uci commit wireless
|
||||||
|
wifi up &
|
||||||
|
else
|
||||||
|
uci set wireless.radio0.disabled="1"
|
||||||
|
uci commit wireless
|
||||||
|
wifi down &
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
update)
|
||||||
|
[ -n "$new_ssid" ] && uci set wireless.default_radio0.ssid="$new_ssid"
|
||||||
|
[ -n "$new_key" ] && [ ${#new_key} -ge 8 ] && uci set wireless.default_radio0.key="$new_key"
|
||||||
|
uci commit wireless
|
||||||
|
wifi reload &
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
disabled=$(uci get wireless.radio0.disabled 2>/dev/null || echo 0)
|
||||||
|
ssid=$(uci get wireless.default_radio0.ssid 2>/dev/null)
|
||||||
|
[ "$disabled" = "1" ] && wstatus="Disabled" && wcolor="#dc2626" && toggle_lbl="Enable WiFi" \
|
||||||
|
|| wstatus="Enabled" && wcolor="#16a34a" && toggle_lbl="Disable WiFi"
|
||||||
|
|
||||||
|
echo "Content-Type: text/html"
|
||||||
|
echo ""
|
||||||
|
cat << HTML
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>WiFi Control</title>
|
||||||
|
<style>
|
||||||
|
*{box-sizing:border-box;margin:0;padding:0}
|
||||||
|
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;background:#f1f5f9;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:20px}
|
||||||
|
.card{background:#fff;border-radius:12px;box-shadow:0 4px 6px rgba(0,0,0,.1);padding:32px;width:100%;max-width:400px}
|
||||||
|
h1{font-size:1.3rem;color:#0f172a;margin-bottom:20px}
|
||||||
|
.status{display:flex;align-items:center;gap:10px;background:#f8fafc;border-radius:8px;padding:12px 16px;margin-bottom:20px}
|
||||||
|
.dot{width:10px;height:10px;border-radius:50%;background:${wcolor};flex-shrink:0}
|
||||||
|
.slabel{font-size:.8rem;color:#64748b}
|
||||||
|
.sval{font-weight:700;color:${wcolor}}
|
||||||
|
.ssid{font-size:.85rem;color:#475569;margin-top:2px}
|
||||||
|
.btn{width:100%;padding:11px;border:none;border-radius:8px;font-size:.9rem;font-weight:600;cursor:pointer}
|
||||||
|
.btn-toggle{background:#0f172a;color:#fff;margin-bottom:20px}
|
||||||
|
.btn-toggle:hover{background:#1e293b}
|
||||||
|
.divider{border:none;border-top:1px solid #e2e8f0;margin-bottom:20px}
|
||||||
|
label{display:block;font-size:.75rem;font-weight:700;color:#64748b;text-transform:uppercase;letter-spacing:.05em;margin-bottom:5px}
|
||||||
|
input{width:100%;padding:9px 12px;border:1px solid #e2e8f0;border-radius:8px;font-size:.9rem;margin-bottom:14px;outline:none}
|
||||||
|
input:focus{border-color:#0284c7;box-shadow:0 0 0 2px rgba(2,132,199,.15)}
|
||||||
|
.btn-save{background:#0284c7;color:#fff}
|
||||||
|
.btn-save:hover{background:#0369a1}
|
||||||
|
.note{font-size:.75rem;color:#94a3b8;margin-top:12px;text-align:center}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="card">
|
||||||
|
<h1>WiFi Control</h1>
|
||||||
|
<div class="status">
|
||||||
|
<div class="dot"></div>
|
||||||
|
<div>
|
||||||
|
<div class="slabel">Status: <span class="sval">${wstatus}</span></div>
|
||||||
|
<div class="ssid">SSID: ${ssid}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form method="POST">
|
||||||
|
<input type="hidden" name="action" value="toggle">
|
||||||
|
<button class="btn btn-toggle">${toggle_lbl}</button>
|
||||||
|
</form>
|
||||||
|
<hr class="divider">
|
||||||
|
<form method="POST">
|
||||||
|
<input type="hidden" name="action" value="update">
|
||||||
|
<label>SSID</label>
|
||||||
|
<input type="text" name="ssid" value="${ssid}" placeholder="Network name">
|
||||||
|
<label>Password <span style="font-weight:400;text-transform:none">(min 8 chars — blank = no change)</span></label>
|
||||||
|
<input type="password" name="key" placeholder="••••••••">
|
||||||
|
<button class="btn btn-save">Save & Apply</button>
|
||||||
|
</form>
|
||||||
|
<p class="note">Changes apply within ~5 seconds</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
HTML
|
||||||
9
deploy.sh
Executable file
9
deploy.sh
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Run the install script on the OpenWrt device.
|
||||||
|
# Usage: ./deploy.sh [user@host]
|
||||||
|
set -e
|
||||||
|
|
||||||
|
HOST="${1:-root@20.0.0.26}"
|
||||||
|
echo "==> Deploying to $HOST"
|
||||||
|
scp -O openwrt/install.sh "$HOST":/tmp/ups-install.sh
|
||||||
|
ssh "$HOST" "chmod +x /tmp/ups-install.sh && /tmp/ups-install.sh"
|
||||||
323
openwrt/install.sh
Executable file
323
openwrt/install.sh
Executable file
@@ -0,0 +1,323 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Run on the OpenWrt device (20.0.0.26) to install and configure NUT + snmpd
|
||||||
|
# Also configures: bridge LAN ports, static IP, WiFi AP, DHCP on WiFi only
|
||||||
|
# Usage: sh /tmp/ups-install.sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "==> Updating package lists..."
|
||||||
|
opkg update
|
||||||
|
|
||||||
|
echo "==> Installing NUT..."
|
||||||
|
opkg install nut nut-server nut-upsmon
|
||||||
|
opkg install nut-driver-usbhid-ups || opkg install nut-usbhid-ups || true
|
||||||
|
opkg install kmod-usb-hid 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "==> Installing LuCI NUT config page and web CGI status..."
|
||||||
|
opkg install luci-app-nut
|
||||||
|
|
||||||
|
echo "==> Installing snmpd (full NET-SNMP with extend support)..."
|
||||||
|
/etc/init.d/mini_snmpd stop 2>/dev/null || true
|
||||||
|
/etc/init.d/mini_snmpd disable 2>/dev/null || true
|
||||||
|
opkg remove mini_snmpd 2>/dev/null || true
|
||||||
|
opkg install snmpd luci-app-snmpd
|
||||||
|
|
||||||
|
echo "==> Configuring NUT via UCI..."
|
||||||
|
uci set nut_server.tripplite=driver
|
||||||
|
uci set nut_server.tripplite.driver='usbhid-ups'
|
||||||
|
uci set nut_server.tripplite.port='auto'
|
||||||
|
uci set nut_server.tripplite.desc='Local UPS'
|
||||||
|
uci set nut_server.tripplite.vendorid='09ae'
|
||||||
|
# No productid filter — matches any Tripp Lite USB UPS (SMART1500RMXL2UA, SU1500RTXL2Ua, etc.)
|
||||||
|
uci set nut_server.tripplite.pollinterval='5'
|
||||||
|
|
||||||
|
uci set nut_server.listen1=listen_address
|
||||||
|
uci set nut_server.listen1.address='127.0.0.1'
|
||||||
|
|
||||||
|
uci set nut_server.upsmon_user=user
|
||||||
|
uci set nut_server.upsmon_user.username='upsmon'
|
||||||
|
uci set nut_server.upsmon_user.password='nutlocal'
|
||||||
|
uci set nut_server.upsmon_user.upsmon='master'
|
||||||
|
|
||||||
|
# Read-only passwordless monitor account for CGI stats page
|
||||||
|
uci set nut_server.monitor_ro=user
|
||||||
|
uci set nut_server.monitor_ro.username='monitor'
|
||||||
|
uci set nut_server.monitor_ro.upsmon='slave'
|
||||||
|
|
||||||
|
uci commit nut_server
|
||||||
|
|
||||||
|
uci set nut_monitor.upsmon=upsmon
|
||||||
|
uci set nut_monitor.upsmon.minsupplies='1'
|
||||||
|
uci set nut_monitor.upsmon.shutdowncmd='/sbin/halt'
|
||||||
|
uci set nut_monitor.upsmon.pollfreq='5'
|
||||||
|
uci set nut_monitor.upsmon.pollfreqalert='5'
|
||||||
|
uci set nut_monitor.upsmon.hostsync='15'
|
||||||
|
uci set nut_monitor.upsmon.deadtime='15'
|
||||||
|
uci set nut_monitor.upsmon.finaldelay='5'
|
||||||
|
|
||||||
|
uci set nut_monitor.tripplite=master
|
||||||
|
uci set nut_monitor.tripplite.upsname='tripplite'
|
||||||
|
uci set nut_monitor.tripplite.hostname='localhost'
|
||||||
|
uci set nut_monitor.tripplite.powervalue='1'
|
||||||
|
uci set nut_monitor.tripplite.username='upsmon'
|
||||||
|
uci set nut_monitor.tripplite.password='nutlocal'
|
||||||
|
|
||||||
|
uci commit nut_monitor
|
||||||
|
|
||||||
|
uci set nut_cgi.tripplite=host
|
||||||
|
uci set nut_cgi.tripplite.upsname='tripplite'
|
||||||
|
uci set nut_cgi.tripplite.hostname='localhost'
|
||||||
|
uci set nut_cgi.tripplite.displayname='Local UPS'
|
||||||
|
uci commit nut_cgi
|
||||||
|
|
||||||
|
echo "==> Configuring snmpd community and UPS extend entries via UCI..."
|
||||||
|
uci set snmpd.public.community='fsr'
|
||||||
|
uci set snmpd.public6.community='fsr'
|
||||||
|
|
||||||
|
for name in battery_charge battery_runtime ups_load input_voltage output_voltage ups_status battery_temp battery_voltage; do
|
||||||
|
# Map UCI name back to NUT variable (underscores -> dots, battery_temp -> battery.temperature)
|
||||||
|
nut_var=$(echo "$name" | tr '_' '.')
|
||||||
|
[ "$name" = "battery_temp" ] && nut_var="battery.temperature"
|
||||||
|
uci set snmpd.${name}=extend
|
||||||
|
uci set snmpd.${name}.name="$name"
|
||||||
|
uci set snmpd.${name}.prog='/usr/bin/upsc'
|
||||||
|
uci set snmpd.${name}.args="tripplite@localhost $nut_var"
|
||||||
|
done
|
||||||
|
uci commit snmpd
|
||||||
|
|
||||||
|
echo "==> Fixing /var/etc/nut directory permissions (persists via rc.local)..."
|
||||||
|
mkdir -p /var/etc/nut
|
||||||
|
chgrp nut /var/etc/nut
|
||||||
|
chmod 750 /var/etc/nut
|
||||||
|
|
||||||
|
grep -q 'var/etc/nut' /etc/rc.local 2>/dev/null || \
|
||||||
|
sed -i 's|^exit 0|mkdir -p /var/etc/nut\nchgrp nut /var/etc/nut\nchmod 750 /var/etc/nut\n\nexit 0|' /etc/rc.local
|
||||||
|
|
||||||
|
echo "==> Creating /etc/nut symlinks to UCI-generated configs..."
|
||||||
|
for f in ups.conf upsd.conf upsd.users nut.conf; do
|
||||||
|
rm -f /etc/nut/$f
|
||||||
|
ln -sf /var/etc/nut/$f /etc/nut/$f
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "==> Enabling services..."
|
||||||
|
/etc/init.d/nut-server enable
|
||||||
|
/etc/init.d/nut-monitor enable
|
||||||
|
/etc/init.d/nut-cgi enable
|
||||||
|
/etc/init.d/snmpd enable
|
||||||
|
|
||||||
|
echo "==> Writing USB hotplug script for automatic NUT restart on UPS connect/disconnect..."
|
||||||
|
cat > /etc/hotplug.d/usb/99-nut-ups << 'HOTPLUG'
|
||||||
|
#!/bin/sh
|
||||||
|
# Auto-restart NUT when Tripp Lite UPS is plugged/unplugged
|
||||||
|
UPS_VENDOR="09ae"
|
||||||
|
|
||||||
|
case "$ACTION" in
|
||||||
|
add)
|
||||||
|
if echo "$PRODUCT" | grep -qi "^${UPS_VENDOR}"; then
|
||||||
|
# Fix USB device permissions so NUT driver (nut user) can access it
|
||||||
|
[ -n "$DEVNAME" ] && chmod 0660 "/dev/$DEVNAME" && chown root:nut "/dev/$DEVNAME"
|
||||||
|
logger -t NUT "Tripp Lite UPS connected (PRODUCT=$PRODUCT) - restarting NUT"
|
||||||
|
sleep 3
|
||||||
|
/etc/init.d/nut-server restart
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
remove)
|
||||||
|
if echo "$PRODUCT" | grep -qi "^${UPS_VENDOR}"; then
|
||||||
|
logger -t NUT "Tripp Lite UPS disconnected - restarting NUT"
|
||||||
|
/etc/init.d/nut-server restart
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
HOTPLUG
|
||||||
|
chmod +x /etc/hotplug.d/usb/99-nut-ups
|
||||||
|
|
||||||
|
echo "==> Removing HTTP basic auth from NUT CGI path (upsstats.cgi accessible without login)..."
|
||||||
|
# nut-web-cgi installs /etc/httpd.conf with auth on /cgi-bin/nut — clear it so upsstats.cgi
|
||||||
|
# is viewable without a username/password (upsset.cgi still requires upsd credentials)
|
||||||
|
> /etc/httpd.conf
|
||||||
|
|
||||||
|
echo "==> Starting services..."
|
||||||
|
/etc/init.d/nut-server restart
|
||||||
|
sleep 10
|
||||||
|
/etc/init.d/nut-monitor restart
|
||||||
|
sleep 2
|
||||||
|
/etc/init.d/nut-cgi restart
|
||||||
|
/etc/init.d/snmpd restart
|
||||||
|
|
||||||
|
echo "==> Configuring network (bridge eth0.1+eth1, static 20.0.0.26/24, WiFi AP 192.168.88.1/24)..."
|
||||||
|
uci batch << 'EOF'
|
||||||
|
delete network.wan
|
||||||
|
delete network.wan6
|
||||||
|
set network.loopback=interface
|
||||||
|
set network.loopback.device='lo'
|
||||||
|
set network.loopback.proto='static'
|
||||||
|
set network.loopback.ipaddr='127.0.0.1'
|
||||||
|
set network.loopback.netmask='255.0.0.0'
|
||||||
|
set network.globals=globals
|
||||||
|
set network.globals.ula_prefix='fd6b:e811:df87::/48'
|
||||||
|
set network.br_lan_dev=device
|
||||||
|
set network.br_lan_dev.name='br-lan'
|
||||||
|
set network.br_lan_dev.type='bridge'
|
||||||
|
del_list network.br_lan_dev.ports='eth0.1'
|
||||||
|
del_list network.br_lan_dev.ports='eth1'
|
||||||
|
add_list network.br_lan_dev.ports='eth0.1'
|
||||||
|
add_list network.br_lan_dev.ports='eth1'
|
||||||
|
set network.lan=interface
|
||||||
|
set network.lan.device='br-lan'
|
||||||
|
set network.lan.proto='static'
|
||||||
|
set network.lan.ipaddr='20.0.0.26'
|
||||||
|
set network.lan.netmask='255.255.255.0'
|
||||||
|
set network.lan.gateway='20.0.0.1'
|
||||||
|
set network.lan.dns='20.0.0.1'
|
||||||
|
set network.wifi_ap=interface
|
||||||
|
set network.wifi_ap.proto='static'
|
||||||
|
set network.wifi_ap.ipaddr='192.168.88.1'
|
||||||
|
set network.wifi_ap.netmask='255.255.255.0'
|
||||||
|
EOF
|
||||||
|
uci commit network
|
||||||
|
|
||||||
|
echo "==> Configuring switch VLAN (all wired ports on VLAN 1)..."
|
||||||
|
uci set network.switch=switch
|
||||||
|
uci set network.switch.name='switch0'
|
||||||
|
uci set network.switch.reset='1'
|
||||||
|
uci set network.switch.enable_vlan='1'
|
||||||
|
uci set network.switch_vlan1=switch_vlan
|
||||||
|
uci set network.switch_vlan1.device='switch0'
|
||||||
|
uci set network.switch_vlan1.vlan='1'
|
||||||
|
uci set network.switch_vlan1.ports='1 2 3 4 0t'
|
||||||
|
uci commit network
|
||||||
|
|
||||||
|
echo "==> Configuring wireless (SSID: fsr, WPA2, AP on wifi_ap interface)..."
|
||||||
|
uci set wireless.radio0.disabled='0'
|
||||||
|
uci set wireless.default_radio0=wifi-iface
|
||||||
|
uci set wireless.default_radio0.device='radio0'
|
||||||
|
uci set wireless.default_radio0.network='wifi_ap'
|
||||||
|
uci set wireless.default_radio0.mode='ap'
|
||||||
|
uci set wireless.default_radio0.ssid='First Step Internet'
|
||||||
|
uci set wireless.default_radio0.encryption='psk2'
|
||||||
|
uci set wireless.default_radio0.key='12345678'
|
||||||
|
uci commit wireless
|
||||||
|
|
||||||
|
echo "==> Configuring DHCP (disabled on lan, enabled on wifi_ap 192.168.88.100-199)..."
|
||||||
|
uci set dhcp.lan.ignore='1'
|
||||||
|
uci set dhcp.wifi_ap=dhcp
|
||||||
|
uci set dhcp.wifi_ap.interface='wifi_ap'
|
||||||
|
uci set dhcp.wifi_ap.start='100'
|
||||||
|
uci set dhcp.wifi_ap.limit='100'
|
||||||
|
uci set dhcp.wifi_ap.leasetime='12h'
|
||||||
|
uci commit dhcp
|
||||||
|
|
||||||
|
echo "==> Writing WiFi control CGI page..."
|
||||||
|
mkdir -p /www/cgi-bin
|
||||||
|
cat > /www/cgi-bin/wifi.cgi << 'CGISCRIPT'
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
urldecode() {
|
||||||
|
echo -e "$(echo "$1" | sed "s/+/ /g; s/%\([0-9A-Fa-f][0-9A-Fa-f]\)/\\\\x\1/g")"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$REQUEST_METHOD" = "POST" ]; then
|
||||||
|
read -n "$CONTENT_LENGTH" POST_DATA 2>/dev/null
|
||||||
|
action=$(echo "$POST_DATA" | tr "&" "\n" | grep "^action=" | cut -d= -f2-)
|
||||||
|
new_ssid=$(echo "$POST_DATA" | tr "&" "\n" | grep "^ssid=" | cut -d= -f2-)
|
||||||
|
new_key=$(echo "$POST_DATA" | tr "&" "\n" | grep "^key=" | cut -d= -f2-)
|
||||||
|
new_ssid=$(urldecode "$new_ssid")
|
||||||
|
new_key=$(urldecode "$new_key")
|
||||||
|
|
||||||
|
case "$action" in
|
||||||
|
toggle)
|
||||||
|
disabled=$(uci get wireless.radio0.disabled 2>/dev/null || echo 0)
|
||||||
|
if [ "$disabled" = "1" ]; then
|
||||||
|
uci set wireless.radio0.disabled="0"
|
||||||
|
uci commit wireless
|
||||||
|
wifi up &
|
||||||
|
else
|
||||||
|
uci set wireless.radio0.disabled="1"
|
||||||
|
uci commit wireless
|
||||||
|
wifi down &
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
update)
|
||||||
|
[ -n "$new_ssid" ] && uci set wireless.default_radio0.ssid="$new_ssid"
|
||||||
|
[ -n "$new_key" ] && [ ${#new_key} -ge 8 ] && uci set wireless.default_radio0.key="$new_key"
|
||||||
|
uci commit wireless
|
||||||
|
wifi reload &
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
disabled=$(uci get wireless.radio0.disabled 2>/dev/null || echo 0)
|
||||||
|
ssid=$(uci get wireless.default_radio0.ssid 2>/dev/null)
|
||||||
|
[ "$disabled" = "1" ] && wstatus="Disabled" && wcolor="#dc2626" && toggle_lbl="Enable WiFi" \
|
||||||
|
|| wstatus="Enabled" && wcolor="#16a34a" && toggle_lbl="Disable WiFi"
|
||||||
|
|
||||||
|
echo "Content-Type: text/html"
|
||||||
|
echo ""
|
||||||
|
cat << HTML
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>WiFi Control</title>
|
||||||
|
<style>
|
||||||
|
*{box-sizing:border-box;margin:0;padding:0}
|
||||||
|
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;background:#f1f5f9;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:20px}
|
||||||
|
.card{background:#fff;border-radius:12px;box-shadow:0 4px 6px rgba(0,0,0,.1);padding:32px;width:100%;max-width:400px}
|
||||||
|
h1{font-size:1.3rem;color:#0f172a;margin-bottom:20px}
|
||||||
|
.status{display:flex;align-items:center;gap:10px;background:#f8fafc;border-radius:8px;padding:12px 16px;margin-bottom:20px}
|
||||||
|
.dot{width:10px;height:10px;border-radius:50%;background:${wcolor};flex-shrink:0}
|
||||||
|
.slabel{font-size:.8rem;color:#64748b}
|
||||||
|
.sval{font-weight:700;color:${wcolor}}
|
||||||
|
.ssid{font-size:.85rem;color:#475569;margin-top:2px}
|
||||||
|
.btn{width:100%;padding:11px;border:none;border-radius:8px;font-size:.9rem;font-weight:600;cursor:pointer}
|
||||||
|
.btn-toggle{background:#0f172a;color:#fff;margin-bottom:20px}
|
||||||
|
.btn-toggle:hover{background:#1e293b}
|
||||||
|
.divider{border:none;border-top:1px solid #e2e8f0;margin-bottom:20px}
|
||||||
|
label{display:block;font-size:.75rem;font-weight:700;color:#64748b;text-transform:uppercase;letter-spacing:.05em;margin-bottom:5px}
|
||||||
|
input{width:100%;padding:9px 12px;border:1px solid #e2e8f0;border-radius:8px;font-size:.9rem;margin-bottom:14px;outline:none}
|
||||||
|
input:focus{border-color:#0284c7;box-shadow:0 0 0 2px rgba(2,132,199,.15)}
|
||||||
|
.btn-save{background:#0284c7;color:#fff}
|
||||||
|
.btn-save:hover{background:#0369a1}
|
||||||
|
.note{font-size:.75rem;color:#94a3b8;margin-top:12px;text-align:center}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="card">
|
||||||
|
<h1>WiFi Control</h1>
|
||||||
|
<div class="status">
|
||||||
|
<div class="dot"></div>
|
||||||
|
<div>
|
||||||
|
<div class="slabel">Status: <span class="sval">${wstatus}</span></div>
|
||||||
|
<div class="ssid">SSID: ${ssid}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form method="POST">
|
||||||
|
<input type="hidden" name="action" value="toggle">
|
||||||
|
<button class="btn btn-toggle">${toggle_lbl}</button>
|
||||||
|
</form>
|
||||||
|
<hr class="divider">
|
||||||
|
<form method="POST">
|
||||||
|
<input type="hidden" name="action" value="update">
|
||||||
|
<label>SSID</label>
|
||||||
|
<input type="text" name="ssid" value="${ssid}" placeholder="Network name">
|
||||||
|
<label>Password <span style="font-weight:400;text-transform:none">(min 8 chars — blank = no change)</span></label>
|
||||||
|
<input type="password" name="key" placeholder="••••••••">
|
||||||
|
<button class="btn btn-save">Save & Apply</button>
|
||||||
|
</form>
|
||||||
|
<p class="note">Changes apply within ~5 seconds</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
HTML
|
||||||
|
CGISCRIPT
|
||||||
|
chmod +x /www/cgi-bin/wifi.cgi
|
||||||
|
|
||||||
|
echo "==> Applying network config (router will be reachable at 20.0.0.26 in ~5s)..."
|
||||||
|
( sleep 3 && /etc/init.d/network reload && wifi up ) &
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "==> Done!"
|
||||||
|
echo " UPS status page: http://20.0.0.26/cgi-bin/nut/upsstats.cgi"
|
||||||
|
echo " WiFi control: http://20.0.0.26/cgi-bin/wifi.cgi"
|
||||||
|
echo " CLI: upsc tripplite@localhost"
|
||||||
|
echo " SNMP test: snmpwalk -v2c -c fsr 20.0.0.26 .1.3.6.1.4.1.8072.1.3.2"
|
||||||
116
readme.md
Normal file
116
readme.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# OpenWrt UPS SNMP
|
||||||
|
|
||||||
|
Sets up NUT (Network UPS Tools) on a MikroTik 951Ui-2HnD running OpenWrt (20.0.0.26)
|
||||||
|
to monitor a Tripp Lite SMART1500 UPS connected via USB.
|
||||||
|
|
||||||
|
- **View UPS status** in the LuCI web interface (Services → UPS)
|
||||||
|
- **SNMP exposure** so the UPS data is queryable from the network like the RouterOS device at 10.223.135.242
|
||||||
|
|
||||||
|
SNMP community: `fsr`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
1. **NUT `usbhid-ups` driver** talks to the Tripp Lite over USB
|
||||||
|
2. **`upsd`** serves UPS data locally on `127.0.0.1:3493`
|
||||||
|
3. **`luci-app-nut`** adds a UPS status page to the LuCI web UI
|
||||||
|
4. **`net-snmp` extend** entries call `upsc` to expose each UPS metric as an SNMP OID
|
||||||
|
|
||||||
|
This mirrors what RouterOS does natively for its connected UPS.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deploy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./deploy.sh root@20.0.0.26
|
||||||
|
```
|
||||||
|
|
||||||
|
Or manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scp -r openwrt/etc/nut root@20.0.0.26:/etc/
|
||||||
|
scp -r openwrt/etc/snmp root@20.0.0.26:/etc/
|
||||||
|
scp openwrt/install.sh root@20.0.0.26:/tmp/ups-install.sh
|
||||||
|
ssh root@20.0.0.26 "sh /tmp/ups-install.sh"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Viewing UPS status
|
||||||
|
|
||||||
|
**UPS status web page (nut-web-cgi):**
|
||||||
|
```
|
||||||
|
http://20.0.0.26/cgi-bin/nut/upsstats.cgi
|
||||||
|
```
|
||||||
|
|
||||||
|
**LuCI — NUT configuration only** (not live status):
|
||||||
|
http://20.0.0.26 → Services → NUT Server / NUT Monitor
|
||||||
|
|
||||||
|
**CLI on the router:**
|
||||||
|
```bash
|
||||||
|
upsc tripplite@localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
**SNMP from the network:**
|
||||||
|
```bash
|
||||||
|
snmpwalk -v2c -c fsr 20.0.0.26 .1.3.6.1.4.1.8072.1.3.2
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## SNMP OIDs
|
||||||
|
|
||||||
|
UPS data is exposed under the NET-SNMP extend tree. Query with `snmpwalk` above or use
|
||||||
|
individual OIDs for polling tools (Zabbix, LibreNMS, PRTG, etc.).
|
||||||
|
|
||||||
|
| Extend name | UPS metric | Notes |
|
||||||
|
|-------------|-----------|-------|
|
||||||
|
| `battery_charge` | battery.charge | % |
|
||||||
|
| `battery_runtime` | battery.runtime | seconds |
|
||||||
|
| `ups_load` | ups.load | % |
|
||||||
|
| `input_voltage` | input.voltage | V |
|
||||||
|
| `output_voltage` | output.voltage | V |
|
||||||
|
| `ups_status` | ups.status | `OL`=online `OB`=on battery `LB`=low battery |
|
||||||
|
| `battery_temp` | battery.temperature | °C (may not be reported by all units) |
|
||||||
|
| `battery_voltage` | battery.voltage | V |
|
||||||
|
|
||||||
|
Each OID follows the pattern:
|
||||||
|
`.1.3.6.1.4.1.8072.1.3.2.3.1.2.<name-length>.<ascii-bytes-of-name>`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Packages installed
|
||||||
|
|
||||||
|
| Package | Purpose |
|
||||||
|
|---------|---------|
|
||||||
|
| `nut` | Core NUT tools (`upsc`, `upsmon`) |
|
||||||
|
| `nut-server` | `upsd` daemon |
|
||||||
|
| `nut-driver-usbhid-ups` | USB HID driver for Tripp Lite |
|
||||||
|
| `luci-app-nut` | UPS status page in LuCI |
|
||||||
|
| `net-snmp` | Full snmpd with extend support |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**UPS not found:**
|
||||||
|
```bash
|
||||||
|
lsusb | grep -i tripp # Tripp Lite vendor ID is 09AE
|
||||||
|
dmesg | grep -i hid
|
||||||
|
```
|
||||||
|
|
||||||
|
**`upsc` returns "connection failure":**
|
||||||
|
```bash
|
||||||
|
upsdrvctl stop && upsdrvctl start && upsd
|
||||||
|
```
|
||||||
|
|
||||||
|
**SNMP returns "No Such Object" for extend OIDs:**
|
||||||
|
- Make sure `net-snmp` is installed, not `mini-snmpd`
|
||||||
|
- Confirm `/etc/snmp/snmpd.conf` has the `extend` lines
|
||||||
|
- Test the extend command directly: `upsc tripplite@localhost battery.charge`
|
||||||
|
|
||||||
|
**SNMP not responding at all:**
|
||||||
|
- Check firewall allows UDP 161 inbound on OpenWrt
|
||||||
|
- Network → Firewall → Traffic Rules → add rule for SNMP
|
||||||
Reference in New Issue
Block a user