Mercurial > ~darius > hgwebdir.cgi > pw2log
view pw2log.py @ 1:7edf54ec37f2
Improve logging.
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Tue, 18 Feb 2020 13:18:25 +1030 |
parents | a5a196b3ba63 |
children | 393a879db9eb |
line wrap: on
line source
#!/usr/bin/env python3 import configparser import daemon import daemon.pidfile import datetime import logging from logging.handlers import RotatingFileHandler import psycopg2 import requests import sys import tesla_powerwall # https://github.com/jrester/tesla_powerwall import time # Standard in 3.7.. class NullContextManager(object): def __init__(self, dummy_resource=None): self.dummy_resource = dummy_resource def __enter__(self): return self.dummy_resource def __exit__(self, *args): pass # Otherwise it's very noisy logging.getLogger('tesla_powerwall').setLevel(logging.WARN) def main(): if len(sys.argv) != 2: print('Bad usage', file = sys.stderr) print('\t%s conf.ini' % (sys.argv[0]), file = sys.stderr) sys.exit(1) cp = configparser.ConfigParser() cp.read(sys.argv[1]) if not cp.has_section('db'): print('Config file missing db section', file = sys.stderr) sys.exit(1) if not cp.has_option('db', 'dsn'): print('db section missing dsn parameter', file = sys.stderr) sys.exit(1) if not cp.has_option('db', 'logtime'): print('db section missing logtime parameter', file = sys.stderr) sys.exit(1) if not cp.has_section('pw'): print('Config file missing pw section', file = sys.stderr) sys.exit(1) if not cp.has_option('pw', 'ip'): print('pw section missing ip parameter', file = sys.stderr) sys.exit(1) if cp.has_option('pw2log', 'logfile'): logfile = cp.get('pw2log', 'logfile') else: logfile = None if cp.has_option('pw2log', 'pidfile'): pidfile = cp.get('pw2log', 'pidfile') else: pidfile = None global logger logger = logging.getLogger('pw2log') logger.setLevel(logging.WARN) fmt = logging.Formatter('%(asctime)s: %(message)s', datefmt = '%Y/%m/%d %H:%M:%S') if logfile == None: ch = logging.StreamHandler() ch.setFormatter(fmt) logger.addHandler(ch) keepfh = None else: fh = RotatingFileHandler(logfile, maxBytes = 2000, backupCount = 10) fh.setFormatter(fmt) logger.addHandler(fh) keepfhs = [fh.stream.fileno()] # XXX: gross if pidfile == None: ctx = NullContextManager() else: try: #fh = open('/tmp/pw2errs.log', 'a') fh = None ctx = daemon.DaemonContext(pidfile = daemon.pidfile.PIDLockFile(pidfile), stdout = fh, stderr = fh, files_preserve = keepfhs) except Exception as e: logger.critical('Unable to get daemon context') try: with ctx: logger.critical('Starting') try: collectdata(cp.get('pw', 'ip'), cp.get('db', 'dsn'), cp.getint('db', 'logtime')) except Exception as e: logger.critical('Unable to collect data: ' + str(e)) except Exception as e: logger.critical('Unable to enter daemon context: ' + str(e)) def collectdata(pwip, dsn, logtime): dbh = psycopg2.connect(dsn) cur = dbh.cursor() pw = tesla_powerwall.PowerWall(pwip) while True: try: # As per.. https://github.com/vloschiavo/powerwall2 # | | Load | Grid | Battery | Solar | # |==========+==============+===================+======================+==================| # | Positive | Supply house | Drawing from grid | Drawing from battery | Solar generation | # | Negative | n/a | Feeding grid | Charging battery | n/a | # grid = pw.grid load = pw.load battery = pw.battery solar = pw.solar charge = pw.charge except requests.ConnectionError as e: logger.error('Error communicating with Powerwall: ' + str(e)) time.sleep(300) continue try: cur.execute('INSERT INTO pw2 (date, grid_voltage, grid_freq, grid_power, load_power, battery_power, battery_charge, solar_power) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)', (datetime.datetime.now(), grid.instant_average_voltage, grid.frequency, grid.instant_power, load.instant_power, battery.instant_power, charge, solar.instant_power)) dbh.commit() except psycopg2.OperationalError as e: logger.error('Reconnecting after database error:' + str(e)) time.sleep(60) dbh = psycopg2.connect(dsn) cur = dbh.cursor() continue time.sleep(logtime) def createdb(dbh): cur = dbh.cursor() cur.execute(''' CREATE TABLE pw2 ( date TIMESTAMP WITH TIME ZONE PRIMARY KEY, grid_voltage REAL, grid_freq REAL, grid_power REAL, load_power REAL, battery_power REAL, battery_charge REAL, solar_power REAL ); ''') cur.execute(''' CREATE INDEX IF NOT EXISTS pw2_date_brin_idx ON pw2 USING brin (date); ''') if __name__ == '__main__': main()