Merge branch 'dev' of https://github.com/balloob/home-assistant into automation_confg_list

This commit is contained in:
Stefan Jonasson 2015-09-19 15:27:46 +02:00
commit e1a7b8f988
30 changed files with 198 additions and 136 deletions

View File

@ -3,11 +3,6 @@ language: python
python:
- "3.4"
install:
- pip install -r requirements_all.txt
- pip install flake8 pylint coveralls
- script/bootstrap_server
script:
- flake8 homeassistant
- pylint homeassistant
- coverage run -m unittest discover tests
after_success:
- coveralls
- script/cibuild

View File

@ -103,6 +103,10 @@ def get_arguments():
'--uninstall-osx',
action='store_true',
help='Uninstalls from OS X.')
parser.add_argument(
'--restart-osx',
action='store_true',
help='Restarts on OS X.')
if os.name != "nt":
parser.add_argument(
'--daemon',
@ -216,6 +220,10 @@ def main():
if args.uninstall_osx:
uninstall_osx()
return
if args.restart_osx:
uninstall_osx()
install_osx()
return
# daemon functions
if args.pid_file:

View File

@ -27,8 +27,7 @@ def trigger(hass, config, action):
if CONF_AFTER in config:
after = dt_util.parse_time_str(config[CONF_AFTER])
if after is None:
_LOGGER.error(
'Received invalid after value: %s', config[CONF_AFTER])
_error_time(config[CONF_AFTER], CONF_AFTER)
return False
hours, minutes, seconds = after.hour, after.minute, after.second
elif (CONF_HOURS in config or CONF_MINUTES in config
@ -63,27 +62,27 @@ def if_action(hass, config):
CONF_BEFORE, CONF_AFTER, CONF_WEEKDAY)
return None
if before is not None:
before = dt_util.parse_time_str(before)
if before is None:
_error_time(before, CONF_BEFORE)
return None
if after is not None:
after = dt_util.parse_time_str(after)
if after is None:
_error_time(after, CONF_AFTER)
return None
def time_if():
""" Validate time based if-condition """
now = dt_util.now()
if before is not None:
time = dt_util.parse_time_str(before)
if time is None:
if before is not None and now > now.replace(hour=before.hour,
minute=before.minute):
return False
before_point = now.replace(hour=time.hour, minute=time.minute)
if now > before_point:
return False
if after is not None:
time = dt_util.parse_time_str(after)
if time is None:
return False
after_point = now.replace(hour=time.hour, minute=time.minute)
if now < after_point:
if after is not None and now < now.replace(hour=after.hour,
minute=after.minute):
return False
if weekday is not None:
@ -96,3 +95,11 @@ def if_action(hass, config):
return True
return time_if
def _error_time(value, key):
""" Helper method to print error. """
_LOGGER.error(
"Received invalid value for '%s': %s", key, value)
if isinstance(value, int):
_LOGGER.error('Make sure you wrap time values in quotes')

View File

@ -1,41 +1,31 @@
"""
Support for Foscam IP Cameras.
homeassistant.components.camera.foscam
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This component provides basic support for Foscam IP cameras.
As part of the basic support the following features will be provided:
-MJPEG video streaming
To use this component, add the following to your config/configuration.yaml:
To use this component, add the following to your configuration.yaml file.
camera:
platform: foscam
name: Door Camera
ip: 192.168.0.123
port: 88
username: visitor
password: password
platform: foscam
name: Door Camera
ip: 192.168.0.123
port: 88
username: YOUR_USERNAME
password: YOUR_PASSWORD
camera 2:
name: 'Second Camera'
...
camera 3:
name: 'Camera Three'
...
VARIABLES:
These are the variables for the device_data array:
Variables:
ip
*Required
The IP address of your foscam device
The IP address of your Foscam device.
username
*Required
The username of a visitor or operator of your camera.
Oddly admin accounts don't seem to have access to take snapshots.
The username of a visitor or operator of your camera. Oddly admin accounts
don't seem to have access to take snapshots.
password
*Required
@ -49,6 +39,8 @@ port
*Optional
The port that the camera is running on. The default is 88.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.foscam.html
"""
import logging
from homeassistant.helpers import validate_config
@ -72,9 +64,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
# pylint: disable=too-many-instance-attributes
class FoscamCamera(Camera):
"""
An implementation of a Foscam IP camera.
"""
""" An implementation of a Foscam IP camera. """
def __init__(self, device_info):
super(FoscamCamera, self).__init__()
@ -94,7 +84,7 @@ class FoscamCamera(Camera):
self._name, self._snap_picture_url)
def camera_image(self):
""" Return a still image reponse from the camera """
""" Return a still image reponse from the camera. """
# send the request to snap a picture
response = requests.get(self._snap_picture_url)
@ -111,5 +101,5 @@ class FoscamCamera(Camera):
@property
def name(self):
""" Return the name of this device """
""" Return the name of this device. """
return self._name

View File

@ -28,6 +28,14 @@ REQUIREMENTS = ['SoCo==0.11.1']
_LOGGER = logging.getLogger(__name__)
# The soco library is excessively chatty when it comes to logging and
# causes a LOT of spam in the logs due to making a http connection to each
# speaker every 10 seconds. Quiet it down a bit to just actual problems.
_SOCO_LOGGER = logging.getLogger('soco')
_SOCO_LOGGER.setLevel(logging.ERROR)
_REQUESTS_LOGGER = logging.getLogger('requests')
_REQUESTS_LOGGER.setLevel(logging.ERROR)
SUPPORT_SONOS = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE |\
SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK | SUPPORT_SEEK

View File

@ -256,7 +256,7 @@ class Recorder(threading.Thread):
""" Query the database. """
try:
with self.conn, self.lock:
_LOGGER.info("Running query %s", sql_query)
_LOGGER.debug("Running query %s", sql_query)
cur = self.conn.cursor()

View File

@ -70,7 +70,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
data,
config.get('name', DEFAULT_NAME),
config.get('unit_of_measurement'),
config.get('correction_factor', None),
config.get('correction_factor', 1.0),
config.get('decimal_places', 0)
)])
@ -108,12 +108,15 @@ class CommandSensor(Entity):
self.data.update()
value = self.data.value
if value is not None:
if self._corr_factor is not None:
self._state = round((int(value) * self._corr_factor),
self._decimal_places)
else:
self._state = value
try:
if value is not None:
if self._corr_factor is not None:
self._state = round((float(value) * self._corr_factor),
self._decimal_places)
else:
self._state = value
except ValueError:
self._state = value
# pylint: disable=too-few-public-methods

View File

@ -3,7 +3,6 @@ homeassistant.components.sensor.glances
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Gathers system information of hosts which running glances.
Configuration:
To use the glances sensor you will need to add something like the following

View File

@ -91,7 +91,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
_LOGGER.error(
"Connection error "
"Please check your settings for OpenWeatherMap.")
return None
return False
data = WeatherData(owm, forecast, hass.config.latitude,
hass.config.longitude)

View File

@ -31,7 +31,7 @@ Details for the API : http://transport.opendata.ch
"""
import logging
from datetime import timedelta
from requests import get
import requests
from homeassistant.util import Throttle
import homeassistant.util.dt as dt_util
@ -53,8 +53,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
try:
for location in [config.get('from', None), config.get('to', None)]:
# transport.opendata.ch doesn't play nice with requests.Session
result = get(_RESOURCE + 'locations?query=%s' % location,
timeout=10)
result = requests.get(_RESOURCE + 'locations?query=%s' % location,
timeout=10)
journey.append(result.json()['stations'][0]['name'])
except KeyError:
_LOGGER.exception(
@ -110,7 +110,7 @@ class PublicTransportData(object):
def update(self):
""" Gets the latest data from opendata.ch. """
response = get(
response = requests.get(
_RESOURCE +
'connections?' +
'from=' + self.start + '&' +

View File

@ -1,6 +1,6 @@
"""Helpers to install PyPi packages."""
import os
import logging
import os
import pkg_resources
import subprocess
import sys
@ -15,25 +15,24 @@ def install_package(package, upgrade=True, 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 target:
args += ['--target', os.path.abspath(target)]
with INSTALL_LOCK:
if check_package_exists(package, target):
return True
_LOGGER.info('Attempting install of %s', package)
args = [sys.executable, '-m', 'pip', 'install', '--quiet', package]
if upgrade:
args.append('--upgrade')
if target:
args += ['--target', os.path.abspath(target)]
try:
return 0 == subprocess.call(args)
except subprocess.SubprocessError:
return False
def check_package_exists(package, target=None):
def check_package_exists(package, target):
"""Check if a package exists.
Returns True when the requirement is met.
Returns False when the package is not installed or doesn't meet req."""
@ -43,16 +42,5 @@ def check_package_exists(package, target=None):
# This is a zip file
req = pkg_resources.Requirement.parse(urlparse(package).fragment)
if target:
work_set = pkg_resources.WorkingSet([target])
search_fun = work_set.find
else:
search_fun = pkg_resources.get_distribution
try:
result = search_fun(req)
except (pkg_resources.DistributionNotFound, pkg_resources.VersionConflict):
return False
return bool(result)
return any(dist in req for dist in
pkg_resources.find_distributions(target))

9
script/bootstrap Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
# script/bootstrap: Resolve all dependencies that the application requires to
# run.
cd "$(dirname "$0")/.."
script/bootstrap_server
script/bootstrap_frontend

5
script/bootstrap_frontend Executable file
View File

@ -0,0 +1,5 @@
echo "Bootstrapping frontend..."
cd homeassistant/components/frontend/www_static/home-assistant-polymer
npm install
npm run setup_js_dev
cd ../../../../..

10
script/bootstrap_server Executable file
View File

@ -0,0 +1,10 @@
cd "$(dirname "$0")/.."
echo "Update the submodule to latest version..."
git submodule update
echo "Installing dependencies..."
python3 -m pip install --upgrade -r requirements_all.txt
echo "Installing development dependencies.."
python3 -m pip install --upgrade flake8 pylint coveralls pytest pytest-cov

View File

@ -1,12 +1,8 @@
# Builds the frontend for production
# If current pwd is scripts, go 1 up.
if [ ${PWD##*/} == "scripts" ]; then
cd ..
fi
cd "$(dirname "$0")/.."
cd homeassistant/components/frontend/www_static/home-assistant-polymer
npm install
npm run frontend_prod
cp bower_components/webcomponentsjs/webcomponents-lite.min.js ..

View File

@ -3,10 +3,7 @@
# apt-get install cython3 libudev-dev python-sphinx python3-setuptools
# pip3 install cython
# If current pwd is scripts, go 1 up.
if [ ${PWD##*/} == "scripts" ]; then
cd ..
fi
cd "$(dirname "$0")/.."
if [ ! -d build ]; then
mkdir build

7
script/cibuild Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
# script/cibuild: Setup environment for CI to run tests. This is primarily
# designed to run on the continuous integration server.
script/test coverage
coveralls

View File

@ -3,10 +3,7 @@
# Optional: pass in a timezone as first argument
# If not given will attempt to mount /etc/localtime
# If current pwd is scripts, go 1 up.
if [ ${PWD##*/} == "scripts" ]; then
cd ..
fi
cd "$(dirname "$0")/.."
docker build -t home-assistant-dev .

View File

@ -1,10 +1,7 @@
# Open a docker that can be used to debug/dev python-openzwave
# Pass in a command line argument to build
# If current pwd is scripts, go 1 up.
if [ ${PWD##*/} == "scripts" ]; then
cd ..
fi
cd "$(dirname "$0")/.."
if [ $# -gt 0 ]
then

3
scripts/hass-daemon → script/hass-daemon Normal file → Executable file
View File

@ -34,6 +34,7 @@ RUN_AS="USER"
PID_FILE="/var/run/hass.pid"
CONFIG_DIR="/var/opt/homeassistant"
FLAGS="-v --config $CONFIG_DIR --pid-file $PID_FILE --daemon"
REDIRECT="> $CONFIG_DIR/home-assistant.log 2>&1"
start() {
if [ -f $PID_FILE ] && kill -0 $(cat $PID_FILE); then
@ -41,7 +42,7 @@ start() {
return 1
fi
echo 'Starting service…' >&2
local CMD="$PRE_EXEC hass $FLAGS;"
local CMD="$PRE_EXEC hass $FLAGS $REDIRECT;"
su -c "$CMD" $RUN_AS
echo 'Service started' >&2
}

9
script/lint Executable file
View File

@ -0,0 +1,9 @@
# Run style checks
cd "$(dirname "$0")/.."
echo "Checking style with flake8..."
flake8 homeassistant
echo "Checking style with pylint..."
pylint homeassistant

8
script/server Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
# script/server: Launch the application and any extra required processes
# locally.
cd "$(dirname "$0")/.."
python3 -m homeassistant -c config

5
script/setup Executable file
View File

@ -0,0 +1,5 @@
cd "$(dirname "$0")/.."
git submodule init
script/bootstrap
python3 setup.py develop

16
script/test Executable file
View File

@ -0,0 +1,16 @@
#!/bin/sh
# script/test: Run test suite for application. Optionallly pass in a path to an
# individual test file to run a single test.
cd "$(dirname "$0")/.."
script/lint
echo "Running tests..."
if [ "$1" = "coverage" ]; then
py.test --cov homeassistant tests
else
py.test tests
fi

8
script/update Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
# script/update: Update application to run for its current checkout.
cd "$(dirname "$0")/.."
git pull
git submodule update

View File

@ -1,9 +0,0 @@
# Run style checks
# If current pwd is scripts, go 1 up.
if [ ${PWD##*/} == "scripts" ]; then
cd ..
fi
flake8 homeassistant
pylint homeassistant

View File

@ -1,10 +0,0 @@
# If current pwd is scripts, go 1 up.
if [ ${PWD##*/} == "scripts" ]; then
cd ..
fi
if [ "$1" = "coverage" ]; then
coverage run -m unittest discover tests
else
python3 -m unittest discover tests
fi

View File

@ -1,6 +0,0 @@
echo "The update script has been deprecated since Home Assistant v0.7"
echo
echo "Home Assistant is now distributed via PyPi and can be installed and"
echo "upgraded by running: pip3 install --upgrade homeassistant"
echo
echo "If you are developing a new feature for Home Assistant, run: git pull"

View File

@ -285,9 +285,9 @@ class TestAutomationTime(unittest.TestCase):
automation.DOMAIN: {
'trigger': {
'platform': 'time',
'hours': 0,
'minutes': 0,
'seconds': 0,
'hours': 1,
'minutes': 2,
'seconds': 3,
},
'action': {
'execute_service': 'test.automation'
@ -296,7 +296,7 @@ class TestAutomationTime(unittest.TestCase):
}))
fire_time_changed(self.hass, dt_util.utcnow().replace(
hour=0, minute=0, second=0))
hour=1, minute=2, second=3))
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
@ -320,6 +320,30 @@ class TestAutomationTime(unittest.TestCase):
self.hass.pool.block_till_done()
self.assertEqual(1, len(self.calls))
@patch('homeassistant.components.automation.time._LOGGER.error')
def test_if_not_fires_using_wrong_after(self, mock_error):
""" YAML translates time values to total seconds. This should break the
before rule. """
self.assertTrue(automation.setup(self.hass, {
automation.DOMAIN: {
'trigger': {
'platform': 'time',
'after': 3605,
# Total seconds. Hour = 3600 second
},
'action': {
'execute_service': 'test.automation'
}
}
}))
fire_time_changed(self.hass, dt_util.utcnow().replace(
hour=1, minute=0, second=5))
self.hass.pool.block_till_done()
self.assertEqual(0, len(self.calls))
self.assertEqual(2, mock_error.call_count)
def test_if_action_before(self):
automation.setup(self.hass, {
automation.DOMAIN: {