mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +00:00
Add multi device support back to honeywell (#54003)
* Add multi device support back to honeywell * Fix device reference in honeywell climate * Use deviceid for unique_id * Add test for multiple thermostats * Reduce recursive jobs * Remove old filter Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
09b872d51f
commit
2aed7b94c5
@ -41,7 +41,7 @@ async def async_setup_entry(hass, config):
|
||||
_LOGGER.debug("No devices found")
|
||||
return False
|
||||
|
||||
data = HoneywellService(hass, client, username, password, devices[0])
|
||||
data = HoneywellData(hass, client, username, password, devices)
|
||||
await data.update()
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
hass.data[DOMAIN][config.entry_id] = data
|
||||
@ -65,16 +65,16 @@ def get_somecomfort_client(username, password):
|
||||
) from ex
|
||||
|
||||
|
||||
class HoneywellService:
|
||||
class HoneywellData:
|
||||
"""Get the latest data and update."""
|
||||
|
||||
def __init__(self, hass, client, username, password, device):
|
||||
def __init__(self, hass, client, username, password, devices):
|
||||
"""Initialize the data object."""
|
||||
self._hass = hass
|
||||
self._client = client
|
||||
self._username = username
|
||||
self._password = password
|
||||
self.device = device
|
||||
self.devices = devices
|
||||
|
||||
async def _retry(self) -> bool:
|
||||
"""Recreate a new somecomfort client.
|
||||
@ -93,23 +93,27 @@ class HoneywellService:
|
||||
device
|
||||
for location in self._client.locations_by_id.values()
|
||||
for device in location.devices_by_id.values()
|
||||
if device.name == self.device.name
|
||||
]
|
||||
|
||||
if len(devices) != 1:
|
||||
_LOGGER.error("Failed to find device %s", self.device.name)
|
||||
if len(devices) == 0:
|
||||
_LOGGER.error("Failed to find any devices")
|
||||
return False
|
||||
|
||||
self.device = devices[0]
|
||||
self.devices = devices
|
||||
return True
|
||||
|
||||
def _refresh_devices(self):
|
||||
"""Refresh each enabled device."""
|
||||
for device in self.devices:
|
||||
device.refresh()
|
||||
|
||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||
async def update(self) -> None:
|
||||
"""Update the state."""
|
||||
retries = 3
|
||||
while retries > 0:
|
||||
try:
|
||||
await self._hass.async_add_executor_job(self.device.refresh)
|
||||
await self._hass.async_add_executor_job(self._refresh_devices)
|
||||
break
|
||||
except (
|
||||
somecomfort.client.APIRateLimited,
|
||||
@ -126,7 +130,3 @@ class HoneywellService:
|
||||
raise exp
|
||||
|
||||
_LOGGER.error("SomeComfort update failed, Retrying - Error: %s", exp)
|
||||
|
||||
_LOGGER.debug(
|
||||
"latestData = %s ", self.device._data # pylint: disable=protected-access
|
||||
)
|
||||
|
@ -41,7 +41,6 @@ from homeassistant.const import (
|
||||
TEMP_FAHRENHEIT,
|
||||
)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
import homeassistant.helpers.device_registry as dr
|
||||
|
||||
from .const import (
|
||||
_LOGGER,
|
||||
@ -116,7 +115,12 @@ async def async_setup_entry(hass, config, async_add_entities, discovery_info=Non
|
||||
|
||||
data = hass.data[DOMAIN][config.entry_id]
|
||||
|
||||
async_add_entities([HoneywellUSThermostat(data, cool_away_temp, heat_away_temp)])
|
||||
async_add_entities(
|
||||
[
|
||||
HoneywellUSThermostat(data, device, cool_away_temp, heat_away_temp)
|
||||
for device in data.devices
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
@ -142,25 +146,24 @@ async def async_setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
class HoneywellUSThermostat(ClimateEntity):
|
||||
"""Representation of a Honeywell US Thermostat."""
|
||||
|
||||
def __init__(self, data, cool_away_temp, heat_away_temp):
|
||||
def __init__(self, data, device, cool_away_temp, heat_away_temp):
|
||||
"""Initialize the thermostat."""
|
||||
self._data = data
|
||||
self._device = device
|
||||
self._cool_away_temp = cool_away_temp
|
||||
self._heat_away_temp = heat_away_temp
|
||||
self._away = False
|
||||
|
||||
self._attr_unique_id = dr.format_mac(data.device.mac_address)
|
||||
self._attr_name = data.device.name
|
||||
self._attr_unique_id = device.deviceid
|
||||
self._attr_name = device.name
|
||||
self._attr_temperature_unit = (
|
||||
TEMP_CELSIUS if data.device.temperature_unit == "C" else TEMP_FAHRENHEIT
|
||||
TEMP_CELSIUS if device.temperature_unit == "C" else TEMP_FAHRENHEIT
|
||||
)
|
||||
self._attr_preset_modes = [PRESET_NONE, PRESET_AWAY]
|
||||
self._attr_is_aux_heat = data.device.system_mode == "emheat"
|
||||
self._attr_is_aux_heat = device.system_mode == "emheat"
|
||||
|
||||
# not all honeywell HVACs support all modes
|
||||
mappings = [
|
||||
v for k, v in HVAC_MODE_TO_HW_MODE.items() if data.device.raw_ui_data[k]
|
||||
]
|
||||
mappings = [v for k, v in HVAC_MODE_TO_HW_MODE.items() if device.raw_ui_data[k]]
|
||||
self._hvac_mode_map = {k: v for d in mappings for k, v in d.items()}
|
||||
self._attr_hvac_modes = list(self._hvac_mode_map)
|
||||
|
||||
@ -170,28 +173,23 @@ class HoneywellUSThermostat(ClimateEntity):
|
||||
| SUPPORT_TARGET_TEMPERATURE_RANGE
|
||||
)
|
||||
|
||||
if data.device._data["canControlHumidification"]:
|
||||
if device._data["canControlHumidification"]:
|
||||
self._attr_supported_features |= SUPPORT_TARGET_HUMIDITY
|
||||
|
||||
if data.device.raw_ui_data["SwitchEmergencyHeatAllowed"]:
|
||||
if device.raw_ui_data["SwitchEmergencyHeatAllowed"]:
|
||||
self._attr_supported_features |= SUPPORT_AUX_HEAT
|
||||
|
||||
if not data.device._data["hasFan"]:
|
||||
if not device._data["hasFan"]:
|
||||
return
|
||||
|
||||
# not all honeywell fans support all modes
|
||||
mappings = [v for k, v in FAN_MODE_TO_HW.items() if data.device.raw_fan_data[k]]
|
||||
mappings = [v for k, v in FAN_MODE_TO_HW.items() if device.raw_fan_data[k]]
|
||||
self._fan_mode_map = {k: v for d in mappings for k, v in d.items()}
|
||||
|
||||
self._attr_fan_modes = list(self._fan_mode_map)
|
||||
|
||||
self._attr_supported_features |= SUPPORT_FAN_MODE
|
||||
|
||||
@property
|
||||
def _device(self):
|
||||
"""Shortcut to access the device."""
|
||||
return self._data.device
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the device specific state attributes."""
|
||||
|
@ -31,7 +31,7 @@ def config_entry(config_data):
|
||||
def device():
|
||||
"""Mock a somecomfort.Device."""
|
||||
mock_device = create_autospec(somecomfort.Device, instance=True)
|
||||
mock_device.deviceid.return_value = "device1"
|
||||
mock_device.deviceid = 1234567
|
||||
mock_device._data = {
|
||||
"canControlHumidification": False,
|
||||
"hasFan": False,
|
||||
@ -43,6 +43,22 @@ def device():
|
||||
return mock_device
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def another_device():
|
||||
"""Mock a somecomfort.Device."""
|
||||
mock_device = create_autospec(somecomfort.Device, instance=True)
|
||||
mock_device.deviceid = 7654321
|
||||
mock_device._data = {
|
||||
"canControlHumidification": False,
|
||||
"hasFan": False,
|
||||
}
|
||||
mock_device.system_mode = "off"
|
||||
mock_device.name = "device2"
|
||||
mock_device.current_temperature = 20
|
||||
mock_device.mac_address = "macaddress1"
|
||||
return mock_device
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def location(device):
|
||||
"""Mock a somecomfort.Location."""
|
||||
|
@ -1,8 +1,27 @@
|
||||
"""Test honeywell setup process."""
|
||||
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
async def test_setup_entry(hass, config_entry):
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_setup_entry(hass: HomeAssistant, config_entry: MockConfigEntry):
|
||||
"""Initialize the config entry."""
|
||||
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
|
||||
|
||||
|
||||
async def test_setup_multiple_thermostats(
|
||||
hass: HomeAssistant, config_entry: MockConfigEntry, location, another_device
|
||||
) -> None:
|
||||
"""Test that the config form is shown."""
|
||||
location.devices_by_id[another_device.deviceid] = another_device
|
||||
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() == 2
|
||||
|
Loading…
x
Reference in New Issue
Block a user