Skip to content

Commit

Permalink
Fix for #18: Workaround attempting to schedule yaml after restore fro…
Browse files Browse the repository at this point in the history
…m 'storage' (.storage/core.entity_registry)

Notes:
HA is calling integration's async_setup_entry (__init__.py) to restore all components in 'storage' before calling components async_setup_platform (binary_sensor.py and switch.py) for yaml which is fine but effective processing of these tasks is taking place asynchronously and in random order while yaml should always the latest (it should overload storage). This is only an issue for integration supporting both configuration options simultaneously (yaml and configflow as it uses storage) which is the case here.

Goal of the workaround is therefore to delay import from configuration.yaml until all entities in storage have been restored.

Because async_setup_platform (yaml) is called after all sync_setup_entry calls from storage, a counter can be incremented for each such call and block the former until all sync_setup_entry complete and decrement the counter back to zero. This counter is implemented within a new SetupEntryStatus class used as a contextmanager guarding processing of each entry setup in async_setup_entry.
  • Loading branch information
jpcornil-git committed Apr 12, 2023
1 parent de08c5a commit 2197bf9
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 7 deletions.
33 changes: 28 additions & 5 deletions custom_components/mcp23017/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,23 @@

MCP23017_DATA_LOCK = asyncio.Lock()

class SetupEntryStatus:
"""Class registering the number of outstanding async_setup_entry calls."""
def __init__(self):
"""Initialize call counter."""
self.number = 0
def __enter__(self):
"""Increment call counter (with statement)."""
self.number +=1
def __exit__(self, exc_type, exc_value, exc_tb):
"""Decrement call counter (with statement)."""
self.number -=1
def busy(self):
"""Return True when there is at least one outstanding call"""
return self.number != 0

setup_entry_status = SetupEntryStatus()


async def async_setup(hass, config):
"""Set up the component."""
Expand Down Expand Up @@ -81,19 +98,18 @@ def stop_polling(event):
async def async_setup_entry(hass, config_entry):
"""Set up the MCP23017 from a config entry."""

# Forward entry setup to configured platform
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(
# Register this setup instance
with setup_entry_status:
# Forward entry setup to configured platform
await hass.config_entries.async_forward_entry_setup(
config_entry, config_entry.data[CONF_FLOW_PLATFORM]
)
)

return True


async def async_unload_entry(hass, config_entry):
"""Unload entity from MCP23017 component and platform."""

# Unload related platform
await hass.config_entries.async_forward_entry_unload(
config_entry, config_entry.data[CONF_FLOW_PLATFORM]
Expand Down Expand Up @@ -124,6 +140,13 @@ async def async_unload_entry(hass, config_entry):
type(component).__name__,
i2c_address,
)
else:
_LOGGER.warning(
"%s@0x%02x component not found, unable to unload entity (pin %d).",
type(component).__name__,
i2c_address,
config_entry.data[CONF_FLOW_PIN_NUMBER],
)

return True

Expand Down
6 changes: 5 additions & 1 deletion custom_components/mcp23017/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from homeassistant.components.binary_sensor import PLATFORM_SCHEMA, BinarySensorEntity
from homeassistant.helpers.device_registry import DeviceEntryType
from . import async_get_or_create
from . import async_get_or_create, setup_entry_status
from homeassistant.config_entries import SOURCE_IMPORT
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
Expand Down Expand Up @@ -48,6 +48,10 @@
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the MCP23017 platform for binary_sensor entities."""

# Wait for configflow to terminate before processing configuration.yaml
while setup_entry_status.busy():
await asyncio.sleep(0)

for pin_number, pin_name in config[CONF_PINS].items():
hass.async_create_task(
hass.config_entries.flow.async_init(
Expand Down
7 changes: 6 additions & 1 deletion custom_components/mcp23017/switch.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"""Platform for mcp23017-based switch."""

import asyncio
import functools
import logging

import voluptuous as vol

from . import async_get_or_create
from . import async_get_or_create, setup_entry_status
from homeassistant.components.switch import PLATFORM_SCHEMA, ToggleEntity
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.config_entries import SOURCE_IMPORT
Expand Down Expand Up @@ -43,6 +44,10 @@
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the MCP23017 for switch entities."""

# Wait for configflow to terminate before processing configuration.yaml
while setup_entry_status.busy():
await asyncio.sleep(0)

for pin_number, pin_name in config[CONF_PINS].items():
hass.async_create_task(
hass.config_entries.flow.async_init(
Expand Down

0 comments on commit 2197bf9

Please sign in to comment.