Skip to content
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
9 changes: 6 additions & 3 deletions homeassistant/components/loqed/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ async def validate_input(
)
cloud_client = cloud_loqed.LoqedCloudAPI(cloud_api_client)
lock_data = await cloud_client.async_get_locks()
except aiohttp.ClientError:
except aiohttp.ClientError as err:
_LOGGER.error("HTTP Connection error to loqed API")
raise CannotConnect from aiohttp.ClientError
raise CannotConnect from err

try:
selected_lock = next(
Expand Down Expand Up @@ -137,7 +137,10 @@ async def async_step_user(
errors["base"] = "invalid_auth"
else:
await self.async_set_unique_id(
re.sub(r"LOQED-([a-f0-9]+)\.local", r"\1", info["bridge_mdns_hostname"])
re.sub(
r"LOQED-([a-f0-9]+)\.local", r"\1", info["bridge_mdns_hostname"]
),
raise_on_progress=False,
)
self._abort_if_unique_id_configured()

Expand Down
2 changes: 0 additions & 2 deletions homeassistant/components/loqed/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,3 @@


DOMAIN = "loqed"
OAUTH2_AUTHORIZE = "https://app.loqed.com/API/integration_oauth3/login.php"
OAUTH2_TOKEN = "https://app.loqed.com/API/integration_oauth3/token.php"
9 changes: 4 additions & 5 deletions homeassistant/components/loqed/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

from homeassistant.components import webhook
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_WEBHOOK_ID
from homeassistant.core import HomeAssistant, callback
from homeassistant.const import CONF_NAME, CONF_WEBHOOK_ID
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

from .const import DOMAIN
Expand Down Expand Up @@ -79,17 +79,16 @@ def __init__(
) -> None:
"""Initialize the Loqed Data Update coordinator."""
super().__init__(hass, _LOGGER, name="Loqed sensors")
self._hass = hass
self._api = api
self._entry = entry
self.lock = lock
self.device_name = self._entry.data[CONF_NAME]

async def _async_update_data(self) -> StatusMessage:
"""Fetch data from API endpoint."""
async with async_timeout.timeout(10):
return await self._api.async_get_lock_details()

@callback
async def _handle_webhook(
self, hass: HomeAssistant, webhook_id: str, request: Request
) -> None:
Expand All @@ -116,7 +115,7 @@ async def ensure_webhooks(self) -> None:
self.hass, DOMAIN, "Loqed", webhook_id, self._handle_webhook
)
webhook_url = webhook.async_generate_url(self.hass, webhook_id)
_LOGGER.info("Webhook URL: %s", webhook_url)
_LOGGER.debug("Webhook URL: %s", webhook_url)

webhooks = await self.lock.getWebhooks()

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/loqed/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def __init__(self, coordinator: LoqedDataCoordinator) -> None:
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, lock_id)},
manufacturer="LOQED",
name="LOQED Lock",
name=coordinator.device_name,
model="Touch Smart Lock",
connections={(CONNECTION_NETWORK_MAC, lock_id)},
)
8 changes: 4 additions & 4 deletions homeassistant/components/loqed/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,25 @@ async def async_setup_entry(
"""Set up the Loqed lock platform."""
coordinator = hass.data[DOMAIN][entry.entry_id]

async_add_entities([LoqedLock(coordinator, entry.data["name"])])
async_add_entities([LoqedLock(coordinator)])


class LoqedLock(LoqedEntity, LockEntity):
"""Representation of a loqed lock."""

_attr_supported_features = LockEntityFeature.OPEN

def __init__(self, coordinator: LoqedDataCoordinator, name: str) -> None:
def __init__(self, coordinator: LoqedDataCoordinator) -> None:
"""Initialize the lock."""
super().__init__(coordinator)
self._lock = coordinator.lock
self._attr_unique_id = self._lock.id
self._attr_name = name
self._attr_name = None

@property
def changed_by(self) -> str:
"""Return internal ID of last used key."""
return "KeyID " + str(self._lock.last_key_id)
return f"KeyID {self._lock.last_key_id}"

@property
def is_locking(self) -> bool | None:
Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/loqed/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"unknown": "[%key:common::config_flow::error::unknown%]"
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
Expand Down
22 changes: 0 additions & 22 deletions homeassistant/components/loqed/translations/en.json

This file was deleted.

46 changes: 9 additions & 37 deletions tests/components/loqed/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,6 @@
from tests.common import MockConfigEntry, load_fixture


async def test_webhook_rejects_invalid_message(
hass: HomeAssistant,
hass_client_no_auth,
integration: MockConfigEntry,
lock: loqed.Lock,
):
"""Test webhook called with invalid message."""
await async_setup_component(hass, "http", {"http": {}})
client = await hass_client_no_auth()

coordinator = hass.data[DOMAIN][integration.entry_id]
lock.receiveWebhook = AsyncMock(return_value={"error": "invalid hash"})

with patch.object(coordinator, "async_set_updated_data") as mock:
message = load_fixture("loqed/battery_update.json")
timestamp = 1653304609
await client.post(
f"/api/webhook/{integration.data[CONF_WEBHOOK_ID]}",
data=message,
headers={"timestamp": str(timestamp), "hash": "incorrect hash"},
)

mock.assert_not_called()


async def test_webhook_accepts_valid_message(
hass: HomeAssistant,
hass_client_no_auth,
Expand All @@ -49,20 +24,17 @@ async def test_webhook_accepts_valid_message(
"""Test webhook called with valid message."""
await async_setup_component(hass, "http", {"http": {}})
client = await hass_client_no_auth()
processed_message = json.loads(load_fixture("loqed/battery_update.json"))
coordinator = hass.data[DOMAIN][integration.entry_id]
processed_message = json.loads(load_fixture("loqed/lock_going_to_nightlock.json"))
lock.receiveWebhook = AsyncMock(return_value=processed_message)

with patch.object(coordinator, "async_update_listeners") as mock:
message = load_fixture("loqed/battery_update.json")
timestamp = 1653304609
await client.post(
f"/api/webhook/{integration.data[CONF_WEBHOOK_ID]}",
data=message,
headers={"timestamp": str(timestamp), "hash": "incorrect hash"},
)

mock.assert_called()
message = load_fixture("loqed/battery_update.json")
timestamp = 1653304609
await client.post(
f"/api/webhook/{integration.data[CONF_WEBHOOK_ID]}",
data=message,
headers={"timestamp": str(timestamp), "hash": "incorrect hash"},
)
lock.receiveWebhook.assert_called()


async def test_setup_webhook_in_bridge(
Expand Down
10 changes: 5 additions & 5 deletions tests/components/loqed/test_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ async def test_lock_entity(
integration: MockConfigEntry,
) -> None:
"""Test the lock entity."""
entity_id = "lock.loqed_lock_home"
entity_id = "lock.home"

state = hass.states.get(entity_id)

Expand All @@ -37,7 +37,7 @@ async def test_lock_responds_to_bolt_state_updates(
lock.bolt_state = "night_lock"
coordinator.async_update_listeners()

entity_id = "lock.loqed_lock_home"
entity_id = "lock.home"

state = hass.states.get(entity_id)

Expand All @@ -50,7 +50,7 @@ async def test_lock_transition_to_unlocked(
) -> None:
"""Tests the lock transitions to unlocked state."""

entity_id = "lock.loqed_lock_home"
entity_id = "lock.home"

await hass.services.async_call(
"lock", SERVICE_UNLOCK, {ATTR_ENTITY_ID: entity_id}, blocking=True
Expand All @@ -64,7 +64,7 @@ async def test_lock_transition_to_locked(
) -> None:
"""Tests the lock transitions to locked state."""

entity_id = "lock.loqed_lock_home"
entity_id = "lock.home"

await hass.services.async_call(
"lock", SERVICE_LOCK, {ATTR_ENTITY_ID: entity_id}, blocking=True
Expand All @@ -78,7 +78,7 @@ async def test_lock_transition_to_open(
) -> None:
"""Tests the lock transitions to open state."""

entity_id = "lock.loqed_lock_home"
entity_id = "lock.home"

await hass.services.async_call(
"lock", SERVICE_OPEN, {ATTR_ENTITY_ID: entity_id}, blocking=True
Expand Down