Use zeroconf attributes in forked-daapd (#58966)

Co-authored-by: epenet <epenet@users.noreply.github.com>
This commit is contained in:
epenet 2021-11-15 20:16:30 +01:00 committed by GitHub
parent e88ea2d48c
commit 3c42ea1a26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 37 deletions

View File

@ -6,8 +6,10 @@ from pyforked_daapd import ForkedDaapdAPI
import voluptuous as vol import voluptuous as vol
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components import zeroconf
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_PORT from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_PORT
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import ( from .const import (
@ -153,35 +155,41 @@ class ForkedDaapdFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
step_id="user", data_schema=vol.Schema(DATA_SCHEMA_DICT), errors={} step_id="user", data_schema=vol.Schema(DATA_SCHEMA_DICT), errors={}
) )
async def async_step_zeroconf(self, discovery_info): async def async_step_zeroconf(
self, discovery_info: zeroconf.ZeroconfServiceInfo
) -> FlowResult:
"""Prepare configuration for a discovered forked-daapd device.""" """Prepare configuration for a discovered forked-daapd device."""
version_num = 0 version_num = 0
if discovery_info.get("properties") and discovery_info["properties"].get( if discovery_info.get(zeroconf.ATTR_PROPERTIES) and discovery_info[
"Machine Name" zeroconf.ATTR_PROPERTIES
): ].get("Machine Name"):
with suppress(ValueError): with suppress(ValueError):
version_num = int( version_num = int(
discovery_info["properties"].get("mtd-version", "0").split(".")[0] discovery_info[zeroconf.ATTR_PROPERTIES]
.get("mtd-version", "0")
.split(".")[0]
) )
if version_num < 27: if version_num < 27:
return self.async_abort(reason="not_forked_daapd") return self.async_abort(reason="not_forked_daapd")
await self.async_set_unique_id(discovery_info["properties"]["Machine Name"]) await self.async_set_unique_id(
discovery_info[zeroconf.ATTR_PROPERTIES]["Machine Name"]
)
self._abort_if_unique_id_configured() self._abort_if_unique_id_configured()
# Update title and abort if we already have an entry for this host # Update title and abort if we already have an entry for this host
for entry in self._async_current_entries(): for entry in self._async_current_entries():
if entry.data.get(CONF_HOST) != discovery_info["host"]: if entry.data.get(CONF_HOST) != discovery_info[zeroconf.ATTR_HOST]:
continue continue
self.hass.config_entries.async_update_entry( self.hass.config_entries.async_update_entry(
entry, entry,
title=discovery_info["properties"]["Machine Name"], title=discovery_info[zeroconf.ATTR_PROPERTIES]["Machine Name"],
) )
return self.async_abort(reason="already_configured") return self.async_abort(reason="already_configured")
zeroconf_data = { zeroconf_data = {
CONF_HOST: discovery_info["host"], CONF_HOST: discovery_info[zeroconf.ATTR_HOST],
CONF_PORT: int(discovery_info["port"]), CONF_PORT: discovery_info[zeroconf.ATTR_PORT],
CONF_NAME: discovery_info["properties"]["Machine Name"], CONF_NAME: discovery_info[zeroconf.ATTR_PROPERTIES]["Machine Name"],
} }
self.discovery_schema = vol.Schema(fill_in_schema_dict(zeroconf_data)) self.discovery_schema = vol.Schema(fill_in_schema_dict(zeroconf_data))
self.context.update({"title_placeholders": zeroconf_data}) self.context.update({"title_placeholders": zeroconf_data})

View File

@ -4,6 +4,7 @@ from unittest.mock import AsyncMock, patch
import pytest import pytest
from homeassistant import data_entry_flow from homeassistant import data_entry_flow
from homeassistant.components import zeroconf
from homeassistant.components.forked_daapd.const import ( from homeassistant.components.forked_daapd.const import (
CONF_LIBRESPOT_JAVA_PORT, CONF_LIBRESPOT_JAVA_PORT,
CONF_MAX_PLAYLISTS, CONF_MAX_PLAYLISTS,
@ -98,11 +99,11 @@ async def test_zeroconf_updates_title(hass, config_entry):
MockConfigEntry(domain=DOMAIN, data={CONF_HOST: "different host"}).add_to_hass(hass) MockConfigEntry(domain=DOMAIN, data={CONF_HOST: "different host"}).add_to_hass(hass)
config_entry.add_to_hass(hass) config_entry.add_to_hass(hass)
assert len(hass.config_entries.async_entries(DOMAIN)) == 2 assert len(hass.config_entries.async_entries(DOMAIN)) == 2
discovery_info = { discovery_info = zeroconf.ZeroconfServiceInfo(
"host": "192.168.1.1", host="192.168.1.1",
"port": 23, port=23,
"properties": {"mtd-version": "27.0", "Machine Name": "zeroconf_test"}, properties={"mtd-version": "27.0", "Machine Name": "zeroconf_test"},
} )
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
) )
@ -129,40 +130,40 @@ async def test_config_flow_no_websocket(hass, config_entry):
async def test_config_flow_zeroconf_invalid(hass): async def test_config_flow_zeroconf_invalid(hass):
"""Test that an invalid zeroconf entry doesn't work.""" """Test that an invalid zeroconf entry doesn't work."""
# test with no discovery properties # test with no discovery properties
discovery_info = {"host": "127.0.0.1", "port": 23} discovery_info = zeroconf.ZeroconfServiceInfo(host="127.0.0.1", port=23)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
) # doesn't create the entry, tries to show form but gets abort ) # doesn't create the entry, tries to show form but gets abort
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "not_forked_daapd" assert result["reason"] == "not_forked_daapd"
# test with forked-daapd version < 27 # test with forked-daapd version < 27
discovery_info = { discovery_info = zeroconf.ZeroconfServiceInfo(
"host": "127.0.0.1", host="127.0.0.1",
"port": 23, port=23,
"properties": {"mtd-version": "26.3", "Machine Name": "forked-daapd"}, properties={"mtd-version": "26.3", "Machine Name": "forked-daapd"},
} )
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
) # doesn't create the entry, tries to show form but gets abort ) # doesn't create the entry, tries to show form but gets abort
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "not_forked_daapd" assert result["reason"] == "not_forked_daapd"
# test with verbose mtd-version from Firefly # test with verbose mtd-version from Firefly
discovery_info = { discovery_info = zeroconf.ZeroconfServiceInfo(
"host": "127.0.0.1", host="127.0.0.1",
"port": 23, port=23,
"properties": {"mtd-version": "0.2.4.1", "Machine Name": "firefly"}, properties={"mtd-version": "0.2.4.1", "Machine Name": "firefly"},
} )
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
) # doesn't create the entry, tries to show form but gets abort ) # doesn't create the entry, tries to show form but gets abort
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "not_forked_daapd" assert result["reason"] == "not_forked_daapd"
# test with svn mtd-version from Firefly # test with svn mtd-version from Firefly
discovery_info = { discovery_info = zeroconf.ZeroconfServiceInfo(
"host": "127.0.0.1", host="127.0.0.1",
"port": 23, port=23,
"properties": {"mtd-version": "svn-1676", "Machine Name": "firefly"}, properties={"mtd-version": "svn-1676", "Machine Name": "firefly"},
} )
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
) # doesn't create the entry, tries to show form but gets abort ) # doesn't create the entry, tries to show form but gets abort
@ -172,15 +173,15 @@ async def test_config_flow_zeroconf_invalid(hass):
async def test_config_flow_zeroconf_valid(hass): async def test_config_flow_zeroconf_valid(hass):
"""Test that a valid zeroconf entry works.""" """Test that a valid zeroconf entry works."""
discovery_info = { discovery_info = zeroconf.ZeroconfServiceInfo(
"host": "192.168.1.1", host="192.168.1.1",
"port": 23, port=23,
"properties": { properties={
"mtd-version": "27.0", "mtd-version": "27.0",
"Machine Name": "zeroconf_test", "Machine Name": "zeroconf_test",
"Machine ID": "5E55EEFF", "Machine ID": "5E55EEFF",
}, },
} )
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info DOMAIN, context={"source": SOURCE_ZEROCONF}, data=discovery_info
) )