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
import homeassistant.util.dt as dt_util
REQUIREMENTS = ['netdisco==2.2.0']
REQUIREMENTS = ['netdisco==2.3.0']
DOMAIN = 'discovery'
@ -51,6 +51,7 @@ SERVICE_DLNA_DMR = 'dlna_dmr'
CONFIG_ENTRY_HANDLERS = {
SERVICE_DAIKIN: 'daikin',
SERVICE_DECONZ: 'deconz',
'esphome': 'esphome',
'google_cast': 'cast',
SERVICE_HUE: 'hue',
SERVICE_TELLDUSLIVE: 'tellduslive',

View File

@ -53,6 +53,24 @@ class EsphomeFlowHandler(config_entries.ConfigFlow):
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):
return self.async_create_entry(
title=self._name,

View File

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

View File

@ -1,11 +1,11 @@
"""Test config flow."""
from collections import namedtuple
from unittest.mock import patch, MagicMock
from unittest.mock import MagicMock, patch
import pytest
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"])
@ -186,3 +186,64 @@ async def test_user_invalid_password(hass, mock_api_connection_error,
assert result['errors'] == {
'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'