1
mirror of https://github.com/home-assistant/core synced 2024-08-31 05:57:13 +02:00

Add discovery for Tube's Zigbee coordinators to ZHA (#48420)

* add discovery for tube zigbee gateways

* update discovery

* add test

* another test

* develop translations

* review comments
This commit is contained in:
David F. Mulcahey 2021-03-30 11:13:26 -04:00 committed by GitHub
parent 9043a1f5aa
commit 4dc885dcc3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 100 additions and 2 deletions

View File

@ -9,6 +9,8 @@ import voluptuous as vol
from zigpy.config import CONF_DEVICE, CONF_DEVICE_PATH
from homeassistant import config_entries
from homeassistant.const import CONF_HOST, CONF_NAME
from homeassistant.helpers.typing import DiscoveryInfoType
from .core.const import (
CONF_BAUDRATE,
@ -91,6 +93,37 @@ class ZhaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
data_schema=vol.Schema(schema),
)
async def async_step_zeroconf(self, discovery_info: DiscoveryInfoType):
"""Handle zeroconf discovery."""
# Hostname is format: livingroom.local.
local_name = discovery_info["hostname"][:-1]
node_name = local_name[: -len(".local")]
host = discovery_info[CONF_HOST]
device_path = f"socket://{host}:6638"
await self.async_set_unique_id(node_name)
self._abort_if_unique_id_configured(
updates={
CONF_DEVICE: {CONF_DEVICE_PATH: device_path},
}
)
# Check if already configured
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
self.context["title_placeholders"] = {
CONF_NAME: node_name,
}
self._device_path = device_path
self._radio_type = (
RadioType.ezsp.name if "efr32" in local_name else RadioType.znp.name
)
return await self.async_step_port_config()
async def async_step_port_config(self, user_input=None):
"""Enter port settings specific for this type of radio."""
errors = {}
@ -118,9 +151,13 @@ class ZhaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
if isinstance(radio_schema, vol.Schema):
radio_schema = radio_schema.schema
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
source = self.context.get("source")
for param, value in radio_schema.items():
if param in SUPPORTED_PORT_SETTINGS:
schema[param] = value
if source == config_entries.SOURCE_ZEROCONF and param == CONF_BAUDRATE:
schema[param] = 115200
return self.async_show_form(
step_id="port_config",

View File

@ -15,5 +15,7 @@
"zigpy-zigate==0.7.3",
"zigpy-znp==0.4.0"
],
"codeowners": ["@dmulcahey", "@adminiuga"]
"codeowners": ["@dmulcahey", "@adminiuga"],
"zeroconf": [{ "type": "_esphomelib._tcp.local.", "name": "tube*" }],
"after_dependencies": ["zeroconf"]
}

View File

@ -1,5 +1,6 @@
{
"config": {
"flow_title": "ZHA: {name}",
"step": {
"user": {
"title": "ZHA",
@ -21,7 +22,9 @@
}
}
},
"error": { "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]" },
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
},
"abort": {
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
}

View File

@ -6,6 +6,7 @@
"error": {
"cannot_connect": "Failed to connect"
},
"flow_title": "ZHA: {name}",
"step": {
"pick_radio": {
"data": {

View File

@ -57,6 +57,10 @@ ZEROCONF = {
"_esphomelib._tcp.local.": [
{
"domain": "esphome"
},
{
"domain": "zha",
"name": "tube*"
}
],
"_fbx-api._tcp.local.": [

View File

@ -28,6 +28,57 @@ def com_port():
return port
@patch("homeassistant.components.zha.async_setup_entry", AsyncMock(return_value=True))
@patch("zigpy_znp.zigbee.application.ControllerApplication.probe", return_value=True)
async def test_discovery(detect_mock, hass):
"""Test zeroconf flow -- radio detected."""
service_info = {
"host": "192.168.1.200",
"port": 6053,
"hostname": "_tube_zb_gw._tcp.local.",
"properties": {"name": "tube_123456"},
}
flow = await hass.config_entries.flow.async_init(
"zha", context={"source": "zeroconf"}, data=service_info
)
result = await hass.config_entries.flow.async_configure(
flow["flow_id"], user_input={}
)
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == "socket://192.168.1.200:6638"
assert result["data"] == {
"device": {
"baudrate": 115200,
"flow_control": None,
"path": "socket://192.168.1.200:6638",
},
CONF_RADIO_TYPE: "znp",
}
@patch("homeassistant.components.zha.async_setup_entry", AsyncMock(return_value=True))
@patch("zigpy_znp.zigbee.application.ControllerApplication.probe", return_value=True)
async def test_discovery_already_setup(detect_mock, hass):
"""Test zeroconf flow -- radio detected."""
service_info = {
"host": "192.168.1.200",
"port": 6053,
"hostname": "_tube_zb_gw._tcp.local.",
"properties": {"name": "tube_123456"},
}
await setup.async_setup_component(hass, "persistent_notification", {})
MockConfigEntry(domain=DOMAIN, data={"usb_path": "/dev/ttyUSB1"}).add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
"zha", context={"source": "zeroconf"}, data=service_info
)
await hass.async_block_till_done()
assert result["type"] == "abort"
assert result["reason"] == "single_instance_allowed"
@patch("serial.tools.list_ports.comports", MagicMock(return_value=[com_port()]))
@patch(
"homeassistant.components.zha.config_flow.detect_radios",