# encoding: utf-8 # # Run snmp_temper.py as a pass-persist module for NetSNMP. # See README.md for instructions. # # Copyright 2012-2020 Philipp Adelt # # This code is licensed under the GNU public license (GPL). See LICENSE.md for details. import os import sys import syslog import threading import snmp_passpersist as snmp from temperusb.temper import TemperHandler, TemperDevice ERROR_TEMPERATURE = 9999 def _unbuffered_handle(fd): return os.fdopen(fd.fileno(), 'w', 0) class LogWriter(): def __init__(self, ident='temper-python', facility=syslog.LOG_DAEMON): syslog.openlog(ident, 0, facility) def write_log(self, message, prio=syslog.LOG_INFO): syslog.syslog(prio, message) class Updater(): def __init__(self, pp, logger, testmode=False): self.logger = logger self.pp = pp self.testmode = testmode self.usb_lock = threading.Lock() # used to stop reinitialization interfering with update-thread self._initialize() def _initialize(self): with self.usb_lock: try: self.th = TemperHandler() self.devs = self.th.get_devices() self.logger.write_log('Found %i thermometer devices.' % len(self.devs)) for i, d in enumerate(self.devs): self.logger.write_log('Initial temperature of device #%i: %0.1f degree celsius' % (i, d.get_temperature())) except Exception as e: self.logger.write_log('Exception while initializing: %s' % str(e)) def _reinitialize(self): # Tries to close all known devices and starts over. self.logger.write_log('Reinitializing devices') with self.usb_lock: for i,d in enumerate(self.devs): try: d.close() except Exception as e: self.logger.write_log('Exception closing device #%i: %s' % (i, str(e))) self._initialize() def update(self): if self.testmode: # APC Internal/Battery Temperature self.pp.add_int('318.1.1.1.2.2.2.0', 99) # Cisco devices temperature OIDs self.pp.add_int('9.9.13.1.3.1.3.1', 97) self.pp.add_int('9.9.13.1.3.1.3.2', 98) self.pp.add_int('9.9.13.1.3.1.3.3', 99) else: try: with self.usb_lock: temperatures = [d.get_temperature() for d in self.devs] self.pp.add_int('318.1.1.1.2.2.2.0', int(max(temperatures))) for i, temperature in enumerate(temperatures[:3]): # use max. first 3 devices self.pp.add_int('9.9.13.1.3.1.3.%i' % (i+1), int(temperature)) except Exception as e: self.logger.write_log('Exception while updating data: %s' % str(e)) # Report an exceptionally large temperature to set off all alarms. # snmp_passpersist does not expose an API to remove an OID. for oid in ('318.1.1.1.2.2.2.0', '9.9.13.1.3.1.3.1', '9.9.13.1.3.1.3.2', '9.9.13.1.3.1.3.3'): self.pp.add_int(oid, ERROR_TEMPERATURE) self.logger.write_log('Starting reinitialize after error on update') self._reinitialize() def main(): sys.stdout = _unbuffered_handle(sys.stdout) pp = snmp.PassPersist(".1.3.6.1.4.1") logger = LogWriter() upd = Updater(pp, logger, testmode=('--testmode' in sys.argv)) pp.start(upd.update, 5) # update every 5s if __name__ == '__main__': main()