Mercurial > code > home > repos > homeauto
annotate service/powerEagle/reader.py @ 1523:0da337780f22
dep updates; graph url renames; and other build updates
Ignore-this: 4603ef3d8db650a13e543dad8580ade8
darcs-hash:0840491cd6a4e4966f47a2abca0ed30ec434022a
author | drewp <drewp@bigasterisk.com> |
---|---|
date | Wed, 05 Feb 2020 00:23:06 -0800 |
parents | 013af6808aca |
children | b87b6e9cedb2 |
rev | line source |
---|---|
1016 | 1 #!bin/python |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
2 import json, time, os, binascii, traceback |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
3 |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
4 from cyclone.httpclient import fetch |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
5 from docopt import docopt |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
6 from greplin import scales |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
7 from greplin.scales.cyclonehandler import StatsHandler |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
8 from influxdb import InfluxDBClient |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
9 from twisted.internet import reactor |
1016 | 10 from twisted.internet.defer import inlineCallbacks |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
11 import cyclone.web |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
12 |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
13 from standardservice.logsetup import log, verboseLogging |
1016 | 14 |
15 from private_config import deviceIp, cloudId, installId, macId, periodSec | |
16 | |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
17 STATS = scales.collection('/root', |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
18 scales.PmfStat('poll'), |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
19 ) |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
20 |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
21 authPlain = cloudId + ':' + installId |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
22 auth = binascii.b2a_base64(authPlain.encode('ascii')).strip(b'=\n') |
1016 | 23 |
24 class Poller(object): | |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
25 def __init__(self, influx): |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
26 self.influx = influx |
1017
3edda1f7a322
LoopingCall sets the interview between calls, but I want the period of calls
drewp <drewp@bigasterisk.com>
parents:
1016
diff
changeset
|
27 reactor.callLater(0, self.poll) |
1016 | 28 |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
29 @STATS.poll.time() |
1016 | 30 @inlineCallbacks |
31 def poll(self): | |
32 ret = None | |
1017
3edda1f7a322
LoopingCall sets the interview between calls, but I want the period of calls
drewp <drewp@bigasterisk.com>
parents:
1016
diff
changeset
|
33 startTime = time.time() |
1016 | 34 try: |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
35 url = (f'http://{deviceIp}/cgi-bin/cgi_manager').encode('ascii') |
1016 | 36 resp = yield fetch( |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
37 url, |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
38 method=b'POST', |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
39 headers={b'Authorization': [b'Basic %s' % auth]}, |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
40 postdata=(f'''<LocalCommand> |
1016 | 41 <Name>get_usage_data</Name> |
42 <MacId>0x{macId}</MacId> | |
43 </LocalCommand> | |
44 <LocalCommand> | |
45 <Name>get_price_blocks</Name> | |
46 <MacId>0x{macId}</MacId> | |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
47 </LocalCommand>''').encode('ascii'), |
1219
bff11263c71e
add request timeout. don't send NaN to influxdb. crash on failures.
drewp <drewp@bigasterisk.com>
parents:
1116
diff
changeset
|
48 timeout=10) |
1016 | 49 ret = json.loads(resp.body) |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
50 log.debug(ret) |
1016 | 51 if ret['demand_units'] != 'kW': |
52 raise ValueError | |
53 if ret['summation_units'] != 'kWh': | |
54 raise ValueError | |
1219
bff11263c71e
add request timeout. don't send NaN to influxdb. crash on failures.
drewp <drewp@bigasterisk.com>
parents:
1116
diff
changeset
|
55 pts = [ |
1116
d22c0c502ff6
powereagle reader writes to influxdb
drewp <drewp@bigasterisk.com>
parents:
1021
diff
changeset
|
56 dict(measurement='housePowerW', |
d22c0c502ff6
powereagle reader writes to influxdb
drewp <drewp@bigasterisk.com>
parents:
1021
diff
changeset
|
57 fields=dict(value=float(ret['demand']) * 1000), |
d22c0c502ff6
powereagle reader writes to influxdb
drewp <drewp@bigasterisk.com>
parents:
1021
diff
changeset
|
58 tags=dict(house='berkeley'), |
1219
bff11263c71e
add request timeout. don't send NaN to influxdb. crash on failures.
drewp <drewp@bigasterisk.com>
parents:
1116
diff
changeset
|
59 time=int(startTime))] |
bff11263c71e
add request timeout. don't send NaN to influxdb. crash on failures.
drewp <drewp@bigasterisk.com>
parents:
1116
diff
changeset
|
60 sd = float(ret['summation_delivered']) |
bff11263c71e
add request timeout. don't send NaN to influxdb. crash on failures.
drewp <drewp@bigasterisk.com>
parents:
1116
diff
changeset
|
61 if sd > 0: # Sometimes nan |
bff11263c71e
add request timeout. don't send NaN to influxdb. crash on failures.
drewp <drewp@bigasterisk.com>
parents:
1116
diff
changeset
|
62 pts.append(dict(measurement='housePowerSumDeliveredKwh', |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
63 fields=dict(value=float()), |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
64 tags=dict(house='berkeley'), |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
65 time=int(startTime))) |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
66 if 'price' in ret: |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
67 pts.append(dict( |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
68 measurement='price', |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
69 fields=dict(price=float(ret['price']), |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
70 price_units=float(ret['price_units'])), |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
71 tags=dict(house='berkeley'), |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
72 time=int(startTime), |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
73 )) |
1219
bff11263c71e
add request timeout. don't send NaN to influxdb. crash on failures.
drewp <drewp@bigasterisk.com>
parents:
1116
diff
changeset
|
74 |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
75 self.influx.write_points(pts, time_precision='s') |
1016 | 76 except Exception as e: |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
77 traceback.print_exc() |
1016 | 78 log.error("failed: %r", e) |
79 log.error(repr(ret)) | |
1219
bff11263c71e
add request timeout. don't send NaN to influxdb. crash on failures.
drewp <drewp@bigasterisk.com>
parents:
1116
diff
changeset
|
80 os.abort() |
1016 | 81 |
1017
3edda1f7a322
LoopingCall sets the interview between calls, but I want the period of calls
drewp <drewp@bigasterisk.com>
parents:
1016
diff
changeset
|
82 now = time.time() |
1021
b8540cba5c66
fudge timing to not miss data points
drewp <drewp@bigasterisk.com>
parents:
1017
diff
changeset
|
83 goal = startTime + periodSec - .2 |
1017
3edda1f7a322
LoopingCall sets the interview between calls, but I want the period of calls
drewp <drewp@bigasterisk.com>
parents:
1016
diff
changeset
|
84 reactor.callLater(max(1, goal - now), self.poll) |
1016 | 85 |
86 | |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
87 if __name__ == '__main__': |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
88 arg = docopt(""" |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
89 Usage: reader.py [options] |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
90 |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
91 -v Verbose |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
92 --port PORT Serve on port [default: 10016]. |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
93 """) |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
94 verboseLogging(arg['-v']) |
1116
d22c0c502ff6
powereagle reader writes to influxdb
drewp <drewp@bigasterisk.com>
parents:
1021
diff
changeset
|
95 |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
96 influx = InfluxDBClient('bang', 9060, 'root', 'root', 'main') |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
97 p = Poller(influx) |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
98 |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
99 reactor.listenTCP( |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
100 int(arg['--port']), |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
101 cyclone.web.Application( |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
102 [ |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
103 (r'/stats/(.*)', StatsHandler, {'serverName': 'powerEagle'}), |
1523
0da337780f22
dep updates; graph url renames; and other build updates
drewp <drewp@bigasterisk.com>
parents:
1335
diff
changeset
|
104 (r"/graph/power", CycloneGraphHandler, {'masterGraph': masterGraph}), |
0da337780f22
dep updates; graph url renames; and other build updates
drewp <drewp@bigasterisk.com>
parents:
1335
diff
changeset
|
105 (r"/graph/power/events", CycloneGraphEventsHandler, {'masterGraph': masterGraph}), |
1335
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
106 ], |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
107 )) |
013af6808aca
update powereagle to py3, be a server with /stats/, save 'price' field
drewp <drewp@bigasterisk.com>
parents:
1219
diff
changeset
|
108 reactor.run() |