Fix pressure in dark sky and openweathermap and add pressure utility (#21210)

This commit is contained in:
MatthewFlamm 2019-03-24 13:37:31 -04:00 committed by Sebastian Muszynski
parent 6988fe783c
commit ed93c3b2c1
8 changed files with 212 additions and 36 deletions

View File

@ -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):

View File

@ -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):

View File

@ -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

View 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]

View File

@ -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)

View File

@ -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):

View 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)

View File

@ -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."""