mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 08:17:08 +00:00
Fix race in rfxtrx config flow (#93804)
* Fix race in rfxtrx config flow * Add timeout * Use async_timeout.timeout
This commit is contained in:
parent
90bf5429ca
commit
55c2bb59c8
@ -2,12 +2,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from contextlib import suppress
|
||||||
import copy
|
import copy
|
||||||
import itertools
|
import itertools
|
||||||
import os
|
import os
|
||||||
from typing import Any, TypedDict, cast
|
from typing import Any, TypedDict, cast
|
||||||
|
|
||||||
import RFXtrx as rfxtrxmod
|
import RFXtrx as rfxtrxmod
|
||||||
|
from async_timeout import timeout
|
||||||
import serial
|
import serial
|
||||||
import serial.tools.list_ports
|
import serial.tools.list_ports
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
@ -346,34 +348,57 @@ class OptionsFlow(config_entries.OptionsFlow):
|
|||||||
entity_migration_map[new_entity_id] = entry
|
entity_migration_map[new_entity_id] = entry
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _handle_state_change(
|
def _handle_state_removed(
|
||||||
entity_id: str, old_state: State | None, new_state: State | None
|
entity_id: str, old_state: State | None, new_state: State | None
|
||||||
) -> None:
|
) -> None:
|
||||||
# Wait for entities to finish cleanup
|
# Wait for entities to finish cleanup
|
||||||
if new_state is None and entity_id in pending_entities:
|
if new_state is None and entity_id in entities_to_be_removed:
|
||||||
pending_entities.remove(entity_id)
|
entities_to_be_removed.remove(entity_id)
|
||||||
if not pending_entities:
|
if not entities_to_be_removed:
|
||||||
wait_for_entities.set()
|
wait_for_entities.set()
|
||||||
|
|
||||||
# Create a set with entities to be removed which are currently in the state
|
# Create a set with entities to be removed which are currently in the state
|
||||||
# machine
|
# machine
|
||||||
pending_entities = {
|
entities_to_be_removed = {
|
||||||
entry.entity_id
|
entry.entity_id
|
||||||
for entry in entity_migration_map.values()
|
for entry in entity_migration_map.values()
|
||||||
if not self.hass.states.async_available(entry.entity_id)
|
if not self.hass.states.async_available(entry.entity_id)
|
||||||
}
|
}
|
||||||
wait_for_entities = asyncio.Event()
|
wait_for_entities = asyncio.Event()
|
||||||
remove_track_state_changes = async_track_state_change(
|
remove_track_state_changes = async_track_state_change(
|
||||||
self.hass, pending_entities, _handle_state_change
|
self.hass, entities_to_be_removed, _handle_state_removed
|
||||||
)
|
)
|
||||||
|
|
||||||
for entry in entity_migration_map.values():
|
for entry in entity_migration_map.values():
|
||||||
entity_registry.async_remove(entry.entity_id)
|
entity_registry.async_remove(entry.entity_id)
|
||||||
|
|
||||||
# Wait for entities to finish cleanup
|
# Wait for entities to finish cleanup
|
||||||
await wait_for_entities.wait()
|
with suppress(asyncio.TimeoutError):
|
||||||
|
async with timeout(10):
|
||||||
|
await wait_for_entities.wait()
|
||||||
remove_track_state_changes()
|
remove_track_state_changes()
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _handle_state_added(
|
||||||
|
entity_id: str, old_state: State | None, new_state: State | None
|
||||||
|
) -> None:
|
||||||
|
# Wait for entities to be added
|
||||||
|
if old_state is None and entity_id in entities_to_be_added:
|
||||||
|
entities_to_be_added.remove(entity_id)
|
||||||
|
if not entities_to_be_added:
|
||||||
|
wait_for_entities.set()
|
||||||
|
|
||||||
|
# Create a set with entities to be added to the state machine
|
||||||
|
entities_to_be_added = {
|
||||||
|
entry.entity_id
|
||||||
|
for entry in entity_migration_map.values()
|
||||||
|
if self.hass.states.async_available(entry.entity_id)
|
||||||
|
}
|
||||||
|
wait_for_entities = asyncio.Event()
|
||||||
|
remove_track_state_changes = async_track_state_change(
|
||||||
|
self.hass, entities_to_be_added, _handle_state_added
|
||||||
|
)
|
||||||
|
|
||||||
for entity_id, entry in entity_migration_map.items():
|
for entity_id, entry in entity_migration_map.items():
|
||||||
entity_registry.async_update_entity(
|
entity_registry.async_update_entity(
|
||||||
entity_id,
|
entity_id,
|
||||||
@ -382,6 +407,12 @@ class OptionsFlow(config_entries.OptionsFlow):
|
|||||||
icon=entry.icon,
|
icon=entry.icon,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Wait for entities to finish renaming
|
||||||
|
with suppress(asyncio.TimeoutError):
|
||||||
|
async with timeout(10):
|
||||||
|
await wait_for_entities.wait()
|
||||||
|
remove_track_state_changes()
|
||||||
|
|
||||||
device_registry.async_remove_device(old_device)
|
device_registry.async_remove_device(old_device)
|
||||||
|
|
||||||
def _can_add_device(self, new_rfx_obj: rfxtrxmod.RFXtrxEvent) -> bool:
|
def _can_add_device(self, new_rfx_obj: rfxtrxmod.RFXtrxEvent) -> bool:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user