diff --git a/config/configuration.yaml.example b/config/configuration.yaml.example index 6c0d9f64a1f..125be6e2d05 100644 --- a/config/configuration.yaml.example +++ b/config/configuration.yaml.example @@ -1,8 +1,20 @@ homeassistant: + # Omitted values in this section will be auto detected using freegeoip.net + # Location required to calculate the time the sun rises and sets latitude: 32.87336 longitude: 117.22743 + # C for Celcius, F for Fahrenheit + temperature_unit: C + + # Pick yours from here: + # http://en.wikipedia.org/wiki/List_of_tz_database_time_zones + time_zone: America/Los_Angeles + + # Name of the location where Home Assistant is running + name: Home + http: api_password: mypass # Set to 1 to enable development mode diff --git a/homeassistant/__init__.py b/homeassistant/__init__.py index bc6dca95113..8ed3d7bc1b6 100644 --- a/homeassistant/__init__.py +++ b/homeassistant/__init__.py @@ -15,11 +15,14 @@ import re import datetime as dt import functools as ft +import requests + from homeassistant.const import ( EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP, SERVICE_HOMEASSISTANT_STOP, EVENT_TIME_CHANGED, EVENT_STATE_CHANGED, EVENT_CALL_SERVICE, ATTR_NOW, ATTR_DOMAIN, ATTR_SERVICE, MATCH_ALL, - EVENT_SERVICE_EXECUTED, ATTR_SERVICE_CALL_ID, EVENT_SERVICE_REGISTERED) + EVENT_SERVICE_EXECUTED, ATTR_SERVICE_CALL_ID, EVENT_SERVICE_REGISTERED, + TEMP_CELCIUS, TEMP_FAHRENHEIT) import homeassistant.util as util DOMAIN = "homeassistant" @@ -49,6 +52,7 @@ class HomeAssistant(object): self.bus = EventBus(pool) self.services = ServiceRegistry(self.bus, pool) self.states = StateMachine(self.bus) + self.config = Config() # List of loaded components self.components = [] @@ -56,12 +60,18 @@ class HomeAssistant(object): # Remote.API object pointing at local API self.local_api = None - # Directory that holds the configuration - self.config_dir = os.path.join(os.getcwd(), 'config') + @property + def config_dir(self): + """ DEPRECATED 3/18/2015. Use hass.config.config_dir """ + _LOGGER.warning( + 'hass.config_dir is deprecated. Use hass.config.config_dir') + return self.config.config_dir def get_config_path(self, path): - """ Returns path to the file within the config dir. """ - return os.path.join(self.config_dir, path) + """ DEPRECATED 3/18/2015. Use hass.config.path """ + _LOGGER.warning( + 'hass.get_config_path is deprecated. Use hass.config.path') + return self.config.path(path) def start(self): """ Start home assistant. """ @@ -836,6 +846,75 @@ class Timer(threading.Thread): self.hass.bus.fire(EVENT_TIME_CHANGED, {ATTR_NOW: now}) +class Config(object): + """ Configuration settings for Home Assistant. """ + def __init__(self): + self.latitude = None + self.longitude = None + self.temperature_unit = None + self.location_name = None + self.time_zone = None + + # Directory that holds the configuration + self.config_dir = os.path.join(os.getcwd(), 'config') + + def auto_detect(self): + """ Will attempt to detect config of Home Assistant. """ + # Only detect if location or temp unit missing + if None not in (self.latitude, self.longitude, self.temperature_unit): + return + + _LOGGER.info('Auto detecting location and temperature unit') + + try: + info = requests.get('https://freegeoip.net/json/').json() + except requests.RequestException: + return + + if self.latitude is None and self.longitude is None: + self.latitude = info['latitude'] + self.longitude = info['longitude'] + + if self.temperature_unit is 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 + if info['country_code'] in ('BS', 'BZ', 'KY', 'PW', + 'US', 'AS', 'VI'): + self.temperature_unit = TEMP_FAHRENHEIT + else: + self.temperature_unit = TEMP_CELCIUS + + if self.location_name is None: + self.location_name = info['city'] + + if self.time_zone is None: + self.time_zone = info['time_zone'] + + def path(self, path): + """ Returns path to the file within the config dir. """ + return os.path.join(self.config_dir, path) + + def temperature(self, value, unit): + """ Converts temperature to user preferred unit if set. """ + if not (unit and self.temperature_unit and + unit != self.temperature_unit): + return value, unit + + try: + if unit == TEMP_CELCIUS: + # Convert C to F + return round(float(value) * 1.8 + 32.0, 1), TEMP_FAHRENHEIT + + # Convert F to C + return round((float(value)-32.0)/1.8, 1), TEMP_CELCIUS + + except ValueError: + # Could not convert value to float + return value, unit + + class HomeAssistantError(Exception): """ General Home Assistant exception occured. """ pass diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index f9a90664ae7..83d966731cd 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -20,7 +20,10 @@ import homeassistant import homeassistant.loader as loader import homeassistant.components as core_components import homeassistant.components.group as group -from homeassistant.const import EVENT_COMPONENT_LOADED +from homeassistant.const import ( + EVENT_COMPONENT_LOADED, CONF_LATITUDE, CONF_LONGITUDE, + CONF_TEMPERATURE_UNIT, CONF_NAME, CONF_TIME_ZONE, TEMP_CELCIUS, + TEMP_FAHRENHEIT) _LOGGER = logging.getLogger(__name__) @@ -73,6 +76,8 @@ def from_config_dict(config, hass=None): if hass is None: hass = homeassistant.HomeAssistant() + process_ha_core_config(hass, config.get(homeassistant.DOMAIN, {})) + enable_logging(hass) _ensure_loader_prepared(hass) @@ -111,8 +116,8 @@ def from_config_file(config_path, hass=None): if hass is None: hass = homeassistant.HomeAssistant() - # Set config dir to directory holding config file - hass.config_dir = os.path.abspath(os.path.dirname(config_path)) + # Set config dir to directory holding config file + hass.config.config_dir = os.path.abspath(os.path.dirname(config_path)) config_dict = {} # check config file type @@ -143,13 +148,13 @@ def enable_logging(hass): logging.basicConfig(level=logging.INFO) # Log errors to a file if we have write access to file or config dir - err_log_path = hass.get_config_path("home-assistant.log") + err_log_path = hass.config.path("home-assistant.log") err_path_exists = os.path.isfile(err_log_path) # Check if we can write to the error log if it exists or that # we can create files in the containing directory if not. if (err_path_exists and os.access(err_log_path, os.W_OK)) or \ - (not err_path_exists and os.access(hass.config_dir, os.W_OK)): + (not err_path_exists and os.access(hass.config.config_dir, os.W_OK)): err_handler = logging.FileHandler( err_log_path, mode='w', delay=True) @@ -165,6 +170,26 @@ def enable_logging(hass): "Unable to setup error log %s (access denied)", err_log_path) +def process_ha_core_config(hass, config): + """ Processes the [homeassistant] section from the config. """ + for key, attr in ((CONF_LATITUDE, 'latitude'), + (CONF_LONGITUDE, 'longitude'), + (CONF_NAME, 'location_name'), + (CONF_TIME_ZONE, 'time_zone')): + if key in config: + setattr(hass.config, attr, config[key]) + + if CONF_TEMPERATURE_UNIT in config: + unit = config[CONF_TEMPERATURE_UNIT] + + if unit == 'C': + hass.config.temperature_unit = TEMP_CELCIUS + elif unit == 'F': + hass.config.temperature_unit = TEMP_FAHRENHEIT + + hass.config.auto_detect() + + def _ensure_loader_prepared(hass): """ Ensure Home Assistant loader is prepared. """ if not loader.PREPARED: diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py index 53774210868..48d8476759f 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -10,8 +10,7 @@ import homeassistant as ha import homeassistant.bootstrap as bootstrap import homeassistant.loader as loader from homeassistant.const import ( - CONF_PLATFORM, ATTR_ENTITY_PICTURE, ATTR_ENTITY_ID, - CONF_LATITUDE, CONF_LONGITUDE) + CONF_PLATFORM, ATTR_ENTITY_PICTURE, ATTR_ENTITY_ID) DOMAIN = "demo" @@ -33,8 +32,6 @@ def setup(hass, config): hass.states.set('a.Demo_Mode', 'Enabled') # Setup sun - config[ha.DOMAIN].setdefault(CONF_LATITUDE, '32.87336') - config[ha.DOMAIN].setdefault(CONF_LONGITUDE, '-117.22743') loader.get_component('sun').setup(hass, config) # Setup demo platforms diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 85e8add47fc..ac0c8d483ff 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -179,7 +179,7 @@ class DeviceTracker(object): # Write new devices to known devices file if not self.invalid_known_devices_file: - known_dev_path = self.hass.get_config_path(KNOWN_DEVICES_FILE) + known_dev_path = self.hass.config.path(KNOWN_DEVICES_FILE) try: # If file does not exist we will write the header too @@ -214,7 +214,7 @@ class DeviceTracker(object): # pylint: disable=too-many-branches def _read_known_devices_file(self): """ Parse and process the known devices file. """ - known_dev_path = self.hass.get_config_path(KNOWN_DEVICES_FILE) + known_dev_path = self.hass.config.path(KNOWN_DEVICES_FILE) # Return if no known devices file exists if not os.path.isfile(known_dev_path): diff --git a/homeassistant/components/light/__init__.py b/homeassistant/components/light/__init__.py index a0bcd742aa2..e7951afe31a 100644 --- a/homeassistant/components/light/__init__.py +++ b/homeassistant/components/light/__init__.py @@ -148,7 +148,7 @@ def setup(hass, config): # Load built-in profiles and custom profiles profile_paths = [os.path.join(os.path.dirname(__file__), LIGHT_PROFILES_FILE), - hass.get_config_path(LIGHT_PROFILES_FILE)] + hass.config.path(LIGHT_PROFILES_FILE)] profiles = {} for profile_path in profile_paths: diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index 1c5e6048f47..def43df4fe2 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -51,7 +51,8 @@ def setup_bridge(host, hass, add_devices_callback): try: bridge = phue.Bridge( - host, config_file_path=hass.get_config_path(PHUE_CONFIG_FILE)) + host, + config_file_path=hass.config.path(PHUE_CONFIG_FILE)) except ConnectionRefusedError: # Wrong host was given _LOGGER.exception("Error connecting to the Hue bridge at %s", host) diff --git a/homeassistant/components/recorder.py b/homeassistant/components/recorder.py index e31f933e421..84d4c1ecccd 100644 --- a/homeassistant/components/recorder.py +++ b/homeassistant/components/recorder.py @@ -262,7 +262,7 @@ class Recorder(threading.Thread): def _setup_connection(self): """ Ensure database is ready to fly. """ - db_path = self.hass.get_config_path(DB_FILE) + db_path = self.hass.config.path(DB_FILE) self.conn = sqlite3.connect(db_path, check_same_thread=False) self.conn.row_factory = sqlite3.Row diff --git a/homeassistant/components/scheduler/__init__.py b/homeassistant/components/scheduler/__init__.py index 120f90b6ccf..d05d90a903b 100644 --- a/homeassistant/components/scheduler/__init__.py +++ b/homeassistant/components/scheduler/__init__.py @@ -74,7 +74,7 @@ def setup(hass, config): schedule.schedule(hass) return True - with open(hass.get_config_path(_SCHEDULE_FILE)) as schedule_file: + with open(hass.config.path(_SCHEDULE_FILE)) as schedule_file: schedule_descriptions = json.load(schedule_file) for schedule_description in schedule_descriptions: diff --git a/homeassistant/components/sensor/demo.py b/homeassistant/components/sensor/demo.py index 3dc5dbd1998..57b905152c2 100644 --- a/homeassistant/components/sensor/demo.py +++ b/homeassistant/components/sensor/demo.py @@ -1,25 +1,25 @@ """ Support for Wink sensors. """ from homeassistant.helpers.device import Device -from homeassistant.const import ( - TEMP_CELCIUS, ATTR_UNIT_OF_MEASUREMENT, ATTR_FRIENDLY_NAME) +from homeassistant.const import TEMP_CELCIUS, ATTR_BATTERY_LEVEL # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): """ Sets up the Demo sensors. """ add_devices([ - DemoSensor('Outside Temperature', 15.6, TEMP_CELCIUS), - DemoSensor('Outside Humidity', 54, '%'), + DemoSensor('Outside Temperature', 15.6, TEMP_CELCIUS, 12), + DemoSensor('Outside Humidity', 54, '%', None), ]) class DemoSensor(Device): """ A Demo sensor. """ - def __init__(self, name, state, unit_of_measurement): + def __init__(self, name, state, unit_of_measurement, battery): self._name = name self._state = state self._unit_of_measurement = unit_of_measurement + self._battery = battery @property def should_poll(self): @@ -36,10 +36,15 @@ class DemoSensor(Device): """ Returns the state of the device. """ return self._state + @property + def unit_of_measurement(self): + """ Unit this state is expressed in. """ + return self._unit_of_measurement + @property def state_attributes(self): """ Returns the state attributes. """ - return { - ATTR_FRIENDLY_NAME: self._name, - ATTR_UNIT_OF_MEASUREMENT: self._unit_of_measurement, - } + if self._battery: + return { + ATTR_BATTERY_LEVEL: self._battery, + } diff --git a/homeassistant/components/sensor/systemmonitor.py b/homeassistant/components/sensor/systemmonitor.py index 3e560c95250..11a5f4dcefd 100644 --- a/homeassistant/components/sensor/systemmonitor.py +++ b/homeassistant/components/sensor/systemmonitor.py @@ -7,8 +7,7 @@ Shows system monitor values such as: disk, memory and processor use """ from homeassistant.helpers.device import Device -from homeassistant.const import ( - ATTR_UNIT_OF_MEASUREMENT, ATTR_FRIENDLY_NAME, STATE_ON, STATE_OFF) +from homeassistant.const import STATE_ON, STATE_OFF import psutil import logging @@ -63,14 +62,6 @@ class SystemMonitorSensor(Device): """ Returns the state of the device. """ return self._state - @property - def state_attributes(self): - """ Returns the state attributes. """ - return { - ATTR_FRIENDLY_NAME: self.name, - ATTR_UNIT_OF_MEASUREMENT: self.unit_of_measurement, - } - def update(self): if self.type == 'disk_use_percent': self._state = psutil.disk_usage(self.argument).percent diff --git a/homeassistant/components/sensor/tellstick.py b/homeassistant/components/sensor/tellstick.py index 4d9f979bf82..6070e6f2e68 100644 --- a/homeassistant/components/sensor/tellstick.py +++ b/homeassistant/components/sensor/tellstick.py @@ -29,8 +29,7 @@ from collections import namedtuple import tellcore.telldus as telldus import tellcore.constants as tellcore_constants -from homeassistant.const import ( - ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT, TEMP_CELCIUS) +from homeassistant.const import TEMP_CELCIUS from homeassistant.helpers.device import Device import homeassistant.util as util @@ -100,7 +99,7 @@ class TellstickSensor(Device): def __init__(self, name, sensor, datatype, sensor_info): self.datatype = datatype self.sensor = sensor - self.unit = sensor_info.unit or None + self.unit_of_measurement = sensor_info.unit or None self._name = "{} {}".format(name, sensor_info.name) @@ -113,15 +112,3 @@ class TellstickSensor(Device): def state(self): """ Returns the state of the device. """ return self.sensor.value(self.datatype).value - - @property - def state_attributes(self): - """ Returns the state attributes. """ - attrs = { - ATTR_FRIENDLY_NAME: self._name, - } - - if self.unit: - attrs[ATTR_UNIT_OF_MEASUREMENT] = self.unit - - return attrs diff --git a/homeassistant/components/sensor/wink.py b/homeassistant/components/sensor/wink.py index 984e218e967..bdabb676b8f 100644 --- a/homeassistant/components/sensor/wink.py +++ b/homeassistant/components/sensor/wink.py @@ -4,8 +4,8 @@ import logging # pylint: disable=no-name-in-module, import-error import homeassistant.external.wink.pywink as pywink -from homeassistant.components.wink import WinkSensorDevice -from homeassistant.const import CONF_ACCESS_TOKEN +from homeassistant.helpers.device import Device +from homeassistant.const import CONF_ACCESS_TOKEN, STATE_OPEN, STATE_CLOSED def setup_platform(hass, config, add_devices, discovery_info=None): @@ -22,3 +22,34 @@ def setup_platform(hass, config, add_devices, discovery_info=None): pywink.set_bearer_token(token) add_devices(WinkSensorDevice(sensor) for sensor in pywink.get_sensors()) + + +class WinkSensorDevice(Device): + """ represents a wink sensor within home assistant. """ + + def __init__(self, wink): + self.wink = wink + + @property + def state(self): + """ Returns the state. """ + return STATE_OPEN if self.is_open else STATE_CLOSED + + @property + def unique_id(self): + """ Returns the id of this wink sensor """ + return "{}.{}".format(self.__class__, self.wink.deviceId()) + + @property + def name(self): + """ Returns the name of the sensor if any. """ + return self.wink.name() + + def update(self): + """ Update state of the sensor. """ + self.wink.updateState() + + @property + def is_open(self): + """ True if door is open. """ + return self.wink.state() diff --git a/homeassistant/components/sensor/zwave.py b/homeassistant/components/sensor/zwave.py index 7edf3962c8c..7e05cfb9624 100644 --- a/homeassistant/components/sensor/zwave.py +++ b/homeassistant/components/sensor/zwave.py @@ -11,7 +11,7 @@ from pydispatch import dispatcher import homeassistant.components.zwave as zwave from homeassistant.helpers.device import Device from homeassistant.const import ( - ATTR_BATTERY_LEVEL, ATTR_UNIT_OF_MEASUREMENT, STATE_ON, STATE_OFF, + ATTR_BATTERY_LEVEL, STATE_ON, STATE_OFF, TEMP_CELCIUS, TEMP_FAHRENHEIT, ATTR_LOCATION) @@ -77,11 +77,6 @@ class ZWaveSensor(Device): if battery_level is not None: attrs[ATTR_BATTERY_LEVEL] = battery_level - unit = self.unit - - if unit: - attrs[ATTR_UNIT_OF_MEASUREMENT] = unit - location = self._node.location if location: @@ -90,8 +85,7 @@ class ZWaveSensor(Device): return attrs @property - def unit(self): - """ Unit if sensor has one. """ + def unit_of_measurement(self): return self._value.units def _value_changed(self, value): @@ -126,8 +120,7 @@ class ZWaveMultilevelSensor(ZWaveSensor): return value @property - def unit(self): - """ Unit of this sensor. """ + def unit_of_measurement(self): unit = self._value.units if unit == 'C': diff --git a/homeassistant/components/sun.py b/homeassistant/components/sun.py index fbfff4e226f..52baf430579 100644 --- a/homeassistant/components/sun.py +++ b/homeassistant/components/sun.py @@ -24,9 +24,6 @@ which event (sunset or sunrise) and the offset. import logging from datetime import datetime, timedelta -import homeassistant as ha -from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE -from homeassistant.helpers import validate_config from homeassistant.util import str_to_datetime, datetime_to_str from homeassistant.components.scheduler import ServiceEventListener @@ -83,11 +80,6 @@ def setup(hass, config): """ Tracks the state of the sun. """ logger = logging.getLogger(__name__) - if not validate_config(config, - {ha.DOMAIN: [CONF_LATITUDE, CONF_LONGITUDE]}, - logger): - return False - try: import ephem except ImportError: @@ -96,8 +88,8 @@ def setup(hass, config): sun = ephem.Sun() # pylint: disable=no-member - latitude = str(config[ha.DOMAIN][CONF_LATITUDE]) - longitude = str(config[ha.DOMAIN][CONF_LONGITUDE]) + latitude = str(hass.config.latitude) + longitude = str(hass.config.longitude) # Validate latitude and longitude observer = ephem.Observer() diff --git a/homeassistant/components/thermostat/__init__.py b/homeassistant/components/thermostat/__init__.py index 47b5f61700d..183d47eb7fe 100644 --- a/homeassistant/components/thermostat/__init__.py +++ b/homeassistant/components/thermostat/__init__.py @@ -11,8 +11,7 @@ from homeassistant.helpers.device_component import DeviceComponent import homeassistant.util as util from homeassistant.helpers.device import Device from homeassistant.const import ( - ATTR_ENTITY_ID, ATTR_TEMPERATURE, ATTR_UNIT_OF_MEASUREMENT, - STATE_ON, STATE_OFF) + ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_ON, STATE_OFF) DOMAIN = "thermostat" DEPENDENCIES = [] @@ -109,11 +108,6 @@ class ThermostatDevice(Device): """ Returns the current state. """ return self.target_temperature - @property - def unit_of_measurement(self): - """ Returns the unit of measurement. """ - return "" - @property def device_state_attributes(self): """ Returns device specific state attributes. """ @@ -123,8 +117,8 @@ class ThermostatDevice(Device): def state_attributes(self): """ Returns optional state attributes. """ data = { - ATTR_UNIT_OF_MEASUREMENT: self.unit_of_measurement, - ATTR_CURRENT_TEMPERATURE: self.current_temperature + ATTR_CURRENT_TEMPERATURE: self.hass.config.temperature( + self.current_temperature, self.unit_of_measurement)[0] } is_away = self.is_away_mode_on diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index 643af935f94..239f308affb 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -8,10 +8,9 @@ import homeassistant.external.wink.pywink as pywink from homeassistant import bootstrap from homeassistant.loader import get_component -from homeassistant.helpers import validate_config, ToggleDevice, Device +from homeassistant.helpers import validate_config, ToggleDevice from homeassistant.const import ( EVENT_PLATFORM_DISCOVERED, CONF_ACCESS_TOKEN, - STATE_OPEN, STATE_CLOSED, ATTR_SERVICE, ATTR_DISCOVERED, ATTR_FRIENDLY_NAME) DOMAIN = "wink" @@ -53,44 +52,6 @@ def setup(hass, config): return True -class WinkSensorDevice(Device): - """ represents a wink sensor within home assistant. """ - - def __init__(self, wink): - self.wink = wink - - @property - def state(self): - """ Returns the state. """ - return STATE_OPEN if self.is_open else STATE_CLOSED - - @property - def unique_id(self): - """ Returns the id of this wink switch """ - return "{}.{}".format(self.__class__, self.wink.deviceId()) - - @property - def name(self): - """ Returns the name of the sensor if any. """ - return self.wink.name() - - @property - def state_attributes(self): - """ Returns optional state attributes. """ - return { - ATTR_FRIENDLY_NAME: self.wink.name() - } - - def update(self): - """ Update state of the sensor. """ - self.wink.updateState() - - @property - def is_open(self): - """ True if door is open. """ - return self.wink.state() - - class WinkToggleDevice(ToggleDevice): """ represents a Wink switch within home assistant. """ diff --git a/homeassistant/components/zwave.py b/homeassistant/components/zwave.py index 41bcfb876ae..15e436d7f4d 100644 --- a/homeassistant/components/zwave.py +++ b/homeassistant/components/zwave.py @@ -72,7 +72,7 @@ def setup(hass, config): # Setup options options = ZWaveOption( config[DOMAIN].get(CONF_USB_STICK_PATH, DEFAULT_CONF_USB_STICK_PATH), - user_path=hass.config_dir) + user_path=hass.config.config_dir) options.set_console_output(use_debug) options.lock() diff --git a/homeassistant/const.py b/homeassistant/const.py index ed74f1edf4f..467bb692399 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -8,6 +8,9 @@ DEVICE_DEFAULT_NAME = "Unnamed Device" # #### CONFIG #### CONF_LATITUDE = "latitude" CONF_LONGITUDE = "longitude" +CONF_TEMPERATURE_UNIT = "temperature_unit" +CONF_NAME = "name" +CONF_TIME_ZONE = "time_zone" CONF_PLATFORM = "platform" CONF_HOST = "host" diff --git a/homeassistant/helpers/device.py b/homeassistant/helpers/device.py index 017d2673f70..5d400124089 100644 --- a/homeassistant/helpers/device.py +++ b/homeassistant/helpers/device.py @@ -8,7 +8,8 @@ Provides ABC for devices in HA. from homeassistant import NoEntitySpecifiedError from homeassistant.const import ( - ATTR_FRIENDLY_NAME, STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME) + ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT, STATE_ON, STATE_OFF, + DEVICE_DEFAULT_NAME, TEMP_CELCIUS, TEMP_FAHRENHEIT) class Device(object): @@ -46,6 +47,11 @@ class Device(object): """ Returns the state attributes. """ return {} + @property + def unit_of_measurement(self): + """ Unit of measurement of this entity if any. """ + return None + # DEPRECATION NOTICE: # Device is moving from getters to properties. # For now the new properties will call the old functions @@ -82,12 +88,25 @@ class Device(object): if force_refresh: self.update() + state = str(self.state) attr = self.state_attributes or {} if ATTR_FRIENDLY_NAME not in attr and self.name: attr[ATTR_FRIENDLY_NAME] = self.name - return self.hass.states.set(self.entity_id, self.state, attr) + if ATTR_UNIT_OF_MEASUREMENT not in attr and self.unit_of_measurement: + attr[ATTR_UNIT_OF_MEASUREMENT] = self.unit_of_measurement + + # Convert temperature if we detect one + if attr.get(ATTR_UNIT_OF_MEASUREMENT) in (TEMP_CELCIUS, + TEMP_FAHRENHEIT): + + state, attr[ATTR_UNIT_OF_MEASUREMENT] = \ + self.hass.config.temperature( + state, attr[ATTR_UNIT_OF_MEASUREMENT]) + state = str(state) + + return self.hass.states.set(self.entity_id, state, attr) def __eq__(self, other): return (isinstance(other, Device) and diff --git a/homeassistant/loader.py b/homeassistant/loader.py index 4bbab3c1ac6..d38e0df4465 100644 --- a/homeassistant/loader.py +++ b/homeassistant/loader.py @@ -46,11 +46,11 @@ def prepare(hass): pkgutil.iter_modules(components.__path__, 'homeassistant.components.')) # Look for available custom components - custom_path = hass.get_config_path("custom_components") + custom_path = hass.config.path("custom_components") if os.path.isdir(custom_path): # Ensure we can load custom components using Pythons import - sys.path.insert(0, hass.config_dir) + sys.path.insert(0, hass.config.config_dir) # We cannot use the same approach as for built-in components because # custom components might only contain a platform for a component. diff --git a/homeassistant/remote.py b/homeassistant/remote.py index 9065c359c19..3c2ffe69f29 100644 --- a/homeassistant/remote.py +++ b/homeassistant/remote.py @@ -14,7 +14,6 @@ import logging import json import enum import urllib.parse -import os import requests @@ -115,10 +114,9 @@ class HomeAssistant(ha.HomeAssistant): self.bus = EventBus(remote_api, pool) self.services = ha.ServiceRegistry(self.bus, pool) self.states = StateMachine(self.bus, self.remote_api) + self.config = ha.Config() self.components = [] - self.config_dir = os.path.join(os.getcwd(), 'config') - def start(self): # Ensure a local API exists to connect with remote if self.local_api is None: diff --git a/tests/helpers.py b/tests/helpers.py index f08df8c4e80..2157b46d835 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -14,7 +14,7 @@ from homeassistant.const import STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME def get_test_home_assistant(): """ Returns a Home Assistant object pointing at test config dir. """ hass = ha.HomeAssistant() - hass.config_dir = os.path.join(os.path.dirname(__file__), "config") + hass.config.config_dir = os.path.join(os.path.dirname(__file__), "config") return hass diff --git a/tests/test_component_device_scanner.py b/tests/test_component_device_scanner.py index 3b43126681f..2bd392c21d0 100644 --- a/tests/test_component_device_scanner.py +++ b/tests/test_component_device_scanner.py @@ -32,7 +32,7 @@ class TestComponentsDeviceTracker(unittest.TestCase): self.hass = get_test_home_assistant() loader.prepare(self.hass) - self.known_dev_path = self.hass.get_config_path( + self.known_dev_path = self.hass.config.path( device_tracker.KNOWN_DEVICES_FILE) def tearDown(self): # pylint: disable=invalid-name diff --git a/tests/test_component_light.py b/tests/test_component_light.py index c5ccb687e07..eb8a17361bf 100644 --- a/tests/test_component_light.py +++ b/tests/test_component_light.py @@ -29,7 +29,7 @@ class TestLight(unittest.TestCase): """ Stop down stuff we started. """ self.hass.stop() - user_light_file = self.hass.get_config_path(light.LIGHT_PROFILES_FILE) + user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) if os.path.isfile(user_light_file): os.remove(user_light_file) @@ -218,7 +218,7 @@ class TestLight(unittest.TestCase): platform = loader.get_component('light.test') platform.init() - user_light_file = self.hass.get_config_path(light.LIGHT_PROFILES_FILE) + user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) # Setup a wrong light file with open(user_light_file, 'w') as user_file: @@ -234,7 +234,7 @@ class TestLight(unittest.TestCase): platform = loader.get_component('light.test') platform.init() - user_light_file = self.hass.get_config_path(light.LIGHT_PROFILES_FILE) + user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) with open(user_light_file, 'w') as user_file: user_file.write('id,x,y,brightness\n') diff --git a/tests/test_component_sun.py b/tests/test_component_sun.py index 33570cdcc4e..a4ff19429f3 100644 --- a/tests/test_component_sun.py +++ b/tests/test_component_sun.py @@ -11,7 +11,6 @@ import datetime as dt import ephem import homeassistant as ha -from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE import homeassistant.components.sun as sun @@ -35,12 +34,9 @@ class TestSun(unittest.TestCase): def test_setting_rising(self): """ Test retrieving sun setting and rising. """ # Compare it with the real data - self.assertTrue(sun.setup( - self.hass, - {ha.DOMAIN: { - CONF_LATITUDE: '32.87336', - CONF_LONGITUDE: '117.22743' - }})) + self.hass.config.latitude = '32.87336' + self.hass.config.longitude = '117.22743' + sun.setup(self.hass, None) observer = ephem.Observer() observer.lat = '32.87336' # pylint: disable=assigning-non-slot @@ -74,12 +70,9 @@ class TestSun(unittest.TestCase): def test_state_change(self): """ Test if the state changes at next setting/rising. """ - self.assertTrue(sun.setup( - self.hass, - {ha.DOMAIN: { - CONF_LATITUDE: '32.87336', - CONF_LONGITUDE: '117.22743' - }})) + self.hass.config.latitude = '32.87336' + self.hass.config.longitude = '117.22743' + sun.setup(self.hass, None) if sun.is_on(self.hass): test_state = sun.STATE_BELOW_HORIZON @@ -96,30 +89,3 @@ class TestSun(unittest.TestCase): self.hass.pool.block_till_done() self.assertEqual(test_state, self.hass.states.get(sun.ENTITY_ID).state) - - def test_setup(self): - """ Test Sun setup with empty and wrong configs. """ - self.assertFalse(sun.setup(self.hass, {})) - self.assertFalse(sun.setup(self.hass, {sun.DOMAIN: {}})) - self.assertFalse(sun.setup( - self.hass, {ha.DOMAIN: {CONF_LATITUDE: '32.87336'}})) - self.assertFalse(sun.setup( - self.hass, {ha.DOMAIN: {CONF_LONGITUDE: '117.22743'}})) - self.assertFalse(sun.setup( - self.hass, {ha.DOMAIN: {CONF_LATITUDE: 'hello'}})) - self.assertFalse(sun.setup( - self.hass, {ha.DOMAIN: {CONF_LONGITUDE: 'how are you'}})) - self.assertFalse(sun.setup( - self.hass, {ha.DOMAIN: { - CONF_LATITUDE: 'wrong', CONF_LONGITUDE: '117.22743' - }})) - self.assertFalse(sun.setup( - self.hass, {ha.DOMAIN: { - CONF_LATITUDE: '32.87336', CONF_LONGITUDE: 'wrong' - }})) - - # Test with correct config - self.assertTrue(sun.setup( - self.hass, {ha.DOMAIN: { - CONF_LATITUDE: '32.87336', CONF_LONGITUDE: '117.22743' - }})) diff --git a/tests/test_core.py b/tests/test_core.py index 61ac776fba8..a5c37f753b9 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -35,10 +35,10 @@ class TestHomeAssistant(unittest.TestCase): def test_get_config_path(self): """ Test get_config_path method. """ self.assertEqual(os.path.join(os.getcwd(), "config"), - self.hass.config_dir) + self.hass.config.config_dir) self.assertEqual(os.path.join(os.getcwd(), "config", "test.conf"), - self.hass.get_config_path("test.conf")) + self.hass.config.path("test.conf")) def test_block_till_stoped(self): """ Test if we can block till stop service is called. """