Skip to content

Commit

Permalink
ps: Add a global config object to Home Assistant
Browse files Browse the repository at this point in the history
  • Loading branch information
balloob committed Mar 19, 2015
1 parent 569b15d commit 9b643d5
Show file tree
Hide file tree
Showing 23 changed files with 224 additions and 173 deletions.
12 changes: 12 additions & 0 deletions config/configuration.yaml.example
Original file line number Diff line number Diff line change
@@ -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
Expand Down
85 changes: 80 additions & 5 deletions homeassistant/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
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"
Expand Down Expand Up @@ -49,19 +52,22 @@ def __init__(self):
self.bus = EventBus(pool)
self.services = ServiceRegistry(self.bus, pool)
self.states = StateMachine(self.bus)
self.config = Config()

# List of loaded components
self.components = []

# 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 """
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.get_config_path """
return self.config.get_config_path(path)

def start(self):
""" Start home assistant. """
Expand Down Expand Up @@ -836,6 +842,75 @@ def run(self):
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 get_config_path(self, path):
""" Returns path to the file within the config dir. """
return os.path.join(self.config_dir, path)

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 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
Expand Down
35 changes: 30 additions & 5 deletions homeassistant/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
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__)

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.get_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)
Expand All @@ -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:
Expand Down
5 changes: 1 addition & 4 deletions homeassistant/components/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
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"

Expand All @@ -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
Expand Down
5 changes: 3 additions & 2 deletions homeassistant/components/device_tracker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ def update_devices(self, now):
# 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.get_config_path(
KNOWN_DEVICES_FILE)

try:
# If file does not exist we will write the header too
Expand Down Expand Up @@ -214,7 +215,7 @@ def update_devices(self, now):
# 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.get_config_path(KNOWN_DEVICES_FILE)

# Return if no known devices file exists
if not os.path.isfile(known_dev_path):
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/light/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.get_config_path(LIGHT_PROFILES_FILE)]
profiles = {}

for profile_path in profile_paths:
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/light/hue.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.get_config_path(PHUE_CONFIG_FILE))
except ConnectionRefusedError: # Wrong host was given
_LOGGER.exception("Error connecting to the Hue bridge at %s", host)

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/scheduler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def setup_schedule(schedule_data):
schedule.schedule(hass)
return True

with open(hass.get_config_path(_SCHEDULE_FILE)) as schedule_file:
with open(hass.config.get_config_path(_SCHEDULE_FILE)) as schedule_file:
schedule_descriptions = json.load(schedule_file)

for schedule_description in schedule_descriptions:
Expand Down
23 changes: 14 additions & 9 deletions homeassistant/components/sensor/demo.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -36,10 +36,15 @@ def state(self):
""" 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,
}
11 changes: 1 addition & 10 deletions homeassistant/components/sensor/systemmonitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
"""

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

Expand Down Expand Up @@ -63,14 +62,6 @@ def state(self):
""" 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
Expand Down
17 changes: 2 additions & 15 deletions homeassistant/components/sensor/tellstick.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@
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

DatatypeDescription = namedtuple("DatatypeDescription", ['name', 'unit'])
Expand Down Expand Up @@ -99,7 +98,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)

Expand All @@ -112,15 +111,3 @@ def name(self):
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
Loading

0 comments on commit 9b643d5

Please sign in to comment.