Initial commit

This commit is contained in:
Torsten Kurbad 2017-09-07 16:27:39 +02:00
commit 0273973538
2 changed files with 246 additions and 0 deletions

210
pyupsmon.py Normal file
View 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
View 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