-
-
Notifications
You must be signed in to change notification settings - Fork 37.1k
Add binary sensor platform to devolo Home Network #60301
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
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
ca7bd0e
Add binary sensor platform
Shutgun 46f8438
Add tests
Shutgun ae4cc31
Switch to single DevoloBinarySensorEntity
Shutgun 6053e26
Fix pylint
Shutgun c0b51de
Replace lamba by function
Shutgun a5a90a3
Combine decorators
Shutgun 8e79d4e
Update entity init
Shutgun 1fc0f09
Apply suggestions
Shutgun e52ab0f
Remove update sensor
Shutgun beaa9c1
Remove fwupdate coordinator
Shutgun 78cd487
Remove unused test code
Shutgun 2ce165c
Merge branch 'dev' into hn_binary_sensor
bdraco File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
99 changes: 99 additions & 0 deletions
99
homeassistant/components/devolo_home_network/binary_sensor.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| """Platform for binary sensor integration.""" | ||
| from __future__ import annotations | ||
|
|
||
| from collections.abc import Callable | ||
| from dataclasses import dataclass | ||
|
|
||
| from devolo_plc_api.device import Device | ||
|
|
||
| from homeassistant.components.binary_sensor import ( | ||
| DEVICE_CLASS_PLUG, | ||
| BinarySensorEntity, | ||
| BinarySensorEntityDescription, | ||
| ) | ||
| from homeassistant.config_entries import ConfigEntry | ||
| from homeassistant.core import HomeAssistant | ||
| from homeassistant.helpers.entity import EntityCategory | ||
| from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
| from homeassistant.helpers.update_coordinator import DataUpdateCoordinator | ||
|
|
||
| from .const import CONNECTED_PLC_DEVICES, CONNECTED_TO_ROUTER, DOMAIN | ||
| from .entity import DevoloEntity | ||
|
|
||
|
|
||
| def _is_connected_to_router(entity: DevoloBinarySensorEntity) -> bool: | ||
| """Check, if device is attached to the router.""" | ||
| return all( | ||
| device["attached_to_router"] | ||
| for device in entity.coordinator.data["network"]["devices"] | ||
| if device["mac_address"] == entity.device.mac | ||
| ) | ||
|
|
||
|
|
||
| @dataclass | ||
| class DevoloBinarySensorRequiredKeysMixin: | ||
| """Mixin for required keys.""" | ||
|
|
||
| value_func: Callable[[DevoloBinarySensorEntity], bool] | ||
|
|
||
|
|
||
| @dataclass | ||
| class DevoloBinarySensorEntityDescription( | ||
| BinarySensorEntityDescription, DevoloBinarySensorRequiredKeysMixin | ||
| ): | ||
| """Describes devolo sensor entity.""" | ||
|
|
||
|
|
||
| SENSOR_TYPES: dict[str, DevoloBinarySensorEntityDescription] = { | ||
| CONNECTED_TO_ROUTER: DevoloBinarySensorEntityDescription( | ||
| key=CONNECTED_TO_ROUTER, | ||
| device_class=DEVICE_CLASS_PLUG, | ||
| entity_category=EntityCategory.DIAGNOSTIC, | ||
| entity_registry_enabled_default=False, | ||
| icon="mdi:router-network", | ||
| name="Connected to router", | ||
| value_func=_is_connected_to_router, | ||
| ), | ||
| } | ||
|
|
||
|
|
||
| async def async_setup_entry( | ||
| hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback | ||
| ) -> None: | ||
| """Get all devices and sensors and setup them via config entry.""" | ||
| device: Device = hass.data[DOMAIN][entry.entry_id]["device"] | ||
| coordinators: dict[str, DataUpdateCoordinator] = hass.data[DOMAIN][entry.entry_id][ | ||
| "coordinators" | ||
| ] | ||
|
|
||
| entities: list[BinarySensorEntity] = [] | ||
| if device.plcnet: | ||
| entities.append( | ||
| DevoloBinarySensorEntity( | ||
| coordinators[CONNECTED_PLC_DEVICES], | ||
| SENSOR_TYPES[CONNECTED_TO_ROUTER], | ||
| device, | ||
| entry.title, | ||
| ) | ||
| ) | ||
| async_add_entities(entities) | ||
|
|
||
|
|
||
| class DevoloBinarySensorEntity(DevoloEntity, BinarySensorEntity): | ||
| """Representation of a devolo binary sensor.""" | ||
|
|
||
| def __init__( | ||
| self, | ||
| coordinator: DataUpdateCoordinator, | ||
| description: DevoloBinarySensorEntityDescription, | ||
| device: Device, | ||
| device_name: str, | ||
| ) -> None: | ||
| """Initialize entity.""" | ||
| self.entity_description: DevoloBinarySensorEntityDescription = description | ||
| super().__init__(coordinator, device, device_name) | ||
|
|
||
| @property | ||
| def is_on(self) -> bool: | ||
| """State of the binary sensor.""" | ||
| return self.entity_description.value_func(self) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
tests/components/devolo_home_network/test_binary_sensor.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| """Tests for the devolo Home Network sensors.""" | ||
| from unittest.mock import AsyncMock, patch | ||
|
|
||
| from devolo_plc_api.exceptions.device import DeviceUnavailable | ||
| import pytest | ||
|
|
||
| from homeassistant.components.binary_sensor import DOMAIN | ||
| from homeassistant.components.devolo_home_network.const import ( | ||
| CONNECTED_TO_ROUTER, | ||
| LONG_UPDATE_INTERVAL, | ||
| ) | ||
| from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE | ||
| from homeassistant.core import HomeAssistant | ||
| from homeassistant.helpers import entity_registry | ||
| from homeassistant.helpers.entity import EntityCategory | ||
| from homeassistant.util import dt | ||
|
|
||
| from . import configure_integration | ||
| from .const import PLCNET_ATTACHED | ||
|
|
||
| from tests.common import async_fire_time_changed | ||
|
|
||
|
|
||
| @pytest.mark.usefixtures("mock_device", "mock_zeroconf") | ||
| async def test_binary_sensor_setup(hass: HomeAssistant): | ||
| """Test default setup of the binary sensor component.""" | ||
| entry = configure_integration(hass) | ||
| await hass.config_entries.async_setup(entry.entry_id) | ||
| await hass.async_block_till_done() | ||
|
|
||
| assert hass.states.get(f"{DOMAIN}.{CONNECTED_TO_ROUTER}") is None | ||
|
|
||
| await hass.config_entries.async_unload(entry.entry_id) | ||
|
|
||
|
|
||
| @pytest.mark.usefixtures("mock_device", "mock_zeroconf") | ||
| async def test_update_attached_to_router(hass: HomeAssistant): | ||
| """Test state change of a attached_to_router binary sensor device.""" | ||
| state_key = f"{DOMAIN}.{CONNECTED_TO_ROUTER}" | ||
| entry = configure_integration(hass) | ||
|
|
||
| er = entity_registry.async_get(hass) | ||
|
|
||
| await hass.config_entries.async_setup(entry.entry_id) | ||
| await hass.async_block_till_done() | ||
|
|
||
| # Enable entity | ||
| er.async_update_entity(state_key, disabled_by=None) | ||
| await hass.async_block_till_done() | ||
| async_fire_time_changed(hass, dt.utcnow() + LONG_UPDATE_INTERVAL) | ||
| await hass.async_block_till_done() | ||
|
|
||
| state = hass.states.get(state_key) | ||
| assert state is not None | ||
| assert state.state == STATE_OFF | ||
|
|
||
| assert er.async_get(state_key).entity_category == EntityCategory.DIAGNOSTIC | ||
|
|
||
| # Emulate device failure | ||
| with patch( | ||
| "devolo_plc_api.plcnet_api.plcnetapi.PlcNetApi.async_get_network_overview", | ||
| side_effect=DeviceUnavailable, | ||
| ): | ||
| async_fire_time_changed(hass, dt.utcnow() + LONG_UPDATE_INTERVAL) | ||
| await hass.async_block_till_done() | ||
|
|
||
| state = hass.states.get(state_key) | ||
| assert state is not None | ||
| assert state.state == STATE_UNAVAILABLE | ||
|
|
||
| # Emulate state change | ||
| with patch( | ||
| "devolo_plc_api.plcnet_api.plcnetapi.PlcNetApi.async_get_network_overview", | ||
| new=AsyncMock(return_value=PLCNET_ATTACHED), | ||
| ): | ||
| async_fire_time_changed(hass, dt.utcnow() + LONG_UPDATE_INTERVAL) | ||
| await hass.async_block_till_done() | ||
|
|
||
| state = hass.states.get(state_key) | ||
| assert state is not None | ||
| assert state.state == STATE_ON | ||
|
|
||
| await hass.config_entries.async_unload(entry.entry_id) | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually we patch where the library is imported so we don't accidentally patch places we don't want to change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case it would probably be better to adjust the
mock_deviceinsteadThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mock_device is just a collection of patches itself. I'm not seeing, how I could adjust it.