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

Allow device removal #8

Merged
merged 2 commits into from
Aug 2, 2022
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
18 changes: 17 additions & 1 deletion custom_components/elro_connects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import SERVICE_RELOAD, Platform
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers.device_registry import DeviceEntry
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import DEFAULT_INTERVAL, DOMAIN
Expand Down Expand Up @@ -39,7 +40,7 @@ async def _async_update_data() -> dict[int, dict]:
device_update = copy.deepcopy(elro_connects_api.data)
for device_id, device_data in device_update.items():
if ATTR_DEVICE_STATE not in device_data:
# Skip entries without device state
# Unlink entry without device state
continue
if device_id not in coordinator_update:
# new device, or known state
Expand Down Expand Up @@ -111,3 +112,18 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data[DOMAIN].pop(entry.entry_id)

return unload_ok


async def async_remove_config_entry_device(
hass: HomeAssistant, entry: ConfigEntry, device_entry: DeviceEntry
) -> bool:
"""Allow manual removal of a device if not in use."""
elro_connects_api: ElroConnectsK1 = hass.data[DOMAIN][entry.entry_id]
device_unique_id: str = device_entry.identifiers.copy().pop()[1]
device_id_str = device_unique_id[len(elro_connects_api.connector_id) + 1 :]
if not device_id_str:
return False
device_id = int(device_id_str)
if device_id in elro_connects_api.data:
return False
return True
2 changes: 1 addition & 1 deletion custom_components/elro_connects/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"requirements": ["lib-elro-connects==0.5.1"],
"codeowners": ["@jbouwh"],
"iot_class": "local_polling",
"version": "0.2.0"
"version": "0.1.7"
}
2 changes: 1 addition & 1 deletion hacs.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "Elro Connects",
"hacs": "1.6.0",
"hacs": "1.0.0",
"homeassistant": "2022.7.0"
}
65 changes: 65 additions & 0 deletions tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,31 @@
import pytest
from pytest_homeassistant_custom_component.common import async_fire_time_changed

from custom_components.elro_connects import async_remove_config_entry_device
from custom_components.elro_connects.const import DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from homeassistant.setup import async_setup_component
from homeassistant.util import dt

from .test_common import MOCK_DEVICE_STATUS_DATA


async def help_remove_device(hass, ws_client, device_id, config_entry_id):
"""Remove config entry from a device."""
await ws_client.send_json(
{
"id": 5,
"type": "config/device_registry/remove_config_entry",
"config_entry_id": config_entry_id,
"device_id": device_id,
}
)
response = await ws_client.receive_json()
assert response["success"]


async def test_setup_integration_no_data(
hass: HomeAssistant,
mock_k1_connector: dict[AsyncMock],
Expand Down Expand Up @@ -113,3 +129,52 @@ async def test_configure_platforms_dynamically(
assert hass.states.get("siren.beganegrond").state == "unknown"
assert hass.states.get("siren.eerste_etage") is not None
assert hass.states.get("siren.zolder") is not None


async def test_remove_device_from_config_entry(
hass: HomeAssistant,
mock_k1_connector: dict[AsyncMock],
mock_entry: ConfigEntry,
) -> None:
"""Test the removing a device would work."""
# Initial status holds device info for device [1,2,4]
initial_status_data = copy.deepcopy(MOCK_DEVICE_STATUS_DATA)
# Updated status holds device info for device [1,2]
updated_status_data = copy.deepcopy(MOCK_DEVICE_STATUS_DATA)
updated_status_data.pop(4)

# setup integration with 3 siren entities
mock_k1_connector["result"].return_value = initial_status_data
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()

# Simulate deactivation of siren 4
mock_k1_connector["result"].return_value = updated_status_data
time = dt.now() + timedelta(seconds=30)
async_fire_time_changed(hass, time)
# await coordinator.async_request_refresh()
await hass.async_block_till_done()
await hass.async_block_till_done()

connector_id = hass.data[DOMAIN][mock_entry.entry_id].connector_id
device_registry = dr.async_get(hass)
# Test removing the device for siren 4 will work
device_entry = device_registry.async_get_device(
identifiers={(DOMAIN, f"{connector_id}_4")}
)
assert device_entry
assert await async_remove_config_entry_device(hass, mock_entry, device_entry)

# Test removing the device for siren 2 will not work because it is in use
device_entry = device_registry.async_get_device(
identifiers={(DOMAIN, f"{connector_id}_2")}
)
assert device_entry
assert not await async_remove_config_entry_device(hass, mock_entry, device_entry)

# Test removing the the K1 connector device will not work
device_entry = device_registry.async_get_device(
identifiers={(DOMAIN, f"{connector_id}")}
)
assert device_entry
assert not await async_remove_config_entry_device(hass, mock_entry, device_entry)
2 changes: 1 addition & 1 deletion version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.6
0.1.7