Skip to content

Commit 31175ec

Browse files
author
Thomas Basche
committed
Migrate existing functions to ApiRequest class
1 parent d982b15 commit 31175ec

5 files changed

Lines changed: 124 additions & 141 deletions

File tree

reposit/data/api.py

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@
44
import logging
55

66
import requests
7-
import six
87

98
from reposit.data.exceptions import InvalidControllerException
109
from reposit.data.utils import is_valid_url
1110
from reposit.settings import BASE_URL
12-
11+
from reposit.utilities import dict_iter
1312

1413
logger = logging.getLogger(__name__)
1514

@@ -29,7 +28,7 @@ def __str__(self):
2928
will leak the access token.
3029
:return:
3130
"""
32-
return self.url, self.schema
31+
return '{} {}'.format(self.url, self.schema)
3332

3433
def __init__(self, path, controller, schema, **kwargs):
3534
"""
@@ -101,17 +100,35 @@ def _simple_format_for_fields(self, api_response):
101100
"""
102101

103102
data = api_response.json()
104-
data_for_retrieval = []
105-
schema_items = self.schema.items() if six.PY3 else self.schema.iteritems()
106-
for key, _ in schema_items:
107-
fetched_data = data.get(key)
108-
if fetched_data:
109-
data_for_retrieval.append(fetched_data)
110-
del data[key]
111-
112-
# if its a list of only one thing then simplify it a smidge.
113-
# Most routes tend to only be.
114-
if len(data_for_retrieval) == 1:
115-
return data_for_retrieval[0]
116-
117-
return data_for_retrieval
103+
target_key = deepest_key(self.schema)
104+
target_data = match_to_schema(data, target_key)
105+
return target_data
106+
107+
108+
def deepest_key(_dict):
109+
"""Return the deepest key in a dict"""
110+
for key, value in dict_iter(_dict):
111+
if isinstance(value, dict) and bool(value):
112+
return deepest_key(_dict[key])
113+
return key
114+
115+
116+
def match_to_schema(_dict, requested_key):
117+
"""
118+
Match the schema supplied with the response to return the
119+
data we requested.
120+
:param _dict:
121+
:param requested_key:
122+
:return:
123+
"""
124+
if _dict.get(requested_key) is not None:
125+
return _dict[requested_key]
126+
127+
for valid_key in _dict:
128+
if valid_key == requested_key:
129+
if not isinstance(_dict.get(valid_key), dict):
130+
return _dict[valid_key]
131+
else:
132+
continue
133+
elif valid_key != requested_key and isinstance(_dict.get(valid_key), dict):
134+
return match_to_schema(_dict[valid_key], requested_key)

reposit/data/controller.py

Lines changed: 72 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from __future__ import absolute_import
55

66
from reposit.data.api import ApiRequest
7-
from reposit.data.utils import api_response, device_summary
87

98

109
class Controller(object):
@@ -39,147 +38,167 @@ def battery_min_state_of_charge(self):
3938
Return the minimum state of charge of the battery
4039
:return:
4140
"""
42-
return api_response(
43-
url='https://{}/v2/deployments/{}/battery/min_soc',
41+
request = ApiRequest(
42+
path='v2/deployments/{}/battery/min_soc'.format(self.user_key),
4443
controller=self,
45-
field='min_soc'
44+
schema={'min_soc': {}}
4645
)
4746

47+
return request.get()
48+
4849
@property
4950
def has_battery(self):
5051
"""
5152
If the system has a battery installed
5253
:return:
5354
"""
54-
return api_response(
55-
url='https://{}/v2/deployments/{}/components',
55+
request = ApiRequest(
56+
path='v2/deployments/{}/components'.format(self.user_key),
5657
controller=self,
57-
field='data',
58-
subfield='battery',
58+
schema={
59+
'data': {
60+
'battery': {}
61+
}
62+
}
5963
)
64+
return request.get()
6065

6166
@property
6267
def has_inverter(self):
6368
"""
6469
If the system has an inverter installed
6570
:return:
6671
"""
67-
return api_response(
68-
url='https://{}/v2/deployments/{}/components',
72+
request = ApiRequest(
73+
path='v2/deployments/{}/components'.format(self.user_key),
6974
controller=self,
70-
field='data',
71-
subfield='inverter',
75+
schema={
76+
'data': {
77+
'inverter': {}
78+
}
79+
}
7280
)
81+
return request.get()
7382

7483
@property
7584
def latest_historical_generation(self):
7685
"""
7786
Return a list of data points as lists. Time are in GMT
7887
:return:
7988
"""
80-
81-
return api_response(
82-
url='https://{}/v2/deployments/{}/generation/historical/p',
89+
request = ApiRequest(
90+
path='v2/deployments/{}/generation/historical/p'.format(self.user_key),
8391
controller=self,
84-
field='solarP',
85-
format_list=True
92+
schema={
93+
'solarP': {}
94+
}
8695
)
96+
return request.get()
8797

8898
@property
8999
def latest_historical_house(self):
90100
"""
91101
Return a list of data points as lists. Time are in GMT
92102
:return:
93103
"""
94-
95-
return api_response(
96-
url='https://{}/v2/deployments/{}/house/historical',
104+
request = ApiRequest(
105+
path='v2/deployments/{}/house/historical'.format(self.user_key),
97106
controller=self,
98-
field='data',
99-
subfield='houseP',
100-
format_list=True
107+
schema={
108+
'data': {
109+
'houseP': {}
110+
}
111+
}
101112
)
113+
return request.get()
102114

103115
@property
104116
def latest_historical_grid_credits(self):
105117
"""
106118
Return a list of data points as lists. Times are in GMT
107119
:return:
108120
"""
109-
return api_response(
110-
url='https://{}/v2/deployments/{}/gridcredits/historical',
121+
122+
request = ApiRequest(
123+
path='v2/deployments/{}/gridcredits/historical'.format(self.user_key),
111124
controller=self,
112-
field='gridcredits',
113-
format_list=True
125+
schema={
126+
'gridcredits': {}
127+
}
114128
)
129+
return request.get()
115130

116131
@property
117132
def latest_historical_inverter(self):
118133
"""
119134
Return a list of data points as lists. Times are in GMT
120135
:return:
121136
"""
122-
return api_response(
123-
url='https://{}/v2/deployments/{}/inverter/historical/p',
137+
request = ApiRequest(
138+
path='v2/deployments/{}/inverter/historical/p'.format(self.user_key),
124139
controller=self,
125-
field='inverterP',
126-
format_list=True
140+
schema={
141+
'inverterP': {}
142+
}
127143
)
144+
return request.get()
128145

129146
@property
130147
def latest_historical_meter(self):
131148
"""
132149
Return a list of data points as lists. Times are in GMT
133150
:return:
134151
"""
135-
return api_response(
136-
url='https://{}/v2/deployments/{}/meter/historical/p',
152+
request = ApiRequest(
153+
path='v2/deployments/{}/meter/historical/p'.format(self.user_key),
137154
controller=self,
138-
field='meterP',
139-
format_list=True
155+
schema={
156+
'meterP': {}
157+
}
140158
)
141-
159+
return request.get()
142160

143161
@property
144162
def weekday_tou_tariff(self):
145163
"""
146164
Returns a list of dicts of weekday time of use tariff information
147165
:return:
148166
"""
149-
return api_response(
150-
url='https://{}/v2/deployments/{}/tariff/tou',
167+
request = ApiRequest(
168+
path='v2/deployments/{}/tariff/tou'.format(self.user_key),
151169
controller=self,
152-
field='weekday'
170+
schema={
171+
'weekday': {}
172+
}
153173
)
174+
return request.get()
154175

155176
@property
156177
def weekend_tou_tariff(self):
157178
"""
158179
Returns a list of dicts of weekend time of use tariff information
159180
:return:
160181
"""
161-
return api_response(
162-
url='https://{}/v2/deployments/{}/tariff/tou',
182+
request = ApiRequest(
183+
path='v2/deployments/{}/tariff/tou'.format(self.user_key),
163184
controller=self,
164-
field='weekend'
185+
schema={
186+
'weekend': {}
187+
}
165188
)
189+
return request.get()
166190

167191
@property
168192
def feed_in_tariff(self):
169193
"""
170194
The feed in tariff cost as a float
171195
:return:
172196
"""
173-
return api_response(
174-
url='https://{}/v2/deployments/{}/tariff/tou',
197+
request = ApiRequest(
198+
path='v2/deployments/{}/tariff/tou'.format(self.user_key),
175199
controller=self,
176-
field='fit'
200+
schema={
201+
'fit': {}
202+
}
177203
)
178-
179-
@property
180-
def summary(self):
181-
"""
182-
Return current system information as a dict
183-
:return:
184-
"""
185-
return device_summary(self)
204+
return request.get()

reposit/data/utils.py

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,6 @@
55

66
import re
77

8-
import arrow
9-
import requests
10-
import six
11-
12-
from reposit.settings import BASE_URL
13-
14-
158
# adapted from Django :)
169
VALID_URL_REGEX = re.compile(
1710
r'^(?:http|ftp)s?://' # http:// or https://
@@ -25,67 +18,3 @@ def is_valid_url(url):
2518
:return:
2619
"""
2720
return bool(re.match(VALID_URL_REGEX, url))
28-
29-
30-
def api_response(url, controller, field, subfield=None, format_list=False, no_user_key=False):
31-
"""
32-
Simple data fetch for a reposit controller
33-
:param url: api url
34-
:param controller: Controller instance
35-
:param field: the first level field
36-
:param subfield: optional second level field
37-
:return:
38-
"""
39-
subfield_check = bool(subfield)
40-
if subfield == 0: # in case some fields are actually a zero
41-
subfield_check = True
42-
43-
if no_user_key:
44-
resp = requests.get(url.format(BASE_URL), headers=controller.auth_headers)
45-
else:
46-
resp = requests.get(url.format(BASE_URL, controller.user_key),
47-
headers=controller.auth_headers)
48-
49-
resp.raise_for_status()
50-
if not subfield_check and not format_list:
51-
return resp.json()[field]
52-
53-
if format_list:
54-
data = resp.json()
55-
if subfield:
56-
for data_point in data[field][subfield]:
57-
data_point[0] = arrow.get(data_point[0]).format('HH:mm:ss DD-MM-YYYY')
58-
return data[field][subfield]
59-
else:
60-
for data_point in data[field]:
61-
data_point[0] = arrow.get(data_point[0]).format('HH:mm:ss DD-MM-YYYY')
62-
return data[field]
63-
64-
return resp.json()[field][subfield]
65-
66-
67-
def device_summary(controller):
68-
"""
69-
Retrieve current summary for the device
70-
:param controller: Controller instance
71-
:return:
72-
"""
73-
url = '{}/v2/deployments/{}/summary/now'.format(BASE_URL, controller.user_key)
74-
resp = requests.get(url, headers=controller.auth_headers)
75-
resp.raise_for_status()
76-
summary = format_summary_response(resp.json())
77-
return summary
78-
79-
80-
def format_summary_response(data):
81-
"""
82-
For a summary set, pull out the interesting values
83-
:param data: dict of info
84-
:return:
85-
"""
86-
response = {}
87-
data_items = data['data'].items() if six.PY3 else data['data'].iteritems()
88-
for key, value in data_items:
89-
if key in ('battery', 'grid', 'house', 'solar'):
90-
response[key] = {'state': value['state'], 'value': value['val']}
91-
return response

reposit/utilities/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
"""
2+
Shortcut imports
3+
"""
4+
from reposit.utilities.utils import dict_iter

0 commit comments

Comments
 (0)