Mercurial > code > home > repos > homeauto
annotate service/powerEagle/reader.py @ 1754:92999dfbf321 default tip
add shelly support
author | drewp@bigasterisk.com |
---|---|
date | Tue, 04 Jun 2024 13:03:43 -0700 |
parents | d012c53c5ae8 |
children |
rev | line source |
---|---|
786
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
1 import binascii |
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
2 import json |
1714 | 3 import logging |
1723 | 4 from pprint import pprint |
786
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
5 from typing import Dict |
532
71aa55cd8433
update powereagle to py3, be a server with /stats/, save 'price' field
drewp@bigasterisk.com
parents:
416
diff
changeset
|
6 |
1714 | 7 import aiohttp |
1719
fb082013fa24
port to use my background_loop lib. various other dep updates.
drewp@bigasterisk.com
parents:
1714
diff
changeset
|
8 import background_loop |
1714 | 9 from patchablegraph import PatchableGraph |
10 from patchablegraph.handler import GraphEvents, StaticGraph | |
1719
fb082013fa24
port to use my background_loop lib. various other dep updates.
drewp@bigasterisk.com
parents:
1714
diff
changeset
|
11 from prometheus_client import Gauge |
786
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
12 from rdflib import Literal, Namespace |
1714 | 13 from starlette.applications import Starlette |
14 from starlette.routing import Route | |
15 from starlette_exporter import PrometheusMiddleware, handle_metrics | |
532
71aa55cd8433
update powereagle to py3, be a server with /stats/, save 'price' field
drewp@bigasterisk.com
parents:
416
diff
changeset
|
16 |
1748
d012c53c5ae8
powereagle now registers a hostname with dhcp so we don't have to hunt for it
drewp@bigasterisk.com
parents:
1723
diff
changeset
|
17 from private_config import cloudId, deviceIp, deviceMac, installId, macId, periodSec |
1714 | 18 |
734 | 19 ROOM = Namespace("http://projects.bigasterisk.com/room/") |
211 | 20 |
1714 | 21 logging.basicConfig(level=logging.INFO) |
22 log = logging.getLogger() | |
23 | |
532
71aa55cd8433
update powereagle to py3, be a server with /stats/, save 'price' field
drewp@bigasterisk.com
parents:
416
diff
changeset
|
24 authPlain = cloudId + ':' + installId |
71aa55cd8433
update powereagle to py3, be a server with /stats/, save 'price' field
drewp@bigasterisk.com
parents:
416
diff
changeset
|
25 auth = binascii.b2a_base64(authPlain.encode('ascii')).strip(b'=\n') |
211 | 26 |
786
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
27 |
1723 | 28 |
211 | 29 class Poller(object): |
786
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
30 |
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
31 def __init__(self, out: Dict[str, Gauge], graph): |
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
32 self.out = out |
734 | 33 self.graph = graph |
1714 | 34 |
1719
fb082013fa24
port to use my background_loop lib. various other dep updates.
drewp@bigasterisk.com
parents:
1714
diff
changeset
|
35 async def poll(self, first_run: bool): |
1714 | 36 url = (f'http://{deviceIp}/cgi-bin/cgi_manager') |
37 | |
38 async with aiohttp.ClientSession() as session: | |
39 async with session.post(url, | |
40 headers={'Authorization': 'Basic %s' % auth.decode('ascii')}, | |
41 data=(f'''<LocalCommand> | |
42 <Name>get_usage_data</Name> | |
43 <MacId>0x{macId}</MacId> | |
44 </LocalCommand> | |
45 <LocalCommand> | |
46 <Name>get_price_blocks</Name> | |
47 <MacId>0x{macId}</MacId> | |
48 </LocalCommand>'''), | |
49 timeout=10) as response: | |
211 | 50 |
1714 | 51 ret = json.loads(await response.text()) |
52 log.debug(f"response body {ret}") | |
53 if ret['demand_units'] != 'kW': | |
54 raise ValueError | |
55 if ret['summation_units'] != 'kWh': | |
56 raise ValueError | |
57 | |
58 demandW = float(ret['demand']) * 1000 | |
59 self.out['w'].set(demandW) | |
786
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
60 |
1714 | 61 sd = float(ret['summation_delivered']) |
62 if sd > 0: # Sometimes nan | |
63 self.out['kwh'].set(sd) | |
734 | 64 |
1714 | 65 if 'price' in ret: |
66 self.out['price'].set(float(ret['price'])) | |
211 | 67 |
1714 | 68 self.graph.patchObject(context=ROOM['powerEagle'], |
69 subject=ROOM['housePower'], | |
70 predicate=ROOM['instantDemandWatts'], | |
71 newObject=Literal(demandW)) | |
211 | 72 |
73 | |
1714 | 74 def main(): |
75 masterGraph = PatchableGraph() | |
311 | 76 |
786
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
77 out = { |
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
78 'w': Gauge('house_power_w', 'house power demand'), |
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
79 'kwh': Gauge('house_power_kwh', 'house power sum delivered'), |
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
80 'price': Gauge('house_power_price', 'house power price'), |
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
81 } |
1714 | 82 |
786
e8654a3bd1c7
update powereagle for k8s and prometheus
drewp@bigasterisk.com
parents:
734
diff
changeset
|
83 p = Poller(out, masterGraph) |
532
71aa55cd8433
update powereagle to py3, be a server with /stats/, save 'price' field
drewp@bigasterisk.com
parents:
416
diff
changeset
|
84 |
1714 | 85 # todo: background_loop isn't trying to maintain a goal of periodSec |
1719
fb082013fa24
port to use my background_loop lib. various other dep updates.
drewp@bigasterisk.com
parents:
1714
diff
changeset
|
86 loop = background_loop.loop_forever(p.poll, periodSec) |
1714 | 87 |
88 app = Starlette(debug=True, | |
89 routes=[ | |
90 Route('/graph/power', StaticGraph(masterGraph)), | |
91 Route('/graph/power/events', GraphEvents(masterGraph)), | |
92 ]) | |
93 | |
94 app.add_middleware(PrometheusMiddleware, app_name='power_eagle') | |
95 app.add_route("/metrics", handle_metrics) | |
96 return app | |
97 | |
98 | |
99 app = main() |