Skip to content

Commit

Permalink
Differentiate between accumulated precipitation and precipitation rat…
Browse files Browse the repository at this point in the history
…e conversions (#323)
  • Loading branch information
bachya authored Oct 14, 2022
1 parent da80d69 commit 6e9eaec
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 38 deletions.
3 changes: 2 additions & 1 deletion ecowitt2mqtt/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,10 @@
UNIT_SYSTEMS: Final = [UNIT_SYSTEM_IMPERIAL, UNIT_SYSTEM_METRIC]

# Unit classes:
ACCUMULATED_PRECIPITATION: Final = "accumulated_precipitation"
DISTANCE: Final = "length"
ILLUMINANCE: Final = "illuminance"
PRECIPITATION: Final = "precipitation"
PRECIPITATION_RATE: Final = "precipitation_rate"
PRESSURE: Final = "pressure"
SPEED: Final = "speed"
TEMPERATURE: Final = "temperature"
Expand Down
32 changes: 22 additions & 10 deletions ecowitt2mqtt/util/unit_conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import math

from ecowitt2mqtt.const import (
ACCUMULATED_PRECIPITATION,
DISTANCE,
ILLUMINANCE,
ILLUMINANCE_FOOT_CANDLES,
Expand All @@ -19,11 +20,11 @@
LENGTH_MILES,
LENGTH_MILLIMETERS,
LENGTH_YARD,
PRECIPITATION,
PRECIPITATION_INCHES,
PRECIPITATION_INCHES_PER_HOUR,
PRECIPITATION_MILLIMETERS,
PRECIPITATION_MILLIMETERS_PER_HOUR,
PRECIPITATION_RATE,
PRESSURE,
PRESSURE_BAR,
PRESSURE_CBAR,
Expand Down Expand Up @@ -138,6 +139,22 @@ def get_unit_ratio(cls, from_unit: str, to_unit: str) -> float:
return cls._UNIT_CONVERSION[from_unit] / cls._UNIT_CONVERSION[to_unit]


class AccumulatedPrecipitationConverter(BaseUnitConverter):
"""Utility to convert accumulated precipitation values."""

UNIT_CLASS = ACCUMULATED_PRECIPITATION
VALID_UNITS = {
PRECIPITATION_MILLIMETERS,
PRECIPITATION_INCHES,
}
NORMALIZED_UNIT = PRECIPITATION_MILLIMETERS

_UNIT_CONVERSION = {
PRECIPITATION_INCHES: 1 * _MM_TO_M / _IN_TO_M,
PRECIPITATION_MILLIMETERS: 1,
}


class DistanceConverter(BaseUnitConverter):
"""Utility to convert distance values."""

Expand Down Expand Up @@ -188,23 +205,18 @@ class IlluminanceConverter(BaseUnitConverter):
}


class PrecipitationConverter(BaseUnitConverter):
"""Utility to convert precipitation values."""
class PrecipitationRateConverter(BaseUnitConverter):
"""Utility to convert precipitation rate values."""

UNIT_CLASS = PRECIPITATION
UNIT_CLASS = PRECIPITATION_RATE
VALID_UNITS = {
PRECIPITATION_MILLIMETERS,
PRECIPITATION_MILLIMETERS_PER_HOUR,
PRECIPITATION_INCHES,
PRECIPITATION_INCHES_PER_HOUR,
}
# Note that we can accept either mm or mm/h as the normalized unit:
NORMALIZED_UNIT = PRECIPITATION_MILLIMETERS
NORMALIZED_UNIT = PRECIPITATION_MILLIMETERS_PER_HOUR

_UNIT_CONVERSION = {
PRECIPITATION_INCHES: 1 * _MM_TO_M / _IN_TO_M,
PRECIPITATION_INCHES_PER_HOUR: 1 * _MM_TO_M / _IN_TO_M,
PRECIPITATION_MILLIMETERS: 1,
PRECIPITATION_MILLIMETERS_PER_HOUR: 1,
}

Expand Down
72 changes: 45 additions & 27 deletions tests/util/test_unit_conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
import pytest

from ecowitt2mqtt.util.unit_conversion import (
AccumulatedPrecipitationConverter,
DistanceConverter,
IlluminanceConverter,
PrecipitationConverter,
PrecipitationRateConverter,
PressureConverter,
SpeedConverter,
TemperatureConverter,
Expand All @@ -14,29 +15,21 @@


@pytest.mark.parametrize(
"unit_class,converter,from_unit,to_unit",
"value,from_unit,to_unit,converted_value",
[
("distance", DistanceConverter, "miles", "ft"),
("distance", DistanceConverter, "m", "dm"),
("illuminance", IlluminanceConverter, "lux", "bulbs"),
("illuminance", IlluminanceConverter, "sunbeams", "klux"),
("precipitation", PrecipitationConverter, "mm/s", "mm/h"),
("precipitation", PrecipitationConverter, "in/h", "yd/yr"),
("pressure", PressureConverter, "hPa", "hPa/s"),
("pressure", PressureConverter, "units", "hPa"),
("speed", SpeedConverter, "mph", "km/s"),
("speed", SpeedConverter, "km/d", "m/s"),
("temperature", TemperatureConverter, "°C", "Bolts"),
("temperature", TemperatureConverter, "Fake", "°C"),
("volume", VolumeConverter, "g/m³", "sparrows"),
("volume", VolumeConverter, "g/km³", "lbs/ft³"),
(10, "mm", "mm", 10.0),
(10, "in", "mm", 254.0),
(10, "mm", "in", 0.39370078740157477),
],
)
def test_invalid_units(converter, from_unit, to_unit, unit_class):
"""Test that invalid units raise an error."""
with pytest.raises(UnitConversionError) as err:
_ = converter.convert(10, from_unit, to_unit)
assert f"is not a recognized {unit_class} unit" in str(err)
def test_accumulated_precipitation_conversion(
converted_value, from_unit, to_unit, value
):
"""Test accumulated precipitation conversions."""
assert (
AccumulatedPrecipitationConverter.convert(value, from_unit, to_unit)
== converted_value
)


@pytest.mark.parametrize(
Expand Down Expand Up @@ -75,20 +68,45 @@ def test_illuminance_conversion(converted_value, from_unit, to_unit, value):
assert IlluminanceConverter.convert(value, from_unit, to_unit) == converted_value


@pytest.mark.parametrize(
"unit_class,converter,from_unit,to_unit",
[
("accumulated_precipitation", AccumulatedPrecipitationConverter, "in", "yd"),
("accumulated_precipitation", AccumulatedPrecipitationConverter, "mm", "dm"),
("distance", DistanceConverter, "m", "dm"),
("distance", DistanceConverter, "miles", "ft"),
("illuminance", IlluminanceConverter, "lux", "bulbs"),
("illuminance", IlluminanceConverter, "sunbeams", "klux"),
("pressure", PressureConverter, "hPa", "hPa/s"),
("pressure", PressureConverter, "units", "hPa"),
("speed", SpeedConverter, "km/d", "m/s"),
("speed", SpeedConverter, "mph", "km/s"),
("temperature", TemperatureConverter, "Fake", "°C"),
("temperature", TemperatureConverter, "°C", "Bolts"),
("volume", VolumeConverter, "g/km³", "lbs/ft³"),
("volume", VolumeConverter, "g/m³", "sparrows"),
],
)
def test_invalid_units(converter, from_unit, to_unit, unit_class):
"""Test that invalid units raise an error."""
with pytest.raises(UnitConversionError) as err:
_ = converter.convert(10, from_unit, to_unit)
assert f"is not a recognized {unit_class} unit" in str(err)


@pytest.mark.parametrize(
"value,from_unit,to_unit,converted_value",
[
(10, "mm", "mm", 10.0),
(10, "in", "mm", 254.0),
(10, "mm", "in", 0.39370078740157477),
(10, "mm/h", "mm/h", 10.0),
(10, "in/h", "mm/h", 254.0),
(10, "mm/h", "in/h", 0.39370078740157477),
],
)
def test_precipitation_conversion(converted_value, from_unit, to_unit, value):
"""Test precipitation conversions."""
assert PrecipitationConverter.convert(value, from_unit, to_unit) == converted_value
def test_precipitation_rate_conversion(converted_value, from_unit, to_unit, value):
"""Test precipitation rate conversions."""
assert (
PrecipitationRateConverter.convert(value, from_unit, to_unit) == converted_value
)


@pytest.mark.parametrize(
Expand Down

0 comments on commit 6e9eaec

Please sign in to comment.