-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvudialsclient.py
More file actions
262 lines (215 loc) · 9.96 KB
/
vudialsclient.py
File metadata and controls
262 lines (215 loc) · 9.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
import requests
import logging
from urllib.parse import quote
# Library code must not call logging.basicConfig() — that configures the root
# logger for the entire host application. Let the application control logging.
LOGGER = logging.getLogger(__name__)
class VUUtil:
def get_uri(self, server_url: str, api_key: str, api_call: str, keyword_params: str) -> str:
# Security note: The API key is transmitted as a URL query parameter.
# This means it will appear in server access logs, proxy logs, and
# HTTP client history. If the server adds header-based authentication
# in the future, prefer an Authorization or X-API-Key header instead.
return f'{server_url}/api/v0/{api_call}?key={quote(api_key)}{keyword_params}'
def send_http_request(self, path_uri: str, files: dict, timeout: int = 10) -> requests.Response:
if files is not None:
r = requests.post(path_uri, files=files, timeout=timeout)
else:
r = requests.get(path_uri, timeout=timeout)
r.raise_for_status()
return r
class VUAdminUtil:
def get_uri(self, server_url: str, api_key: str, api_call: str, keyword_params: str) -> str:
# Security note: See VUUtil.get_uri — same key-in-URL caveat applies.
return f'{server_url}/api/v0/{api_call}?admin_key={quote(api_key)}{keyword_params}'
def send_http_request(self, path_uri: str, method: str, timeout: int = 10) -> requests.Response:
if method == "post":
r = requests.post(path_uri, timeout=timeout)
else:
r = requests.get(path_uri, timeout=timeout)
r.raise_for_status()
return r
class VUDial(VUUtil):
def __init__(self, server_address: str, server_port: int, api_key: str):
"""
Initialize the class with required values.
:param server_address: str, the server ip address.
:param server_port: int, the vu-dial server port.
:param api_key: str, a valid api key for the vu-dial server.
Security note: Communication uses plain HTTP. Ensure the server is
only reachable on a trusted local network interface. The API key is
passed as a URL query parameter and will appear in server access logs.
"""
self.server_url = f'http://{server_address}:{server_port}'
self.key = api_key
def list_dials(self) -> requests.Response:
"""
List the connected vu-dials.
:return: requests.Response
"""
r_uri = self.get_uri(self.server_url, self.key, 'dial/list', '')
return self.send_http_request(r_uri, None)
def get_dial_info(self, uid: str) -> requests.Response:
"""
Get vu-dial information.
:param uid: str, the uid of the vu-dial.
:return: requests.Response
"""
api_call = f'dial/{quote(uid, safe="")}/status'
r_uri = self.get_uri(self.server_url, self.key, api_call, '')
return self.send_http_request(r_uri, None)
def set_dial_value(self, uid: str, value: int) -> requests.Response:
"""
Set the dial value.
:param uid: str, the uid of the vu-dial.
:param value: int, the dial value.
:return: requests.Response
"""
api_call = f'dial/{quote(uid, safe="")}/set'
params = f'&value={int(value)}'
r_uri = self.get_uri(self.server_url, self.key, api_call, params)
return self.send_http_request(r_uri, None)
def set_dial_color(self, uid: str, red: int, green: int, blue: int) -> requests.Response:
"""
Set the dial backlight color.
:param uid: str, the uid of the vu-dial.
:param red: int, red channel (0-255).
:param green: int, green channel (0-255).
:param blue: int, blue channel (0-255).
:return: requests.Response
"""
api_call = f'dial/{quote(uid, safe="")}/backlight'
params = f'&red={int(red)}&green={int(green)}&blue={int(blue)}'
r_uri = self.get_uri(self.server_url, self.key, api_call, params)
return self.send_http_request(r_uri, None)
def set_dial_background(self, uid: str, file: str) -> requests.Response:
"""
Set the dial background image.
:param uid: str, the uid of the vu-dial.
:param file: str, path to the image file to upload.
:return: requests.Response
"""
api_call = f'dial/{quote(uid, safe="")}/image/set'
with open(file, 'rb') as f:
files = {'imgfile': f}
r_uri = self.get_uri(self.server_url, self.key, api_call, '')
return self.send_http_request(r_uri, files)
def get_dial_image_crc(self, uid: str) -> requests.Response:
"""
Get the CRC of the dial background image.
:param uid: str, the uid of the vu-dial.
:return: requests.Response
"""
api_call = f'dial/{quote(uid, safe="")}/image/crc'
r_uri = self.get_uri(self.server_url, self.key, api_call, '')
return self.send_http_request(r_uri, None)
def set_dial_name(self, uid: str, name: str) -> requests.Response:
"""
Set the dial name.
:param uid: str, the uid of the vu-dial.
:param name: str, the name to assign to the dial.
:return: requests.Response
"""
api_call = f'dial/{quote(uid, safe="")}/name'
params = f'&name={quote(name)}'
r_uri = self.get_uri(self.server_url, self.key, api_call, params)
return self.send_http_request(r_uri, None)
def reload_hw_info(self, uid: str) -> requests.Response:
"""
Reload hardware info for a dial.
:param uid: str, the uid of the vu-dial.
:return: requests.Response
"""
api_call = f'dial/{quote(uid, safe="")}/reload'
r_uri = self.get_uri(self.server_url, self.key, api_call, '')
return self.send_http_request(r_uri, None)
def set_dial_easing(self, uid: str, period: int, step: int) -> requests.Response:
"""
Set dial easing parameters.
:param uid: str, the uid of the vu-dial.
:param period: int, easing period.
:param step: int, easing step.
:return: requests.Response
"""
api_call = f'dial/{quote(uid, safe="")}/easing/dial'
params = f'&period={int(period)}&step={int(step)}'
r_uri = self.get_uri(self.server_url, self.key, api_call, params)
return self.send_http_request(r_uri, None)
def set_backlight_easing(self, uid: str, period: int, step: int) -> requests.Response:
"""
Set backlight easing parameters.
:param uid: str, the uid of the vu-dial.
:param period: int, easing period.
:param step: int, easing step.
:return: requests.Response
"""
api_call = f'dial/{quote(uid, safe="")}/easing/backlight'
params = f'&period={int(period)}&step={int(step)}'
r_uri = self.get_uri(self.server_url, self.key, api_call, params)
return self.send_http_request(r_uri, None)
def get_easing_config(self, uid: str) -> requests.Response:
"""
Get easing configuration for a dial.
:param uid: str, the uid of the vu-dial.
:return: requests.Response
"""
api_call = f'dial/{quote(uid, safe="")}/easing/get'
r_uri = self.get_uri(self.server_url, self.key, api_call, '')
return self.send_http_request(r_uri, None)
class VUAdmin(VUAdminUtil):
def __init__(self, server_address: str, server_port: int, admin_key: str):
"""
Initialize the class with required values.
:param server_address: str, the server ip address.
:param server_port: int, the vu-dial server port.
:param admin_key: str, a valid admin key for the vu-dial server.
Security note: Communication uses plain HTTP. Ensure the server is
only reachable on a trusted local network interface. The admin key is
passed as a URL query parameter and will appear in server access logs.
"""
self.server_url = f'http://{server_address}:{server_port}'
self.key = admin_key
def provision_dials(self) -> requests.Response:
"""
Provision connected vu-dials.
:return: requests.Response
"""
r_uri = self.get_uri(self.server_url, self.key, 'dial/provision', '')
return self.send_http_request(r_uri, 'get')
def list_api_keys(self) -> requests.Response:
"""
List all configured API keys.
:return: requests.Response
"""
r_uri = self.get_uri(self.server_url, self.key, 'admin/keys/list', '')
return self.send_http_request(r_uri, 'get')
def remove_api_key(self, target_key: str) -> requests.Response:
"""
Remove an API key.
:param target_key: str, the key to remove.
:return: requests.Response
"""
params = f'&key={quote(target_key)}'
r_uri = self.get_uri(self.server_url, self.key, 'admin/keys/remove', params)
return self.send_http_request(r_uri, 'get')
def create_api_key(self, name: str, dials: str) -> requests.Response:
"""
Create a new API key.
:param name: str, the name for the new key.
:param dials: str, the dials to associate with the key.
:return: requests.Response
"""
params = f'&name={quote(name)}&dials={quote(dials)}'
r_uri = self.get_uri(self.server_url, self.key, 'admin/keys/create', params)
return self.send_http_request(r_uri, 'post')
def update_api_key(self, name: str, target_key: str, dials: str) -> requests.Response:
"""
Update an existing API key.
:param name: str, the new name for the key.
:param target_key: str, the key to update.
:param dials: str, the updated dials to associate.
:return: requests.Response
"""
params = f'&key={quote(target_key)}&name={quote(name)}&dials={quote(dials)}'
r_uri = self.get_uri(self.server_url, self.key, 'admin/keys/update', params)
return self.send_http_request(r_uri, 'get')