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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user