Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
67 changes: 65 additions & 2 deletions homeassistant/components/daikin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
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
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -127,3 +130,63 @@ def device_info(self) -> DeviceInfo:
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.get("name")
Comment thread
mover85 marked this conversation as resolved.
Outdated

@callback
def update_unique_id(entity_entry: er.RegistryEntry) -> dict[str, str] | None:
"""Update unique ID of entity entry."""
if entity_entry.unique_id.startswith(new_unique_id):
# Already correct, nothing to do
return None

unique_id_parts = entity_entry.unique_id.split("-")
unique_id_parts[0] = new_unique_id
entity_new_unique_id = "-".join(unique_id_parts)

_LOGGER.info(
"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}

if new_unique_id != old_unique_id:
Comment thread
mover85 marked this conversation as resolved.
Outdated
# 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.info(
Comment thread
mover85 marked this conversation as resolved.
Outdated
"Migrating device %s to %s and connections to %s",
device_entry.name,
new_name,
new_connections,
)
dev_reg.async_update_device(
device_entry.id,
name=new_name,
merge_connections=new_connections,
)

# 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
)
2 changes: 1 addition & 1 deletion homeassistant/components/daikin/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -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."]
}
2 changes: 1 addition & 1 deletion homeassistant/components/daikin/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1615,7 +1615,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
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1197,7 +1197,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
Expand Down
85 changes: 85 additions & 0 deletions tests/components/daikin/test_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"""Define tests for the Airzone init."""
Comment thread
mover85 marked this conversation as resolved.
Outdated

from homeassistant.components.daikin.const import DOMAIN, KEY_MAC
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
from tests.test_util.aiohttp import mock_aiohttp_client

DATA = {
"skyfi/common/get_datetime?cur=": {
"text": "ret=OK,sta=2,cur=2023/6/5 13:36:41,reg=au,dst=1,zone=27"
},
"common/basic_info": {"text": "", "status": 404},
"skyfi/common/basic_info": {
"text": "ret=OK,type=aircon,reg=au,dst=1,ver=1_1_8,rev=1F,pow=1,err=0,location=0,name=%44%61%69%6b%69%6e%41%50%30%30%30%30%30,icon=0,method=home only,port=30050,id=,pw=,lpw_flag=0,adp_kind=3,led=1,en_setzone=1,mac=AABBCCDDEEFF,adp_mode=run,ssid=DaikinAP00000,err_type=0,err_code=0,en_ch=1,holiday=1,en_hol=0,sync_time=0"
},
"skyfi/aircon/get_control_info": {
"text": "ret=OK,pow=1,mode=1,operate=1,bk_auto=1,stemp=21,dt1=21,dt2=28,f_rate=1,dfr1=1,dfr2=1,f_airside=1,airside1=1,airside2=1,f_auto=0,auto1=0,auto2=0,f_dir=0,dfd1=0,dfd2=1,filter_sign_info=0,cent=0,en_cent=0,remo=2"
},
"skyfi/aircon/get_model_info": {
"text": "ret=OK,err=0,model=NOTSUPPORT,type=N,humd=0,s_humd=7,en_zone=4,en_linear_zone=1,en_filter_sign=1,acled=1,land=0,elec=0,temp=1,m_dtct=0,ac_dst=au,dmnd=0,en_temp_setting=1,en_frate=1,en_fdir=0,en_rtemp_a=0,en_spmode=0,en_ipw_sep=0,en_scdltmr=0,en_mompow=0,en_patrol=0,en_airside=1,en_quick_timer=1,en_auto=1,en_dry=1,en_common_zone=0,cool_l=16,cool_h=32,heat_l=16,heat_h=32,frate_steps=3,en_frate_auto=1"
},
"skyfi/aircon/get_sensor_info": {"text": "ret=OK,err=0,htemp=21,otemp=-"},
"skyfi/aircon/get_zone_setting": {
"text": "ret=OK,zone_name=%5a%6f%6e%65%20%31%3b%5a%6f%6e%65%20%32%3b%5a%6f%6e%65%20%33%3b%5a%6f%6e%65%20%34%3b%2d%3b%2d%3b%2d%3b%2d,zone_onoff=1%3b1%3b0%3b1%3b0%3b0%3b0%3b0,lztemp_c=22%3b22%3b22%3b22%3b22%3b22%3b22%3b22,lztemp_h=21%3b19%3b19%3b0%3b0%3b0%3b0%3b0"
},
}
Comment thread
mover85 marked this conversation as resolved.

INVALID_DATA = {
**DATA,
"skyfi/common/basic_info": {"text": "", "status": 404},
}


async def test_unique_id_migrate(hass: HomeAssistant) -> 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)

with mock_aiohttp_client() as newsession:
Comment thread
mover85 marked this conversation as resolved.
Outdated
for path, data in INVALID_DATA.items():
newsession.get(f"http://{HOST}/{path}", **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

assert entity_registry.async_get("climate.daikin_127_0_0_1").unique_id == HOST
assert entity_registry.async_get("switch.none_zone_1").unique_id.startswith(
HOST
)

newsession.clear_requests()

for path, data in DATA.items():
newsession.get(f"http://{HOST}/{path}", **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"
)

assert entity_registry.async_get("climate.daikin_127_0_0_1").unique_id == MAC
assert entity_registry.async_get("switch.none_zone_1").unique_id.startswith(MAC)