From 086796cbde5c20f91d6984d16c54ad98c2525eee Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Sun, 19 Jan 2020 23:30:15 -0800 Subject: [PATCH] add start of enphase data logger... --- .gitignore | 1 + enphase.py | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++ start | 5 ++ 3 files changed, 162 insertions(+) create mode 100644 .gitignore create mode 100644 enphase.py create mode 100644 start diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf32007 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +creds.txt diff --git a/enphase.py b/enphase.py new file mode 100644 index 0000000..f859847 --- /dev/null +++ b/enphase.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python + +from requests.auth import HTTPDigestAuth + +import copy +import threading +import json +import requests +import sys +import time +import urlparse + +with open('creds.txt') as fp: + ip, username, password = fp.readline().split() + +def fetch_envoy_data(envoy_ip, path, username, password): + url = urlparse.urlunsplit(('http', envoy_ip, path, '', '')) + + resp = requests.get(url, auth=HTTPDigestAuth(username, password)) + + return json.loads(resp.text) + +def myenvoy(x): + while True: + try: + return fetch_envoy_data(ip, x, username, password) + except ValueError: + time.sleep(5) + +loglock = threading.Lock() +def logdata(hdr, obj): + with loglock: + print '%s %.3f %s' % (hdr, time.time(), json.dumps(obj)) + sys.stdout.flush() + +if False: + data = myenvoy('/api/v1/production/inverters/') + print(repr(data)) + import pprint + pprint.pprint([ x[u'lastReportWatts'] for x in data ]) + print sum([ int(x[u'lastReportWatts']) for x in data ], 0) + lrdates = [ x['lastReportDate'] for x in data ] + lrdates.sort() + pprint.pprint([ lrdates[x] - lrdates[x - 1] for x in xrange(1, len(lrdates)) ]) + +def shortprodcmp(a, b): + if b is None or a is None: + return cmp(a, b) + + a = copy.deepcopy(a) + b = copy.deepcopy(b) + + del a['eim']['readingTime'] + del b['eim']['readingTime'] + + return cmp(a, b) + +def thread_production(): + global doexit + + lastfulllog = 0 + lastdata = None + + s = time.time() + while not doexit: + r = myenvoy('/production.json?details=1') + + # full, every 5 minutes + if time.time() > lastfulllog + 5*60: + logdata('production', r) + lastfulllog = time.time() + + # remap by type + tmap = { x['type']: x for x in r['production'] } + + # take what fields we want + eim = tmap['eim'] + eimfields = [ 'readingTime', 'wNow', 'whLifetime', ] + data = { + 'inverters': tmap['inverters'], + 'eim': { k: eim[k] for k in eimfields }, + } + + # log if it's different + if shortprodcmp(data, lastdata) != 0: + logdata('shortprod', data) + + lastdata = data + + s += 10 + e = time.time() + if s > e: + time.sleep(s - time.time()) + +def thread_inventory(): + global doexit + + lastr = None + lastlog = 0 + while not doexit: + r = myenvoy('/inventory.json') + + # if it changes, or every 24hrs + if lastr != r or time.time() > lastlog + 24*60*60: + logdata('inventory', r) + lastlog = time.time() + + lastr = r + + time.sleep(60*60) + +def thread_panels(): + global doexit + + lastr = None + while not doexit: + r = myenvoy('/api/v1/production/inverters/') + + if lastr != r: + logdata('panel', r) + + lastr = r + + #reps = [ x['lastReportDate'] for x in r ] + #reps.sort() + #print '\n'.join(time.ctime(x) for x in reps) + + lastrepdate = max(x['lastReportDate'] for x in r) + + waittotime = lastrepdate + 300 + 10 + curtime = time.time() + + if waittotime < curtime: + wait = 120 # 2 minutes + else: + wait = waittotime - curtime + + print 'debug waiting:', wait + time.sleep(wait) + +if __name__ == '__main__': + doexit = False + + threadfuns = [ x for x in dir() if x.startswith('thread_') ] + + threadobjs = { x: threading.Thread(target=globals()[x]) for x in threadfuns } + + for i in threadobjs.itervalues(): + i.setDaemon(True) + i.start() + + while True: + time.sleep(120) + + time.sleep(3) + sys.exit() diff --git a/start b/start new file mode 100644 index 0000000..c0262cf --- /dev/null +++ b/start @@ -0,0 +1,5 @@ +#!/bin/sh - + +. ./p/bin/activate + +python enphase.py > solar.$(date +%Y%m%d%H%M).log