Skip to content
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

Refresh coordinators when setting or clearing usercode #68

Merged
merged 11 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 39 additions & 32 deletions custom_components/lock_code_manager/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,12 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> bool:
"""Set up config entry."""
coordinators: list[LockUsercodeUpdateCoordinator] = list(
hass.data[DOMAIN][config_entry.entry_id][COORDINATORS].values()
)

@callback
def add_pin_enabled_entity(slot_num: int, ent_reg: er.EntityRegistry) -> None:
"""Add PIN enabled binary sensor entities for slot."""
async_add_entities(
[
LockCodeManagerPINSyncedEntity(
hass, ent_reg, config_entry, coordinators, slot_num
)
],
[LockCodeManagerPINSyncedEntity(hass, ent_reg, config_entry, slot_num)],
True,
)

Expand All @@ -84,14 +77,12 @@ def __init__(
hass: HomeAssistant,
ent_reg: er.EntityRegistry,
config_entry: ConfigEntry,
coordinators: list[LockUsercodeUpdateCoordinator],
slot_num: int,
) -> None:
"""Initialize entity."""
BaseLockCodeManagerEntity.__init__(
self, hass, ent_reg, config_entry, slot_num, ATTR_PIN_SYNCED_TO_LOCKS
)
self.coordinators = coordinators
self._entity_id_map: dict[str, str] = {}
self._issue_reg: ir.IssueRegistry | None = None
self._call_later_unsub: Callable | None = None
Expand All @@ -114,18 +105,7 @@ async def async_update_usercodes(
"""Update usercodes on locks based on state change."""
if not states:
states = {}
disabling_entity_ids = (
state["entity_id"]
for key, state in states.items()
if (key != CONF_NUMBER_OF_USES and state["state"] != STATE_ON)
or (
key == CONF_NUMBER_OF_USES
and (
state["state"] in (STATE_UNAVAILABLE, STATE_UNKNOWN)
or int(float(state["state"])) == 0
)
)
)
coordinators: list[LockUsercodeUpdateCoordinator] = []
for lock in self.locks:
lock_slot_sensor_state = self._lock_slot_sensor_state(lock)
if self.is_on:
Expand All @@ -145,27 +125,52 @@ async def async_update_usercodes(
if lock_slot_sensor_state == pin_state.state:
continue

await lock.async_set_usercode(
int(self.slot_num), pin_state.state, name_state.state
)

_LOGGER.info(
"%s (%s): Setting usercode for %s slot %s",
"%s (%s): Set usercode for %s slot %s",
self.config_entry.entry_id,
self.config_entry.title,
lock.lock.entity_id,
self.slot_num,
)

await lock.async_set_usercode(
int(self.slot_num), pin_state.state, name_state.state
)
else:
if lock_slot_sensor_state in (
"",
STATE_UNKNOWN,
):
continue

if not (
disabling_entity_ids := list(
state["entity_id"]
for key, state in states.items()
if (
key not in (CONF_NUMBER_OF_USES, CONF_PIN)
and state["state"] != STATE_ON
)
or (
key == CONF_NUMBER_OF_USES
and (
state["state"] in (STATE_UNAVAILABLE, STATE_UNKNOWN)
or int(float(state["state"])) == 0
)
)
or (
key == CONF_PIN
and state["state"] != self._lock_slot_sensor_state(lock)
)
)
):
return

await lock.async_clear_usercode(int(self.slot_num))

_LOGGER.info(
(
"%s (%s): Clearing usercode for lock %s slot %s because the "
"%s (%s): Cleared usercode for lock %s slot %s because the "
"following entities indicate the slot is disabled: %s"
),
self.config_entry.entry_id,
Expand All @@ -175,12 +180,14 @@ async def async_update_usercodes(
", ".join(disabling_entity_ids),
)

await lock.async_clear_usercode(int(self.slot_num))

await asyncio.gather(
*[coordinator.async_refresh() for coordinator in self.coordinators]
coordinators.append(
self.hass.data[DOMAIN][COORDINATORS][lock.lock.entity_id]
)

await asyncio.gather(
*[coordinator.async_refresh() for coordinator in coordinators]
)

async def _update_state(self, _: datetime | None = None) -> None:
"""Update binary sensor state by getting dependent states."""
if self._call_later_unsub:
Expand Down
6 changes: 3 additions & 3 deletions tests/test_binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ async def test_binary_sensor_entity(
)
await hass.async_block_till_done()

assert hass.data[LOCK_DATA][LOCK_1_ENTITY_ID]["service_calls"]["set_usercode"] == [
(2, "0987", "test2")
]
assert hass.data[LOCK_DATA][LOCK_1_ENTITY_ID]["service_calls"]["set_usercode"][
-1
] == (2, "0987", "test2")

new_config = copy.deepcopy(BASE_CONFIG)
new_config[CONF_SLOTS][2][CONF_CALENDAR] = "calendar.test_2"
Expand Down
3 changes: 2 additions & 1 deletion tests/test_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import logging

from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant

_LOGGER = logging.getLogger(__name__)
Expand All @@ -13,7 +14,7 @@ async def test_sensor_entity(
lock_code_manager_config_entry,
):
"""Test sensor entity."""
for code_slot, pin in ((1, "1234"), (2, "5678")):
for code_slot, pin in ((1, "1234"), (2, STATE_UNAVAILABLE)):
state = hass.states.get(f"sensor.test_1_code_slot_{code_slot}")
assert state
assert state.state == pin
Expand Down