annotate pw2log.py @ 0:a5a196b3ba63

Initial version of powerwall logger
author Daniel O'Connor <darius@dons.net.au>
date Wed, 20 Nov 2019 13:12:45 +1030
parents
children 7edf54ec37f2
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1 #!/usr/bin/env python3
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
2
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
3 import configparser
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
4 import daemon
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
5 import daemon.pidfile
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
6 import datetime
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
7 import logging
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
8 from logging.handlers import RotatingFileHandler
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
9 import psycopg2
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
10 import requests
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
11 import sys
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
12 import tesla_powerwall # https://github.com/jrester/tesla_powerwall
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
13 import time
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
14
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
15 # Standard in 3.7..
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
16 class NullContextManager(object):
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
17 def __init__(self, dummy_resource=None):
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
18 self.dummy_resource = dummy_resource
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
19 def __enter__(self):
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
20 return self.dummy_resource
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
21 def __exit__(self, *args):
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
22 pass
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
23
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
24 # Otherwise it's very noisy
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
25 logging.getLogger('tesla_powerwall').setLevel(logging.WARN)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
26
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
27 def main():
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
28 if len(sys.argv) != 2:
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
29 print('Bad usage', file = sys.stderr)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
30 print('\t%s conf.ini' % (sys.argv[0]), file = sys.stderr)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
31 sys.exit(1)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
32
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
33 cp = configparser.ConfigParser()
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
34 cp.read(sys.argv[1])
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
35 if not cp.has_section('db'):
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
36 print('Config file missing db section', file = sys.stderr)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
37 sys.exit(1)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
38 if not cp.has_option('db', 'dsn'):
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
39 print('db section missing dsn parameter', file = sys.stderr)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
40 sys.exit(1)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
41 if not cp.has_option('db', 'logtime'):
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
42 print('db section missing logtime parameter', file = sys.stderr)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
43 sys.exit(1)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
44
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
45 if not cp.has_section('pw'):
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
46 print('Config file missing pw section', file = sys.stderr)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
47 sys.exit(1)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
48 if not cp.has_option('pw', 'ip'):
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
49 print('pw section missing ip parameter', file = sys.stderr)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
50 sys.exit(1)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
51
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
52 if cp.has_option('pw2log', 'logfile'):
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
53 logfile = cp.get('pw2log', 'logfile')
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
54 else:
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
55 logfile = None
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
56 if cp.has_option('pw2log', 'pidfile'):
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
57 pidfile = cp.get('pw2log', 'pidfile')
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
58 else:
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
59 pidfile = None
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
60
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
61 global logger
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
62 logger = logging.getLogger('pw2log')
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
63 logger.setLevel(logging.WARN)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
64 fmt = logging.Formatter('%(asctime)s: %(message)s', datefmt = '%Y/%m/%d %H:%M:%S')
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
65 if logfile == None:
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
66 ch = logging.StreamHandler()
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
67 ch.setFormatter(fmt)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
68 logger.addHandler(ch)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
69 else:
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
70 fh = RotatingFileHandler(logfile, maxBytes = 2000, backupCount = 10)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
71 fh.setFormatter(fmt)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
72 logger.addHandler(fh)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
73
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
74 if pidfile == None:
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
75 ctx = NullContextManager()
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
76 else:
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
77 ctx = daemon.DaemonContext(pidfile = daemon.pidfile.PIDLockFile(pidfile))
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
78
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
79 with ctx:
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
80 logger.critical('Starting')
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
81 collectdata(cp.get('pw', 'ip'), cp.get('db', 'dsn'), cp.getint('db', 'logtime'))
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
82
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
83 def collectdata(pwip, dsn, logtime):
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
84 dbh = psycopg2.connect(dsn)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
85 cur = dbh.cursor()
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
86
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
87 pw = tesla_powerwall.PowerWall(pwip)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
88
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
89 while True:
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
90 try:
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
91 # As per.. https://github.com/vloschiavo/powerwall2
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
92 # | | Load | Grid | Battery | Solar |
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
93 # |==========+==============+===================+======================+==================|
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
94 # | Positive | Supply house | Drawing from grid | Drawing from battery | Solar generation |
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
95 # | Negative | n/a | Feeding grid | Charging battery | n/a |
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
96 #
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
97 grid = pw.grid
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
98 load = pw.load
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
99 battery = pw.battery
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
100 solar = pw.solar
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
101 charge = pw.charge
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
102 except requests.ConnectionError as e:
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
103 logger.error('Error communicating with Powerwall: ' + str(e))
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
104 time.sleep(300)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
105 continue
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
106 try:
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
107 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)',
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
108 (datetime.datetime.now(), grid.instant_average_voltage, grid.frequency, grid.instant_power, load.instant_power, battery.instant_power, charge, solar.instant_power))
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
109 dbh.commit()
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
110 except psycopg2.OperationalError as e:
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
111 logger.error('Reconnecting after database error:' + str(e))
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
112 time.sleep(60)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
113 dbh = psycopg2.connect(dsn)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
114 cur = dbh.cursor()
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
115 continue
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
116
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
117 time.sleep(logtime)
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
118
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
119 def createdb(dbh):
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
120 cur = dbh.cursor()
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
121 cur.execute('''
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
122 CREATE TABLE pw2 (
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
123 date TIMESTAMP WITH TIME ZONE PRIMARY KEY,
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
124 grid_voltage REAL,
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
125 grid_freq REAL,
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
126 grid_power REAL,
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
127 load_power REAL,
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
128 battery_power REAL,
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
129 battery_charge REAL,
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
130 solar_power REAL
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
131 );
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
132 ''')
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
133 cur.execute('''
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
134 CREATE INDEX IF NOT EXISTS pw2_date_brin_idx ON pw2 USING brin (date);
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
135 ''')
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
136
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
137 if __name__ == '__main__':
a5a196b3ba63 Initial version of powerwall logger
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
138 main()