Skip to content

Commit 39e0e2d

Browse files
authored
Merge pull request #146 from natekspencer/dev
Handle race condition and alarm panel unique_id change
2 parents b3ddce3 + 4f2b75f commit 39e0e2d

File tree

3 files changed

+37
-11
lines changed

3 files changed

+37
-11
lines changed

custom_components/vivint/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,9 @@ def async_on_device_event(event_type: str, viv_device: VivintDevice) -> None:
155155
dev_reg.async_remove_device(device.id)
156156

157157
@callback
158-
def _async_save_tokens(ev: Event) -> None:
158+
async def _async_save_tokens(ev: Event) -> None:
159159
"""Save tokens to the config entry data."""
160-
undo_listener()
160+
await entry.runtime_data.disconnect()
161161
hass.config_entries.async_update_entry(
162162
entry, data=entry.data | {CONF_REFRESH_TOKEN: hub.account.refresh_token}
163163
)

custom_components/vivint/alarm_control_panel.py

+24-1
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
from __future__ import annotations
44

5+
from typing import Iterable
6+
57
from vivintpy.devices.alarm_panel import AlarmPanel
68
from vivintpy.enums import ArmedState
79

810
from homeassistant.components.alarm_control_panel import (
11+
DOMAIN as PLATFORM,
912
AlarmControlPanelEntity,
1013
AlarmControlPanelEntityFeature as Feature,
1114
CodeFormat,
@@ -19,11 +22,12 @@
1922
STATE_ALARM_TRIGGERED,
2023
)
2124
from homeassistant.core import HomeAssistant
25+
from homeassistant.helpers import entity_registry as er
2226
from homeassistant.helpers.entity_platform import AddEntitiesCallback
2327
from homeassistant.helpers.typing import StateType
2428

2529
from . import VivintConfigEntry
26-
from .const import CONF_DISARM_CODE
30+
from .const import CONF_DISARM_CODE, DOMAIN
2731
from .hub import VivintEntity, VivintHub
2832

2933
ARMED_STATE_MAP = {
@@ -62,6 +66,9 @@ async def async_setup_entry(
6266
if not entities:
6367
return
6468

69+
# Migrate unique ids
70+
async_update_unique_id(hass, PLATFORM, entities)
71+
6572
async_add_entities(entities)
6673

6774

@@ -105,3 +112,19 @@ async def async_alarm_arm_away(self, code: str | None = None) -> None:
105112
async def async_alarm_trigger(self, code: str | None = None) -> None:
106113
"""Send alarm trigger command."""
107114
await self.device.trigger_alarm()
115+
116+
117+
# to be removed 2025-01
118+
def async_update_unique_id(
119+
hass: HomeAssistant, domain: str, entities: Iterable[VivintAlarmControlPanelEntity]
120+
) -> None:
121+
"""Update unique ID to be based on VIN and entity description key instead of name."""
122+
ent_reg = er.async_get(hass)
123+
for entity in entities:
124+
old_unique_id = int(entity.unique_id)
125+
if entity_id := ent_reg.async_get_entity_id(domain, DOMAIN, old_unique_id):
126+
if existing_entity_id := ent_reg.async_get_entity_id(
127+
domain, DOMAIN, entity.unique_id
128+
):
129+
ent_reg.async_remove(existing_entity_id)
130+
ent_reg.async_update_entity(entity_id, new_unique_id=entity.unique_id)

custom_components/vivint/hub.py

+11-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
import asyncio
56
from collections.abc import Callable
67
from datetime import timedelta
78
import logging
@@ -72,6 +73,7 @@ def __init__(
7273
self.account: Account = None
7374
self.logged_in = False
7475
self.session = ClientSession()
76+
self._lock = asyncio.Lock()
7577

7678
async def _async_update_data() -> None:
7779
"""Update all device states from the Vivint API."""
@@ -113,14 +115,15 @@ async def login(
113115
raise ex
114116

115117
async def disconnect(self) -> None:
116-
"""Disconnect from Vivint, close the session and optionally remove cache."""
117-
if self.account.connected:
118-
await self.account.disconnect()
119-
if not self.session.closed:
120-
await self.session.close()
121-
if self.__undo_listener:
122-
self.__undo_listener()
123-
self.__undo_listener = None
118+
"""Disconnect from Vivint, close the session and stop listener."""
119+
async with self._lock:
120+
if self.account.connected:
121+
await self.account.disconnect()
122+
if not self.session.closed:
123+
await self.session.close()
124+
if self.__undo_listener:
125+
self.__undo_listener()
126+
self.__undo_listener = None
124127

125128
async def verify_mfa(self, code: str) -> bool:
126129
"""Verify MFA."""

0 commit comments

Comments
 (0)