Skip to content

Instantly share code, notes, and snippets.

@utdrmac
Last active December 10, 2021 17:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save utdrmac/48cc4ac31e5085b74a7a8dfeb317703f to your computer and use it in GitHub Desktop.
Save utdrmac/48cc4ac31e5085b74a7a8dfeb317703f to your computer and use it in GitHub Desktop.
Monitor UPS status and graph using RRD
#!/usr/bin/python
import time
import signal, sys, os, re
import rrdtool
import requests
#
# Add data points every second (step)
# Keep:
# - every step for 2 days
# - average every 60 steps and store for 7 days
#
# rrdtool create router.rrd \
# --step '1' \
# 'DS:inBytes:COUNTER:5:0:U' \
# 'DS:outBytes:COUNTER:5:0:U' \
# 'RRA:LAST:0.5:1:172800' \
# 'RRA:AVERAGE:0.5:60:10080'
def runloop():
url = "http://10.10.10.1:1980/control?WANCommonInterfaceConfig"
while True:
try:
# bytesOut
headers = {
'content-type': 'text/xml; charset="UTF-8"',
'connection': 'close',
'SOAPAction': 'urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1#GetTotalBytesSent'
}
payload = """<?xml version=\"1.0\"?>
<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">
<s:Body>
<u:GetTotalBytesSent xmlns:u=\"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1\"></u:GetTotalBytesSent>
</s:Body></s:Envelope>"""
r = requests.post(url, data=payload, headers=headers)
outBytes = re.search('<NewTotalBytesSent>(.*)</NewTotalBytesSent>', r.text, re.IGNORECASE).group(1)
# bytesIn
headers = {
'content-type': 'text/xml; charset="UTF-8"',
'connection': 'close',
'SOAPAction': 'urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1#GetTotalBytesReceived'
}
payload = """<?xml version=\"1.0\"?>
<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">
<s:Body>
<u:GetTotalBytesReceived xmlns:u=\"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1\"></u:GetTotalBytesReceived>
</s:Body></s:Envelope>"""
r = requests.post(url, data=payload, headers=headers)
inBytes = re.search('<NewTotalBytesReceived>(.*)</NewTotalBytesReceived>', r.text, re.IGNORECASE).group(1)
rrdtool.update("router.rrd", "N:%s:%s" % (str(inBytes), str(outBytes)))
time.sleep(1)
except KeyboardInterrupt:
print "Caught ctrl-c. Quitting..."
sys.exit(0)
except Exception as e:
print "Some other exception: "
print e
def signal_term_handler(signal, frame):
print 'got SIGTERM'
sys.exit(0)
signal.signal(signal.SIGTERM, signal_term_handler)
if __name__ == "__main__":
# Main entry
if len(sys.argv) == 1:
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError, e:
print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror)
sys.exit(1)
runloop()
#!/usr/bin/python
import PyNUT
import time
import signal, sys, os
import rrdtool
#
# Add data points every 5 seconds (step)
# Keep the last 8 days of data (last, min, max)
# of each datasource (DS) with per-step granularity
#
# rrdtool create ups.rrd \
# --step '5' \
# 'DS:load:GAUGE:10:0:50' \
# 'DS:voltage:GAUGE:10:0:140' \
# 'DS:charge:GAUGE:10:0:100' \
# 'RRA:LAST:0.5:1:138240' \
# 'RRA:MIN:0.5:1:138240' \
# 'RRA:MAX:0.5:1:138240'
def runloop():
nut = PyNUT.PyNUTClient( login="monuser", password="pass" )
while True:
try:
result = nut.GetUPSVars( "UPS" )
rrdtool.update("ups.rrd", "N:%s:%s:%s" %
(result["ups.load"].rstrip(),
result["input.voltage"].rstrip(),
result["battery.charge"].rstrip()))
time.sleep(5)
except KeyboardInterrupt:
print "Caught ctrl-c. Quitting..."
sys.exit(0)
except Exception as e:
print "Some other exception: "
print e
def signal_term_handler(signal, frame):
print 'got SIGTERM'
sys.exit(0)
signal.signal(signal.SIGTERM, signal_term_handler)
if __name__ == "__main__":
# Main entry
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError, e:
print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror)
sys.exit(1)
runloop()
[Unit]
Description=Collect Router Info
After=network.target
[Service]
Type=forking
ExecStart=/root/routermon/collect_router_stats.py
KillMode=process
Restart=on-failure
PIDFile=/var/run/collect_router_stats.pid
[Install]
WantedBy=multi-user.target
[Unit]
Description=Collect UPS Battery Info
After=network.target
[Service]
Type=forking
ExecStart=/root/upsmon/collect_ups_status.py
KillMode=process
Restart=on-failure
PIDFile=/var/run/collect_ups_status.pid
[Install]
WantedBy=multi-user.target
#!/bin/bash
/usr/bin/rrdtool graph \
'/frontview/dashboard/router.png' \
--title 'Network Traffic' \
--width '1280' --height '400' --full-size-mode \
--start end-4h \
'DEF:inBytes=/root/routermon/router.rrd:inBytes:LAST' \
'DEF:outBytes=/root/routermon/router.rrd:outBytes:LAST' \
'CDEF:inKB=inBytes,1024,/' \
'CDEF:outKB=outBytes,1024,/' \
'LINE1:inKB#00FF00:Inbound (KB/sec)' \
"GPRINT:inKB:LAST:%3.2lf %s\n" \
'LINE1:outKB#0000FF:Outbound (KB/sec)' \
"GPRINT:outKB:LAST:%3.2lf\n"
#!/bin/bash
/usr/bin/rrdtool graph \
'/frontview/dashboard/ups.png' \
--title 'UPS Status' \
--width '1280' --height '400' --full-size-mode \
--right-axis-label 'Load (amps)' \
--right-axis 0.125:0 \
--right-axis-format "%1.1lf" \
--start end-4h \
--upper-limit 150 \
--lower-limit 50 \
--rigid \
'DEF:LD=/root/upsmon/ups.rrd:load:LAST' \
'DEF:VT=/root/upsmon/ups.rrd:voltage:LAST' \
'DEF:CR=/root/upsmon/ups.rrd:charge:LAST' \
'CDEF:scaledLD=LD,8,*' \
'LINE2:scaledLD#003300:Load (Amps)' \
"GPRINT:LD:LAST:%3.2lf\n" \
'LINE2:VT#FF0000:Volts' \
"GPRINT:VT:LAST: %3.2lf\n" \
'LINE2:CR#66FF00:Charge (%)' \
"GPRINT:CR:LAST:%3.2lf\n"
<!DOCTYPE html>
<html>
<head>
<title>Network Status</title>
</head>
<body style="margin: 20px;">
<h2>UPS Status</h2>
<img src="ups.png" style="width: 1280px; height: 400px;" /><br/>
<h2>Router Status</h2>
<img src="router.png" style="width: 1280px; height: 400px;" />
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment