Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
7a16ff1
refactor: introduce provider abstraction for multi-platform lock support
raman325 Jan 12, 2026
d17a318
fix: update tests for provider abstraction and add developer guide
raman325 Jan 12, 2026
34559f9
style: apply ruff formatting to provider abstraction changes
raman325 Jan 12, 2026
ff7d1ef
fix: use async_create_task for provider lock event callback
raman325 Jan 18, 2026
eb8a71e
fix: improve test cleanup to work in CI environment
raman325 Jan 18, 2026
2d6d9c6
style: fix ruff errors and move imports to top level
raman325 Jan 18, 2026
1ae5a21
test: add comprehensive Z-Wave JS provider tests and MockProvider
raman325 Jan 18, 2026
cc9f393
test: add tests for helpers and coordinator coverage
raman325 Jan 18, 2026
4c088de
refactor: move provider imports to top-level and simplify domain checks
raman325 Jan 19, 2026
934bc70
refactor: add optional usercode methods to BaseLockProvider
raman325 Jan 19, 2026
92aa880
refactor: remove deprecated zwave_js_lock_node/device fields
raman325 Jan 19, 2026
d3adb32
refactor: rename exception and remove deprecated zwave helpers
raman325 Jan 19, 2026
dc29406
chore: remove unused fixtures and dead code
raman325 Jan 19, 2026
7a86550
refactor: move provider tests to tests/providers/ directory
raman325 Jan 19, 2026
ab9c410
fix: exclude provider from JSON serialization
raman325 Jan 19, 2026
0418b95
style: apply ruff formatting fixes
raman325 Jan 19, 2026
74b38de
style: add docstring to providers test package
raman325 Jan 19, 2026
f5c6833
Merge branch 'beta' into feature/provider-abstraction
raman325 Jan 20, 2026
41f16a3
fix: update test to use int for accesslimit_count
raman325 Jan 20, 2026
72865a1
refactor: rename async_get_usercode_from_node to async_refresh_usercode
raman325 Jan 20, 2026
924d9b2
docs: clarify async_refresh_usercode is for integrations with caching
raman325 Jan 20, 2026
0084503
refactor: async_refresh_usercode defaults to calling async_get_usercode
raman325 Jan 20, 2026
8b0d131
feat: filter config flow lock list to supported platforms only
raman325 Jan 20, 2026
d2d4cc5
refactor: remove redundant provider checks from platform setup
raman325 Jan 20, 2026
c387e95
Merge remote-tracking branch 'upstream/beta' into feature/provider-ab…
raman325 Jan 21, 2026
19577f6
fix: notify immediately when sync status changes
raman325 Jan 21, 2026
fdb263f
fix: notify after successful PIN set/clear operations
raman325 Jan 21, 2026
0268170
refactor: move Z-Wave specific logic from coordinator to provider
raman325 Jan 22, 2026
a89f662
refactor: move LockActivity to zwave_js provider
raman325 Jan 22, 2026
d062225
feat: add reset button to code slot lovelace card
raman325 Jan 28, 2026
1934c7a
style: apply ruff formatting to lovelace.py
raman325 Jan 28, 2026
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
54 changes: 31 additions & 23 deletions custom_components/keymaster/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from .const import CONF_SLOTS, CONF_START, COORDINATOR, DOMAIN
from .coordinator import KeymasterCoordinator
from .entity import KeymasterEntity, KeymasterEntityDescription
from .helpers import async_using_zwave_js

_LOGGER: logging.Logger = logging.getLogger(__name__)

Expand All @@ -30,7 +29,17 @@ async def async_setup_entry(
coordinator: KeymasterCoordinator = hass.data[DOMAIN][COORDINATOR]
kmlock = await coordinator.get_lock_by_config_entry_id(config_entry.entry_id)
entities: list = []
if async_using_zwave_js(hass=hass, kmlock=kmlock):

if not kmlock:
_LOGGER.error("Lock not found for config entry %s", config_entry.entry_id)
raise PlatformNotReady

# Provider is guaranteed to exist - config flow filters to supported platforms
# and coordinator fails setup if provider creation fails
assert kmlock.provider is not None

# Add connection status sensor if provider supports it
if kmlock.provider.supports_connection_status:
entities.append(
KeymasterBinarySensor(
entity_description=KeymasterBinarySensorEntityDescription(
Expand All @@ -44,28 +53,27 @@ async def async_setup_entry(
),
)
)
entities.extend(
[
KeymasterBinarySensor(
entity_description=KeymasterBinarySensorEntityDescription(
key=f"binary_sensor.code_slots:{x}.active",
name=f"Code Slot {x}: Active",
icon="mdi:run",
entity_registry_enabled_default=True,
hass=hass,
config_entry=config_entry,
coordinator=coordinator,
)
)
for x in range(
config_entry.data[CONF_START],
config_entry.data[CONF_START] + config_entry.data[CONF_SLOTS],

# Add code slot active sensors
entities.extend(
[
KeymasterBinarySensor(
entity_description=KeymasterBinarySensorEntityDescription(
key=f"binary_sensor.code_slots:{x}.active",
name=f"Code Slot {x}: Active",
icon="mdi:run",
entity_registry_enabled_default=True,
hass=hass,
config_entry=config_entry,
coordinator=coordinator,
)
]
)
else:
_LOGGER.error("Z-Wave integration not found")
raise PlatformNotReady
)
for x in range(
config_entry.data[CONF_START],
config_entry.data[CONF_START] + config_entry.data[CONF_SLOTS],
)
]
)

async_add_entities(entities, True)

Expand Down
22 changes: 21 additions & 1 deletion custom_components/keymaster/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations

from collections.abc import MutableMapping
from collections.abc import Callable, MutableMapping
import logging
from typing import Any

Expand Down Expand Up @@ -39,6 +39,7 @@
NONE_TEXT,
)
from .coordinator import KeymasterCoordinator
from .providers import is_platform_supported

_LOGGER: logging.Logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -155,14 +156,32 @@ def _get_entities(
extra_entities: list[str] | None = None,
exclude_entities: list[str] | None = None,
sort: bool = True,
filter_func: Callable[[HomeAssistant, str], bool] | None = None,
) -> list[str]:
"""Get entities from a domain with optional filtering.

Args:
hass: Home Assistant instance
domain: Entity domain (e.g., "lock", "sensor")
search: Only include entities whose ID contains one of these strings
extra_entities: Additional entity IDs to append to results
exclude_entities: Entity IDs to remove from results
sort: Whether to sort the results alphabetically
filter_func: Optional callback(hass, entity_id) -> bool to filter entities.
Entity is included only if filter_func returns True.

"""
data: list[str] = []
if domain not in hass.data:
return extra_entities or []

for entity in hass.data[domain].entities:
# Skip if search terms provided and entity ID doesn't contain any of them
if search is not None and not any(map(entity.entity_id.__contains__, search)):
continue
# Skip if filter function provided and it returns False for this entity
if filter_func is not None and not filter_func(hass, entity.entity_id):
continue
data.append(entity.entity_id)

if extra_entities:
Expand Down Expand Up @@ -220,6 +239,7 @@ def _get_default(key: str, fallback_default: Any = None) -> Any:
hass=hass,
domain=LOCK_DOMAIN,
exclude_entities=_get_locks_in_use(hass=hass, exclude=_get_default(CONF_LOCK_ENTITY_ID)),
filter_func=is_platform_supported,
)
if not lock_entities:
if flow is not None:
Expand Down
Loading