diff --git a/homeassistant/components/template/number.py b/homeassistant/components/template/number.py index a7737c31246..86cc4886430 100644 --- a/homeassistant/components/template/number.py +++ b/homeassistant/components/template/number.py @@ -18,7 +18,13 @@ from homeassistant.components.number.const import ( DOMAIN as NUMBER_DOMAIN, ) from homeassistant.components.template import TriggerUpdateCoordinator -from homeassistant.const import CONF_NAME, CONF_OPTIMISTIC, CONF_STATE, CONF_UNIQUE_ID +from homeassistant.const import ( + CONF_ICON, + CONF_NAME, + CONF_OPTIMISTIC, + CONF_STATE, + CONF_UNIQUE_ID, +) from homeassistant.core import Config, HomeAssistant import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -47,6 +53,7 @@ NUMBER_SCHEMA = vol.Schema( vol.Optional(CONF_AVAILABILITY): cv.template, vol.Optional(CONF_OPTIMISTIC, default=DEFAULT_OPTIMISTIC): cv.boolean, vol.Optional(CONF_UNIQUE_ID): cv.string, + vol.Optional(CONF_ICON): cv.template, } ) @@ -72,6 +79,7 @@ async def _async_create_entities( definition[ATTR_MAX], definition[CONF_OPTIMISTIC], unique_id, + definition.get(CONF_ICON), ) ) return entities @@ -119,9 +127,12 @@ class TemplateNumber(TemplateEntity, NumberEntity): maximum_template: Template | None, optimistic: bool, unique_id: str | None, + icon_template: Template | None, ) -> None: """Initialize the number.""" - super().__init__(availability_template=availability_template) + super().__init__( + availability_template=availability_template, icon_template=icon_template + ) self._attr_name = DEFAULT_NAME self._name_template = name_template name_template.hass = hass diff --git a/tests/components/template/test_number.py b/tests/components/template/test_number.py index f297307fd0e..1f317c06330 100644 --- a/tests/components/template/test_number.py +++ b/tests/components/template/test_number.py @@ -15,7 +15,7 @@ from homeassistant.components.number.const import ( DOMAIN as NUMBER_DOMAIN, SERVICE_SET_VALUE as NUMBER_SERVICE_SET_VALUE, ) -from homeassistant.const import CONF_ENTITY_ID, STATE_UNKNOWN +from homeassistant.const import ATTR_ICON, CONF_ENTITY_ID, STATE_UNKNOWN from homeassistant.core import Context from homeassistant.helpers.entity_registry import async_get @@ -35,6 +35,17 @@ _MAXIMUM_INPUT_NUMBER = "input_number.maximum" # Represent for number's step _STEP_INPUT_NUMBER = "input_number.step" +# Config for `_VALUE_INPUT_NUMBER` +_VALUE_INPUT_NUMBER_CONFIG = { + "value": { + "min": 0.0, + "max": 100.0, + "name": "Value", + "step": 1.0, + "mode": "slider", + } +} + @pytest.fixture def calls(hass): @@ -128,20 +139,14 @@ async def test_all_optional_config(hass, calls): async def test_templates_with_entities(hass, calls): - """Test tempalates with values from other entities.""" + """Test templates with values from other entities.""" with assert_setup_component(4, "input_number"): assert await setup.async_setup_component( hass, "input_number", { "input_number": { - "value": { - "min": 0.0, - "max": 100.0, - "name": "Value", - "step": 1.0, - "mode": "slider", - }, + **_VALUE_INPUT_NUMBER_CONFIG, "step": { "min": 0.0, "max": 100.0, @@ -334,3 +339,118 @@ def _verify( assert attributes.get(ATTR_STEP) == float(expected_step) assert attributes.get(ATTR_MAX) == float(expected_maximum) assert attributes.get(ATTR_MIN) == float(expected_minimum) + + +async def test_icon_template(hass): + """Test template numbers with icon templates.""" + with assert_setup_component(1, "input_number"): + assert await setup.async_setup_component( + hass, + "input_number", + {"input_number": _VALUE_INPUT_NUMBER_CONFIG}, + ) + + with assert_setup_component(1, "template"): + assert await setup.async_setup_component( + hass, + "template", + { + "template": { + "unique_id": "b", + "number": { + "state": f"{{{{ states('{_VALUE_INPUT_NUMBER}') }}}}", + "step": 1, + "min": 0, + "max": 100, + "set_value": { + "service": "input_number.set_value", + "data_template": { + "entity_id": _VALUE_INPUT_NUMBER, + "value": "{{ value }}", + }, + }, + "icon": "{% if ((states.input_number.value.state or 0) | int) > 50 %}mdi:greater{% else %}mdi:less{% endif %}", + }, + } + }, + ) + + hass.states.async_set(_VALUE_INPUT_NUMBER, 49) + + await hass.async_block_till_done() + await hass.async_start() + await hass.async_block_till_done() + + state = hass.states.get(_TEST_NUMBER) + assert float(state.state) == 49 + assert state.attributes[ATTR_ICON] == "mdi:less" + + await hass.services.async_call( + INPUT_NUMBER_DOMAIN, + INPUT_NUMBER_SERVICE_SET_VALUE, + {CONF_ENTITY_ID: _VALUE_INPUT_NUMBER, INPUT_NUMBER_ATTR_VALUE: 51}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get(_TEST_NUMBER) + assert float(state.state) == 51 + assert state.attributes[ATTR_ICON] == "mdi:greater" + + +async def test_icon_template_with_trigger(hass): + """Test template numbers with icon templates.""" + with assert_setup_component(1, "input_number"): + assert await setup.async_setup_component( + hass, + "input_number", + {"input_number": _VALUE_INPUT_NUMBER_CONFIG}, + ) + + with assert_setup_component(1, "template"): + assert await setup.async_setup_component( + hass, + "template", + { + "template": { + "trigger": {"platform": "state", "entity_id": _VALUE_INPUT_NUMBER}, + "unique_id": "b", + "number": { + "state": "{{ trigger.to_state.state }}", + "step": 1, + "min": 0, + "max": 100, + "set_value": { + "service": "input_number.set_value", + "data_template": { + "entity_id": _VALUE_INPUT_NUMBER, + "value": "{{ value }}", + }, + }, + "icon": "{% if ((trigger.to_state.state or 0) | int) > 50 %}mdi:greater{% else %}mdi:less{% endif %}", + }, + } + }, + ) + + hass.states.async_set(_VALUE_INPUT_NUMBER, 49) + + await hass.async_block_till_done() + await hass.async_start() + await hass.async_block_till_done() + + state = hass.states.get(_TEST_NUMBER) + assert float(state.state) == 49 + assert state.attributes[ATTR_ICON] == "mdi:less" + + await hass.services.async_call( + INPUT_NUMBER_DOMAIN, + INPUT_NUMBER_SERVICE_SET_VALUE, + {CONF_ENTITY_ID: _VALUE_INPUT_NUMBER, INPUT_NUMBER_ATTR_VALUE: 51}, + blocking=True, + ) + await hass.async_block_till_done() + + state = hass.states.get(_TEST_NUMBER) + assert float(state.state) == 51 + assert state.attributes[ATTR_ICON] == "mdi:greater"