8000 Allow to set translation_domain for SelectSelector and create helpers for sensor/switch device_class and sensor state_class by jbouwh · Pull Request #141544 · home-assistant/core · GitHub
[go: up one dir, main page]

Skip to content

Allow to set translation_domain for SelectSelector and create helpers for sensor/switch device_class and sensor state_class #141544

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 10 additions & 24 deletions homeassistant/components/mqtt/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@
DEVICE_CLASS_UNITS,
STATE_CLASS_UNITS,
SensorDeviceClass,
SensorStateClass,
)
from homeassistant.components.sensor.helpers import (
create_sensor_device_class_select_selector,
create_sensor_state_class_select_selector,
)
from homeassistant.components.switch import SwitchDeviceClass
from homeassistant.config_entries import (
Expand Down Expand Up @@ -412,15 +415,6 @@
}
)

# Sensor specific selectors
SENSOR_DEVICE_CLASS_SELECTOR = SelectSelector(
SelectSelectorConfig(
options=[device_class.value for device_class in SensorDeviceClass],
mode=SelectSelectorMode.DROPDOWN,
translation_key="device_class_sensor",
sort=True,
)
)
BINARY_SENSOR_DEVICE_CLASS_SELECTOR = SelectSelector(
SelectSelectorConfig(
options=[device_class.value for device_class in BinarySensorDeviceClass],
Expand All @@ -445,19 +439,9 @@
sort=True,
)
)
SENSOR_STATE_CLASS_SELECTOR = SelectSelector(
SelectSelectorConfig(
options=[device_class.value for device_class in SensorStateClass],
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_STATE_CLASS,
)
)

OPTIONS_SELECTOR = SelectSelector(
SelectSelectorConfig(
options=[],
custom_value=True,
multiple=True,
)
SelectSelectorConfig(options=[], custom_value=True, multiple=True)
)
SUGGESTED_DISPLAY_PRECISION_SELECTOR = NumberSelector(
NumberSelectorConfig(mode=NumberSelectorMode.BOX, min=0, max=9)
Expand Down Expand Up @@ -783,10 +767,12 @@ def validate_light_platform_config(user_data: dict[str, Any]) -> dict[str, str]:
Platform.NOTIFY.value: {},
Platform.SENSOR.value: {
CONF_DEVICE_CLASS: PlatformField(
selector=SENSOR_DEVICE_CLASS_SELECTOR, required=False
selector=create_sensor_device_class_select_selector(),
required=False,
),
CONF_STATE_CLASS: PlatformField(
selector=SENSOR_STATE_CLASS_SELECTOR, required=False
selector=create_sensor_state_class_select_selector(),
required=False,
),
CONF_UNIT_OF_MEASUREMENT: PlatformField(
selector=unit_of_measurement_selector,
Expand Down
68 changes: 0 additions & 68 deletions homeassistant/components/mqtt/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -817,66 +817,6 @@
"window": "[%key:component::cover::entity_component::window::name%]"
}
},
"device_class_sensor": {
"options": {
"apparent_power": "[%key:component::sensor::entity_component::apparent_power::name%]",
"area": "[%key:component::sensor::entity_component::area::name%]",
"aqi": "[%key:component::sensor::entity_component::aqi::name%]",
"atmospheric_pressure": "[%key:component::sensor::entity_component::atmospheric_pressure::name%]",
"battery": "[%key:component::sensor::entity_component::battery::name%]",
"blood_glucose_concentration": "[%key:component::sensor::entity_component::blood_glucose_concentration::name%]",
"carbon_dioxide": "[%key:component::sensor::entity_component::carbon_dioxide::name%]",
"carbon_monoxide": "[%key:component::sensor::entity_component::carbon_monoxide::name%]",
"conductivity": "[%key:component::sensor::entity_component::conductivity::name%]",
"current": "[%key:component::sensor::entity_component::current::name%]",
"data_rate": "[%key:component::sensor::entity_component::data_rate::name%]",
"data_size": "[%key:component::sensor::entity_component::data_size::name%]",
"date": "[%key:component::sensor::entity_component::date::name%]",
"distance": "[%key:component::sensor::entity_component::distance::name%]",
"duration": "[%key:component::sensor::entity_component::duration::name%]",
"energy": "[%key:component::sensor::entity_component::energy::name%]",
"energy_distance": "[%key:component::sensor::entity_component::energy_distance::name%]",
"energy_storage": "[%key:component::sensor::entity_component::energy_storage::name%]",
"enum": "Enumeration",
"frequency": "[%key:component::sensor::entity_component::frequency::name%]",
"gas": "[%key:component::sensor::entity_component::gas::name%]",
"humidity": "[%key:component::sensor::entity_component::humidity::name%]",
"illuminance": "[%key:component::sensor::entity_component::illuminance::name%]",
"irradiance": "[%key:component::sensor::entity_component::irradiance::name%]",
"moisture": "[%key:component::sensor::entity_component::moisture::name%]",
"monetary": "[%key:component::sensor::entity_component::monetary::name%]",
"nitrogen_dioxide": "[%key:component::sensor::entity_component::nitrogen_dioxide::name%]",
"nitrogen_monoxide": "[%key:component::sensor::entity_component::nitrogen_monoxide::name%]",
"nitrous_oxide": "[%key:component::sensor::entity_component::nitrous_oxide::name%]",
"ozone": "[%key:component::sensor::entity_component::ozone::name%]",
"ph": "[%key:component::sensor::entity_component::ph::name%]",
"pm1": "[%key:component::sensor::entity_component::pm1::name%]",
"pm10": "[%key:component::sensor::entity_component::pm10::name%]",
"pm25": "[%key:component::sensor::entity_component::pm25::name%]",
"power": "[%key:component::sensor::entity_component::power::name%]",
"power_factor": "[%key:component::sensor::entity_component::power_factor::name%]",
"precipitation": "[%key:component::sensor::entity_component::precipitation::name%]",
"precipitation_intensity": "[%key:component::sensor::entity_component::precipitation_intensity::name%]",
"pressure": "[%key:component::sensor::entity_component::pressure::name%]",
"reactive_power": "[%key:component::sensor::entity_component::reactive_power::name%]",
"signal_strength": "[%key:component::sensor::entity_component::signal_strength::name%]",
"sound_pressure": "[%key:component::sensor::entity_component::sound_pressure::name%]",
"speed": "[%key:component::sensor::entity_component::speed::name%]",
"sulphur_dioxide": "[%key:component::sensor::entity_component::sulphur_dioxide::name%]",
"temperature": "[%key:component::sensor::entity_component::temperature::name%]",
"timestamp": "[%key:component::sensor::entity_component::timestamp::name%]",
"volatile_organic_compounds": "[%key:component::sensor::entity_component::volatile_organic_compounds::name%]",
"volatile_organic_compounds_parts": "[%key:component::sensor::entity_component::volatile_organic_compounds_parts::name%]",
"voltage": "[%key:component::sensor::entity_component::voltage::name%]",
"volume": "[%key:component::sensor::entity_component::volume::name%]",
"volume_flow_rate": "[%key:component::sensor::entity_component::volume_flow_rate::name%]",
"volume_storage": "[%key:component::sensor::entity_component::volume_storage::name%]",
"water": "[%key:component::sensor::entity_component::water::name%]",
"weight": "[%key:component::sensor::entity_component::weight::name%]",
"wind_direction": "[%key:component::sensor::entity_component::wind_direction::name%]",
"wind_speed": "[%key:component::sensor::entity_component::wind_speed::name%]"
}
},
"device_class_switch": {
"options": {
"outlet": "[%key:component::switch::entity_component::outlet::name%]",
Expand Down Expand Up @@ -916,14 +856,6 @@
"custom": "Custom"
}
},
"state_class": {
"options": {
"measurement": "[%key:component::sensor::entity_component::_::state_attributes::state_class::state::measurement%]",
"measurement_angle": "[%key:component::sensor::entity_component::_::state_attributes::state_class::state::measurement_angle%]",
"total": "[%key:component::sensor::entity_component::_::state_attributes::state_class::state::total%]",
"total_increasing": "[%key:component::sensor::entity_component::_::state_attributes::state_class::state::total_increasing%]"
}
},
"supported_color_modes": {
"options": {
"onoff": "[%key:component::light::entity_component::_::state_attributes::color_mode::state::onoff%]",
Expand Down
35 changes: 34 additions & 1 deletion homeassistant/components/sensor/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@
import logging

from homeassistant.core import callback
from homeassistant.helpers.selector import (
SelectSelector,
SelectSelectorConfig,
SelectSelectorMode,
)
from homeassistant.util import dt as dt_util

from . import SensorDeviceClass
from . import DOMAIN, SensorDeviceClass, SensorStateClass

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -37,3 +42,31 @@ def async_parse_date_datetime(

_LOGGER.warning("%s rendered invalid date %s", entity_id, value)
return None


@callback
def create_sensor_device_class_select_selector() -> SelectSelector:
"""Create sensor device class select selector."""
return SelectSelector(
SelectSelectorConfig(
options=[device_class.value for device_class in SensorDeviceClass],
mode=SelectSelectorMode.DROPDOWN,
translation_key="device_class",
translation_domain=DOMAIN,
sort=True,
)
)


@callback
def create_sensor_state_class_select_selector() -> SelectSelector:
"""Create sensor state class select selector."""
return SelectSelector(
SelectSelectorConfig(
options=[device_class.value for device_class in SensorStateClass],
mode=SelectSelectorMode.DROPDOWN,
translation_key="state_class",
translation_domain=DOMAIN,
sort=True,
)
)
69 changes: 69 additions & 0 deletions homeassistant/components/sensor/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -327,5 +327,74 @@
"title": "The unit of {statistic_id} has changed",
"description": ""
}
},
"selector": {
"device_class": {
"options": {
"apparent_power": "[%key:component::sensor::entity_component::apparent_power::name%]",
"area": "[%key:component::sensor::entity_component::area::name%]",
"aqi": "[%key:component::sensor::entity_component::aqi::name%]",
"atmospheric_pressure": "[%key:component::sensor::entity_component::atmospheric_pressure::name%]",
"battery": "[%key:component::sensor::entity_component::battery::name%]",
"blood_glucose_concentration": "[%key:component::sensor::entity_component::blood_glucose_concentration::name%]",
"carbon_dioxide": "[%key:component::sensor::entity_component::carbon_dioxide::name%]",
"carbon_monoxide": "[%key:component::sensor::entity_component::carbon_monoxide::name%]",
"conductivity": "[%key:component::sensor::entity_component::conductivity::name%]",
"current": "[%key:component::sensor::entity_component::current::name%]",
"data_rate": "[%key:component::sensor::entity_component::data_rate::name%]",
"data_size": "[%key:component::sensor::entity_component::data_size::name%]",
"date": "[%key:component::sensor::entity_component::date::name%]",
"distance": "[%key:component::sensor::entity_component::distance::name%]",
"duration": "[%key:component::sensor::entity_component::duration::name%]",
"energy": "[%key:component::sensor::entity_component::energy::name%]",
"energy_distance": "[%key:component::sensor::entity_component::energy_distance::name%]",
"energy_storage": "[%key:component::sensor::entity_component::energy_storage::name%]",
"enum": "Enumeration",
"frequency": "[%key:component::sensor::entity_component::frequency::name%]",
"gas": "[%key:component::sensor::entity_component::gas::name%]",
"humidity": "[%key:component::sensor::entity_component::humidity::name%]",
"illuminance": "[%key:component::sensor::entity_component::illuminance::name%]",
"irradiance": "[%key:component::sensor::entity_component::irradiance::name%]",
"moisture": "[%key:component::sensor::entity_component::moisture::name%]",
"monetary": "[%key:component::sensor::entity_component::monetary::name%]",
"nitrogen_dioxide": "[%key:component::sensor::entity_component::nitrogen_dioxide::name%]",
"nitrogen_monoxide": "[%key:component::sensor::entity_component::nitrogen_monoxide::name%]",
"nitrous_oxide": "[%key:component::sensor::entity_component::nitrous_oxide::name%]",
"ozone": "[%key:component::sensor::entity_component::ozone::name%]",
"ph": "[%key:component::sensor::entity_component::ph::name%]",
"pm1": "[%key:component::sensor::entity_component::pm1::name%]",
"pm10": "[%key:component::sensor::entity_component::pm10::name%]",
"pm25": "[%key:component::sensor::entity_component::pm25::name%]",
"power": "[%key:component::sensor::entity_component::power::name%]",
"power_factor": "[%key:component::sensor::entity_component::power_factor::name%]",
"precipitation": "[%key:component::sensor::entity_component::precipitation::name%]",
"precipitation_intensity": "[%key:component::sensor::entity_component::precipitation_intensity::name%]",
"pressure": "[%key:component::sensor::entity_component::pressure::name%]",
"reactive_power": "[%key:component::sensor::entity_component::reactive_power::name%]",
"signal_strength": "[%key:component::sensor::entity_component::signal_strength::name%]",
"sound_pressure": "[%key:component::sensor::entity_component::sound_pressure::name%]",
"speed": "[%key:component::sensor::entity_component::speed::name%]",
"sulphur_dioxide": "[%key:component::sensor::entity_component::sulphur_dioxide::name%]",
"temperature": "[%key:component::sensor::entity_component::temperature::name%]",
"timestamp": "[%key:component::sensor::entity_component::timestamp::name%]",
"volatile_organic_compounds": "[%key:component::sensor::entity_component::volatile_organic_compounds::name%]",
"volatile_organic_compounds_parts": "[%key:component::sensor::entity_component::volatile_organic_compounds::name%]",
"voltage": "[%key:component::sensor::entity_component::voltage::name%]",
"volume": "[%key:component::sensor::entity_component::volume::name%]",
"volume_flow_rate": "[%key:component::sensor::entity_component::volume_flow_rate::name%]",
"volume_storage": "[%key:component::sensor::entity_component::volume_storage::name%]",
"water": "[%key:component::sensor::entity_component::water::name%]",
"weight": "[%key:component::sensor::entity_component::weight::name%]",
"wind_direction": "[%key:component::sensor::entity_component::wind_direction::name%]",
"wind_speed": "[%key:component::sensor::entity_component::wind_speed::name%]"
}
},
"state_class": {
"options": {
"measurement": "[%key:component::sensor::entity_component::_::state_attributes::state_class::state::measurement%]",
"total": "[%key:component::sensor::entity_component::_::state_attributes::state_class::state::total%]",
"total_increasing": "[%key:component::sensor::entity_component::_::state_attributes::state_class::state::total_increasing%]"
}
}
}
}
25 changes: 25 additions & 0 deletions homeassistant/components/switch/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Helpers for switch entities."""

from homeassistant.core import callback
from homeassistant.helpers.selector import (
SelectSelector,
SelectSelectorConfig,
SelectSelectorMode,
)

from . import DOMAIN, SwitchDeviceClass


@callback
def create_switch_device_class_select_selector() -> SelectSelector:
"""Create sensor device class select selector."""

return SelectSelector(
SelectSelectorConfig(
options=[device_class.value for device_class in SwitchDeviceClass],
mode=SelectSelectorMode.DROPDOWN,
translation_key="device_class",
translation_domain=DOMAIN,
sort=True,
)
)
8 changes: 8 additions & 0 deletions homeassistant/components/switch/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,13 @@
"name": "[%key:common::action::toggle%]",
"description": "Toggles a switch on/off."
}
},
"selector": {
"device_class": {
"options": {
"outlet": "[%key:component::switch::entity_component::outlet::name%]",
"switch": "[%key:component::switch::title%]"
}
}
}
}
2 changes: 2 additions & 0 deletions homeassistant/helpers/selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,7 @@ class SelectSelectorConfig(BaseSelectorConfig, total=False):
custom_value: bool
mode: SelectSelectorMode
translation_key: str
translation_domain: str
sort: bool


Expand All @@ -1185,6 +1186,7 @@ class SelectSelector(Selector[SelectSelectorConfig]):
vol.Coerce(SelectSelectorMode), lambda val: val.value
),
vol.Optional("translation_key"): cv.string,
vol.Optional("translation_domain"): cv.string,
vol.Optional("sort", default=False): cv.boolean,
}
)
Expand Down
30 changes: 27 additions & 3 deletions tests/components/sensor/test_helpers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
"""The test for sensor helpers."""
"""Tests for sensor helpers."""

import pytest

from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.components.sensor.helpers import async_parse_date_datetime
from homeassistant.components.sensor import DOMAIN, SensorDeviceClass, SensorStateClass
from homeassistant.components.sensor.helpers import (
async_parse_date_datetime,
create_sensor_device_class_select_selector,
create_sensor_state_class_select_selector,
)


def test_async_parse_datetime(caplog: pytest.LogCaptureFixture) -> None:
Expand Down Expand Up @@ -39,3 +43,23 @@ def test_async_parse_datetime(caplog: pytest.LogCaptureFixture) -> None:
# Invalid date
assert async_parse_date_datetime("December 12th", entity_id, device_class) is None
assert "sensor.timestamp rendered invalid date December 12th" in caplog.text


def test_create_sensor_device_class_select_selector() -> None:
"Test Create sensor state class select selector helper."
selector = create_sensor_device_class_select_selector()
assert selector.config["options"] == list(SensorDeviceClass)
assert selector.config["translation_domain"] == DOMAIN
assert selector.config["translation_key"] == "device_class"
assert selector.config["sort"]
assert not selector.config["custom_value"]


def test_create_sensor_state_class_select_selector() -> None:
"Test Create sensor state class select selector helper."
selector = create_sensor_state_class_select_selector()
assert selector.config["options"] == list(SensorStateClass)
assert selector.config["translation_domain"] == DOMAIN
assert selector.config["translation_key"] == "state_class"
assert selector.config["sort"]
assert not selector.config["custom_value"]
16 changes: 16 additions & 0 deletions tests/components/switch/test_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Tests for switch helpers."""

from homeassistant.components.switch import DOMAIN, SwitchDeviceClass
from homeassistant.components.switch.helpers import (
create_switch_device_class_select_selector,
)


def test_create_switch_device_class_select_selector() -> None:
"Test Create sensor state class select selector helper."
selector = create_switch_device_class_select_selector()
assert selector.config["options"] == list(SwitchDeviceClass)
assert selector.config["translation_domain"] == DOMAIN
assert selector.config["translation_key"] == "device_class"
assert selector.config["sort"]
assert not selector.config["custom_value"]
1 change: 1 addition & 0 deletions tests/helpers/test_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,7 @@ def test_text_selector_schema(schema, valid_selections, invalid_selections) -> N
{
"options": ["red", "green", "blue"],
"translation_key": "color",
"translation_domain": "homeassistant",
},
("red", "green", "blue"),
("cat", 0, None, ["red"]),
Expand Down
0