Add ESPHome native API discovery (#19399)

* ESPHome discovery

* Add note about netdisco

* 🔡

* Address comments

* Bump netdisco to 2.3.0

* Update requirements_all.txt
This commit is contained in:
Otto Winter 2019-01-05 16:00:07 +01:00 committed by GitHub
parent 0125b3fd80
commit 68723730a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 84 additions and 4 deletions

View File

@ -21,7 +21,7 @@ from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers.discovery import async_load_platform, async_discover from homeassistant.helpers.discovery import async_load_platform, async_discover
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
REQUIREMENTS = ['netdisco==2.2.0'] REQUIREMENTS = ['netdisco==2.3.0']
DOMAIN = 'discovery' DOMAIN = 'discovery'
@ -51,6 +51,7 @@ SERVICE_DLNA_DMR = 'dlna_dmr'
CONFIG_ENTRY_HANDLERS = { CONFIG_ENTRY_HANDLERS = {
SERVICE_DAIKIN: 'daikin', SERVICE_DAIKIN: 'daikin',
SERVICE_DECONZ: 'deconz', SERVICE_DECONZ: 'deconz',
'esphome': 'esphome',
'google_cast': 'cast', 'google_cast': 'cast',
SERVICE_HUE: 'hue', SERVICE_HUE: 'hue',
SERVICE_TELLDUSLIVE: 'tellduslive', SERVICE_TELLDUSLIVE: 'tellduslive',

View File

@ -53,6 +53,24 @@ class EsphomeFlowHandler(config_entries.ConfigFlow):
errors=errors errors=errors
) )
async def async_step_discovery(self, user_input: ConfigType):
"""Handle discovery."""
# mDNS hostname has additional '.' at end
hostname = user_input['hostname'][:-1]
hosts = (hostname, user_input['host'])
for entry in self._async_current_entries():
if entry.data['host'] in hosts:
return self.async_abort(
reason='already_configured'
)
# Prefer .local addresses (mDNS is available after all, otherwise
# we wouldn't have received the discovery message)
return await self.async_step_user(user_input={
'host': hostname,
'port': user_input['port'],
})
def _async_get_entry(self): def _async_get_entry(self):
return self.async_create_entry( return self.async_create_entry(
title=self._name, title=self._name,

View File

@ -705,7 +705,7 @@ nessclient==0.9.9
netdata==0.1.2 netdata==0.1.2
# homeassistant.components.discovery # homeassistant.components.discovery
netdisco==2.2.0 netdisco==2.3.0
# homeassistant.components.sensor.neurio_energy # homeassistant.components.sensor.neurio_energy
neurio==0.3.1 neurio==0.3.1

View File

@ -1,11 +1,11 @@
"""Test config flow.""" """Test config flow."""
from collections import namedtuple from collections import namedtuple
from unittest.mock import patch, MagicMock from unittest.mock import MagicMock, patch
import pytest import pytest
from homeassistant.components.esphome import config_flow from homeassistant.components.esphome import config_flow
from tests.common import mock_coro from tests.common import mock_coro, MockConfigEntry
MockDeviceInfo = namedtuple("DeviceInfo", ["uses_password", "name"]) MockDeviceInfo = namedtuple("DeviceInfo", ["uses_password", "name"])
@ -186,3 +186,64 @@ async def test_user_invalid_password(hass, mock_api_connection_error,
assert result['errors'] == { assert result['errors'] == {
'base': 'invalid_password' 'base': 'invalid_password'
} }
async def test_discovery_initiation(hass, mock_client):
"""Test discovery importing works."""
flow = config_flow.EsphomeFlowHandler()
flow.hass = hass
service_info = {
'host': '192.168.43.183',
'port': 6053,
'hostname': 'test8266.local.',
'properties': {}
}
mock_client.device_info.return_value = mock_coro(
MockDeviceInfo(False, "test8266"))
result = await flow.async_step_discovery(user_input=service_info)
assert result['type'] == 'create_entry'
assert result['title'] == 'test8266'
assert result['data']['host'] == 'test8266.local'
assert result['data']['port'] == 6053
async def test_discovery_already_configured_hostname(hass, mock_client):
"""Test discovery aborts if already configured via hostname."""
MockConfigEntry(
domain='esphome',
data={'host': 'test8266.local', 'port': 6053, 'password': ''}
).add_to_hass(hass)
flow = config_flow.EsphomeFlowHandler()
flow.hass = hass
service_info = {
'host': '192.168.43.183',
'port': 6053,
'hostname': 'test8266.local.',
'properties': {}
}
result = await flow.async_step_discovery(user_input=service_info)
assert result['type'] == 'abort'
assert result['reason'] == 'already_configured'
async def test_discovery_already_configured_ip(hass, mock_client):
"""Test discovery aborts if already configured via static IP."""
MockConfigEntry(
domain='esphome',
data={'host': '192.168.43.183', 'port': 6053, 'password': ''}
).add_to_hass(hass)
flow = config_flow.EsphomeFlowHandler()
flow.hass = hass
service_info = {
'host': '192.168.43.183',
'port': 6053,
'hostname': 'test8266.local.',
'properties': {}
}
result = await flow.async_step_discovery(user_input=service_info)
assert result['type'] == 'abort'
assert result['reason'] == 'already_configured'