Add caching mechanism
This commit is contained in:
parent
83eac2787d
commit
aef6f5700c
51
solaredge.py
51
solaredge.py
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
import bottle
|
import bottle
|
||||||
import datetime
|
import datetime
|
||||||
|
import logging
|
||||||
import requests
|
import requests
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from sys import stderr
|
||||||
|
|
||||||
api_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
api_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||||
site_id = 4143190
|
site_id = 4143190
|
||||||
@ -12,7 +14,9 @@ inverter = '7B0E5700-E0'
|
|||||||
|
|
||||||
endpoint = "https://monitoringapi.solaredge.com/"
|
endpoint = "https://monitoringapi.solaredge.com/"
|
||||||
|
|
||||||
delta = datetime.timedelta(minutes=20)
|
query_delta = datetime.timedelta(minutes=20)
|
||||||
|
freshness_delta = datetime.timedelta(minutes=20)
|
||||||
|
cache = {}
|
||||||
|
|
||||||
numeric_modes = {
|
numeric_modes = {
|
||||||
'OFF': 0,
|
'OFF': 0,
|
||||||
@ -40,6 +44,11 @@ metric_data = {
|
|||||||
'ac_cos_phi': ["gauge", "AC Phase factor"]
|
'ac_cos_phi': ["gauge", "AC Phase factor"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last_ts = {}
|
||||||
|
|
||||||
|
def is_fresh(date):
|
||||||
|
return (datetime.datetime.now()) - date < freshness_delta
|
||||||
|
|
||||||
def numeric_mode(s):
|
def numeric_mode(s):
|
||||||
if s in numeric_modes:
|
if s in numeric_modes:
|
||||||
return numeric_modes[s]
|
return numeric_modes[s]
|
||||||
@ -55,7 +64,7 @@ def ptime(s):
|
|||||||
def get(path, params={}, **kw):
|
def get(path, params={}, **kw):
|
||||||
r = requests.get(endpoint + path, params | { "api_key": api_key }, **kw)
|
r = requests.get(endpoint + path, params | { "api_key": api_key }, **kw)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()
|
return r.json() | { 'fetch_time': datetime.datetime.now().timestamp() }
|
||||||
|
|
||||||
def details():
|
def details():
|
||||||
return get(f"site/{site_id}/details.json")
|
return get(f"site/{site_id}/details.json")
|
||||||
@ -69,22 +78,39 @@ def get_inverters():
|
|||||||
def energy(**kw):
|
def energy(**kw):
|
||||||
return get(f"site/{site_id}/energyDetails.json",
|
return get(f"site/{site_id}/energyDetails.json",
|
||||||
kw | {"timeUnit": "QUARTER_OF_AN_HOUR"})
|
kw | {"timeUnit": "QUARTER_OF_AN_HOUR"})
|
||||||
|
11
|
||||||
def tech_data(**kw):
|
def tech_data(**kw):
|
||||||
return get(f"equipment/{site_id}/{inverter}/data.json", kw)
|
return get(f"equipment/{site_id}/{inverter}/data.json", kw)
|
||||||
|
|
||||||
def meters(**kw):
|
def meters(**kw):
|
||||||
return get(f"site/{site_id}/meters.json", kw)
|
return get(f"site/{site_id}/meters.json", kw | {"timeUnit": "QUARTER_OF_AN_HOUR"})
|
||||||
|
|
||||||
def latest(method, **kw):
|
def latest(method, timefn, **kw):
|
||||||
|
name = method.__name__
|
||||||
|
if name in cache and is_fresh(timefn(cache[name])):
|
||||||
|
logging.info("Cache for {} is fresh", method.__name__)
|
||||||
|
return cache[name]
|
||||||
|
|
||||||
|
logging.info("Cache for {} is stale, requesting", method.__name__)
|
||||||
end = datetime.datetime.now()
|
end = datetime.datetime.now()
|
||||||
start = end - delta
|
start = end - query_delta
|
||||||
return method(startTime=time(start), endTime=time(end), **kw)
|
data = method(startTime=time(start), endTime=time(end), **kw)
|
||||||
|
cache[name] = data
|
||||||
|
return data
|
||||||
|
|
||||||
|
def tech_check(c):
|
||||||
|
if c['data']['telemetries']:
|
||||||
|
return ptime(c['data']['telemetries'][-1]['date'])
|
||||||
|
else:
|
||||||
|
return datetime.datetime.fromtimestamp(c['fetch_time'])
|
||||||
|
|
||||||
|
|
||||||
|
def meters_check(c):
|
||||||
|
return ptime(c['meterEnergyDetails']['meters'][0]['values'][-1]['date'])
|
||||||
|
|
||||||
def collect():
|
def collect():
|
||||||
tech = latest(tech_data)['data']['telemetries']
|
tech = latest(tech_data, tech_check)['data']['telemetries']
|
||||||
ms = latest(meters)['meterEnergyDetails']['meters']
|
ms = latest(meters, meters_check)['meterEnergyDetails']['meters']
|
||||||
|
|
||||||
if len(tech):
|
if len(tech):
|
||||||
point = tech[-1]
|
point = tech[-1]
|
||||||
date = ptime(point['date'])
|
date = ptime(point['date'])
|
||||||
@ -111,7 +137,7 @@ def collect():
|
|||||||
date = ptime(point['date'])
|
date = ptime(point['date'])
|
||||||
yield (date, 'meter_energy_watthours_total', {'meter': m['meterType'].lower()}, point['value'])
|
yield (date, 'meter_energy_watthours_total', {'meter': m['meterType'].lower()}, point['value'])
|
||||||
|
|
||||||
def format_metrics(entries):
|
def format_metrics(entries, timestamps=False):
|
||||||
collected = defaultdict(list)
|
collected = defaultdict(list)
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
collected[entry[1]].append(entry)
|
collected[entry[1]].append(entry)
|
||||||
@ -127,7 +153,10 @@ def format_metrics(entries):
|
|||||||
attr_s = ""
|
attr_s = ""
|
||||||
if attrs:
|
if attrs:
|
||||||
attr_s = "{" + ','.join('{}="{}"'.format(k, attrs[k]) for k in attrs ) + "}"
|
attr_s = "{" + ','.join('{}="{}"'.format(k, attrs[k]) for k in attrs ) + "}"
|
||||||
|
if timestamps:
|
||||||
yield f"{metric} {attr_s} {value} {time_s}\n"
|
yield f"{metric} {attr_s} {value} {time_s}\n"
|
||||||
|
else:
|
||||||
|
yield f"{metric} {attr_s} {value}\n"
|
||||||
|
|
||||||
@bottle.route('/')
|
@bottle.route('/')
|
||||||
def root():
|
def root():
|
||||||
|
Loading…
Reference in New Issue
Block a user