Initial commit
This commit is contained in:
commit
0273973538
210
pyupsmon.py
Normal file
210
pyupsmon.py
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
#
|
||||||
|
# Depends on pyyaml!
|
||||||
|
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from serial import Serial
|
||||||
|
from threading import Timer
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
|
||||||
|
class ConvertUPS(Serial):
|
||||||
|
""" Class that implements monitoring for Wöhrle Convert-[123]000 UPS
|
||||||
|
devices connected via RS232.
|
||||||
|
Has to be initialized like serial.Serial().
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Class variables
|
||||||
|
_isOnBattery = False # Is UPS running on battery right now?
|
||||||
|
_powerToggled = False # Did power state (battery / AC) toggle recently?
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, configfile = '/etc/pyupsmon.yml', port = None,
|
||||||
|
baudrate = None, interval = None, shutdownTimeout = None,
|
||||||
|
shutdownCommand = None, debug = None, *args, **kwargs):
|
||||||
|
""" Read config file and/or set default config values. """
|
||||||
|
self.serialPort = port
|
||||||
|
self.serialBaud = baudrate
|
||||||
|
self.interval = interval
|
||||||
|
self.shutdownTimeout = shutdownTimeout
|
||||||
|
self.shutdownCommand = shutdownCommand
|
||||||
|
self.debug = debug
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(configfile, 'r') as ymlfile:
|
||||||
|
cfg = yaml.load(ymlfile)
|
||||||
|
|
||||||
|
if cfg.get('serial') is not None:
|
||||||
|
if self.serialPort is None:
|
||||||
|
self.serialPort = cfg['serial'].get('port', '/dev/ttyS0')
|
||||||
|
if self.serialBaud is None:
|
||||||
|
self.serialBaud = int(cfg['serial'].get('baudrate', 2400))
|
||||||
|
if cfg.get('daemon') is not None:
|
||||||
|
if self.interval is None:
|
||||||
|
self.interval = float(cfg['daemon'].get('interval', 1.0))
|
||||||
|
if self.debug is None:
|
||||||
|
self.debug = bool(cfg['daemon'].get('debug', False))
|
||||||
|
if cfg.get('shutdown') is not None:
|
||||||
|
if self.shutdownTimeout is None:
|
||||||
|
self.shutdownTimeout = float(cfg['shutdown'].get('timeout', 3600))
|
||||||
|
if self.shutdownCommand is None:
|
||||||
|
self.shutdownCommand = shlex.split(cfg['shutdown'].get('command', '/sbin/shutdown -h now'))
|
||||||
|
except OSError:
|
||||||
|
if debug:
|
||||||
|
print('Could not read config file %s.' % configfile)
|
||||||
|
|
||||||
|
if self.serialPort is None:
|
||||||
|
self.serialPort = '/dev/ttyS0'
|
||||||
|
if self.serialBaud is None:
|
||||||
|
self.serialBaud = 2400
|
||||||
|
if self.interval is None:
|
||||||
|
self.interval = 1.0
|
||||||
|
if self.debug is None:
|
||||||
|
self.debug = False
|
||||||
|
if self.shutdownTimeout is None:
|
||||||
|
self.shutdownTimeout = 3600.0
|
||||||
|
if self.shutdownCommand is None:
|
||||||
|
self.shutdownCommand = shlex.split('/sbin/shutdown -h now')
|
||||||
|
|
||||||
|
if self.debug:
|
||||||
|
print('Configuration:')
|
||||||
|
print('\tSerial Port:\t\t%s' % self.serialPort)
|
||||||
|
print('\tBaud Rate:\t\t%d' % self.serialBaud)
|
||||||
|
print('\tQuery Interval:\t\t%.2f s' % self.interval)
|
||||||
|
print('\tDebugging:\t\t%s' % self.debug)
|
||||||
|
print('\tShutdown Timeout:\t%.2f' % self.shutdownTimeout)
|
||||||
|
print('\tShutdown Command:\t%s' % self.shutdownCommand)
|
||||||
|
|
||||||
|
super(ConvertUPS, self).__init__(port = self.serialPort,
|
||||||
|
baudrate = self.serialBaud, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def upsInit(self):
|
||||||
|
""" Start communicating with the UPS. """
|
||||||
|
if not self.name:
|
||||||
|
if self.debug:
|
||||||
|
raise NameError('Please, set the serial communication parameters first.')
|
||||||
|
if self.debug:
|
||||||
|
print('Successfully connected to serial port %s' % (ups.name))
|
||||||
|
print('Sending initialization sequence (you should hear a short beep).')
|
||||||
|
|
||||||
|
self.write(b'CT\rDQ1\r')
|
||||||
|
sleep(5.0)
|
||||||
|
self.write(b'Rt\r')
|
||||||
|
sleep(3.0)
|
||||||
|
|
||||||
|
self.write(b'Q1\r')
|
||||||
|
sleep(1.0)
|
||||||
|
|
||||||
|
readbuffer = b''
|
||||||
|
data = self.read(1)
|
||||||
|
while b'\r' not in data:
|
||||||
|
readbuffer += data
|
||||||
|
data = self.read(1)
|
||||||
|
|
||||||
|
if readbuffer.strip().startswith(b'('):
|
||||||
|
if self.debug:
|
||||||
|
print('Initialization successful.')
|
||||||
|
print('Initial values returned:', readbuffer.strip())
|
||||||
|
return True
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def upsRead(self):
|
||||||
|
""" Read the current status of the UPS. """
|
||||||
|
ups.write(b'Q1\r')
|
||||||
|
readbuffer = b''
|
||||||
|
data = ups.read(1)
|
||||||
|
|
||||||
|
while b'\r' not in data:
|
||||||
|
readbuffer += data
|
||||||
|
data = ups.read(1)
|
||||||
|
if self.debug:
|
||||||
|
print(readbuffer.strip())
|
||||||
|
return readbuffer.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def isOnBattery(self):
|
||||||
|
""" Check whether UPS is on Battery. """
|
||||||
|
status = self.upsRead()
|
||||||
|
if status.startswith(b'(000.0 '):
|
||||||
|
if not self._isOnBattery:
|
||||||
|
self._isOnBattery = True
|
||||||
|
self._powerToggled = True
|
||||||
|
if self.debug:
|
||||||
|
print('UPS is on battery.')
|
||||||
|
else:
|
||||||
|
if self._isOnBattery:
|
||||||
|
self._isOnBattery = False
|
||||||
|
self._powerToggled = True
|
||||||
|
if self.debug:
|
||||||
|
print('UPS is on AC.')
|
||||||
|
return self._isOnBattery
|
||||||
|
|
||||||
|
|
||||||
|
def powerToggled(self):
|
||||||
|
""" Check if a power toggle (AC -> Battery or vice versa)
|
||||||
|
occured and reset the flag.
|
||||||
|
"""
|
||||||
|
onBattery = self.isOnBattery()
|
||||||
|
if self._powerToggled:
|
||||||
|
self._powerToggled = False
|
||||||
|
if self.debug:
|
||||||
|
print('Power toggle has occured recently.')
|
||||||
|
if onBattery:
|
||||||
|
return(True, True)
|
||||||
|
else:
|
||||||
|
return(True, False)
|
||||||
|
if self.debug:
|
||||||
|
print('No power toggle has occured recently.')
|
||||||
|
if onBattery:
|
||||||
|
return (False, True)
|
||||||
|
return (False, False)
|
||||||
|
|
||||||
|
|
||||||
|
def doShutdown(self):
|
||||||
|
""" Execute self.shutdownCommand. """
|
||||||
|
subprocess.call(self.shutdownCommand)
|
||||||
|
|
||||||
|
|
||||||
|
def startShutdownTimer(self):
|
||||||
|
""" Start a timer that executes self.shutdownCommand as soon as
|
||||||
|
self.shutdownTimeout has expired.
|
||||||
|
If self.shutdownTimeout == 0, the timer is disabled.
|
||||||
|
"""
|
||||||
|
if self.shutdownTimeout > 0:
|
||||||
|
self.timer = Timer(self.shutdownTimeout, self.doShutdown)
|
||||||
|
self.timer.start()
|
||||||
|
|
||||||
|
|
||||||
|
def cancelShutdownTimer(self):
|
||||||
|
""" Cancel a previously started shutdown timer. """
|
||||||
|
if self.timer is not None:
|
||||||
|
self.timer.cancel()
|
||||||
|
self.timer = None
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
#try:
|
||||||
|
ups = ConvertUPS()
|
||||||
|
#except:
|
||||||
|
# print('Error: Could not open UPS serial connection.')
|
||||||
|
# print('\tCheck the config file!')
|
||||||
|
# sys.exit(1)
|
||||||
|
|
||||||
|
if not ups.upsInit():
|
||||||
|
print('Error: Could not initialize UPS.')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
(toggled, onBatt) = ups.powerToggled()
|
||||||
|
if toggled:
|
||||||
|
if onBatt:
|
||||||
|
ups.startShutdownTimer()
|
||||||
|
if not onBatt:
|
||||||
|
ups.cancelShutdownTimer()
|
||||||
|
sleep(ups.interval)
|
36
pyupsmon.yml.example
Normal file
36
pyupsmon.yml.example
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Serial port parameters
|
||||||
|
serial:
|
||||||
|
# Serial port the UPS is connected to
|
||||||
|
#
|
||||||
|
# Default: /dev/ttyS0
|
||||||
|
#port: /dev/ttyS0
|
||||||
|
|
||||||
|
# Baud rate to set for the serial port
|
||||||
|
#
|
||||||
|
# Default: 2400
|
||||||
|
#baudrate: 2400
|
||||||
|
|
||||||
|
# Daemon settings
|
||||||
|
daemon:
|
||||||
|
# UPS query interval (in seconds)
|
||||||
|
#
|
||||||
|
# Default: 1.0
|
||||||
|
#interval: 2
|
||||||
|
|
||||||
|
# Enable debug output?
|
||||||
|
#
|
||||||
|
# Default: 0
|
||||||
|
#debug: 1
|
||||||
|
|
||||||
|
# Shutdown settings
|
||||||
|
shutdown:
|
||||||
|
# Shutdown the monitoring host after this many seconds
|
||||||
|
# on battery (0 to disable)
|
||||||
|
#
|
||||||
|
# Default: 3600.0
|
||||||
|
#timeout: 180.0
|
||||||
|
|
||||||
|
# Shutdown command to execute after timeout expired
|
||||||
|
#
|
||||||
|
# Default: /sbin/shutdown -h now
|
||||||
|
#command: /sbin/shutdown -h now
|
Loading…
Reference in New Issue
Block a user