diff --git a/src/elmo/api/client.py b/src/elmo/api/client.py index 6d26841..7fc4487 100644 --- a/src/elmo/api/client.py +++ b/src/elmo/api/client.py @@ -653,13 +653,16 @@ def query(self, query): # Address potential data inconsistency between cloud data and main unit. # In some installations, they may be out of sync, resulting in the cloud # providing a sector/input/output that doesn't actually exist in the main unit. + # This case happens also when all inputs or sectors or outputs are used in the + # main unit, but their strings are not synchronized with the cloud. # To handle this, we default the name to "Unknown" if its description # isn't found in the cloud data to prevent KeyError. + description = descriptions.get(query, {}) item = { "id": entry.get("Id"), "index": entry.get("Index"), "element": entry.get("Element"), - "name": descriptions[query].get(entry["Index"], "Unknown"), + "name": description.get(entry["Index"], "Unknown"), } if query == q.SECTORS: diff --git a/tests/test_client.py b/tests/test_client.py index c3abde0..dd8ad91 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1928,6 +1928,137 @@ def test_client_get_outputs_status(server, mocker): } +def test_client_missing_sectors_strings(server, mocker): + """The query should return an empty list if outputs strings are not synchronized. + Regression test for: https://github.com/palazzem/ha-econnect-alarm/issues/115 + """ + html = """[ + { + "Active": true, + "ActivePartial": false, + "Max": false, + "Activable": true, + "ActivablePartial": false, + "InUse": true, + "Id": 1, + "Index": 0, + "Element": 1, + "CommandId": 0, + "InProgress": false + } + ]""" + server.add(responses.POST, "https://example.com/api/areas", body=html, status=200) + client = ElmoClient(base_url="https://example.com", domain="domain") + client._session_id = "test" + mocker.patch.object(client, "_get_descriptions") + client._get_descriptions.return_value = {} + # Test + sectors = client.query(query.SECTORS) + # Expected output + assert client._get_descriptions.called is True + assert len(server.calls) == 1 + assert sectors == { + "last_id": 1, + "sectors": { + 0: { + "element": 1, + "id": 1, + "index": 0, + "status": True, + "activable": True, + "name": "Unknown", + }, + }, + } + + +def test_client_missing_inputs_strings(server, mocker): + """The query should return an empty list if outputs strings are not synchronized. + Regression test for: https://github.com/palazzem/ha-econnect-alarm/issues/115 + """ + html = """[ + { + "Alarm": true, + "MemoryAlarm": false, + "Excluded": false, + "InUse": true, + "IsVideo": false, + "Id": 1, + "Index": 0, + "Element": 1, + "CommandId": 0, + "InProgress": false + } + ]""" + server.add(responses.POST, "https://example.com/api/inputs", body=html, status=200) + client = ElmoClient(base_url="https://example.com", domain="domain") + client._session_id = "test" + mocker.patch.object(client, "_get_descriptions") + client._get_descriptions.return_value = {} + # Test + inputs = client.query(query.INPUTS) + # Expected output + assert client._get_descriptions.called is True + assert len(server.calls) == 1 + assert inputs == { + "last_id": 1, + "inputs": { + 0: { + "element": 1, + "id": 1, + "index": 0, + "status": True, + "excluded": False, + "name": "Unknown", + }, + }, + } + + +def test_client_missing_outputs_strings(server, mocker): + """The query should return an empty list if outputs strings are not synchronized. + Regression test for: https://github.com/palazzem/ha-econnect-alarm/issues/115 + """ + html = """[ + { + "Active": true, + "InUse": true, + "DoNotRequireAuthentication": true, + "ControlDeniedToUsers": false, + "Id": 400258, + "Index": 0, + "Element": 1, + "CommandId": 0, + "InProgress": false + } + ]""" + server.add(responses.POST, "https://example.com/api/outputs", body=html, status=200) + client = ElmoClient(base_url="https://example.com", domain="domain") + client._session_id = "test" + mocker.patch.object(client, "_get_descriptions") + client._get_descriptions.return_value = {} + # Test + outputs = client.query(query.OUTPUTS) + # Expected output + assert client._get_descriptions.called is True + assert len(server.calls) == 1 + + assert outputs == { + "last_id": 400258, + "outputs": { + 0: { + "control_denied_to_users": False, + "do_not_require_authentication": True, + "element": 1, + "id": 400258, + "index": 0, + "name": "Unknown", + "status": True, + }, + }, + } + + def test_client_get_sectors_missing_area(server, mocker): """Should set an Unknown `sector` name if the description is missing. Regression test for: https://github.com/palazzem/econnect-python/issues/91"""