Mercurial > ~darius > hgwebdir.cgi > pw2log
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 |
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() |