Add binary platform to IronOS (#132691)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
pull/132715/head
Manu 2024-12-09 13:37:38 +01:00 committed by GitHub
parent 4bb3d6123d
commit f4e48c31bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 198 additions and 1 deletions

View File

@ -26,7 +26,12 @@ from .coordinator import (
IronOSSettingsCoordinator,
)
PLATFORMS: list[Platform] = [Platform.NUMBER, Platform.SENSOR, Platform.UPDATE]
PLATFORMS: list[Platform] = [
Platform.BINARY_SENSOR,
Platform.NUMBER,
Platform.SENSOR,
Platform.UPDATE,
]
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)

View File

@ -0,0 +1,54 @@
"""Binary sensor platform for IronOS integration."""
from __future__ import annotations
from enum import StrEnum
from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
BinarySensorEntity,
BinarySensorEntityDescription,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import IronOSConfigEntry
from .coordinator import IronOSLiveDataCoordinator
from .entity import IronOSBaseEntity
# Coordinator is used to centralize the data updates
PARALLEL_UPDATES = 0
class PinecilBinarySensor(StrEnum):
"""Pinecil Binary Sensors."""
TIP_CONNECTED = "tip_connected"
async def async_setup_entry(
hass: HomeAssistant,
entry: IronOSConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up binary sensors from a config entry."""
coordinator = entry.runtime_data.live_data
entity_description = BinarySensorEntityDescription(
key=PinecilBinarySensor.TIP_CONNECTED,
translation_key=PinecilBinarySensor.TIP_CONNECTED,
device_class=BinarySensorDeviceClass.CONNECTIVITY,
)
async_add_entities([IronOSBinarySensorEntity(coordinator, entity_description)])
class IronOSBinarySensorEntity(IronOSBaseEntity, BinarySensorEntity):
"""Representation of a IronOS binary sensor entity."""
coordinator: IronOSLiveDataCoordinator
@property
def is_on(self) -> bool | None:
"""Return true if the binary sensor is on."""
return self.coordinator.has_tip

View File

@ -1,5 +1,13 @@
{
"entity": {
"binary_sensor": {
"tip_connected": {
"default": "mdi:pencil-outline",
"state": {
"off": "mdi:pencil-off-outline"
}
}
},
"number": {
"setpoint_temperature": {
"default": "mdi:thermometer"

View File

@ -20,6 +20,11 @@
}
},
"entity": {
"binary_sensor": {
"tip_connected": {
"name": "Soldering tip"
}
},
"number": {
"setpoint_temperature": {
"name": "Setpoint temperature"

View File

@ -0,0 +1,48 @@
# serializer version: 1
# name: test_binary_sensors[binary_sensor.pinecil_soldering_tip-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'binary_sensor',
'entity_category': None,
'entity_id': 'binary_sensor.pinecil_soldering_tip',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <BinarySensorDeviceClass.CONNECTIVITY: 'connectivity'>,
'original_icon': None,
'original_name': 'Soldering tip',
'platform': 'iron_os',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': <PinecilBinarySensor.TIP_CONNECTED: 'tip_connected'>,
'unique_id': 'c0:ff:ee:c0:ff:ee_tip_connected',
'unit_of_measurement': None,
})
# ---
# name: test_binary_sensors[binary_sensor.pinecil_soldering_tip-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'connectivity',
'friendly_name': 'Pinecil Soldering tip',
}),
'context': <ANY>,
'entity_id': 'binary_sensor.pinecil_soldering_tip',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---

View File

@ -0,0 +1,77 @@
"""Tests for the Pinecil Binary Sensors."""
from collections.abc import AsyncGenerator
from datetime import timedelta
from unittest.mock import AsyncMock, patch
from freezegun.api import FrozenDateTimeFactory
from pynecil import LiveDataResponse
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.binary_sensor import STATE_OFF, STATE_ON
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
@pytest.fixture(autouse=True)
async def binary_sensor_only() -> AsyncGenerator[None]:
"""Enable only the binary sensor platform."""
with patch(
"homeassistant.components.iron_os.PLATFORMS",
[Platform.BINARY_SENSOR],
):
yield
@pytest.mark.usefixtures(
"entity_registry_enabled_by_default", "mock_pynecil", "ble_device"
)
async def test_binary_sensors(
hass: HomeAssistant,
config_entry: MockConfigEntry,
snapshot: SnapshotAssertion,
entity_registry: er.EntityRegistry,
) -> None:
"""Test the Pinecil binary sensor platform."""
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
@pytest.mark.usefixtures(
"entity_registry_enabled_by_default", "ble_device", "mock_pynecil"
)
async def test_tip_on_off(
hass: HomeAssistant,
config_entry: MockConfigEntry,
mock_pynecil: AsyncMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test tip_connected binary sensor on/off states."""
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
assert hass.states.get("binary_sensor.pinecil_soldering_tip").state == STATE_ON
mock_pynecil.get_live_data.return_value = LiveDataResponse(
live_temp=479,
max_tip_temp_ability=460,
)
freezer.tick(timedelta(seconds=5))
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert hass.states.get("binary_sensor.pinecil_soldering_tip").state == STATE_OFF