mirror of
https://github.com/home-assistant/core.git
synced 2025-04-25 01:38:02 +00:00
Fix pressure in dark sky and openweathermap and add pressure utility (#21210)
This commit is contained in:
parent
6988fe783c
commit
ed93c3b2c1
@ -12,10 +12,10 @@ from homeassistant.components.weather import (
|
||||
ATTR_FORECAST_WIND_SPEED, PLATFORM_SCHEMA, WeatherEntity)
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_MODE, CONF_NAME,
|
||||
TEMP_CELSIUS, TEMP_FAHRENHEIT)
|
||||
PRESSURE_HPA, PRESSURE_INHG, TEMP_CELSIUS, TEMP_FAHRENHEIT)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
from homeassistant.util.pressure import convert as convert_pressure
|
||||
REQUIREMENTS = ['python-forecastio==1.4.0']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -131,7 +131,11 @@ class DarkSkyWeather(WeatherEntity):
|
||||
@property
|
||||
def pressure(self):
|
||||
"""Return the pressure."""
|
||||
return self._ds_currently.get('pressure')
|
||||
pressure = self._ds_currently.get('pressure')
|
||||
if 'us' in self._dark_sky.units:
|
||||
return round(
|
||||
convert_pressure(pressure, PRESSURE_HPA, PRESSURE_INHG), 2)
|
||||
return pressure
|
||||
|
||||
@property
|
||||
def visibility(self):
|
||||
|
@ -10,10 +10,10 @@ from homeassistant.components.weather import (
|
||||
ATTR_FORECAST_WIND_SPEED, PLATFORM_SCHEMA, WeatherEntity)
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_MODE, CONF_NAME,
|
||||
STATE_UNKNOWN, TEMP_CELSIUS)
|
||||
PRESSURE_HPA, PRESSURE_INHG, STATE_UNKNOWN, TEMP_CELSIUS)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
from homeassistant.util.pressure import convert as convert_pressure
|
||||
REQUIREMENTS = ['pyowm==2.10.0']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -114,7 +114,11 @@ class OpenWeatherMapWeather(WeatherEntity):
|
||||
@property
|
||||
def pressure(self):
|
||||
"""Return the pressure."""
|
||||
return self.data.get_pressure().get('press')
|
||||
pressure = self.data.get_pressure().get('press')
|
||||
if self.hass.config.units.name == 'imperial':
|
||||
return round(
|
||||
convert_pressure(pressure, PRESSURE_HPA, PRESSURE_INHG), 2)
|
||||
return pressure
|
||||
|
||||
@property
|
||||
def humidity(self):
|
||||
|
@ -343,6 +343,13 @@ LENGTH_FEET = 'ft' # type: str
|
||||
LENGTH_YARD = 'yd' # type: str
|
||||
LENGTH_MILES = 'mi' # type: str
|
||||
|
||||
# Pressure units
|
||||
PRESSURE_PA = 'Pa' # type: str
|
||||
PRESSURE_HPA = 'hPa' # type: str
|
||||
PRESSURE_MBAR = 'mbar' # type: str
|
||||
PRESSURE_INHG = 'inHg' # type: str
|
||||
PRESSURE_PSI = 'psi' # type: str
|
||||
|
||||
# Volume units
|
||||
VOLUME_LITERS = 'L' # type: str
|
||||
VOLUME_MILLILITERS = 'mL' # type: str
|
||||
@ -455,6 +462,7 @@ UNIT_NOT_RECOGNIZED_TEMPLATE = '{} is not a recognized {} unit.' # type: str
|
||||
|
||||
LENGTH = 'length' # type: str
|
||||
MASS = 'mass' # type: str
|
||||
PRESSURE = 'pressure' # type: str
|
||||
VOLUME = 'volume' # type: str
|
||||
TEMPERATURE = 'temperature' # type: str
|
||||
SPEED_MS = 'speed_ms' # type: str
|
||||
|
51
homeassistant/util/pressure.py
Normal file
51
homeassistant/util/pressure.py
Normal file
@ -0,0 +1,51 @@
|
||||
"""Pressure util functions."""
|
||||
|
||||
import logging
|
||||
from numbers import Number
|
||||
|
||||
from homeassistant.const import (
|
||||
PRESSURE_PA,
|
||||
PRESSURE_HPA,
|
||||
PRESSURE_MBAR,
|
||||
PRESSURE_INHG,
|
||||
PRESSURE_PSI,
|
||||
UNIT_NOT_RECOGNIZED_TEMPLATE,
|
||||
PRESSURE,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
VALID_UNITS = [
|
||||
PRESSURE_PA,
|
||||
PRESSURE_HPA,
|
||||
PRESSURE_MBAR,
|
||||
PRESSURE_INHG,
|
||||
PRESSURE_PSI,
|
||||
]
|
||||
|
||||
UNIT_CONVERSION = {
|
||||
PRESSURE_PA: 1,
|
||||
PRESSURE_HPA: 1 / 100,
|
||||
PRESSURE_MBAR: 1 / 100,
|
||||
PRESSURE_INHG: 1 / 3386.389,
|
||||
PRESSURE_PSI: 1 / 6894.757,
|
||||
}
|
||||
|
||||
|
||||
def convert(value: float, unit_1: str, unit_2: str) -> float:
|
||||
"""Convert one unit of measurement to another."""
|
||||
if unit_1 not in VALID_UNITS:
|
||||
raise ValueError(
|
||||
UNIT_NOT_RECOGNIZED_TEMPLATE.format(unit_1, PRESSURE))
|
||||
if unit_2 not in VALID_UNITS:
|
||||
raise ValueError(
|
||||
UNIT_NOT_RECOGNIZED_TEMPLATE.format(unit_2, PRESSURE))
|
||||
|
||||
if not isinstance(value, Number):
|
||||
raise TypeError('{} is not of numeric type'.format(value))
|
||||
|
||||
if unit_1 == unit_2 or unit_1 not in VALID_UNITS:
|
||||
return value
|
||||
|
||||
pascals = value / UNIT_CONVERSION[unit_1]
|
||||
return pascals * UNIT_CONVERSION[unit_2]
|
@ -5,27 +5,19 @@ from typing import Optional
|
||||
from numbers import Number
|
||||
|
||||
from homeassistant.const import (
|
||||
TEMP_CELSIUS, TEMP_FAHRENHEIT, LENGTH_CENTIMETERS, LENGTH_METERS,
|
||||
LENGTH_KILOMETERS, LENGTH_INCHES, LENGTH_FEET, LENGTH_YARD, LENGTH_MILES,
|
||||
VOLUME_LITERS, VOLUME_MILLILITERS, VOLUME_GALLONS, VOLUME_FLUID_OUNCE,
|
||||
TEMP_CELSIUS, TEMP_FAHRENHEIT, LENGTH_MILES, LENGTH_KILOMETERS,
|
||||
PRESSURE_PA, PRESSURE_PSI, VOLUME_LITERS, VOLUME_GALLONS,
|
||||
MASS_GRAMS, MASS_KILOGRAMS, MASS_OUNCES, MASS_POUNDS,
|
||||
CONF_UNIT_SYSTEM_METRIC, CONF_UNIT_SYSTEM_IMPERIAL, LENGTH, MASS, VOLUME,
|
||||
TEMPERATURE, UNIT_NOT_RECOGNIZED_TEMPLATE)
|
||||
CONF_UNIT_SYSTEM_METRIC, CONF_UNIT_SYSTEM_IMPERIAL, LENGTH, MASS, PRESSURE,
|
||||
VOLUME, TEMPERATURE, UNIT_NOT_RECOGNIZED_TEMPLATE)
|
||||
from homeassistant.util import temperature as temperature_util
|
||||
from homeassistant.util import distance as distance_util
|
||||
from homeassistant.util import pressure as pressure_util
|
||||
from homeassistant.util import volume as volume_util
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
LENGTH_UNITS = [
|
||||
LENGTH_MILES,
|
||||
LENGTH_YARD,
|
||||
LENGTH_FEET,
|
||||
LENGTH_INCHES,
|
||||
LENGTH_KILOMETERS,
|
||||
LENGTH_METERS,
|
||||
LENGTH_CENTIMETERS,
|
||||
]
|
||||
LENGTH_UNITS = distance_util.VALID_UNITS
|
||||
|
||||
MASS_UNITS = [
|
||||
MASS_POUNDS,
|
||||
@ -34,12 +26,9 @@ MASS_UNITS = [
|
||||
MASS_GRAMS,
|
||||
]
|
||||
|
||||
VOLUME_UNITS = [
|
||||
VOLUME_GALLONS,
|
||||
VOLUME_FLUID_OUNCE,
|
||||
VOLUME_LITERS,
|
||||
VOLUME_MILLILITERS,
|
||||
]
|
||||
PRESSURE_UNITS = pressure_util.VALID_UNITS
|
||||
|
||||
VOLUME_UNITS = volume_util.VALID_UNITS
|
||||
|
||||
TEMPERATURE_UNITS = [
|
||||
TEMP_FAHRENHEIT,
|
||||
@ -57,6 +46,8 @@ def is_valid_unit(unit: str, unit_type: str) -> bool:
|
||||
units = MASS_UNITS
|
||||
elif unit_type == VOLUME:
|
||||
units = VOLUME_UNITS
|
||||
elif unit_type == PRESSURE:
|
||||
units = PRESSURE_UNITS
|
||||
else:
|
||||
return False
|
||||
|
||||
@ -67,7 +58,7 @@ class UnitSystem:
|
||||
"""A container for units of measure."""
|
||||
|
||||
def __init__(self, name: str, temperature: str, length: str,
|
||||
volume: str, mass: str) -> None:
|
||||
volume: str, mass: str, pressure: str) -> None:
|
||||
"""Initialize the unit system object."""
|
||||
errors = \
|
||||
', '.join(UNIT_NOT_RECOGNIZED_TEMPLATE.format(unit, unit_type)
|
||||
@ -75,7 +66,8 @@ class UnitSystem:
|
||||
(temperature, TEMPERATURE),
|
||||
(length, LENGTH),
|
||||
(volume, VOLUME),
|
||||
(mass, MASS), ]
|
||||
(mass, MASS),
|
||||
(pressure, PRESSURE), ]
|
||||
if not is_valid_unit(unit, unit_type)) # type: str
|
||||
|
||||
if errors:
|
||||
@ -85,6 +77,7 @@ class UnitSystem:
|
||||
self.temperature_unit = temperature
|
||||
self.length_unit = length
|
||||
self.mass_unit = mass
|
||||
self.pressure_unit = pressure
|
||||
self.volume_unit = volume
|
||||
|
||||
@property
|
||||
@ -109,6 +102,14 @@ class UnitSystem:
|
||||
return distance_util.convert(length, from_unit,
|
||||
self.length_unit)
|
||||
|
||||
def pressure(self, pressure: Optional[float], from_unit: str) -> float:
|
||||
"""Convert the given pressure to this unit system."""
|
||||
if not isinstance(pressure, Number):
|
||||
raise TypeError('{} is not a numeric value.'.format(str(pressure)))
|
||||
|
||||
return pressure_util.convert(pressure, from_unit,
|
||||
self.pressure_unit)
|
||||
|
||||
def volume(self, volume: Optional[float], from_unit: str) -> float:
|
||||
"""Convert the given volume to this unit system."""
|
||||
if not isinstance(volume, Number):
|
||||
@ -121,13 +122,16 @@ class UnitSystem:
|
||||
return {
|
||||
LENGTH: self.length_unit,
|
||||
MASS: self.mass_unit,
|
||||
PRESSURE: self.pressure_unit,
|
||||
TEMPERATURE: self.temperature_unit,
|
||||
VOLUME: self.volume_unit
|
||||
}
|
||||
|
||||
|
||||
METRIC_SYSTEM = UnitSystem(CONF_UNIT_SYSTEM_METRIC, TEMP_CELSIUS,
|
||||
LENGTH_KILOMETERS, VOLUME_LITERS, MASS_GRAMS)
|
||||
LENGTH_KILOMETERS, VOLUME_LITERS, MASS_GRAMS,
|
||||
PRESSURE_PA)
|
||||
|
||||
IMPERIAL_SYSTEM = UnitSystem(CONF_UNIT_SYSTEM_IMPERIAL, TEMP_FAHRENHEIT,
|
||||
LENGTH_MILES, VOLUME_GALLONS, MASS_POUNDS)
|
||||
LENGTH_MILES, VOLUME_GALLONS, MASS_POUNDS,
|
||||
PRESSURE_PSI)
|
||||
|
@ -15,6 +15,7 @@ from homeassistant.const import (
|
||||
LENGTH_METERS,
|
||||
TEMP_CELSIUS,
|
||||
MASS_GRAMS,
|
||||
PRESSURE_PA,
|
||||
VOLUME_LITERS,
|
||||
MATCH_ALL,
|
||||
)
|
||||
@ -33,7 +34,7 @@ class TestHelpersTemplate(unittest.TestCase):
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.units = UnitSystem('custom', TEMP_CELSIUS,
|
||||
LENGTH_METERS, VOLUME_LITERS,
|
||||
MASS_GRAMS)
|
||||
MASS_GRAMS, PRESSURE_PA)
|
||||
|
||||
# pylint: disable=invalid-name
|
||||
def tearDown(self):
|
||||
|
66
tests/util/test_pressure.py
Normal file
66
tests/util/test_pressure.py
Normal file
@ -0,0 +1,66 @@
|
||||
"""Test homeassistant pressure utility functions."""
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
from homeassistant.const import (PRESSURE_PA, PRESSURE_HPA, PRESSURE_MBAR,
|
||||
PRESSURE_INHG, PRESSURE_PSI)
|
||||
import homeassistant.util.pressure as pressure_util
|
||||
|
||||
INVALID_SYMBOL = 'bob'
|
||||
VALID_SYMBOL = PRESSURE_PA
|
||||
|
||||
|
||||
class TestPressureUtil(unittest.TestCase):
|
||||
"""Test the pressure utility functions."""
|
||||
|
||||
def test_convert_same_unit(self):
|
||||
"""Test conversion from any unit to same unit."""
|
||||
assert pressure_util.convert(2, PRESSURE_PA, PRESSURE_PA) == 2
|
||||
assert pressure_util.convert(3, PRESSURE_HPA, PRESSURE_HPA) == 3
|
||||
assert pressure_util.convert(4, PRESSURE_MBAR, PRESSURE_MBAR) == 4
|
||||
assert pressure_util.convert(5, PRESSURE_INHG, PRESSURE_INHG) == 5
|
||||
|
||||
def test_convert_invalid_unit(self):
|
||||
"""Test exception is thrown for invalid units."""
|
||||
with pytest.raises(ValueError):
|
||||
pressure_util.convert(5, INVALID_SYMBOL, VALID_SYMBOL)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
pressure_util.convert(5, VALID_SYMBOL, INVALID_SYMBOL)
|
||||
|
||||
def test_convert_nonnumeric_value(self):
|
||||
"""Test exception is thrown for nonnumeric type."""
|
||||
with pytest.raises(TypeError):
|
||||
pressure_util.convert('a', PRESSURE_HPA, PRESSURE_INHG)
|
||||
|
||||
def test_convert_from_hpascals(self):
|
||||
"""Test conversion from hPA to other units."""
|
||||
hpascals = 1000
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(hpascals, PRESSURE_HPA, PRESSURE_PSI),
|
||||
14.5037743897)
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(hpascals, PRESSURE_HPA, PRESSURE_INHG),
|
||||
29.5299801647)
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(hpascals, PRESSURE_HPA, PRESSURE_PA),
|
||||
100000)
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(hpascals, PRESSURE_HPA, PRESSURE_MBAR),
|
||||
1000)
|
||||
|
||||
def test_convert_from_inhg(self):
|
||||
"""Test conversion from inHg to other units."""
|
||||
inhg = 30
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(inhg, PRESSURE_INHG, PRESSURE_PSI),
|
||||
14.7346266155)
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(inhg, PRESSURE_INHG, PRESSURE_HPA),
|
||||
1015.9167)
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(inhg, PRESSURE_INHG, PRESSURE_PA),
|
||||
101591.67)
|
||||
self.assertAlmostEqual(
|
||||
pressure_util.convert(inhg, PRESSURE_INHG, PRESSURE_MBAR),
|
||||
1015.9167)
|
@ -10,10 +10,12 @@ from homeassistant.const import (
|
||||
LENGTH_METERS,
|
||||
LENGTH_KILOMETERS,
|
||||
MASS_GRAMS,
|
||||
PRESSURE_PA,
|
||||
VOLUME_LITERS,
|
||||
TEMP_CELSIUS,
|
||||
LENGTH,
|
||||
MASS,
|
||||
PRESSURE,
|
||||
TEMPERATURE,
|
||||
VOLUME
|
||||
)
|
||||
@ -30,19 +32,23 @@ class TestUnitSystem(unittest.TestCase):
|
||||
"""Test errors are raised when invalid units are passed in."""
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, INVALID_UNIT, LENGTH_METERS, VOLUME_LITERS,
|
||||
MASS_GRAMS)
|
||||
MASS_GRAMS, PRESSURE_PA)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, INVALID_UNIT, VOLUME_LITERS,
|
||||
MASS_GRAMS)
|
||||
MASS_GRAMS, PRESSURE_PA)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, LENGTH_METERS, INVALID_UNIT,
|
||||
MASS_GRAMS)
|
||||
MASS_GRAMS, PRESSURE_PA)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, LENGTH_METERS, VOLUME_LITERS,
|
||||
INVALID_UNIT)
|
||||
INVALID_UNIT, PRESSURE_PA)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, LENGTH_METERS, VOLUME_LITERS,
|
||||
MASS_GRAMS, INVALID_UNIT)
|
||||
|
||||
def test_invalid_value(self):
|
||||
"""Test no conversion happens if value is non-numeric."""
|
||||
@ -50,6 +56,10 @@ class TestUnitSystem(unittest.TestCase):
|
||||
METRIC_SYSTEM.length('25a', LENGTH_KILOMETERS)
|
||||
with pytest.raises(TypeError):
|
||||
METRIC_SYSTEM.temperature('50K', TEMP_CELSIUS)
|
||||
with pytest.raises(TypeError):
|
||||
METRIC_SYSTEM.volume('50L', VOLUME_LITERS)
|
||||
with pytest.raises(TypeError):
|
||||
METRIC_SYSTEM.pressure('50Pa', PRESSURE_PA)
|
||||
|
||||
def test_as_dict(self):
|
||||
"""Test that the as_dict() method returns the expected dictionary."""
|
||||
@ -57,7 +67,8 @@ class TestUnitSystem(unittest.TestCase):
|
||||
LENGTH: LENGTH_KILOMETERS,
|
||||
TEMPERATURE: TEMP_CELSIUS,
|
||||
VOLUME: VOLUME_LITERS,
|
||||
MASS: MASS_GRAMS
|
||||
MASS: MASS_GRAMS,
|
||||
PRESSURE: PRESSURE_PA
|
||||
}
|
||||
|
||||
assert expected == METRIC_SYSTEM.as_dict()
|
||||
@ -108,12 +119,39 @@ class TestUnitSystem(unittest.TestCase):
|
||||
assert 3.106855 == \
|
||||
IMPERIAL_SYSTEM.length(5, METRIC_SYSTEM.length_unit)
|
||||
|
||||
def test_pressure_same_unit(self):
|
||||
"""Test no conversion happens if to unit is same as from unit."""
|
||||
assert 5 == \
|
||||
METRIC_SYSTEM.pressure(5, METRIC_SYSTEM.pressure_unit)
|
||||
|
||||
def test_pressure_unknown_unit(self):
|
||||
"""Test no conversion happens if unknown unit."""
|
||||
with pytest.raises(ValueError):
|
||||
METRIC_SYSTEM.pressure(5, 'K')
|
||||
|
||||
def test_pressure_to_metric(self):
|
||||
"""Test pressure conversion to metric system."""
|
||||
assert 25 == \
|
||||
METRIC_SYSTEM.pressure(25, METRIC_SYSTEM.pressure_unit)
|
||||
self.assertAlmostEqual(
|
||||
METRIC_SYSTEM.pressure(14.7, IMPERIAL_SYSTEM.pressure_unit),
|
||||
101352.932, places=1)
|
||||
|
||||
def test_pressure_to_imperial(self):
|
||||
"""Test pressure conversion to imperial system."""
|
||||
assert 77 == \
|
||||
IMPERIAL_SYSTEM.pressure(77, IMPERIAL_SYSTEM.pressure_unit)
|
||||
self.assertAlmostEqual(
|
||||
IMPERIAL_SYSTEM.pressure(101352.932, METRIC_SYSTEM.pressure_unit),
|
||||
14.7, places=4)
|
||||
|
||||
def test_properties(self):
|
||||
"""Test the unit properties are returned as expected."""
|
||||
assert LENGTH_KILOMETERS == METRIC_SYSTEM.length_unit
|
||||
assert TEMP_CELSIUS == METRIC_SYSTEM.temperature_unit
|
||||
assert MASS_GRAMS == METRIC_SYSTEM.mass_unit
|
||||
assert VOLUME_LITERS == METRIC_SYSTEM.volume_unit
|
||||
assert PRESSURE_PA == METRIC_SYSTEM.pressure_unit
|
||||
|
||||
def test_is_metric(self):
|
||||
"""Test the is metric flag."""
|
||||
|
Loading…
x
Reference in New Issue
Block a user