From dcaa68902326c76834373a185b0b4ad051a59198 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Thu, 21 Oct 2021 07:20:39 +0200 Subject: [PATCH] Add auto slider/box mode to number entity (#57737) --- homeassistant/components/demo/number.py | 29 ++++++++++++++++++++- homeassistant/components/number/__init__.py | 11 +++++++- homeassistant/components/number/const.py | 6 +++++ tests/components/demo/test_number.py | 21 ++++++++++++++- 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/demo/number.py b/homeassistant/components/demo/number.py index cad2255806e..8f3ccf47230 100644 --- a/homeassistant/components/demo/number.py +++ b/homeassistant/components/demo/number.py @@ -1,7 +1,10 @@ """Demo platform that offers a fake Number entity.""" from __future__ import annotations +from typing import Literal + from homeassistant.components.number import NumberEntity +from homeassistant.components.number.const import MODE_AUTO, MODE_BOX, MODE_SLIDER from homeassistant.const import DEVICE_DEFAULT_NAME from . import DOMAIN @@ -17,6 +20,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= 42.0, "mdi:volume-high", False, + mode=MODE_SLIDER, ), DemoNumber( "pwm1", @@ -27,6 +31,27 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= 0.0, 1.0, 0.01, + MODE_BOX, + ), + DemoNumber( + "large_range", + "Large Range", + 500, + "mdi:square-wave", + False, + 1, + 1000, + 1, + ), + DemoNumber( + "small_range", + "Small Range", + 128, + "mdi:square-wave", + False, + 1, + 255, + 1, ), ] ) @@ -51,7 +76,8 @@ class DemoNumber(NumberEntity): assumed: bool, min_value: float | None = None, max_value: float | None = None, - step=None, + step: float | None = None, + mode: Literal["auto", "box", "slider"] = MODE_AUTO, ) -> None: """Initialize the Demo Number entity.""" self._attr_assumed_state = assumed @@ -59,6 +85,7 @@ class DemoNumber(NumberEntity): self._attr_name = name or DEVICE_DEFAULT_NAME self._attr_unique_id = unique_id self._attr_value = state + self._attr_mode = mode if min_value is not None: self._attr_min_value = min_value diff --git a/homeassistant/components/number/__init__.py b/homeassistant/components/number/__init__.py index ac727288b07..89ad7d8b8c2 100644 --- a/homeassistant/components/number/__init__.py +++ b/homeassistant/components/number/__init__.py @@ -4,11 +4,12 @@ from __future__ import annotations from dataclasses import dataclass from datetime import timedelta import logging -from typing import Any, final +from typing import Any, Literal, final import voluptuous as vol from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ATTR_MODE from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.helpers.config_validation import ( # noqa: F401 PLATFORM_SCHEMA, @@ -27,6 +28,7 @@ from .const import ( DEFAULT_MIN_VALUE, DEFAULT_STEP, DOMAIN, + MODE_AUTO, SERVICE_SET_VALUE, ) @@ -90,6 +92,7 @@ class NumberEntity(Entity): _attr_min_value: float = DEFAULT_MIN_VALUE _attr_state: None = None _attr_step: float + _attr_mode: Literal["auto", "slider", "box"] = MODE_AUTO _attr_value: float @property @@ -99,6 +102,7 @@ class NumberEntity(Entity): ATTR_MIN: self.min_value, ATTR_MAX: self.max_value, ATTR_STEP: self.step, + ATTR_MODE: self.mode, } @property @@ -123,6 +127,11 @@ class NumberEntity(Entity): step /= 10.0 return step + @property + def mode(self) -> Literal["auto", "slider", "box"]: + """Return the mode of the entity.""" + return self._attr_mode + @property @final def state(self) -> float | None: diff --git a/homeassistant/components/number/const.py b/homeassistant/components/number/const.py index 2aa8075cba3..749463b11e5 100644 --- a/homeassistant/components/number/const.py +++ b/homeassistant/components/number/const.py @@ -1,10 +1,16 @@ """Provides the constants needed for the component.""" +from typing import Final + ATTR_VALUE = "value" ATTR_MIN = "min" ATTR_MAX = "max" ATTR_STEP = "step" +MODE_AUTO: Final = "auto" +MODE_BOX: Final = "box" +MODE_SLIDER: Final = "slider" + DEFAULT_MIN_VALUE = 0.0 DEFAULT_MAX_VALUE = 100.0 DEFAULT_STEP = 1.0 diff --git a/tests/components/demo/test_number.py b/tests/components/demo/test_number.py index 82536b0d2f8..88e46f5c66d 100644 --- a/tests/components/demo/test_number.py +++ b/tests/components/demo/test_number.py @@ -9,13 +9,18 @@ from homeassistant.components.number.const import ( ATTR_STEP, ATTR_VALUE, DOMAIN, + MODE_AUTO, + MODE_BOX, + MODE_SLIDER, SERVICE_SET_VALUE, ) -from homeassistant.const import ATTR_ENTITY_ID +from homeassistant.const import ATTR_ENTITY_ID, ATTR_MODE from homeassistant.setup import async_setup_component ENTITY_VOLUME = "number.volume" ENTITY_PWM = "number.pwm_1" +ENTITY_LARGE_RANGE = "number.large_range" +ENTITY_SMALL_RANGE = "number.small_range" @pytest.fixture(autouse=True) @@ -37,11 +42,25 @@ def test_default_setup_params(hass): assert state.attributes.get(ATTR_MIN) == 0.0 assert state.attributes.get(ATTR_MAX) == 100.0 assert state.attributes.get(ATTR_STEP) == 1.0 + assert state.attributes.get(ATTR_MODE) == MODE_SLIDER state = hass.states.get(ENTITY_PWM) assert state.attributes.get(ATTR_MIN) == 0.0 assert state.attributes.get(ATTR_MAX) == 1.0 assert state.attributes.get(ATTR_STEP) == 0.01 + assert state.attributes.get(ATTR_MODE) == MODE_BOX + + state = hass.states.get(ENTITY_LARGE_RANGE) + assert state.attributes.get(ATTR_MIN) == 1.0 + assert state.attributes.get(ATTR_MAX) == 1000.0 + assert state.attributes.get(ATTR_STEP) == 1.0 + assert state.attributes.get(ATTR_MODE) == MODE_AUTO + + state = hass.states.get(ENTITY_SMALL_RANGE) + assert state.attributes.get(ATTR_MIN) == 1.0 + assert state.attributes.get(ATTR_MAX) == 255.0 + assert state.attributes.get(ATTR_STEP) == 1.0 + assert state.attributes.get(ATTR_MODE) == MODE_AUTO async def test_set_value_bad_attr(hass):