Mercurial > code > home > repos > homeauto
changeset 532:71aa55cd8433
update powereagle to py3, be a server with /stats/, save 'price' field
Ignore-this: 1b738295b503fb7409311ddd637b7a18
author | drewp@bigasterisk.com |
---|---|
date | Tue, 23 Apr 2019 03:57:55 -0700 |
parents | f372e9d358d2 |
children | bb6b4988dd75 |
files | service/powerEagle/Dockerfile service/powerEagle/reader.py service/powerEagle/requirements.txt service/powerEagle/tasks.py |
diffstat | 4 files changed, 105 insertions(+), 27 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/powerEagle/Dockerfile Tue Apr 23 03:57:55 2019 -0700 @@ -0,0 +1,15 @@ +FROM bang6:5000/base_x86 + +WORKDIR /opt + +COPY requirements.txt ./ + +RUN pip3 install --index-url https://projects.bigasterisk.com/ --extra-index-url https://pypi.org/simple -r requirements.txt +# not sure why this doesn't work from inside requirements.txt +RUN pip3 install -U 'https://github.com/drewp/cyclone/archive/python3.zip?v3' + +COPY *.py *.html ./ + +EXPOSE 10016 + +CMD [ "python3", "reader.py" ]
--- a/service/powerEagle/reader.py Tue Apr 23 02:56:07 2019 -0700 +++ b/service/powerEagle/reader.py Tue Apr 23 03:57:55 2019 -0700 @@ -1,42 +1,53 @@ #!bin/python -import json, logging, time, os -import sys -sys.path.append("/my/proj/homeauto/lib") -from logsetup import log +import json, time, os, binascii, traceback + +from cyclone.httpclient import fetch +from docopt import docopt +from greplin import scales +from greplin.scales.cyclonehandler import StatsHandler +from influxdb import InfluxDBClient +from twisted.internet import reactor from twisted.internet.defer import inlineCallbacks -from twisted.internet import reactor -from cyclone.httpclient import fetch -from influxdb import InfluxDBClient +import cyclone.web + +from standardservice.logsetup import log, verboseLogging from private_config import deviceIp, cloudId, installId, macId, periodSec -auth = (cloudId + ':' + installId).encode('base64').strip() -influx = InfluxDBClient('bang', 9060, 'root', 'root', 'main') +STATS = scales.collection('/root', + scales.PmfStat('poll'), + ) + +authPlain = cloudId + ':' + installId +auth = binascii.b2a_base64(authPlain.encode('ascii')).strip(b'=\n') class Poller(object): - def __init__(self, carbon): - self.carbon = carbon + def __init__(self, influx): + self.influx = influx reactor.callLater(0, self.poll) + @STATS.poll.time() @inlineCallbacks def poll(self): ret = None startTime = time.time() try: + url = (f'http://{deviceIp}/cgi-bin/cgi_manager').encode('ascii') resp = yield fetch( - 'http://{deviceIp}/cgi-bin/cgi_manager'.format(deviceIp=deviceIp), - method='POST', - headers={'Authorization': ['Basic %s' % auth]}, - postdata='''<LocalCommand> + url, + method=b'POST', + headers={b'Authorization': [b'Basic %s' % auth]}, + postdata=(f'''<LocalCommand> <Name>get_usage_data</Name> <MacId>0x{macId}</MacId> </LocalCommand> <LocalCommand> <Name>get_price_blocks</Name> <MacId>0x{macId}</MacId> - </LocalCommand>'''.format(macId=macId), + </LocalCommand>''').encode('ascii'), timeout=10) ret = json.loads(resp.body) + log.debug(ret) if ret['demand_units'] != 'kW': raise ValueError if ret['summation_units'] != 'kWh': @@ -49,12 +60,21 @@ sd = float(ret['summation_delivered']) if sd > 0: # Sometimes nan pts.append(dict(measurement='housePowerSumDeliveredKwh', - fields=dict(value=float()), - tags=dict(house='berkeley'), - time=int(startTime))) + fields=dict(value=float()), + tags=dict(house='berkeley'), + time=int(startTime))) + if 'price' in ret: + pts.append(dict( + measurement='price', + fields=dict(price=float(ret['price']), + price_units=float(ret['price_units'])), + tags=dict(house='berkeley'), + time=int(startTime), + )) - influx.write_points(pts, time_precision='s') + self.influx.write_points(pts, time_precision='s') except Exception as e: + traceback.print_exc() log.error("failed: %r", e) log.error(repr(ret)) os.abort() @@ -64,8 +84,23 @@ reactor.callLater(max(1, goal - now), self.poll) -log.setLevel(logging.INFO) -influx = InfluxDBClient('bang', 9060, 'root', 'root', 'main') +if __name__ == '__main__': + arg = docopt(""" + Usage: reader.py [options] + + -v Verbose + --port PORT Serve on port [default: 10016]. + """) + verboseLogging(arg['-v']) -p = Poller(influx) -reactor.run() + influx = InfluxDBClient('bang', 9060, 'root', 'root', 'main') + p = Poller(influx) + + reactor.listenTCP( + int(arg['--port']), + cyclone.web.Application( + [ + (r'/stats/(.*)', StatsHandler, {'serverName': 'powerEagle'}), + ], + )) + reactor.run()
--- a/service/powerEagle/requirements.txt Tue Apr 23 02:56:07 2019 -0700 +++ b/service/powerEagle/requirements.txt Tue Apr 23 03:57:55 2019 -0700 @@ -1,4 +1,5 @@ -cyclone==1.1 -service-identity==14.0.0 -Twisted==15.5.0 +cyclone influxdb==3.0.0 +standardservice==0.3.0 +git+http://github.com/drewp/scales.git@448d59fb491b7631877528e7695a93553bfaaa93#egg=scales +https://github.com/drewp/cyclone/archive/python3.zip
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/powerEagle/tasks.py Tue Apr 23 03:57:55 2019 -0700 @@ -0,0 +1,27 @@ +from invoke import task + +JOB = 'powerEagle' +PORT = 10016 +TAG = f'bang6:5000/{JOB.lower()}_x86:latest' + + +@task +def build_image(ctx): + ctx.run(f'docker build --network=host -t {TAG} .') + +@task(pre=[build_image]) +def push_image(ctx): + ctx.run(f'docker push {TAG}') + +@task(pre=[build_image]) +def shell(ctx): + ctx.run(f'docker run --rm -it --cap-add SYS_PTRACE --net=host {TAG} /bin/bash', pty=True) + +@task(pre=[build_image]) +def local_run(ctx): + ctx.run(f'docker run --rm -it -p {PORT}:{PORT} --net=host {TAG} python3 reader.py -v', pty=True) + +@task(pre=[push_image]) +def redeploy(ctx): + ctx.run(f'sudo /my/proj/ansible/playbook -l bang -t {JOB}') + ctx.run(f'supervisorctl -s http://bang:9001/ restart {JOB}_{PORT}')