Update pydaikin to 2.0.0 (#34807)
This commit is contained in:
parent
c71a7b901f
commit
d8222a8eb6
12 changed files with 91 additions and 54 deletions
|
@ -5,19 +5,18 @@ import logging
|
||||||
|
|
||||||
from aiohttp import ClientConnectionError
|
from aiohttp import ClientConnectionError
|
||||||
from async_timeout import timeout
|
from async_timeout import timeout
|
||||||
from pydaikin.appliance import Appliance
|
from pydaikin.daikin_base import Appliance
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||||
from homeassistant.const import CONF_HOST, CONF_HOSTS
|
from homeassistant.const import CONF_HOST, CONF_HOSTS, CONF_PASSWORD
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
|
|
||||||
from homeassistant.helpers.typing import HomeAssistantType
|
from homeassistant.helpers.typing import HomeAssistantType
|
||||||
from homeassistant.util import Throttle
|
from homeassistant.util import Throttle
|
||||||
|
|
||||||
from . import config_flow # noqa: F401
|
from . import config_flow # noqa: F401
|
||||||
from .const import TIMEOUT
|
from .const import CONF_KEY, CONF_UUID, TIMEOUT
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -62,7 +61,13 @@ async def async_setup(hass, config):
|
||||||
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
|
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
|
||||||
"""Establish connection with Daikin."""
|
"""Establish connection with Daikin."""
|
||||||
conf = entry.data
|
conf = entry.data
|
||||||
daikin_api = await daikin_api_setup(hass, conf[CONF_HOST])
|
daikin_api = await daikin_api_setup(
|
||||||
|
hass,
|
||||||
|
conf[CONF_HOST],
|
||||||
|
conf.get(CONF_KEY),
|
||||||
|
conf.get(CONF_UUID),
|
||||||
|
conf.get(CONF_PASSWORD),
|
||||||
|
)
|
||||||
if not daikin_api:
|
if not daikin_api:
|
||||||
return False
|
return False
|
||||||
hass.data.setdefault(DOMAIN, {}).update({entry.entry_id: daikin_api})
|
hass.data.setdefault(DOMAIN, {}).update({entry.entry_id: daikin_api})
|
||||||
|
@ -87,14 +92,15 @@ async def async_unload_entry(hass, config_entry):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def daikin_api_setup(hass, host):
|
async def daikin_api_setup(hass, host, key, uuid, password):
|
||||||
"""Create a Daikin instance only once."""
|
"""Create a Daikin instance only once."""
|
||||||
|
|
||||||
session = hass.helpers.aiohttp_client.async_get_clientsession()
|
session = hass.helpers.aiohttp_client.async_get_clientsession()
|
||||||
try:
|
try:
|
||||||
with timeout(TIMEOUT):
|
with timeout(TIMEOUT):
|
||||||
device = Appliance(host, session)
|
device = await Appliance.factory(
|
||||||
await device.init()
|
host, session, key=key, uuid=uuid, password=password
|
||||||
|
)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
_LOGGER.debug("Connection to %s timed out", host)
|
_LOGGER.debug("Connection to %s timed out", host)
|
||||||
raise ConfigEntryNotReady
|
raise ConfigEntryNotReady
|
||||||
|
@ -116,8 +122,8 @@ class DaikinApi:
|
||||||
def __init__(self, device):
|
def __init__(self, device):
|
||||||
"""Initialize the Daikin Handle."""
|
"""Initialize the Daikin Handle."""
|
||||||
self.device = device
|
self.device = device
|
||||||
self.name = device.values["name"]
|
self.name = device.values.get("name", "Daikin AC")
|
||||||
self.ip_address = device.ip
|
self.ip_address = device.device_ip
|
||||||
self._available = True
|
self._available = True
|
||||||
|
|
||||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||||
|
@ -135,20 +141,14 @@ class DaikinApi:
|
||||||
"""Return True if entity is available."""
|
"""Return True if entity is available."""
|
||||||
return self._available
|
return self._available
|
||||||
|
|
||||||
@property
|
|
||||||
def mac(self):
|
|
||||||
"""Return mac-address of device."""
|
|
||||||
return self.device.values.get(CONNECTION_NETWORK_MAC)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_info(self):
|
def device_info(self):
|
||||||
"""Return a device description for device registry."""
|
"""Return a device description for device registry."""
|
||||||
info = self.device.values
|
info = self.device.values
|
||||||
return {
|
return {
|
||||||
"connections": {(CONNECTION_NETWORK_MAC, self.mac)},
|
"identifieres": self.device.mac,
|
||||||
"identifieres": self.mac,
|
|
||||||
"manufacturer": "Daikin",
|
"manufacturer": "Daikin",
|
||||||
"model": info.get("model"),
|
"model": info.get("model"),
|
||||||
"name": info.get("name"),
|
"name": info.get("name"),
|
||||||
"sw_version": info.get("ver").replace("_", "."),
|
"sw_version": info.get("ver", "").replace("_", "."),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
"""Support for the Daikin HVAC."""
|
"""Support for the Daikin HVAC."""
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from pydaikin import appliance
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.climate import PLATFORM_SCHEMA, ClimateEntity
|
from homeassistant.components.climate import PLATFORM_SCHEMA, ClimateEntity
|
||||||
|
@ -96,12 +95,7 @@ class DaikinClimate(ClimateEntity):
|
||||||
self._list = {
|
self._list = {
|
||||||
ATTR_HVAC_MODE: list(HA_STATE_TO_DAIKIN),
|
ATTR_HVAC_MODE: list(HA_STATE_TO_DAIKIN),
|
||||||
ATTR_FAN_MODE: self._api.device.fan_rate,
|
ATTR_FAN_MODE: self._api.device.fan_rate,
|
||||||
ATTR_SWING_MODE: list(
|
ATTR_SWING_MODE: self._api.device.swing_modes,
|
||||||
map(
|
|
||||||
str.title,
|
|
||||||
appliance.daikin_values(HA_ATTR_TO_DAIKIN[ATTR_SWING_MODE]),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self._supported_features = SUPPORT_TARGET_TEMPERATURE
|
self._supported_features = SUPPORT_TARGET_TEMPERATURE
|
||||||
|
@ -156,7 +150,7 @@ class DaikinClimate(ClimateEntity):
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
"""Return a unique ID."""
|
"""Return a unique ID."""
|
||||||
return self._api.mac
|
return self._api.device.mac
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def temperature_unit(self):
|
def temperature_unit(self):
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
"""Config flow for the Daikin platform."""
|
"""Config flow for the Daikin platform."""
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
from aiohttp import ClientError
|
from aiohttp import ClientError
|
||||||
from async_timeout import timeout
|
from async_timeout import timeout
|
||||||
from pydaikin.appliance import Appliance
|
from pydaikin.daikin_base import Appliance
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.const import CONF_HOST
|
from homeassistant.const import CONF_HOST, CONF_PASSWORD
|
||||||
|
|
||||||
from .const import KEY_IP, KEY_MAC, TIMEOUT
|
from .const import CONF_KEY, CONF_UUID, KEY_IP, KEY_MAC, TIMEOUT
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -22,24 +23,46 @@ class FlowHandler(config_entries.ConfigFlow):
|
||||||
VERSION = 1
|
VERSION = 1
|
||||||
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
|
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
|
||||||
|
|
||||||
async def _create_entry(self, host, mac):
|
def _create_entry(self, host, mac, key=None, uuid=None, password=None):
|
||||||
"""Register new entry."""
|
"""Register new entry."""
|
||||||
# Check if mac already is registered
|
# Check if mac already is registered
|
||||||
for entry in self._async_current_entries():
|
for entry in self._async_current_entries():
|
||||||
if entry.data[KEY_MAC] == mac:
|
if entry.data[KEY_MAC] == mac:
|
||||||
return self.async_abort(reason="already_configured")
|
return self.async_abort(reason="already_configured")
|
||||||
|
|
||||||
return self.async_create_entry(title=host, data={CONF_HOST: host, KEY_MAC: mac})
|
return self.async_create_entry(
|
||||||
|
title=host,
|
||||||
|
data={
|
||||||
|
CONF_HOST: host,
|
||||||
|
KEY_MAC: mac,
|
||||||
|
CONF_KEY: key,
|
||||||
|
CONF_UUID: uuid,
|
||||||
|
CONF_PASSWORD: password,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
async def _create_device(self, host):
|
async def _create_device(self, host, key=None, password=None):
|
||||||
"""Create device."""
|
"""Create device."""
|
||||||
|
|
||||||
|
# BRP07Cxx devices needs uuid together with key
|
||||||
|
if key:
|
||||||
|
uuid = str(uuid4())
|
||||||
|
else:
|
||||||
|
uuid = None
|
||||||
|
key = None
|
||||||
|
|
||||||
|
if not password:
|
||||||
|
password = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
device = Appliance(
|
|
||||||
host, self.hass.helpers.aiohttp_client.async_get_clientsession()
|
|
||||||
)
|
|
||||||
with timeout(TIMEOUT):
|
with timeout(TIMEOUT):
|
||||||
await device.init()
|
device = await Appliance.factory(
|
||||||
|
host,
|
||||||
|
self.hass.helpers.aiohttp_client.async_get_clientsession(),
|
||||||
|
key=key,
|
||||||
|
uuid=uuid,
|
||||||
|
password=password,
|
||||||
|
)
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
return self.async_abort(reason="device_timeout")
|
return self.async_abort(reason="device_timeout")
|
||||||
except ClientError:
|
except ClientError:
|
||||||
|
@ -49,16 +72,27 @@ class FlowHandler(config_entries.ConfigFlow):
|
||||||
_LOGGER.exception("Unexpected error creating device")
|
_LOGGER.exception("Unexpected error creating device")
|
||||||
return self.async_abort(reason="device_fail")
|
return self.async_abort(reason="device_fail")
|
||||||
|
|
||||||
mac = device.values.get("mac")
|
mac = device.mac
|
||||||
return await self._create_entry(host, mac)
|
return self._create_entry(host, mac, key, uuid, password)
|
||||||
|
|
||||||
async def async_step_user(self, user_input=None):
|
async def async_step_user(self, user_input=None):
|
||||||
"""User initiated config flow."""
|
"""User initiated config flow."""
|
||||||
if user_input is None:
|
if user_input is None:
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="user", data_schema=vol.Schema({vol.Required(CONF_HOST): str})
|
step_id="user",
|
||||||
|
data_schema=vol.Schema(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_HOST): str,
|
||||||
|
vol.Optional(CONF_KEY): str,
|
||||||
|
vol.Optional(CONF_PASSWORD): str,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return await self._create_device(
|
||||||
|
user_input[CONF_HOST],
|
||||||
|
user_input.get(CONF_KEY),
|
||||||
|
user_input.get(CONF_PASSWORD),
|
||||||
)
|
)
|
||||||
return await self._create_device(user_input[CONF_HOST])
|
|
||||||
|
|
||||||
async def async_step_import(self, user_input):
|
async def async_step_import(self, user_input):
|
||||||
"""Import a config entry."""
|
"""Import a config entry."""
|
||||||
|
@ -70,4 +104,4 @@ class FlowHandler(config_entries.ConfigFlow):
|
||||||
async def async_step_discovery(self, user_input):
|
async def async_step_discovery(self, user_input):
|
||||||
"""Initialize step from discovery."""
|
"""Initialize step from discovery."""
|
||||||
_LOGGER.info("Discovered device: %s", user_input)
|
_LOGGER.info("Discovered device: %s", user_input)
|
||||||
return await self._create_entry(user_input[KEY_IP], user_input[KEY_MAC])
|
return self._create_entry(user_input[KEY_IP], user_input[KEY_MAC])
|
||||||
|
|
|
@ -23,6 +23,9 @@ SENSOR_TYPES = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CONF_KEY = "key"
|
||||||
|
CONF_UUID = "uuid"
|
||||||
|
|
||||||
KEY_MAC = "mac"
|
KEY_MAC = "mac"
|
||||||
KEY_IP = "ip"
|
KEY_IP = "ip"
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"name": "Daikin AC",
|
"name": "Daikin AC",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/daikin",
|
"documentation": "https://www.home-assistant.io/integrations/daikin",
|
||||||
"requirements": ["pydaikin==1.6.3"],
|
"requirements": ["pydaikin==2.0.0"],
|
||||||
"codeowners": ["@fredrike"],
|
"codeowners": ["@fredrike"],
|
||||||
"quality_scale": "platinum"
|
"quality_scale": "platinum"
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ class DaikinClimateSensor(Entity):
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
"""Return a unique ID."""
|
"""Return a unique ID."""
|
||||||
return f"{self._api.mac}-{self._device_attribute}"
|
return f"{self._api.device.mac}-{self._device_attribute}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def icon(self):
|
def icon(self):
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
"user": {
|
"user": {
|
||||||
"title": "Configure Daikin AC",
|
"title": "Configure Daikin AC",
|
||||||
"description": "Enter IP address of your Daikin AC.",
|
"description": "Enter IP address of your Daikin AC.",
|
||||||
"data": { "host": "Host" }
|
"data": {
|
||||||
|
"host": "Host",
|
||||||
|
"key": "Authentication key (only used by BRP072C/Zena devices)",
|
||||||
|
"password": "Device password (only used by SKYFi devices)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
|
|
|
@ -43,7 +43,7 @@ class DaikinZoneSwitch(ToggleEntity):
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
"""Return a unique ID."""
|
"""Return a unique ID."""
|
||||||
return f"{self._api.mac}-zone{self._zone_id}"
|
return f"{self._api.device.mac}-zone{self._zone_id}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def icon(self):
|
def icon(self):
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
"step": {
|
"step": {
|
||||||
"user": {
|
"user": {
|
||||||
"data": {
|
"data": {
|
||||||
"host": "Host"
|
"host": "Host",
|
||||||
|
"key": "Authentication key (only used by BRP072C/Zena devices)",
|
||||||
|
"password": "Device password (only used by SKYFi devices)"
|
||||||
},
|
},
|
||||||
"description": "Enter IP address of your Daikin AC.",
|
"description": "Enter IP address of your Daikin AC.",
|
||||||
"title": "Configure Daikin AC"
|
"title": "Configure Daikin AC"
|
||||||
|
|
|
@ -1248,7 +1248,7 @@ pycsspeechtts==1.0.3
|
||||||
# pycups==1.9.73
|
# pycups==1.9.73
|
||||||
|
|
||||||
# homeassistant.components.daikin
|
# homeassistant.components.daikin
|
||||||
pydaikin==1.6.3
|
pydaikin==2.0.0
|
||||||
|
|
||||||
# homeassistant.components.danfoss_air
|
# homeassistant.components.danfoss_air
|
||||||
pydanfossair==0.1.0
|
pydanfossair==0.1.0
|
||||||
|
|
|
@ -518,7 +518,7 @@ pychromecast==5.0.0
|
||||||
pycoolmasternet==0.0.4
|
pycoolmasternet==0.0.4
|
||||||
|
|
||||||
# homeassistant.components.daikin
|
# homeassistant.components.daikin
|
||||||
pydaikin==1.6.3
|
pydaikin==2.0.0
|
||||||
|
|
||||||
# homeassistant.components.deconz
|
# homeassistant.components.deconz
|
||||||
pydeconz==70
|
pydeconz==70
|
||||||
|
|
|
@ -9,7 +9,7 @@ from homeassistant.components.daikin import config_flow
|
||||||
from homeassistant.components.daikin.const import KEY_IP, KEY_MAC
|
from homeassistant.components.daikin.const import KEY_IP, KEY_MAC
|
||||||
from homeassistant.const import CONF_HOST
|
from homeassistant.const import CONF_HOST
|
||||||
|
|
||||||
from tests.async_mock import patch
|
from tests.async_mock import PropertyMock, patch
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
MAC = "AABBCCDDEEFF"
|
MAC = "AABBCCDDEEFF"
|
||||||
|
@ -27,13 +27,13 @@ def init_config_flow(hass):
|
||||||
def mock_daikin():
|
def mock_daikin():
|
||||||
"""Mock pydaikin."""
|
"""Mock pydaikin."""
|
||||||
|
|
||||||
async def mock_daikin_init():
|
async def mock_daikin_factory(*args, **kwargs):
|
||||||
"""Mock the init function in pydaikin."""
|
"""Mock the init function in pydaikin."""
|
||||||
pass
|
return Appliance
|
||||||
|
|
||||||
with patch("homeassistant.components.daikin.config_flow.Appliance") as Appliance:
|
with patch("homeassistant.components.daikin.config_flow.Appliance") as Appliance:
|
||||||
Appliance().values.get.return_value = "AABBCCDDEEFF"
|
type(Appliance).mac = PropertyMock(return_value="AABBCCDDEEFF")
|
||||||
Appliance().init = mock_daikin_init
|
Appliance.factory.side_effect = mock_daikin_factory
|
||||||
yield Appliance
|
yield Appliance
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ async def test_discovery(hass, mock_daikin):
|
||||||
async def test_device_abort(hass, mock_daikin, s_effect, reason):
|
async def test_device_abort(hass, mock_daikin, s_effect, reason):
|
||||||
"""Test device abort."""
|
"""Test device abort."""
|
||||||
flow = init_config_flow(hass)
|
flow = init_config_flow(hass)
|
||||||
mock_daikin.side_effect = s_effect
|
mock_daikin.factory.side_effect = s_effect
|
||||||
|
|
||||||
result = await flow.async_step_user({CONF_HOST: HOST})
|
result = await flow.async_step_user({CONF_HOST: HOST})
|
||||||
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue