diff --git a/.travis.yml b/.travis.yml index 7af8ce86dcd..65e417fffb6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/homeassistant/__main__.py b/homeassistant/__main__.py index 2514b35587f..815404b1de1 100644 --- a/homeassistant/__main__.py +++ b/homeassistant/__main__.py @@ -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: diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index e5f6d2b9672..e9f04d9ab71 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -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) diff --git a/homeassistant/components/device_tracker/netgear.py b/homeassistant/components/device_tracker/netgear.py index c04a1d07b1f..346fbb37d37 100644 --- a/homeassistant/components/device_tracker/netgear.py +++ b/homeassistant/components/device_tracker/netgear.py @@ -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): diff --git a/homeassistant/components/device_tracker/nmap_tracker.py b/homeassistant/components/device_tracker/nmap_tracker.py index 00fc8fd12b4..ee1650594ee 100644 --- a/homeassistant/components/device_tracker/nmap_tracker.py +++ b/homeassistant/components/device_tracker/nmap_tracker.py @@ -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 diff --git a/homeassistant/components/discovery.py b/homeassistant/components/discovery.py index 4ad0299cc8f..c21249fbc60 100644 --- a/homeassistant/components/discovery.py +++ b/homeassistant/components/discovery.py @@ -19,7 +19,7 @@ from homeassistant.const import ( DOMAIN = "discovery" DEPENDENCIES = [] -REQUIREMENTS = ['netdisco>=0.3'] +REQUIREMENTS = ['netdisco==0.3'] SCAN_INTERVAL = 300 # seconds diff --git a/homeassistant/components/frontend/www_static/__init__.py b/homeassistant/components/frontend/www_static/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/homeassistant/components/frontend/www_static/images/__init__.py b/homeassistant/components/frontend/www_static/images/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/homeassistant/components/isy994.py b/homeassistant/components/isy994.py index f5998faeaf8..63c7b6c4af6 100644 --- a/homeassistant/components/isy994.py +++ b/homeassistant/components/isy994.py @@ -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" diff --git a/homeassistant/components/keyboard.py b/homeassistant/components/keyboard.py index 5359791087e..3629fce31bf 100644 --- a/homeassistant/components/keyboard.py +++ b/homeassistant/components/keyboard.py @@ -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): diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index c3b28ec1dd6..b438d7b92b1 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -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) diff --git a/homeassistant/components/light/limitlessled.py b/homeassistant/components/light/limitlessled.py index b3e0858ffe2..8fdb525d4e0 100644 --- a/homeassistant/components/light/limitlessled.py +++ b/homeassistant/components/light/limitlessled.py @@ -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): diff --git a/homeassistant/components/light/tellstick.py b/homeassistant/components/light/tellstick.py index 9132604b294..8068d20bb74 100644 --- a/homeassistant/components/light/tellstick.py +++ b/homeassistant/components/light/tellstick.py @@ -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): diff --git a/homeassistant/components/light/wink.py b/homeassistant/components/light/wink.py index e8c8eb7a224..4b5af0c3250 100644 --- a/homeassistant/components/light/wink.py +++ b/homeassistant/components/light/wink.py @@ -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): diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 5fca233013a..d19e4166c1c 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -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 | \ diff --git a/homeassistant/components/media_player/kodi.py b/homeassistant/components/media_player/kodi.py index 4b24f8694ed..dfc2f64a2a8 100644 --- a/homeassistant/components/media_player/kodi.py +++ b/homeassistant/components/media_player/kodi.py @@ -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 diff --git a/homeassistant/components/media_player/mpd.py b/homeassistant/components/media_player/mpd.py index 0239173f7cc..aca2413d3e4 100644 --- a/homeassistant/components/media_player/mpd.py +++ b/homeassistant/components/media_player/mpd.py @@ -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 diff --git a/homeassistant/components/modbus.py b/homeassistant/components/modbus.py index 0bd3b23c2f9..e6c3f1cfcee 100644 --- a/homeassistant/components/modbus.py +++ b/homeassistant/components/modbus.py @@ -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" diff --git a/homeassistant/components/mqtt.py b/homeassistant/components/mqtt.py index aa1a3167029..474b5ebb53e 100644 --- a/homeassistant/components/mqtt.py +++ b/homeassistant/components/mqtt.py @@ -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' diff --git a/homeassistant/components/notify/pushbullet.py b/homeassistant/components/notify/pushbullet.py index 5e322cfc3b5..58462954d2e 100644 --- a/homeassistant/components/notify/pushbullet.py +++ b/homeassistant/components/notify/pushbullet.py @@ -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): diff --git a/homeassistant/components/notify/pushover.py b/homeassistant/components/notify/pushover.py index 1bc5e9ac9a3..0df035a4a6e 100644 --- a/homeassistant/components/notify/pushover.py +++ b/homeassistant/components/notify/pushover.py @@ -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__) diff --git a/homeassistant/components/notify/slack.py b/homeassistant/components/notify/slack.py index 859b5b0388a..d604cffb754 100644 --- a/homeassistant/components/notify/slack.py +++ b/homeassistant/components/notify/slack.py @@ -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__) diff --git a/homeassistant/components/notify/xmpp.py b/homeassistant/components/notify/xmpp.py index e756be82014..81268c734b7 100644 --- a/homeassistant/components/notify/xmpp.py +++ b/homeassistant/components/notify/xmpp.py @@ -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): diff --git a/homeassistant/components/sensor/bitcoin.py b/homeassistant/components/sensor/bitcoin.py index e0ecbab6db5..b30886448ad 100644 --- a/homeassistant/components/sensor/bitcoin.py +++ b/homeassistant/components/sensor/bitcoin.py @@ -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'], diff --git a/homeassistant/components/sensor/dht.py b/homeassistant/components/sensor/dht.py index c7df4b4a8d3..7949a7a44fa 100644 --- a/homeassistant/components/sensor/dht.py +++ b/homeassistant/components/sensor/dht.py @@ -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', ''], diff --git a/homeassistant/components/sensor/forecast.py b/homeassistant/components/sensor/forecast.py index a9783104cd8..b56432ab89b 100644 --- a/homeassistant/components/sensor/forecast.py +++ b/homeassistant/components/sensor/forecast.py @@ -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 diff --git a/homeassistant/components/sensor/mysensors.py b/homeassistant/components/sensor/mysensors.py index a626858db31..994b110a585 100644 --- a/homeassistant/components/sensor/mysensors.py +++ b/homeassistant/components/sensor/mysensors.py @@ -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): diff --git a/homeassistant/components/sensor/openweathermap.py b/homeassistant/components/sensor/openweathermap.py index f4635cd13ca..537fc9f59b5 100644 --- a/homeassistant/components/sensor/openweathermap.py +++ b/homeassistant/components/sensor/openweathermap.py @@ -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', ''], diff --git a/homeassistant/components/sensor/rfxtrx.py b/homeassistant/components/sensor/rfxtrx.py index ffc688804ef..8e5a1ad3dca 100644 --- a/homeassistant/components/sensor/rfxtrx.py +++ b/homeassistant/components/sensor/rfxtrx.py @@ -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), diff --git a/homeassistant/components/sensor/rpi_gpio.py b/homeassistant/components/sensor/rpi_gpio.py index c57cf31b397..f973b24a301 100644 --- a/homeassistant/components/sensor/rpi_gpio.py +++ b/homeassistant/components/sensor/rpi_gpio.py @@ -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__) diff --git a/homeassistant/components/sensor/systemmonitor.py b/homeassistant/components/sensor/systemmonitor.py index 1d1bdb1f3b5..b473cc27283 100644 --- a/homeassistant/components/sensor/systemmonitor.py +++ b/homeassistant/components/sensor/systemmonitor.py @@ -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'], diff --git a/homeassistant/components/sensor/tellstick.py b/homeassistant/components/sensor/tellstick.py index 7d024333023..e93c6e4c97f 100644 --- a/homeassistant/components/sensor/tellstick.py +++ b/homeassistant/components/sensor/tellstick.py @@ -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 diff --git a/homeassistant/components/sensor/temper.py b/homeassistant/components/sensor/temper.py index e443e81b93f..8579a922661 100644 --- a/homeassistant/components/sensor/temper.py +++ b/homeassistant/components/sensor/temper.py @@ -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 diff --git a/homeassistant/components/sensor/transmission.py b/homeassistant/components/sensor/transmission.py index b9ed3ea4e9f..587f5131d9d 100644 --- a/homeassistant/components/sensor/transmission.py +++ b/homeassistant/components/sensor/transmission.py @@ -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'], diff --git a/homeassistant/components/sensor/wink.py b/homeassistant/components/sensor/wink.py index 4056bbd7733..0b3d33cea24 100644 --- a/homeassistant/components/sensor/wink.py +++ b/homeassistant/components/sensor/wink.py @@ -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): diff --git a/homeassistant/components/sun.py b/homeassistant/components/sun.py index 507c4a2b63b..802eddb4a3a 100644 --- a/homeassistant/components/sun.py +++ b/homeassistant/components/sun.py @@ -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" diff --git a/homeassistant/components/switch/edimax.py b/homeassistant/components/switch/edimax.py index 17fe6d61735..200c5746e27 100644 --- a/homeassistant/components/switch/edimax.py +++ b/homeassistant/components/switch/edimax.py @@ -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__) diff --git a/homeassistant/components/switch/hikvisioncam.py b/homeassistant/components/switch/hikvisioncam.py index 5ab084319fc..6ab82df482a 100644 --- a/homeassistant/components/switch/hikvisioncam.py +++ b/homeassistant/components/switch/hikvisioncam.py @@ -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 diff --git a/homeassistant/components/switch/rpi_gpio.py b/homeassistant/components/switch/rpi_gpio.py index bb9cf13e3ed..4afa38aa80a 100644 --- a/homeassistant/components/switch/rpi_gpio.py +++ b/homeassistant/components/switch/rpi_gpio.py @@ -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__) diff --git a/homeassistant/components/switch/tellstick.py b/homeassistant/components/switch/tellstick.py index 4fde4babf9e..230151382e7 100644 --- a/homeassistant/components/switch/tellstick.py +++ b/homeassistant/components/switch/tellstick.py @@ -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 diff --git a/homeassistant/components/switch/transmission.py b/homeassistant/components/switch/transmission.py index 7575951f53b..d5cf716c770 100644 --- a/homeassistant/components/switch/transmission.py +++ b/homeassistant/components/switch/transmission.py @@ -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 diff --git a/homeassistant/components/switch/wemo.py b/homeassistant/components/switch/wemo.py index d133191e6db..2d6e25b296b 100644 --- a/homeassistant/components/switch/wemo.py +++ b/homeassistant/components/switch/wemo.py @@ -8,7 +8,7 @@ import logging from homeassistant.components.switch import SwitchDevice -REQUIREMENTS = ['pywemo>=0.2'] +REQUIREMENTS = ['pywemo==0.2'] # pylint: disable=unused-argument diff --git a/homeassistant/components/switch/wink.py b/homeassistant/components/switch/wink.py index 556a40b181f..c9fb045d9c0 100644 --- a/homeassistant/components/switch/wink.py +++ b/homeassistant/components/switch/wink.py @@ -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): diff --git a/homeassistant/components/thermostat/nest.py b/homeassistant/components/thermostat/nest.py index cb74fa091ff..1de729b590d 100644 --- a/homeassistant/components/thermostat/nest.py +++ b/homeassistant/components/thermostat/nest.py @@ -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 diff --git a/homeassistant/components/verisure.py b/homeassistant/components/verisure.py index f084ce9874c..d716c8c46ad 100644 --- a/homeassistant/components/verisure.py +++ b/homeassistant/components/verisure.py @@ -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__) diff --git a/homeassistant/components/wink.py b/homeassistant/components/wink.py index d56a244b84c..eb2beac508a 100644 --- a/homeassistant/components/wink.py +++ b/homeassistant/components/wink.py @@ -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" diff --git a/homeassistant/components/zwave.py b/homeassistant/components/zwave.py index ce189a242b4..ef7e7308959 100644 --- a/homeassistant/components/zwave.py +++ b/homeassistant/components/zwave.py @@ -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" diff --git a/homeassistant/config.py b/homeassistant/config.py index 54ad297e62a..ca2d43eeb40 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -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. diff --git a/homeassistant/const.py b/homeassistant/const.py index 7d58dbb01d2..a3b9cc8d396 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -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 = '*' diff --git a/homeassistant/core.py b/homeassistant/core.py index 76b4b38f3fc..c04e9a9ab63 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -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). diff --git a/homeassistant/exceptions.py b/homeassistant/exceptions.py new file mode 100644 index 00000000000..bd32d356670 --- /dev/null +++ b/homeassistant/exceptions.py @@ -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 diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index 0ca63856c27..b29379049d3 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -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, diff --git a/homeassistant/remote.py b/homeassistant/remote.py index 2488f0a9c46..2193ede86e7 100644 --- a/homeassistant/remote.py +++ b/homeassistant/remote.py @@ -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") diff --git a/homeassistant/util/package.py b/homeassistant/util/package.py index d220a5a7e61..75d59970bfb 100644 --- a/homeassistant/util/package.py +++ b/homeassistant/util/package.py @@ -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: diff --git a/pylintrc b/pylintrc index 54b1f80cdc5..888fb50ee0f 100644 --- a/pylintrc +++ b/pylintrc @@ -1,5 +1,5 @@ [MASTER] -ignore=external +ignore=external,setup.py reports=no # Reasons disabled: diff --git a/requirements.txt b/requirements.txt index f851f70e86f..1b7d2396971 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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 diff --git a/requirements_all.txt b/requirements_all.txt new file mode 100644 index 00000000000..a900846e30d --- /dev/null +++ b/requirements_all.txt @@ -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 diff --git a/setup.py b/setup.py new file mode 100755 index 00000000000..610a7398735 --- /dev/null +++ b/setup.py @@ -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' + ] +) diff --git a/tests/test_core.py b/tests/test_core.py index 6e7b52795b2..1aab679805a 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -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):