From aea0067e496baee4e564da6c6d9d208da934ab59 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Tue, 25 Oct 2022 12:51:23 +0200 Subject: [PATCH] Add additional rules for converting distances (#80940) * Add additional rules for converting distances * Convert in to mm * Adjust existing tests * Add test --- homeassistant/util/unit_system.py | 31 ++++++++++++++++------ tests/helpers/test_template.py | 2 +- tests/util/test_unit_system.py | 43 ++++++++++++++++++++++++++----- 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/homeassistant/util/unit_system.py b/homeassistant/util/unit_system.py index db0e0e49e17..72779fe8c84 100644 --- a/homeassistant/util/unit_system.py +++ b/homeassistant/util/unit_system.py @@ -9,8 +9,14 @@ import voluptuous as vol from homeassistant.const import ( ACCUMULATED_PRECIPITATION, LENGTH, + LENGTH_CENTIMETERS, + LENGTH_FEET, + LENGTH_INCHES, LENGTH_KILOMETERS, + LENGTH_METERS, LENGTH_MILES, + LENGTH_MILLIMETERS, + LENGTH_YARD, MASS, MASS_GRAMS, MASS_KILOGRAMS, @@ -92,8 +98,8 @@ class UnitSystem: name: str, *, accumulated_precipitation: str, + conversions: dict[tuple[str | None, str | None], str], length: str, - length_conversions: dict[str | None, str], mass: str, pressure: str, temperature: str, @@ -126,7 +132,7 @@ class UnitSystem: self.pressure_unit = pressure self.volume_unit = volume self.wind_speed_unit = wind_speed - self._length_conversions = length_conversions + self._conversions = conversions @property def name(self) -> str: @@ -226,10 +232,7 @@ class UnitSystem: original_unit: str | None, ) -> str | None: """Return converted unit given a device class or an original unit.""" - if device_class == "distance": - return self._length_conversions.get(original_unit) - - return None + return self._conversions.get((device_class, original_unit)) def get_unit_system(key: str) -> UnitSystem: @@ -259,8 +262,14 @@ validate_unit_system = vol.All( METRIC_SYSTEM = UnitSystem( _CONF_UNIT_SYSTEM_METRIC, accumulated_precipitation=PRECIPITATION_MILLIMETERS, + conversions={ + # Convert non-metric distances + ("distance", LENGTH_FEET): LENGTH_METERS, + ("distance", LENGTH_INCHES): LENGTH_MILLIMETERS, + ("distance", LENGTH_MILES): LENGTH_KILOMETERS, + ("distance", LENGTH_YARD): LENGTH_METERS, + }, length=LENGTH_KILOMETERS, - length_conversions={LENGTH_MILES: LENGTH_KILOMETERS}, mass=MASS_GRAMS, pressure=PRESSURE_PA, temperature=TEMP_CELSIUS, @@ -271,8 +280,14 @@ METRIC_SYSTEM = UnitSystem( US_CUSTOMARY_SYSTEM = UnitSystem( _CONF_UNIT_SYSTEM_US_CUSTOMARY, accumulated_precipitation=PRECIPITATION_INCHES, + conversions={ + # Convert non-USCS distances + ("distance", LENGTH_CENTIMETERS): LENGTH_INCHES, + ("distance", LENGTH_KILOMETERS): LENGTH_MILES, + ("distance", LENGTH_METERS): LENGTH_FEET, + ("distance", LENGTH_MILLIMETERS): LENGTH_INCHES, + }, length=LENGTH_MILES, - length_conversions={LENGTH_KILOMETERS: LENGTH_MILES}, mass=MASS_POUNDS, pressure=PRESSURE_PSI, temperature=TEMP_FAHRENHEIT, diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index 28130bdb3bf..e42f001818b 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -44,8 +44,8 @@ def _set_up_units(hass): hass.config.units = UnitSystem( "custom", accumulated_precipitation=LENGTH_MILLIMETERS, + conversions={}, length=LENGTH_METERS, - length_conversions={}, mass=MASS_GRAMS, pressure=PRESSURE_PA, temperature=TEMP_CELSIUS, diff --git a/tests/util/test_unit_system.py b/tests/util/test_unit_system.py index 6734abba7ac..dd584a8dd3b 100644 --- a/tests/util/test_unit_system.py +++ b/tests/util/test_unit_system.py @@ -4,9 +4,14 @@ import pytest from homeassistant.const import ( ACCUMULATED_PRECIPITATION, LENGTH, + LENGTH_CENTIMETERS, + LENGTH_FEET, + LENGTH_INCHES, LENGTH_KILOMETERS, LENGTH_METERS, + LENGTH_MILES, LENGTH_MILLIMETERS, + LENGTH_YARD, MASS, MASS_GRAMS, PRESSURE, @@ -40,8 +45,8 @@ def test_invalid_units(): UnitSystem( SYSTEM_NAME, accumulated_precipitation=LENGTH_MILLIMETERS, + conversions={}, length=LENGTH_METERS, - length_conversions={}, mass=MASS_GRAMS, pressure=PRESSURE_PA, temperature=INVALID_UNIT, @@ -53,8 +58,8 @@ def test_invalid_units(): UnitSystem( SYSTEM_NAME, accumulated_precipitation=LENGTH_MILLIMETERS, + conversions={}, length=INVALID_UNIT, - length_conversions={}, mass=MASS_GRAMS, pressure=PRESSURE_PA, temperature=TEMP_CELSIUS, @@ -66,8 +71,8 @@ def test_invalid_units(): UnitSystem( SYSTEM_NAME, accumulated_precipitation=LENGTH_MILLIMETERS, + conversions={}, length=LENGTH_METERS, - length_conversions={}, mass=MASS_GRAMS, pressure=PRESSURE_PA, temperature=TEMP_CELSIUS, @@ -79,8 +84,8 @@ def test_invalid_units(): UnitSystem( SYSTEM_NAME, accumulated_precipitation=LENGTH_MILLIMETERS, + conversions={}, length=LENGTH_METERS, - length_conversions={}, mass=MASS_GRAMS, pressure=PRESSURE_PA, temperature=TEMP_CELSIUS, @@ -92,8 +97,8 @@ def test_invalid_units(): UnitSystem( SYSTEM_NAME, accumulated_precipitation=LENGTH_MILLIMETERS, + conversions={}, length=LENGTH_METERS, - length_conversions={}, mass=INVALID_UNIT, pressure=PRESSURE_PA, temperature=TEMP_CELSIUS, @@ -105,8 +110,8 @@ def test_invalid_units(): UnitSystem( SYSTEM_NAME, accumulated_precipitation=LENGTH_MILLIMETERS, + conversions={}, length=LENGTH_METERS, - length_conversions={}, mass=MASS_GRAMS, pressure=INVALID_UNIT, temperature=TEMP_CELSIUS, @@ -118,8 +123,8 @@ def test_invalid_units(): UnitSystem( SYSTEM_NAME, accumulated_precipitation=INVALID_UNIT, + conversions={}, length=LENGTH_METERS, - length_conversions={}, mass=MASS_GRAMS, pressure=PRESSURE_PA, temperature=TEMP_CELSIUS, @@ -374,3 +379,27 @@ def test_get_unit_system_invalid(key: str) -> None: """Test get_unit_system with an invalid key.""" with pytest.raises(ValueError, match=f"`{key}` is not a valid unit system key"): _ = get_unit_system(key) + + +@pytest.mark.parametrize( + "unit_system, device_class, original_unit, state_unit", + ( + (METRIC_SYSTEM, "distance", LENGTH_FEET, LENGTH_METERS), + (METRIC_SYSTEM, "distance", LENGTH_INCHES, LENGTH_MILLIMETERS), + (METRIC_SYSTEM, "distance", LENGTH_MILES, LENGTH_KILOMETERS), + (METRIC_SYSTEM, "distance", LENGTH_YARD, LENGTH_METERS), + (METRIC_SYSTEM, "distance", LENGTH_KILOMETERS, None), + (METRIC_SYSTEM, "distance", "very_long", None), + (US_CUSTOMARY_SYSTEM, "distance", LENGTH_CENTIMETERS, LENGTH_INCHES), + (US_CUSTOMARY_SYSTEM, "distance", LENGTH_KILOMETERS, LENGTH_MILES), + (US_CUSTOMARY_SYSTEM, "distance", LENGTH_METERS, LENGTH_FEET), + (US_CUSTOMARY_SYSTEM, "distance", LENGTH_MILLIMETERS, LENGTH_INCHES), + (US_CUSTOMARY_SYSTEM, "distance", LENGTH_MILES, None), + (US_CUSTOMARY_SYSTEM, "distance", "very_long", None), + ), +) +def test_get_converted_unit( + unit_system, device_class, original_unit, state_unit +) -> None: + """Test unit conversion rules.""" + assert unit_system.get_converted_unit(device_class, original_unit) == state_unit