From e5ed363eea1f8521b8d43342332e467fd2639f41 Mon Sep 17 00:00:00 2001 From: tr4nt0r <4445816+tr4nt0r@users.noreply.github.com> Date: Sat, 30 Nov 2024 00:12:11 +0000 Subject: [PATCH 1/7] Add binary platform and tip connected detection to IronOS --- homeassistant/components/iron_os/__init__.py | 7 +- .../components/iron_os/binary_sensor.py | 53 +++++++++++++ .../components/iron_os/coordinator.py | 11 +++ homeassistant/components/iron_os/icons.json | 8 ++ homeassistant/components/iron_os/sensor.py | 34 +++++---- homeassistant/components/iron_os/strings.json | 5 ++ .../iron_os/snapshots/test_binary_sensor.ambr | 48 ++++++++++++ .../components/iron_os/test_binary_sensor.py | 74 +++++++++++++++++++ tests/components/iron_os/test_sensor.py | 35 ++++++++- 9 files changed, 257 insertions(+), 18 deletions(-) create mode 100644 homeassistant/components/iron_os/binary_sensor.py create mode 100644 tests/components/iron_os/snapshots/test_binary_sensor.ambr create mode 100644 tests/components/iron_os/test_binary_sensor.py diff --git a/homeassistant/components/iron_os/__init__.py b/homeassistant/components/iron_os/__init__.py index 35b426d11abed..225bf0ff5820d 100644 --- a/homeassistant/components/iron_os/__init__.py +++ b/homeassistant/components/iron_os/__init__.py @@ -26,7 +26,12 @@ 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) diff --git a/homeassistant/components/iron_os/binary_sensor.py b/homeassistant/components/iron_os/binary_sensor.py new file mode 100644 index 0000000000000..4ef6ed7c02fd9 --- /dev/null +++ b/homeassistant/components/iron_os/binary_sensor.py @@ -0,0 +1,53 @@ +"""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 + + +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 + + async_add_entities([IronOSBinarySensorEntity(coordinator)]) + + +class IronOSBinarySensorEntity(IronOSBaseEntity, BinarySensorEntity): + """Representation of a IronOS binary sensor entity.""" + + entity_description = BinarySensorEntityDescription( + key=PinecilBinarySensor.TIP_CONNECTED, + translation_key=PinecilBinarySensor.TIP_CONNECTED, + device_class=BinarySensorDeviceClass.CONNECTIVITY, + ) + + def __init__(self, coordinator: IronOSLiveDataCoordinator) -> None: + """Initialize the entity.""" + super().__init__(coordinator, self.entity_description) + + @property + def is_on(self) -> bool | None: + """Return true if the binary sensor is on.""" + return self.coordinator.has_tip diff --git a/homeassistant/components/iron_os/coordinator.py b/homeassistant/components/iron_os/coordinator.py index cfd40d66ac781..37df9c6870266 100644 --- a/homeassistant/components/iron_os/coordinator.py +++ b/homeassistant/components/iron_os/coordinator.py @@ -92,6 +92,17 @@ async def _async_update_data(self) -> LiveDataResponse: except CommunicationError as e: raise UpdateFailed("Cannot connect to device") from e + @property + def has_tip(self) -> bool: + """Return True if the tip is connected.""" + if ( + self.data.max_tip_temp_ability is not None + and self.data.live_temp is not None + ): + threshold = self.data.max_tip_temp_ability - 5 + return self.data.live_temp <= threshold + return False + class IronOSFirmwareUpdateCoordinator(DataUpdateCoordinator[GitHubReleaseModel]): """IronOS coordinator for retrieving update information from github.""" diff --git a/homeassistant/components/iron_os/icons.json b/homeassistant/components/iron_os/icons.json index 24d2745768909..eadcc17bb37e6 100644 --- a/homeassistant/components/iron_os/icons.json +++ b/homeassistant/components/iron_os/icons.json @@ -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" diff --git a/homeassistant/components/iron_os/sensor.py b/homeassistant/components/iron_os/sensor.py index 05d56db26d35e..1ccc942a1822b 100644 --- a/homeassistant/components/iron_os/sensor.py +++ b/homeassistant/components/iron_os/sensor.py @@ -54,7 +54,7 @@ class PinecilSensor(StrEnum): class IronOSSensorEntityDescription(SensorEntityDescription): """IronOS sensor entity descriptions.""" - value_fn: Callable[[LiveDataResponse], StateType] + value_fn: Callable[[LiveDataResponse, bool], StateType] PINECIL_SENSOR_DESCRIPTIONS: tuple[IronOSSensorEntityDescription, ...] = ( @@ -64,7 +64,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data: data.live_temp, + value_fn=lambda data, has_tip: data.live_temp if has_tip else None, ), IronOSSensorEntityDescription( key=PinecilSensor.DC_VOLTAGE, @@ -72,7 +72,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfElectricPotential.VOLT, device_class=SensorDeviceClass.VOLTAGE, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data: data.dc_voltage, + value_fn=lambda data, _: data.dc_voltage, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -81,7 +81,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data: data.handle_temp, + value_fn=lambda data, _: data.handle_temp, ), IronOSSensorEntityDescription( key=PinecilSensor.PWMLEVEL, @@ -90,7 +90,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): suggested_display_precision=0, device_class=SensorDeviceClass.POWER_FACTOR, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data: data.pwm_level, + value_fn=lambda data, _: data.pwm_level, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -98,14 +98,16 @@ class IronOSSensorEntityDescription(SensorEntityDescription): translation_key=PinecilSensor.POWER_SRC, device_class=SensorDeviceClass.ENUM, options=[item.name.lower() for item in PowerSource], - value_fn=lambda data: data.power_src.name.lower() if data.power_src else None, + value_fn=lambda data, _: data.power_src.name.lower() + if data.power_src + else None, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( key=PinecilSensor.TIP_RESISTANCE, translation_key=PinecilSensor.TIP_RESISTANCE, native_unit_of_measurement=OHM, - value_fn=lambda data: data.tip_resistance, + value_fn=lambda data, has_tip: data.tip_resistance if has_tip else None, entity_category=EntityCategory.DIAGNOSTIC, state_class=SensorStateClass.MEASUREMENT, ), @@ -115,7 +117,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfTime.SECONDS, device_class=SensorDeviceClass.DURATION, state_class=SensorStateClass.TOTAL_INCREASING, - value_fn=lambda data: data.uptime, + value_fn=lambda data, _: data.uptime, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -124,7 +126,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfTime.SECONDS, device_class=SensorDeviceClass.DURATION, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data: data.movement_time, + value_fn=lambda data, _: data.movement_time, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -132,7 +134,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): translation_key=PinecilSensor.MAX_TIP_TEMP_ABILITY, native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, - value_fn=lambda data: data.max_tip_temp_ability, + value_fn=lambda data, has_tip: data.max_tip_temp_ability if has_tip else None, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -142,7 +144,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): device_class=SensorDeviceClass.VOLTAGE, state_class=SensorStateClass.MEASUREMENT, suggested_display_precision=0, - value_fn=lambda data: data.tip_voltage, + value_fn=lambda data, has_tip: data.tip_voltage if has_tip else None, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -150,7 +152,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): translation_key=PinecilSensor.HALL_SENSOR, state_class=SensorStateClass.MEASUREMENT, entity_registry_enabled_default=False, - value_fn=lambda data: data.hall_sensor, + value_fn=lambda data, _: data.hall_sensor, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -159,7 +161,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): device_class=SensorDeviceClass.ENUM, options=[item.name.lower() for item in OperatingMode], value_fn=( - lambda data: data.operating_mode.name.lower() + lambda data, _: data.operating_mode.name.lower() if data.operating_mode else None ), @@ -170,7 +172,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfPower.WATT, device_class=SensorDeviceClass.POWER, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data: data.estimated_power, + value_fn=lambda data, _: data.estimated_power, ), ) @@ -197,4 +199,6 @@ class IronOSSensorEntity(IronOSBaseEntity, SensorEntity): @property def native_value(self) -> StateType: """Return sensor state.""" - return self.entity_description.value_fn(self.coordinator.data) + return self.entity_description.value_fn( + self.coordinator.data, self.coordinator.has_tip + ) diff --git a/homeassistant/components/iron_os/strings.json b/homeassistant/components/iron_os/strings.json index c474b70467731..13528104f8c47 100644 --- a/homeassistant/components/iron_os/strings.json +++ b/homeassistant/components/iron_os/strings.json @@ -20,6 +20,11 @@ } }, "entity": { + "binary_sensor": { + "tip_connected": { + "name": "Soldering tip" + } + }, "number": { "setpoint_temperature": { "name": "Setpoint temperature" diff --git a/tests/components/iron_os/snapshots/test_binary_sensor.ambr b/tests/components/iron_os/snapshots/test_binary_sensor.ambr new file mode 100644 index 0000000000000..bcad4ec8c3092 --- /dev/null +++ b/tests/components/iron_os/snapshots/test_binary_sensor.ambr @@ -0,0 +1,48 @@ +# serializer version: 1 +# name: test_sensors[binary_sensor.pinecil_soldering_tip-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + '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': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Soldering tip', + 'platform': 'iron_os', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'c0:ff:ee:c0:ff:ee_tip_connected', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[binary_sensor.pinecil_soldering_tip-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'connectivity', + 'friendly_name': 'Pinecil Soldering tip', + }), + 'context': , + 'entity_id': 'binary_sensor.pinecil_soldering_tip', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- diff --git a/tests/components/iron_os/test_binary_sensor.py b/tests/components/iron_os/test_binary_sensor.py new file mode 100644 index 0000000000000..f2e1451ee761b --- /dev/null +++ b/tests/components/iron_os/test_binary_sensor.py @@ -0,0 +1,74 @@ +"""Tests for the Pinecil Binary Sensors.""" + +from collections.abc import AsyncGenerator +from datetime import timedelta +from unittest.mock import AsyncMock, patch + +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 +import homeassistant.util.dt as dt_util + +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_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, +) -> 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, + ) + async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=5)) + + assert hass.states.get("binary_sensor.pinecil_soldering_tip").state == STATE_OFF diff --git a/tests/components/iron_os/test_sensor.py b/tests/components/iron_os/test_sensor.py index 2f79487a7fd77..fec111c5799f8 100644 --- a/tests/components/iron_os/test_sensor.py +++ b/tests/components/iron_os/test_sensor.py @@ -4,13 +4,13 @@ from unittest.mock import AsyncMock, MagicMock, patch from freezegun.api import FrozenDateTimeFactory -from pynecil import CommunicationError +from pynecil import CommunicationError, LiveDataResponse import pytest from syrupy.assertion import SnapshotAssertion from homeassistant.components.iron_os.coordinator import SCAN_INTERVAL from homeassistant.config_entries import ConfigEntryState -from homeassistant.const import STATE_UNAVAILABLE, Platform +from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er @@ -71,3 +71,34 @@ async def test_sensors_unavailable( ) for entity_entry in entity_entries: assert hass.states.get(entity_entry.entity_id).state == STATE_UNAVAILABLE + + +@pytest.mark.usefixtures( + "entity_registry_enabled_by_default", "ble_device", "mock_pynecil" +) +async def test_tip_detection( + hass: HomeAssistant, + config_entry: MockConfigEntry, + mock_pynecil: AsyncMock, + ble_device: MagicMock, +) -> None: + """Test sensor state is unknown when tip is disconnected.""" + + mock_pynecil.get_live_data.return_value = LiveDataResponse( + live_temp=479, + max_tip_temp_ability=460, + ) + + 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 + entities = { + "sensor.pinecil_tip_temperature", + "sensor.pinecil_max_tip_temperature", + "sensor.pinecil_raw_tip_voltage", + "sensor.pinecil_tip_resistance", + } + for entity_id in entities: + assert hass.states.get(entity_id).state == STATE_UNKNOWN From 4f3d8a5e1f43698ec3abfbd618dd55c3825b96a6 Mon Sep 17 00:00:00 2001 From: tr4nt0r <4445816+tr4nt0r@users.noreply.github.com> Date: Sat, 30 Nov 2024 20:24:50 +0000 Subject: [PATCH 2/7] suggested changes --- homeassistant/components/iron_os/binary_sensor.py | 15 +++++---------- .../iron_os/snapshots/test_binary_sensor.ambr | 4 ++-- tests/components/iron_os/test_binary_sensor.py | 2 +- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/iron_os/binary_sensor.py b/homeassistant/components/iron_os/binary_sensor.py index 4ef6ed7c02fd9..19e21895881f5 100644 --- a/homeassistant/components/iron_os/binary_sensor.py +++ b/homeassistant/components/iron_os/binary_sensor.py @@ -13,7 +13,6 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import IronOSConfigEntry -from .coordinator import IronOSLiveDataCoordinator from .entity import IronOSBaseEntity @@ -31,21 +30,17 @@ async def async_setup_entry( """Set up binary sensors from a config entry.""" coordinator = entry.runtime_data - async_add_entities([IronOSBinarySensorEntity(coordinator)]) - - -class IronOSBinarySensorEntity(IronOSBaseEntity, BinarySensorEntity): - """Representation of a IronOS binary sensor entity.""" - entity_description = BinarySensorEntityDescription( key=PinecilBinarySensor.TIP_CONNECTED, translation_key=PinecilBinarySensor.TIP_CONNECTED, device_class=BinarySensorDeviceClass.CONNECTIVITY, ) - def __init__(self, coordinator: IronOSLiveDataCoordinator) -> None: - """Initialize the entity.""" - super().__init__(coordinator, self.entity_description) + async_add_entities([IronOSBinarySensorEntity(coordinator, entity_description)]) + + +class IronOSBinarySensorEntity(IronOSBaseEntity, BinarySensorEntity): + """Representation of a IronOS binary sensor entity.""" @property def is_on(self) -> bool | None: diff --git a/tests/components/iron_os/snapshots/test_binary_sensor.ambr b/tests/components/iron_os/snapshots/test_binary_sensor.ambr index bcad4ec8c3092..17b49c1d687ee 100644 --- a/tests/components/iron_os/snapshots/test_binary_sensor.ambr +++ b/tests/components/iron_os/snapshots/test_binary_sensor.ambr @@ -1,5 +1,5 @@ # serializer version: 1 -# name: test_sensors[binary_sensor.pinecil_soldering_tip-entry] +# name: test_binary_sensors[binary_sensor.pinecil_soldering_tip-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -32,7 +32,7 @@ 'unit_of_measurement': None, }) # --- -# name: test_sensors[binary_sensor.pinecil_soldering_tip-state] +# name: test_binary_sensors[binary_sensor.pinecil_soldering_tip-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'connectivity', diff --git a/tests/components/iron_os/test_binary_sensor.py b/tests/components/iron_os/test_binary_sensor.py index f2e1451ee761b..37776f1cbd765 100644 --- a/tests/components/iron_os/test_binary_sensor.py +++ b/tests/components/iron_os/test_binary_sensor.py @@ -31,7 +31,7 @@ async def binary_sensor_only() -> AsyncGenerator[None]: @pytest.mark.usefixtures( "entity_registry_enabled_by_default", "mock_pynecil", "ble_device" ) -async def test_sensors( +async def test_binary_sensors( hass: HomeAssistant, config_entry: MockConfigEntry, snapshot: SnapshotAssertion, From bc33096f3df0e38f95e91fb8ee00b7d0b35716df Mon Sep 17 00:00:00 2001 From: tr4nt0r <4445816+tr4nt0r@users.noreply.github.com> Date: Mon, 2 Dec 2024 12:01:08 +0000 Subject: [PATCH 3/7] fix --- homeassistant/components/iron_os/binary_sensor.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/iron_os/binary_sensor.py b/homeassistant/components/iron_os/binary_sensor.py index 19e21895881f5..5ef6dc82c4fd6 100644 --- a/homeassistant/components/iron_os/binary_sensor.py +++ b/homeassistant/components/iron_os/binary_sensor.py @@ -13,6 +13,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import IronOSConfigEntry +from .coordinator import IronOSLiveDataCoordinator from .entity import IronOSBaseEntity @@ -28,7 +29,7 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up binary sensors from a config entry.""" - coordinator = entry.runtime_data + coordinator = entry.runtime_data.live_data entity_description = BinarySensorEntityDescription( key=PinecilBinarySensor.TIP_CONNECTED, @@ -42,6 +43,8 @@ async def async_setup_entry( 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.""" From 9ccc420633f6d34df5fab03e874aa1144a0c41a8 Mon Sep 17 00:00:00 2001 From: tr4nt0r <4445816+tr4nt0r@users.noreply.github.com> Date: Mon, 2 Dec 2024 12:25:09 +0000 Subject: [PATCH 4/7] fix mypy --- homeassistant/components/iron_os/sensor.py | 36 ++++++++++------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/iron_os/sensor.py b/homeassistant/components/iron_os/sensor.py index 1ccc942a1822b..46618961f6003 100644 --- a/homeassistant/components/iron_os/sensor.py +++ b/homeassistant/components/iron_os/sensor.py @@ -28,6 +28,7 @@ from . import IronOSConfigEntry from .const import OHM +from .coordinator import IronOSLiveDataCoordinator from .entity import IronOSBaseEntity @@ -54,7 +55,7 @@ class PinecilSensor(StrEnum): class IronOSSensorEntityDescription(SensorEntityDescription): """IronOS sensor entity descriptions.""" - value_fn: Callable[[LiveDataResponse, bool], StateType] + value_fn: Callable[[LiveDataResponse], StateType] PINECIL_SENSOR_DESCRIPTIONS: tuple[IronOSSensorEntityDescription, ...] = ( @@ -64,7 +65,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data, has_tip: data.live_temp if has_tip else None, + value_fn=lambda data: data.live_temp, ), IronOSSensorEntityDescription( key=PinecilSensor.DC_VOLTAGE, @@ -72,7 +73,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfElectricPotential.VOLT, device_class=SensorDeviceClass.VOLTAGE, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data, _: data.dc_voltage, + value_fn=lambda data: data.dc_voltage, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -81,7 +82,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data, _: data.handle_temp, + value_fn=lambda data: data.handle_temp, ), IronOSSensorEntityDescription( key=PinecilSensor.PWMLEVEL, @@ -90,7 +91,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): suggested_display_precision=0, device_class=SensorDeviceClass.POWER_FACTOR, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data, _: data.pwm_level, + value_fn=lambda data: data.pwm_level, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -98,16 +99,14 @@ class IronOSSensorEntityDescription(SensorEntityDescription): translation_key=PinecilSensor.POWER_SRC, device_class=SensorDeviceClass.ENUM, options=[item.name.lower() for item in PowerSource], - value_fn=lambda data, _: data.power_src.name.lower() - if data.power_src - else None, + value_fn=lambda data: data.power_src.name.lower() if data.power_src else None, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( key=PinecilSensor.TIP_RESISTANCE, translation_key=PinecilSensor.TIP_RESISTANCE, native_unit_of_measurement=OHM, - value_fn=lambda data, has_tip: data.tip_resistance if has_tip else None, + value_fn=lambda data: data.tip_resistance, entity_category=EntityCategory.DIAGNOSTIC, state_class=SensorStateClass.MEASUREMENT, ), @@ -117,7 +116,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfTime.SECONDS, device_class=SensorDeviceClass.DURATION, state_class=SensorStateClass.TOTAL_INCREASING, - value_fn=lambda data, _: data.uptime, + value_fn=lambda data: data.uptime, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -126,7 +125,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfTime.SECONDS, device_class=SensorDeviceClass.DURATION, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data, _: data.movement_time, + value_fn=lambda data: data.movement_time, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -134,7 +133,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): translation_key=PinecilSensor.MAX_TIP_TEMP_ABILITY, native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, - value_fn=lambda data, has_tip: data.max_tip_temp_ability if has_tip else None, + value_fn=lambda data: data.max_tip_temp_ability, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -144,7 +143,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): device_class=SensorDeviceClass.VOLTAGE, state_class=SensorStateClass.MEASUREMENT, suggested_display_precision=0, - value_fn=lambda data, has_tip: data.tip_voltage if has_tip else None, + value_fn=lambda data: data.tip_voltage, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -152,7 +151,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): translation_key=PinecilSensor.HALL_SENSOR, state_class=SensorStateClass.MEASUREMENT, entity_registry_enabled_default=False, - value_fn=lambda data, _: data.hall_sensor, + value_fn=lambda data: data.hall_sensor, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -161,7 +160,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): device_class=SensorDeviceClass.ENUM, options=[item.name.lower() for item in OperatingMode], value_fn=( - lambda data, _: data.operating_mode.name.lower() + lambda data: data.operating_mode.name.lower() if data.operating_mode else None ), @@ -172,7 +171,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfPower.WATT, device_class=SensorDeviceClass.POWER, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data, _: data.estimated_power, + value_fn=lambda data: data.estimated_power, ), ) @@ -195,10 +194,9 @@ class IronOSSensorEntity(IronOSBaseEntity, SensorEntity): """Representation of a IronOS sensor entity.""" entity_description: IronOSSensorEntityDescription + coordinator: IronOSLiveDataCoordinator @property def native_value(self) -> StateType: """Return sensor state.""" - return self.entity_description.value_fn( - self.coordinator.data, self.coordinator.has_tip - ) + return self.entity_description.value_fn(self.coordinator.data) From 243722f9ec0d8da36e17d63ce256f3ab686d5613 Mon Sep 17 00:00:00 2001 From: tr4nt0r <4445816+tr4nt0r@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:34:02 +0000 Subject: [PATCH 5/7] revert accidental overwriting --- homeassistant/components/iron_os/sensor.py | 34 ++++++++++++---------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/iron_os/sensor.py b/homeassistant/components/iron_os/sensor.py index 46618961f6003..78a96b81b8ff0 100644 --- a/homeassistant/components/iron_os/sensor.py +++ b/homeassistant/components/iron_os/sensor.py @@ -55,7 +55,7 @@ class PinecilSensor(StrEnum): class IronOSSensorEntityDescription(SensorEntityDescription): """IronOS sensor entity descriptions.""" - value_fn: Callable[[LiveDataResponse], StateType] + value_fn: Callable[[LiveDataResponse, bool], StateType] PINECIL_SENSOR_DESCRIPTIONS: tuple[IronOSSensorEntityDescription, ...] = ( @@ -65,7 +65,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data: data.live_temp, + value_fn=lambda data, has_tip: data.live_temp if has_tip else None, ), IronOSSensorEntityDescription( key=PinecilSensor.DC_VOLTAGE, @@ -73,7 +73,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfElectricPotential.VOLT, device_class=SensorDeviceClass.VOLTAGE, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data: data.dc_voltage, + value_fn=lambda data, _: data.dc_voltage, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -82,7 +82,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data: data.handle_temp, + value_fn=lambda data, _: data.handle_temp, ), IronOSSensorEntityDescription( key=PinecilSensor.PWMLEVEL, @@ -91,7 +91,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): suggested_display_precision=0, device_class=SensorDeviceClass.POWER_FACTOR, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data: data.pwm_level, + value_fn=lambda data, _: data.pwm_level, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -99,14 +99,16 @@ class IronOSSensorEntityDescription(SensorEntityDescription): translation_key=PinecilSensor.POWER_SRC, device_class=SensorDeviceClass.ENUM, options=[item.name.lower() for item in PowerSource], - value_fn=lambda data: data.power_src.name.lower() if data.power_src else None, + value_fn=( + lambda data, _: data.power_src.name.lower() if data.power_src else None + ), entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( key=PinecilSensor.TIP_RESISTANCE, translation_key=PinecilSensor.TIP_RESISTANCE, native_unit_of_measurement=OHM, - value_fn=lambda data: data.tip_resistance, + value_fn=lambda data, has_tip: data.tip_resistance if has_tip else None, entity_category=EntityCategory.DIAGNOSTIC, state_class=SensorStateClass.MEASUREMENT, ), @@ -116,7 +118,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfTime.SECONDS, device_class=SensorDeviceClass.DURATION, state_class=SensorStateClass.TOTAL_INCREASING, - value_fn=lambda data: data.uptime, + value_fn=lambda data, _: data.uptime, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -125,7 +127,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfTime.SECONDS, device_class=SensorDeviceClass.DURATION, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data: data.movement_time, + value_fn=lambda data, _: data.movement_time, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -133,7 +135,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): translation_key=PinecilSensor.MAX_TIP_TEMP_ABILITY, native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, - value_fn=lambda data: data.max_tip_temp_ability, + value_fn=lambda data, has_tip: data.max_tip_temp_ability if has_tip else None, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -143,7 +145,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): device_class=SensorDeviceClass.VOLTAGE, state_class=SensorStateClass.MEASUREMENT, suggested_display_precision=0, - value_fn=lambda data: data.tip_voltage, + value_fn=lambda data, has_tip: data.tip_voltage if has_tip else None, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -151,7 +153,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): translation_key=PinecilSensor.HALL_SENSOR, state_class=SensorStateClass.MEASUREMENT, entity_registry_enabled_default=False, - value_fn=lambda data: data.hall_sensor, + value_fn=lambda data, _: data.hall_sensor, entity_category=EntityCategory.DIAGNOSTIC, ), IronOSSensorEntityDescription( @@ -160,7 +162,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): device_class=SensorDeviceClass.ENUM, options=[item.name.lower() for item in OperatingMode], value_fn=( - lambda data: data.operating_mode.name.lower() + lambda data, _: data.operating_mode.name.lower() if data.operating_mode else None ), @@ -171,7 +173,7 @@ class IronOSSensorEntityDescription(SensorEntityDescription): native_unit_of_measurement=UnitOfPower.WATT, device_class=SensorDeviceClass.POWER, state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda data: data.estimated_power, + value_fn=lambda data, _: data.estimated_power, ), ) @@ -199,4 +201,6 @@ class IronOSSensorEntity(IronOSBaseEntity, SensorEntity): @property def native_value(self) -> StateType: """Return sensor state.""" - return self.entity_description.value_fn(self.coordinator.data) + return self.entity_description.value_fn( + self.coordinator.data, self.coordinator.has_tip + ) From 1585dfcd8c3918df602e18d8ede25971f8aa2377 Mon Sep 17 00:00:00 2001 From: tr4nt0r <4445816+tr4nt0r@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:24:59 +0000 Subject: [PATCH 6/7] Remove binary sensor --- homeassistant/components/iron_os/__init__.py | 7 +- .../components/iron_os/binary_sensor.py | 51 ------------- homeassistant/components/iron_os/icons.json | 8 -- homeassistant/components/iron_os/strings.json | 5 -- .../components/iron_os/test_binary_sensor.py | 74 ------------------- 5 files changed, 1 insertion(+), 144 deletions(-) delete mode 100644 homeassistant/components/iron_os/binary_sensor.py delete mode 100644 tests/components/iron_os/test_binary_sensor.py diff --git a/homeassistant/components/iron_os/__init__.py b/homeassistant/components/iron_os/__init__.py index 225bf0ff5820d..35b426d11abed 100644 --- a/homeassistant/components/iron_os/__init__.py +++ b/homeassistant/components/iron_os/__init__.py @@ -26,12 +26,7 @@ IronOSSettingsCoordinator, ) -PLATFORMS: list[Platform] = [ - Platform.BINARY_SENSOR, - Platform.NUMBER, - Platform.SENSOR, - Platform.UPDATE, -] +PLATFORMS: list[Platform] = [Platform.NUMBER, Platform.SENSOR, Platform.UPDATE] CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN) diff --git a/homeassistant/components/iron_os/binary_sensor.py b/homeassistant/components/iron_os/binary_sensor.py deleted file mode 100644 index 5ef6dc82c4fd6..0000000000000 --- a/homeassistant/components/iron_os/binary_sensor.py +++ /dev/null @@ -1,51 +0,0 @@ -"""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 - - -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 diff --git a/homeassistant/components/iron_os/icons.json b/homeassistant/components/iron_os/icons.json index eadcc17bb37e6..24d2745768909 100644 --- a/homeassistant/components/iron_os/icons.json +++ b/homeassistant/components/iron_os/icons.json @@ -1,13 +1,5 @@ { "entity": { - "binary_sensor": { - "tip_connected": { - "default": "mdi:pencil-outline", - "state": { - "off": "mdi:pencil-off-outline" - } - } - }, "number": { "setpoint_temperature": { "default": "mdi:thermometer" diff --git a/homeassistant/components/iron_os/strings.json b/homeassistant/components/iron_os/strings.json index 13528104f8c47..c474b70467731 100644 --- a/homeassistant/components/iron_os/strings.json +++ b/homeassistant/components/iron_os/strings.json @@ -20,11 +20,6 @@ } }, "entity": { - "binary_sensor": { - "tip_connected": { - "name": "Soldering tip" - } - }, "number": { "setpoint_temperature": { "name": "Setpoint temperature" diff --git a/tests/components/iron_os/test_binary_sensor.py b/tests/components/iron_os/test_binary_sensor.py deleted file mode 100644 index 37776f1cbd765..0000000000000 --- a/tests/components/iron_os/test_binary_sensor.py +++ /dev/null @@ -1,74 +0,0 @@ -"""Tests for the Pinecil Binary Sensors.""" - -from collections.abc import AsyncGenerator -from datetime import timedelta -from unittest.mock import AsyncMock, patch - -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 -import homeassistant.util.dt as dt_util - -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, -) -> 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, - ) - async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=5)) - - assert hass.states.get("binary_sensor.pinecil_soldering_tip").state == STATE_OFF From 60f6f414081b3dea9c4a673ff0906f6e54d0ce67 Mon Sep 17 00:00:00 2001 From: tr4nt0r <4445816+tr4nt0r@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:48:46 +0000 Subject: [PATCH 7/7] snapshot --- .../iron_os/snapshots/test_binary_sensor.ambr | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 tests/components/iron_os/snapshots/test_binary_sensor.ambr diff --git a/tests/components/iron_os/snapshots/test_binary_sensor.ambr b/tests/components/iron_os/snapshots/test_binary_sensor.ambr deleted file mode 100644 index 17b49c1d687ee..0000000000000 --- a/tests/components/iron_os/snapshots/test_binary_sensor.ambr +++ /dev/null @@ -1,48 +0,0 @@ -# serializer version: 1 -# name: test_binary_sensors[binary_sensor.pinecil_soldering_tip-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'device_class': None, - 'device_id': , - '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': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Soldering tip', - 'platform': 'iron_os', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': , - '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': , - 'entity_id': 'binary_sensor.pinecil_soldering_tip', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'on', - }) -# ---