Skip to content

Commit

Permalink
Uplift to Home Assistant 2022.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
postlund committed Feb 2, 2022
1 parent 0ce0162 commit f5a156d
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 99 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ shipped with Home Assistant:

## Changes

## Release 3.0.0

Synchronize with Home Assistant 2022.2.0, i.e. this is exactly the same code
that is shipped with that release (except for translations, only english is
included here). Contains:

* Lots of (performance) improvements for device discovery
* Re-connect bug is fixed
* Errors regarding "BlockedStateError" should be gone
* App list is sorted alphabetically

This release will no longer discover generic AirPlay devices, e.g. Sonos speakers
or TVs supporting AirPlay. Only Apple devices will be discovered. You can still
try adding generic AirPlay devices manually, e.g. by name or address. AirPlay v1
devices should work, most AirPlay v2 does not however.

## Release 2.2.0

**REQUIRES HOME ASSISTANT 2021.12.x OR LATER!!!**
Expand Down
23 changes: 13 additions & 10 deletions custom_components/apple_tv/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from pyatv.const import DeviceModel, Protocol
from pyatv.convert import model_str

from homeassistant.components.media_player import DOMAIN as MP_DOMAIN
from homeassistant.components.remote import DOMAIN as REMOTE_DOMAIN
from homeassistant.components import zeroconf
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_CONNECTIONS,
ATTR_IDENTIFIERS,
Expand All @@ -20,8 +20,9 @@
CONF_ADDRESS,
CONF_NAME,
EVENT_HOMEASSISTANT_STOP,
Platform,
)
from homeassistant.core import callback
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.dispatcher import (
Expand All @@ -42,10 +43,10 @@
SIGNAL_CONNECTED = "apple_tv_connected"
SIGNAL_DISCONNECTED = "apple_tv_disconnected"

PLATFORMS = [MP_DOMAIN, REMOTE_DOMAIN]
PLATFORMS = [Platform.MEDIA_PLAYER, Platform.REMOTE]


async def async_setup_entry(hass, entry):
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up a config entry for Apple TV."""
manager = AppleTVManager(hass, entry)
hass.data.setdefault(DOMAIN, {})[entry.unique_id] = manager
Expand Down Expand Up @@ -73,7 +74,7 @@ async def setup_platforms():
return True


async def async_unload_entry(hass, entry):
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload an Apple TV config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

Expand Down Expand Up @@ -178,7 +179,6 @@ def connection_closed(self):
def _handle_disconnect(self):
"""Handle that the device disconnected and restart connect loop."""
if self.atv:
self.atv.listener = None
self.atv.close()
self.atv = None
self._dispatch_send(SIGNAL_DISCONNECTED)
Expand All @@ -195,8 +195,6 @@ async def disconnect(self):
self._is_on = False
try:
if self.atv:
self.atv.push_updater.listener = None
self.atv.push_updater.stop()
self.atv.close()
self.atv = None
if self._task:
Expand Down Expand Up @@ -269,8 +267,13 @@ async def _scan(self):
}

_LOGGER.debug("Discovering device %s", self.config_entry.title)
aiozc = await zeroconf.async_get_async_instance(self.hass)
atvs = await scan(
self.hass.loop, identifier=identifiers, protocol=protocols, hosts=[address]
self.hass.loop,
identifier=identifiers,
protocol=protocols,
hosts=[address],
aiozc=aiozc,
)
if atvs:
return atvs[0]
Expand Down
8 changes: 5 additions & 3 deletions custom_components/apple_tv/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
DISCOVERY_AGGREGATION_TIME = 15 # seconds


async def device_scan(identifier, loop):
async def device_scan(hass, identifier, loop):
"""Scan for a specific device using identifier as filter."""

def _filter_device(dev):
Expand All @@ -53,7 +53,8 @@ def _host_filter():

# If we have an address, only probe that address to avoid
# broadcast traffic on the network
scan_result = await scan(loop, timeout=3, hosts=_host_filter())
aiozc = await zeroconf.async_get_async_instance(hass)
scan_result = await scan(loop, timeout=3, hosts=_host_filter(), aiozc=aiozc)
matches = [atv for atv in scan_result if _filter_device(atv)]

if matches:
Expand Down Expand Up @@ -180,6 +181,7 @@ async def async_step_zeroconf(
self._abort_if_unique_id_configured(updates={CONF_ADDRESS: host})

self._async_abort_entries_match({CONF_ADDRESS: host})

await self._async_aggregate_discoveries(host, unique_id)
# Scan for the device in order to extract _all_ unique identifiers assigned to
# it. Not doing it like this will yield multiple config flows for the same
Expand Down Expand Up @@ -279,7 +281,7 @@ async def async_find_device_wrapper(self, next_func, allow_exist=False):
async def async_find_device(self, allow_exist=False):
"""Scan for the selected device to discover services."""
self.atv, self.atv_identifiers = await device_scan(
self.scan_filter, self.hass.loop
self.hass, self.scan_filter, self.hass.loop
)
if not self.atv:
raise DeviceNotFound()
Expand Down
21 changes: 14 additions & 7 deletions custom_components/apple_tv/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,24 @@
"name": "Apple TV",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/apple_tv",
"requirements": ["pyatv==0.9.8"],
"requirements": ["pyatv==0.10.0"],
"dependencies": ["zeroconf"],
"zeroconf": [
"_mediaremotetv._tcp.local.",
"_companion-link._tcp.local.",
"_airport._tcp.local.",
"_sleep-proxy._udp.local.",
"_touch-able._tcp.local.",
{"type":"_airplay._tcp.local.","model":"appletv*"},
{"type":"_airplay._tcp.local.","model":"audioaccessory*"},
"_appletv-v2._tcp.local.",
"_raop._tcp.local.",
"_hscp._tcp.local."
"_hscp._tcp.local.",
{"type":"_airplay._tcp.local.", "properties": {"model":"appletv*"}},
{"type":"_airplay._tcp.local.", "properties": {"model":"audioaccessory*"}},
{"type":"_airplay._tcp.local.", "properties": {"am":"airport*"}},
{"type":"_raop._tcp.local.", "properties": {"am":"appletv*"}},
{"type":"_raop._tcp.local.", "properties": {"am":"audioaccessory*"}},
{"type":"_raop._tcp.local.", "properties": {"am":"airport*"}}
],
"codeowners": ["@postlund"],
"version": "2.2.0",
"iot_class": "local_push"
"iot_class": "local_push",
"loggers": ["pyatv", "srptools"]
}
18 changes: 12 additions & 6 deletions custom_components/apple_tv/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
SUPPORT_VOLUME_SET,
SUPPORT_VOLUME_STEP,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_NAME,
STATE_IDLE,
Expand All @@ -46,7 +47,8 @@
STATE_PLAYING,
STATE_STANDBY,
)
from homeassistant.core import callback
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
import homeassistant.util.dt as dt_util

from . import AppleTVEntity
Expand Down Expand Up @@ -100,7 +102,11 @@
}


async def async_setup_entry(hass, config_entry, async_add_entities):
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Load Apple TV media player based on a config entry."""
name = config_entry.data[CONF_NAME]
manager = hass.data[DOMAIN][config_entry.unique_id]
Expand Down Expand Up @@ -156,15 +162,15 @@ async def _update_app_list(self):
except exceptions.ProtocolError:
_LOGGER.exception("Failed to update app list")
else:
self._app_list = {app.name: app.identifier for app in apps}
self._app_list = {
app.name: app.identifier
for app in sorted(apps, key=lambda app: app.name.lower())
}
self.async_write_ha_state()

@callback
def async_device_disconnected(self):
"""Handle when connection was lost to device."""
self.atv.push_updater.stop()
self.atv.push_updater.listener = None
self.atv.power.listener = None
self._attr_supported_features = SUPPORT_APPLE_TV

@property
Expand Down
10 changes: 8 additions & 2 deletions custom_components/apple_tv/remote.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""Remote control support for Apple TV."""

import asyncio
import logging

Expand All @@ -9,7 +8,10 @@
DEFAULT_DELAY_SECS,
RemoteEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from . import AppleTVEntity
from .const import DOMAIN
Expand All @@ -19,7 +21,11 @@
PARALLEL_UPDATES = 0


async def async_setup_entry(hass, config_entry, async_add_entities):
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Load Apple TV remote based on a config entry."""
name = config_entry.data[CONF_NAME]
manager = hass.data[DOMAIN][config_entry.unique_id]
Expand Down
2 changes: 1 addition & 1 deletion custom_components/apple_tv/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]",
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"device_did_not_pair": "No attempt to finish pairing process was made from the device.",
"backoff": "Device does not accept pairing reqests at this time (you might have entered an invalid PIN code too many times), try again later.",
"backoff": "Device does not accept pairing requests at this time (you might have entered an invalid PIN code too many times), try again later.",
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
"unknown": "[%key:common::config_flow::error::unknown%]",
"setup_failed": "Failed to set up device.",
Expand Down
Loading

0 comments on commit f5a156d

Please sign in to comment.