Bump pydaikin 2.10.5 (#95656)

This commit is contained in:
Aaron Collins 2023-07-06 00:12:18 +12:00 committed by GitHub
parent b2e708834f
commit f028d1a1ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 216 additions and 7 deletions

View file

@ -182,7 +182,6 @@ omit =
homeassistant/components/crownstone/listeners.py
homeassistant/components/cups/sensor.py
homeassistant/components/currencylayer/sensor.py
homeassistant/components/daikin/__init__.py
homeassistant/components/daikin/climate.py
homeassistant/components/daikin/sensor.py
homeassistant/components/daikin/switch.py

View file

@ -15,8 +15,9 @@ from homeassistant.const import (
CONF_UUID,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
@ -52,6 +53,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if not daikin_api:
return False
await async_migrate_unique_id(hass, entry, daikin_api)
hass.data.setdefault(DOMAIN, {}).update({entry.entry_id: daikin_api})
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
@ -67,7 +70,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return unload_ok
async def daikin_api_setup(hass, host, key, uuid, password):
async def daikin_api_setup(hass: HomeAssistant, host, key, uuid, password):
"""Create a Daikin instance only once."""
session = async_get_clientsession(hass)
@ -127,3 +130,82 @@ class DaikinApi:
name=info.get("name"),
sw_version=info.get("ver", "").replace("_", "."),
)
async def async_migrate_unique_id(
hass: HomeAssistant, config_entry: ConfigEntry, api: DaikinApi
) -> None:
"""Migrate old entry."""
dev_reg = dr.async_get(hass)
old_unique_id = config_entry.unique_id
new_unique_id = api.device.mac
new_name = api.device.values["name"]
@callback
def _update_unique_id(entity_entry: er.RegistryEntry) -> dict[str, str] | None:
"""Update unique ID of entity entry."""
return update_unique_id(entity_entry, new_unique_id)
if new_unique_id == old_unique_id:
return
# Migrate devices
for device_entry in dr.async_entries_for_config_entry(
dev_reg, config_entry.entry_id
):
for connection in device_entry.connections:
if connection[1] == old_unique_id:
new_connections = {
(CONNECTION_NETWORK_MAC, dr.format_mac(new_unique_id))
}
_LOGGER.debug(
"Migrating device %s connections to %s",
device_entry.name,
new_connections,
)
dev_reg.async_update_device(
device_entry.id,
merge_connections=new_connections,
)
if device_entry.name is None:
_LOGGER.debug(
"Migrating device name to %s",
new_name,
)
dev_reg.async_update_device(
device_entry.id,
name=new_name,
)
# Migrate entities
await er.async_migrate_entries(hass, config_entry.entry_id, _update_unique_id)
new_data = {**config_entry.data, KEY_MAC: dr.format_mac(new_unique_id)}
hass.config_entries.async_update_entry(
config_entry, unique_id=new_unique_id, data=new_data
)
@callback
def update_unique_id(
entity_entry: er.RegistryEntry, unique_id: str
) -> dict[str, str] | None:
"""Update unique ID of entity entry."""
if entity_entry.unique_id.startswith(unique_id):
# Already correct, nothing to do
return None
unique_id_parts = entity_entry.unique_id.split("-")
unique_id_parts[0] = unique_id
entity_new_unique_id = "-".join(unique_id_parts)
_LOGGER.debug(
"Migrating entity %s from %s to new id %s",
entity_entry.entity_id,
entity_entry.unique_id,
entity_new_unique_id,
)
return {"new_unique_id": entity_new_unique_id}

View file

@ -7,6 +7,6 @@
"iot_class": "local_polling",
"loggers": ["pydaikin"],
"quality_scale": "platinum",
"requirements": ["pydaikin==2.9.0"],
"requirements": ["pydaikin==2.10.5"],
"zeroconf": ["_dkapi._tcp.local."]
}

View file

@ -42,7 +42,7 @@ async def async_setup_entry(
[
DaikinZoneSwitch(daikin_api, zone_id)
for zone_id, zone in enumerate(zones)
if zone != ("-", "0")
if zone[0] != "-"
]
)
if daikin_api.device.support_advanced_modes:

View file

@ -1618,7 +1618,7 @@ pycsspeechtts==1.0.8
# pycups==1.9.73
# homeassistant.components.daikin
pydaikin==2.9.0
pydaikin==2.10.5
# homeassistant.components.danfoss_air
pydanfossair==0.1.0

View file

@ -1200,7 +1200,7 @@ pycoolmasternet-async==0.1.5
pycsspeechtts==1.0.8
# homeassistant.components.daikin
pydaikin==2.9.0
pydaikin==2.10.5
# homeassistant.components.deconz
pydeconz==113

View file

@ -0,0 +1,128 @@
"""Define tests for the Daikin init."""
import asyncio
from unittest.mock import AsyncMock, PropertyMock, patch
from aiohttp import ClientConnectionError
import pytest
from homeassistant.components.daikin import update_unique_id
from homeassistant.components.daikin.const import DOMAIN, KEY_MAC
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from .test_config_flow import HOST, MAC
from tests.common import MockConfigEntry
@pytest.fixture
def mock_daikin():
"""Mock pydaikin."""
async def mock_daikin_factory(*args, **kwargs):
"""Mock the init function in pydaikin."""
return Appliance
with patch("homeassistant.components.daikin.Appliance") as Appliance:
Appliance.factory.side_effect = mock_daikin_factory
type(Appliance).update_status = AsyncMock()
type(Appliance).inside_temperature = PropertyMock(return_value=22)
type(Appliance).target_temperature = PropertyMock(return_value=22)
type(Appliance).zones = PropertyMock(return_value=[("Zone 1", "0", 0)])
type(Appliance).fan_rate = PropertyMock(return_value=[])
type(Appliance).swing_modes = PropertyMock(return_value=[])
yield Appliance
DATA = {
"ver": "1_1_8",
"name": "DaikinAP00000",
"mac": MAC,
"model": "NOTSUPPORT",
}
INVALID_DATA = {**DATA, "name": None, "mac": HOST}
async def test_unique_id_migrate(hass: HomeAssistant, mock_daikin) -> None:
"""Test unique id migration."""
config_entry = MockConfigEntry(
domain=DOMAIN,
unique_id=HOST,
title=None,
data={CONF_HOST: HOST, KEY_MAC: HOST},
)
config_entry.add_to_hass(hass)
entity_registry = er.async_get(hass)
device_registry = dr.async_get(hass)
type(mock_daikin).mac = PropertyMock(return_value=HOST)
type(mock_daikin).values = PropertyMock(return_value=INVALID_DATA)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.unique_id == HOST
assert device_registry.async_get_device({}, {(KEY_MAC, HOST)}).name is None
entity = entity_registry.async_get("climate.daikin_127_0_0_1")
assert entity.unique_id == HOST
assert update_unique_id(entity, MAC) is not None
assert entity_registry.async_get("switch.none_zone_1").unique_id.startswith(HOST)
type(mock_daikin).mac = PropertyMock(return_value=MAC)
type(mock_daikin).values = PropertyMock(return_value=DATA)
assert config_entry.unique_id != MAC
assert await hass.config_entries.async_reload(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.unique_id == MAC
assert (
device_registry.async_get_device({}, {(KEY_MAC, MAC)}).name == "DaikinAP00000"
)
entity = entity_registry.async_get("climate.daikin_127_0_0_1")
assert entity.unique_id == MAC
assert update_unique_id(entity, MAC) is None
assert entity_registry.async_get("switch.none_zone_1").unique_id.startswith(MAC)
async def test_client_connection_error(hass: HomeAssistant, mock_daikin) -> None:
"""Test unique id migration."""
config_entry = MockConfigEntry(
domain=DOMAIN,
unique_id=MAC,
data={CONF_HOST: HOST, KEY_MAC: MAC},
)
config_entry.add_to_hass(hass)
mock_daikin.factory.side_effect = ClientConnectionError
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state == ConfigEntryState.SETUP_RETRY
async def test_timeout_error(hass: HomeAssistant, mock_daikin) -> None:
"""Test unique id migration."""
config_entry = MockConfigEntry(
domain=DOMAIN,
unique_id=MAC,
data={CONF_HOST: HOST, KEY_MAC: MAC},
)
config_entry.add_to_hass(hass)
mock_daikin.factory.side_effect = asyncio.TimeoutError
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state == ConfigEntryState.SETUP_RETRY