Honeywell unique id fix (#59393)

* Move error logging and remove reload

* Change device assignment and improve logging

* Use dictionary for devices

* Check if new device exists in API response

* Add test and make loop better

* Make test assert on error in log
This commit is contained in:
RDFurman 2021-12-13 21:38:43 -07:00 committed by GitHub
parent 228f141bfd
commit 1ed6abe23d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 14 deletions

View File

@ -30,14 +30,13 @@ async def async_setup_entry(hass, config):
loc_id = config.data.get(CONF_LOC_ID) loc_id = config.data.get(CONF_LOC_ID)
dev_id = config.data.get(CONF_DEV_ID) dev_id = config.data.get(CONF_DEV_ID)
devices = [] devices = {}
for location in client.locations_by_id.values(): for location in client.locations_by_id.values():
for device in location.devices_by_id.values(): if not loc_id or location.locationid == loc_id:
if (not loc_id or location.locationid == loc_id) and ( for device in location.devices_by_id.values():
not dev_id or device.deviceid == dev_id if not dev_id or device.deviceid == dev_id:
): devices[device.deviceid] = device
devices.append(device)
if len(devices) == 0: if len(devices) == 0:
_LOGGER.debug("No devices found") _LOGGER.debug("No devices found")
@ -107,23 +106,30 @@ class HoneywellData:
if self._client is None: if self._client is None:
return False return False
devices = [ refreshed_devices = [
device device
for location in self._client.locations_by_id.values() for location in self._client.locations_by_id.values()
for device in location.devices_by_id.values() for device in location.devices_by_id.values()
] ]
if len(devices) == 0: if len(refreshed_devices) == 0:
_LOGGER.error("Failed to find any devices") _LOGGER.error("Failed to find any devices after retry")
return False return False
self.devices = devices for updated_device in refreshed_devices:
if updated_device.deviceid in self.devices:
self.devices[updated_device.deviceid] = updated_device
else:
_LOGGER.info(
"New device with ID %s detected, reload the honeywell integration if you want to access it in Home Assistant"
)
await self._hass.config_entries.async_reload(self._config.entry_id) await self._hass.config_entries.async_reload(self._config.entry_id)
return True return True
async def _refresh_devices(self): async def _refresh_devices(self):
"""Refresh each enabled device.""" """Refresh each enabled device."""
for device in self.devices: for device in self.devices.values():
await self._hass.async_add_executor_job(device.refresh) await self._hass.async_add_executor_job(device.refresh)
await asyncio.sleep(UPDATE_LOOP_SLEEP_TIME) await asyncio.sleep(UPDATE_LOOP_SLEEP_TIME)
@ -143,11 +149,16 @@ class HoneywellData:
) as exp: ) as exp:
retries -= 1 retries -= 1
if retries == 0: if retries == 0:
_LOGGER.error(
"Ran out of retry attempts (3 attempts allocated). Error: %s",
exp,
)
raise exp raise exp
result = await self._retry() result = await self._retry()
if not result: if not result:
_LOGGER.error("Retry result was empty. Error: %s", exp)
raise exp raise exp
_LOGGER.error("SomeComfort update failed, Retrying - Error: %s", exp) _LOGGER.info("SomeComfort update failed, retrying. Error: %s", exp)

View File

@ -122,7 +122,7 @@ async def async_setup_entry(hass, config, async_add_entities, discovery_info=Non
async_add_entities( async_add_entities(
[ [
HoneywellUSThermostat(data, device, cool_away_temp, heat_away_temp) HoneywellUSThermostat(data, device, cool_away_temp, heat_away_temp)
for device in data.devices for device in data.devices.values()
] ]
) )

View File

@ -1,6 +1,8 @@
"""Test honeywell setup process.""" """Test honeywell setup process."""
from unittest.mock import patch from unittest.mock import create_autospec, patch
import somecomfort
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -29,3 +31,20 @@ async def test_setup_multiple_thermostats(
await hass.async_block_till_done() await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED assert config_entry.state is ConfigEntryState.LOADED
assert hass.states.async_entity_ids_count() == 2 assert hass.states.async_entity_ids_count() == 2
@patch("homeassistant.components.honeywell.UPDATE_LOOP_SLEEP_TIME", 0)
async def test_setup_multiple_thermostats_with_same_deviceid(
hass: HomeAssistant, caplog, config_entry: MockConfigEntry, device, client
) -> None:
"""Test Honeywell TCC API returning duplicate device IDs."""
mock_location2 = create_autospec(somecomfort.Location, instance=True)
mock_location2.locationid.return_value = "location2"
mock_location2.devices_by_id = {device.deviceid: device}
client.locations_by_id["location2"] = mock_location2
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
assert hass.states.async_entity_ids_count() == 1
assert "Platform honeywell does not generate unique IDs" not in caplog.text