Mercurial > ~darius > hgwebdir.cgi > vanlogger
comparison graph.py @ 15:c04c75360a3b
Fix timezone screw up.
Remove cut & paste code from the AGL script
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Fri, 23 Feb 2018 14:57:45 +1030 |
parents | aa18210c2703 |
children | 29a61ec4755b |
comparison
equal
deleted
inserted
replaced
14:aa18210c2703 | 15:c04c75360a3b |
---|---|
112 | 112 |
113 if args.start.tzinfo == None: | 113 if args.start.tzinfo == None: |
114 args.start = args.start.replace(tzinfo = lt) | 114 args.start = args.start.replace(tzinfo = lt) |
115 if args.end.tzinfo == None: | 115 if args.end.tzinfo == None: |
116 args.end = args.end.replace(tzinfo = lt) | 116 args.end = args.end.replace(tzinfo = lt) |
117 startlt = args.start | |
118 endlt = args.end | |
119 args.start = args.start.astimezone(utc) | |
120 args.end = args.end.astimezone(utc) | |
121 graph(args.graphfn, cur, cols, args.start, args.end, lt, utc) | 117 graph(args.graphfn, cur, cols, args.start, args.end, lt, utc) |
122 | 118 |
123 def graph(fname, cur, _cols, start, end, lt, utc): | 119 def graph(fname, cur, _cols, start, end, lt, utc): |
124 import numpy | 120 import numpy |
125 import matplotlib | 121 import matplotlib |
161 cur.execute('SELECT tstamp, ' + c.rowname + ' FROM ' + c.table + ' WHERE tstamp > ? AND tstamp < ? ORDER BY tstamp', | 157 cur.execute('SELECT tstamp, ' + c.rowname + ' FROM ' + c.table + ' WHERE tstamp > ? AND tstamp < ? ORDER BY tstamp', |
162 (startepoch, endepoch)) | 158 (startepoch, endepoch)) |
163 ary = numpy.array(cur.fetchall()) | 159 ary = numpy.array(cur.fetchall()) |
164 if ary.shape[0] == 0: | 160 if ary.shape[0] == 0: |
165 print('No data for ' + c.rowname) | 161 print('No data for ' + c.rowname) |
166 return | 162 continue |
167 | 163 |
168 # Create TZ naive from POSIX stamp, then convert to TZ aware UTC then adjust to local time | 164 # Convert epoch stamp to datetime with UTC timezone |
169 c.xdata = map(lambda f: datetime.datetime.fromtimestamp(f).replace(tzinfo = utc).astimezone(lt), ary[:,0]) | 165 c.xdata = map(lambda f: datetime.datetime.utcfromtimestamp(f).replace(tzinfo = utc), ary[:,0]) |
170 c.ydata = ary[:,1] | 166 c.ydata = ary[:,1] |
171 if c.conv != None: | 167 if c.conv != None: |
172 c.ydata = map(c.conv, c.ydata) | 168 c.ydata = map(c.conv, c.ydata) |
173 | 169 |
174 scale_min, scale_max = c.limits | 170 scale_min, scale_max = c.limits |
185 else: | 181 else: |
186 ax = ax2lines | 182 ax = ax2lines |
187 c.colour = colourlist[colouridx] | 183 c.colour = colourlist[colouridx] |
188 colouridx += 1 | 184 colouridx += 1 |
189 ax.append(c) | 185 ax.append(c) |
186 | |
187 if len(ax1lines) == 0 and len(ax2lines) == 0: | |
188 print('Nothing to plot') | |
189 return | |
190 | 190 |
191 # Load the right backend for display or save | 191 # Load the right backend for display or save |
192 if fname == None: | 192 if fname == None: |
193 import matplotlib.pylab | 193 import matplotlib.pylab |
194 fig = matplotlib.pylab.figure() | 194 fig = matplotlib.pylab.figure() |
205 ax1.plot(line.xdata, line.ydata, label = line.title, color = line.colour) | 205 ax1.plot(line.xdata, line.ydata, label = line.title, color = line.colour) |
206 if line.limits[0] != None or line.limits[1] != None: | 206 if line.limits[0] != None or line.limits[1] != None: |
207 ax1.set_ylim(line.limits[0], line.limits[1]) | 207 ax1.set_ylim(line.limits[0], line.limits[1]) |
208 if line.annotation != None: | 208 if line.annotation != None: |
209 annotations.append(line.annotation) | 209 annotations.append(line.annotation) |
210 ax1.legend(loc = 'upper left') | 210 ax1.legend(loc = 'center left') |
211 | 211 |
212 if len(ax2lines) > 0: | 212 if len(ax2lines) > 0: |
213 ax2 = ax1.twinx() | 213 ax2 = ax1.twinx() |
214 ax2.set_ylabel(yaxisunits2) | 214 ax2.set_ylabel(yaxisunits2) |
215 | 215 |
218 if line.limits[0] != None or line.limits[1] != None: | 218 if line.limits[0] != None or line.limits[1] != None: |
219 ax2.set_ylim(line.limits[0], line.limits[1]) | 219 ax2.set_ylim(line.limits[0], line.limits[1]) |
220 if line.annotation != None: | 220 if line.annotation != None: |
221 annotations.append(line.annotation) | 221 annotations.append(line.annotation) |
222 | 222 |
223 ax2.legend(loc = 'upper right') | 223 ax2.legend(loc = 'center right') |
224 | 224 |
225 if len(annotations) > 0: | 225 if len(annotations) > 0: |
226 ax1.text(0.02, 0.5, reduce(lambda a, b: a + '\n' + b, annotations), | 226 ax1.text(0.02, 0.3, reduce(lambda a, b: a + '\n' + b, annotations), |
227 transform = ax1.transAxes, bbox = dict(facecolor = 'blue', alpha = 0.5), | 227 transform = ax1.transAxes, bbox = dict(facecolor = 'blue', alpha = 0.5), |
228 ha = 'left', va = 'top') | 228 ha = 'left', va = 'top') |
229 ndays = int(max(1, round(((end - start).total_seconds()) / 86400))) | 229 ndays = int(max(1, round(((end - start).total_seconds()) / 86400))) |
230 once = False | |
230 for ax in fig.get_axes(): | 231 for ax in fig.get_axes(): |
231 if ndays > 1: | 232 if not once: |
232 ax.set_title('%s to %s' % (start.strftime('%Y-%m-%d'), end.strftime('%Y-%m-%d'))) | 233 once = True |
233 else: | 234 if ndays > 1: |
234 ax.set_title('%s' % (start.strftime('%Y-%m-%d'))) | 235 ax.set_title('%s to %s' % (start.astimezone(lt).strftime('%Y-%m-%d'), end.astimezone(lt).strftime('%Y-%m-%d'))) |
235 ax.set_xlim([start, end]) | 236 else: |
236 ax.format_xdata = lambda d: matplotlib.dates.num2date(d).strftime('%d %b %H:%M') | 237 ax.set_title('%s' % (start.astimezone(lt).strftime('%Y-%m-%d'))) |
238 ax.set_xlim([start.astimezone(utc), end.astimezone(utc)]) | |
237 ax.xaxis.grid(True) | 239 ax.xaxis.grid(True) |
240 ax.xaxis.axis_date(lt) | |
238 ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('%d %b\n%H:%M')) | 241 ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('%d %b\n%H:%M')) |
239 ax.xaxis.set_major_locator(matplotlib.dates.HourLocator(interval = 2 * ndays)) | 242 ax.xaxis.set_major_locator(matplotlib.dates.HourLocator(interval = 2 * ndays)) |
240 ax.xaxis.set_minor_locator(matplotlib.dates.MinuteLocator(interval = 5 * ndays)) | 243 ax.xaxis.set_minor_locator(matplotlib.dates.MinuteLocator(interval = 5 * ndays)) |
241 for label in ax.get_xticklabels(): | 244 for label in ax.get_xticklabels(): |
242 label.set_ha('center') | 245 label.set_ha('center') |
248 matplotlib.pyplot.show() | 251 matplotlib.pyplot.show() |
249 else: | 252 else: |
250 canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(fig) # Sets canvas in fig too | 253 canvas = matplotlib.backends.backend_agg.FigureCanvasAgg(fig) # Sets canvas in fig too |
251 fig.savefig(startdt.strftime(fname)) | 254 fig.savefig(startdt.strftime(fname)) |
252 | 255 |
253 def updatedb(cur, data): | |
254 mkdb(cur) | |
255 for d in data['reads']['data']: | |
256 ts = datetime.datetime.strptime(d['t_stamp'], '%Y-%m-%dT%H:%M:%SZ') | |
257 # Note we rename *energy* to *power* here to match what it actually means | |
258 vals = [ts, d['battery_charge'], d['battery_energy'], d['energy_consumed'], d['energy_expected'], d['energy_exported'], d['energy_generated'], | |
259 d['energy_imported'], d['estimated_savings'], d['pv_forecast'], d['pv_generation']['battery_energy'], | |
260 d['pv_generation']['grid_energy'], d['pv_generation']['site_energy'], d['site_consumption']['battery_energy'], | |
261 d['site_consumption']['grid_energy'], d['site_consumption']['pv_energy']] | |
262 skip = True | |
263 for v in vals[1:]: | |
264 if v != None: | |
265 skip = False | |
266 break | |
267 if skip: | |
268 print('Skipping empty record at ' + str(ts)) | |
269 continue | |
270 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) | |
271 | |
272 def gettoken(username, password): | |
273 authblob = json.encoder.JSONEncoder().encode({'email' : username, 'password' : password}) | |
274 reply = requests.request('POST', loginurl, data = authblob, headers = {'Content-Type' : 'application/json'}) | |
275 if reply.status_code != 200: | |
276 return None | |
277 return json.decoder.JSONDecoder().decode(reply.content)['access_token'] | |
278 | |
279 def getdata(token, startdate, enddate): | |
280 #print('getting ' + startdate.strftime('%Y-%m-%d')) | |
281 reply = requests.request('GET', dataurl, params = { | |
282 'startDate' : startdate.strftime('%Y-%m-%d'), | |
283 'endDate' : enddate.strftime('%Y-%m-%d'), | |
284 'granularity' : 'Minute', | |
285 'metrics' : 'read', | |
286 'units' : 'W', | |
287 }, headers = { 'Authorization' : 'Bearer ' + token}) | |
288 | |
289 if reply.status_code != 200: | |
290 return None | |
291 | |
292 return json.decoder.JSONDecoder().decode(reply.content) | |
293 | |
294 def logout(token): | |
295 reply = requests.request('GET', logouturl, headers = { 'Authorization' : 'Bearer ' + token}) | |
296 return reply.status_code == 200 | |
297 | |
298 if __name__ == '__main__': | 256 if __name__ == '__main__': |
299 main() | 257 main() |