Merge pull request #2731 from home-assistant/teagan-unit-system

Teagan unit system
This commit is contained in:
Paulus Schoutsen 2016-08-04 22:53:44 -07:00 committed by GitHub
commit d1107a9cf3
40 changed files with 604 additions and 294 deletions

View File

@ -10,8 +10,8 @@ homeassistant:
# Impacts weather/sunrise data
elevation: 665
# C for Celsius, F for Fahrenheit
temperature_unit: C
# 'metric' for Metric System, 'imperial' for imperial system
unit_system: metric
# Pick yours from here:
# http://en.wikipedia.org/wiki/List_of_tz_database_time_zones

View File

@ -419,8 +419,9 @@ definitions:
description: Longitude of Home Assistant server
location_name:
type: string
temperature_unit:
unit_system:
type: string
description: The system for measurement units
time_zone:
type: string
version:

@ -1 +1 @@
Subproject commit cbafbda5fdd2216ab4b6ebd962cbd1164fa8abec
Subproject commit a343d3d098e78976fc66f8ed66ce0ae5d7bc3861

View File

@ -6,13 +6,14 @@ https://home-assistant.io/components/hvac/
"""
import logging
import os
from numbers import Number
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.config import load_yaml_config_file
import homeassistant.util as util
from homeassistant.util.temperature import convert as convert_temperature
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.temperature import convert
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_ON, STATE_OFF, STATE_UNKNOWN,
@ -204,8 +205,8 @@ def setup(hass, config):
return
for hvac in target_hvacs:
hvac.set_temperature(convert(
temperature, hass.config.temperature_unit,
hvac.set_temperature(convert_temperature(
temperature, hass.config.units.temperature_unit,
hvac.unit_of_measurement))
if hvac.should_poll:
@ -462,12 +463,12 @@ class HvacDevice(Entity):
@property
def min_temp(self):
"""Return the minimum temperature."""
return convert(19, TEMP_CELSIUS, self.unit_of_measurement)
return convert_temperature(19, TEMP_CELSIUS, self.unit_of_measurement)
@property
def max_temp(self):
"""Return the maximum temperature."""
return convert(30, TEMP_CELSIUS, self.unit_of_measurement)
return convert_temperature(30, TEMP_CELSIUS, self.unit_of_measurement)
@property
def min_humidity(self):
@ -481,13 +482,13 @@ class HvacDevice(Entity):
def _convert_for_display(self, temp):
"""Convert temperature into preferred units for display purposes."""
if temp is None:
return None
if temp is None or not isinstance(temp, Number):
return temp
value = convert(temp, self.unit_of_measurement,
self.hass.config.temperature_unit)
value = convert_temperature(temp, self.unit_of_measurement,
self.hass.config.units.temperature_unit)
if self.hass.config.temperature_unit is TEMP_CELSIUS:
if self.hass.config.units.temperature_unit is TEMP_CELSIUS:
decimal_count = 1
else:
# Users of fahrenheit generally expect integer units.

View File

@ -10,7 +10,7 @@ import socket
from homeassistant.const import (ATTR_BATTERY_LEVEL, CONF_OPTIMISTIC,
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP,
STATE_OFF, STATE_ON, TEMP_CELSIUS)
STATE_OFF, STATE_ON)
from homeassistant.helpers import validate_config, discovery
CONF_GATEWAYS = 'gateways'
@ -53,7 +53,7 @@ def setup(hass, config): # pylint: disable=too-many-locals
import mysensors.mysensors as mysensors
version = str(config[DOMAIN].get(CONF_VERSION, DEFAULT_VERSION))
is_metric = (hass.config.temperature_unit == TEMP_CELSIUS)
is_metric = hass.config.units.is_metric
persistence = config[DOMAIN].get(CONF_PERSISTENCE, True)
def setup_gateway(device, persistence_file, baud_rate, tcp_port):

View File

@ -27,9 +27,6 @@ DEFAULT_TOLERANCE = 1
# Default zone
DEFAULT_PROXIMITY_ZONE = 'home'
# Default unit of measure
DEFAULT_UNIT_OF_MEASUREMENT = 'km'
# Default distance to zone
DEFAULT_DIST_TO_ZONE = NOT_SET
@ -71,7 +68,7 @@ def setup_proximity_component(hass, config):
# Get the unit of measurement from configuration.yaml.
unit_of_measure = config.get(ATTR_UNIT_OF_MEASUREMENT,
DEFAULT_UNIT_OF_MEASUREMENT)
hass.config.units.length_unit)
zone_id = 'zone.{}'.format(proximity_zone)
state = hass.states.get(zone_id)
@ -216,11 +213,11 @@ class Proximity(Entity): # pylint: disable=too-many-instance-attributes
# Loop through each of the distances collected and work out the
# closest.
closest_device = ''
dist_to_zone = 1000000
closest_device = None # type: str
dist_to_zone = None # type: float
for device in distances_to_zone:
if distances_to_zone[device] < dist_to_zone:
if not dist_to_zone or distances_to_zone[device] < dist_to_zone:
closest_device = device
dist_to_zone = distances_to_zone[device]

View File

@ -10,6 +10,7 @@ from datetime import timedelta
from homeassistant.const import TEMP_FAHRENHEIT
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
from homeassistant.util.temperature import celsius_to_fahrenheit
# Update this requirement to upstream as soon as it supports Python 3.
REQUIREMENTS = ['http://github.com/mala-zaba/Adafruit_Python_DHT/archive/'
@ -32,8 +33,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
# pylint: disable=import-error
import Adafruit_DHT
SENSOR_TYPES['temperature'][1] = hass.config.temperature_unit
unit = hass.config.temperature_unit
SENSOR_TYPES['temperature'][1] = hass.config.units.temperature_unit
available_sensors = {
"DHT11": Adafruit_DHT.DHT11,
"DHT22": Adafruit_DHT.DHT22,
@ -58,7 +58,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
if variable not in SENSOR_TYPES:
_LOGGER.error('Sensor type: "%s" does not exist', variable)
else:
dev.append(DHTSensor(data, variable, unit, name))
dev.append(
DHTSensor(data, variable, SENSOR_TYPES[variable][1], name))
except KeyError:
pass
@ -103,7 +104,8 @@ class DHTSensor(Entity):
if self.type == 'temperature':
self._state = round(data['temperature'], 1)
if self.temp_unit == TEMP_FAHRENHEIT:
self._state = round(data['temperature'] * 1.8 + 32, 1)
self._state = round(celsius_to_fahrenheit(data['temperature']),
1)
elif self.type == 'humidity':
self._state = round(data['humidity'], 1)

View File

@ -10,7 +10,6 @@ import logging
import datetime
import time
from homeassistant.const import TEMP_CELSIUS
from homeassistant.util import Throttle
from homeassistant.helpers.entity import Entity
from homeassistant.loader import get_component
@ -238,8 +237,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
for resource in config.get("monitored_resources",
FITBIT_DEFAULT_RESOURCE_LIST):
dev.append(FitbitSensor(authd_client, config_path, resource,
hass.config.temperature_unit ==
TEMP_CELSIUS))
hass.config.units.is_metric))
add_devices(dev)
else:

View File

@ -10,7 +10,7 @@ from requests.exceptions import ConnectionError as ConnectError, \
HTTPError, Timeout
from homeassistant.components.sensor import DOMAIN
from homeassistant.const import CONF_API_KEY, TEMP_CELSIUS
from homeassistant.const import CONF_API_KEY
from homeassistant.helpers import validate_config
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
@ -62,7 +62,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
if 'units' in config:
units = config['units']
elif hass.config.temperature_unit == TEMP_CELSIUS:
elif hass.config.units.is_metric:
units = 'si'
else:
units = 'us'

View File

@ -11,8 +11,7 @@ import voluptuous as vol
from homeassistant.helpers.entity import Entity
from homeassistant.const import (
CONF_API_KEY, TEMP_CELSIUS, TEMP_FAHRENHEIT,
EVENT_HOMEASSISTANT_START, ATTR_LATITUDE, ATTR_LONGITUDE)
CONF_API_KEY, EVENT_HOMEASSISTANT_START, ATTR_LATITUDE, ATTR_LONGITUDE)
from homeassistant.util import Throttle
import homeassistant.helpers.config_validation as cv
@ -92,10 +91,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
options = config.get(CONF_OPTIONS)
if options.get('units') is None:
if hass.config.temperature_unit is TEMP_CELSIUS:
options['units'] = 'metric'
elif hass.config.temperature_unit is TEMP_FAHRENHEIT:
options['units'] = 'imperial'
options['units'] = hass.config.units.name
travel_mode = config.get(CONF_TRAVEL_MODE)
mode = options.get(CONF_MODE)

View File

@ -65,7 +65,7 @@ class MoldIndicator(Entity):
self._indoor_humidity_sensor = indoor_humidity_sensor
self._outdoor_temp_sensor = outdoor_temp_sensor
self._calib_factor = calib_factor
self._is_metric = (hass.config.temperature_unit == TEMP_CELSIUS)
self._is_metric = hass.config.units.is_metric
self._dewpoint = None
self._indoor_temp = None

View File

@ -48,8 +48,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
from pyowm import OWM
SENSOR_TYPES['temperature'][1] = hass.config.temperature_unit
unit = hass.config.temperature_unit
SENSOR_TYPES['temperature'][1] = hass.config.units.temperature_unit
forecast = config.get('forecast')
owm = OWM(config.get(CONF_API_KEY, None))
@ -67,13 +66,15 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
if variable not in SENSOR_TYPES:
_LOGGER.error('Sensor type: "%s" does not exist', variable)
else:
dev.append(OpenWeatherMapSensor(data, variable, unit))
dev.append(OpenWeatherMapSensor(data, variable,
SENSOR_TYPES[variable][1]))
except KeyError:
pass
if forecast:
SENSOR_TYPES['forecast'] = ['Forecast', None]
dev.append(OpenWeatherMapSensor(data, 'forecast', unit))
dev.append(OpenWeatherMapSensor(data, 'forecast',
SENSOR_TYPES['temperature'][1]))
add_devices(dev)

View File

@ -21,7 +21,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
"""Setup the Temper sensors."""
from temperusb.temper import TemperHandler
temp_unit = hass.config.temperature_unit
temp_unit = hass.config.units.temperature_unit
name = config.get(CONF_NAME, DEVICE_DEFAULT_NAME)
temper_devices = TemperHandler().get_devices()
add_devices_callback([TemperSensor(dev, temp_unit, name + '_' + str(idx))

View File

@ -51,7 +51,8 @@ class VeraSensor(VeraDevice, Entity):
def update(self):
"""Update the state."""
if self.vera_device.category == "Temperature Sensor":
current_temp = self.vera_device.temperature
self.current_value = self.vera_device.temperature
vera_temp_units = (
self.vera_device.vera_controller.temperature_units)
@ -60,14 +61,6 @@ class VeraSensor(VeraDevice, Entity):
else:
self._temperature_units = TEMP_CELSIUS
if self.hass:
temp = self.hass.config.temperature(
current_temp,
self._temperature_units)
current_temp, self._temperature_units = temp
self.current_value = current_temp
elif self.vera_device.category == "Light Sensor":
self.current_value = self.vera_device.light
elif self.vera_device.category == "Humidity Sensor":

View File

@ -45,7 +45,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the Yahoo! weather sensor."""
from yahooweather import get_woeid, UNIT_C, UNIT_F
unit = hass.config.temperature_unit
unit = hass.config.units.temperature_unit
woeid = config.get("woeid", None)
forecast = config.get("forecast", 0)

View File

@ -6,6 +6,7 @@ https://home-assistant.io/components/thermostat/
"""
import logging
import os
from numbers import Number
import voluptuous as vol
@ -13,9 +14,9 @@ from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.config import load_yaml_config_file
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.temperature import convert
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
import homeassistant.helpers.config_validation as cv
from homeassistant.util.temperature import convert
from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_ON, STATE_OFF, STATE_UNKNOWN,
TEMP_CELSIUS)
@ -146,10 +147,11 @@ def setup(hass, config):
temperature = service.data[ATTR_TEMPERATURE]
for thermostat in target_thermostats:
thermostat.set_temperature(convert(
temperature, hass.config.temperature_unit,
thermostat.unit_of_measurement))
converted_temperature = convert(
temperature, hass.config.units.temperature_unit,
thermostat.unit_of_measurement)
thermostat.set_temperature(converted_temperature)
thermostat.update_ha_state(True)
hass.services.register(
@ -310,13 +312,13 @@ class ThermostatDevice(Entity):
def _convert_for_display(self, temp):
"""Convert temperature into preferred units for display purposes."""
if temp is None:
return None
if temp is None or not isinstance(temp, Number):
return temp
value = convert(temp, self.unit_of_measurement,
self.hass.config.temperature_unit)
value = self.hass.config.units.temperature(temp,
self.unit_of_measurement)
if self.hass.config.temperature_unit is TEMP_CELSIUS:
if self.hass.config.units.is_metric:
decimal_count = 1
else:
# Users of fahrenheit generally expect integer units.

View File

@ -8,7 +8,7 @@ import logging
from homeassistant.components.thermostat import ThermostatDevice
from homeassistant.const import TEMP_CELSIUS
from homeassistant.helpers.temperature import convert
from homeassistant.util.temperature import convert
REQUIREMENTS = ['bluepy_devices==0.2.0']

View File

@ -8,12 +8,10 @@ import logging
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
import homeassistant.util as util
from homeassistant.components import switch
from homeassistant.components.thermostat import (
STATE_HEAT, STATE_COOL, STATE_IDLE, ThermostatDevice)
from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT, TEMP_CELSIUS, TEMP_FAHRENHEIT)
from homeassistant.const import ATTR_UNIT_OF_MEASUREMENT
from homeassistant.helpers.event import track_state_change
DEPENDENCIES = ['switch', 'sensor']
@ -75,7 +73,7 @@ class HeatControl(ThermostatDevice):
self._min_temp = min_temp
self._max_temp = max_temp
self._target_temp = target_temp
self._unit = None
self._unit = hass.config.units.temperature_unit
track_state_change(hass, sensor_entity_id, self._sensor_changed)
@ -157,24 +155,11 @@ class HeatControl(ThermostatDevice):
"""Update thermostat with latest state from sensor."""
unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
if unit not in (TEMP_CELSIUS, TEMP_FAHRENHEIT):
self._cur_temp = None
self._unit = None
_LOGGER.error('Sensor has unsupported unit: %s (allowed: %s, %s)',
unit, TEMP_CELSIUS, TEMP_FAHRENHEIT)
return
temp = util.convert(state.state, float)
if temp is None:
self._cur_temp = None
self._unit = None
_LOGGER.error('Unable to parse sensor temperature: %s',
state.state)
return
self._cur_temp = temp
self._unit = unit
try:
self._cur_temp = self.hass.config.units.temperature(
float(state.state), unit)
except ValueError as ex:
_LOGGER.error('Unable to update from sensor: %s', ex)
def _control_heating(self):
"""Check if we need to turn heating on or off."""

View File

@ -7,7 +7,7 @@ https://home-assistant.io/components/thermostat.homematic/
import logging
import homeassistant.components.homematic as homematic
from homeassistant.components.thermostat import ThermostatDevice
from homeassistant.helpers.temperature import convert
from homeassistant.util.temperature import convert
from homeassistant.const import TEMP_CELSIUS, STATE_UNKNOWN
DEPENDENCIES = ['homematic']

View File

@ -7,12 +7,14 @@ from types import MappingProxyType
import voluptuous as vol
from homeassistant.const import (
CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME, CONF_TEMPERATURE_UNIT,
CONF_TIME_ZONE, CONF_CUSTOMIZE, CONF_ELEVATION, TEMP_FAHRENHEIT,
TEMP_CELSIUS, __version__)
CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME, CONF_UNIT_SYSTEM,
CONF_TIME_ZONE, CONF_CUSTOMIZE, CONF_ELEVATION, CONF_UNIT_SYSTEM_METRIC,
CONF_UNIT_SYSTEM_IMPERIAL, CONF_TEMPERATURE_UNIT, TEMP_CELSIUS,
__version__)
from homeassistant.exceptions import HomeAssistantError
from homeassistant.util.yaml import load_yaml
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.unit_system import (IMPERIAL_SYSTEM, METRIC_SYSTEM)
from homeassistant.helpers.entity import valid_entity_id, set_customize
from homeassistant.util import dt as date_util, location as loc_util
@ -30,7 +32,9 @@ DEFAULT_CORE_CONFIG = (
' the sun rises and sets'),
(CONF_LONGITUDE, 0, 'longitude', None),
(CONF_ELEVATION, 0, None, 'Impacts weather/sunrise data'),
(CONF_TEMPERATURE_UNIT, 'C', None, 'C for Celsius, F for Fahrenheit'),
(CONF_UNIT_SYSTEM, CONF_UNIT_SYSTEM_METRIC, None,
'{} for Metric, {} for Imperial'.format(CONF_UNIT_SYSTEM_METRIC,
CONF_UNIT_SYSTEM_IMPERIAL)),
(CONF_TIME_ZONE, 'UTC', 'time_zone', 'Pick yours from here: http://en.wiki'
'pedia.org/wiki/List_of_tz_database_time_zones'),
)
@ -88,7 +92,8 @@ CORE_CONFIG_SCHEMA = vol.Schema({
CONF_LATITUDE: cv.latitude,
CONF_LONGITUDE: cv.longitude,
CONF_ELEVATION: vol.Coerce(int),
CONF_TEMPERATURE_UNIT: cv.temperature_unit,
vol.Optional(CONF_TEMPERATURE_UNIT): cv.temperature_unit,
CONF_UNIT_SYSTEM: cv.unit_system,
CONF_TIME_ZONE: cv.time_zone,
vol.Required(CONF_CUSTOMIZE,
default=MappingProxyType({})): _valid_customize,
@ -131,8 +136,10 @@ def create_default_config(config_dir, detect_location=True):
location_info = detect_location and loc_util.detect_location_info()
if location_info:
if location_info.use_fahrenheit:
info[CONF_TEMPERATURE_UNIT] = 'F'
if location_info.use_metric:
info[CONF_UNIT_SYSTEM] = CONF_UNIT_SYSTEM_METRIC
else:
info[CONF_UNIT_SYSTEM] = CONF_UNIT_SYSTEM_IMPERIAL
for attr, default, prop, _ in DEFAULT_CORE_CONFIG:
if prop is None:
@ -244,18 +251,30 @@ def process_ha_core_config(hass, config):
set_customize(config.get(CONF_CUSTOMIZE) or {})
if CONF_TEMPERATURE_UNIT in config:
hac.temperature_unit = config[CONF_TEMPERATURE_UNIT]
if CONF_UNIT_SYSTEM in config:
if config[CONF_UNIT_SYSTEM] == CONF_UNIT_SYSTEM_IMPERIAL:
hac.units = IMPERIAL_SYSTEM
else:
hac.units = METRIC_SYSTEM
elif CONF_TEMPERATURE_UNIT in config:
unit = config[CONF_TEMPERATURE_UNIT]
if unit == TEMP_CELSIUS:
hac.units = METRIC_SYSTEM
else:
hac.units = IMPERIAL_SYSTEM
_LOGGER.warning("Found deprecated temperature unit in core config, "
"expected unit system. Replace 'temperature: %s' with "
"'unit_system: %s'", unit, hac.units.name)
# Shortcut if no auto-detection necessary
if None not in (hac.latitude, hac.longitude, hac.temperature_unit,
if None not in (hac.latitude, hac.longitude, hac.units,
hac.time_zone, hac.elevation):
return
discovered = []
# If we miss some of the needed values, auto detect them
if None in (hac.latitude, hac.longitude, hac.temperature_unit,
if None in (hac.latitude, hac.longitude, hac.units,
hac.time_zone):
info = loc_util.detect_location_info()
@ -264,18 +283,13 @@ def process_ha_core_config(hass, config):
return
if hac.latitude is None and hac.longitude is None:
hac.latitude = info.latitude
hac.longitude = info.longitude
hac.latitude, hac.longitude = (info.latitude, info.longitude)
discovered.append(('latitude', hac.latitude))
discovered.append(('longitude', hac.longitude))
if hac.temperature_unit is None:
if info.use_fahrenheit:
hac.temperature_unit = TEMP_FAHRENHEIT
discovered.append(('temperature_unit', 'F'))
else:
hac.temperature_unit = TEMP_CELSIUS
discovered.append(('temperature_unit', 'C'))
if hac.units is None:
hac.units = METRIC_SYSTEM if info.use_metric else IMPERIAL_SYSTEM
discovered.append((CONF_UNIT_SYSTEM, hac.units.name))
if hac.location_name is None:
hac.location_name = info.city

View File

@ -47,6 +47,7 @@ CONF_PORT = 'port'
CONF_SCAN_INTERVAL = 'scan_interval'
CONF_STATE = 'state'
CONF_TEMPERATURE_UNIT = 'temperature_unit'
CONF_UNIT_SYSTEM = 'unit_system'
CONF_TIME_ZONE = 'time_zone'
CONF_USERNAME = 'username'
CONF_VALUE_TEMPLATE = 'value_template'
@ -112,11 +113,38 @@ ATTR_ICON = "icon"
# The unit of measurement if applicable
ATTR_UNIT_OF_MEASUREMENT = "unit_of_measurement"
CONF_UNIT_SYSTEM_METRIC = 'metric' # type: str
CONF_UNIT_SYSTEM_IMPERIAL = 'imperial' # type: str
# Temperature attribute
ATTR_TEMPERATURE = "temperature"
TEMP_CELSIUS = "°C"
TEMP_FAHRENHEIT = "°F"
# Length units
LENGTH_CENTIMETERS = "cm" # type: str
LENGTH_METERS = "m" # type: str
LENGTH_KILOMETERS = "km" # type: str
LENGTH_INCHES = "in" # type: str
LENGTH_FEET = "ft" # type: str
LENGTH_YARD = "yd" # type: str
LENGTH_MILES = "mi" # type: str
# Volume units
VOLUME_LITERS = "L" # type: str
VOLUME_MILLILITERS = "mL" # type: str
VOLUME_GALLONS = "gal" # type: str
VOLUME_FLUID_OUNCE = "fl. oz." # type: str
# Mass units
MASS_GRAMS = "g" # type: str
MASS_KILOGRAMS = "kg" # type: str
MASS_OUNCES = "oz" # type: str
MASS_POUNDS = "lb" # type: str
# Contains the information that is discovered
ATTR_DISCOVERED = "discovered"
@ -243,3 +271,10 @@ CONTENT_TYPE_TEXT_PLAIN = 'text/plain'
# The exit code to send to request a restart
RESTART_EXIT_CODE = 100
UNIT_NOT_RECOGNIZED_TEMPLATE = '{} is not a recognized {} unit.' # type: str
LENGTH = 'length' # type: str
MASS = 'mass' # type: str
VOLUME = 'volume' # type: str
TEMPERATURE = 'temperature' # type: str

View File

@ -17,7 +17,6 @@ from types import MappingProxyType
from typing import Any, Callable
import voluptuous as vol
import homeassistant.helpers.temperature as temp_helper
import homeassistant.util as util
import homeassistant.util.dt as dt_util
import homeassistant.util.location as location
@ -28,11 +27,13 @@ from homeassistant.const import (
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
EVENT_SERVICE_EXECUTED, EVENT_SERVICE_REGISTERED, EVENT_STATE_CHANGED,
EVENT_TIME_CHANGED, MATCH_ALL, RESTART_EXIT_CODE,
SERVICE_HOMEASSISTANT_RESTART, SERVICE_HOMEASSISTANT_STOP, TEMP_CELSIUS,
TEMP_FAHRENHEIT, __version__)
SERVICE_HOMEASSISTANT_RESTART, SERVICE_HOMEASSISTANT_STOP, __version__)
from homeassistant.exceptions import (
HomeAssistantError, InvalidEntityFormatError)
from homeassistant.helpers.entity import split_entity_id, valid_entity_id
from homeassistant.helpers.unit_system import (
METRIC_SYSTEM,
)
DOMAIN = "homeassistant"
@ -95,7 +96,7 @@ class HomeAssistant(object):
self.bus = EventBus(pool)
self.services = ServiceRegistry(self.bus, self.add_job)
self.states = StateMachine(self.bus)
self.config = Config()
self.config = Config() # type: Config
self.state = CoreState.not_running
@property
@ -715,9 +716,9 @@ class Config(object):
self.latitude = None
self.longitude = None
self.elevation = None
self.temperature_unit = None
self.location_name = None
self.time_zone = None
self.units = METRIC_SYSTEM
# If True, pip install is skipped for requirements on startup
self.skip_pip = False
@ -731,29 +732,15 @@ class Config(object):
# Directory that holds the configuration
self.config_dir = get_default_config_dir()
def distance(self, lat, lon):
"""Calculate distance from Home Assistant in meters."""
return location.distance(self.latitude, self.longitude, lat, lon)
def distance(self: object, lat: float, lon: float) -> float:
"""Calculate distance from Home Assistant."""
return self.units.length(
location.distance(self.latitude, self.longitude, lat, lon), 'm')
def path(self, *path):
"""Generate path to the file within the config dir."""
return os.path.join(self.config_dir, *path)
def temperature(self, value, unit):
"""Convert temperature to user preferred unit if set."""
if not (unit in (TEMP_CELSIUS, TEMP_FAHRENHEIT) and
self.temperature_unit and unit != self.temperature_unit):
return value, unit
try:
temp = float(value)
except ValueError: # Could not convert value to float
return value, unit
return (
round(temp_helper.convert(temp, unit, self.temperature_unit), 1),
self.temperature_unit)
def as_dict(self):
"""Create a dict representation of this dict."""
time_zone = self.time_zone or dt_util.UTC
@ -761,7 +748,7 @@ class Config(object):
return {
'latitude': self.latitude,
'longitude': self.longitude,
'temperature_unit': self.temperature_unit,
'unit_system': self.units.as_dict(),
'location_name': self.location_name,
'time_zone': time_zone.zone,
'components': self.components,

View File

@ -9,7 +9,7 @@ from homeassistant.const import (
CONF_PLATFORM, CONF_SCAN_INTERVAL, TEMP_CELSIUS, TEMP_FAHRENHEIT,
CONF_ALIAS, CONF_ENTITY_ID, CONF_VALUE_TEMPLATE, WEEKDAYS,
CONF_CONDITION, CONF_BELOW, CONF_ABOVE, SUN_EVENT_SUNSET,
SUN_EVENT_SUNRISE)
SUN_EVENT_SUNRISE, CONF_UNIT_SYSTEM_IMPERIAL, CONF_UNIT_SYSTEM_METRIC)
from homeassistant.helpers.entity import valid_entity_id
import homeassistant.util.dt as dt_util
from homeassistant.util import slugify
@ -226,6 +226,10 @@ def temperature_unit(value):
raise vol.Invalid('invalid temperature unit (expected C or F)')
unit_system = vol.All(vol.Lower, vol.Any(CONF_UNIT_SYSTEM_METRIC,
CONF_UNIT_SYSTEM_IMPERIAL))
def template(value):
"""Validate a jinja2 template."""
if value is None:

View File

@ -199,13 +199,15 @@ class Entity(object):
attr.pop(ATTR_HIDDEN)
# Convert temperature if we detect one
if attr.get(ATTR_UNIT_OF_MEASUREMENT) in (TEMP_CELSIUS,
TEMP_FAHRENHEIT):
state, attr[ATTR_UNIT_OF_MEASUREMENT] = \
self.hass.config.temperature(
state, attr[ATTR_UNIT_OF_MEASUREMENT])
state = str(state)
try:
unit_of_measure = attr.get(ATTR_UNIT_OF_MEASUREMENT)
if unit_of_measure in (TEMP_CELSIUS, TEMP_FAHRENHEIT):
units = self.hass.config.units
state = str(units.temperature(float(state), unit_of_measure))
attr[ATTR_UNIT_OF_MEASUREMENT] = units.temperature_unit
except ValueError:
# Could not convert state to float
pass
return self.hass.states.set(
self.entity_id, state, attr, self.force_update)

View File

@ -1,13 +0,0 @@
"""Methods to help handle temperature in Home Assistant."""
import homeassistant.util.temperature as temp_util
from homeassistant.const import TEMP_CELSIUS
def convert(temperature, unit, to_unit):
"""Convert temperature to correct unit."""
if unit == to_unit or unit is None or to_unit is None:
return temperature
elif unit == TEMP_CELSIUS:
return temp_util.celsius_to_fahrenheit(temperature)
return temp_util.fahrenheit_to_celsius(temperature)

View File

@ -219,7 +219,8 @@ class LocationMethods(object):
if len(locations) == 1:
return self._hass.config.distance(*locations[0])
return loc_util.distance(*locations[0] + locations[1])
return self._hass.config.units.length(
loc_util.distance(*locations[0] + locations[1]), 'm')
def _resolve_state(self, entity_id_or_state):
"""Return state or entity_id if given."""

View File

@ -0,0 +1,125 @@
"""Unit system helper class and methods."""
import logging
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,
MASS_GRAMS, MASS_KILOGRAMS, MASS_OUNCES, MASS_POUNDS,
CONF_UNIT_SYSTEM_METRIC,
CONF_UNIT_SYSTEM_IMPERIAL, LENGTH, MASS, VOLUME, TEMPERATURE,
UNIT_NOT_RECOGNIZED_TEMPLATE)
from homeassistant.util import temperature as temperature_util
from homeassistant.util import distance as distance_util
_LOGGER = logging.getLogger(__name__)
LENGTH_UNITS = [
LENGTH_MILES,
LENGTH_YARD,
LENGTH_FEET,
LENGTH_INCHES,
LENGTH_KILOMETERS,
LENGTH_METERS,
LENGTH_CENTIMETERS,
]
MASS_UNITS = [
MASS_POUNDS,
MASS_OUNCES,
MASS_KILOGRAMS,
MASS_GRAMS,
]
VOLUME_UNITS = [
VOLUME_GALLONS,
VOLUME_FLUID_OUNCE,
VOLUME_LITERS,
VOLUME_MILLILITERS,
]
TEMPERATURE_UNITS = [
TEMP_FAHRENHEIT,
TEMP_CELSIUS,
]
def is_valid_unit(unit: str, unit_type: str) -> bool:
"""Check if the unit is valid for it's type."""
if unit_type == LENGTH:
units = LENGTH_UNITS
elif unit_type == TEMPERATURE:
units = TEMPERATURE_UNITS
elif unit_type == MASS:
units = MASS_UNITS
elif unit_type == VOLUME:
units = VOLUME_UNITS
else:
return False
return unit in units
class UnitSystem(object):
"""A container for units of measure."""
# pylint: disable=too-many-arguments
def __init__(self: object, name: str, temperature: str, length: str,
volume: str, mass: str) -> None:
"""Initialize the unit system object."""
errors = \
', '.join(UNIT_NOT_RECOGNIZED_TEMPLATE.format(unit, unit_type)
for unit, unit_type in [
(temperature, TEMPERATURE),
(length, LENGTH),
(volume, VOLUME),
(mass, MASS), ]
if not is_valid_unit(unit, unit_type)) # type: str
if errors:
raise ValueError(errors)
self.name = name
self.temperature_unit = temperature
self.length_unit = length
self.mass_unit = mass
self.volume_unit = volume
@property
def is_metric(self: object) -> bool:
"""Determine if this is the metric unit system."""
return self.name == CONF_UNIT_SYSTEM_METRIC
def temperature(self: object, temperature: float, from_unit: str) -> float:
"""Convert the given temperature to this unit system."""
if not isinstance(temperature, Number):
raise TypeError(
'{} is not a numeric value.'.format(str(temperature)))
return temperature_util.convert(temperature,
from_unit, self.temperature_unit)
def length(self: object, length: float, from_unit: str) -> float:
"""Convert the given length to this unit system."""
if not isinstance(length, Number):
raise TypeError('{} is not a numeric value.'.format(str(length)))
return distance_util.convert(length, from_unit,
self.length_unit) # type: float
def as_dict(self) -> dict:
"""Convert the unit system to a dictionary."""
return {
LENGTH: self.length_unit,
MASS: self.mass_unit,
TEMPERATURE: self.temperature_unit,
VOLUME: self.volume_unit
}
METRIC_SYSTEM = UnitSystem(CONF_UNIT_SYSTEM_METRIC, TEMP_CELSIUS,
LENGTH_KILOMETERS, VOLUME_LITERS, MASS_GRAMS)
IMPERIAL_SYSTEM = UnitSystem(CONF_UNIT_SYSTEM_IMPERIAL, TEMP_FAHRENHEIT,
LENGTH_MILES, VOLUME_GALLONS, MASS_POUNDS)

View File

@ -3,82 +3,86 @@
import logging
from numbers import Number
from homeassistant.const import (
LENGTH_KILOMETERS,
LENGTH_MILES,
LENGTH_FEET,
LENGTH_METERS,
UNIT_NOT_RECOGNIZED_TEMPLATE,
LENGTH,
)
_LOGGER = logging.getLogger(__name__)
KILOMETERS_SYMBOL = 'km'
METERS_SYMBOL = 'm'
FEET_SYMBOL = 'ft'
MILES_SYMBOL = 'mi'
VALID_UNITS = [
KILOMETERS_SYMBOL,
METERS_SYMBOL,
FEET_SYMBOL,
MILES_SYMBOL,
LENGTH_KILOMETERS,
LENGTH_MILES,
LENGTH_FEET,
LENGTH_METERS,
]
def convert(value, unit_1, unit_2):
def convert(value: float, unit_1: str, unit_2: str) -> float:
"""Convert one unit of measurement to another."""
if not isinstance(value, Number):
raise TypeError(str(value) + ' is not of numeric type')
if unit_1 == unit_2:
return value
if unit_1 not in VALID_UNITS:
_LOGGER.error('Unknown unit of measure: ' + str(unit_1))
raise ValueError('Unknown unit of measure: ' + str(unit_1))
elif unit_2 not in VALID_UNITS:
_LOGGER.error('Unknown unit of measure: ' + str(unit_2))
raise ValueError('Unknown unit of measure: ' + str(unit_2))
raise ValueError(
UNIT_NOT_RECOGNIZED_TEMPLATE.format(unit_1, LENGTH))
if unit_2 not in VALID_UNITS:
raise ValueError(
UNIT_NOT_RECOGNIZED_TEMPLATE.format(unit_2, LENGTH))
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
meters = value
if unit_1 == MILES_SYMBOL:
if unit_1 == LENGTH_MILES:
meters = __miles_to_meters(value)
elif unit_1 == FEET_SYMBOL:
elif unit_1 == LENGTH_FEET:
meters = __feet_to_meters(value)
elif unit_1 == KILOMETERS_SYMBOL:
elif unit_1 == LENGTH_KILOMETERS:
meters = __kilometers_to_meters(value)
result = meters
if unit_2 == MILES_SYMBOL:
if unit_2 == LENGTH_MILES:
result = __meters_to_miles(meters)
elif unit_2 == FEET_SYMBOL:
elif unit_2 == LENGTH_FEET:
result = __meters_to_feet(meters)
elif unit_2 == KILOMETERS_SYMBOL:
elif unit_2 == LENGTH_KILOMETERS:
result = __meters_to_kilometers(meters)
return result
def __miles_to_meters(miles):
def __miles_to_meters(miles: float) -> float:
"""Convert miles to meters."""
return miles * 1609.344
def __feet_to_meters(feet):
def __feet_to_meters(feet: float) -> float:
"""Convert feet to meters."""
return feet * 0.3048
def __kilometers_to_meters(kilometers):
def __kilometers_to_meters(kilometers: float) -> float:
"""Convert kilometers to meters."""
return kilometers * 1000
def __meters_to_miles(meters):
def __meters_to_miles(meters: float) -> float:
"""Convert meters to miles."""
return meters * 0.000621371
def __meters_to_feet(meters):
def __meters_to_feet(meters: float) -> float:
"""Convert meters to feet."""
return meters * 3.28084
def __meters_to_kilometers(meters):
def __meters_to_kilometers(meters: float) -> float:
"""Convert meters to kilometers."""
return meters * 0.001

View File

@ -31,7 +31,7 @@ LocationInfo = collections.namedtuple(
"LocationInfo",
['ip', 'country_code', 'country_name', 'region_code', 'region_name',
'city', 'zip_code', 'time_zone', 'latitude', 'longitude',
'use_fahrenheit'])
'use_metric'])
def detect_location_info():
@ -44,11 +44,8 @@ def detect_location_info():
if data is None:
return None
# From Wikipedia: Fahrenheit is used in the Bahamas, Belize,
# the Cayman Islands, Palau, and the United States and associated
# territories of American Samoa and the U.S. Virgin Islands
data['use_fahrenheit'] = data['country_code'] in (
'BS', 'BZ', 'KY', 'PW', 'US', 'AS', 'VI')
data['use_metric'] = data['country_code'] not in (
'US', 'MM', 'LR')
return LocationInfo(**data)

View File

@ -1,4 +1,10 @@
"""Temperature util functions."""
from homeassistant.const import (
TEMP_CELSIUS,
TEMP_FAHRENHEIT,
UNIT_NOT_RECOGNIZED_TEMPLATE,
TEMPERATURE
)
def fahrenheit_to_celsius(fahrenheit: float) -> float:
@ -9,3 +15,20 @@ def fahrenheit_to_celsius(fahrenheit: float) -> float:
def celsius_to_fahrenheit(celsius: float) -> float:
"""Convert a Celsius temperature to Fahrenheit."""
return celsius * 1.8 + 32.0
def convert(temperature: float, from_unit: str, to_unit: str) -> float:
"""Convert a temperature from one unit to another."""
if from_unit not in (TEMP_CELSIUS, TEMP_FAHRENHEIT):
raise ValueError(UNIT_NOT_RECOGNIZED_TEMPLATE.format(from_unit,
TEMPERATURE))
if to_unit not in (TEMP_CELSIUS, TEMP_FAHRENHEIT):
raise ValueError(UNIT_NOT_RECOGNIZED_TEMPLATE.format(to_unit,
TEMPERATURE))
if from_unit == to_unit:
return temperature
elif from_unit == TEMP_CELSIUS:
return celsius_to_fahrenheit(temperature)
else:
return round(fahrenheit_to_celsius(temperature), 1)

View File

@ -6,11 +6,12 @@ from unittest import mock
from homeassistant import core as ha, loader
from homeassistant.bootstrap import _setup_component
from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.unit_system import METRIC_SYSTEM
import homeassistant.util.dt as date_util
from homeassistant.const import (
STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME, EVENT_TIME_CHANGED,
EVENT_STATE_CHANGED, EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE,
ATTR_DISCOVERED, SERVER_PORT, TEMP_CELSIUS)
ATTR_DISCOVERED, SERVER_PORT)
from homeassistant.components import sun, mqtt
_TEST_INSTANCE_PORT = SERVER_PORT
@ -37,7 +38,7 @@ def get_test_home_assistant(num_threads=None):
hass.config.longitude = -117.22743
hass.config.elevation = 0
hass.config.time_zone = date_util.get_time_zone('US/Pacific')
hass.config.temperature_unit = TEMP_CELSIUS
hass.config.units = METRIC_SYSTEM
if 'custom_components.test' not in loader.AVAILABLE_COMPONENTS:
loader.prepare(hass)

View File

@ -1,8 +1,8 @@
"""The tests for the demo hvac."""
import unittest
from homeassistant.const import (
TEMP_CELSIUS,
from homeassistant.helpers.unit_system import (
METRIC_SYSTEM,
)
from homeassistant.components import hvac
@ -18,7 +18,7 @@ class TestDemoHvac(unittest.TestCase):
def setUp(self): # pylint: disable=invalid-name
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.hass.config.temperature_unit = TEMP_CELSIUS
self.hass.config.units = METRIC_SYSTEM
self.assertTrue(hvac.setup(self.hass, {'hvac': {
'platform': 'demo',
}}))

View File

@ -1,8 +1,8 @@
"""The tests for the demo thermostat."""
import unittest
from homeassistant.const import (
TEMP_CELSIUS,
from homeassistant.helpers.unit_system import (
METRIC_SYSTEM,
)
from homeassistant.components import thermostat
@ -18,7 +18,7 @@ class TestDemoThermostat(unittest.TestCase):
def setUp(self): # pylint: disable=invalid-name
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.hass.config.temperature_unit = TEMP_CELSIUS
self.hass.config.units = METRIC_SYSTEM
self.assertTrue(thermostat.setup(self.hass, {'thermostat': {
'platform': 'demo',
}}))
@ -43,10 +43,10 @@ class TestDemoThermostat(unittest.TestCase):
def test_set_target_temp_bad_attr(self):
"""Test setting the target temperature without required attribute."""
self.assertEqual('21', self.hass.states.get(ENTITY_NEST).state)
self.assertEqual('21.0', self.hass.states.get(ENTITY_NEST).state)
thermostat.set_temperature(self.hass, None, ENTITY_NEST)
self.hass.pool.block_till_done()
self.assertEqual('21', self.hass.states.get(ENTITY_NEST).state)
self.assertEqual('21.0', self.hass.states.get(ENTITY_NEST).state)
def test_set_target_temp(self):
"""Test the setting of the target temperature."""

View File

@ -10,6 +10,7 @@ from homeassistant.const import (
STATE_OFF,
TEMP_CELSIUS,
)
from homeassistant.helpers.unit_system import METRIC_SYSTEM
from homeassistant.components import thermostat
from tests.common import get_test_home_assistant
@ -75,7 +76,7 @@ class TestThermostatHeatControl(unittest.TestCase):
def setUp(self): # pylint: disable=invalid-name
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.hass.config.temperature_unit = TEMP_CELSIUS
self.hass.config.units = METRIC_SYSTEM
thermostat.setup(self.hass, {'thermostat': {
'platform': 'heat_control',
'name': 'test',
@ -123,19 +124,29 @@ class TestThermostatHeatControl(unittest.TestCase):
def test_sensor_bad_unit(self):
"""Test sensor that have bad unit."""
state = self.hass.states.get(ENTITY)
temp = state.attributes.get('current_temperature')
unit = state.attributes.get('unit_of_measurement')
self._setup_sensor(22.0, unit='bad_unit')
self.hass.pool.block_till_done()
state = self.hass.states.get(ENTITY)
self.assertEqual(None, state.attributes.get('unit_of_measurement'))
self.assertEqual(None, state.attributes.get('current_temperature'))
self.assertEqual(unit, state.attributes.get('unit_of_measurement'))
self.assertEqual(temp, state.attributes.get('current_temperature'))
def test_sensor_bad_value(self):
"""Test sensor that have None as state."""
state = self.hass.states.get(ENTITY)
temp = state.attributes.get('current_temperature')
unit = state.attributes.get('unit_of_measurement')
self._setup_sensor(None)
self.hass.pool.block_till_done()
state = self.hass.states.get(ENTITY)
self.assertEqual(None, state.attributes.get('unit_of_measurement'))
self.assertEqual(None, state.attributes.get('current_temperature'))
self.assertEqual(unit, state.attributes.get('unit_of_measurement'))
self.assertEqual(temp, state.attributes.get('current_temperature'))
def test_set_target_temp_heater_on(self):
"""Test if target temperature turn heater on."""

View File

@ -6,6 +6,13 @@ from unittest.mock import patch
from homeassistant.components import group
from homeassistant.exceptions import TemplateError
from homeassistant.helpers import template
from homeassistant.helpers.unit_system import UnitSystem
from homeassistant.const import (
LENGTH_METERS,
TEMP_CELSIUS,
MASS_GRAMS,
VOLUME_LITERS,
)
import homeassistant.util.dt as dt_util
from tests.common import get_test_home_assistant
@ -17,6 +24,9 @@ class TestUtilTemplate(unittest.TestCase):
def setUp(self): # pylint: disable=invalid-name
"""Setup the tests."""
self.hass = get_test_home_assistant()
self.hass.config.units = UnitSystem('custom', TEMP_CELSIUS,
LENGTH_METERS, VOLUME_LITERS,
MASS_GRAMS)
def tearDown(self): # pylint: disable=invalid-name
"""Stop down stuff we started."""

View File

@ -0,0 +1,132 @@
"""Test the unit system helper."""
import unittest
from homeassistant.helpers.unit_system import (
UnitSystem,
METRIC_SYSTEM,
IMPERIAL_SYSTEM,
)
from homeassistant.const import (
LENGTH_METERS,
LENGTH_KILOMETERS,
MASS_GRAMS,
VOLUME_LITERS,
TEMP_CELSIUS,
LENGTH,
MASS,
TEMPERATURE,
VOLUME
)
SYSTEM_NAME = 'TEST'
INVALID_UNIT = 'INVALID'
class TestUnitSystem(unittest.TestCase):
"""Test the unit system helper."""
def test_invalid_units(self):
"""Test errors are raised when invalid units are passed in."""
with self.assertRaises(ValueError):
UnitSystem(SYSTEM_NAME, INVALID_UNIT, LENGTH_METERS, VOLUME_LITERS,
MASS_GRAMS)
with self.assertRaises(ValueError):
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, INVALID_UNIT, VOLUME_LITERS,
MASS_GRAMS)
with self.assertRaises(ValueError):
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, LENGTH_METERS, INVALID_UNIT,
MASS_GRAMS)
with self.assertRaises(ValueError):
UnitSystem(SYSTEM_NAME, TEMP_CELSIUS, LENGTH_METERS, VOLUME_LITERS,
INVALID_UNIT)
def test_invalid_value(self):
"""Test no conversion happens if value is non-numeric."""
with self.assertRaises(TypeError):
METRIC_SYSTEM.length('25a', LENGTH_KILOMETERS)
with self.assertRaises(TypeError):
METRIC_SYSTEM.temperature('50K', TEMP_CELSIUS)
def test_as_dict(self):
"""Test that the as_dict() method returns the expected dictionary."""
expected = {
LENGTH: LENGTH_KILOMETERS,
TEMPERATURE: TEMP_CELSIUS,
VOLUME: VOLUME_LITERS,
MASS: MASS_GRAMS
}
self.assertEqual(expected, METRIC_SYSTEM.as_dict())
def test_temperature_same_unit(self):
"""Test no conversion happens if to unit is same as from unit."""
self.assertEqual(
5,
METRIC_SYSTEM.temperature(5,
METRIC_SYSTEM.temperature_unit))
def test_temperature_unknown_unit(self):
"""Test no conversion happens if unknown unit."""
with self.assertRaises(ValueError):
METRIC_SYSTEM.temperature(5, 'K')
def test_temperature_to_metric(self):
"""Test temperature conversion to metric system."""
self.assertEqual(
25,
METRIC_SYSTEM.temperature(25, METRIC_SYSTEM.temperature_unit))
self.assertEqual(
26.7,
METRIC_SYSTEM.temperature(80, IMPERIAL_SYSTEM.temperature_unit))
def test_temperature_to_imperial(self):
"""Test temperature conversion to imperial system."""
self.assertEqual(
77,
IMPERIAL_SYSTEM.temperature(77, IMPERIAL_SYSTEM.temperature_unit))
self.assertEqual(
77,
IMPERIAL_SYSTEM.temperature(25, METRIC_SYSTEM.temperature_unit))
def test_length_unknown_unit(self):
"""Test length conversion with unknown from unit."""
with self.assertRaises(ValueError):
METRIC_SYSTEM.length(5, 'fr')
def test_length_to_metric(self):
"""Test length conversion to metric system."""
self.assertEqual(
100,
METRIC_SYSTEM.length(100, METRIC_SYSTEM.length_unit)
)
self.assertEqual(
8.04672,
METRIC_SYSTEM.length(5, IMPERIAL_SYSTEM.length_unit)
)
def test_length_to_imperial(self):
"""Test length conversion to imperial system."""
self.assertEqual(
100,
IMPERIAL_SYSTEM.length(100,
IMPERIAL_SYSTEM.length_unit)
)
self.assertEqual(
3.106855,
IMPERIAL_SYSTEM.length(5, METRIC_SYSTEM.length_unit)
)
def test_properties(self):
"""Test the unit properties are returned as expected."""
self.assertEqual(LENGTH_KILOMETERS, METRIC_SYSTEM.length_unit)
self.assertEqual(TEMP_CELSIUS, METRIC_SYSTEM.temperature_unit)
self.assertEqual(MASS_GRAMS, METRIC_SYSTEM.mass_unit)
self.assertEqual(VOLUME_LITERS, METRIC_SYSTEM.volume_unit)
def test_is_metric(self):
"""Test the is metric flag."""
self.assertTrue(METRIC_SYSTEM.is_metric)
self.assertFalse(IMPERIAL_SYSTEM.is_metric)

View File

@ -11,9 +11,9 @@ from voluptuous import MultipleInvalid
from homeassistant.core import DOMAIN, HomeAssistantError, Config
import homeassistant.config as config_util
from homeassistant.const import (
CONF_LATITUDE, CONF_LONGITUDE, CONF_TEMPERATURE_UNIT, CONF_NAME,
CONF_LATITUDE, CONF_LONGITUDE, CONF_UNIT_SYSTEM, CONF_NAME,
CONF_TIME_ZONE, CONF_ELEVATION, CONF_CUSTOMIZE, __version__,
TEMP_FAHRENHEIT)
CONF_UNIT_SYSTEM_METRIC, CONF_UNIT_SYSTEM_IMPERIAL, CONF_TEMPERATURE_UNIT)
from homeassistant.util import location as location_util, dt as dt_util
from homeassistant.helpers.entity import Entity
@ -145,7 +145,7 @@ class TestConfig(unittest.TestCase):
CONF_LATITUDE: 32.8594,
CONF_LONGITUDE: -117.2073,
CONF_ELEVATION: 101,
CONF_TEMPERATURE_UNIT: 'F',
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC,
CONF_NAME: 'Home',
CONF_TIME_ZONE: 'America/Los_Angeles'
}
@ -167,7 +167,7 @@ class TestConfig(unittest.TestCase):
def test_core_config_schema(self):
for value in (
{'temperature_unit': 'K'},
{CONF_UNIT_SYSTEM: 'K'},
{'time_zone': 'non-exist'},
{'latitude': '91'},
{'longitude': -181},
@ -182,7 +182,7 @@ class TestConfig(unittest.TestCase):
'name': 'Test name',
'latitude': '-23.45',
'longitude': '123.45',
'temperature_unit': 'c',
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_METRIC,
'customize': {
'sensor.temperature': {
'hidden': True,
@ -264,7 +264,7 @@ class TestConfig(unittest.TestCase):
'longitude': 50,
'elevation': 25,
'name': 'Huis',
'temperature_unit': 'F',
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL,
'time_zone': 'America/New_York',
})
@ -272,7 +272,28 @@ class TestConfig(unittest.TestCase):
assert config.longitude == 50
assert config.elevation == 25
assert config.location_name == 'Huis'
assert config.temperature_unit == TEMP_FAHRENHEIT
assert config.units.name == CONF_UNIT_SYSTEM_IMPERIAL
assert config.time_zone.zone == 'America/New_York'
def test_loading_configuration_temperature_unit(self):
"""Test backward compatibility when loading core config."""
config = Config()
hass = mock.Mock(config=config)
config_util.process_ha_core_config(hass, {
'latitude': 60,
'longitude': 50,
'elevation': 25,
'name': 'Huis',
CONF_TEMPERATURE_UNIT: 'C',
'time_zone': 'America/New_York',
})
assert config.latitude == 60
assert config.longitude == 50
assert config.elevation == 25
assert config.location_name == 'Huis'
assert config.units.name == CONF_UNIT_SYSTEM_METRIC
assert config.time_zone.zone == 'America/New_York'
@mock.patch('homeassistant.util.location.detect_location_info',
@ -292,7 +313,8 @@ class TestConfig(unittest.TestCase):
assert config.longitude == -117.2073
assert config.elevation == 101
assert config.location_name == 'San Diego'
assert config.temperature_unit == TEMP_FAHRENHEIT
assert config.units.name == CONF_UNIT_SYSTEM_METRIC
assert config.units.is_metric
assert config.time_zone.zone == 'America/Los_Angeles'
@mock.patch('homeassistant.util.location.detect_location_info',
@ -311,5 +333,5 @@ class TestConfig(unittest.TestCase):
assert config.longitude == blankConfig.longitude
assert config.elevation == blankConfig.elevation
assert config.location_name == blankConfig.location_name
assert config.temperature_unit == blankConfig.temperature_unit
assert config.units == blankConfig.units
assert config.time_zone == blankConfig.time_zone

View File

@ -15,10 +15,10 @@ import homeassistant.core as ha
from homeassistant.exceptions import (
HomeAssistantError, InvalidEntityFormatError)
import homeassistant.util.dt as dt_util
from homeassistant.helpers.unit_system import (METRIC_SYSTEM)
from homeassistant.const import (
__version__, EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
EVENT_STATE_CHANGED, ATTR_FRIENDLY_NAME, TEMP_CELSIUS,
TEMP_FAHRENHEIT)
EVENT_STATE_CHANGED, ATTR_FRIENDLY_NAME, CONF_UNIT_SYSTEM)
from tests.common import get_test_home_assistant
@ -465,56 +465,12 @@ class TestConfig(unittest.TestCase):
os.path.join(data_dir, ".homeassistant", "dir", "test.conf"),
self.config.path("dir", "test.conf"))
def test_temperature_not_convert_if_no_preference(self):
"""No unit conversion to happen if no preference."""
self.assertEqual(
(25, TEMP_CELSIUS),
self.config.temperature(25, TEMP_CELSIUS))
self.assertEqual(
(80, TEMP_FAHRENHEIT),
self.config.temperature(80, TEMP_FAHRENHEIT))
def test_temperature_not_convert_if_invalid_value(self):
"""No unit conversion to happen if no preference."""
self.config.temperature_unit = TEMP_FAHRENHEIT
self.assertEqual(
('25a', TEMP_CELSIUS),
self.config.temperature('25a', TEMP_CELSIUS))
def test_temperature_not_convert_if_invalid_unit(self):
"""No unit conversion to happen if no preference."""
self.assertEqual(
(25, 'Invalid unit'),
self.config.temperature(25, 'Invalid unit'))
def test_temperature_to_convert_to_celsius(self):
"""Test temperature conversion to celsius."""
self.config.temperature_unit = TEMP_CELSIUS
self.assertEqual(
(25, TEMP_CELSIUS),
self.config.temperature(25, TEMP_CELSIUS))
self.assertEqual(
(26.7, TEMP_CELSIUS),
self.config.temperature(80, TEMP_FAHRENHEIT))
def test_temperature_to_convert_to_fahrenheit(self):
"""Test temperature conversion to fahrenheit."""
self.config.temperature_unit = TEMP_FAHRENHEIT
self.assertEqual(
(77, TEMP_FAHRENHEIT),
self.config.temperature(25, TEMP_CELSIUS))
self.assertEqual(
(80, TEMP_FAHRENHEIT),
self.config.temperature(80, TEMP_FAHRENHEIT))
def test_as_dict(self):
"""Test as dict."""
expected = {
'latitude': None,
'longitude': None,
'temperature_unit': None,
CONF_UNIT_SYSTEM: METRIC_SYSTEM.as_dict(),
'location_name': None,
'time_zone': 'UTC',
'components': [],

View File

@ -2,14 +2,11 @@
import unittest
import homeassistant.util.distance as distance_util
KILOMETERS = distance_util.KILOMETERS_SYMBOL
METERS = distance_util.METERS_SYMBOL
FEET = distance_util.FEET_SYMBOL
MILES = distance_util.MILES_SYMBOL
from homeassistant.const import (LENGTH_KILOMETERS, LENGTH_METERS, LENGTH_FEET,
LENGTH_MILES)
INVALID_SYMBOL = 'bob'
VALID_SYMBOL = KILOMETERS
VALID_SYMBOL = LENGTH_KILOMETERS
class TestDistanceUtil(unittest.TestCase):
@ -17,52 +14,78 @@ class TestDistanceUtil(unittest.TestCase):
def test_convert_same_unit(self):
"""Test conversion from any unit to same unit."""
self.assertEqual(5, distance_util.convert(5, KILOMETERS, KILOMETERS))
self.assertEqual(2, distance_util.convert(2, METERS, METERS))
self.assertEqual(10, distance_util.convert(10, MILES, MILES))
self.assertEqual(9, distance_util.convert(9, FEET, FEET))
self.assertEqual(5,
distance_util.convert(5, LENGTH_KILOMETERS,
LENGTH_KILOMETERS))
self.assertEqual(2,
distance_util.convert(2, LENGTH_METERS,
LENGTH_METERS))
self.assertEqual(10,
distance_util.convert(10, LENGTH_MILES, LENGTH_MILES))
self.assertEqual(9,
distance_util.convert(9, LENGTH_FEET, LENGTH_FEET))
def test_convert_invalid_unit(self):
"""Test exception is thrown for invalid units."""
with self.assertRaises(ValueError):
distance_util.convert(5, INVALID_SYMBOL, VALID_SYMBOL)
distance_util.convert(5, INVALID_SYMBOL,
VALID_SYMBOL)
with self.assertRaises(ValueError):
distance_util.convert(5, VALID_SYMBOL, INVALID_SYMBOL)
distance_util.convert(5, VALID_SYMBOL,
INVALID_SYMBOL)
def test_convert_nonnumeric_value(self):
"""Test exception is thrown for nonnumeric type."""
with self.assertRaises(TypeError):
distance_util.convert('a', KILOMETERS, METERS)
distance_util.convert('a', LENGTH_KILOMETERS, LENGTH_METERS)
def test_convert_from_miles(self):
"""Test conversion from miles to other units."""
miles = 5
self.assertEqual(distance_util.convert(miles, MILES, KILOMETERS),
self.assertEqual(
distance_util.convert(miles, LENGTH_MILES, LENGTH_KILOMETERS),
8.04672)
self.assertEqual(distance_util.convert(miles, MILES, METERS), 8046.72)
self.assertEqual(distance_util.convert(miles, MILES, FEET),
self.assertEqual(
distance_util.convert(miles, LENGTH_MILES, LENGTH_METERS),
8046.72)
self.assertEqual(
distance_util.convert(miles, LENGTH_MILES, LENGTH_FEET),
26400.0008448)
def test_convert_from_feet(self):
"""Test conversion from feet to other units."""
feet = 5000
self.assertEqual(distance_util.convert(feet, FEET, KILOMETERS), 1.524)
self.assertEqual(distance_util.convert(feet, FEET, METERS), 1524)
self.assertEqual(distance_util.convert(feet, FEET, MILES),
self.assertEqual(
distance_util.convert(feet, LENGTH_FEET, LENGTH_KILOMETERS),
1.524)
self.assertEqual(
distance_util.convert(feet, LENGTH_FEET, LENGTH_METERS),
1524)
self.assertEqual(
distance_util.convert(feet, LENGTH_FEET, LENGTH_MILES),
0.9469694040000001)
def test_convert_from_kilometers(self):
"""Test conversion from kilometers to other units."""
km = 5
self.assertEqual(distance_util.convert(km, KILOMETERS, FEET), 16404.2)
self.assertEqual(distance_util.convert(km, KILOMETERS, METERS), 5000)
self.assertEqual(distance_util.convert(km, KILOMETERS, MILES),
self.assertEqual(
distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_FEET),
16404.2)
self.assertEqual(
distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_METERS),
5000)
self.assertEqual(
distance_util.convert(km, LENGTH_KILOMETERS, LENGTH_MILES),
3.106855)
def test_convert_from_meters(self):
"""Test conversion from meters to other units."""
m = 5000
self.assertEqual(distance_util.convert(m, METERS, FEET), 16404.2)
self.assertEqual(distance_util.convert(m, METERS, KILOMETERS), 5)
self.assertEqual(distance_util.convert(m, METERS, MILES), 3.106855)
self.assertEqual(distance_util.convert(m, LENGTH_METERS, LENGTH_FEET),
16404.2)
self.assertEqual(
distance_util.convert(m, LENGTH_METERS, LENGTH_KILOMETERS),
5)
self.assertEqual(distance_util.convert(m, LENGTH_METERS, LENGTH_MILES),
3.106855)

View File

@ -79,7 +79,7 @@ class TestLocationUtil(TestCase):
assert info.time_zone == 'America/Los_Angeles'
assert info.latitude == 32.8594
assert info.longitude == -117.2073
assert info.use_fahrenheit
assert not info.use_metric
@requests_mock.Mocker()
@patch('homeassistant.util.location._get_freegeoip', return_value=None)
@ -101,7 +101,7 @@ class TestLocationUtil(TestCase):
assert info.time_zone == 'America/Los_Angeles'
assert info.latitude == 32.8594
assert info.longitude == -117.2073
assert info.use_fahrenheit
assert not info.use_metric
@patch('homeassistant.util.location.elevation', return_value=0)
@patch('homeassistant.util.location._get_freegeoip', return_value=None)