Skip to content

Commit 150d1ef

Browse files
MitterdorferMathiasmuhlba91
authored andcommitted
/events: correctly handle onyx server-sent events
1 parent ce1beee commit 150d1ef

File tree

2 files changed

+69
-32
lines changed

2 files changed

+69
-32
lines changed

onyx_client/client.py

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -245,29 +245,34 @@ async def events(self, include_details: bool = False) -> Device:
245245
246246
include_details: ensures all device details are queried
247247
before emiting the device"""
248+
event = ""
248249
async for message in self.url_helper.start_stream("/events"):
249-
if message is not None and len(message) > 0 and message.startswith("data:"):
250-
message = message[len("data:") :].strip()
251-
events = json.loads(message)
252-
for key, value in events.get("devices", dict()).items():
253-
try:
254-
if value is not None:
255-
device = (
256-
await self.device(key)
257-
if include_details
258-
else init_device(
250+
if message is not None and len(message) > 0:
251+
if message.startswith("event:"):
252+
event = message[len("event:") :].strip()
253+
elif message.startswith("data:"):
254+
if event in ["snapshot", "patch"]:
255+
data = json.loads(message[len("data:") :].strip())
256+
for key, value in data.get("devices", dict()).items():
257+
try:
258+
if value is not None:
259+
device = (
260+
await self.device(key)
261+
if include_details
262+
else init_device(
263+
key,
264+
value.get("name", None),
265+
DeviceType.convert(value.get("type", None)),
266+
value.get("properties", None),
267+
value,
268+
)
269+
)
270+
yield device
271+
except AttributeError:
272+
_LOGGER.error(
273+
"Received unknown device data. Dropping device %s",
259274
key,
260-
value.get("name", None),
261-
DeviceType.convert(value.get("type", None)),
262-
value.get("properties", None),
263-
value,
264275
)
265-
)
266-
yield device
267-
except AttributeError:
268-
_LOGGER.error(
269-
"Received unknown device data. Dropping device %s", key
270-
)
271276

272277
def start(self, include_details: bool = False, backoff_time: int = 1):
273278
"""Start the event stream via callback.

tests/test_client.py

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,10 @@ async def test_events(self, mock_response, client):
10951095
mock_response.get(
10961096
f"{API_URL}/box/finger/api/{API_VERSION}/events",
10971097
status=200,
1098-
body='data: { "devices": { "device1":'
1098+
body="event: pulse\n"
1099+
"data: 1730803627\n\n"
1100+
"event: snapshot\n"
1101+
'data: { "devices": { "device1":'
10991102
'{ "name": "device1", "type": "rollershutter" },'
11001103
'"device2": { "name": "device2" },'
11011104
'"device3": { "type": "rollershutter" } } }',
@@ -1112,7 +1115,10 @@ async def test_start(self, mock__complete_internal_task, mock_response, client):
11121115
mock_response.get(
11131116
f"{API_URL}/box/finger/api/{API_VERSION}/events",
11141117
status=200,
1115-
body='data: { "devices": { "device1":'
1118+
body="event: pulse\n"
1119+
"data: 1730803627\n\n"
1120+
"event: snapshot\n"
1121+
'data: { "devices": { "device1":'
11161122
'{ "name": "device1", "type": "rollershutter" },'
11171123
'"device2": { "name": "device2" },'
11181124
'"device3": { "type": "rollershutter" } } }',
@@ -1141,12 +1147,14 @@ async def test_start_break(self, mock_response, client):
11411147
mock_response.get(
11421148
f"{API_URL}/box/finger/api/{API_VERSION}/events",
11431149
status=200,
1144-
body='data: { "devices": { "device1":'
1150+
body="event: pulse\n"
1151+
"data: 1730803627\n\n"
1152+
"event: snapshot\n"
1153+
'data: { "devices": { "device1":'
11451154
'{ "name": "device1", "type": "rollershutter" },'
11461155
'"device2": { "name": "device2" },'
11471156
'"device3": { "type": "rollershutter" } } }',
11481157
)
1149-
11501158
def callback(device):
11511159
if device.identifier == "device1":
11521160
client.stop()
@@ -1163,7 +1171,10 @@ async def test_start_without_callback(self, mock_response, client):
11631171
mock_response.get(
11641172
f"{API_URL}/box/finger/api/{API_VERSION}/events",
11651173
status=200,
1166-
body='data: { "devices": { "device1":'
1174+
body="event: pulse\n"
1175+
"data: 1730803627\n\n"
1176+
"event: snapshot\n"
1177+
'data: { "devices": { "device1":'
11671178
'{ "name": "device1", "type": "rollershutter" },'
11681179
'"device2": { "name": "device2" },'
11691180
'"device3": { "type": "rollershutter" } } }',
@@ -1179,7 +1190,10 @@ async def test_events_details(self, mock_device, mock_response, client):
11791190
mock_response.get(
11801191
f"{API_URL}/box/finger/api/{API_VERSION}/events",
11811192
status=200,
1182-
body='data: { "devices": { "device":'
1193+
body="event: pulse\n"
1194+
"data: 1730803627\n\n"
1195+
"event: snapshot\n"
1196+
'data: { "devices": { "device":'
11831197
'{ "name": "device", "type": "rollershutter" } } }',
11841198
)
11851199
mock_device.return_value = Device(
@@ -1202,7 +1216,10 @@ async def test_events_device_exception(self, mock_device, mock_response, client)
12021216
mock_response.get(
12031217
f"{API_URL}/box/finger/api/{API_VERSION}/events",
12041218
status=200,
1205-
body='data: { "devices": { "device":'
1219+
body="event: pulse\n"
1220+
"data: 1730803627\n\n"
1221+
"event: patch\n"
1222+
'data: { "devices": { "device":'
12061223
'{ "name": "device", "type": "rollershutter" } } }',
12071224
)
12081225
mock_device.side_effect = AttributeError()
@@ -1217,7 +1234,10 @@ async def test_events_empty_data(self, mock_response, client):
12171234
mock_response.get(
12181235
f"{API_URL}/box/finger/api/{API_VERSION}/events",
12191236
status=200,
1220-
body='data: { "devices": { "device1": {} } }',
1237+
body="event: pulse\n"
1238+
"data: 1730803627\n\n"
1239+
"event: patch\n"
1240+
'data: { "devices": { "device1": {} } }',
12211241
)
12221242
index = 1
12231243
async for device in client.events():
@@ -1230,7 +1250,10 @@ async def test_events_no_devices(self, mock_response, client):
12301250
mock_response.get(
12311251
f"{API_URL}/box/finger/api/{API_VERSION}/events",
12321252
status=200,
1233-
body='data: { "devices": { } }',
1253+
body="event: pulse\n"
1254+
"data: 1730803627\n\n"
1255+
"event: patch\n"
1256+
'data: { "devices": { } }',
12341257
)
12351258
index = 1
12361259
async for device in client.events():
@@ -1243,7 +1266,10 @@ async def test_events_none(self, mock_response, client):
12431266
mock_response.get(
12441267
f"{API_URL}/box/finger/api/{API_VERSION}/events",
12451268
status=200,
1246-
body="data: { }",
1269+
body="event: pulse\n"
1270+
"data: 1730803627\n\n"
1271+
"event: patch\n"
1272+
"data: { }",
12471273
)
12481274
index = 1
12491275
async for device in client.events():
@@ -1255,7 +1281,10 @@ async def test_events_error(self, mock_response, client):
12551281
mock_response.get(
12561282
f"{API_URL}/box/finger/api/{API_VERSION}/events",
12571283
status=500,
1258-
body="data: { }",
1284+
body="event: pulse\n"
1285+
"data: 1730803627\n\n"
1286+
"event: patch\n"
1287+
"data: { }",
12591288
)
12601289
index = 1
12611290
async for device in client.events():
@@ -1267,7 +1296,10 @@ async def test_events_shutter(self, mock_response, client):
12671296
mock_response.get(
12681297
f"{API_URL}/box/finger/api/{API_VERSION}/events",
12691298
status=200,
1270-
body='data: { "devices": { "device1":'
1299+
body="event: pulse\n"
1300+
"data: 1730803627\n\n"
1301+
"event: patch\n"
1302+
'data: { "devices": { "device1":'
12711303
'{ "name": "device1", "type": "rollershutter" },'
12721304
'"device2": { "name": "device2" },'
12731305
'"device3": { "type": "rollershutter" } } }',

0 commit comments

Comments
 (0)