From 233c04a469b283a66f21e4acec7594377d527442 Mon Sep 17 00:00:00 2001 From: Alex MF Date: Wed, 31 Jul 2024 11:22:07 +0100 Subject: [PATCH] Add number entity for Ecovacs mower cut direction (#122598) --- homeassistant/components/ecovacs/icons.json | 3 + homeassistant/components/ecovacs/number.py | 16 ++- homeassistant/components/ecovacs/strings.json | 3 + .../ecovacs/snapshots/test_number.ambr | 111 ++++++++++++++++++ tests/components/ecovacs/test_init.py | 2 +- tests/components/ecovacs/test_number.py | 28 ++++- 6 files changed, 156 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/ecovacs/icons.json b/homeassistant/components/ecovacs/icons.json index d129273e891..0c7178ced84 100644 --- a/homeassistant/components/ecovacs/icons.json +++ b/homeassistant/components/ecovacs/icons.json @@ -43,6 +43,9 @@ "clean_count": { "default": "mdi:counter" }, + "cut_direction": { + "default": "mdi:angle-acute" + }, "volume": { "default": "mdi:volume-high", "state": { diff --git a/homeassistant/components/ecovacs/number.py b/homeassistant/components/ecovacs/number.py index 3b24091ca34..2b9bdc1a425 100644 --- a/homeassistant/components/ecovacs/number.py +++ b/homeassistant/components/ecovacs/number.py @@ -7,14 +7,14 @@ from dataclasses import dataclass from typing import Generic from deebot_client.capabilities import CapabilitySet -from deebot_client.events import CleanCountEvent, VolumeEvent +from deebot_client.events import CleanCountEvent, CutDirectionEvent, VolumeEvent from homeassistant.components.number import ( NumberEntity, NumberEntityDescription, NumberMode, ) -from homeassistant.const import EntityCategory +from homeassistant.const import DEGREE, EntityCategory from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -53,6 +53,18 @@ ENTITY_DESCRIPTIONS: tuple[EcovacsNumberEntityDescription, ...] = ( native_max_value=10, native_step=1.0, ), + EcovacsNumberEntityDescription[CutDirectionEvent]( + capability_fn=lambda caps: caps.settings.cut_direction, + value_fn=lambda e: e.angle, + key="cut_direction", + translation_key="cut_direction", + entity_registry_enabled_default=False, + entity_category=EntityCategory.CONFIG, + native_min_value=0, + native_max_value=180, + native_step=1.0, + native_unit_of_measurement=DEGREE, + ), EcovacsNumberEntityDescription[CleanCountEvent]( capability_fn=lambda caps: caps.clean.count, value_fn=lambda e: e.count, diff --git a/homeassistant/components/ecovacs/strings.json b/homeassistant/components/ecovacs/strings.json index d501c333a03..d2e385c79c7 100644 --- a/homeassistant/components/ecovacs/strings.json +++ b/homeassistant/components/ecovacs/strings.json @@ -91,6 +91,9 @@ "clean_count": { "name": "Clean count" }, + "cut_direction": { + "name": "Cut direction" + }, "volume": { "name": "Volume" } diff --git a/tests/components/ecovacs/snapshots/test_number.ambr b/tests/components/ecovacs/snapshots/test_number.ambr index da8406491b4..c80132784e1 100644 --- a/tests/components/ecovacs/snapshots/test_number.ambr +++ b/tests/components/ecovacs/snapshots/test_number.ambr @@ -1,4 +1,115 @@ # serializer version: 1 +# name: test_number_entities[5xu9h3][number.goat_g1_cut_direction:entity-registry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max': 180, + 'min': 0, + 'mode': , + 'step': 1.0, + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'number', + 'entity_category': , + 'entity_id': 'number.goat_g1_cut_direction', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Cut direction', + 'platform': 'ecovacs', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'cut_direction', + 'unique_id': '8516fbb1-17f1-4194-0000000_cut_direction', + 'unit_of_measurement': '°', + }) +# --- +# name: test_number_entities[5xu9h3][number.goat_g1_cut_direction:state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Goat G1 Cut direction', + 'max': 180, + 'min': 0, + 'mode': , + 'step': 1.0, + 'unit_of_measurement': '°', + }), + 'context': , + 'entity_id': 'number.goat_g1_cut_direction', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '45', + }) +# --- +# name: test_number_entities[5xu9h3][number.goat_g1_volume:entity-registry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max': 11, + 'min': 0, + 'mode': , + 'step': 1.0, + }), + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'number', + 'entity_category': , + 'entity_id': 'number.goat_g1_volume', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Volume', + 'platform': 'ecovacs', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'volume', + 'unique_id': '8516fbb1-17f1-4194-0000000_volume', + 'unit_of_measurement': None, + }) +# --- +# name: test_number_entities[5xu9h3][number.goat_g1_volume:state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Goat G1 Volume', + 'max': 11, + 'min': 0, + 'mode': , + 'step': 1.0, + }), + 'context': , + 'entity_id': 'number.goat_g1_volume', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '3', + }) +# --- # name: test_number_entities[yna5x1][number.ozmo_950_volume:entity-registry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/ecovacs/test_init.py b/tests/components/ecovacs/test_init.py index c0c475217c1..ac4d5661a83 100644 --- a/tests/components/ecovacs/test_init.py +++ b/tests/components/ecovacs/test_init.py @@ -136,7 +136,7 @@ async def test_devices_in_dr( ("device_fixture", "entities"), [ ("yna5x1", 26), - ("5xu9h3", 24), + ("5xu9h3", 25), ("123", 1), ], ) diff --git a/tests/components/ecovacs/test_number.py b/tests/components/ecovacs/test_number.py index d444d6510a8..a735863d40a 100644 --- a/tests/components/ecovacs/test_number.py +++ b/tests/components/ecovacs/test_number.py @@ -3,8 +3,8 @@ from dataclasses import dataclass from deebot_client.command import Command -from deebot_client.commands.json import SetVolume -from deebot_client.events import Event, VolumeEvent +from deebot_client.commands.json import SetCutDirection, SetVolume +from deebot_client.events import CutDirectionEvent, Event, VolumeEvent import pytest from syrupy import SnapshotAssertion @@ -53,8 +53,23 @@ class NumberTestCase: ), ], ), + ( + "5xu9h3", + [ + NumberTestCase( + "number.goat_g1_volume", VolumeEvent(3, 11), "3", 7, SetVolume(7) + ), + NumberTestCase( + "number.goat_g1_cut_direction", + CutDirectionEvent(45), + "45", + 97, + SetCutDirection(97), + ), + ], + ), ], - ids=["yna5x1"], + ids=["yna5x1", "5xu9h3"], ) async def test_number_entities( hass: HomeAssistant, @@ -107,8 +122,12 @@ async def test_number_entities( "yna5x1", ["number.ozmo_950_volume"], ), + ( + "5xu9h3", + ["number.goat_g1_cut_direction", "number.goat_g1_volume"], + ), ], - ids=["yna5x1"], + ids=["yna5x1", "5xu9h3"], ) async def test_disabled_by_default_number_entities( hass: HomeAssistant, entity_registry: er.EntityRegistry, entity_ids: list[str] @@ -125,6 +144,7 @@ async def test_disabled_by_default_number_entities( @pytest.mark.usefixtures("entity_registry_enabled_by_default") +@pytest.mark.parametrize(("device_fixture"), ["yna5x1"]) async def test_volume_maximum( hass: HomeAssistant, controller: EcovacsController,