annotate agl.py @ 1:6e3ca5bfda04

Improve plotting/timezone stuff. Still not very generic - MPL wants a name like 'Australia/Adelaide' but there sees to be no way to get that from dateutil or pytz.
author Daniel O'Connor <darius@dons.net.au>
date Sun, 10 Sep 2017 11:25:39 +0930
parents 8d6ba11c1b76
children 2b7fb26f9114
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
1 #!/usr/bin/env python
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
2
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
3 import ConfigParser
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
4 import datetime
1
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
5 import dateutil
0
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
6 import exceptions
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
7 import json
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
8 import os
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
9 import requests
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
10 import sqlite3
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
11 import sys
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
12
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
13 loginurl = 'https://command.aglsolar.com.au/api/v2/Account/LoginUser'
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
14 dataurl = 'https://command.aglsolar.com.au/api/v2/graph/b8e08afb-818f-4d2d-9d28-5afe8fc76a32'
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
15 # ?endDate=2017-08-23&granularity=Minute&metrics=read&startDate=2017-08-23&units=W'
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
16 logouturl = 'https://command.aglsolar.com.au/api/v2/Account/Logout'
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
17
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
18 class UTC(datetime.tzinfo):
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
19 def utcoffset(self, dt):
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
20 return datetime.timedelta(0)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
21
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
22 def dst(self, dt):
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
23 return datetime.timedelta(0)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
24
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
25 def tzname(self, dt):
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
26 return "UTC"
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
27
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
28
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
29 def main():
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
30 conf = ConfigParser.ConfigParser()
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
31 confname = os.environ['HOME'] + '/.agl.ini'
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
32 conf.read(confname)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
33 username = conf.get('DEFAULT', 'username')
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
34 password = conf.get('DEFAULT', 'password')
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
35 dbfn = conf.get('DEFAULT', 'db')
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
36
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
37 if conf.has_option('DEFAULT', 'token'):
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
38 token = conf.get('DEFAULT', 'token')
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
39 else:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
40 token = gettoken(username, password)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
41 conf.set('DEFAULT', 'token', token)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
42 conf.write(file(confname, 'w'))
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
43
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
44 if len(sys.argv) > 1:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
45 date = sys.argv[1]
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
46 else:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
47 date = datetime.datetime.now().strftime('%Y-%m-%d')
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
48
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
49 dbh = sqlite3.connect(dbfn, detect_types = sqlite3.PARSE_DECLTYPES)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
50 cur = dbh.cursor()
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
51 data = getdata(token, date, date)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
52 if data == None:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
53 token = gettoken(username, password)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
54 data = getdata(token, date, date)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
55 if data == None:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
56 print('Unable to fetch data')
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
57 updatedb(cur, data)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
58 dbh.commit()
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
59
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
60 def mkdb(cur):
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
61 cur.execute('''
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
62 CREATE TABLE IF NOT EXISTS agl (
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
63 t_stamp TIMESTAMP PRIMARY KEY,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
64 battery_charge NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
65 battery_power NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
66 power_consumed NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
67 power_expected NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
68 power_exported NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
69 power_generated NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
70 power_imported NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
71 estimated_savings NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
72 pv_forecast NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
73 pv_gen_battery NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
74 pv_gen_grid NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
75 pv_gen_site NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
76 site_cons_battery NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
77 site_cons_grid NUMBER,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
78 site_cons_pv NUMBER
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
79 )''')
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
80
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
81 units = {
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
82 'battery_charge' : '%',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
83 'battery_power' : 'Watt',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
84 'power_consumed' : 'Watt',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
85 'power_expected' : 'Watt',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
86 'power_exported' : 'Watt',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
87 'power_generated' : 'Watt',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
88 'power_imported' : 'Watt',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
89 'estimated_savings' : '$',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
90 'pv_forecast' : 'Watt',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
91 'pv_gen_battery' : 'Watt',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
92 'pv_gen_grid' : 'Watt',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
93 'pv_gen_site' : 'Watt',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
94 'site_cons_battery' : 'Watt',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
95 'site_cons_grid' : 'Watt',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
96 'site_cons_pv' : 'Watt'
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
97 }
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
98 def graph(cur, cols, start, end):
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
99 import numpy
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
100 import matplotlib
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
101 import matplotlib.dates
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
102 import matplotlib.pylab
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
103
1
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
104 colourlist = ['b','g','r','c','m','y','k']
0
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
105
1
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
106 # Work out what axes we are using
0
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
107 yaxisunits1 = None
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
108 yaxisunits2 = None
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
109 ax1lines = []
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
110 ax2lines = []
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
111 colouridx = 0
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
112 for col in cols:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
113 unit = units[col]
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
114 if yaxisunits1 == None:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
115 yaxisunits1 = unit
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
116 if yaxisunits2 == None:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
117 if unit != yaxisunits1:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
118 yaxisunits2 = unit
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
119 else:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
120 if unit != yaxisunits1 and unit != yaxisunits2:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
121 raise exceptions.Exception('Asked to graph >2 different units')
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
122
1
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
123 ltname = 'Australia/Adelaide'
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
124 lt = dateutil.tz.gettz(ltname)
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
125 utc = dateutil.tz.gettz('UTC')
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
126 matplotlib.rcParams['timezone'] = ltname
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
127
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
128 if start.tzinfo == None:
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
129 start = start.replace(tzinfo = lt)
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
130 if end.tzinfo == None:
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
131 end = end.replace(tzinfo = lt)
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
132
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
133 start = start.astimezone(utc)
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
134 end = end.astimezone(utc)
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
135
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
136 # Actually get the data
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
137 colstr = reduce(lambda a, b: a + ', ' + b, cols)
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
138 # Data is stored as naive datetime's which are in UTC so convert the requested time here
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
139 cur.execute('SELECT t_stamp, ' + colstr + ' FROM agl WHERE t_stamp > ? AND t_stamp < ? ORDER BY t_stamp',
0
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
140 (start, end))
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
141 ary = numpy.array(cur.fetchall())
1
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
142 # Convert naive UTC to proper UTC then adjust to local time
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
143 xdata = map(lambda f: f.replace(tzinfo = utc).astimezone(lt), ary[:,0])
0
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
144 for idx in range(len(cols)):
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
145 if units[cols[idx]] == yaxisunits1:
1
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
146 ax1lines.append([xdata, ary[:,idx + 1], cols[idx], colourlist[colouridx]])
0
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
147 else:
1
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
148 ax2lines.append([xdata, ary[:,idx + 1], cols[idx], colourlist[colouridx]])
0
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
149 colouridx += 1
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
150
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
151 fig = matplotlib.pylab.figure()
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
152 ax1 = fig.add_subplot(111)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
153 ax1.set_ylabel(yaxisunits1)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
154
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
155 for line in ax1lines:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
156 ax1.plot(line[0], line[1], label = line[2])
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
157
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
158 ax1.legend(loc = 'upper left')
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
159
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
160 if yaxisunits2 != None:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
161 ax2 = ax1.twinx()
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
162 ax2.set_ylabel(yaxisunits2)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
163
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
164 for line in ax2lines:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
165 ax2.plot(line[0], line[1], label = line[2], color = line[3])
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
166 ax2.legend(loc = 'upper right')
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
167
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
168 # Rotate X axis labels
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
169 for ax in fig.get_axes():
1
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
170 ax.set_xlim([start, end])
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
171 ax.xaxis.grid(True)
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
172 ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('%d %b\n%H:%M'))
0
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
173 ax.xaxis.set_major_locator(matplotlib.dates.HourLocator(interval = 2))
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
174 ax.xaxis.set_minor_locator(matplotlib.dates.MinuteLocator(interval = 5))
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
175 for label in ax.get_xticklabels():
1
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
176 label.set_ha('center')
6e3ca5bfda04 Improve plotting/timezone stuff.
Daniel O'Connor <darius@dons.net.au>
parents: 0
diff changeset
177 label.set_rotation(90)
0
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
178
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
179 # Fudge margins to give more graph and less space
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
180 fig.subplots_adjust(left = 0.10, right = 0.88, top = 0.95, bottom = 0.15)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
181 matplotlib.pyplot.show()
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
182
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
183 def updatedb(cur, data):
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
184 mkdb(cur)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
185 for d in data['reads']['data']:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
186 ts = datetime.datetime.strptime(d['t_stamp'], '%Y-%m-%dT%H:%M:%SZ')
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
187 # Note we rename *energy* to *power* here to match what it actually means
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
188 vals = [ts, d['battery_charge'], d['battery_energy'], d['energy_consumed'], d['energy_expected'], d['energy_exported'], d['energy_generated'],
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
189 d['energy_imported'], d['estimated_savings'], d['pv_forecast'], d['pv_generation']['battery_energy'],
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
190 d['pv_generation']['grid_energy'], d['pv_generation']['site_energy'], d['site_consumption']['battery_energy'],
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
191 d['site_consumption']['grid_energy'], d['site_consumption']['pv_energy']]
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
192 skip = True
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
193 for v in vals[1:]:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
194 if v != None:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
195 skip = False
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
196 break
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
197 if skip:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
198 print('Skipping empty record at ' + str(ts))
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
199 continue
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
200 cur.execute('INSERT OR IGNORE INTO agl(t_stamp, battery_charge, battery_power, power_consumed, power_expected, power_exported, power_generated, power_imported, estimated_savings, pv_forecast, pv_gen_battery, pv_gen_grid, pv_gen_site, site_cons_battery, site_cons_grid, site_cons_pv) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', vals)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
201
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
202 def gettoken(username, password):
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
203 authblob = json.encoder.JSONEncoder().encode({'email' : username, 'password' : password})
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
204 reply = requests.request('POST', loginurl, data = authblob, headers = {'Content-Type' : 'application/json'})
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
205 if reply.status_code != 200:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
206 return None
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
207 return json.decoder.JSONDecoder().decode(reply.content)['access_token']
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
208
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
209 def getdata(token, startdate, enddate):
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
210 reply = requests.request('GET', dataurl, params = {
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
211 'startDate' : startdate,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
212 'endDate' : enddate,
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
213 'granularity' : 'Minute',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
214 'metrics' : 'read',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
215 'units' : 'W',
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
216 }, headers = { 'Authorization' : 'Bearer ' + token})
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
217
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
218 if reply.status_code != 200:
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
219 return None
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
220
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
221 return json.decoder.JSONDecoder().decode(reply.content)
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
222
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
223 def logout(token):
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
224 reply = requests.request('GET', logouturl, headers = { 'Authorization' : 'Bearer ' + token})
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
225 return reply.status_code == 200
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
226
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
227 if __name__ == '__main__':
8d6ba11c1b76 Fetch & graphing code basically works.
Daniel O'Connor <darius@dons.net.au>
parents:
diff changeset
228 main()