Skip to content

Commit fa36cbe

Browse files
authored
feat: add last_id for alerts poll (#125)
#125
1 parent 68c2ef1 commit fa36cbe

File tree

2 files changed

+154
-64
lines changed

2 files changed

+154
-64
lines changed

src/elmo/api/client.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ def poll(self, ids):
121121
"sessionId": self._session_id,
122122
"Areas": ids[q.SECTORS],
123123
"Inputs": ids[q.INPUTS],
124+
"StatusAdv": ids[q.ALERTS],
124125
"CanElevate": "1",
125126
"ConnectionStatus": "1",
126127
}
@@ -132,9 +133,10 @@ def poll(self, ids):
132133
state = response.json()
133134
try:
134135
update = {
135-
"has_changes": state["Areas"] or state["Inputs"],
136+
"has_changes": state["Areas"] or state["Inputs"] or state["StatusAdv"],
136137
"areas": state["Areas"],
137138
"inputs": state["Inputs"],
139+
"statusadv": state["StatusAdv"],
138140
}
139141
except KeyError as err:
140142
raise ParseError(f"Client | Unable to parse poll response: {err} is missing") from err
@@ -593,6 +595,7 @@ def query(self, query):
593595
try:
594596
# Check if the response has the expected format
595597
msg = response.json()
598+
last_id = msg["StatusUid"]
596599
status = msg["PanelLeds"]
597600
anomalies = msg["PanelAnomalies"]
598601
except (KeyError, ValueError):
@@ -603,8 +606,11 @@ def query(self, query):
603606

604607
# Convert the dict to a snake_case one to simplify the usage in other modules, and sort alphabetically
605608
new_dict = {
606-
i: {"name": _camel_to_snake_case(k), "status": v}
607-
for i, (k, v) in enumerate(sorted(merged_dict.items()))
609+
"last_id": last_id,
610+
"alerts": {
611+
i: {"name": _camel_to_snake_case(k), "status": v}
612+
for i, (k, v) in enumerate(sorted(merged_dict.items()))
613+
},
608614
}
609615
_LOGGER.debug(f"Client | Status retrieved: {new_dict}")
610616

tests/test_client.py

Lines changed: 145 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -273,14 +273,16 @@ def test_client_poll(server):
273273
ids = {
274274
query.SECTORS: 42,
275275
query.INPUTS: 4242,
276+
query.ALERTS: 424242,
276277
}
277278
# Test
278279
state = client.poll(ids)
279-
assert len(state.keys()) == 3
280+
assert len(state.keys()) == 4
280281
# Check response
281282
assert state["has_changes"] is False
282283
assert state["inputs"] is False
283284
assert state["areas"] is False
285+
assert state["statusadv"] is False
284286
# Check request
285287
body = server.calls[0].request.body.split("&")
286288
assert "sessionId=test" in body
@@ -308,7 +310,7 @@ def test_client_poll_with_changes(server):
308310
"Strings": 0,
309311
"ManagedAccounts": false,
310312
"Temperature": false,
311-
"StatusAdv": false,
313+
"StatusAdv": true,
312314
"Images": false,
313315
"AdditionalInfoSupported": true,
314316
"HasChanges": true
@@ -320,13 +322,15 @@ def test_client_poll_with_changes(server):
320322
ids = {
321323
query.SECTORS: 42,
322324
query.INPUTS: 4242,
325+
query.ALERTS: 424242,
323326
}
324327
# Test
325328
state = client.poll(ids)
326-
assert len(state.keys()) == 3
329+
assert len(state.keys()) == 4
327330
assert state["has_changes"] is True
328331
assert state["inputs"] is True
329332
assert state["areas"] is True
333+
assert state["statusadv"] is True
330334

331335

332336
def test_client_poll_ignore_has_changes(server):
@@ -359,10 +363,11 @@ def test_client_poll_ignore_has_changes(server):
359363
ids = {
360364
query.SECTORS: 42,
361365
query.INPUTS: 4242,
366+
query.ALERTS: 424242,
362367
}
363368
# Test
364369
state = client.poll(ids)
365-
assert len(state.keys()) == 3
370+
assert len(state.keys()) == 4
366371
assert state["has_changes"] is False
367372

368373

@@ -379,46 +384,122 @@ def test_client_poll_unknown_error(server):
379384
ids = {
380385
query.SECTORS: 42,
381386
query.INPUTS: 4242,
387+
query.ALERTS: 424242,
382388
}
383389
# Test
384390
with pytest.raises(HTTPError):
385391
client.poll(ids)
386392
assert len(server.calls) == 1
387393

388394

389-
def test_client_poll_parse_error(server):
390-
"""Should raise a ParseError if the response is different from what is expected.
391-
In this case `Areas` and `Inputs` are missing from the response."""
392-
html = """
393-
{
394-
"ConnectionStatus": false,
395-
"CanElevate": false,
396-
"LoggedIn": false,
397-
"LoginInProgress": false,
398-
"Events": false,
399-
"Outputs": false,
400-
"Anomalies": false,
401-
"ReadStringsInProgress": false,
402-
"ReadStringPercentage": 0,
403-
"Strings": 0,
404-
"ManagedAccounts": false,
405-
"Temperature": false,
406-
"StatusAdv": false,
407-
"Images": false,
408-
"AdditionalInfoSupported": true,
409-
"HasChanges": false
395+
class TestClientPollParseError:
396+
def test_areas_missing(self, server):
397+
"""Should raise a ParseError if the response is different from what is expected.
398+
In this case `Areas` is missing from the response."""
399+
html = """
400+
{
401+
"ConnectionStatus": false,
402+
"CanElevate": false,
403+
"LoggedIn": false,
404+
"LoginInProgress": false,
405+
"Events": true,
406+
"Inputs": false,
407+
"Outputs": false,
408+
"Anomalies": false,
409+
"ReadStringsInProgress": false,
410+
"ReadStringPercentage": 0,
411+
"Strings": 0,
412+
"ManagedAccounts": false,
413+
"Temperature": false,
414+
"StatusAdv": false,
415+
"Images": false,
416+
"AdditionalInfoSupported": true,
417+
"HasChanges": false
418+
}
419+
"""
420+
server.add(responses.POST, "https://example.com/api/updates", body=html, status=200)
421+
client = ElmoClient(base_url="https://example.com", domain="domain")
422+
client._session_id = "test"
423+
ids = {
424+
query.SECTORS: 42,
425+
query.INPUTS: 4242,
426+
query.ALERTS: 424242,
410427
}
411-
"""
412-
server.add(responses.POST, "https://example.com/api/updates", body=html, status=200)
413-
client = ElmoClient(base_url="https://example.com", domain="domain")
414-
client._session_id = "test"
415-
ids = {
416-
query.SECTORS: 42,
417-
query.INPUTS: 4242,
418-
}
419-
# Test
420-
with pytest.raises(ParseError):
421-
client.poll(ids)
428+
# Test
429+
with pytest.raises(ParseError):
430+
client.poll(ids)
431+
432+
def test_inputs_missing(self, server):
433+
"""Should raise a ParseError if the response is different from what is expected.
434+
In this case `Inputs` is missing from the response."""
435+
html = """
436+
{
437+
"ConnectionStatus": false,
438+
"CanElevate": false,
439+
"LoggedIn": false,
440+
"LoginInProgress": false,
441+
"Areas": false,
442+
"Events": true,
443+
"Outputs": false,
444+
"Anomalies": false,
445+
"ReadStringsInProgress": false,
446+
"ReadStringPercentage": 0,
447+
"Strings": 0,
448+
"ManagedAccounts": false,
449+
"Temperature": false,
450+
"StatusAdv": false,
451+
"Images": false,
452+
"AdditionalInfoSupported": true,
453+
"HasChanges": false
454+
}
455+
"""
456+
server.add(responses.POST, "https://example.com/api/updates", body=html, status=200)
457+
client = ElmoClient(base_url="https://example.com", domain="domain")
458+
client._session_id = "test"
459+
ids = {
460+
query.SECTORS: 42,
461+
query.INPUTS: 4242,
462+
query.ALERTS: 424242,
463+
}
464+
# Test
465+
with pytest.raises(ParseError):
466+
client.poll(ids)
467+
468+
def test_statusadv_missing(self, server):
469+
"""Should raise a ParseError if the response is different from what is expected.
470+
In this case `StatusAdv` is missing from the response."""
471+
html = """
472+
{
473+
"ConnectionStatus": false,
474+
"CanElevate": false,
475+
"LoggedIn": false,
476+
"LoginInProgress": false,
477+
"Areas": false,
478+
"Events": true,
479+
"Inputs": false,
480+
"Outputs": false,
481+
"Anomalies": false,
482+
"ReadStringsInProgress": false,
483+
"ReadStringPercentage": 0,
484+
"Strings": 0,
485+
"ManagedAccounts": false,
486+
"Temperature": false,
487+
"Images": false,
488+
"AdditionalInfoSupported": true,
489+
"HasChanges": false
490+
}
491+
"""
492+
server.add(responses.POST, "https://example.com/api/updates", body=html, status=200)
493+
client = ElmoClient(base_url="https://example.com", domain="domain")
494+
client._session_id = "test"
495+
ids = {
496+
query.SECTORS: 42,
497+
query.INPUTS: 4242,
498+
query.ALERTS: 424242,
499+
}
500+
# Test
501+
with pytest.raises(ParseError):
502+
client.poll(ids)
422503

423504

424505
def test_client_lock(server, mocker):
@@ -1680,31 +1761,34 @@ def test_client_get_alerts_status(server):
16801761
assert body == "sessionId=test"
16811762
# Expected output
16821763
assert alerts == {
1683-
0: {"name": "alarm_led", "status": 0},
1684-
1: {"name": "anomalies_led", "status": 1},
1685-
2: {"name": "device_failure", "status": 0},
1686-
3: {"name": "device_low_battery", "status": 0},
1687-
4: {"name": "device_no_power", "status": 0},
1688-
5: {"name": "device_no_supervision", "status": 0},
1689-
6: {"name": "device_system_block", "status": 0},
1690-
7: {"name": "device_tamper", "status": 0},
1691-
8: {"name": "gsm_anomaly", "status": 0},
1692-
9: {"name": "gsm_low_balance", "status": 0},
1693-
10: {"name": "has_anomaly", "status": False},
1694-
11: {"name": "input_alarm", "status": 0},
1695-
12: {"name": "input_bypass", "status": 0},
1696-
13: {"name": "input_failure", "status": 0},
1697-
14: {"name": "input_low_battery", "status": 0},
1698-
15: {"name": "input_no_supervision", "status": 0},
1699-
16: {"name": "inputs_led", "status": 2},
1700-
17: {"name": "module_registration", "status": 0},
1701-
18: {"name": "panel_low_battery", "status": 0},
1702-
19: {"name": "panel_no_power", "status": 0},
1703-
20: {"name": "panel_tamper", "status": 0},
1704-
21: {"name": "pstn_anomaly", "status": 0},
1705-
22: {"name": "rf_interference", "status": 0},
1706-
23: {"name": "system_test", "status": 0},
1707-
24: {"name": "tamper_led", "status": 0},
1764+
"last_id": 1,
1765+
"alerts": {
1766+
0: {"name": "alarm_led", "status": 0},
1767+
1: {"name": "anomalies_led", "status": 1},
1768+
2: {"name": "device_failure", "status": 0},
1769+
3: {"name": "device_low_battery", "status": 0},
1770+
4: {"name": "device_no_power", "status": 0},
1771+
5: {"name": "device_no_supervision", "status": 0},
1772+
6: {"name": "device_system_block", "status": 0},
1773+
7: {"name": "device_tamper", "status": 0},
1774+
8: {"name": "gsm_anomaly", "status": 0},
1775+
9: {"name": "gsm_low_balance", "status": 0},
1776+
10: {"name": "has_anomaly", "status": False},
1777+
11: {"name": "input_alarm", "status": 0},
1778+
12: {"name": "input_bypass", "status": 0},
1779+
13: {"name": "input_failure", "status": 0},
1780+
14: {"name": "input_low_battery", "status": 0},
1781+
15: {"name": "input_no_supervision", "status": 0},
1782+
16: {"name": "inputs_led", "status": 2},
1783+
17: {"name": "module_registration", "status": 0},
1784+
18: {"name": "panel_low_battery", "status": 0},
1785+
19: {"name": "panel_no_power", "status": 0},
1786+
20: {"name": "panel_tamper", "status": 0},
1787+
21: {"name": "pstn_anomaly", "status": 0},
1788+
22: {"name": "rf_interference", "status": 0},
1789+
23: {"name": "system_test", "status": 0},
1790+
24: {"name": "tamper_led", "status": 0},
1791+
},
17081792
}
17091793

17101794

0 commit comments

Comments
 (0)