Improve IPP Config Flow (#34212)
parent
ede432ba71
commit
9d794b820a
|
@ -134,13 +134,18 @@ class IPPEntity(Entity):
|
|||
enabled_default: bool = True,
|
||||
) -> None:
|
||||
"""Initialize the IPP entity."""
|
||||
self._device_id = None
|
||||
self._enabled_default = enabled_default
|
||||
self._entry_id = entry_id
|
||||
self._icon = icon
|
||||
self._name = name
|
||||
self._unsub_dispatcher = None
|
||||
self.coordinator = coordinator
|
||||
|
||||
if coordinator.data.info.uuid is not None:
|
||||
self._device_id = coordinator.data.info.uuid
|
||||
elif coordinator.data.info.serial is not None:
|
||||
self._device_id = coordinator.data.info.serial
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the entity."""
|
||||
|
@ -179,8 +184,11 @@ class IPPEntity(Entity):
|
|||
@property
|
||||
def device_info(self) -> Dict[str, Any]:
|
||||
"""Return device information about this IPP device."""
|
||||
if self._device_id is None:
|
||||
return None
|
||||
|
||||
return {
|
||||
ATTR_IDENTIFIERS: {(DOMAIN, self.coordinator.data.info.uuid)},
|
||||
ATTR_IDENTIFIERS: {(DOMAIN, self._device_id)},
|
||||
ATTR_NAME: self.coordinator.data.info.name,
|
||||
ATTR_MANUFACTURER: self.coordinator.data.info.manufacturer,
|
||||
ATTR_MODEL: self.coordinator.data.info.model,
|
||||
|
|
|
@ -24,7 +24,7 @@ from homeassistant.const import (
|
|||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
|
||||
|
||||
from .const import CONF_BASE_PATH, CONF_UUID
|
||||
from .const import CONF_BASE_PATH, CONF_SERIAL, CONF_UUID
|
||||
from .const import DOMAIN # pylint: disable=unused-import
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -47,7 +47,7 @@ async def validate_input(hass: HomeAssistantType, data: dict) -> Dict[str, Any]:
|
|||
|
||||
printer = await ipp.printer()
|
||||
|
||||
return {CONF_UUID: printer.info.uuid}
|
||||
return {CONF_SERIAL: printer.info.serial, CONF_UUID: printer.info.uuid}
|
||||
|
||||
|
||||
class IPPFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
|
@ -83,20 +83,28 @@ class IPPFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||
_LOGGER.debug("IPP Error", exc_info=True)
|
||||
return self.async_abort(reason="ipp_error")
|
||||
|
||||
user_input[CONF_UUID] = info[CONF_UUID]
|
||||
unique_id = user_input[CONF_UUID] = info[CONF_UUID]
|
||||
|
||||
await self.async_set_unique_id(user_input[CONF_UUID])
|
||||
if unique_id is None and info[CONF_SERIAL] is not None:
|
||||
_LOGGER.debug(
|
||||
"Printer UUID is missing from IPP response. Falling back to IPP serial number"
|
||||
)
|
||||
unique_id = info[CONF_SERIAL]
|
||||
elif unique_id is None:
|
||||
_LOGGER.debug("Unable to determine unique id from IPP response")
|
||||
|
||||
await self.async_set_unique_id(unique_id)
|
||||
self._abort_if_unique_id_configured(updates={CONF_HOST: user_input[CONF_HOST]})
|
||||
|
||||
return self.async_create_entry(title=user_input[CONF_HOST], data=user_input)
|
||||
|
||||
async def async_step_zeroconf(self, discovery_info: ConfigType) -> Dict[str, Any]:
|
||||
"""Handle zeroconf discovery."""
|
||||
# Hostname is format: EPSON123456.local.
|
||||
host = discovery_info["hostname"].rstrip(".")
|
||||
port = discovery_info["port"]
|
||||
name, _ = host.rsplit(".")
|
||||
tls = discovery_info["type"] == "_ipps._tcp.local."
|
||||
port = discovery_info[CONF_PORT]
|
||||
zctype = discovery_info["type"]
|
||||
name = discovery_info[CONF_NAME].replace(f".{zctype}", "")
|
||||
tls = zctype == "_ipps._tcp.local."
|
||||
base_path = discovery_info["properties"].get("rp", "ipp/print")
|
||||
|
||||
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
|
||||
self.context.update({"title_placeholders": {"name": name}})
|
||||
|
@ -107,8 +115,7 @@ class IPPFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||
CONF_PORT: port,
|
||||
CONF_SSL: tls,
|
||||
CONF_VERIFY_SSL: False,
|
||||
CONF_BASE_PATH: "/"
|
||||
+ discovery_info["properties"].get("rp", "ipp/print"),
|
||||
CONF_BASE_PATH: f"/{base_path}",
|
||||
CONF_NAME: name,
|
||||
CONF_UUID: discovery_info["properties"].get("UUID"),
|
||||
}
|
||||
|
@ -130,12 +137,28 @@ class IPPFlowHandler(ConfigFlow, domain=DOMAIN):
|
|||
_LOGGER.debug("IPP Error", exc_info=True)
|
||||
return self.async_abort(reason="ipp_error")
|
||||
|
||||
if info[CONF_UUID] is not None:
|
||||
self.discovery_info[CONF_UUID] = info[CONF_UUID]
|
||||
unique_id = self.discovery_info[CONF_UUID]
|
||||
if unique_id is None and info[CONF_UUID] is not None:
|
||||
_LOGGER.debug(
|
||||
"Printer UUID is missing from discovery info. Falling back to IPP UUID"
|
||||
)
|
||||
unique_id = self.discovery_info[CONF_UUID] = info[CONF_UUID]
|
||||
elif unique_id is None and info[CONF_SERIAL] is not None:
|
||||
_LOGGER.debug(
|
||||
"Printer UUID is missing from discovery info and IPP response. Falling back to IPP serial number"
|
||||
)
|
||||
unique_id = info[CONF_SERIAL]
|
||||
elif unique_id is None:
|
||||
_LOGGER.debug(
|
||||
"Unable to determine unique id from discovery info and IPP response"
|
||||
)
|
||||
|
||||
await self.async_set_unique_id(self.discovery_info[CONF_UUID])
|
||||
await self.async_set_unique_id(unique_id)
|
||||
self._abort_if_unique_id_configured(
|
||||
updates={CONF_HOST: self.discovery_info[CONF_HOST]}
|
||||
updates={
|
||||
CONF_HOST: self.discovery_info[CONF_HOST],
|
||||
CONF_NAME: self.discovery_info[CONF_NAME],
|
||||
},
|
||||
)
|
||||
|
||||
return await self.async_step_zeroconf_confirm()
|
||||
|
|
|
@ -21,5 +21,6 @@ ATTR_URI_SUPPORTED = "uri_supported"
|
|||
|
||||
# Config Keys
|
||||
CONF_BASE_PATH = "base_path"
|
||||
CONF_SERIAL = "serial"
|
||||
CONF_TLS = "tls"
|
||||
CONF_UUID = "uuid"
|
||||
|
|
|
@ -60,6 +60,12 @@ class IPPSensor(IPPEntity):
|
|||
"""Initialize IPP sensor."""
|
||||
self._unit_of_measurement = unit_of_measurement
|
||||
self._key = key
|
||||
self._unique_id = None
|
||||
|
||||
if coordinator.data.info.uuid is not None:
|
||||
self._unique_id = f"{coordinator.data.info.uuid}_{key}"
|
||||
elif coordinator.data.info.serial is not None:
|
||||
self._unique_id = f"{coordinator.data.info.serial}_{key}"
|
||||
|
||||
super().__init__(
|
||||
entry_id=entry_id,
|
||||
|
@ -72,7 +78,7 @@ class IPPSensor(IPPEntity):
|
|||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return the unique ID for this sensor."""
|
||||
return f"{self.coordinator.data.info.uuid}_{self._key}"
|
||||
return self._unique_id
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> str:
|
||||
|
|
|
@ -21,7 +21,7 @@ ATTR_PROPERTIES = "properties"
|
|||
IPP_ZEROCONF_SERVICE_TYPE = "_ipp._tcp.local."
|
||||
IPPS_ZEROCONF_SERVICE_TYPE = "_ipps._tcp.local."
|
||||
|
||||
ZEROCONF_NAME = "EPSON123456"
|
||||
ZEROCONF_NAME = "EPSON XP-6000 Series"
|
||||
ZEROCONF_HOST = "192.168.1.31"
|
||||
ZEROCONF_HOSTNAME = "EPSON123456.local."
|
||||
ZEROCONF_PORT = 631
|
||||
|
|
|
@ -50,7 +50,7 @@ async def test_show_zeroconf_form(
|
|||
|
||||
assert result["step_id"] == "zeroconf_confirm"
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["description_placeholders"] == {CONF_NAME: "EPSON123456"}
|
||||
assert result["description_placeholders"] == {CONF_NAME: "EPSON XP-6000 Series"}
|
||||
|
||||
|
||||
async def test_connection_error(
|
||||
|
@ -276,8 +276,13 @@ async def test_zeroconf_with_uuid_device_exists_abort(
|
|||
"""Test we abort zeroconf flow if printer already configured."""
|
||||
await init_integration(hass, aioclient_mock)
|
||||
|
||||
discovery_info = MOCK_ZEROCONF_IPP_SERVICE_INFO.copy()
|
||||
discovery_info["properties"]["UUID"] = "cfe92100-67c4-11d4-a45f-f8d027761251"
|
||||
discovery_info = {
|
||||
**MOCK_ZEROCONF_IPP_SERVICE_INFO,
|
||||
"properties": {
|
||||
**MOCK_ZEROCONF_IPP_SERVICE_INFO["properties"],
|
||||
"UUID": "cfe92100-67c4-11d4-a45f-f8d027761251",
|
||||
},
|
||||
}
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info,
|
||||
)
|
||||
|
@ -315,6 +320,9 @@ async def test_full_user_flow_implementation(
|
|||
assert result["data"][CONF_HOST] == "192.168.1.31"
|
||||
assert result["data"][CONF_UUID] == "cfe92100-67c4-11d4-a45f-f8d027761251"
|
||||
|
||||
assert result["result"]
|
||||
assert result["result"].unique_id == "cfe92100-67c4-11d4-a45f-f8d027761251"
|
||||
|
||||
|
||||
async def test_full_zeroconf_flow_implementation(
|
||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
||||
|
@ -339,13 +347,17 @@ async def test_full_zeroconf_flow_implementation(
|
|||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == "EPSON123456"
|
||||
assert result["title"] == "EPSON XP-6000 Series"
|
||||
|
||||
assert result["data"]
|
||||
assert result["data"][CONF_HOST] == "192.168.1.31"
|
||||
assert result["data"][CONF_NAME] == "EPSON XP-6000 Series"
|
||||
assert result["data"][CONF_UUID] == "cfe92100-67c4-11d4-a45f-f8d027761251"
|
||||
assert not result["data"][CONF_SSL]
|
||||
|
||||
assert result["result"]
|
||||
assert result["result"].unique_id == "cfe92100-67c4-11d4-a45f-f8d027761251"
|
||||
|
||||
|
||||
async def test_full_zeroconf_tls_flow_implementation(
|
||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
||||
|
@ -364,17 +376,20 @@ async def test_full_zeroconf_tls_flow_implementation(
|
|||
|
||||
assert result["step_id"] == "zeroconf_confirm"
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["description_placeholders"] == {CONF_NAME: "EPSON123456"}
|
||||
assert result["description_placeholders"] == {CONF_NAME: "EPSON XP-6000 Series"}
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={}
|
||||
)
|
||||
|
||||
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == "EPSON123456"
|
||||
assert result["title"] == "EPSON XP-6000 Series"
|
||||
|
||||
assert result["data"]
|
||||
assert result["data"][CONF_HOST] == "192.168.1.31"
|
||||
assert result["data"][CONF_NAME] == "EPSON123456"
|
||||
assert result["data"][CONF_NAME] == "EPSON XP-6000 Series"
|
||||
assert result["data"][CONF_UUID] == "cfe92100-67c4-11d4-a45f-f8d027761251"
|
||||
assert result["data"][CONF_SSL]
|
||||
|
||||
assert result["result"]
|
||||
assert result["result"].unique_id == "cfe92100-67c4-11d4-a45f-f8d027761251"
|
||||
|
|
Loading…
Reference in New Issue