Merge pull request #289 from rmkraus/pip_updates

Update dependency installs and prepare for pip deployment
This commit is contained in:
Paulus Schoutsen 2015-08-29 22:11:20 -07:00
commit 5aa8814a67
59 changed files with 359 additions and 306 deletions

View file

@ -3,7 +3,7 @@ language: python
python:
- "3.4"
install:
- pip install -r requirements.txt
- pip install -r requirements_all.txt
- pip install flake8 pylint coveralls
script:
- flake8 homeassistant --exclude bower_components,external

View file

@ -4,12 +4,11 @@ from __future__ import print_function
import sys
import os
import argparse
import subprocess
import importlib
DEPENDENCIES = ['requests>=2.0', 'pyyaml>=3.11', 'pytz>=2015.2']
IS_VIRTUAL = (getattr(sys, 'base_prefix', sys.prefix) != sys.prefix or
hasattr(sys, 'real_prefix'))
from homeassistant import bootstrap
import homeassistant.config as config_util
from homeassistant.const import EVENT_HOMEASSISTANT_START
def validate_python():
@ -18,7 +17,7 @@ def validate_python():
if major < 3 or (major == 3 and minor < 4):
print("Home Assistant requires atleast Python 3.4")
sys.exit()
sys.exit(1)
def ensure_pip():
@ -28,85 +27,43 @@ def ensure_pip():
print("Home Assistant requires 'pip' to be installed.")
print("Please install pip: "
"https://pip.pypa.io/en/latest/installing.html")
sys.exit()
# Copy of homeassistant.util.package because we can't import yet
def install_package(package):
"""Install a package on PyPi. Accepts pip compatible package strings.
Return boolean if install successfull."""
args = [sys.executable, '-m', 'pip', 'install', '--quiet', package]
if not IS_VIRTUAL:
args.append('--user')
try:
return 0 == subprocess.call(args)
except subprocess.SubprocessError:
return False
def validate_dependencies():
""" Validate all dependencies that HA uses. """
ensure_pip()
print("Validating dependencies...")
import_fail = False
for requirement in DEPENDENCIES:
if not install_package(requirement):
import_fail = True
print('Fatal Error: Unable to install dependency', requirement)
if import_fail:
print(("Install dependencies by running: "
"python3 -m pip install -r requirements.txt"))
sys.exit()
def ensure_path_and_load_bootstrap():
""" Ensure sys load path is correct and load Home Assistant bootstrap. """
try:
from homeassistant import bootstrap
except ImportError:
# This is to add support to load Home Assistant using
# `python3 homeassistant` instead of `python3 -m homeassistant`
# Insert the parent directory of this file into the module search path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from homeassistant import bootstrap
return bootstrap
def validate_git_submodules():
""" Validate the git submodules are cloned. """
try:
# pylint: disable=no-name-in-module, unused-variable
from homeassistant.external.noop import WORKING # noqa
except ImportError:
print("Repository submodules have not been initialized")
print("Please run: git submodule update --init --recursive")
sys.exit()
sys.exit(1)
def ensure_config_path(config_dir):
""" Gets the path to the configuration file.
Creates one if it not exists. """
lib_dir = os.path.join(config_dir, 'lib')
# Test if configuration directory exists
if not os.path.isdir(config_dir):
print(('Fatal Error: Unable to find specified configuration '
'directory {} ').format(config_dir))
sys.exit()
if config_dir != config_util.get_default_config_dir():
print(('Fatal Error: Specified configuration directory does '
'not exist {} ').format(config_dir))
sys.exit(1)
import homeassistant.config as config_util
try:
os.mkdir(config_dir)
except OSError:
print(('Fatal Error: Unable to create default configuration '
'directory {} ').format(config_dir))
sys.exit(1)
# Test if library directory exists
if not os.path.isdir(lib_dir):
try:
os.mkdir(lib_dir)
except OSError:
print(('Fatal Error: Unable to create library '
'directory {} ').format(lib_dir))
sys.exit(1)
config_path = config_util.ensure_config_exists(config_dir)
if config_path is None:
print('Error getting configuration path')
sys.exit()
sys.exit(1)
return config_path
@ -117,7 +74,7 @@ def get_arguments():
parser.add_argument(
'-c', '--config',
metavar='path_to_config_dir',
default="config",
default=config_util.get_default_config_dir(),
help="Directory that contains the Home Assistant configuration")
parser.add_argument(
'--demo-mode',
@ -134,14 +91,6 @@ def get_arguments():
def main():
""" Starts Home Assistant. """
validate_python()
validate_dependencies()
# Windows needs this to pick up new modules
importlib.invalidate_caches()
bootstrap = ensure_path_and_load_bootstrap()
validate_git_submodules()
args = get_arguments()
@ -149,18 +98,14 @@ def main():
config_path = ensure_config_path(config_dir)
if args.demo_mode:
from homeassistant.components import frontend, demo
hass = bootstrap.from_config_dict({
frontend.DOMAIN: {},
demo.DOMAIN: {}
})
'frontend': {},
'demo': {}
}, config_dir=config_dir)
else:
hass = bootstrap.from_config_file(config_path)
if args.open_ui:
from homeassistant.const import EVENT_HOMEASSISTANT_START
def open_browser(event):
""" Open the webinterface in a browser. """
if hass.config.api is not None:

View file

@ -10,6 +10,7 @@ start by calling homeassistant.start_home_assistant(bus)
"""
import os
import sys
import logging
from collections import defaultdict
@ -61,13 +62,13 @@ def setup_component(hass, domain, config=None):
return True
def _handle_requirements(component, name):
def _handle_requirements(hass, component, name):
""" Installs requirements for component. """
if not hasattr(component, 'REQUIREMENTS'):
return True
for req in component.REQUIREMENTS:
if not pkg_util.install_package(req):
if not pkg_util.install_package(req, target=hass.config.path('lib')):
_LOGGER.error('Not initializing %s because could not install '
'dependency %s', name, req)
return False
@ -88,7 +89,7 @@ def _setup_component(hass, domain, config):
domain, ", ".join(missing_deps))
return False
if not _handle_requirements(component, domain):
if not _handle_requirements(hass, component, domain):
return False
try:
@ -138,14 +139,19 @@ def prepare_setup_platform(hass, config, domain, platform_name):
component)
return None
if not _handle_requirements(platform, platform_path):
if not _handle_requirements(hass, platform, platform_path):
return None
return platform
def mount_local_lib_path(config_dir):
""" Add local library to Python Path """
sys.path.insert(0, os.path.join(config_dir, 'lib'))
# pylint: disable=too-many-branches, too-many-statements
def from_config_dict(config, hass=None):
def from_config_dict(config, hass=None, config_dir=None):
"""
Tries to configure Home Assistant from a config dict.
@ -153,6 +159,10 @@ def from_config_dict(config, hass=None):
"""
if hass is None:
hass = core.HomeAssistant()
if config_dir is not None:
config_dir = os.path.abspath(config_dir)
hass.config.config_dir = config_dir
mount_local_lib_path(config_dir)
process_ha_core_config(hass, config.get(core.DOMAIN, {}))
@ -195,7 +205,9 @@ def from_config_file(config_path, hass=None):
hass = core.HomeAssistant()
# Set config dir to directory holding config file
hass.config.config_dir = os.path.abspath(os.path.dirname(config_path))
config_dir = os.path.abspath(os.path.dirname(config_path))
hass.config.config_dir = config_dir
mount_local_lib_path(config_dir)
config_dict = config_util.load_config_file(config_path)

View file

@ -42,7 +42,7 @@ from homeassistant.components.device_tracker import DOMAIN
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5)
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['pynetgear>=0.3']
REQUIREMENTS = ['pynetgear==0.3']
def get_scanner(hass, config):

View file

@ -26,8 +26,12 @@ from collections import namedtuple
import subprocess
import re
from libnmap.process import NmapProcess
from libnmap.parser import NmapParser, NmapParserException
try:
from libnmap.process import NmapProcess
from libnmap.parser import NmapParser, NmapParserException
LIB_LOADED = True
except ImportError:
LIB_LOADED = False
import homeassistant.util.dt as dt_util
from homeassistant.const import CONF_HOSTS
@ -43,7 +47,7 @@ _LOGGER = logging.getLogger(__name__)
# interval in minutes to exclude devices from a scan while they are home
CONF_HOME_INTERVAL = "home_interval"
REQUIREMENTS = ['python-libnmap>=0.6.3']
REQUIREMENTS = ['python-libnmap==0.6.1']
def get_scanner(hass, config):
@ -52,6 +56,10 @@ def get_scanner(hass, config):
_LOGGER):
return None
if not LIB_LOADED:
_LOGGER.error("Error while importing dependency python-libnmap.")
return False
scanner = NmapDeviceScanner(config[DOMAIN])
return scanner if scanner.success_init else None

View file

@ -19,7 +19,7 @@ from homeassistant.const import (
DOMAIN = "discovery"
DEPENDENCIES = []
REQUIREMENTS = ['netdisco>=0.3']
REQUIREMENTS = ['netdisco==0.3']
SCAN_INTERVAL = 300 # seconds

View file

@ -21,7 +21,7 @@ from homeassistant.const import (
DOMAIN = "isy994"
DEPENDENCIES = []
REQUIREMENTS = ['PyISY>=1.0.5']
REQUIREMENTS = ['PyISY==1.0.5']
DISCOVER_LIGHTS = "isy994.lights"
DISCOVER_SWITCHES = "isy994.switches"
DISCOVER_SENSORS = "isy994.sensors"

View file

@ -14,7 +14,7 @@ from homeassistant.const import (
DOMAIN = "keyboard"
DEPENDENCIES = []
REQUIREMENTS = ['pyuserinput>=0.1.9']
REQUIREMENTS = ['pyuserinput==0.1.9']
def volume_up(hass):

View file

@ -16,7 +16,7 @@ from homeassistant.components.light import (
ATTR_FLASH, FLASH_LONG, FLASH_SHORT, ATTR_EFFECT,
EFFECT_COLORLOOP)
REQUIREMENTS = ['phue>=0.8']
REQUIREMENTS = ['phue==0.8']
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(milliseconds=100)

View file

@ -34,7 +34,7 @@ from homeassistant.components.light import (Light, ATTR_BRIGHTNESS,
from homeassistant.util.color import color_RGB_to_xy
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['ledcontroller>=1.0.7']
REQUIREMENTS = ['ledcontroller==1.0.7']
def setup_platform(hass, config, add_devices_callback, discovery_info=None):

View file

@ -9,7 +9,7 @@ from homeassistant.components.light import Light, ATTR_BRIGHTNESS
from homeassistant.const import ATTR_FRIENDLY_NAME
import tellcore.constants as tellcore_constants
REQUIREMENTS = ['tellcore-py>=1.0.4']
REQUIREMENTS = ['tellcore-py==1.0.4']
def setup_platform(hass, config, add_devices_callback, discovery_info=None):

View file

@ -9,8 +9,8 @@ from homeassistant.components.light import ATTR_BRIGHTNESS
from homeassistant.components.wink import WinkToggleDevice
from homeassistant.const import CONF_ACCESS_TOKEN
REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/master.zip'
'#pywink>=0.1']
REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/' +
'c2b700e8ca866159566ecf5e644d9c297f69f257.zip']
def setup_platform(hass, config, add_devices_callback, discovery_info=None):

View file

@ -19,7 +19,7 @@ from homeassistant.components.media_player import (
SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK,
MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, MEDIA_TYPE_VIDEO)
REQUIREMENTS = ['pychromecast>=0.6.10']
REQUIREMENTS = ['pychromecast==0.6.10']
CONF_IGNORE_CEC = 'ignore_cec'
CAST_SPLASH = 'https://home-assistant.io/images/cast/splash.png'
SUPPORT_CAST = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \

View file

@ -48,7 +48,7 @@ except ImportError:
jsonrpc_requests = None
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['jsonrpc-requests>=0.1']
REQUIREMENTS = ['jsonrpc-requests==0.1']
SUPPORT_KODI = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \
SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK | SUPPORT_SEEK

View file

@ -48,7 +48,7 @@ from homeassistant.components.media_player import (
MEDIA_TYPE_MUSIC)
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['python-mpd2>=0.5.4']
REQUIREMENTS = ['python-mpd2==0.5.4']
SUPPORT_MPD = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_TURN_OFF | \
SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK

View file

@ -38,8 +38,8 @@ from homeassistant.const import (EVENT_HOMEASSISTANT_START,
DOMAIN = "modbus"
DEPENDENCIES = []
REQUIREMENTS = ['https://github.com/bashwork/pymodbus/archive/python3.zip'
'#pymodbus>=1.2.0']
REQUIREMENTS = ['https://github.com/bashwork/pymodbus/archive/' +
'd7fc4f1cc975631e0a9011390e8017f64b612661.zip']
# Type of network
MEDIUM = "type"

View file

@ -46,7 +46,7 @@ The keep alive in seconds for this client. Default is 60.
import logging
import socket
from homeassistant.core import HomeAssistantError
from homeassistant.exceptions import HomeAssistantError
import homeassistant.util as util
from homeassistant.helpers import validate_config
from homeassistant.const import (
@ -66,7 +66,7 @@ SERVICE_PUBLISH = 'publish'
EVENT_MQTT_MESSAGE_RECEIVED = 'MQTT_MESSAGE_RECEIVED'
DEPENDENCIES = []
REQUIREMENTS = ['paho-mqtt>=1.1']
REQUIREMENTS = ['paho-mqtt==1.1']
CONF_BROKER = 'broker'
CONF_PORT = 'port'

View file

@ -28,7 +28,7 @@ from homeassistant.components.notify import (
from homeassistant.const import CONF_API_KEY
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['pushbullet.py>=0.7.1']
REQUIREMENTS = ['pushbullet.py==0.7.1']
def get_service(hass, config):

View file

@ -42,7 +42,7 @@ from homeassistant.components.notify import (
DOMAIN, ATTR_TITLE, BaseNotificationService)
from homeassistant.const import CONF_API_KEY
REQUIREMENTS = ['python-pushover>=0.2']
REQUIREMENTS = ['python-pushover==0.2']
_LOGGER = logging.getLogger(__name__)

View file

@ -32,7 +32,7 @@ from homeassistant.components.notify import (
DOMAIN, BaseNotificationService)
from homeassistant.const import CONF_API_KEY
REQUIREMENTS = ['slacker>=0.6.8']
REQUIREMENTS = ['slacker==0.6.8']
_LOGGER = logging.getLogger(__name__)

View file

@ -45,7 +45,7 @@ from homeassistant.helpers import validate_config
from homeassistant.components.notify import (
DOMAIN, ATTR_TITLE, BaseNotificationService)
REQUIREMENTS = ['sleekxmpp>=1.3.1', 'dnspython3>=1.12.0']
REQUIREMENTS = ['sleekxmpp==1.3.1', 'dnspython3==1.12.0']
def get_service(hass, config):

View file

@ -71,7 +71,7 @@ from homeassistant.util import Throttle
from homeassistant.helpers.entity import Entity
REQUIREMENTS = ['blockchain>=1.1.2']
REQUIREMENTS = ['blockchain==1.1.2']
_LOGGER = logging.getLogger(__name__)
OPTION_TYPES = {
'wallet': ['Wallet balance', 'BTC'],

View file

@ -44,7 +44,8 @@ from homeassistant.const import TEMP_FAHRENHEIT
from homeassistant.helpers.entity import Entity
# update this requirement to upstream as soon as it supports python3
REQUIREMENTS = ['git+git://github.com/mala-zaba/Adafruit_Python_DHT']
REQUIREMENTS = ['http://github.com/mala-zaba/Adafruit_Python_DHT/archive/' +
'4101340de8d2457dd194bca1e8d11cbfc237e919.zip']
_LOGGER = logging.getLogger(__name__)
SENSOR_TYPES = {
'temperature': ['Temperature', ''],

View file

@ -49,7 +49,7 @@ Details for the API : https://developer.forecast.io/docs/v2
import logging
from datetime import timedelta
REQUIREMENTS = ['python-forecastio>=1.3.3']
REQUIREMENTS = ['python-forecastio==1.3.3']
try:
import forecastio

View file

@ -36,8 +36,8 @@ ATTR_NODE_ID = "node_id"
ATTR_CHILD_ID = "child_id"
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['https://github.com/theolind/pymysensors/archive/master.zip'
'#egg=pymysensors-0.1']
REQUIREMENTS = ['https://github.com/theolind/pymysensors/archive/' +
'35b87d880147a34107da0d40cb815d75e6cb4af7.zip']
def setup_platform(hass, config, add_devices, discovery_info=None):

View file

@ -48,7 +48,7 @@ from homeassistant.util import Throttle
from homeassistant.const import (CONF_API_KEY, TEMP_CELCIUS, TEMP_FAHRENHEIT)
from homeassistant.helpers.entity import Entity
REQUIREMENTS = ['pyowm>=2.2.1']
REQUIREMENTS = ['pyowm==2.2.1']
_LOGGER = logging.getLogger(__name__)
SENSOR_TYPES = {
'weather': ['Condition', ''],

View file

@ -26,8 +26,8 @@ from collections import OrderedDict
from homeassistant.const import (TEMP_CELCIUS)
from homeassistant.helpers.entity import Entity
REQUIREMENTS = ['https://github.com/Danielhiversen/pyRFXtrx/archive/master.zip'
'#RFXtrx>=0.15']
REQUIREMENTS = ['https://github.com/Danielhiversen/pyRFXtrx/archive/' +
'ec7a1aaddf8270db6e5da1c13d58c1547effd7cf.zip']
DATA_TYPES = OrderedDict([
('Temperature', TEMP_CELCIUS),

View file

@ -53,7 +53,7 @@ DEFAULT_VALUE_HIGH = "HIGH"
DEFAULT_VALUE_LOW = "LOW"
DEFAULT_BOUNCETIME = 50
REQUIREMENTS = ['RPi.GPIO>=0.5.11']
REQUIREMENTS = ['RPi.GPIO==0.5.11']
_LOGGER = logging.getLogger(__name__)

View file

@ -66,7 +66,7 @@ import homeassistant.util.dt as dt_util
from homeassistant.helpers.entity import Entity
from homeassistant.const import STATE_ON, STATE_OFF
REQUIREMENTS = ['psutil>=3.0.0']
REQUIREMENTS = ['psutil==3.0.0']
SENSOR_TYPES = {
'disk_use_percent': ['Disk Use', '%'],
'disk_use': ['Disk Use', 'GiB'],

View file

@ -35,7 +35,7 @@ import homeassistant.util as util
DatatypeDescription = namedtuple("DatatypeDescription", ['name', 'unit'])
REQUIREMENTS = ['tellcore-py>=1.0.4']
REQUIREMENTS = ['tellcore-py==1.0.4']
# pylint: disable=unused-argument

View file

@ -18,7 +18,8 @@ from homeassistant.const import CONF_NAME, DEVICE_DEFAULT_NAME
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['https://github.com/rkabadi/temper-python/archive/master.zip']
REQUIREMENTS = ['https://github.com/rkabadi/temper-python/archive/' +
'3dbdaf2d87b8db9a3cd6e5585fc704537dd2d09b.zip']
# pylint: disable=unused-argument

View file

@ -67,7 +67,7 @@ from transmissionrpc.error import TransmissionError
import logging
REQUIREMENTS = ['transmissionrpc>=0.11']
REQUIREMENTS = ['transmissionrpc==0.11']
SENSOR_TYPES = {
'current_status': ['Status', ''],
'download_speed': ['Down Speed', 'MB/s'],

View file

@ -8,8 +8,8 @@ import logging
from homeassistant.helpers.entity import Entity
from homeassistant.const import CONF_ACCESS_TOKEN, STATE_OPEN, STATE_CLOSED
REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/master.zip'
'#pywink>=0.1']
REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/' +
'c2b700e8ca866159566ecf5e644d9c297f69f257.zip']
def setup_platform(hass, config, add_devices, discovery_info=None):

View file

@ -31,7 +31,7 @@ from homeassistant.helpers.entity import Entity
from homeassistant.components.scheduler import ServiceEventListener
DEPENDENCIES = []
REQUIREMENTS = ['astral>=0.8.1']
REQUIREMENTS = ['astral==0.8.1']
DOMAIN = "sun"
ENTITY_ID = "sun.sun"

View file

@ -44,7 +44,8 @@ from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD,\
DEFAULT_USERNAME = 'admin'
DEFAULT_PASSWORD = '1234'
DEVICE_DEFAULT_NAME = 'Edimax Smart Plug'
REQUIREMENTS = ['https://github.com/rkabadi/pyedimax/archive/master.zip']
REQUIREMENTS = ['https://github.com/rkabadi/pyedimax/archive/' +
'365301ce3ff26129a7910c501ead09ea625f3700.zip']
# setup logger
_LOGGER = logging.getLogger(__name__)

View file

@ -49,7 +49,7 @@ except ImportError:
hikvision.api = None
_LOGGING = logging.getLogger(__name__)
REQUIREMENTS = ['hikvision>=0.4']
REQUIREMENTS = ['hikvision==0.4']
# pylint: disable=too-many-arguments
# pylint: disable=too-many-instance-attributes

View file

@ -36,7 +36,7 @@ from homeassistant.const import (DEVICE_DEFAULT_NAME,
DEFAULT_INVERT_LOGIC = False
REQUIREMENTS = ['RPi.GPIO>=0.5.11']
REQUIREMENTS = ['RPi.GPIO==0.5.11']
_LOGGER = logging.getLogger(__name__)

View file

@ -19,7 +19,7 @@ import tellcore.constants as tellcore_constants
SINGAL_REPETITIONS = 1
REQUIREMENTS = ['tellcore-py>=1.0.4']
REQUIREMENTS = ['tellcore-py==1.0.4']
# pylint: disable=unused-argument

View file

@ -48,7 +48,7 @@ from transmissionrpc.error import TransmissionError
import logging
_LOGGING = logging.getLogger(__name__)
REQUIREMENTS = ['transmissionrpc>=0.11']
REQUIREMENTS = ['transmissionrpc==0.11']
# pylint: disable=unused-argument

View file

@ -8,7 +8,7 @@ import logging
from homeassistant.components.switch import SwitchDevice
REQUIREMENTS = ['pywemo>=0.2']
REQUIREMENTS = ['pywemo==0.2']
# pylint: disable=unused-argument

View file

@ -9,8 +9,8 @@ import logging
from homeassistant.components.wink import WinkToggleDevice
from homeassistant.const import CONF_ACCESS_TOKEN
REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/master.zip'
'#pywink>=0.1']
REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/' +
'c2b700e8ca866159566ecf5e644d9c297f69f257.zip']
def setup_platform(hass, config, add_devices, discovery_info=None):

View file

@ -6,7 +6,7 @@ import logging
from homeassistant.components.thermostat import ThermostatDevice
from homeassistant.const import (CONF_USERNAME, CONF_PASSWORD, TEMP_CELCIUS)
REQUIREMENTS = ['python-nest>=2.4.0']
REQUIREMENTS = ['python-nest==2.4.0']
# pylint: disable=unused-argument

View file

@ -61,7 +61,8 @@ DISCOVER_SWITCHES = 'verisure.switches'
DEPENDENCIES = []
REQUIREMENTS = [
'https://github.com/persandstrom/python-verisure/archive/master.zip'
'https://github.com/persandstrom/python-verisure/archive/' +
'9873c4527f01b1ba1f72ae60f7f35854390d59be.zip'
]
_LOGGER = logging.getLogger(__name__)

View file

@ -16,8 +16,8 @@ from homeassistant.const import (
DOMAIN = "wink"
DEPENDENCIES = []
REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/master.zip'
'#pywink>=0.1']
REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/' +
'c2b700e8ca866159566ecf5e644d9c297f69f257.zip']
DISCOVER_LIGHTS = "wink.lights"
DISCOVER_SWITCHES = "wink.switches"

View file

@ -12,7 +12,7 @@ from homeassistant.const import (
DOMAIN = "zwave"
DEPENDENCIES = []
REQUIREMENTS = ['pydispatcher>=2.0.5']
REQUIREMENTS = ['pydispatcher==2.0.5']
CONF_USB_STICK_PATH = "usb_path"
DEFAULT_CONF_USB_STICK_PATH = "/zwaveusbstick"

View file

@ -7,7 +7,7 @@ Module to help with parsing and generating configuration files.
import logging
import os
from homeassistant.core import HomeAssistantError
from homeassistant.exceptions import HomeAssistantError
from homeassistant.const import (
CONF_LATITUDE, CONF_LONGITUDE, CONF_TEMPERATURE_UNIT, CONF_NAME,
CONF_TIME_ZONE)
@ -16,6 +16,7 @@ import homeassistant.util.location as loc_util
_LOGGER = logging.getLogger(__name__)
YAML_CONFIG_FILE = 'configuration.yaml'
CONFIG_DIR_NAME = '.homeassistant'
DEFAULT_CONFIG = (
# Tuples (attribute, default, auto detect property, description)
@ -39,6 +40,13 @@ DEFAULT_COMPONENTS = {
}
def get_default_config_dir():
""" Put together the default configuration directory based on OS. """
data_dir = os.getenv('APPDATA') if os.name == "nt" \
else os.path.expanduser('~')
return os.path.join(data_dir, CONFIG_DIR_NAME)
def ensure_config_exists(config_dir, detect_location=True):
""" Ensures a config file exists in given config dir.
Creating a default one if needed.

View file

@ -1,4 +1,7 @@
""" Constants used by Home Assistant components. """
__version__ = "0.7.0"
# Can be used to specify a catch all when registering state or event listeners.
MATCH_ALL = '*'

View file

@ -21,9 +21,12 @@ from homeassistant.const import (
EVENT_CALL_SERVICE, ATTR_NOW, ATTR_DOMAIN, ATTR_SERVICE, MATCH_ALL,
EVENT_SERVICE_EXECUTED, ATTR_SERVICE_CALL_ID, EVENT_SERVICE_REGISTERED,
TEMP_CELCIUS, TEMP_FAHRENHEIT, ATTR_FRIENDLY_NAME)
from homeassistant.exceptions import (
HomeAssistantError, InvalidEntityFormatError)
import homeassistant.util as util
import homeassistant.util.dt as date_util
import homeassistant.helpers.temperature as temp_helper
from homeassistant.config import get_default_config_dir
DOMAIN = "homeassistant"
@ -660,7 +663,7 @@ class Config(object):
self.api = None
# Directory that holds the configuration
self.config_dir = os.path.join(os.getcwd(), 'config')
self.config_dir = get_default_config_dir()
def path(self, *path):
""" Returns path to the file within the config dir. """
@ -695,21 +698,6 @@ class Config(object):
}
class HomeAssistantError(Exception):
""" General Home Assistant exception occured. """
pass
class InvalidEntityFormatError(HomeAssistantError):
""" When an invalid formatted entity is encountered. """
pass
class NoEntitySpecifiedError(HomeAssistantError):
""" When no entity is specified. """
pass
def create_timer(hass, interval=TIMER_INTERVAL):
""" Creates a timer. Timer will start on HOMEASSISTANT_START. """
# We want to be able to fire every time a minute starts (seconds=0).

View file

@ -0,0 +1,16 @@
""" Exceptions used by Home Assistant """
class HomeAssistantError(Exception):
""" General Home Assistant exception occured. """
pass
class InvalidEntityFormatError(HomeAssistantError):
""" When an invalid formatted entity is encountered. """
pass
class NoEntitySpecifiedError(HomeAssistantError):
""" When no entity is specified. """
pass

View file

@ -7,7 +7,7 @@ Provides ABC for entities in HA.
from collections import defaultdict
from homeassistant.core import NoEntitySpecifiedError
from homeassistant.exceptions import NoEntitySpecifiedError
from homeassistant.const import (
ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT, ATTR_HIDDEN,

View file

@ -18,6 +18,7 @@ import urllib.parse
import requests
import homeassistant.core as ha
from homeassistant.exceptions import HomeAssistantError
import homeassistant.bootstrap as bootstrap
from homeassistant.const import (
@ -84,12 +85,12 @@ class API(object):
except requests.exceptions.ConnectionError:
_LOGGER.exception("Error connecting to server")
raise ha.HomeAssistantError("Error connecting to server")
raise HomeAssistantError("Error connecting to server")
except requests.exceptions.Timeout:
error = "Timeout when talking to {}".format(self.host)
_LOGGER.exception(error)
raise ha.HomeAssistantError(error)
raise HomeAssistantError(error)
def __repr__(self):
return "API({}, {}, {})".format(
@ -102,7 +103,7 @@ class HomeAssistant(ha.HomeAssistant):
def __init__(self, remote_api, local_api=None):
if not remote_api.validate_api():
raise ha.HomeAssistantError(
raise HomeAssistantError(
"Remote API at {}:{} not valid: {}".format(
remote_api.host, remote_api.port, remote_api.status))
@ -121,7 +122,7 @@ class HomeAssistant(ha.HomeAssistant):
# Ensure a local API exists to connect with remote
if self.config.api is None:
if not bootstrap.setup_component(self, 'api'):
raise ha.HomeAssistantError(
raise HomeAssistantError(
'Unable to setup local API to receive events')
ha.create_timer(self)
@ -132,7 +133,7 @@ class HomeAssistant(ha.HomeAssistant):
# Setup that events from remote_api get forwarded to local_api
# Do this after we fire START, otherwise HTTP is not started
if not connect_remote_events(self.remote_api, self.config.api):
raise ha.HomeAssistantError((
raise HomeAssistantError((
'Could not setup event forwarding from api {} to '
'local api {}').format(self.remote_api, self.config.api))
@ -293,7 +294,7 @@ def validate_api(api):
else:
return APIStatus.UNKNOWN
except ha.HomeAssistantError:
except HomeAssistantError:
return APIStatus.CANNOT_CONNECT
@ -318,7 +319,7 @@ def connect_remote_events(from_api, to_api):
return False
except ha.HomeAssistantError:
except HomeAssistantError:
_LOGGER.exception("Error setting up event forwarding")
return False
@ -342,7 +343,7 @@ def disconnect_remote_events(from_api, to_api):
return False
except ha.HomeAssistantError:
except HomeAssistantError:
_LOGGER.exception("Error removing an event forwarder")
return False
@ -354,7 +355,7 @@ def get_event_listeners(api):
return req.json() if req.status_code == 200 else {}
except (ha.HomeAssistantError, ValueError):
except (HomeAssistantError, ValueError):
# ValueError if req.json() can't parse the json
_LOGGER.exception("Unexpected result retrieving event listeners")
@ -371,7 +372,7 @@ def fire_event(api, event_type, data=None):
_LOGGER.error("Error firing event: %d - %d",
req.status_code, req.text)
except ha.HomeAssistantError:
except HomeAssistantError:
_LOGGER.exception("Error firing event")
@ -387,7 +388,7 @@ def get_state(api, entity_id):
return ha.State.from_dict(req.json()) \
if req.status_code == 200 else None
except (ha.HomeAssistantError, ValueError):
except (HomeAssistantError, ValueError):
# ValueError if req.json() can't parse the json
_LOGGER.exception("Error fetching state")
@ -404,7 +405,7 @@ def get_states(api):
return [ha.State.from_dict(item) for
item in req.json()]
except (ha.HomeAssistantError, ValueError, AttributeError):
except (HomeAssistantError, ValueError, AttributeError):
# ValueError if req.json() can't parse the json
_LOGGER.exception("Error fetching states")
@ -434,7 +435,7 @@ def set_state(api, entity_id, new_state, attributes=None):
else:
return True
except ha.HomeAssistantError:
except HomeAssistantError:
_LOGGER.exception("Error setting state")
return False
@ -457,7 +458,7 @@ def get_services(api):
return req.json() if req.status_code == 200 else {}
except (ha.HomeAssistantError, ValueError):
except (HomeAssistantError, ValueError):
# ValueError if req.json() can't parse the json
_LOGGER.exception("Got unexpected services result")
@ -475,5 +476,5 @@ def call_service(api, domain, service, service_data=None):
_LOGGER.error("Error calling service: %d - %s",
req.status_code, req.text)
except ha.HomeAssistantError:
except HomeAssistantError:
_LOGGER.exception("Error calling service")

View file

@ -1,4 +1,5 @@
"""Helpers to install PyPi packages."""
import os
import subprocess
import sys
@ -8,15 +9,15 @@ from . import environment as env
INSTALL_USER = not env.is_virtual()
def install_package(package, upgrade=False, user=INSTALL_USER):
def install_package(package, upgrade=False, target=None):
"""Install a package on PyPi. Accepts pip compatible package strings.
Return boolean if install successfull."""
# Not using 'import pip; pip.main([])' because it breaks the logger
args = [sys.executable, '-m', 'pip', 'install', '--quiet', package]
if upgrade:
args.append('--upgrade')
if user:
args.append('--user')
if target:
args += ['--target', os.path.abspath(target)]
try:
return 0 == subprocess.call(args)
except subprocess.SubprocessError:

View file

@ -1,5 +1,5 @@
[MASTER]
ignore=external
ignore=external,setup.py
reports=no
# Reasons disabled:

View file

@ -1,119 +1,4 @@
# Required for Home Assistant core
requests>=2.0
pyyaml>=3.11
pytz>=2015.2
# Optional, needed for specific components
# Sun (sun)
astral>=0.8.1
# Philips Hue library (lights.hue)
phue>=0.8
# Limitlessled/Easybulb/Milight library (lights.limitlessled)
ledcontroller>=1.0.7
# Chromecast bindings (media_player.cast)
pychromecast>=0.6.10
# Keyboard (keyboard)
pyuserinput>=0.1.9
# Tellstick bindings (*.tellstick)
tellcore-py>=1.0.4
# Nmap bindings (device_tracker.nmap)
python-libnmap>=0.6.3
# PushBullet bindings (notify.pushbullet)
pushbullet.py>=0.7.1
# Nest Thermostat bindings (thermostat.nest)
python-nest>=2.4.0
# Z-Wave (*.zwave)
pydispatcher>=2.0.5
# ISY994 bindings (*.isy994)
PyISY>=1.0.5
# PSutil (sensor.systemmonitor)
psutil>=3.0.0
# Pushover bindings (notify.pushover)
python-pushover>=0.2
# Transmission Torrent Client (*.transmission)
transmissionrpc>=0.11
# OpenWeatherMap Web API (sensor.openweathermap)
pyowm>=2.2.1
# XMPP Bindings (notify.xmpp)
sleekxmpp>=1.3.1
dnspython3>=1.12.0
# Blockchain (sensor.bitcoin)
blockchain>=1.1.2
# MPD Bindings (media_player.mpd)
python-mpd2>=0.5.4
# Hikvision (switch.hikvisioncam)
hikvision>=0.4
# console log coloring
colorlog>=2.6.0
# JSON-RPC interface (media_player.kodi)
jsonrpc-requests>=0.1
# Forecast.io Bindings (sensor.forecast)
python-forecastio>=1.3.3
# Firmata Bindings (*.arduino)
PyMata==2.07a
# Rfxtrx sensor (sensor.rfxtrx)
https://github.com/Danielhiversen/pyRFXtrx/archive/master.zip
# Mysensors
https://github.com/theolind/pymysensors/archive/master.zip#egg=pymysensors-0.1
# Netgear (device_tracker.netgear)
pynetgear>=0.3
# Netdisco (discovery)
netdisco>=0.3
# Wemo (switch.wemo)
pywemo>=0.2
# Wink (*.wink)
https://github.com/balloob/python-wink/archive/master.zip#pywink>=0.1
# Slack notifier (notify.slack)
slacker>=0.6.8
# Temper sensors (sensor.temper)
https://github.com/rkabadi/temper-python/archive/master.zip
# PyEdimax
https://github.com/rkabadi/pyedimax/archive/master.zip
# RPI-GPIO platform (*.rpi_gpio)
RPi.GPIO >=0.5.11
# Adafruit temperature/humidity sensor
# uncomment on a Raspberry Pi / Beaglebone
#git+git://github.com/mala-zaba/Adafruit_Python_DHT
# PAHO MQTT Binding (mqtt)
paho-mqtt>=1.1
# PyModbus (modbus)
https://github.com/bashwork/pymodbus/archive/python3.zip#pymodbus>=1.2.0
# Verisure (verisure)
https://github.com/persandstrom/python-verisure/archive/master.zip
requests>=2,<3
pyyaml>=3.11,<4
pytz>=2015.4
pip>=7.0.0

121
requirements_all.txt Normal file
View file

@ -0,0 +1,121 @@
# Required for Home Assistant core
requests>=2,<3
pyyaml>=3.11,<4
pytz>=2015.4
pip>=7.0.0
# Optional, needed for specific components
# Sun (sun)
astral==0.8.1
# Philips Hue library (lights.hue)
phue==0.8
# Limitlessled/Easybulb/Milight library (lights.limitlessled)
ledcontroller==1.0.7
# Chromecast bindings (media_player.cast)
pychromecast==0.6.10
# Keyboard (keyboard)
pyuserinput==0.1.9
# Tellstick bindings (*.tellstick)
tellcore-py==1.0.4
# Nmap bindings (device_tracker.nmap)
python-libnmap==0.6.3
# PushBullet bindings (notify.pushbullet)
pushbullet.py==0.7.1
# Nest Thermostat bindings (thermostat.nest)
python-nest==2.4.0
# Z-Wave (*.zwave)
pydispatcher==2.0.5
# ISY994 bindings (*.isy994)
PyISY==1.0.5
# PSutil (sensor.systemmonitor)
psutil==3.0.0
# Pushover bindings (notify.pushover)
python-pushover==0.2
# Transmission Torrent Client (*.transmission)
transmissionrpc==0.11
# OpenWeatherMap Web API (sensor.openweathermap)
pyowm==2.2.1
# XMPP Bindings (notify.xmpp)
sleekxmpp==1.3.1
dnspython3==1.12.0
# Blockchain (sensor.bitcoin)
blockchain==1.1.2
# MPD Bindings (media_player.mpd)
python-mpd2==0.5.4
# Hikvision (switch.hikvisioncam)
hikvision==0.4
# console log coloring
colorlog==2.6.0
# JSON-RPC interface (media_player.kodi)
jsonrpc-requests==0.1
# Forecast.io Bindings (sensor.forecast)
python-forecastio==1.3.3
# Firmata Bindings (*.arduino)
PyMata==2.07a
# Rfxtrx sensor (sensor.rfxtrx)
https://github.com/Danielhiversen/pyRFXtrx/archive/ec7a1aaddf8270db6e5da1c13d58c1547effd7cf.zip
# Mysensors
https://github.com/theolind/pymysensors/archive/35b87d880147a34107da0d40cb815d75e6cb4af7.zip
# Netgear (device_tracker.netgear)
pynetgear==0.3
# Netdisco (discovery)
netdisco==0.3
# Wemo (switch.wemo)
pywemo==0.2
# Wink (*.wink)
https://github.com/balloob/python-wink/archive/c2b700e8ca866159566ecf5e644d9c297f69f257.zip
# Slack notifier (notify.slack)
slacker==0.6.8
# Temper sensors (sensor.temper)
https://github.com/rkabadi/temper-python/archive/3dbdaf2d87b8db9a3cd6e5585fc704537dd2d09b.zip
# PyEdimax
https://github.com/rkabadi/pyedimax/archive/365301ce3ff26129a7910c501ead09ea625f3700.zip
# RPI-GPIO platform (*.rpi_gpio)
# Uncomment for Raspberry Pi
# RPi.GPIO ==0.5.11
# Adafruit temperature/humidity sensor
# uncomment on a Raspberry Pi / Beaglebone
# http://github.com/mala-zaba/Adafruit_Python_DHT/archive/4101340de8d2457dd194bca1e8d11cbfc237e919.zip
# PAHO MQTT Binding (mqtt)
paho-mqtt==1.1
# PyModbus (modbus)
https://github.com/bashwork/pymodbus/archive/d7fc4f1cc975631e0a9011390e8017f64b612661.zip
# Verisure (verisure)
https://github.com/persandstrom/python-verisure/archive/9873c4527f01b1ba1f72ae60f7f35854390d59be.zip

53
setup.py Executable file
View file

@ -0,0 +1,53 @@
import os
import re
from setuptools import setup, find_packages
PACKAGE_NAME = 'homeassistant'
HERE = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(HERE, PACKAGE_NAME, 'const.py')) as fp:
VERSION = re.search("__version__ = ['\"]([^']+)['\"]\n", fp.read()).group(1)
DOWNLOAD_URL = \
'https://github.com/balloob/home-assistant/tarball/{}'.format(VERSION)
PACKAGES = find_packages() + \
['homeassistant.external', 'homeassistant.external.noop',
'homeassistant.external.nzbclients', 'homeassistant.external.vera']
PACKAGE_DATA = \
{'homeassistant.components.frontend': ['index.html.template'],
'homeassistant.components.frontend.www_static': ['*.*'],
'homeassistant.components.frontend.www_static.images': ['*.*']}
REQUIRES = \
[line.strip() for line in open('requirements.txt', 'r')]
setup(
name=PACKAGE_NAME,
version=VERSION,
license='MIT License',
url='https://home-assistant.io/',
download_url=DOWNLOAD_URL,
author='Paulus Schoutsen',
author_email='paulus@paulusschoutsen.nl',
description='Open-source home automation platform running on Python 3.',
packages=PACKAGES,
include_package_data=True,
package_data=PACKAGE_DATA,
zip_safe=False,
platforms='any',
install_requires=REQUIRES,
keywords=['home', 'automation'],
entry_points={
'console_scripts': [
'hass = homeassistant.__main__:main'
]
},
classifiers=[
'Intended Audience :: End Users/Desktop',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3.4',
'Topic :: Home Automation'
]
)

View file

@ -16,6 +16,8 @@ from datetime import datetime
import pytz
import homeassistant.core as ha
from homeassistant.exceptions import (
HomeAssistantError, InvalidEntityFormatError)
import homeassistant.util.dt as dt_util
from homeassistant.helpers.event import track_state_change
from homeassistant.const import (
@ -41,7 +43,7 @@ class TestHomeAssistant(unittest.TestCase):
""" Stop down stuff we started. """
try:
self.hass.stop()
except ha.HomeAssistantError:
except HomeAssistantError:
# Already stopped after the block till stopped test
pass
@ -250,7 +252,7 @@ class TestState(unittest.TestCase):
def test_init(self):
""" Test state.init """
self.assertRaises(
ha.InvalidEntityFormatError, ha.State,
InvalidEntityFormatError, ha.State,
'invalid_entity_format', 'test_state')
def test_domain(self):
@ -489,18 +491,24 @@ class TestConfig(unittest.TestCase):
def test_config_dir_set_correct(self):
""" Test config dir set correct. """
self.assertEqual(os.path.join(os.getcwd(), "config"),
data_dir = os.getenv('APPDATA') if os.name == "nt" \
else os.path.expanduser('~')
self.assertEqual(os.path.join(data_dir, ".homeassistant"),
self.config.config_dir)
def test_path_with_file(self):
""" Test get_config_path method. """
self.assertEqual(os.path.join(os.getcwd(), "config", "test.conf"),
data_dir = os.getenv('APPDATA') if os.name == "nt" \
else os.path.expanduser('~')
self.assertEqual(os.path.join(data_dir, ".homeassistant", "test.conf"),
self.config.path("test.conf"))
def test_path_with_dir_and_file(self):
""" Test get_config_path method. """
data_dir = os.getenv('APPDATA') if os.name == "nt" \
else os.path.expanduser('~')
self.assertEqual(
os.path.join(os.getcwd(), "config", "dir", "test.conf"),
os.path.join(data_dir, ".homeassistant", "dir", "test.conf"),
self.config.path("dir", "test.conf"))
def test_temperature_not_convert_if_no_preference(self):