-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Interlogix Ultrasync Alarm System Integration #42549
Changes from 28 commits
28b5de0
1a65f38
e277a52
ad12e12
0423a28
8a21c0c
3b23444
ba1c170
2770ea3
4bdf064
4d7e22d
c0a19f4
13b8e90
d7643ff
009eb10
55b4332
c97a2e0
6a2c66c
f123eab
db83a0e
f40a0af
ceb672b
df39b56
9d91708
945e1ae
fc511af
9a0ecd4
e465097
b348fc0
4d05fe3
ea0452b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,143 @@ | ||||||||||||||||||||||||||||||||||||||||||||
"""The Interlogix/Hills ComNav UltraSync Hub component.""" | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
import asyncio | ||||||||||||||||||||||||||||||||||||||||||||
from datetime import timedelta | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
from ultrasync import AlarmScene | ||||||||||||||||||||||||||||||||||||||||||||
import voluptuous as vol | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
from homeassistant.config_entries import ConfigEntry | ||||||||||||||||||||||||||||||||||||||||||||
from homeassistant.const import CONF_SCAN_INTERVAL | ||||||||||||||||||||||||||||||||||||||||||||
from homeassistant.exceptions import ConfigEntryNotReady | ||||||||||||||||||||||||||||||||||||||||||||
from homeassistant.helpers.typing import HomeAssistantType | ||||||||||||||||||||||||||||||||||||||||||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
from .const import ( | ||||||||||||||||||||||||||||||||||||||||||||
DATA_COORDINATOR, | ||||||||||||||||||||||||||||||||||||||||||||
DATA_UNDO_UPDATE_LISTENER, | ||||||||||||||||||||||||||||||||||||||||||||
DEFAULT_SCAN_INTERVAL, | ||||||||||||||||||||||||||||||||||||||||||||
DOMAIN, | ||||||||||||||||||||||||||||||||||||||||||||
SENSORS, | ||||||||||||||||||||||||||||||||||||||||||||
SERVICE_AWAY, | ||||||||||||||||||||||||||||||||||||||||||||
SERVICE_DISARM, | ||||||||||||||||||||||||||||||||||||||||||||
SERVICE_STAY, | ||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||
from .coordinator import UltraSyncDataUpdateCoordinator | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
PLATFORMS = ["sensor"] | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
async def async_setup(hass: HomeAssistantType, config: dict) -> bool: | ||||||||||||||||||||||||||||||||||||||||||||
"""Set up the UltraSync integration.""" | ||||||||||||||||||||||||||||||||||||||||||||
hass.data.setdefault(DOMAIN, {}) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
return True | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool: | ||||||||||||||||||||||||||||||||||||||||||||
"""Set up UltraSync from a config entry.""" | ||||||||||||||||||||||||||||||||||||||||||||
if not entry.options: | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
options = { | ||||||||||||||||||||||||||||||||||||||||||||
CONF_SCAN_INTERVAL: entry.data.get( | ||||||||||||||||||||||||||||||||||||||||||||
CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL | ||||||||||||||||||||||||||||||||||||||||||||
), | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
hass.config_entries.async_update_entry(entry, options=options) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
coordinator = UltraSyncDataUpdateCoordinator( | ||||||||||||||||||||||||||||||||||||||||||||
hass, | ||||||||||||||||||||||||||||||||||||||||||||
config=entry.data, | ||||||||||||||||||||||||||||||||||||||||||||
options=entry.options, | ||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
await coordinator.async_refresh() | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
if not coordinator.last_update_success: | ||||||||||||||||||||||||||||||||||||||||||||
raise ConfigEntryNotReady | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
undo_listener = entry.add_update_listener(_async_update_listener) | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
hass.data[DOMAIN][entry.entry_id] = { | ||||||||||||||||||||||||||||||||||||||||||||
DATA_COORDINATOR: coordinator, | ||||||||||||||||||||||||||||||||||||||||||||
DATA_UNDO_UPDATE_LISTENER: [undo_listener], | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
SENSORS: {}, | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
for component in PLATFORMS: | ||||||||||||||||||||||||||||||||||||||||||||
hass.async_create_task( | ||||||||||||||||||||||||||||||||||||||||||||
hass.config_entries.async_forward_entry_setup(entry, component) | ||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
_async_register_services(hass, coordinator) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
return True | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool: | ||||||||||||||||||||||||||||||||||||||||||||
"""Unload a config entry.""" | ||||||||||||||||||||||||||||||||||||||||||||
unload_ok = all( | ||||||||||||||||||||||||||||||||||||||||||||
await asyncio.gather( | ||||||||||||||||||||||||||||||||||||||||||||
*[ | ||||||||||||||||||||||||||||||||||||||||||||
hass.config_entries.async_forward_entry_unload(entry, component) | ||||||||||||||||||||||||||||||||||||||||||||
for component in PLATFORMS | ||||||||||||||||||||||||||||||||||||||||||||
] | ||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
if unload_ok: | ||||||||||||||||||||||||||||||||||||||||||||
for unsub in hass.data[DOMAIN][entry.entry_id][DATA_UNDO_UPDATE_LISTENER]: | ||||||||||||||||||||||||||||||||||||||||||||
unsub() | ||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+71
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
hass.data[DOMAIN].pop(entry.entry_id) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
return unload_ok | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
def _async_register_services( | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not create a You can use the states (An alarm_control_panel should be added as a follow up PR, since prs should contain just one platform). |
||||||||||||||||||||||||||||||||||||||||||||
hass: HomeAssistantType, | ||||||||||||||||||||||||||||||||||||||||||||
coordinator: UltraSyncDataUpdateCoordinator, | ||||||||||||||||||||||||||||||||||||||||||||
) -> None: | ||||||||||||||||||||||||||||||||||||||||||||
"""Register integration-level services.""" | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
def away(call) -> None: | ||||||||||||||||||||||||||||||||||||||||||||
"""Service call to set alarm system to 'away' mode in UltraSync Hub.""" | ||||||||||||||||||||||||||||||||||||||||||||
coordinator.hub.set_alarm(state=AlarmScene.AWAY) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
def stay(call) -> None: | ||||||||||||||||||||||||||||||||||||||||||||
"""Service call to set alarm system to 'stay' mode in UltraSync Hub.""" | ||||||||||||||||||||||||||||||||||||||||||||
coordinator.hub.set_alarm(state=AlarmScene.STAY) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
def disarm(call) -> None: | ||||||||||||||||||||||||||||||||||||||||||||
"""Service call to disable alarm in UltraSync Hub.""" | ||||||||||||||||||||||||||||||||||||||||||||
coordinator.hub.set_alarm(state=AlarmScene.DISARMED) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
hass.services.async_register(DOMAIN, SERVICE_AWAY, away, schema=vol.Schema({})) | ||||||||||||||||||||||||||||||||||||||||||||
hass.services.async_register(DOMAIN, SERVICE_STAY, stay, schema=vol.Schema({})) | ||||||||||||||||||||||||||||||||||||||||||||
hass.services.async_register(DOMAIN, SERVICE_DISARM, disarm, schema=vol.Schema({})) | ||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+78
to
+98
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
async def _async_update_listener(hass: HomeAssistantType, entry: ConfigEntry) -> None: | ||||||||||||||||||||||||||||||||||||||||||||
"""Handle options update.""" | ||||||||||||||||||||||||||||||||||||||||||||
if entry.options[CONF_SCAN_INTERVAL]: | ||||||||||||||||||||||||||||||||||||||||||||
coordinator = hass.data[DOMAIN][entry.entry_id]["coordinator"] | ||||||||||||||||||||||||||||||||||||||||||||
coordinator.update_interval = timedelta( | ||||||||||||||||||||||||||||||||||||||||||||
seconds=entry.options[CONF_SCAN_INTERVAL] | ||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
await coordinator.async_refresh() | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
class UltraSyncEntity(CoordinatorEntity): | ||||||||||||||||||||||||||||||||||||||||||||
"""Defines a base UltraSync entity.""" | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
def __init__( | ||||||||||||||||||||||||||||||||||||||||||||
self, *, entry_id: str, name: str, coordinator: UltraSyncDataUpdateCoordinator | ||||||||||||||||||||||||||||||||||||||||||||
) -> None: | ||||||||||||||||||||||||||||||||||||||||||||
"""Initialize the UltraSync entity.""" | ||||||||||||||||||||||||||||||||||||||||||||
super().__init__(coordinator) | ||||||||||||||||||||||||||||||||||||||||||||
self._name = name | ||||||||||||||||||||||||||||||||||||||||||||
self._entry_id = entry_id | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
@property | ||||||||||||||||||||||||||||||||||||||||||||
def name(self) -> str: | ||||||||||||||||||||||||||||||||||||||||||||
"""Return the name of the entity.""" | ||||||||||||||||||||||||||||||||||||||||||||
return self._name |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,123 @@ | ||||||
"""Config flow for the Interlogix/Hills ComNav UltraSync Hub.""" | ||||||
import logging | ||||||
from typing import Any, Dict, Optional | ||||||
|
||||||
import ultrasync | ||||||
import voluptuous as vol | ||||||
|
||||||
from homeassistant import config_entries | ||||||
from homeassistant.const import ( | ||||||
CONF_HOST, | ||||||
CONF_NAME, | ||||||
CONF_PIN, | ||||||
CONF_SCAN_INTERVAL, | ||||||
CONF_USERNAME, | ||||||
) | ||||||
from homeassistant.core import callback | ||||||
from homeassistant.helpers.typing import ConfigType, HomeAssistantType | ||||||
|
||||||
from .const import DEFAULT_NAME, DEFAULT_SCAN_INTERVAL | ||||||
from .const import DOMAIN # pylint: disable=unused-import | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
_LOGGER = logging.getLogger(__name__) | ||||||
|
||||||
|
||||||
class AuthFailureException(Exception): | ||||||
"""A general exception we can use to track Authentication failures.""" | ||||||
|
||||||
pass | ||||||
|
||||||
|
||||||
def validate_input(hass: HomeAssistantType, data: dict) -> Dict[str, Any]: | ||||||
"""Validate the user input allows us to connect.""" | ||||||
|
||||||
usync = ultrasync.UltraSync( | ||||||
host=data[CONF_HOST], user=data[CONF_USERNAME], pin=data[CONF_PIN] | ||||||
) | ||||||
|
||||||
# validate by attempting to authenticate with our hub | ||||||
|
||||||
if not usync.login(): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you the author of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am the author, yes. I agree it's not ideal; but 3 errors you identified that are all captured into one only play a role for the users initial hookup. Then it just works flawlessly from that point on. There is no internet requirement here; the panel is usually in the persons local home network. So presuming the user is already accessing their panel internal on their network (via web browser), they're just entering the same 3 entries here too ( Either way, it's still a good suggestion, but I'd have to re-factor a section of the code to handle this sort of thing. Is this required to at the start to just get support for the Ultrasync Panel into HA? |
||||||
# report our connection issue | ||||||
raise AuthFailureException() | ||||||
|
||||||
return True | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need to return anything. On failure this function will raise an exception. |
||||||
|
||||||
|
||||||
class UltraSyncConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): | ||||||
"""UltraSync config flow.""" | ||||||
|
||||||
VERSION = 1 | ||||||
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL | ||||||
|
||||||
@staticmethod | ||||||
@callback | ||||||
def async_get_options_flow(config_entry): | ||||||
"""Get the options flow for this handler.""" | ||||||
return UltraSyncOptionsFlowHandler(config_entry) | ||||||
|
||||||
async def async_step_user( | ||||||
self, user_input: Optional[ConfigType] = None | ||||||
) -> Dict[str, Any]: | ||||||
"""Handle user flow.""" | ||||||
|
||||||
errors = {} | ||||||
|
||||||
if user_input is not None: | ||||||
await self.async_set_unique_id(user_input.get(CONF_HOST)) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please check our criteria for config entry unique id: |
||||||
self._abort_if_unique_id_configured() | ||||||
|
||||||
try: | ||||||
await self.hass.async_add_executor_job( | ||||||
validate_input, self.hass, user_input | ||||||
) | ||||||
|
||||||
except AuthFailureException: | ||||||
errors["base"] = "invalid_auth" | ||||||
|
||||||
except Exception: # pylint: disable=broad-except | ||||||
_LOGGER.exception("Unexpected exception") | ||||||
errors["base"] = "unknown" | ||||||
|
||||||
else: | ||||||
return self.async_create_entry( | ||||||
title=user_input[CONF_HOST], | ||||||
data=user_input, | ||||||
) | ||||||
|
||||||
return self.async_show_form( | ||||||
step_id="user", | ||||||
data_schema=vol.Schema( | ||||||
{ | ||||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): str, | ||||||
vol.Required(CONF_HOST): str, | ||||||
vol.Required(CONF_USERNAME): str, | ||||||
vol.Required(CONF_PIN): str, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there any specifications? (for example 4 digits?). Could be nice to specify this, an example from worxlandroid vol.Required(CONF_PIN): vol.All(vol.Coerce(str), vol.Match(r"\d{4}")), |
||||||
} | ||||||
), | ||||||
errors=errors, | ||||||
) | ||||||
|
||||||
|
||||||
class UltraSyncOptionsFlowHandler(config_entries.OptionsFlow): | ||||||
"""Handle UltraSync client options.""" | ||||||
|
||||||
def __init__(self, config_entry): | ||||||
"""Initialize options flow.""" | ||||||
self.config_entry = config_entry | ||||||
|
||||||
async def async_step_init(self, user_input: Optional[ConfigType] = None): | ||||||
"""Manage UltraSync options.""" | ||||||
if user_input is not None: | ||||||
return self.async_create_entry(title="", data=user_input) | ||||||
|
||||||
options = { | ||||||
vol.Optional( | ||||||
CONF_SCAN_INTERVAL, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need to configure scan interval? Can we set a sane default instead? |
||||||
default=self.config_entry.options.get( | ||||||
CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL | ||||||
), | ||||||
): int, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you only want to accept positive numbers? I believe int can also be negative, but you would have to double check. ): cv.positive_int |
||||||
} | ||||||
|
||||||
return self.async_show_form(step_id="init", data_schema=vol.Schema(options)) |
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,20 @@ | ||||||||||||
"""Constants the Interlogix/Hills ComNav UltraSync Hub.""" | ||||||||||||
|
||||||||||||
DOMAIN = "ultrasync" | ||||||||||||
|
||||||||||||
# Scan Time (in seconds) | ||||||||||||
DEFAULT_SCAN_INTERVAL = 1 | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Normally we don't allow lower scan interval than 5 seconds for polling integrations. |
||||||||||||
|
||||||||||||
DEFAULT_NAME = "UltraSync" | ||||||||||||
|
||||||||||||
# Services | ||||||||||||
SERVICE_AWAY = "away" | ||||||||||||
SERVICE_STAY = "stay" | ||||||||||||
SERVICE_DISARM = "disarm" | ||||||||||||
|
||||||||||||
Comment on lines
+10
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
# Index used for managing loaded sensors | ||||||||||||
SENSORS = "sensors" | ||||||||||||
|
||||||||||||
DATA_COORDINATOR = "coordinator" | ||||||||||||
DATA_UNDO_UPDATE_LISTENER = "undo_update_listener" | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
SENSOR_UPDATE_LISTENER = "ultrasync_update_sensors" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need this anymore. We can move the code to
async_setup_entry
.