comparison pw2log.py @ 2:393a879db9eb

Update to latest tesla_powerwall code changes.
author Daniel O'Connor <darius@dons.net.au>
date Tue, 09 Feb 2021 21:30:06 +1030
parents 7edf54ec37f2
children ec3c8b63d8e7
comparison
equal deleted inserted replaced
1:7edf54ec37f2 2:393a879db9eb
7 import logging 7 import logging
8 from logging.handlers import RotatingFileHandler 8 from logging.handlers import RotatingFileHandler
9 import psycopg2 9 import psycopg2
10 import requests 10 import requests
11 import sys 11 import sys
12 import tesla_powerwall # https://github.com/jrester/tesla_powerwall 12 # https://github.com/jrester/tesla_powerwall
13 from tesla_powerwall import APIError, Powerwall
13 import time 14 import time
14 15
15 # Standard in 3.7.. 16 # Standard in 3.7..
16 class NullContextManager(object): 17 class NullContextManager(object):
17 def __init__(self, dummy_resource=None): 18 def __init__(self, dummy_resource=None):
43 sys.exit(1) 44 sys.exit(1)
44 45
45 if not cp.has_section('pw'): 46 if not cp.has_section('pw'):
46 print('Config file missing pw section', file = sys.stderr) 47 print('Config file missing pw section', file = sys.stderr)
47 sys.exit(1) 48 sys.exit(1)
48 if not cp.has_option('pw', 'ip'): 49 for opt in ('ip', 'username', 'password'):
49 print('pw section missing ip parameter', file = sys.stderr) 50 if not cp.has_option('pw', opt):
50 sys.exit(1) 51 print('pw section missing %s parameter' % (opt,), file = sys.stderr)
52 sys.exit(1)
51 53
52 if cp.has_option('pw2log', 'logfile'): 54 if cp.has_option('pw2log', 'logfile'):
53 logfile = cp.get('pw2log', 'logfile') 55 logfile = cp.get('pw2log', 'logfile')
54 else: 56 else:
55 logfile = None 57 logfile = None
85 87
86 try: 88 try:
87 with ctx: 89 with ctx:
88 logger.critical('Starting') 90 logger.critical('Starting')
89 try: 91 try:
90 collectdata(cp.get('pw', 'ip'), cp.get('db', 'dsn'), cp.getint('db', 'logtime')) 92 collectdata(cp.get('pw', 'ip'), cp.get('pw', 'username'), cp.get('pw', 'password'), cp.get('db', 'dsn'), cp.getint('db', 'logtime'))
91 except Exception as e: 93 except Exception as e:
92 logger.critical('Unable to collect data: ' + str(e)) 94 logger.critical('Unable to collect data: ' + str(e))
93 except Exception as e: 95 except Exception as e:
94 logger.critical('Unable to enter daemon context: ' + str(e)) 96 logger.critical('Unable to enter daemon context: ' + str(e))
95 97
96 def collectdata(pwip, dsn, logtime): 98 def collectdata(pwip, username, password, dsn, logtime):
97 dbh = psycopg2.connect(dsn) 99 dbh = psycopg2.connect(dsn)
98 cur = dbh.cursor() 100 cur = dbh.cursor()
99 101 pw = None
100 pw = tesla_powerwall.PowerWall(pwip)
101 102
102 while True: 103 while True:
103 try: 104 try:
104 # As per.. https://github.com/vloschiavo/powerwall2 105 # As per.. https://github.com/vloschiavo/powerwall2
105 # | | Load | Grid | Battery | Solar | 106 # | | Load | Grid | Battery | Solar |
106 # |==========+==============+===================+======================+==================| 107 # |==========+==============+===================+======================+==================|
107 # | Positive | Supply house | Drawing from grid | Drawing from battery | Solar generation | 108 # | Positive | Supply house | Drawing from grid | Drawing from battery | Solar generation |
108 # | Negative | n/a | Feeding grid | Charging battery | n/a | 109 # | Negative | n/a | Feeding grid | Charging battery | n/a |
109 # 110 #
110 grid = pw.grid 111 if not pw:
111 load = pw.load 112 first = True
112 battery = pw.battery 113 pw = Powerwall(pwip)
113 solar = pw.solar 114 pw.login(username, password)
114 charge = pw.charge 115 pw.detect_and_pin_version()
115 except requests.ConnectionError as e: 116 meters = pw.get_meters()
117 grid_volts = meters.site.avarage_voltage
118 grid_freq = meters.site.avarage_voltage
119 grid_power = meters.site.instant_power
120 load_power = meters.load.instant_power
121 battery_power = meters.battery.instant_power
122 solar_power = meters.solar.instant_power
123 charge = pw.get_charge()
124 except APIError as e:
125 pw = None
116 logger.error('Error communicating with Powerwall: ' + str(e)) 126 logger.error('Error communicating with Powerwall: ' + str(e))
117 time.sleep(300) 127 time.sleep(300)
118 continue 128 continue
119 try: 129 try:
120 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)', 130 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)',
121 (datetime.datetime.now(), grid.instant_average_voltage, grid.frequency, grid.instant_power, load.instant_power, battery.instant_power, charge, solar.instant_power)) 131 (datetime.datetime.now(), grid_volts, grid_freq, grid_power, load_power, battery_power, charge, solar_power))
122 dbh.commit() 132 dbh.commit()
123 except psycopg2.OperationalError as e: 133 except psycopg2.OperationalError as e:
124 logger.error('Reconnecting after database error:' + str(e)) 134 logger.error('Reconnecting after database error:' + str(e))
125 time.sleep(60) 135 time.sleep(60)
126 dbh = psycopg2.connect(dsn) 136 dbh = psycopg2.connect(dsn)
127 cur = dbh.cursor() 137 cur = dbh.cursor()
128 continue 138 continue
139 if first:
140 logger.error('Logged OK')
141 first = False
129 142
130 time.sleep(logtime) 143 time.sleep(logtime)
131 144
132 def createdb(dbh): 145 def createdb(dbh):
133 cur = dbh.cursor() 146 cur = dbh.cursor()