Skip to content

Commit

Permalink
Formatted with black
Browse files Browse the repository at this point in the history
  • Loading branch information
kbickar committed Feb 12, 2022
1 parent 688904e commit 907d6a2
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 151 deletions.
36 changes: 18 additions & 18 deletions sense_energy/asyncsenseable.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ def __init__(
api_timeout=API_TIMEOUT,
wss_timeout=WSS_TIMEOUT,
client_session=None,
ssl_verify=True,
ssl_cafile=""
ssl_verify=True,
ssl_cafile="",
):
"""Init the ASyncSenseable object."""
self._client_session = client_session or aiohttp.ClientSession()
Expand All @@ -42,7 +42,7 @@ def set_ssl_context(self, ssl_verify, ssl_cafile):
self.ssl_context = ssl.create_default_context(cafile=ssl_cafile)
else:
self.ssl_context = ssl.create_default_context()

async def authenticate(self, username, password, ssl_verify=True, ssl_cafile=""):
auth_data = {"email": username, "password": password}
self.set_ssl_context(ssl_verify, ssl_cafile)
Expand All @@ -55,9 +55,9 @@ async def authenticate(self, username, password, ssl_verify=True, ssl_cafile="")
# check MFA code required
if resp.status == 401:
data = await resp.json()
if 'mfa_token' in data:
self._mfa_token = data['mfa_token']
raise SenseMFARequiredException(data['error_reason'])
if "mfa_token" in data:
self._mfa_token = data["mfa_token"]
raise SenseMFARequiredException(data["error_reason"])

# check for 200 return
if resp.status != 200:
Expand All @@ -71,11 +71,11 @@ async def authenticate(self, username, password, ssl_verify=True, ssl_cafile="")

async def validate_mfa(self, code):
mfa_data = {
"totp": code,
"mfa_token": self._mfa_token,
"client_time:":datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ'),
"totp": code,
"mfa_token": self._mfa_token,
"client_time:": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
}

# Get auth token
async with self._client_session.post(
API_URL + "authenticate/mfa", timeout=self.api_timeout, data=mfa_data
Expand All @@ -101,7 +101,7 @@ async def update_realtime(self):
await self.async_realtime_stream(single=True)

async def async_realtime_stream(self, callback=None, single=False):
""" Reads realtime data from websocket"""
"""Reads realtime data from websocket"""
url = WS_URL % (self.sense_monitor_id, self.sense_access_token)
# hello, features, [updates,] data
async with websockets.connect(url, ssl=self.ssl_context) as ws:
Expand All @@ -126,7 +126,7 @@ async def async_realtime_stream(self, callback=None, single=False):
raise SenseWebsocketException(data["error_reason"])

async def get_realtime_future(self, callback):
""" Returns an async Future to parse realtime data with callback"""
"""Returns an async Future to parse realtime data with callback"""
await self.async_realtime_stream(callback)

async def api_call(self, url, payload={}):
Expand All @@ -146,19 +146,19 @@ async def get_trend_data(self, scale, dt=None):
if not dt:
dt = datetime.utcnow()
json = self.api_call(
'app/history/trends?monitor_id=%s&scale=%s&start=%s'
% (self.sense_monitor_id, scale, dt.strftime('%Y-%m-%dT%H:%M:%S'))
"app/history/trends?monitor_id=%s&scale=%s&start=%s"
% (self.sense_monitor_id, scale, dt.strftime("%Y-%m-%dT%H:%M:%S"))
)
self._trend_data[scale] = await json

async def update_trend_data(self, dt=None):
for scale in valid_scales:
await self.get_trend_data(scale, dt)

async def get_monitor_data(self):
async def get_monitor_data(self):
json = await self.api_call("app/monitors/%s/overview" % self.sense_monitor_id)
if 'monitor_overview' in json and 'monitor' in json['monitor_overview']:
self._monitor = json['monitor_overview']['monitor']
if "monitor_overview" in json and "monitor" in json["monitor_overview"]:
self._monitor = json["monitor_overview"]["monitor"]
return self._monitor

async def get_discovered_device_names(self):
Expand Down
134 changes: 70 additions & 64 deletions sense_energy/sense_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,60 @@

from .sense_exceptions import *

API_URL = 'https://api.sense.com/apiservice/api/v1/'
API_URL = "https://api.sense.com/apiservice/api/v1/"
WS_URL = "wss://clientrt.sense.com/monitors/%s/realtimefeed?access_token=%s"
API_TIMEOUT = 5
WSS_TIMEOUT = 5
RATE_LIMIT = 60

# for the last day, week, month, or year
valid_scales = ['DAY', 'WEEK', 'MONTH', 'YEAR']
valid_scales = ["DAY", "WEEK", "MONTH", "YEAR"]


class SenseableBase(object):

def __init__(self, username=None, password=None,
api_timeout=API_TIMEOUT, wss_timeout=WSS_TIMEOUT,
ssl_verify=True,
ssl_cafile=""):
def __init__(
self,
username=None,
password=None,
api_timeout=API_TIMEOUT,
wss_timeout=WSS_TIMEOUT,
ssl_verify=True,
ssl_cafile="",
):

# Timeout instance variables
self.api_timeout = api_timeout
self.wss_timeout = wss_timeout
self.rate_limit = RATE_LIMIT
self.last_realtime_call = 0
self._mfa_token = ''

self._mfa_token = ""
self._realtime = {}
self._devices = []
self._trend_data = {}
self._monitor = {}
for scale in valid_scales: self._trend_data[scale] = {}
for scale in valid_scales:
self._trend_data[scale] = {}
self.set_ssl_context(ssl_verify, ssl_cafile)

if username and password:
self.authenticate(username, password)
def load_auth(self, access_token, user_id, monitor_id):

def load_auth(self, access_token, user_id, monitor_id):
data = {
'access_token': access_token,
'user_id': user_id,
'monitors': [{'id':monitor_id}]
"access_token": access_token,
"user_id": user_id,
"monitors": [{"id": monitor_id}],
}
self.set_auth_data(data)

def set_auth_data(self, data):
self.sense_access_token = data['access_token']
self.sense_user_id = data['user_id']
self.sense_monitor_id = data['monitors'][0]['id']
self.sense_access_token = data["access_token"]
self.sense_user_id = data["user_id"]
self.sense_monitor_id = data["monitors"][0]["id"]

# create the auth header
self.headers = {'Authorization': 'bearer {}'.format(
self.sense_access_token)}
self.headers = {"Authorization": "bearer {}".format(self.sense_access_token)}

@property
def devices(self):
Expand All @@ -70,156 +74,158 @@ def get_realtime(self):

@property
def active_power(self):
return self._realtime.get('w', 0)
return self._realtime.get("w", 0)

@property
def active_solar_power(self):
return self._realtime.get('solar_w', 0)
return self._realtime.get("solar_w", 0)

@property
def active_voltage(self):
return self._realtime.get('voltage', [])
return self._realtime.get("voltage", [])

@property
def active_frequency(self):
return self._realtime.get('hz', 0)
return self._realtime.get("hz", 0)

@property
def daily_usage(self):
return self.get_trend('DAY', 'consumption')
return self.get_trend("DAY", "consumption")

@property
def daily_production(self):
return self.get_trend('DAY', 'production')
return self.get_trend("DAY", "production")

@property
def daily_production_pct(self):
return self.get_trend('DAY', 'production_pct')
return self.get_trend("DAY", "production_pct")

@property
def daily_net_production(self):
return self.get_trend('DAY', 'net_production')
return self.get_trend("DAY", "net_production")

@property
def daily_from_grid(self):
return self.get_trend('DAY', 'from_grid')
return self.get_trend("DAY", "from_grid")

@property
def daily_to_grid(self):
return self.get_trend('DAY', 'to_grid')
return self.get_trend("DAY", "to_grid")

@property
def daily_solar_powered(self):
return self.get_trend('DAY', 'solar_powered')
return self.get_trend("DAY", "solar_powered")

@property
def weekly_usage(self):
return self.get_trend('WEEK', 'consumption')
return self.get_trend("WEEK", "consumption")

@property
def weekly_production(self):
return self.get_trend('WEEK', 'production')
return self.get_trend("WEEK", "production")

@property
def weekly_production_pct(self):
return self.get_trend('WEEK', 'production_pct')
return self.get_trend("WEEK", "production_pct")

@property
def weekly_net_production(self):
return self.get_trend('WEEK', 'net_production')
return self.get_trend("WEEK", "net_production")

@property
def weekly_from_grid(self):
return self.get_trend('WEEK', 'from_grid')
return self.get_trend("WEEK", "from_grid")

@property
def weekly_to_grid(self):
return self.get_trend('WEEK', 'to_grid')
return self.get_trend("WEEK", "to_grid")

@property
def weekly_solar_powered(self):
return self.get_trend('WEEK', 'solar_powered')
return self.get_trend("WEEK", "solar_powered")

@property
def monthly_usage(self):
return self.get_trend('MONTH', 'consumption')
return self.get_trend("MONTH", "consumption")

@property
def monthly_production(self):
return self.get_trend('MONTH', 'production')
return self.get_trend("MONTH", "production")

@property
def monthly_production_pct(self):
return self.get_trend('MONTH', 'production_pct')
return self.get_trend("MONTH", "production_pct")

@property
def monthly_net_production(self):
return self.get_trend('MONTH', 'net_production')
return self.get_trend("MONTH", "net_production")

@property
def monthly_from_grid(self):
return self.get_trend('MONTH', 'from_grid')
return self.get_trend("MONTH", "from_grid")

@property
def monthly_to_grid(self):
return self.get_trend('MONTH', 'to_grid')
return self.get_trend("MONTH", "to_grid")

@property
def monthly_solar_powered(self):
return self.get_trend('MONTH', 'solar_powered')
return self.get_trend("MONTH", "solar_powered")

@property
def yearly_usage(self):
return self.get_trend('YEAR', 'consumption')
return self.get_trend("YEAR", "consumption")

@property
def yearly_production(self):
return self.get_trend('YEAR', 'production')
return self.get_trend("YEAR", "production")

@property
def yearly_production_pct(self):
return self.get_trend('YEAR', 'production_pct')
return self.get_trend("YEAR", "production_pct")

@property
def yearly_net_production(self):
return self.get_trend('YEAR', 'net_production')
return self.get_trend("YEAR", "net_production")

@property
def yearly_from_grid(self):
return self.get_trend('YEAR', 'from_grid')
return self.get_trend("YEAR", "from_grid")

@property
def yearly_to_grid(self):
return self.get_trend('YEAR', 'to_grid')
return self.get_trend("YEAR", "to_grid")

@property
def yearly_solar_powered(self):
return self.get_trend('YEAR', 'solar_powered')
return self.get_trend("YEAR", "solar_powered")

@property
def active_devices(self):
return [d['name'] for d in self._realtime.get('devices', {})]
return [d["name"] for d in self._realtime.get("devices", {})]

@property
def time_zone(self):
return self._monitor.get('time_zone', '')
return self._monitor.get("time_zone", "")

def trend_start(self, scale):
if 'start' not in self._trend_data[scale]:
if "start" not in self._trend_data[scale]:
return None
start_iso = self._trend_data[scale]['start'].replace('Z', '+00:00')
return datetime.strptime(start_iso, '%Y-%m-%dT%H:%M:%S.%f%z')
start_iso = self._trend_data[scale]["start"].replace("Z", "+00:00")
return datetime.strptime(start_iso, "%Y-%m-%dT%H:%M:%S.%f%z")

def get_trend(self, scale, key):
if isinstance(key, bool):
key = 'production' if key is True else 'consumption'
key = "production" if key is True else "consumption"
else:
key = 'consumption' if key == 'usage' else key
if key not in self._trend_data[scale]: return 0
key = "consumption" if key == "usage" else key
if key not in self._trend_data[scale]:
return 0
# Perform a check for a valid type
if not isinstance(self._trend_data[scale][key], (dict, float, int)): return 0
if not isinstance(self._trend_data[scale][key], (dict, float, int)):
return 0
if isinstance(self._trend_data[scale][key], dict):
total = self._trend_data[scale][key].get('total', 0)
total = self._trend_data[scale][key].get("total", 0)
else:
total = self._trend_data[scale][key]
return total
4 changes: 3 additions & 1 deletion sense_energy/sense_exceptions.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@

class SenseAPITimeoutException(Exception):
pass


class SenseAuthenticationException(Exception):
pass


class SenseMFARequiredException(Exception):
pass


class SenseWebsocketException(Exception):
pass
Loading

0 comments on commit 907d6a2

Please sign in to comment.