diff --git a/homeassistant/components/alexa/capabilities.py b/homeassistant/components/alexa/capabilities.py index ac4784132f5..008870c8dd9 100644 --- a/homeassistant/components/alexa/capabilities.py +++ b/homeassistant/components/alexa/capabilities.py @@ -1564,7 +1564,7 @@ class AlexaRangeController(AlexaCapability): min_value = float(self.entity.attributes[input_number.ATTR_MIN]) max_value = float(self.entity.attributes[input_number.ATTR_MAX]) precision = float(self.entity.attributes.get(input_number.ATTR_STEP, 1)) - unit = self.entity.attributes.get(input_number.ATTR_UNIT_OF_MEASUREMENT) + unit = self.entity.attributes.get(ATTR_UNIT_OF_MEASUREMENT) self._resource = AlexaPresetResource( ["Value", AlexaGlobalCatalog.SETTING_PRESET], diff --git a/homeassistant/components/input_number/__init__.py b/homeassistant/components/input_number/__init__.py index 8ec26ea3956..1f979cad7a9 100644 --- a/homeassistant/components/input_number/__init__.py +++ b/homeassistant/components/input_number/__init__.py @@ -7,11 +7,11 @@ import voluptuous as vol from homeassistant.const import ( ATTR_EDITABLE, ATTR_MODE, - ATTR_UNIT_OF_MEASUREMENT, CONF_ICON, CONF_ID, CONF_MODE, CONF_NAME, + CONF_UNIT_OF_MEASUREMENT, SERVICE_RELOAD, ) from homeassistant.core import callback @@ -67,7 +67,7 @@ CREATE_FIELDS = { vol.Optional(CONF_INITIAL): vol.Coerce(float), vol.Optional(CONF_STEP, default=1): vol.All(vol.Coerce(float), vol.Range(min=1e-3)), vol.Optional(CONF_ICON): cv.icon, - vol.Optional(ATTR_UNIT_OF_MEASUREMENT): cv.string, + vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, vol.Optional(CONF_MODE, default=MODE_SLIDER): vol.In([MODE_BOX, MODE_SLIDER]), } @@ -78,7 +78,7 @@ UPDATE_FIELDS = { vol.Optional(CONF_INITIAL): vol.Coerce(float), vol.Optional(CONF_STEP): vol.All(vol.Coerce(float), vol.Range(min=1e-3)), vol.Optional(CONF_ICON): cv.icon, - vol.Optional(ATTR_UNIT_OF_MEASUREMENT): cv.string, + vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, vol.Optional(CONF_MODE): vol.In([MODE_BOX, MODE_SLIDER]), } @@ -95,7 +95,7 @@ CONFIG_SCHEMA = vol.Schema( vol.Coerce(float), vol.Range(min=1e-3) ), vol.Optional(CONF_ICON): cv.icon, - vol.Optional(ATTR_UNIT_OF_MEASUREMENT): cv.string, + vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, vol.Optional(CONF_MODE, default=MODE_SLIDER): vol.In( [MODE_BOX, MODE_SLIDER] ), @@ -250,7 +250,7 @@ class InputNumber(RestoreEntity): @property def unit_of_measurement(self): """Return the unit the value is expressed in.""" - return self._config.get(ATTR_UNIT_OF_MEASUREMENT) + return self._config.get(CONF_UNIT_OF_MEASUREMENT) @property def unique_id(self) -> typing.Optional[str]: diff --git a/homeassistant/helpers/selector.py b/homeassistant/helpers/selector.py index d3e96a5205e..d02a41f5f97 100644 --- a/homeassistant/helpers/selector.py +++ b/homeassistant/helpers/selector.py @@ -3,6 +3,7 @@ from typing import Any, Callable, Dict, cast import voluptuous as vol +from homeassistant.const import CONF_MODE, CONF_UNIT_OF_MEASUREMENT from homeassistant.util import decorator SELECTORS = decorator.Registry() @@ -68,3 +69,39 @@ class DeviceSelector(Selector): vol.Optional("model"): str, } ) + + +@SELECTORS.register("number") +class NumberSelector(Selector): + """Selector of a numeric value.""" + + CONFIG_SCHEMA = vol.Schema( + { + vol.Required("min"): vol.Coerce(float), + vol.Required("max"): vol.Coerce(float), + vol.Optional("step", default=1): vol.All( + vol.Coerce(float), vol.Range(min=1e-3) + ), + vol.Optional(CONF_UNIT_OF_MEASUREMENT): str, + vol.Optional(CONF_MODE, default="slider"): vol.In(["box", "slider"]), + } + ) + + +@SELECTORS.register("boolean") +class BooleanSelector(Selector): + """Selector of a boolean value.""" + + CONFIG_SCHEMA = vol.Schema({}) + + +@SELECTORS.register("datetime") +class DateTimeSelector(Selector): + """Selector of a date and or time value.""" + + CONFIG_SCHEMA = vol.Schema( + { + vol.Optional("has_date", default=False): bool, + vol.Optional("has_time", default=False): bool, + } + ) diff --git a/tests/helpers/test_selector.py b/tests/helpers/test_selector.py index a8410821c42..c5b11285e48 100644 --- a/tests/helpers/test_selector.py +++ b/tests/helpers/test_selector.py @@ -66,3 +66,42 @@ def test_device_selector_schema(schema): def test_entity_selector_schema(schema): """Test entity selector.""" selector.validate_selector({"entity": schema}) + + +@pytest.mark.parametrize( + "schema", + ( + {"min": 10, "max": 50}, + {"min": -100, "max": 100, "step": 5}, + {"min": -20, "max": -10, "mode": "box"}, + {"min": 0, "max": 100, "unit_of_measurement": "seconds", "mode": "slider"}, + {"min": 10, "max": 1000, "mode": "slider", "step": 0.5}, + ), +) +def test_number_selector_schema(schema): + """Test number selector.""" + selector.validate_selector({"number": schema}) + + +@pytest.mark.parametrize( + "schema", + ({},), +) +def test_boolean_selector_schema(schema): + """Test boolean selector.""" + selector.validate_selector({"boolean": schema}) + + +@pytest.mark.parametrize( + "schema", + ( + {}, + {"has_date": True, "has_time": True}, + {"has_date": False, "has_time": False}, + {"has_date": True, "has_time": False}, + {"has_date": False, "has_time": True}, + ), +) +def test_datetime_selector_schema(schema): + """Test datetime selector.""" + selector.validate_selector({"datetime": schema})