Compare commits

...

432 Commits

Author SHA1 Message Date
Paulus Schoutsen 527d30ae4a Merge pull request #680 from balloob/dev
Version 0.9.0
2015-12-06 11:45:08 -08:00
Paulus Schoutsen 535a3c399e Version bump to 0.9.0 2015-12-06 11:44:38 -08:00
Paulus Schoutsen e0c4c8d7dd Remove unused constant in HTTP 2015-12-06 11:41:43 -08:00
Paulus Schoutsen d9b8ab8851 Update frontend 2015-12-06 11:34:53 -08:00
Paulus Schoutsen b2ae365558 Scripts call services in blocking manner 2015-12-06 11:03:31 -08:00
Paulus Schoutsen 1cb4d40bbb Update frontend 2015-12-06 10:00:10 -08:00
Paulus Schoutsen b7712ac682 Clean up influx component 2015-12-06 09:45:58 -08:00
Paulus Schoutsen a833e8b413 Update requirements_all.txt 2015-12-06 09:38:49 -08:00
Paulus Schoutsen e112620b2d Merge pull request #648 from fabaff/influx
Influx component
2015-12-06 09:38:13 -08:00
Paulus Schoutsen 934b097bc7 Rename date_util to dt_util
Follows the rest of Home Assistant
2015-12-06 09:12:36 -08:00
Paulus Schoutsen f8668075d0 Fix State.copy() 2015-12-06 09:12:36 -08:00
Paulus Schoutsen 03962ab6ae Fix demo component messing up the config
Could cause HTTP to be initialised in production mode.
2015-12-06 09:12:35 -08:00
Paulus Schoutsen facbbabe58 Merge pull request #700 from nkgilley/ecobee
point ecobee to latest api
2015-12-06 08:58:57 -08:00
Paulus Schoutsen c4fe480b7b HTTP will not fail if no config 2015-12-05 13:44:50 -08:00
Paulus Schoutsen 705e3e4fbb Update material design icons 2015-12-05 13:20:00 -08:00
Paulus Schoutsen eefa62748b Update frontend 2015-12-05 01:12:58 -08:00
Paulus Schoutsen be14499bca Add rollershutter demo 2015-12-05 01:12:38 -08:00
nkgilley@gmail.com f582137fe3 point ecobee to latest api which has been cleaned up a bit. 2015-12-04 14:17:12 -05:00
Fabian Affolter 0383dddae7 Remove dependency 2015-12-04 16:25:34 +01:00
Paulus Schoutsen d0ae22428d Merge pull request #695 from nkgilley/ecobee
Improve ecobee support for multiple thermostats
2015-12-03 13:25:08 -08:00
nkgilley@gmail.com 107994f3ac implement logic improvement suggestion by @balloob 2015-12-03 08:57:28 -05:00
Paulus Schoutsen 853aa2ac42 Merge pull request #692 from sfam/dev
Rename motor component back to rollershutter
2015-12-03 01:19:03 -08:00
nkgilley@gmail.com 7985468aba remove the use of unnecessary dictionary. 2015-12-02 17:42:53 -05:00
nkgilley@gmail.com 502184812d fix flake8 warnings 2015-12-02 16:37:16 -05:00
nkgilley@gmail.com 02a8ce71d0 fix req_all 2015-12-02 16:32:28 -05:00
nkgilley@gmail.com 08de7d954a improve support for multiple thermostats. 2015-12-02 16:22:25 -05:00
sfam 9d8865ad4d adjust rollershutter after rename 2015-12-02 12:18:49 +00:00
sfam c3f0d618be change constant names for rollershutter services 2015-12-02 12:16:13 +00:00
sfam 21ee621aec rename motor component back to rollershutter 2015-12-02 12:15:00 +00:00
Paulus Schoutsen dd0424435a Merge branch 'heatcontroll_config' into dev 2015-12-01 23:34:30 -08:00
Paulus Schoutsen 0555294afe Remove Hue transition time limit 2015-12-01 23:33:55 -08:00
Paulus Schoutsen 28bbf39155 Fix ISY994 hidden property 2015-12-01 23:33:55 -08:00
Jeff Schroeder 587ef04560 Merge pull request #686 from balloob/sonos-fix
Have Sonos work nicer with discovery
2015-12-01 22:44:58 -06:00
Paulus Schoutsen 38f28fe24b Merge pull request #691 from watchforstock/dev
Adding Honeywell Evohome support
2015-12-01 20:08:51 -08:00
Andrew Stock 1ce81ee6db Fixing exception 2015-12-01 21:30:44 +00:00
Andrew Stock 228142e497 Adding Honeywell Evohome support 2015-12-01 21:23:28 +00:00
Daniel Hoyer Iversen 9bd11205fb Merge branch 'heatcontroll_config' of https://github.com/balloob/home-assistant into heatcontroll_config 2015-12-01 11:09:47 +01:00
Daniel Hoyer Iversen 0025e67b05 Added test to heat control 2015-12-01 11:09:22 +01:00
Paulus Schoutsen 5e2641e288 Merge pull request #689 from happyleavesaoc/limitlessled_off_transition_fix
LimitlessLED off->off transition fix
2015-11-30 22:48:24 -08:00
happyleaves f173f8b88b fix #688 2015-11-30 18:47:04 -05:00
Daniel Høyer Iversen d6cac08be6 Update heat_control.py 2015-11-30 11:46:14 +01:00
Daniel Hoyer Iversen 2e89f0a8c7 style fix in heat control 2015-11-30 11:45:09 +01:00
Daniel Høyer Iversen 758c0aae24 Update heat_control.py 2015-11-30 10:32:32 +01:00
Daniel Høyer Iversen 8fee38f2cd style fix in heat control 2015-11-30 10:05:05 +01:00
Paulus Schoutsen 41ab635dcd Have Sonos work nicer with discovery 2015-11-30 00:55:36 -08:00
Paulus Schoutsen 48a424e86f Frontend upgrade 2015-11-30 00:48:58 -08:00
Paulus Schoutsen 6113988ccd Merge pull request #685 from balloob/python-3.5-travis
Update Travis to test on Python 3.5 too
2015-11-30 00:30:44 -08:00
Daniel Høyer Iversen 2732b20305 style fix in heatcontrol 2015-11-30 09:22:04 +01:00
Daniel Høyer Iversen ac59847120 Update heat_control.py 2015-11-30 09:14:32 +01:00
Paulus Schoutsen b53993e8c0 Update Travis to test on Python 3.5 too 2015-11-30 00:09:58 -08:00
Paulus Schoutsen 90eab17ea6 Fix MQTT light bugs 2015-11-29 23:23:27 -08:00
Paulus Schoutsen 5b4f607da1 Upgrade frontend with lock support 2015-11-29 22:49:54 -08:00
Paulus Schoutsen 72ebb22eba Update demo entities 2015-11-29 17:59:59 -08:00
Paulus Schoutsen dc2f3861c9 Merge remote-tracking branch 'fabaff/alarm-demo' into dev 2015-11-29 17:35:19 -08:00
Paulus Schoutsen 6a25af4a9f Merge pull request #671 from happyleavesaoc/limitlessled
limitlessled improvements
2015-11-29 16:26:22 -08:00
happyleaves 6e0c30d9f7 warn -> warning 2015-11-29 18:29:37 -05:00
happyleaves 022d6af6fc Merge branch 'limitlessled' of https://github.com/happyleavesaoc/home-assistant into limitlessled 2015-11-29 17:52:42 -05:00
happyleaves 32003daf3f refactor legacy; move imports 2015-11-29 17:15:06 -05:00
happyleaves 5fba67f6c3 limitlessled improvements 2015-11-29 17:15:06 -05:00
Paulus Schoutsen a3981be501 Merge pull request #681 from pavoni/add_solar_elevation
Add automations based on Solar Elevation
2015-11-29 14:14:26 -08:00
Paulus Schoutsen 343b5bd2b8 Merge pull request #682 from happyleavesaoc/s20-update
Orvibo updates
2015-11-29 14:13:31 -08:00
Paulus Schoutsen 35f1810c74 Merge pull request #683 from balloob/pylint-15-fixes
PyLint 1.5 fixes
2015-11-29 14:11:35 -08:00
Paulus Schoutsen 7ba9fb90f1 More PyLint fixes 2015-11-29 14:04:44 -08:00
Paulus Schoutsen 5023772b3e Fix gen_requirements_all.py and add updated requirements_all.txt 2015-11-29 13:58:14 -08:00
Paulus Schoutsen ee805ec145 Merge remote-tracking branch 'fabaff/gen-requirements' into pylint-15-fixes 2015-11-29 13:49:19 -08:00
Paulus Schoutsen a301d869d7 PyLint 1.5 fixes 2015-11-29 13:49:05 -08:00
pavoni cb0eb2df7d Add tests 2015-11-29 21:37:08 +00:00
happyleaves 18ca7b4f9e bump requirement version; support multiple switches per platform 2015-11-29 15:52:16 -05:00
pavoni aff1c27372 Remove unused and potentially confusing property 2015-11-29 20:45:03 +00:00
Paulus Schoutsen 01203c7c4c Add updater tests 2015-11-29 12:13:06 -08:00
Paulus Schoutsen 8841eef2b7 Add tests for lock component 2015-11-29 11:44:27 -08:00
happyleaves 52b39efc51 Merge branch 'dev' of https://github.com/balloob/home-assistant into limitlessled 2015-11-29 12:44:44 -05:00
Fabian Affolter 7d503e3f8b Update docstrings 2015-11-29 15:52:44 +01:00
pavoni 73e3ce5044 Fix bug 2015-11-29 12:18:54 +00:00
pavoni f4c3fbe8fd Add attribuet config to numeric state platform to allow trigger based in attributes rather than states. 2015-11-29 11:56:47 +00:00
pavoni 41a0f2c198 Add elevation attribute 2015-11-29 10:47:20 +00:00
Paulus Schoutsen 0016ff6acc Merge pull request #678 from balloob/mqtt-light
Fixes for MQTT light with RGB colors
2015-11-28 23:22:57 -08:00
Paulus Schoutsen 45bd371cbf Merge pull request #679 from balloob/bugfixes
Bugfixes
2015-11-28 23:22:33 -08:00
Paulus Schoutsen 70698f7ab0 Update demo camera images 2015-11-28 23:16:20 -08:00
Paulus Schoutsen 286299c4c9 update frontend 2015-11-28 22:19:34 -08:00
Paulus Schoutsen f76edf0ed9 Tweak manifest and frontend index 2015-11-28 22:15:11 -08:00
Paulus Schoutsen 733de6b357 Streaming API will keep session alive 2015-11-28 22:14:40 -08:00
Paulus Schoutsen e67732b4f8 Remove no longer needed image 2015-11-28 19:12:42 -08:00
Paulus Schoutsen 546377e80a Throttle camera stream to 2fps 2015-11-28 18:59:59 -08:00
Paulus Schoutsen 0df39b4df5 Remove no password set boolean 2015-11-28 18:32:15 -08:00
Paulus Schoutsen 64ebe8c6d0 Update frontend splash screen 2015-11-28 18:20:17 -08:00
Paulus Schoutsen 78cfed1fb0 Clean up HTTP sessions and allow log out 2015-11-28 17:18:35 -08:00
Paulus Schoutsen 99aa4307ef Add locks to entity component 2015-11-28 15:55:01 -08:00
Paulus Schoutsen ef394b8af7 Pushbullet tweaks 2015-11-28 15:41:30 -08:00
Daniel Høyer Iversen aebab47fff Update tellstick.py 2015-11-28 23:30:12 +01:00
Daniel Høyer Iversen f2d553bfd1 Update tellstick.py 2015-11-28 23:28:17 +01:00
Paulus Schoutsen e84ef2d2d7 API to fetch Error log is no longer cached. 2015-11-28 14:08:01 -08:00
Paulus Schoutsen 957b09707d Fixes for MQTT light with RGB colors 2015-11-28 12:46:35 -08:00
Paulus Schoutsen 9ecfc41e09 Merge pull request #677 from theseal/legacy_nmap
Support for legacy nmap.
2015-11-28 11:47:48 -08:00
Paulus Schoutsen 194e7f8811 Merge pull request #676 from balloob/tellstick_light
Added signal repetitions to tellstick light
2015-11-28 11:43:55 -08:00
Johan Carlquist 6a021c9ef6 Support for legacy nmap.
Older nmap like the one bundled with Ubuntu Precise (12.04), 5.21
requires that you specify what unit the value to --host-timeout is.
2015-11-28 20:43:27 +01:00
Daniel Hoyer Iversen b6d7cacc61 Added signal repetitions to tellstick light 2015-11-28 20:39:48 +01:00
happyleaves e6fdcc94e6 refactor legacy; move imports 2015-11-28 12:21:00 -05:00
Paulus Schoutsen 05978ad88d Update discovery component to netdisco 0.5.2 2015-11-28 01:36:42 -08:00
Paulus Schoutsen 1146d6e58d Allow thermostat temperatures with decimal numbers 2015-11-28 01:18:02 -08:00
Paulus Schoutsen 6809a881fa Tweak MQTT Motor component 2015-11-28 01:02:35 -08:00
Paulus Schoutsen 9f01d7abca Merge branch 'pr/655' into dev 2015-11-28 00:55:22 -08:00
Paulus Schoutsen bbfeba0fe4 Merge branch 'pr/635' into dev
Conflicts:
	requirements_all.txt
2015-11-28 00:50:18 -08:00
Paulus Schoutsen ad3f96fa25 Merge pull request #672 from balloob/some-cleanup
Make component dependencies optional
2015-11-27 15:08:22 -08:00
happyleaves d91fe792c5 limitlessled improvements 2015-11-27 16:27:52 -05:00
Paulus Schoutsen 93c86ca5a1 Merge pull request #670 from pavoni/bump_pywemo
Bump pywemo version
2015-11-27 13:08:12 -08:00
pavoni bbf73e0bae Bump pywemo version - fixed scan device = None bug 2015-11-27 19:05:15 +00:00
Paulus Schoutsen 47eb4e76cf Merge pull request #669 from pavoni/handle-efergy_value_error
Trap and trace error rather than throwing exception when efergy server
2015-11-27 10:27:45 -08:00
Paulus Schoutsen ada612e09d Merge pull request #668 from pavoni/handle_vera_timeout
Add exception handler for vera timeout
2015-11-27 10:23:19 -08:00
pavoni 00f0dfb971 Trap and trace error rather than throwing exception when efergy server 2015-11-27 18:21:26 +00:00
pavoni 7204bc018f Add exception handler for vera timeout 2015-11-27 11:43:43 +00:00
Fabian Affolter 7224775aa8 Use manual alarm control panel as base for demo 2015-11-27 00:40:51 +01:00
Fabian Affolter 60460e8217 Add alarm control panel as platform and remove camera/acp entries 2015-11-27 00:18:11 +01:00
Fabian Affolter 67bcb00c9e Add demo platform for alarm control panel 2015-11-27 00:18:11 +01:00
Fabian Affolter 74b37bd61b Change to exception instead of error 2015-11-26 23:57:57 +01:00
Fabian Affolter 08da1e6f8d Add influx component 2015-11-26 23:57:34 +01:00
Paulus Schoutsen fabd0ced3f Make DEPENDENCIES optional for components 2015-11-26 13:11:59 -08:00
Paulus Schoutsen 2861bbb02c Warn if config invalid shape for script 2015-11-26 13:08:13 -08:00
Paulus Schoutsen 4c3d6981a6 Merge pull request #661 from bachp/mqtt-retain
Allow setting the retain flag for mqtt switch.
2015-11-26 12:19:52 -08:00
Pascal Bach 341c3a8fcd Fix tests for mqtt publish with retain. 2015-11-26 21:03:21 +01:00
Pascal Bach 69e9d39690 Allow setting the retain flag for mqtt switch.
Some devices can read the initial value on startup.
If the retain flag is set they always receive the value as last set by
home assistant.
2015-11-26 21:03:21 +01:00
Paulus Schoutsen 65f3e7ccf4 Merge pull request #652 from bachp/arest-function
Function support for aREST backend
2015-11-26 11:55:24 -08:00
Pascal Bach 067011af15 function support for aREST backend
The implementation sends /<name>?params=1 for turn_on and /<name>?params=0 for turn_off
It uses the return value of the function to determine the current state.
0=Off, 1=On
2015-11-26 20:45:07 +01:00
Paulus Schoutsen 271c2f6537 Merge pull request #664 from fabaff/mystrom-switch
myStrom switch
2015-11-26 09:43:55 -08:00
Fabian Affolter f2f598bd26 Use host as config var instead of resource 2015-11-26 16:37:00 +01:00
sfam 4f75286f64 fix some comments 2015-11-26 09:38:25 +00:00
Paulus Schoutsen c4d4dcccb7 Merge pull request #665 from badele/rfxtrx_event
Add should_fire_event in rfxtrx component
2015-11-25 23:40:39 -08:00
badele 128e3bb762 Move import module 2015-11-26 08:27:31 +01:00
badele a33220db7f Fix pylint style 2015-11-26 08:12:04 +01:00
badele 4bd0db30c9 Add should_fire_event in rfxtrx component 2015-11-26 07:52:37 +01:00
Fabian Affolter e60ab8f4c2 Add possibility to write data to file 2015-11-25 23:31:04 +01:00
Fabian Affolter 38b564e413 Remove class, just use state_changed, and update the export data 2015-11-25 22:49:32 +01:00
Fabian Affolter 76ac913fc0 Add influx component 2015-11-25 22:49:32 +01:00
sfam 0dbf4b3c10 add const.py changes to commit 2015-11-25 18:20:16 +00:00
sfam 08ba71a359 rename component to motor and services to open/close/stop 2015-11-25 18:13:39 +00:00
Fabian Affolter 1bebb17e9f Not need to raise exception 2015-11-25 18:14:19 +01:00
Fabian Affolter e45ef0013b Catch connection timeout 2015-11-25 18:07:29 +01:00
Fabian Affolter 9dfa4ea233 Add mystrom switch 2015-11-25 17:21:31 +01:00
Fabian Affolter a8ddae9343 Add myStrom switch platform 2015-11-25 17:21:11 +01:00
Fabian Affolter 3e60c4801c Update docstrings 2015-11-25 08:56:50 +01:00
Fabian Affolter bc106bcb10 Move configuration details to docs 2015-11-25 08:48:27 +01:00
Paulus Schoutsen 6f3cebdacf Merge pull request #657 from goir/thermostat_homematic
Added support for Homematic thermostat
2015-11-24 21:38:23 -08:00
Goir b0fa80ad4c Added support for Homematic thermostat 2015-11-24 21:23:12 +01:00
nkgilley@gmail.com 067b5862c0 bug fixes 2015-11-24 09:29:33 -05:00
sfam 351430c1b3 move current_position to RollershutterDevice class 2015-11-24 10:41:39 +00:00
sfam e001ea913a add __init__.py to test folder 2015-11-24 08:03:02 +00:00
Paulus Schoutsen 901b9075dc Merge pull request #658 from bachp/arest-logargs
Fix order of log arguments for arest switch
2015-11-23 20:53:39 -08:00
Paulus Schoutsen d141306493 Update Dockerfile to depend on Python 3.4 instead of latest 2015-11-23 20:42:32 -08:00
Paulus Schoutsen 6c12580b69 Merge pull request #659 from allanglen/improve-dockerfile
Re-order Dockerfile for faster rebuild on code changes
2015-11-23 20:42:08 -08:00
Pascal Bach 0d3a099926 arest: fix order argument order of log messages 2015-11-23 21:46:47 +01:00
Allan Glen 09a82dedf0 Re-order Dockerfile for faster rebuild on code changes 2015-11-23 11:58:59 -07:00
nkgilley@gmail.com 80e829f53a was getting errors for NETWORK being None. looked like it was being loaded too early, so this will wait until it's ready 2015-11-23 11:52:02 -05:00
nkgilley@gmail.com 27bc4c582b update network data before sensor setup. 2015-11-23 11:40:54 -05:00
nkgilley@gmail.com cc196d9888 fixed sensors and thermostat. discovery working for both now. 2015-11-23 11:15:19 -05:00
sfam 68ff9dd74f rollershutter component - fix const 2015-11-23 00:35:22 +00:00
sfam d4b3af327d Initial commit for rollershutter component 2015-11-23 00:25:10 +00:00
sfam 8269e843f2 Initial commit for rollershutter component 2015-11-23 00:22:43 +00:00
Paulus Schoutsen 7acb3dffe4 Merge pull request #653 from balloob/mqtt-disconnect
Reconnect when disconnected from MQTT
2015-11-22 16:08:30 -08:00
Paulus Schoutsen 1bda0bd73b Add some MQTT tests 2015-11-22 16:04:16 -08:00
Paulus Schoutsen f170799182 Reconnect when disconnected from MQTT 2015-11-22 15:19:51 -08:00
Paulus Schoutsen d4f0f0ffd3 Update automation url in warning 2015-11-22 15:10:24 -08:00
Paulus Schoutsen 7f1254d750 Merge pull request #647 from mcdeck/dev
Support for json messages in mqtt switches and sensors
2015-11-22 11:22:56 -08:00
Oliver van Porten 100400f149 move requirements to single line to not to affect coverage 2015-11-22 16:28:21 +01:00
Oliver van Porten 90681c2dc9 fix incorrect requirements 2015-11-22 16:19:08 +01:00
Oliver van Porten dbcd055cfe move import of jsonpath-rw to c'tor of _JsonFmtParser 2015-11-22 16:18:05 +01:00
Paulus Schoutsen d6feb82f9b Merge branch 'pr/634' into dev
Conflicts:
	requirements_all.txt
2015-11-21 23:22:47 -08:00
Paulus Schoutsen fc0e76764d Merge pull request #645 from fabaff/arest-binary-sensor
aREST binary sensor
2015-11-21 22:38:48 -08:00
Paulus Schoutsen 64c9619d75 Merge pull request #646 from fabaff/mqtt-binary-sensor
MQTT binary sensor
2015-11-21 22:31:17 -08:00
Paulus Schoutsen ee73bc9ad4 Merge pull request #642 from bburan/bburan/openzwave-config-fix
Fix issue with finding location of OpenZWave conf
2015-11-21 12:10:20 -08:00
nkgilley@gmail.com 8dc0de1d05 move EcobeeData class and Throttle to the main ecobee component, this way the sensor and thermostat will use the same throttled updating object. 2015-11-21 12:24:06 -05:00
Oliver van Porten 715abf241e Disable pylint warning for callable classes 2015-11-21 17:57:15 +01:00
miniconfig f37d0d1c20 Updated wink library version in requirements_all.txt 2015-11-21 09:52:43 -05:00
Brad Buran 0621260435 Fix issue with finding location of OpenZWave conf
Under some install scenarios, it may be possible that OpenZWave can't
automatically discover the location of the vendor-specific XML config
files. In this event, we need to specify the location in the Home
Assistant configuration.yaml file.
2015-11-20 19:47:29 -08:00
Oliver van Porten 427944cc44 add test for mqtt+json switch 2015-11-20 23:50:46 +01:00
Fabian Affolter 422a93e735 Add tests for MQTT binary sensor 2015-11-20 23:48:59 +01:00
Fabian Affolter b4ee3f73b4 Add aREST binary sensor and fix ordering 2015-11-20 23:47:49 +01:00
nkgilley@gmail.com 44abc31057 work in progress: configurator is now in it's own component. configurator seems to work but the thermostat is now broken. 2015-11-20 17:47:25 -05:00
Oliver van Porten 820b2a31b3 Add additional unit tests for mqtt state format parsing 2015-11-20 23:47:21 +01:00
Fabian Affolter 08d29d3630 Add MQTT binary sensor 2015-11-20 23:43:59 +01:00
Oliver van Porten 44714614ad Fix unit tests for mqtt 2015-11-20 23:42:22 +01:00
Fabian Affolter 065f4b7c20 Add binary sensor for aREST 2015-11-20 23:39:39 +01:00
Oliver van Porten 030686a978 fix flak8 warnings 2015-11-20 22:55:52 +01:00
Oliver van Porten 799043dc0a refactor format mqtt format parser 2015-11-20 22:45:09 +01:00
miniconfig 105dc2847e Changed locked method of lock support to "is_locked".
Added lock and unlock methods
Updated wink components to use the new version of the wink library.
2015-11-20 16:34:27 -05:00
Oliver van Porten b4cf0e874a Support parsing mqtt messages via jsonpath 2015-11-20 22:03:17 +01:00
Paulus Schoutsen 3df6c584c0 Update frontend 2015-11-20 08:38:56 -08:00
Paulus Schoutsen 3493db1052 Merge pull request #608 from fabaff/contact
Binary sensor component
2015-11-20 08:37:10 -08:00
Fabian Affolter d254e7e9e5 Fix pylint issue 2015-11-20 15:29:36 +01:00
Fabian Affolter 52344d65bc Merge branch 'contact' of github.com:fabaff/home-assistant into contact 2015-11-20 15:02:17 +01:00
Fabian Affolter a6006b1835 Move state 2015-11-20 14:59:21 +01:00
Fabian Affolter b9730e6914 Binary sensor component 2015-11-20 14:59:21 +01:00
Paulus Schoutsen 037bca041e Merge pull request #641 from balloob/pushbullet_email
Notify/pushbullet - adjustment in supported targets
2015-11-19 22:46:41 -08:00
Tom Duijf 77a1a1529c Added support for email, removed 'device/' hack to send to all own devices, as own email address does the same 2015-11-19 22:14:41 +00:00
miniconfig fa7391cdf6 Changed do_lock and do_unlock methods to lock and unlock.
Implemented state method.
Fixed locked method for demo interface.
Changed LockDevice to extend Entity instead of ToggleEntity
2015-11-19 16:54:55 -05:00
Paulus Schoutsen d25f58e650 Merge pull request #631 from balloob/gen-requirements_all
Allow generating requirements_all.txt
2015-11-19 12:49:23 -08:00
Paulus Schoutsen 6d315a1a7c Merge pull request #636 from fabaff/camera-demo
Camera demo
2015-11-19 12:11:12 -08:00
Fabian Affolter 685964785d Add camera to demos 2015-11-19 19:35:51 +01:00
Fabian Affolter ca32c81612 Camera demo 2015-11-19 19:27:28 +01:00
Fabian Affolter 5f89db5957 Binary sensor component 2015-11-19 19:00:22 +01:00
Fabian Affolter 4eacea32da Fix pylint issue 2015-11-19 18:07:54 +01:00
nkgilley@gmail.com d05af62680 use Throttle like the BitCoin component. 2015-11-18 14:57:27 -05:00
Fabian Affolter f1fed78992 Fix issue with older glances releases #637 (thanks @jdotbdot) 2015-11-18 19:19:27 +01:00
nkgilley@gmail.com 8df32aac3c point to updated python-ecobee library 2015-11-18 10:43:52 -05:00
nkgilley@gmail.com 18d0f4461f add config png to images dir. 2015-11-18 10:16:16 -05:00
nkgilley@gmail.com c6d1a4bdaf Fix configurator, rename repo, cleanup code. 2015-11-18 10:13:46 -05:00
Fabian Affolter ab9e173179 Update docstrings 2015-11-18 08:42:49 +01:00
Nolan Gilley 22fcbc67cf fix req 2015-11-17 19:20:56 -05:00
Nolan Gilley e317e0798b initial commit for ecobee thermostat component. 2015-11-17 19:14:29 -05:00
miniconfig c78899c4f3 Added support for Locks, including those connected through a wink hub. 2015-11-17 10:17:57 -05:00
Paulus Schoutsen bca65b620a Update Vera sensor dependency 2015-11-17 00:34:14 -08:00
Paulus Schoutsen e92fe149fe Comment out requirements that break on certain platforms 2015-11-17 00:30:13 -08:00
Paulus Schoutsen 377d2c6e5a Allow generating requirements_all.txt 2015-11-17 00:21:49 -08:00
Paulus Schoutsen 8be53af78f Convert README to RST format 2015-11-16 22:02:35 -08:00
Paulus Schoutsen 573dfb648f Version bump to 0.9.0.dev0 2015-11-16 00:03:37 -08:00
Paulus Schoutsen 8e44ed0090 Merge pull request #617 from balloob/dev
0.8.0.rc1
2015-11-16 00:03:20 -08:00
Paulus Schoutsen 5fb6076f6e Version bump to 0.8.0 2015-11-16 00:03:00 -08:00
Fabian Affolter 4ea6def1bd Update docstrings and link to docs 2015-11-16 07:53:31 +01:00
Paulus Schoutsen 314185ffb8 Merge pull request #629 from rmkraus/dev
Adding updater to default list of components
2015-11-15 17:30:15 -08:00
Ryan Kraus 8aafb89a64 Merge remote-tracking branch 'balloob/dev' into dev 2015-11-15 20:04:21 -05:00
Ryan Kraus d01ed9788f Added updater to set of default components 2015-11-15 20:03:45 -05:00
Paulus Schoutsen b4e2f4f0be Merge pull request #625 from balloob/enhancement_pushbullet
Enhancement: targeted notifications in pushbullet
2015-11-15 16:41:18 -08:00
Tom Duijf f4d8325084 Pushbullet; code cleanup & better errors on config typos 2015-11-16 00:29:04 +00:00
Tom Duijf cc5dec3c59 Processed feedback from PR comments 2015-11-15 23:46:16 +00:00
Ryan Kraus ec5a93a0fd Merge remote-tracking branch 'balloob/dev' into dev 2015-11-15 18:16:49 -05:00
Paulus Schoutsen aabda1b7b0 Merge pull request #628 from rmkraus/dev
Small tweaks to daemon management.
2015-11-15 14:46:58 -08:00
Tom Duijf aee4411cfb <type>.<name> split only on first separator 2015-11-15 22:44:51 +00:00
Ryan Kraus 135eb0a0ac Fixed hass daemon management
1) Changed signal to exit hass to SIGTERM
2) Updated initd script to send SIGTERM
3) Updated systemd script to never send SIGKILL.
2015-11-15 17:43:38 -05:00
Ryan Kraus 01daac066a Merge remote-tracking branch 'balloob/dev' into dev 2015-11-15 17:37:57 -05:00
Ryan Kraus 5d96ca133d Merge pull request #627 from rmkraus/update_notify
Updater component
2015-11-15 17:36:55 -05:00
Ryan Kraus 3cda1aacff Fixed typo in updater entity attributes.
Left some quotes in there. My bad.
2015-11-15 17:34:06 -05:00
Ryan Kraus 243130c133 Using ATTR_FRIENDLY_NAME in updater component. 2015-11-15 17:32:05 -05:00
Paulus Schoutsen 0d74b628b0 Merge pull request #623 from balloob/lib-clean-on-upgrade
Lib clean on upgrade
2015-11-15 14:30:51 -08:00
Ryan Kraus c314101dde Updater suggestions from Paulus
1) Moved error checking into get_newest_version function.
2) Fixed import formatting mistake.
2015-11-15 17:30:42 -05:00
Paulus Schoutsen 0f68dc6b7b Add tests for version upgrade 2015-11-15 14:28:50 -08:00
Ryan Kraus 919c20a263 Implemented suggestions from Paulus for updater
1) Better Error handling when making PyPI requests.
2) More efficient event scheduling.
3) ENTITY_ID in constant
3) friendly_name from constant
2015-11-15 17:23:56 -05:00
Ryan Kraus 9b5385c565 Merge remote-tracking branch 'balloob/dev' into update_notify
Conflicts:
	homeassistant/components/frontend/version.py
	homeassistant/components/frontend/www_static/frontend.html
2015-11-15 17:00:35 -05:00
Ryan Kraus 7dacf01baa Updating fronted to latest version. 2015-11-15 16:56:33 -05:00
Tom Duijf 9b4650afd4 Added comments 2015-11-15 20:49:42 +00:00
Tom Duijf 0b0fd2490d Pushbullet; styling, requirements, example 2015-11-15 19:14:10 +00:00
Tom Duijf 3a85bebbf6 pushbullet; styling and minor fixed before PR 2015-11-15 18:57:16 +00:00
Paulus Schoutsen 18f1de10a5 Merge pull request #624 from leoc/feature-zwave-meter-sensor
Add Zwave `meter` command class
2015-11-15 10:16:57 -08:00
Paulus Schoutsen 869d6df65e Merge pull request #618 from nkgilley/camera-fix
add exception handling to generic camera requests function.
2015-11-15 10:02:20 -08:00
Tom Duijf 0a586bd919 Initial commit of pushbullet enhancement 2015-11-15 17:50:36 +00:00
Fabian Affolter a98b1b0ebc Update link to docs 2015-11-15 18:50:06 +01:00
Paulus Schoutsen 511028612c Merge pull request #593 from leoc/feature-zwave-switches
Implement zwave switches
2015-11-15 09:30:06 -08:00
Paulus Schoutsen e3efce5ded Merge pull request #622 from happyleavesaoc/s20
s20 switch support
2015-11-15 09:28:40 -08:00
Arthur Andersen 340ee171b5 [Zwave] Add zwave polling interval configuration 2015-11-15 17:50:14 +01:00
Arthur Andersen 773da3f755 [Zwave] Add Meter command class 2015-11-15 17:50:11 +01:00
happyleaves 12bdc39274 don't update state in turn_on/off 2015-11-15 08:59:18 -05:00
Paulus Schoutsen 700b7ba591 Remove unused import in notify 2015-11-15 02:20:35 -08:00
Paulus Schoutsen 295f27d259 Only delete lib dir in config upgrade if exists 2015-11-15 02:16:52 -08:00
Ryan Kraus 4463b69245 Added friendly name to updater component. 2015-11-15 05:15:36 -05:00
Paulus Schoutsen 71e4283a2e Remove lib directory in version upgrade 2015-11-15 02:05:46 -08:00
Paulus Schoutsen 6135b87b1d Log error if unable to install package 2015-11-15 02:05:13 -08:00
Paulus Schoutsen 04bb7ed58f Have Notify platform install platform dependencies 2015-11-15 02:04:57 -08:00
Ryan Kraus dfa9880176 Created updater component 2015-11-15 05:00:24 -05:00
Paulus Schoutsen 88f3a5a50a Update to new version frontend 2015-11-15 00:51:12 -08:00
Paulus Schoutsen e2c530b85d Script: new attribute if can cancel 2015-11-14 15:38:07 -08:00
Arthur Andersen 56c5d345a4 [Zwave] Update HA state on value change 2015-11-14 23:14:08 +01:00
happyleaves 86b9ae9566 addressed comments 2015-11-14 16:14:25 -05:00
Nolan Gilley df264f2ec0 remove unnecessary else 2015-11-14 15:49:39 -05:00
happyleaves aabcad59d8 rename platform to orvibo 2015-11-14 15:05:22 -05:00
happyleaves 70fef3c5b5 fixed names 2015-11-14 14:25:53 -05:00
happyleaves 57ec58e255 fixed requirements 2015-11-14 14:19:47 -05:00
happyleaves cf8e23adbc s20 switch support 2015-11-14 14:14:02 -05:00
Paulus Schoutsen eabf9087f3 Merge pull request #621 from fabaff/cleanup-glances
Glances sensor cleanup
2015-11-14 10:51:57 -08:00
Nolan Gilley 9acb341b96 remove break 2015-11-14 10:51:07 -05:00
Fabian Affolter 5275ca9ce7 Fix typo 2015-11-14 15:25:52 +01:00
Fabian Affolter 646618a25e Improve error messages, use constants, and fix docstrings 2015-11-14 15:23:20 +01:00
Paulus Schoutsen bc48e4f98e Merge pull request #619 from nkgilley/mqtt-light-color-fix
Remove rgb color if it's not an rgb bulb.
2015-11-14 00:51:18 -08:00
Nolan Gilley 776324807e last PR was dumb. this fix is better. 2015-11-13 14:58:49 -05:00
Nolan Gilley d68a4b52f1 Remove rgb color if it's not an rgb bulb. 2015-11-13 14:32:47 -05:00
Nolan Gilley 85e0db6ade add exception handling to generic camera requests function. 2015-11-13 13:55:22 -05:00
Fabian Affolter d993f4014e Add link to docs 2015-11-13 08:29:54 +01:00
Paulus Schoutsen 7ebda9c3c6 Fix MQTT light test 2015-11-12 23:08:26 -08:00
Paulus Schoutsen 16e948d032 Merge branch 'pr/552' into dev 2015-11-12 23:04:05 -08:00
Paulus Schoutsen 41d0f95d9a Move core light test to correct dir 2015-11-12 23:03:56 -08:00
Paulus Schoutsen bfaaf39e9e Merge pull request #613 from Xorso/squeezebox_fix
Fixing bug when connecting to squeezebox and it is a float
2015-11-12 22:45:03 -08:00
Paulus Schoutsen 16904452b8 Merge pull request #614 from persandstrom/asuswrt_not_loading
ASUSWRT more logging and more robust
2015-11-12 11:43:49 -08:00
Per Sandström 158d9e27ff more robust and more logging 2015-11-12 20:10:25 +01:00
Fabian Affolter b652dd47cd Update file header and docstrings 2015-11-12 18:04:48 +01:00
Daren Lord 2812fae721 Fixing bug when connecting to squeezebox and it is a float 2015-11-11 16:21:42 -07:00
Tom Duijf 6da88108fe Merge pull request #612 from balloob/dt_snmp_fix
Fix memory issue in SNMP device tracker
2015-11-11 23:30:43 +01:00
Tom Duijf 5503c12cfd Fixes memory consumption issue 2015-11-11 21:54:33 +00:00
hexxter 329d63ac11 next online unittest test ;) 2015-11-11 20:52:41 +01:00
hexxter 698e30bd2b more self.hass.pool.block_till_done() 2015-11-11 20:40:21 +01:00
hexxter 90063ea7f8 check the default value only checkable local. I removed it. 2015-11-11 12:44:59 +01:00
hexxter 0c52b143ae now saved 2015-11-11 12:38:10 +01:00
hexxter 8f12b997f8 more unittests 2015-11-11 12:32:24 +01:00
Arthur Andersen 877926cfee [Zwave] Fix docstring 2015-11-11 10:24:00 +01:00
Arthur Andersen 19649390d3 [Zwave] Add binary switch component 2015-11-11 10:24:00 +01:00
Paulus Schoutsen 50d19bb1b4 Merge pull request #592 from leoc/feature-zwave-lights
Implement zwave light support
2015-11-11 00:11:51 -08:00
Arthur Andersen 665436cd91 [Zwave] Use threading.Timer for value refresh delay 2015-11-10 19:59:45 +01:00
Paulus Schoutsen 1a3410119e Merge pull request #606 from fabaff/pushetta
Pushetta notification platform
2015-11-10 09:27:16 -08:00
Fabian Affolter bf2bcb6dcf Use _LOGGER.error instead of _LOGGER.exception 2015-11-10 18:20:10 +01:00
Fabian Affolter 8371b08676 Add pushetta notify platform 2015-11-10 14:17:28 +01:00
Fabian Affolter e8a0d54fdd Add pushetta 2015-11-10 14:17:28 +01:00
Fabian Affolter f4a82c6f6b Add pushetta 2015-11-10 14:17:28 +01:00
Paulus Schoutsen 963c4bb70e Update frontend with new card style 2015-11-10 00:56:56 -08:00
Paulus Schoutsen ec2e0cc77d Compile new version frontend 2015-11-10 00:27:41 -08:00
Paulus Schoutsen 0c0ccb361d Merge branch 'dev-tool-info' into dev 2015-11-10 00:25:33 -08:00
Paulus Schoutsen 994fc32f25 Upgrade frontend with about page 2015-11-10 00:25:19 -08:00
Paulus Schoutsen d68263d5c4 Another LimitlessLED color fix 2015-11-09 21:55:49 -08:00
Paulus Schoutsen 27b001df2b Add dev info to frontend urls 2015-11-09 21:48:36 -08:00
Paulus Schoutsen dafc0ced6b Update limitlessled with lists for colors 2015-11-09 16:55:10 -08:00
Paulus Schoutsen 3ec2555c66 Merge pull request #601 from balloob/package-install-global
Check global installed packages
2015-11-09 12:45:51 -08:00
Fabian Affolter bfa8e58879 Update link to docs (Jekyll 3 update) 2015-11-09 18:33:11 +01:00
Paulus Schoutsen 2d9a785c18 Merge pull request #600 from balloob/cleanup-notify
Clean up notifiy component
2015-11-09 07:32:13 -08:00
Fabian Affolter 97f9f8aa49 Update link to docs (Jekyll 3 update) 2015-11-09 13:12:18 +01:00
Fabian Affolter 64d5ca4da0 Add link to docs and update some docstrings 2015-11-09 08:25:46 +01:00
Paulus Schoutsen 4fb301b7a9 Check global installed packages 2015-11-08 22:55:22 -08:00
Paulus Schoutsen fda65a4934 Update coveragerc 2015-11-08 22:33:43 -08:00
Paulus Schoutsen 98b4c27211 Style fixes 2015-11-08 22:21:02 -08:00
Paulus Schoutsen 3b3f5fe6fe Clean up notifiy component 2015-11-08 22:15:34 -08:00
Paulus Schoutsen 1c9c5ce1bd Merge pull request #599 from ryanturner/dev
Initial implementation of mjpeg camera
2015-11-08 22:13:49 -08:00
Ryan Turner a36b315927 Fixed indentations hopefully 2015-11-09 00:11:11 -06:00
Ryan Turner f3352546c6 More lint fixes 2015-11-09 00:00:31 -06:00
Ryan Turner 3a6aa8f3d1 Fixed line length issues to make lint happy. Still bummed that I decreased test coverage :( 2015-11-08 23:51:01 -06:00
Ryan Turner dfa81b0117 Changed camera.mjpeg to use Response and Closing; cleaned up a number of code-clarity issues near that 2015-11-08 23:41:21 -06:00
Paulus Schoutsen 3947691347 Style fixes + rename honeywell 2015-11-08 20:56:11 -08:00
Ryan Turner 8541fdb112 Fixed style issue related to failing build 2015-11-08 22:26:27 -06:00
Ryan Turner e078ab53ca Initial implementation of mjpeg camera 2015-11-08 22:15:06 -06:00
Paulus Schoutsen 0665af7f0f Merge branch 'pr/579' into dev
Conflicts:
	requirements_all.txt
2015-11-08 20:10:30 -08:00
Paulus Schoutsen 6dfb8f5737 Merge pull request #591 from balloob/error-log
Expose API to view error log
2015-11-08 20:06:56 -08:00
Paulus Schoutsen 1be2be0886 Merge pull request #590 from balloob/light-rgb
Light: base color now in RGB instead of XY
2015-11-08 20:06:49 -08:00
Paulus Schoutsen 3a095f53a8 Merge pull request #596 from badele/dev
Minor change for logger component
2015-11-08 19:57:58 -08:00
Paulus Schoutsen ffce252a12 Merge pull request #598 from SEJeff/update-foscam-snapshot
Make a single request to get the foscam camera image
2015-11-08 19:57:21 -08:00
Paulus Schoutsen 7f4c13c382 Upgrade Wink version to v0.1.1 2015-11-08 19:41:22 -08:00
Jeff Schroeder 0f292e8fa6 Remove unused import for re 2015-11-08 20:37:29 -06:00
badele e63d0c51e0 Change log severity 2015-11-08 19:02:51 +01:00
badele ebaecdb9d6 Fix flake & pylint 2015-11-08 11:29:56 +01:00
badele fd50693ca7 Minor change to documentation for logger component 2015-11-08 11:26:36 +01:00
badele ebc95aca51 Add log info in the rfxtrx component 2015-11-08 11:15:03 +01:00
Jeff Schroeder 137cadb59c Make a single request to get the foscam camera image
This uses the `snapPicture2` command, which is documented in their
cgi sdk to return raw jpeg data instead of html containing the image
2015-11-07 20:18:46 -06:00
Arthur Andersen 84f81480bb [Zwave] Add light zwave component 2015-11-07 15:58:28 +01:00
Arthur Andersen 5565e418f8 [Zwave] Add type and genre to value filter 2015-11-07 15:57:46 +01:00
Arthur Andersen 5b4fc4f346 [Zwave] Add check for missing discovery_service 2015-11-07 15:57:28 +01:00
Paulus Schoutsen e4c3d47dbf Expose API to view error log 2015-11-07 01:44:02 -08:00
Paulus Schoutsen 95320f39b3 Light: base color now in RGB instead of XY 2015-11-07 01:25:33 -08:00
Paulus Schoutsen 0c97280479 Merge pull request #587 from badele/logfilter
Add logger filter feature
2015-11-06 21:59:56 -08:00
Paulus Schoutsen 3e339c7304 Update vincenty version in setup.py 2015-11-06 21:58:18 -08:00
badele 6f06f48ac6 Ensure the component is loaded first 2015-11-06 22:57:03 +01:00
badele aeacbad4a0 Fix pull request from balloob comments 2015-11-06 22:51:33 +01:00
sander f60f3fa4a2 Removed unused self._sensorid. 2015-11-06 08:37:22 +01:00
sander e49dc94d4b slightly better update method. 2015-11-05 09:58:35 +01:00
sander 26a6438e93 learning the alphabet ;-) 2015-11-05 09:37:05 +01:00
Paulus Schoutsen cae71a73a1 Update frontend 2015-11-05 00:03:01 -08:00
Paulus Schoutsen df7f6e1235 Remove alarm sensor from demo platform 2015-11-04 23:53:22 -08:00
badele a31f7d2816 Fix flake & pylint 2015-11-04 22:08:15 +01:00
badele c52c982510 Add logger feature 2015-11-04 21:30:02 +01:00
sander ea06d946e6 modified .converagerc and requirements_all.txt 2015-11-04 21:15:56 +01:00
Paulus Schoutsen bd798b8c55 Merge pull request #582 from balloob/mdi-icons
Icons for everyone!
2015-11-04 09:08:34 -08:00
Paulus Schoutsen ac7456b73b Merge pull request #577 from happyleavesaoc/limitlessled_additions
LimitlessLED effects
2015-11-04 09:02:43 -08:00
Fabian Affolter d69b08ecf5 Update with comments from PR 579 2015-11-03 11:46:03 +01:00
Paulus Schoutsen be6dd20236 Update frontend with new icons 2015-11-03 00:20:59 -08:00
Paulus Schoutsen 4d069323f4 Add icon support to entity 2015-11-03 00:20:48 -08:00
Paulus Schoutsen 77f4fc8c22 Frontend: Add materialdesignicons 2015-11-03 00:20:20 -08:00
Paulus Schoutsen 72b4212b19 Demo uses device tracker demo platform 2015-11-03 00:19:28 -08:00
Fabian Affolter 5fce381b89 Remove empty point 2015-11-03 08:50:27 +01:00
happyleaves 7b968f6a6b re-fix conditionals 2015-11-02 18:11:58 -05:00
happyleaves 4d958c6d18 style fix 2015-11-02 18:08:17 -05:00
happyleaves 566712023d consolidate conditionals 2015-11-02 18:08:17 -05:00
happyleaves 3cd89f8474 add disco, white effects 2015-11-02 18:08:17 -05:00
Fabian Affolter 218a05356a Add docstrings 2015-11-02 21:00:53 +01:00
hexxter 186f68cce3 not working mqtt light unittest 2015-11-02 20:16:36 +01:00
hexxter 168eb8e5a2 mqtt light test is working more test should be written 2015-11-02 17:02:34 +01:00
Paulus Schoutsen c6b5a04312 Allow more static files to be fingerprinted 2015-11-02 00:03:53 -08:00
Paulus Schoutsen 728cd8bb5e Upgrade Vincenty to latest version 2015-11-02 00:03:53 -08:00
Stefan Jonasson d873ab0262 Merge pull request #569 from stefan-jonasson/dev
Fix for Philio Zwave devices which don't send an off event.
2015-11-02 08:15:57 +01:00
Daniel Høyer Iversen 0ff6a460c2 Update rfxtrx.py 2015-11-01 14:20:11 +01:00
Daniel Høyer Iversen 77539a5b89 revert prev commit 2015-11-01 12:51:09 +01:00
Daniel Høyer Iversen 92b05389f2 Update rfxtrx.py 2015-11-01 12:41:21 +01:00
Daniel Høyer Iversen 82aec895a0 Minor bug in rfxtrx 2015-11-01 12:40:41 +01:00
Stefan Jonasson ec732becfc Fixed the get_config_value method when the zwave node was changed while reading it. 2015-10-31 23:34:19 +01:00
Stefan Jonasson c4261ae2e0 Z-Wave workaround - Added a default value if we did not get any config value. 2015-10-31 23:03:40 +01:00
Stefan Jonasson cae8932b18 Z-Wave workaround - Connected to the timeout to the configured node value "9. Turn Off Light Time" 2015-10-31 21:23:33 +01:00
sander efacd66bec linting and flakeing.. 2015-10-31 20:35:23 +01:00
hexxter 31826ab263 redesigned mqtt light an first steps with the unittest system 2015-10-31 19:26:03 +01:00
Paulus Schoutsen 6bb95f5c9b Merge pull request #560 from pavoni/add-vera-dimmer
Add vera dimmer
2015-10-30 21:47:02 -07:00
Paulus Schoutsen 46761d827f Merge pull request #570 from nkgilley/actiontec-fix
Actiontec device_tracker bugfix and removed home_interval
2015-10-30 21:18:28 -07:00
Paulus Schoutsen 288db9a57f Merge pull request #559 from balloob/light_ct_color
Color temperature support for light component and hue platform
2015-10-30 19:11:24 -07:00
Tom Duijf b76471c4b3 :( .. pyliny 2015-10-30 19:15:38 +00:00
Tom Duijf 194c6343ac Minor corrections to light and light/demo 2015-10-30 19:01:42 +00:00
Stefan Jonasson 2ad647bb09 Style fixes 2015-10-30 15:30:08 +01:00
Stefan Jonasson a56173676e Fixed the workaround match logic 2015-10-30 15:28:06 +01:00
Nolan Gilley e961dd5f95 increase valid for time to 60 since I was having some issues. removed deprecated lines. 2015-10-30 07:00:35 -04:00
pavoni 0269be5813 Update pyvera version 2015-10-30 09:39:30 +00:00
pavoni 031d5ce255 Fix style issues, update pyvera version. 2015-10-30 09:37:16 +00:00
sander 85bb828149 changed requirements to the latest evohome version. 2015-10-29 21:17:10 +01:00
Paulus Schoutsen c7a0b5800c Update links in introduction component 2015-10-29 00:23:05 -07:00
Tom Duijf f456d2ff23 styling fix 2015-10-28 23:16:25 +00:00
Tom Duijf 6bad702db4 Renamed to color_temp, removed capabilities (not needed afterall) 2015-10-28 23:12:16 +00:00
Nolan Gilley bcb2451752 fix pylint warning 2015-10-28 17:47:13 -04:00
Nolan Gilley 8eeca94517 removed home_interval option since it was added to the main device_tracker component 2015-10-28 17:43:41 -04:00
Nolan Gilley 3b37a7b737 bugfix for actiontec device tracker 2015-10-28 17:20:15 -04:00
Stefan Jonasson d578bf3494 Removed extra pylint hint from a previous merge 2015-10-28 22:17:17 +01:00
Stefan Jonasson 8cb046a4a9 Merge remote-tracking branch 'origin/dev' into dev 2015-10-28 22:16:00 +01:00
Stefan Jonasson 30de5af445 Fix for Philio Zwave devices which don't send an off event. 2015-10-28 22:08:50 +01:00
Stefan Jonasson f74a6ed4c9 Merge remote-tracking branch 'origin/dev' into dev
Conflicts:
	homeassistant/components/script.py
	homeassistant/helpers/entity_component.py
2015-10-28 21:43:46 +01:00
Stefan Jonasson f3500542dd Added pylint hint 2015-10-28 21:42:42 +01:00
Paulus Schoutsen 2eb65c8eb8 Version bump to 0.8.0.dev0 2015-10-28 12:45:57 -07:00
Paulus Schoutsen f8bb807707 Merge pull request #568 from balloob/dev
0.7.7
2015-10-28 12:45:42 -07:00
Paulus Schoutsen 5f40115605 Version bump to 0.7.7 2015-10-28 12:43:04 -07:00
Paulus Schoutsen 776616bcac Merge pull request #562 from pavoni/efergy_error_handling
Log request exceptions in Efergy sensor
2015-10-28 12:41:42 -07:00
Paulus Schoutsen a98cb798f7 Merge pull request #567 from balloob/fix-script-regression
Fix script regression
2015-10-28 12:37:50 -07:00
Paulus Schoutsen 12495c717e Fix script regression 2015-10-28 12:24:33 -07:00
Stefan Jonasson 10c95b4352 Added pylint hint 2015-10-28 20:17:17 +01:00
Stefan Jonasson 48bfc98acb Fixed entity name 2015-10-28 19:52:09 +01:00
Stefan Jonasson de027609d8 Fixed entity_id for the script component. Alias now does not override the entity_id
Fixed issue: #561
2015-10-28 12:27:58 +01:00
pavoni 16a3511c0a Catch request exceptions and log a warning 2015-10-28 10:57:10 +00:00
Paulus Schoutsen 0a36c96a55 Fill in service info for thermostat 2015-10-27 19:51:50 -07:00
pavoni 6ef0d089ea Add VeraLight class based on VeraSwitch - add dimmer support 2015-10-27 23:18:46 +00:00
Fabian Affolter b3b2f2e326 Fix pylint and flake issues 2015-10-28 00:18:03 +01:00
Fabian Affolter bef0b2b01e Make pins optional 2015-10-27 23:51:16 +01:00
Tom Duijf 805aecd6f9 pylint & flake cleanup 2015-10-27 22:49:45 +00:00
Tom Duijf e4d33bc6d4 Included ct_color in code coverage 2015-10-27 22:45:35 +00:00
Tom Duijf e25503bc4a Hue device capabilities. Color temperature support for light component and hue platform 2015-10-27 22:34:49 +00:00
root 4fcd27e905 light/mqtt to .coveragerc 2015-10-27 16:52:43 +01:00
Fabian Affolter 52b1080ccd Catch invalid chat ids 2015-10-27 14:26:44 +01:00
root 0128357024 Merge remote-tracking branch 'upstream/dev' into dev 2015-10-27 07:52:04 +01:00
root c5f8095f53 Merge remote-tracking branch 'upstream/master' into dev 2015-10-27 07:51:21 +01:00
Paulus Schoutsen 27c6c27db6 Merge pull request #554 from balloob/dev
0.7.6-rc1
2015-10-26 21:31:41 -07:00
root b66e4f1e15 two different demo lights on without RGB and one with RGB support.
and code cleanup more pylint aligned
2015-10-26 15:05:01 +01:00
pavoni 49f4d92c62 Add dimmer as switch 2015-10-26 10:51:23 +00:00
root a8c2cc4c33 rework for flake8 errors done 2015-10-25 23:38:24 +01:00
root 538f8545f7 fix a bug after the pylint rework 2015-10-25 23:04:43 +01:00
root 7cfce94dfb pylint rework for light/mqtt 2015-10-25 22:58:07 +01:00
root 469d0619ba mqtt light component 2015-10-25 21:48:01 +01:00
sander 863955e1bd got the basics working 2015-10-21 21:48:21 +02:00
sander f376061e23 Revert "had to change to let this work on windows."
This reverts commit 6c106a87f1.
2015-10-21 19:00:23 +02:00
sander 076b3db5e8 first try 2015-10-21 19:00:15 +02:00
sander 6c106a87f1 had to change to let this work on windows. 2015-10-15 15:02:09 +02:00
243 changed files with 7527 additions and 3071 deletions
+14 -1
View File
@@ -17,6 +17,9 @@ omit =
homeassistant/components/*/tellstick.py
homeassistant/components/*/vera.py
homeassistant/components/ecobee.py
homeassistant/components/*/ecobee.py
homeassistant/components/verisure.py
homeassistant/components/*/verisure.py
@@ -29,25 +32,30 @@ omit =
homeassistant/components/rfxtrx.py
homeassistant/components/*/rfxtrx.py
homeassistant/components/ifttt.py
homeassistant/components/binary_sensor/arest.py
homeassistant/components/browser.py
homeassistant/components/camera/*
homeassistant/components/device_tracker/actiontec.py
homeassistant/components/device_tracker/aruba.py
homeassistant/components/device_tracker/asuswrt.py
homeassistant/components/device_tracker/ddwrt.py
homeassistant/components/device_tracker/geofancy.py
homeassistant/components/device_tracker/luci.py
homeassistant/components/device_tracker/ubus.py
homeassistant/components/device_tracker/netgear.py
homeassistant/components/device_tracker/nmap_tracker.py
homeassistant/components/device_tracker/owntracks.py
homeassistant/components/device_tracker/thomson.py
homeassistant/components/device_tracker/tomato.py
homeassistant/components/device_tracker/tplink.py
homeassistant/components/device_tracker/snmp.py
homeassistant/components/discovery.py
homeassistant/components/downloader.py
homeassistant/components/ifttt.py
homeassistant/components/influx.py
homeassistant/components/keyboard.py
homeassistant/components/light/hue.py
homeassistant/components/light/mqtt.py
homeassistant/components/light/limitlessled.py
homeassistant/components/light/blinksticklight.py
homeassistant/components/light/hyperion.py
@@ -64,6 +72,7 @@ omit =
homeassistant/components/notify/instapush.py
homeassistant/components/notify/nma.py
homeassistant/components/notify/pushbullet.py
homeassistant/components/notify/pushetta.py
homeassistant/components/notify/pushover.py
homeassistant/components/notify/slack.py
homeassistant/components/notify/smtp.py
@@ -93,10 +102,14 @@ omit =
homeassistant/components/switch/command_switch.py
homeassistant/components/switch/edimax.py
homeassistant/components/switch/hikvisioncam.py
homeassistant/components/switch/mystrom.py
homeassistant/components/switch/orvibo.py
homeassistant/components/switch/rest.py
homeassistant/components/switch/rpi_gpio.py
homeassistant/components/switch/transmission.py
homeassistant/components/switch/wemo.py
homeassistant/components/thermostat/homematic.py
homeassistant/components/thermostat/honeywell.py
homeassistant/components/thermostat/nest.py
homeassistant/components/thermostat/radiotherm.py
+3 -2
View File
@@ -2,9 +2,10 @@ sudo: false
language: python
cache:
directories:
- $HOME/virtualenv/python3.4.2/
- $HOME/virtualenv/python$TRAVIS_PYTHON_VERSION/
python:
- "3.4"
- 3.4.2
- 3.5.0
install:
- script/bootstrap_server
script:
+7 -7
View File
@@ -17,19 +17,19 @@ For help on building your component, please see the [developer documentation](ht
After you finish adding support for your device:
- Update the supported devices in the `README.md` file.
- Add any new dependencies to `requirements_all.txt`. There is no ordering right now, so just add it to the end.
- Update the `.coveragerc` file.
- Provide some documentation for [home-assistant.io](https://home-assistant.io/). The documentation is handled in a separate [git repository](https://github.com/balloob/home-assistant.io). It's OK to add a docstring with configuration details to the file header.
- Add a link to the website of your device/service/component in the "examples" listing of the `README.md` file.
- Add any new dependencies to `requirements_all.txt` if needed. There is no ordering right now, so just add it to the end of the file.
- Update the `.coveragerc` file to exclude your platform if there are no tests available.
- Provide some documentation for [home-assistant.io](https://home-assistant.io/). It's OK to just add a docstring with configuration details (sample entry for `configuration.yaml` file and alike) to the file header as a start. Visit the [website documentation](https://home-assistant.io/developers/website/) for further information on contributing to [home-assistant.io](https://github.com/balloob/home-assistant.io).
- Make sure all your code passes ``pylint`` and ``flake8`` (PEP8 and some more) validation. To check your repository, run `./script/lint`.
- Create a Pull Request against the [**dev**](https://github.com/balloob/home-assistant/tree/dev) branch of Home Assistant.
- Check for comments and suggestions on your Pull Request and keep an eye on the [Travis output](https://travis-ci.org/balloob/home-assistant/).
If you've added a component:
If you add a platform for an existing component, there is usually no need for updating the frontend. Only if you've added a new component that should show up in the frontend, there are more steps needed:
- Update the file [`home-assistant-icons.html`](https://github.com/balloob/home-assistant/blob/master/homeassistant/components/frontend/www_static/polymer/resources/home-assistant-icons.html) with an icon for your domain ([pick one from this list](https://www.polymer-project.org/1.0/components/core-elements/demo.html#core-icon)).
- Update the demo component with two states that it provides
- Add your component to home-assistant.conf.example
- Update the demo component with two states that it provides.
- Add your component to `home-assistant.conf.example`.
Since you've updated `home-assistant-icons.html`, you've made changes to the frontend:
+10 -2
View File
@@ -1,19 +1,27 @@
FROM python:3-onbuild
FROM python:3.4
MAINTAINER Paulus Schoutsen <Paulus@PaulusSchoutsen.nl>
VOLUME /config
RUN pip3 install --no-cache-dir -r requirements_all.txt
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# For the nmap tracker
RUN apt-get update && \
apt-get install -y --no-install-recommends nmap net-tools && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY script/build_python_openzwave script/build_python_openzwave
RUN apt-get update && \
apt-get install -y cython3 libudev-dev && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
pip3 install "cython<0.23" && \
script/build_python_openzwave
COPY requirements_all.txt requirements_all.txt
RUN pip3 install --no-cache-dir -r requirements_all.txt
# Copy source
COPY . .
CMD [ "python", "-m", "homeassistant", "--config", "/config" ]
+1 -1
View File
@@ -1,4 +1,4 @@
include README.md
include README.rst
include LICENSE
graft homeassistant
prune homeassistant/components/frontend/www_static/home-assistant-polymer
-39
View File
@@ -1,39 +0,0 @@
# Home Assistant [![Build Status](https://travis-ci.org/balloob/home-assistant.svg?branch=master)](https://travis-ci.org/balloob/home-assistant) [![Coverage Status](https://img.shields.io/coveralls/balloob/home-assistant.svg)](https://coveralls.io/r/balloob/home-assistant?branch=master) [![Join the chat at https://gitter.im/balloob/home-assistant](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/balloob/home-assistant?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[demo]: https://home-assistant.io/demo/
Home Assistant is a home automation platform running on Python 3. The goal of Home Assistant is to be able to track and control all devices at home and offer a platform for automating control.
To get started:
```bash
python3 -m pip install homeassistant
hass --open-ui
```
Check out [the website](https://home-assistant.io) for [a demo][demo], installation instructions, tutorials and documentation.
[![screenshot-states](https://raw.github.com/balloob/home-assistant/master/docs/screenshots.png)][demo]
Examples of devices it can interface it:
* Monitoring connected devices to a wireless router: [OpenWrt](https://openwrt.org/), [Tomato](http://www.polarcloud.com/tomato), [Netgear](http://netgear.com), [DD-WRT](http://www.dd-wrt.com/site/index), [TPLink](http://www.tp-link.us/), [ASUSWRT](http://event.asus.com/2013/nw/ASUSWRT/) and any SNMP capable Linksys WAP/WRT
*
* [Philips Hue](http://meethue.com) lights, [WeMo](http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/) switches, [Edimax](http://www.edimax.com/) switches, [Efergy](https://efergy.com) energy monitoring, RFXtrx sensors, and [Tellstick](http://www.telldus.se/products/tellstick) devices and sensors
* [Google Chromecasts](http://www.google.com/intl/en/chrome/devices/chromecast), [Music Player Daemon](http://www.musicpd.org/), [Logitech Squeezebox](https://en.wikipedia.org/wiki/Squeezebox_%28network_music_player%29), [Plex](https://plex.tv/), [Kodi (XBMC)](http://kodi.tv/), iTunes (by way of [itunes-api](https://github.com/maddox/itunes-api)), and Amazon Fire TV (by way of [python-firetv](https://github.com/happyleavesaoc/python-firetv))
* Support for [ISY994](https://www.universal-devices.com/residential/isy994i-series/) (Insteon and X10 devices), [Z-Wave](http://www.z-wave.com/), [Nest Thermostats](https://nest.com/), [RFXtrx](http://www.rfxcom.com/), [Arduino](https://www.arduino.cc/), [Raspberry Pi](https://www.raspberrypi.org/), and [Modbus](http://www.modbus.org/)
* Interaction with [IFTTT](https://ifttt.com/)
* Integrate data from the [Bitcoin](https://bitcoin.org) network, meteorological data from [OpenWeatherMap](http://openweathermap.org/) and [Forecast.io](https://forecast.io/), [Transmission](http://www.transmissionbt.com/), or [SABnzbd](http://sabnzbd.org).
* [See full list of supported devices](https://home-assistant.io/components/)
Built home automation on top of your devices:
* Keep a precise history of every change to the state of your house
* Turn on the lights when people get home after sun set
* Turn on lights slowly during sun set to compensate for less light
* Turn off all lights and devices when everybody leaves the house
* Offers a [REST API](https://home-assistant.io/developers/api.html) and can interface with MQTT for easy integration with other projects like [OwnTracks](http://owntracks.org/)
* Allow sending notifications using [Instapush](https://instapush.im), [Notify My Android (NMA)](http://www.notifymyandroid.com/), [PushBullet](https://www.pushbullet.com/), [PushOver](https://pushover.net/), [Slack](https://slack.com/), [Telegram](https://telegram.org/), and [Jabber (XMPP)](http://xmpp.org)
The system is built modular so support for other devices or actions can be implemented easily. See also the [section on architecture](https://home-assistant.io/developers/architecture.html) and the [section on creating your own components](https://home-assistant.io/developers/creating_components.html).
If you run into issues while using Home Assistant or during development of a component, check the [Home Assistant help section](https://home-assistant.io/help/) how to reach us.
+98
View File
@@ -0,0 +1,98 @@
Home Assistant |Build Status| |Coverage Status| |Join the chat at https://gitter.im/balloob/home-assistant|
===========================================================================================================
Home Assistant is a home automation platform running on Python 3. The
goal of Home Assistant is to be able to track and control all devices at
home and offer a platform for automating control.
To get started:
.. code:: bash
python3 -m pip install homeassistant
hass --open-ui
Check out `the website <https://home-assistant.io>`__ for `a
demo <https://home-assistant.io/demo/>`__, installation instructions,
tutorials and documentation.
|screenshot-states|
Examples of devices it can interface it:
- Monitoring connected devices to a wireless router:
`OpenWrt <https://openwrt.org/>`__,
`Tomato <http://www.polarcloud.com/tomato>`__,
`Netgear <http://netgear.com>`__,
`DD-WRT <http://www.dd-wrt.com/site/index>`__,
`TPLink <http://www.tp-link.us/>`__,
`ASUSWRT <http://event.asus.com/2013/nw/ASUSWRT/>`__ and any SNMP
capable Linksys WAP/WRT
- `Philips Hue <http://meethue.com>`__ lights,
`WeMo <http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/>`__
switches, `Edimax <http://www.edimax.com/>`__ switches,
`Efergy <https://efergy.com>`__ energy monitoring, and
`Tellstick <http://www.telldus.se/products/tellstick>`__ devices and
sensors
- `Google
Chromecasts <http://www.google.com/intl/en/chrome/devices/chromecast>`__,
`Music Player Daemon <http://www.musicpd.org/>`__, `Logitech
Squeezebox <https://en.wikipedia.org/wiki/Squeezebox_%28network_music_player%29>`__,
`Plex <https://plex.tv/>`__, `Kodi (XBMC) <http://kodi.tv/>`__,
iTunes (by way of
`itunes-api <https://github.com/maddox/itunes-api>`__), and Amazon
Fire TV (by way of
`python-firetv <https://github.com/happyleavesaoc/python-firetv>`__)
- Support for
`ISY994 <https://www.universal-devices.com/residential/isy994i-series/>`__
(Insteon and X10 devices), `Z-Wave <http://www.z-wave.com/>`__, `Nest
Thermostats <https://nest.com/>`__,
`RFXtrx <http://www.rfxcom.com/>`__,
`Arduino <https://www.arduino.cc/>`__, `Raspberry
Pi <https://www.raspberrypi.org/>`__, and
`Modbus <http://www.modbus.org/>`__
- Interaction with `IFTTT <https://ifttt.com/>`__
- Integrate data from the `Bitcoin <https://bitcoin.org>`__ network,
meteorological data from
`OpenWeatherMap <http://openweathermap.org/>`__ and
`Forecast.io <https://forecast.io/>`__,
`Transmission <http://www.transmissionbt.com/>`__, or
`SABnzbd <http://sabnzbd.org>`__.
- `See full list of supported
devices <https://home-assistant.io/components/>`__
Built home automation on top of your devices:
- Keep a precise history of every change to the state of your house
- Turn on the lights when people get home after sun set
- Turn on lights slowly during sun set to compensate for less light
- Turn off all lights and devices when everybody leaves the house
- Offers a `REST API <https://home-assistant.io/developers/api/>`__
and can interface with MQTT for easy integration with other projects
like `OwnTracks <http://owntracks.org/>`__
- Allow sending notifications using
`Instapush <https://instapush.im>`__, `Notify My Android
(NMA) <http://www.notifymyandroid.com/>`__,
`PushBullet <https://www.pushbullet.com/>`__,
`PushOver <https://pushover.net/>`__, `Slack <https://slack.com/>`__,
`Telegram <https://telegram.org/>`__, and `Jabber
(XMPP) <http://xmpp.org>`__
The system is built modular so support for other devices or actions can
be implemented easily. See also the `section on
architecture <https://home-assistant.io/developers/architecture.html>`__
and the `section on creating your own
components <https://home-assistant.io/developers/creating_components.html>`__.
If you run into issues while using Home Assistant or during development
of a component, check the `Home Assistant help
section <https://home-assistant.io/help/>`__ how to reach us.
.. |Build Status| image:: https://travis-ci.org/balloob/home-assistant.svg?branch=master
:target: https://travis-ci.org/balloob/home-assistant
.. |Coverage Status| image:: https://img.shields.io/coveralls/balloob/home-assistant.svg
:target: https://coveralls.io/r/balloob/home-assistant?branch=master
.. |Join the chat at https://gitter.im/balloob/home-assistant| image:: https://badges.gitter.im/Join%20Chat.svg
:target: https://gitter.im/balloob/home-assistant?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
.. |screenshot-states| image:: https://raw.github.com/balloob/home-assistant/master/docs/screenshots.png
:target: https://home-assistant.io/demo/
+42 -15
View File
@@ -9,11 +9,12 @@ After bootstrapping you can add your own components or
start by calling homeassistant.start_home_assistant(bus)
"""
import os
import sys
from collections import defaultdict
import logging
import logging.handlers
from collections import defaultdict
import os
import shutil
import sys
import homeassistant.core as core
import homeassistant.util.dt as date_util
@@ -25,7 +26,7 @@ import homeassistant.components as core_components
import homeassistant.components.group as group
from homeassistant.helpers.entity import Entity
from homeassistant.const import (
EVENT_COMPONENT_LOADED, CONF_LATITUDE, CONF_LONGITUDE,
__version__, EVENT_COMPONENT_LOADED, CONF_LATITUDE, CONF_LONGITUDE,
CONF_TEMPERATURE_UNIT, CONF_NAME, CONF_TIME_ZONE, CONF_CUSTOMIZE,
TEMP_CELCIUS, TEMP_FAHRENHEIT)
@@ -34,6 +35,7 @@ _LOGGER = logging.getLogger(__name__)
ATTR_COMPONENT = 'component'
PLATFORM_FORMAT = '{}.{}'
ERROR_LOG_FILENAME = 'home-assistant.log'
def setup_component(hass, domain, config=None):
@@ -80,7 +82,7 @@ def _setup_component(hass, domain, config):
return True
component = loader.get_component(domain)
missing_deps = [dep for dep in component.DEPENDENCIES
missing_deps = [dep for dep in getattr(component, 'DEPENDENCIES', [])
if dep not in hass.config.components]
if missing_deps:
@@ -104,7 +106,7 @@ def _setup_component(hass, domain, config):
# Assumption: if a component does not depend on groups
# it communicates with devices
if group.DOMAIN not in component.DEPENDENCIES:
if group.DOMAIN not in getattr(component, 'DEPENDENCIES', []):
hass.pool.add_worker()
hass.bus.fire(
@@ -131,14 +133,13 @@ def prepare_setup_platform(hass, config, domain, platform_name):
return platform
# Load dependencies
if hasattr(platform, 'DEPENDENCIES'):
for component in platform.DEPENDENCIES:
if not setup_component(hass, component, config):
_LOGGER.error(
'Unable to prepare setup for platform %s because '
'dependency %s could not be initialized', platform_path,
component)
return None
for component in getattr(platform, 'DEPENDENCIES', []):
if not setup_component(hass, component, config):
_LOGGER.error(
'Unable to prepare setup for platform %s because '
'dependency %s could not be initialized', platform_path,
component)
return None
if not _handle_requirements(hass, platform, platform_path):
return None
@@ -167,6 +168,7 @@ def from_config_dict(config, hass=None, config_dir=None, enable_log=True,
hass.config.config_dir = config_dir
mount_local_lib_path(config_dir)
process_ha_config_upgrade(hass)
process_ha_core_config(hass, config.get(core.DOMAIN, {}))
if enable_log:
@@ -252,7 +254,7 @@ def enable_logging(hass, verbose=False, daemon=False, log_rotate_days=None):
"Colorlog package not found, console coloring disabled")
# Log errors to a file if we have write access to file or config dir
err_log_path = hass.config.path('home-assistant.log')
err_log_path = hass.config.path(ERROR_LOG_FILENAME)
err_path_exists = os.path.isfile(err_log_path)
# Check if we can write to the error log if it exists or that
@@ -280,6 +282,31 @@ def enable_logging(hass, verbose=False, daemon=False, log_rotate_days=None):
'Unable to setup error log %s (access denied)', err_log_path)
def process_ha_config_upgrade(hass):
""" Upgrade config if necessary. """
version_path = hass.config.path('.HA_VERSION')
try:
with open(version_path, 'rt') as inp:
conf_version = inp.readline().strip()
except FileNotFoundError:
# Last version to not have this file
conf_version = '0.7.7'
if conf_version == __version__:
return
_LOGGER.info('Upgrading config directory from %s to %s', conf_version,
__version__)
lib_path = hass.config.path('lib')
if os.path.isdir(lib_path):
shutil.rmtree(lib_path)
with open(version_path, 'wt') as outp:
outp.write(__version__)
def process_ha_core_config(hass, config):
""" Processes the [homeassistant] section from the config. """
hac = hass.config
-2
View File
@@ -1,7 +1,6 @@
"""
homeassistant.components
~~~~~~~~~~~~~~~~~~~~~~~~
This package contains components that can be plugged into Home Assistant.
Component design guidelines:
@@ -12,7 +11,6 @@ Each component that tracks states should create state entity names in the
format "<DOMAIN>.<OBJECT_ID>".
Each component should publish services only under its own domain.
"""
import itertools as it
import logging
@@ -15,7 +15,6 @@ from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
DOMAIN = 'alarm_control_panel'
DEPENDENCIES = []
SCAN_INTERVAL = 30
ENTITY_ID_FORMAT = DOMAIN + '.{}'
@@ -0,0 +1,13 @@
"""
homeassistant.components.alarm_control_panel.demo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo platform that has two fake alarm control panels.
"""
import homeassistant.components.alarm_control_panel.manual as manual
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Demo alarm control panels. """
add_devices([
manual.ManualAlarm(hass, 'Alarm', '1234', 5, 10),
])
@@ -4,7 +4,7 @@ homeassistant.components.alarm_control_panel.manual
Support for manual alarms.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.manual.html
https://home-assistant.io/components/alarm_control_panel.manual/
"""
import logging
import datetime
@@ -18,8 +18,6 @@ from homeassistant.const import (
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = []
DEFAULT_ALARM_NAME = 'HA Alarm'
DEFAULT_PENDING_TIME = 60
DEFAULT_TRIGGER_TIME = 120
@@ -4,7 +4,7 @@ homeassistant.components.alarm_control_panel.mqtt
This platform enables the possibility to control a MQTT alarm.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.mqtt.html
https://home-assistant.io/components/alarm_control_panel.mqtt/
"""
import logging
import homeassistant.components.mqtt as mqtt
@@ -2,6 +2,9 @@
homeassistant.components.alarm_control_panel.verisure
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Interfaces with Verisure alarm control panel.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/verisure/
"""
import logging
+24 -6
View File
@@ -4,7 +4,7 @@ homeassistant.components.api
Provides a Rest API for Home Assistant.
For more details about the RESTful API, please refer to the documentation at
https://home-assistant.io/developers/api.html
https://home-assistant.io/developers/api/
"""
import re
import logging
@@ -14,10 +14,11 @@ import json
import homeassistant.core as ha
from homeassistant.helpers.state import TrackStates
import homeassistant.remote as rem
from homeassistant.bootstrap import ERROR_LOG_FILENAME
from homeassistant.const import (
URL_API, URL_API_STATES, URL_API_EVENTS, URL_API_SERVICES, URL_API_STREAM,
URL_API_EVENT_FORWARD, URL_API_STATES_ENTITY, URL_API_COMPONENTS,
URL_API_CONFIG, URL_API_BOOTSTRAP,
URL_API_CONFIG, URL_API_BOOTSTRAP, URL_API_ERROR_LOG, URL_API_LOG_OUT,
EVENT_TIME_CHANGED, EVENT_HOMEASSISTANT_STOP, MATCH_ALL,
HTTP_OK, HTTP_CREATED, HTTP_BAD_REQUEST, HTTP_NOT_FOUND,
HTTP_UNPROCESSABLE_ENTITY)
@@ -35,10 +36,6 @@ _LOGGER = logging.getLogger(__name__)
def setup(hass, config):
""" Register the API with the HTTP interface. """
if 'http' not in hass.config.components:
_LOGGER.error('Dependency http is not loaded')
return False
# /api - for validation purposes
hass.http.register_path('GET', URL_API, _handle_get_api)
@@ -89,6 +86,11 @@ def setup(hass, config):
hass.http.register_path(
'GET', URL_API_COMPONENTS, _handle_get_api_components)
hass.http.register_path('GET', URL_API_ERROR_LOG,
_handle_get_api_error_log)
hass.http.register_path('POST', URL_API_LOG_OUT, _handle_post_api_log_out)
return True
@@ -104,6 +106,7 @@ def _handle_get_api_stream(handler, path_match, data):
wfile = handler.wfile
write_lock = threading.Lock()
block = threading.Event()
session_id = None
restrict = data.get('restrict')
if restrict:
@@ -117,6 +120,7 @@ def _handle_get_api_stream(handler, path_match, data):
try:
wfile.write(msg.encode("UTF-8"))
wfile.flush()
handler.server.sessions.extend_validation(session_id)
except IOError:
block.set()
@@ -136,6 +140,7 @@ def _handle_get_api_stream(handler, path_match, data):
handler.send_response(HTTP_OK)
handler.send_header('Content-type', 'text/event-stream')
session_id = handler.set_session_cookie_header()
handler.end_headers()
hass.bus.listen(MATCH_ALL, forward_events)
@@ -341,6 +346,19 @@ def _handle_get_api_components(handler, path_match, data):
handler.write_json(handler.server.hass.config.components)
def _handle_get_api_error_log(handler, path_match, data):
""" Returns the logged errors for this session. """
handler.write_file(handler.server.hass.config.path(ERROR_LOG_FILENAME),
False)
def _handle_post_api_log_out(handler, path_match, data):
""" Log user out. """
handler.send_response(HTTP_OK)
handler.destroy_session()
handler.end_headers()
def _services_json(hass):
""" Generate services data to JSONify. """
return [{"domain": key, "services": value}
+1 -2
View File
@@ -5,7 +5,7 @@ Arduino component that connects to a directly attached Arduino board which
runs with the Firmata firmware.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/arduino.html
https://home-assistant.io/components/arduino/
"""
import logging
@@ -19,7 +19,6 @@ from homeassistant.const import (EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP)
DOMAIN = "arduino"
DEPENDENCIES = []
REQUIREMENTS = ['PyMata==2.07a']
BOARD = None
_LOGGER = logging.getLogger(__name__)
@@ -1,8 +1,10 @@
"""
homeassistant.components.automation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to setup simple automation rules via the config file.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/automation/
"""
import logging
@@ -121,7 +123,7 @@ def _migrate_old_config(config):
_LOGGER.warning(
'You are using an old configuration format. Please upgrade: '
'https://home-assistant.io/components/automation.html')
'https://home-assistant.io/components/automation/')
new_conf = {
CONF_TRIGGER: dict(config),
+1 -1
View File
@@ -4,7 +4,7 @@ homeassistant.components.automation.event
Offers event listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#event-trigger
at https://home-assistant.io/components/automation/#event-trigger
"""
import logging
+1 -1
View File
@@ -4,7 +4,7 @@ homeassistant.components.automation.mqtt
Offers MQTT listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#mqtt-trigger
at https://home-assistant.io/components/automation/#mqtt-trigger
"""
import logging
@@ -1,10 +1,10 @@
"""
homeassistant.components.automation.numeric_state
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Offers numeric state listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#numeric-state-trigger
at https://home-assistant.io/components/automation/#numeric-state-trigger
"""
import logging
@@ -14,6 +14,7 @@ from homeassistant.helpers.event import track_state_change
CONF_ENTITY_ID = "entity_id"
CONF_BELOW = "below"
CONF_ABOVE = "above"
CONF_ATTRIBUTE = "attribute"
_LOGGER = logging.getLogger(__name__)
@@ -28,6 +29,7 @@ def trigger(hass, config, action):
below = config.get(CONF_BELOW)
above = config.get(CONF_ABOVE)
attribute = config.get(CONF_ATTRIBUTE)
if below is None and above is None:
_LOGGER.error("Missing configuration key."
@@ -40,8 +42,8 @@ def trigger(hass, config, action):
""" Listens for state changes and calls action. """
# Fire action if we go from outside range into range
if _in_range(to_s.state, above, below) and \
(from_s is None or not _in_range(from_s.state, above, below)):
if _in_range(to_s, above, below, attribute) and \
(from_s is None or not _in_range(from_s, above, below, attribute)):
action()
track_state_change(
@@ -61,6 +63,7 @@ def if_action(hass, config):
below = config.get(CONF_BELOW)
above = config.get(CONF_ABOVE)
attribute = config.get(CONF_ATTRIBUTE)
if below is None and above is None:
_LOGGER.error("Missing configuration key."
@@ -71,18 +74,19 @@ def if_action(hass, config):
def if_numeric_state():
""" Test numeric state condition. """
state = hass.states.get(entity_id)
return state is not None and _in_range(state.state, above, below)
return state is not None and _in_range(state, above, below, attribute)
return if_numeric_state
def _in_range(value, range_start, range_end):
def _in_range(state, range_start, range_end, attribute):
""" Checks if value is inside the range """
value = (state.state if attribute is None
else state.attributes.get(attribute))
try:
value = float(value)
except ValueError:
_LOGGER.warn("Missing value in numeric check")
_LOGGER.warning("Missing value in numeric check")
return False
if range_start is not None and range_end is not None:
+1 -1
View File
@@ -4,7 +4,7 @@ homeassistant.components.automation.state
Offers state listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#state-trigger
at https://home-assistant.io/components/automation/#state-trigger
"""
import logging
+1 -1
View File
@@ -4,7 +4,7 @@ homeassistant.components.automation.sun
Offers sun based automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#sun-trigger
at https://home-assistant.io/components/automation/#sun-trigger
"""
import logging
from datetime import timedelta
+1 -1
View File
@@ -4,7 +4,7 @@ homeassistant.components.automation.time
Offers time listening automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#time-trigger
at https://home-assistant.io/components/automation/#time-trigger
"""
import logging
+2 -1
View File
@@ -4,7 +4,7 @@ homeassistant.components.automation.zone
Offers zone automation rules.
For more details about this automation rule, please refer to the documentation
at https://home-assistant.io/components/automation.html#zone-trigger
at https://home-assistant.io/components/automation/#zone-trigger
"""
import logging
@@ -46,6 +46,7 @@ def trigger(hass, config, action):
from_match = _in_zone(hass, zone_entity_id, from_s) if from_s else None
to_match = _in_zone(hass, zone_entity_id, to_s)
# pylint: disable=too-many-boolean-expressions
if event == EVENT_ENTER and not from_match and to_match or \
event == EVENT_LEAVE and from_match and not to_match:
action()
@@ -0,0 +1,49 @@
"""
homeassistant.components.binary_sensor
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component to interface with binary sensors (sensors which only know two states)
that can be monitored.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/binary_sensor/
"""
import logging
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.entity import Entity
from homeassistant.const import (STATE_ON, STATE_OFF)
DOMAIN = 'binary_sensor'
SCAN_INTERVAL = 30
ENTITY_ID_FORMAT = DOMAIN + '.{}'
def setup(hass, config):
""" Track states and offer events for binary sensors. """
component = EntityComponent(
logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL)
component.setup(config)
return True
# pylint: disable=no-self-use
class BinarySensorDevice(Entity):
""" Represents a binary sensor. """
@property
def is_on(self):
""" True if the binary sensor is on. """
return None
@property
def state(self):
""" Returns the state of the binary sensor. """
return STATE_ON if self.is_on else STATE_OFF
@property
def friendly_state(self):
""" Returns the friendly state of the binary sensor. """
return None
@@ -0,0 +1,107 @@
"""
homeassistant.components.binary_sensor.arest
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The arest sensor will consume an exposed aREST API of a device.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.arest/
"""
from datetime import timedelta
import logging
import requests
from homeassistant.util import Throttle
from homeassistant.components.binary_sensor import BinarySensorDevice
_LOGGER = logging.getLogger(__name__)
# Return cached results if last scan was less then this time ago
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=30)
CONF_RESOURCE = 'resource'
CONF_PIN = 'pin'
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Get the aREST binary sensor. """
resource = config.get(CONF_RESOURCE)
pin = config.get(CONF_PIN)
if None in (resource, pin):
_LOGGER.error('Not all required config keys present: %s',
', '.join((CONF_RESOURCE, CONF_PIN)))
return False
try:
response = requests.get(resource, timeout=10).json()
except requests.exceptions.MissingSchema:
_LOGGER.error('Missing resource or schema in configuration. '
'Add http:// to your URL.')
return False
except requests.exceptions.ConnectionError:
_LOGGER.error('No route to device at %s. '
'Please check the IP address in the configuration file.',
resource)
return False
arest = ArestData(resource, pin)
add_devices([ArestBinarySensor(arest,
resource,
config.get('name', response['name']),
pin)])
# pylint: disable=too-many-instance-attributes, too-many-arguments
class ArestBinarySensor(BinarySensorDevice):
""" Implements an aREST binary sensor for a pin. """
def __init__(self, arest, resource, name, pin):
self.arest = arest
self._resource = resource
self._name = name
self._pin = pin
self.update()
if self._pin is not None:
request = requests.get('{}/mode/{}/i'.format
(self._resource, self._pin), timeout=10)
if request.status_code is not 200:
_LOGGER.error("Can't set mode. Is device offline?")
@property
def name(self):
""" The name of the binary sensor. """
return self._name
@property
def is_on(self):
""" True if the binary sensor is on. """
return bool(self.arest.data.get('state'))
def update(self):
""" Gets the latest data from aREST API. """
self.arest.update()
# pylint: disable=too-few-public-methods
class ArestData(object):
""" Class for handling the data retrieval for pins. """
def __init__(self, resource, pin):
self._resource = resource
self._pin = pin
self.data = {}
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
""" Gets the latest data from aREST device. """
try:
response = requests.get('{}/digital/{}'.format(
self._resource, self._pin), timeout=10)
self.data = {'state': response.json()['return_value']}
except requests.exceptions.ConnectionError:
_LOGGER.error("No route to device '%s'. Is device offline?",
self._resource)
@@ -0,0 +1,37 @@
"""
homeassistant.components.binary_sensor.demo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo platform that has two fake binary sensors.
"""
from homeassistant.components.binary_sensor import BinarySensorDevice
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Demo binary sensors. """
add_devices([
DemoBinarySensor('Basement Floor Wet', False),
DemoBinarySensor('Movement Backyard', True),
])
class DemoBinarySensor(BinarySensorDevice):
""" A Demo binary sensor. """
def __init__(self, name, state):
self._name = name
self._state = state
@property
def should_poll(self):
""" No polling needed for a demo binary sensor. """
return False
@property
def name(self):
""" Returns the name of the binary sensor. """
return self._name
@property
def is_on(self):
""" True if the binary sensor is on. """
return self._state
@@ -0,0 +1,76 @@
"""
homeassistant.components.binary_sensor.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to configure a MQTT binary sensor.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.mqtt/
"""
import logging
from homeassistant.components.binary_sensor import BinarySensorDevice
import homeassistant.components.mqtt as mqtt
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = 'MQTT Binary sensor'
DEFAULT_QOS = 0
DEFAULT_PAYLOAD_ON = 'ON'
DEFAULT_PAYLOAD_OFF = 'OFF'
DEPENDENCIES = ['mqtt']
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Add MQTT binary sensor. """
if config.get('state_topic') is None:
_LOGGER.error('Missing required variable: state_topic')
return False
add_devices([MqttBinarySensor(
hass,
config.get('name', DEFAULT_NAME),
config.get('state_topic', None),
config.get('qos', DEFAULT_QOS),
config.get('payload_on', DEFAULT_PAYLOAD_ON),
config.get('payload_off', DEFAULT_PAYLOAD_OFF))])
# pylint: disable=too-many-arguments, too-many-instance-attributes
class MqttBinarySensor(BinarySensorDevice):
""" Represents a binary sensor that is updated by MQTT. """
def __init__(self, hass, name, state_topic, qos, payload_on, payload_off):
self._hass = hass
self._name = name
self._state = False
self._state_topic = state_topic
self._payload_on = payload_on
self._payload_off = payload_off
self._qos = qos
def message_received(topic, payload, qos):
""" A new MQTT message has been received. """
if payload == self._payload_on:
self._state = True
self.update_ha_state()
elif payload == self._payload_off:
self._state = False
self.update_ha_state()
mqtt.subscribe(hass, self._state_topic, message_received, self._qos)
@property
def should_poll(self):
""" No polling needed. """
return False
@property
def name(self):
""" The name of the binary sensor. """
return self._name
@property
def is_on(self):
""" True if the binary sensor is on. """
return self._state
+3 -2
View File
@@ -1,12 +1,13 @@
"""
homeassistant.components.browser
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to launch a webbrowser on the host machine.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/browser/
"""
DOMAIN = "browser"
DEPENDENCIES = []
SERVICE_BROWSE_URL = "browse_url"
+34 -46
View File
@@ -4,38 +4,23 @@ homeassistant.components.camera
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component to interface with various cameras.
The following features are supported:
- Returning recorded camera images and streams
- Proxying image requests via HA for external access
- Converting a still image url into a live video stream
Upcoming features
- Recording
- Snapshot
- Motion Detection Recording(for supported cameras)
- Automatic Configuration(for supported cameras)
- Creation of child entities for supported functions
- Collating motion event images passed via FTP into time based events
- A service for calling camera functions
- Camera movement(panning)
- Zoom
- Light/Nightvision toggling
- Support for more devices
- Expanded documentation
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/camera/
"""
import requests
import logging
import time
import re
import time
import requests
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.const import (
ATTR_ENTITY_PICTURE,
HTTP_NOT_FOUND,
ATTR_ENTITY_ID,
)
from homeassistant.helpers.entity_component import EntityComponent
DOMAIN = 'camera'
DEPENDENCIES = ['http']
@@ -74,7 +59,7 @@ MJPEG_START_HEADER = 'Content-type: {0}\r\n\r\n'
# pylint: disable=too-many-branches
def setup(hass, config):
""" Track states and offer events for sensors. """
""" Track states and offer events for cameras. """
component = EntityComponent(
logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL,
@@ -96,16 +81,21 @@ def setup(hass, config):
def _proxy_camera_image(handler, path_match, data):
""" Proxies the camera image via the HA server. """
entity_id = path_match.group(ATTR_ENTITY_ID)
camera = component.entities.get(entity_id)
camera = None
if entity_id in component.entities.keys():
camera = component.entities[entity_id]
if camera:
response = camera.camera_image()
handler.wfile.write(response)
else:
if camera is None:
handler.send_response(HTTP_NOT_FOUND)
handler.end_headers()
return
response = camera.camera_image()
if response is None:
handler.send_response(HTTP_NOT_FOUND)
handler.end_headers()
return
handler.wfile.write(response)
hass.http.register_path(
'GET',
@@ -114,18 +104,16 @@ def setup(hass, config):
# pylint: disable=unused-argument
def _proxy_camera_mjpeg_stream(handler, path_match, data):
""" Proxies the camera image as an mjpeg stream via the HA server.
"""
Proxies the camera image as an mjpeg stream via the HA server.
This function takes still images from the IP camera and turns them
into an MJPEG stream. This means that HA can return a live video
stream even with only a still image URL available.
"""
entity_id = path_match.group(ATTR_ENTITY_ID)
camera = component.entities.get(entity_id)
camera = None
if entity_id in component.entities.keys():
camera = component.entities[entity_id]
if not camera:
if camera is None:
handler.send_response(HTTP_NOT_FOUND)
handler.end_headers()
return
@@ -143,9 +131,9 @@ def setup(hass, config):
# MJPEG_START_HEADER.format()
while True:
img_bytes = camera.camera_image()
if img_bytes is None:
continue
headers_str = '\r\n'.join((
'Content-length: {}'.format(len(img_bytes)),
'Content-type: image/jpeg',
@@ -159,12 +147,12 @@ def setup(hass, config):
handler.request.sendall(
bytes('--jpgboundary\r\n', 'utf-8'))
time.sleep(0.5)
except (requests.RequestException, IOError):
camera.is_streaming = False
camera.update_ha_state()
camera.is_streaming = False
hass.http.register_path(
'GET',
re.compile(
@@ -175,7 +163,7 @@ def setup(hass, config):
class Camera(Entity):
""" The base class for camera components """
""" The base class for camera components. """
def __init__(self):
self.is_streaming = False
@@ -183,23 +171,23 @@ class Camera(Entity):
@property
# pylint: disable=no-self-use
def is_recording(self):
""" Returns true if the device is recording """
""" Returns true if the device is recording. """
return False
@property
# pylint: disable=no-self-use
def brand(self):
""" Should return a string of the camera brand """
""" Should return a string of the camera brand. """
return None
@property
# pylint: disable=no-self-use
def model(self):
""" Returns string of camera model """
""" Returns string of camera model. """
return None
def camera_image(self):
""" Return bytes of camera image """
""" Return bytes of camera image. """
raise NotImplementedError()
@property
+37
View File
@@ -0,0 +1,37 @@
"""
homeassistant.components.camera.demo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo platform that has a fake camera.
"""
import os
from homeassistant.components.camera import Camera
import homeassistant.util.dt as dt_util
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Demo camera. """
add_devices([
DemoCamera('Demo camera')
])
class DemoCamera(Camera):
""" A Demo camera. """
def __init__(self, name):
super().__init__()
self._name = name
def camera_image(self):
""" Return a faked still image response. """
now = dt_util.utcnow()
image_path = os.path.join(os.path.dirname(__file__),
'demo_{}.jpg'.format(now.second % 4))
with open(image_path, 'rb') as file:
return file.read()
@property
def name(self):
""" Return the name of this device. """
return self._name
Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

+7 -15
View File
@@ -4,14 +4,14 @@ homeassistant.components.camera.foscam
This component provides basic support for Foscam IP cameras.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.foscam.html
https://home-assistant.io/components/camera.foscam/
"""
import logging
from homeassistant.helpers import validate_config
from homeassistant.components.camera import DOMAIN
from homeassistant.components.camera import Camera
import requests
import re
from homeassistant.helpers import validate_config
from homeassistant.components.camera import DOMAIN, Camera
_LOGGER = logging.getLogger(__name__)
@@ -40,7 +40,7 @@ class FoscamCamera(Camera):
self._username = device_info.get('username')
self._password = device_info.get('password')
self._snap_picture_url = self._base_url \
+ 'cgi-bin/CGIProxy.fcgi?cmd=snapPicture&usr=' \
+ 'cgi-bin/CGIProxy.fcgi?cmd=snapPicture2&usr=' \
+ self._username + '&pwd=' + self._password
self._name = device_info.get('name', 'Foscam Camera')
@@ -50,17 +50,9 @@ class FoscamCamera(Camera):
def camera_image(self):
""" Return a still image reponse from the camera. """
# send the request to snap a picture
# Send the request to snap a picture and return raw jpg data
response = requests.get(self._snap_picture_url)
# parse the response to find the image file name
pattern = re.compile('src="[.][.]/(.*[.]jpg)"')
filename = pattern.search(response.content.decode("utf-8")).group(1)
# send request for the image
response = requests.get(self._base_url + filename)
return response.content
@property
+19 -10
View File
@@ -4,14 +4,15 @@ homeassistant.components.camera.generic
Support for IP Cameras.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.generic.html
https://home-assistant.io/components/camera.generic/
"""
import logging
from requests.auth import HTTPBasicAuth
from homeassistant.helpers import validate_config
from homeassistant.components.camera import DOMAIN
from homeassistant.components.camera import Camera
import requests
from requests.auth import HTTPBasicAuth
from homeassistant.helpers import validate_config
from homeassistant.components.camera import DOMAIN, Camera
_LOGGER = logging.getLogger(__name__)
@@ -40,13 +41,21 @@ class GenericCamera(Camera):
self._still_image_url = device_info['still_image_url']
def camera_image(self):
""" Return a still image reponse from the camera. """
""" Return a still image response from the camera. """
if self._username and self._password:
response = requests.get(
self._still_image_url,
auth=HTTPBasicAuth(self._username, self._password))
try:
response = requests.get(
self._still_image_url,
auth=HTTPBasicAuth(self._username, self._password))
except requests.exceptions.RequestException as error:
_LOGGER.error('Error getting camera image: %s', error)
return None
else:
response = requests.get(self._still_image_url)
try:
response = requests.get(self._still_image_url)
except requests.exceptions.RequestException as error:
_LOGGER.error('Error getting camera image: %s', error)
return None
return response.content
+72
View File
@@ -0,0 +1,72 @@
"""
homeassistant.components.camera.mjpeg
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for IP Cameras.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.mjpeg/
"""
from contextlib import closing
import logging
import requests
from requests.auth import HTTPBasicAuth
from homeassistant.helpers import validate_config
from homeassistant.components.camera import DOMAIN, Camera
_LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Adds a mjpeg IP Camera. """
if not validate_config({DOMAIN: config}, {DOMAIN: ['mjpeg_url']},
_LOGGER):
return None
add_devices_callback([MjpegCamera(config)])
# pylint: disable=too-many-instance-attributes
class MjpegCamera(Camera):
"""
A generic implementation of an IP camera that is reachable over a URL.
"""
def __init__(self, device_info):
super().__init__()
self._name = device_info.get('name', 'Mjpeg Camera')
self._username = device_info.get('username')
self._password = device_info.get('password')
self._mjpeg_url = device_info['mjpeg_url']
def camera_image(self):
""" Return a still image response from the camera. """
def process_response(response):
""" Take in a response object, return the jpg from it. """
data = b''
for chunk in response.iter_content(1024):
data += chunk
jpg_start = data.find(b'\xff\xd8')
jpg_end = data.find(b'\xff\xd9')
if jpg_start != -1 and jpg_end != -1:
jpg = data[jpg_start:jpg_end + 2]
return jpg
if self._username and self._password:
with closing(requests.get(self._mjpeg_url,
auth=HTTPBasicAuth(self._username,
self._password),
stream=True)) as response:
return process_response(response)
else:
with closing(requests.get(self._mjpeg_url,
stream=True)) as response:
return process_response(response)
@property
def name(self):
""" Return the name of this device. """
return self._name
-1
View File
@@ -15,7 +15,6 @@ from homeassistant.helpers import generate_entity_id
from homeassistant.const import EVENT_TIME_CHANGED
DOMAIN = "configurator"
DEPENDENCIES = []
ENTITY_ID_FORMAT = DOMAIN + ".{}"
SERVICE_CONFIGURE = "configure"
+1 -2
View File
@@ -4,7 +4,7 @@ homeassistant.components.conversation
Provides functionality to have conversations with Home Assistant.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/conversation.html
https://home-assistant.io/components/conversation/
"""
import logging
import re
@@ -14,7 +14,6 @@ from homeassistant.const import (
ATTR_ENTITY_ID, SERVICE_TURN_ON, SERVICE_TURN_OFF)
DOMAIN = "conversation"
DEPENDENCIES = []
SERVICE_PROCESS = "process"
+18 -41
View File
@@ -10,14 +10,26 @@ import homeassistant.core as ha
import homeassistant.bootstrap as bootstrap
import homeassistant.loader as loader
from homeassistant.const import (
CONF_PLATFORM, ATTR_ENTITY_PICTURE, ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME)
CONF_PLATFORM, ATTR_ENTITY_ID)
DOMAIN = "demo"
DEPENDENCIES = ['introduction', 'conversation']
DEPENDENCIES = ['conversation', 'introduction', 'zone']
COMPONENTS_WITH_DEMO_PLATFORM = [
'switch', 'light', 'sensor', 'thermostat', 'media_player', 'notify']
'alarm_control_panel',
'binary_sensor',
'camera',
'device_tracker',
'light',
'lock',
'media_player',
'notify',
'rollershutter',
'sensor',
'switch',
'thermostat',
]
def setup(hass, config):
@@ -41,9 +53,10 @@ def setup(hass, config):
bootstrap.setup_component(hass, 'sun')
# Setup demo platforms
demo_config = config.copy()
for component in COMPONENTS_WITH_DEMO_PLATFORM:
bootstrap.setup_component(
hass, component, {component: {CONF_PLATFORM: 'demo'}})
demo_config[component] = {CONF_PLATFORM: 'demo'}
bootstrap.setup_component(hass, component, demo_config)
# Setup room groups
lights = sorted(hass.states.entity_ids('light'))
@@ -54,23 +67,6 @@ def setup(hass, config):
group.setup_group(hass, 'bedroom', [lights[0], switches[1],
media_players[0]])
# Setup IP Camera
bootstrap.setup_component(
hass, 'camera',
{'camera': {
'platform': 'generic',
'name': 'IP Camera',
'still_image_url': 'http://home-assistant.io/demo/webcam.jpg',
}})
# Setup alarm_control_panel
bootstrap.setup_component(
hass, 'alarm_control_panel',
{'alarm_control_panel': {
'platform': 'manual',
'name': 'Test Alarm',
}})
# Setup scripts
bootstrap.setup_component(
hass, 'script',
@@ -110,25 +106,6 @@ def setup(hass, config):
}},
]})
# Setup fake device tracker
hass.states.set("device_tracker.paulus", "home",
{ATTR_ENTITY_PICTURE:
"http://graph.facebook.com/297400035/picture",
ATTR_FRIENDLY_NAME: 'Paulus'})
hass.states.set("device_tracker.anne_therese", "not_home",
{ATTR_FRIENDLY_NAME: 'Anne Therese',
'latitude': hass.config.latitude + 0.002,
'longitude': hass.config.longitude + 0.002})
hass.states.set("group.all_devices", "home",
{
"auto": True,
ATTR_ENTITY_ID: [
"device_tracker.paulus",
"device_tracker.anne_therese"
]
})
# Setup configurator
configurator_ids = []
@@ -1,9 +1,11 @@
"""
homeassistant.components.device_sun_light_trigger
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to turn on lights based on the state of the sun and
devices.
Provides functionality to turn on lights based on
the state of the sun and devices.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/device_sun_light_trigger/
"""
import logging
from datetime import timedelta
@@ -1,25 +1,10 @@
"""
homeassistant.components.device_tracker
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to keep track of devices.
device_tracker:
platform: netgear
# Optional
# How many seconds to wait after not seeing device to consider it not home
consider_home: 180
# Seconds between each scan
interval_seconds: 12
# New found devices auto found
track_new_devices: yes
# Maximum distance from home we consider people home
range_home: 100
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/device_tracker/
"""
# pylint: disable=too-many-instance-attributes, too-many-arguments
# pylint: disable=too-many-locals
@@ -5,7 +5,7 @@ Device tracker platform that supports scanning an Actiontec MI424WR
(Verizon FIOS) router for device presence.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.actiontec.html
https://home-assistant.io/components/device_tracker.actiontec/
"""
import logging
from datetime import timedelta
@@ -17,20 +17,19 @@ import telnetlib
import homeassistant.util.dt as dt_util
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
from homeassistant.helpers import validate_config
from homeassistant.util import Throttle, convert
from homeassistant.util import Throttle
from homeassistant.components.device_tracker import DOMAIN
# Return cached results if last scan was less then this time ago
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=5)
# Interval in minutes to exclude devices from a scan while they are home
CONF_HOME_INTERVAL = "home_interval"
_LOGGER = logging.getLogger(__name__)
_LEASES_REGEX = re.compile(
r'(?P<ip>([0-9]{1,3}[\.]){3}[0-9]{1,3})' +
r'\smac:\s(?P<mac>([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))')
r'\smac:\s(?P<mac>([0-9a-f]{2}[:-]){5}([0-9a-f]{2}))' +
r'\svalid\sfor:\s(?P<timevalid>(-?\d+))' +
r'\ssec')
# pylint: disable=unused-argument
@@ -40,9 +39,7 @@ def get_scanner(hass, config):
{DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
_LOGGER):
return None
scanner = ActiontecDeviceScanner(config[DOMAIN])
return scanner if scanner.success_init else None
Device = namedtuple("Device", ["mac", "ip", "last_update"])
@@ -58,19 +55,11 @@ class ActiontecDeviceScanner(object):
self.host = config[CONF_HOST]
self.username = config[CONF_USERNAME]
self.password = config[CONF_PASSWORD]
minutes = convert(config.get(CONF_HOME_INTERVAL), int, 0)
self.home_interval = timedelta(minutes=minutes)
self.lock = threading.Lock()
self.last_results = []
# Test the router is accessible
data = self.get_actiontec_data()
self.success_init = data is not None
_LOGGER.info("actiontec scanner initialized")
if self.home_interval:
_LOGGER.info("home_interval set to: %s", self.home_interval)
def scan_devices(self):
"""
@@ -100,27 +89,13 @@ class ActiontecDeviceScanner(object):
return False
with self.lock:
exclude_targets = set()
exclude_target_list = []
now = dt_util.now()
if self.home_interval:
for host in self.last_results:
if host.last_update + self.home_interval > now:
exclude_targets.add(host)
if len(exclude_targets) > 0:
exclude_target_list = [t.ip for t in exclude_targets]
actiontec_data = self.get_actiontec_data()
if not actiontec_data:
return False
self.last_results = []
for client in exclude_target_list:
if client in actiontec_data:
actiontec_data.pop(client)
for name, data in actiontec_data.items():
device = Device(data['mac'], name, now)
self.last_results.append(device)
self.last_results.extend(exclude_targets)
self.last_results = [Device(data['mac'], name, now)
for name, data in actiontec_data.items()
if data['timevalid'] > -60]
_LOGGER.info("actiontec scan successful")
return True
@@ -153,6 +128,7 @@ class ActiontecDeviceScanner(object):
if match is not None:
devices[match.group('ip')] = {
'ip': match.group('ip'),
'mac': match.group('mac').upper()
'mac': match.group('mac').upper(),
'timevalid': int(match.group('timevalid'))
}
return devices
@@ -5,7 +5,7 @@ Device tracker platform that supports scanning a Aruba Access Point for device
presence.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.aruba.html
https://home-assistant.io/components/device_tracker.aruba/
"""
import logging
from datetime import timedelta
@@ -4,32 +4,8 @@ homeassistant.components.device_tracker.asuswrt
Device tracker platform that supports scanning a ASUSWRT router for device
presence.
This device tracker needs telnet to be enabled on the router.
Configuration:
To use the ASUSWRT tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: asuswrt
host: YOUR_ROUTER_IP
username: YOUR_ADMIN_USERNAME
password: YOUR_ADMIN_PASSWORD
Variables:
host
*Required
The IP address of your router, e.g. 192.168.1.1.
username
*Required
The username of an user with administrative privileges, usually 'admin'.
password
*Required
The password for your given admin account.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.asuswrt/
"""
import logging
from datetime import timedelta
@@ -158,13 +134,16 @@ class AsusWrtDeviceScanner(object):
for lease in leases_result:
match = _LEASES_REGEX.search(lease.decode('utf-8'))
if not match:
_LOGGER.warning("Could not parse lease row: %s", lease)
continue
# For leases where the client doesn't set a hostname, ensure
# it is blank and not '*', which breaks the entity_id down
# the line
if match:
host = match.group('host')
if host == '*':
host = ''
host = match.group('host')
if host == '*':
host = ''
devices[match.group('ip')] = {
'host': host,
@@ -175,6 +154,9 @@ class AsusWrtDeviceScanner(object):
for neighbor in neighbors:
match = _IP_NEIGH_REGEX.search(neighbor.decode('utf-8'))
if match and match.group('ip') in devices:
if not match:
_LOGGER.warning("Could not parse neighbor row: %s", neighbor)
continue
if match.group('ip') in devices:
devices[match.group('ip')]['status'] = match.group('status')
return devices
@@ -5,7 +5,7 @@ Device tracker platform that supports scanning a DD-WRT router for device
presence.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.ddwrt.html
https://home-assistant.io/components/device_tracker.ddwrt/
"""
import logging
from datetime import timedelta
@@ -1,7 +1,6 @@
"""
homeassistant.components.device_tracker.demo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo platform for the device tracker.
device_tracker:
@@ -4,9 +4,8 @@ homeassistant.components.device_tracker.geofancy
Geofancy platform for the device tracker.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.geofancy.html
https://home-assistant.io/components/device_tracker.geofancy/
"""
from homeassistant.const import (
HTTP_UNPROCESSABLE_ENTITY, HTTP_INTERNAL_SERVER_ERROR)
@@ -5,7 +5,7 @@ Device tracker platform that supports scanning a OpenWRT router for device
presence.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.luci.html
https://home-assistant.io/components/device_tracker.luci/
"""
import logging
import json
@@ -4,7 +4,7 @@ homeassistant.components.device_tracker.mqtt
MQTT platform for the device tracker.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.mqtt.html
https://home-assistant.io/components/device_tracker.mqtt/
"""
import logging
from homeassistant import util
@@ -5,7 +5,7 @@ Device tracker platform that supports scanning a Netgear router for device
presence.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.netgear.html
https://home-assistant.io/components/device_tracker.netgear/
"""
import logging
from datetime import timedelta
@@ -4,7 +4,7 @@ homeassistant.components.device_tracker.nmap
Device tracker platform that supports scanning a network with nmap.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.nmap_scanner.html
https://home-assistant.io/components/device_tracker.nmap_scanner/
"""
import logging
from datetime import timedelta
@@ -98,7 +98,7 @@ class NmapDeviceScanner(object):
from nmap import PortScanner, PortScannerError
scanner = PortScanner()
options = "-F --host-timeout 5"
options = "-F --host-timeout 5s"
if self.home_interval:
boundary = dt_util.now() - self.home_interval
@@ -4,7 +4,7 @@ homeassistant.components.device_tracker.owntracks
OwnTracks platform for the device tracker.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.owntracks.html
https://home-assistant.io/components/device_tracker.owntracks/
"""
import json
import logging
@@ -5,7 +5,7 @@ Device tracker platform that supports fetching WiFi associations
through SNMP.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.snmp.html
https://home-assistant.io/components/device_tracker.snmp/
"""
import logging
from datetime import timedelta
@@ -45,9 +45,12 @@ class SnmpScanner(object):
This class queries any SNMP capable Acces Point for connected devices.
"""
def __init__(self, config):
self.host = config[CONF_HOST]
self.community = config[CONF_COMMUNITY]
self.baseoid = config[CONF_BASEOID]
from pysnmp.entity.rfc3413.oneliner import cmdgen
self.snmp = cmdgen.CommandGenerator()
self.host = cmdgen.UdpTransportTarget((config[CONF_HOST], 161))
self.community = cmdgen.CommunityData(config[CONF_COMMUNITY])
self.baseoid = cmdgen.MibVariable(config[CONF_BASEOID])
self.lock = threading.Lock()
@@ -91,16 +94,11 @@ class SnmpScanner(object):
def get_snmp_data(self):
""" Fetch mac addresses from WAP via SNMP. """
from pysnmp.entity.rfc3413.oneliner import cmdgen
devices = []
snmp = cmdgen.CommandGenerator()
errindication, errstatus, errindex, restable = snmp.nextCmd(
cmdgen.CommunityData(self.community),
cmdgen.UdpTransportTarget((self.host, 161)),
cmdgen.MibVariable(self.baseoid)
)
errindication, errstatus, errindex, restable = self.snmp.nextCmd(
self.community, self.host, self.baseoid)
if errindication:
_LOGGER.error("SNMPLIB error: %s", errindication)
@@ -5,7 +5,7 @@ Device tracker platform that supports scanning a THOMSON router for device
presence.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.thomson.html
https://home-assistant.io/components/device_tracker.thomson/
"""
import logging
from datetime import timedelta
@@ -5,7 +5,7 @@ Device tracker platform that supports scanning a Tomato router for device
presence.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.tomato.html
https://home-assistant.io/components/device_tracker.tomato/
"""
import logging
import json
@@ -5,7 +5,7 @@ Device tracker platform that supports scanning a TP-Link router for device
presence.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.tplink.html
https://home-assistant.io/components/device_tracker.tplink/
"""
import base64
import logging
@@ -5,7 +5,7 @@ Device tracker platform that supports scanning a OpenWRT router for device
presence.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.ubus.html
https://home-assistant.io/components/device_tracker.ubus/
"""
import logging
import json
+1 -3
View File
@@ -1,7 +1,6 @@
"""
homeassistant.components.discovery
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Starts a service to scan in intervals for new devices.
Will emit EVENT_PLATFORM_DISCOVERED whenever a new service has been discovered.
@@ -18,8 +17,7 @@ from homeassistant.const import (
ATTR_SERVICE, ATTR_DISCOVERED)
DOMAIN = "discovery"
DEPENDENCIES = []
REQUIREMENTS = ['netdisco==0.5.1']
REQUIREMENTS = ['netdisco==0.5.2']
SCAN_INTERVAL = 300 # seconds
+1 -2
View File
@@ -4,7 +4,7 @@ homeassistant.components.downloader
Provides functionality to download files.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/downloader.html
https://home-assistant.io/components/downloader/
"""
import os
import logging
@@ -15,7 +15,6 @@ from homeassistant.helpers import validate_config
from homeassistant.util import sanitize_filename
DOMAIN = "downloader"
DEPENDENCIES = []
SERVICE_DOWNLOAD_FILE = "download_file"
+155
View File
@@ -0,0 +1,155 @@
"""
homeassistant.components.ecobee
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ecobee Component
This component adds support for Ecobee3 Wireless Thermostats.
You will need to setup developer access to your thermostat,
and create and API key on the ecobee website.
The first time you run this component you will see a configuration
component card in Home Assistant. This card will contain a PIN code
that you will need to use to authorize access to your thermostat. You
can do this at https://www.ecobee.com/consumerportal/index.html
Click My Apps, Add application, Enter Pin and click Authorize.
After authorizing the application click the button in the configuration
card. Now your thermostat and sensors should shown in home-assistant.
You can use the optional hold_temp parameter to set whether or not holds
are set indefintely or until the next scheduled event.
ecobee:
api_key: asdfasdfasdfasdfasdfaasdfasdfasdfasdf
hold_temp: True
"""
from datetime import timedelta
import logging
import os
from homeassistant.loader import get_component
from homeassistant import bootstrap
from homeassistant.util import Throttle
from homeassistant.const import (
EVENT_PLATFORM_DISCOVERED, ATTR_SERVICE, ATTR_DISCOVERED, CONF_API_KEY)
DOMAIN = "ecobee"
DISCOVER_THERMOSTAT = "ecobee.thermostat"
DISCOVER_SENSORS = "ecobee.sensor"
NETWORK = None
HOLD_TEMP = 'hold_temp'
REQUIREMENTS = [
'https://github.com/nkgilley/python-ecobee-api/archive/'
'92a2f330cbaf601d0618456fdd97e5a8c42c1c47.zip#python-ecobee==0.0.4']
_LOGGER = logging.getLogger(__name__)
ECOBEE_CONFIG_FILE = 'ecobee.conf'
_CONFIGURING = {}
# Return cached results if last scan was less then this time ago
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=180)
def request_configuration(network, hass, config):
""" Request configuration steps from the user. """
configurator = get_component('configurator')
if 'ecobee' in _CONFIGURING:
configurator.notify_errors(
_CONFIGURING['ecobee'], "Failed to register, please try again.")
return
# pylint: disable=unused-argument
def ecobee_configuration_callback(callback_data):
""" Actions to do when our configuration callback is called. """
network.request_tokens()
network.update()
setup_ecobee(hass, network, config)
_CONFIGURING['ecobee'] = configurator.request_config(
hass, "Ecobee", ecobee_configuration_callback,
description=(
'Please authorize this app at https://www.ecobee.com/consumer'
'portal/index.html with pin code: ' + network.pin),
description_image="/static/images/config_ecobee_thermostat.png",
submit_caption="I have authorized the app."
)
def setup_ecobee(hass, network, config):
""" Setup ecobee thermostat """
# If ecobee has a PIN then it needs to be configured.
if network.pin is not None:
request_configuration(network, hass, config)
return
if 'ecobee' in _CONFIGURING:
configurator = get_component('configurator')
configurator.request_done(_CONFIGURING.pop('ecobee'))
# Ensure component is loaded
bootstrap.setup_component(hass, 'thermostat', config)
bootstrap.setup_component(hass, 'sensor', config)
hold_temp = config[DOMAIN].get(HOLD_TEMP, False)
# Fire thermostat discovery event
hass.bus.fire(EVENT_PLATFORM_DISCOVERED, {
ATTR_SERVICE: DISCOVER_THERMOSTAT,
ATTR_DISCOVERED: {'hold_temp': hold_temp}
})
# Fire sensor discovery event
hass.bus.fire(EVENT_PLATFORM_DISCOVERED, {
ATTR_SERVICE: DISCOVER_SENSORS,
ATTR_DISCOVERED: {}
})
# pylint: disable=too-few-public-methods
class EcobeeData(object):
""" Gets the latest data and update the states. """
def __init__(self, config_file):
from pyecobee import Ecobee
self.ecobee = Ecobee(config_file)
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
""" Get the latest data from pyecobee. """
self.ecobee.update()
_LOGGER.info("ecobee data updated successfully.")
def setup(hass, config):
"""
Setup Ecobee.
Will automatically load thermostat and sensor components to support
devices discovered on the network.
"""
# pylint: disable=global-statement, import-error
global NETWORK
if 'ecobee' in _CONFIGURING:
return
from pyecobee import config_from_file
# Create ecobee.conf if it doesn't exist
if not os.path.isfile(hass.config.path(ECOBEE_CONFIG_FILE)):
if config[DOMAIN].get(CONF_API_KEY) is None:
_LOGGER.error("No ecobee api_key found in config.")
return
jsonconfig = {"API_KEY": config[DOMAIN].get(CONF_API_KEY)}
config_from_file(hass.config.path(ECOBEE_CONFIG_FILE), jsonconfig)
NETWORK = EcobeeData(hass.config.path(ECOBEE_CONFIG_FILE))
setup_ecobee(hass, NETWORK.ecobee, config)
return True
+11 -8
View File
@@ -8,7 +8,7 @@ import re
import os
import logging
from . import version
from . import version, mdi_version
import homeassistant.util as util
from homeassistant.const import URL_ROOT, HTTP_OK
from homeassistant.config import get_default_config_dir
@@ -22,9 +22,11 @@ _LOGGER = logging.getLogger(__name__)
FRONTEND_URLS = [
URL_ROOT, '/logbook', '/history', '/map', '/devService', '/devState',
'/devEvent']
'/devEvent', '/devInfo']
STATES_URL = re.compile(r'/states(/([a-zA-Z\._\-0-9/]+)|)')
_FINGERPRINT = re.compile(r'^(\w+)-[a-z0-9]{32}\.(\w+)$', re.IGNORECASE)
def setup(hass, config):
""" Setup serving the frontend. """
@@ -52,8 +54,7 @@ def setup(hass, config):
def _handle_get_root(handler, path_match, data):
""" Renders the debug interface. """
""" Renders the frontend. """
handler.send_response(HTTP_OK)
handler.send_header('Content-type', 'text/html; charset=utf-8')
handler.end_headers()
@@ -64,7 +65,7 @@ def _handle_get_root(handler, path_match, data):
app_url = "frontend-{}.html".format(version.VERSION)
# auto login if no password was set, else check api_password param
auth = ('no_password_set' if handler.server.no_password_set
auth = ('no_password_set' if handler.server.api_password is None
else data.get('api_password', ''))
with open(INDEX_PATH) as template_file:
@@ -72,6 +73,7 @@ def _handle_get_root(handler, path_match, data):
template_html = template_html.replace('{{ app_url }}', app_url)
template_html = template_html.replace('{{ auth }}', auth)
template_html = template_html.replace('{{ icons }}', mdi_version.VERSION)
handler.wfile.write(template_html.encode("UTF-8"))
@@ -80,9 +82,10 @@ def _handle_get_static(handler, path_match, data):
""" Returns a static file for the frontend. """
req_file = util.sanitize_path(path_match.group('file'))
# Strip md5 hash out of frontend filename
if re.match(r'^frontend-[A-Za-z0-9]{32}\.html$', req_file):
req_file = "frontend.html"
# Strip md5 hash out
fingerprinted = _FINGERPRINT.match(req_file)
if fingerprinted:
req_file = "{}.{}".format(*fingerprinted.groups())
path = os.path.join(os.path.dirname(__file__), 'www_static', req_file)
@@ -4,16 +4,13 @@
<meta charset="utf-8">
<title>Home Assistant</title>
<link rel='manifest' href='/static/manifest.json' />
<link rel='shortcut icon' href='/static/favicon.ico' />
<link rel='icon' type='image/png'
href='/static/favicon-192x192.png' sizes='192x192'>
<link rel='manifest' href='/static/manifest.json'>
<link rel='icon' href='/static/favicon.ico'>
<link rel='apple-touch-icon' sizes='180x180'
href='/static/favicon-apple-180x180.png'>
href='/static/favicon-apple-180x180.png'>
<meta name='apple-mobile-web-app-capable' content='yes'>
<meta name='mobile-web-app-capable' content='yes'>
<meta name='viewport' content='width=device-width,
user-scalable=no' />
<meta name='viewport' content='width=device-width, user-scalable=no'>
<meta name='theme-color' content='#03a9f4'>
<style>
#init {
@@ -26,26 +23,19 @@
justify-content: center;
align-items: center;
text-align: center;
font-family: 'Roboto', 'Noto', sans-serif;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
#init div {
line-height: 34px;
margin-bottom: 89px;
margin-bottom: 123px;
}
</style>
</head>
<body fullbleed>
<div id='init'>
<img src='/static/splash.png' height='230' />
<div>Initializing</div>
</div>
<div id='init'><img src='/static/favicon-192x192.png' height='192'></div>
<script src='/static/webcomponents-lite.min.js'></script>
<link rel='import' href='/static/{{ app_url }}' />
<home-assistant auth='{{ auth }}'></home-assistant>
<home-assistant auth='{{ auth }}' icons='{{ icons }}'></home-assistant>
</body>
</html>
@@ -0,0 +1,2 @@
""" DO NOT MODIFY. Auto-generated by update_mdi script """
VERSION = "7d76081c37634d36af21f5cc1ca79408"
+1 -1
View File
@@ -1,2 +1,2 @@
""" DO NOT MODIFY. Auto-generated by build_frontend script """
VERSION = "beb922c55bb26ea576581b453f6d7c04"
VERSION = "8470cd10f28b20eae9022fa4c8f40c1b"
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

@@ -3,12 +3,17 @@
"short_name": "Assistant",
"start_url": "/",
"display": "standalone",
"theme_color": "#03A9F4",
"icons": [
{
"src": "\/static\/favicon-192x192.png",
"src": "/static/favicon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
"type": "image/png",
},
{
"src": "/static/favicon-384x384.png",
"sizes": "384x384",
"type": "image/png",
}
]
}
File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

File diff suppressed because one or more lines are too long
+1 -2
View File
@@ -4,7 +4,7 @@ homeassistant.components.group
Provides functionality to group devices that can be turned on or off.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/group.html
https://home-assistant.io/components/group/
"""
import homeassistant.core as ha
from homeassistant.helpers import generate_entity_id
@@ -17,7 +17,6 @@ from homeassistant.const import (
STATE_UNKNOWN)
DOMAIN = "group"
DEPENDENCIES = []
ENTITY_ID_FORMAT = DOMAIN + ".{}"
+1 -1
View File
@@ -4,7 +4,7 @@ homeassistant.components.history
Provide pre-made queries on top of the recorder component.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/history.html
https://home-assistant.io/components/history/
"""
import re
from datetime import timedelta
+117 -136
View File
@@ -4,7 +4,7 @@ homeassistant.components.http
This module provides an API and a HTTP interface for debug purposes.
For more details about the RESTful API, please refer to the documentation at
https://home-assistant.io/developers/api.html
https://home-assistant.io/developers/api/
"""
import json
import threading
@@ -12,10 +12,7 @@ import logging
import time
import gzip
import os
import random
import string
from datetime import timedelta
from homeassistant.util import Throttle
from http.server import SimpleHTTPRequestHandler, HTTPServer
from http import cookies
from socketserver import ThreadingMixIn
@@ -34,51 +31,39 @@ import homeassistant.util.dt as date_util
import homeassistant.bootstrap as bootstrap
DOMAIN = "http"
DEPENDENCIES = []
CONF_API_PASSWORD = "api_password"
CONF_SERVER_HOST = "server_host"
CONF_SERVER_PORT = "server_port"
CONF_DEVELOPMENT = "development"
CONF_SESSIONS_ENABLED = "sessions_enabled"
DATA_API_PASSWORD = 'api_password'
# Throttling time in seconds for expired sessions check
MIN_SEC_SESSION_CLEARING = timedelta(seconds=20)
SESSION_CLEAR_INTERVAL = timedelta(seconds=20)
SESSION_TIMEOUT_SECONDS = 1800
SESSION_KEY = 'sessionId'
_LOGGER = logging.getLogger(__name__)
def setup(hass, config=None):
def setup(hass, config):
""" Sets up the HTTP API and debug interface. """
if config is None or DOMAIN not in config:
config = {DOMAIN: {}}
conf = config.get(DOMAIN, {})
api_password = util.convert(config[DOMAIN].get(CONF_API_PASSWORD), str)
no_password_set = api_password is None
if no_password_set:
api_password = util.get_random_string()
api_password = util.convert(conf.get(CONF_API_PASSWORD), str)
# If no server host is given, accept all incoming requests
server_host = config[DOMAIN].get(CONF_SERVER_HOST, '0.0.0.0')
server_port = config[DOMAIN].get(CONF_SERVER_PORT, SERVER_PORT)
development = str(config[DOMAIN].get(CONF_DEVELOPMENT, "")) == "1"
sessions_enabled = config[DOMAIN].get(CONF_SESSIONS_ENABLED, True)
server_host = conf.get(CONF_SERVER_HOST, '0.0.0.0')
server_port = conf.get(CONF_SERVER_PORT, SERVER_PORT)
development = str(conf.get(CONF_DEVELOPMENT, "")) == "1"
try:
server = HomeAssistantHTTPServer(
(server_host, server_port), RequestHandler, hass, api_password,
development, no_password_set, sessions_enabled)
development)
except OSError:
# Happens if address already in use
# If address already in use
_LOGGER.exception("Error setting up HTTP server")
return False
@@ -103,17 +88,15 @@ class HomeAssistantHTTPServer(ThreadingMixIn, HTTPServer):
# pylint: disable=too-many-arguments
def __init__(self, server_address, request_handler_class,
hass, api_password, development, no_password_set,
sessions_enabled):
hass, api_password, development):
super().__init__(server_address, request_handler_class)
self.server_address = server_address
self.hass = hass
self.api_password = api_password
self.development = development
self.no_password_set = no_password_set
self.paths = []
self.sessions = SessionStore(sessions_enabled)
self.sessions = SessionStore()
# We will lazy init this one if needed
self.event_forwarder = None
@@ -162,12 +145,13 @@ class RequestHandler(SimpleHTTPRequestHandler):
def __init__(self, req, client_addr, server):
""" Contructor, call the base constructor and set up session """
self._session = None
# Track if this was an authenticated request
self.authenticated = False
SimpleHTTPRequestHandler.__init__(self, req, client_addr, server)
def log_message(self, fmt, *arguments):
""" Redirect built-in log to HA logging """
if self.server.no_password_set:
if self.server.api_password is None:
_LOGGER.info(fmt, *arguments)
else:
_LOGGER.info(
@@ -202,18 +186,17 @@ class RequestHandler(SimpleHTTPRequestHandler):
"Error parsing JSON", HTTP_UNPROCESSABLE_ENTITY)
return
self._session = self.get_session()
if self.server.no_password_set:
api_password = self.server.api_password
else:
if self.server.api_password is None:
self.authenticated = True
elif HTTP_HEADER_HA_AUTH in self.headers:
api_password = self.headers.get(HTTP_HEADER_HA_AUTH)
if not api_password and DATA_API_PASSWORD in data:
api_password = data[DATA_API_PASSWORD]
if not api_password and self._session is not None:
api_password = self._session.cookie_values.get(
CONF_API_PASSWORD)
self.authenticated = api_password == self.server.api_password
else:
self.authenticated = self.verify_session()
if '_METHOD' in data:
method = data.pop('_METHOD')
@@ -246,18 +229,13 @@ class RequestHandler(SimpleHTTPRequestHandler):
# Did we find a handler for the incoming request?
if handle_request_method:
# For some calls we need a valid password
if require_auth and api_password != self.server.api_password:
if require_auth and not self.authenticated:
self.write_json_message(
"API password missing or incorrect.", HTTP_UNAUTHORIZED)
return
else:
if self._session is None and require_auth:
self._session = self.server.sessions.create(
api_password)
handle_request_method(self, path_match, data)
handle_request_method(self, path_match, data)
elif path_matched_but_not_method:
self.send_response(HTTP_METHOD_NOT_ALLOWED)
@@ -308,18 +286,19 @@ class RequestHandler(SimpleHTTPRequestHandler):
json.dumps(data, indent=4, sort_keys=True,
cls=rem.JSONEncoder).encode("UTF-8"))
def write_file(self, path):
def write_file(self, path, cache_headers=True):
""" Returns a file to the user. """
try:
with open(path, 'rb') as inp:
self.write_file_pointer(self.guess_type(path), inp)
self.write_file_pointer(self.guess_type(path), inp,
cache_headers)
except IOError:
self.send_response(HTTP_NOT_FOUND)
self.end_headers()
_LOGGER.exception("Unable to serve %s", path)
def write_file_pointer(self, content_type, inp):
def write_file_pointer(self, content_type, inp, cache_headers=True):
"""
Helper function to write a file pointer to the user.
Does not do error handling.
@@ -329,7 +308,8 @@ class RequestHandler(SimpleHTTPRequestHandler):
self.send_response(HTTP_OK)
self.send_header(HTTP_HEADER_CONTENT_TYPE, content_type)
self.set_cache_header()
if cache_headers:
self.set_cache_header()
self.set_session_cookie_header()
if do_gzip:
@@ -356,75 +336,81 @@ class RequestHandler(SimpleHTTPRequestHandler):
def set_cache_header(self):
""" Add cache headers if not in development """
if not self.server.development:
# 1 year in seconds
cache_time = 365 * 86400
if self.server.development:
return
self.send_header(
HTTP_HEADER_CACHE_CONTROL,
"public, max-age={}".format(cache_time))
self.send_header(
HTTP_HEADER_EXPIRES,
self.date_time_string(time.time()+cache_time))
# 1 year in seconds
cache_time = 365 * 86400
self.send_header(
HTTP_HEADER_CACHE_CONTROL,
"public, max-age={}".format(cache_time))
self.send_header(
HTTP_HEADER_EXPIRES,
self.date_time_string(time.time()+cache_time))
def set_session_cookie_header(self):
""" Add the header for the session cookie """
if self.server.sessions.enabled and self._session is not None:
existing_sess_id = self.get_current_session_id()
""" Add the header for the session cookie and return session id. """
if not self.authenticated:
return
if existing_sess_id != self._session.session_id:
self.send_header(
'Set-Cookie',
SESSION_KEY+'='+self._session.session_id)
session_id = self.get_cookie_session_id()
def get_session(self):
""" Get the requested session object from cookie value """
if self.server.sessions.enabled is not True:
return None
session_id = self.get_current_session_id()
if session_id is not None:
session = self.server.sessions.get(session_id)
if session is not None:
session.reset_expiry()
return session
self.server.sessions.extend_validation(session_id)
return
return None
self.send_header(
'Set-Cookie',
'{}={}'.format(SESSION_KEY, self.server.sessions.create())
)
def get_current_session_id(self):
return session_id
def verify_session(self):
""" Verify that we are in a valid session. """
return self.get_cookie_session_id() is not None
def get_cookie_session_id(self):
"""
Extracts the current session id from the
cookie or returns None if not set
cookie or returns None if not set or invalid
"""
if 'Cookie' not in self.headers:
return None
cookie = cookies.SimpleCookie()
try:
cookie.load(self.headers["Cookie"])
except cookies.CookieError:
return None
if self.headers.get('Cookie', None) is not None:
cookie.load(self.headers.get("Cookie"))
morsel = cookie.get(SESSION_KEY)
if cookie.get(SESSION_KEY, False):
return cookie[SESSION_KEY].value
if morsel is None:
return None
session_id = cookie[SESSION_KEY].value
if self.server.sessions.is_valid(session_id):
return session_id
return None
def destroy_session(self):
""" Destroys session. """
session_id = self.get_cookie_session_id()
class ServerSession:
""" A very simple session class """
def __init__(self, session_id):
""" Set up the expiry time on creation """
self._expiry = 0
self.reset_expiry()
self.cookie_values = {}
self.session_id = session_id
if session_id is None:
return
def reset_expiry(self):
""" Resets the expiry based on current time """
self._expiry = date_util.utcnow() + timedelta(
seconds=SESSION_TIMEOUT_SECONDS)
self.send_header('Set-Cookie', '')
self.server.sessions.destroy(session_id)
@property
def is_expired(self):
""" Return true if the session is expired based on the expiry time """
return self._expiry < date_util.utcnow()
def session_valid_time():
""" Time till when a session will be valid. """
return date_util.utcnow() + timedelta(seconds=SESSION_TIMEOUT_SECONDS)
class SessionStore(object):
@@ -432,47 +418,42 @@ class SessionStore(object):
def __init__(self, enabled=True):
""" Set up the session store """
self._sessions = {}
self.enabled = enabled
self.session_lock = threading.RLock()
self.lock = threading.RLock()
@Throttle(MIN_SEC_SESSION_CLEARING)
def remove_expired(self):
@util.Throttle(SESSION_CLEAR_INTERVAL)
def _remove_expired(self):
""" Remove any expired sessions. """
if self.session_lock.acquire(False):
try:
keys = []
for key in self._sessions.keys():
keys.append(key)
now = date_util.utcnow()
for key in [key for key, valid_time in self._sessions.items()
if valid_time < now]:
self._sessions.pop(key)
for key in keys:
if self._sessions[key].is_expired:
del self._sessions[key]
_LOGGER.info("Cleared expired session %s", key)
finally:
self.session_lock.release()
def is_valid(self, key):
""" Return True if a valid session is given. """
with self.lock:
self._remove_expired()
def add(self, key, session):
""" Add a new session to the list of tracked sessions """
self.remove_expired()
with self.session_lock:
self._sessions[key] = session
return (key in self._sessions and
self._sessions[key] > date_util.utcnow())
def get(self, key):
""" get a session by key """
self.remove_expired()
session = self._sessions.get(key, None)
if session is not None and session.is_expired:
return None
return session
def extend_validation(self, key):
""" Extend a session validation time. """
with self.lock:
self._sessions[key] = session_valid_time()
def create(self, api_password):
""" Creates a new session and adds it to the sessions """
if self.enabled is not True:
return None
def destroy(self, key):
""" Destroy a session by key. """
with self.lock:
self._sessions.pop(key, None)
chars = string.ascii_letters + string.digits
session_id = ''.join([random.choice(chars) for i in range(20)])
session = ServerSession(session_id)
session.cookie_values[CONF_API_PASSWORD] = api_password
self.add(session_id, session)
return session
def create(self):
""" Creates a new session. """
with self.lock:
session_id = util.get_random_string(20)
while session_id in self._sessions:
session_id = util.get_random_string(20)
self._sessions[session_id] = session_valid_time()
return session_id
+3 -5
View File
@@ -4,7 +4,7 @@ homeassistant.components.ifttt
This component enable you to trigger Maker IFTTT recipes.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/ifttt.html
https://home-assistant.io/components/ifttt/
"""
import logging
import requests
@@ -22,13 +22,11 @@ ATTR_VALUE1 = 'value1'
ATTR_VALUE2 = 'value2'
ATTR_VALUE3 = 'value3'
DEPENDENCIES = []
REQUIREMENTS = ['pyfttt==0.3']
def trigger(hass, event, value1=None, value2=None, value3=None):
""" Trigger a Maker IFTTT recipe """
""" Trigger a Maker IFTTT recipe. """
data = {
ATTR_EVENT: event,
ATTR_VALUE1: value1,
@@ -39,7 +37,7 @@ def trigger(hass, event, value1=None, value2=None, value3=None):
def setup(hass, config):
""" Setup the ifttt service component """
""" Setup the ifttt service component. """
if not validate_config(config, {DOMAIN: ['key']}, _LOGGER):
return False
+113
View File
@@ -0,0 +1,113 @@
"""
homeassistant.components.influx
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
InfluxDB component which allows you to send data to an Influx database.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/influx/
Configuration:
influx:
host: localhost
port: 8086
dbname: home_assistant
dbuser: DB_USER
dbuser_password: DB_USER_PASSWORD
"""
import logging
import homeassistant.util as util
from homeassistant.helpers import validate_config
from homeassistant.const import (EVENT_STATE_CHANGED, STATE_ON, STATE_OFF,
STATE_UNLOCKED, STATE_LOCKED, STATE_UNKNOWN)
from homeassistant.components.sun import (STATE_ABOVE_HORIZON,
STATE_BELOW_HORIZON)
_LOGGER = logging.getLogger(__name__)
DOMAIN = "influx"
DEPENDENCIES = []
DEFAULT_HOST = 'localhost'
DEFAULT_PORT = 8086
DEFAULT_DATABASE = 'home_assistant'
REQUIREMENTS = ['influxdb==2.10.0']
CONF_HOST = 'host'
CONF_PORT = 'port'
CONF_DB_NAME = 'database'
CONF_USERNAME = 'username'
CONF_PASSWORD = 'password'
def setup(hass, config):
""" Setup the Influx component. """
from influxdb import InfluxDBClient, exceptions
if not validate_config(config, {DOMAIN: ['host']}, _LOGGER):
return False
conf = config[DOMAIN]
host = conf[CONF_HOST]
port = util.convert(conf.get(CONF_PORT), int, DEFAULT_PORT)
dbname = util.convert(conf.get(CONF_DB_NAME), str, DEFAULT_DATABASE)
username = util.convert(conf.get(CONF_USERNAME), str)
password = util.convert(conf.get(CONF_PASSWORD), str)
try:
influx = InfluxDBClient(host=host, port=port, username=username,
password=password, database=dbname)
databases = [i['name'] for i in influx.get_list_database()]
except exceptions.InfluxDBClientError:
_LOGGER.error("Database host is not accessible. "
"Please check your entries in the configuration file.")
return False
if dbname not in databases:
_LOGGER.error("Database %s doesn't exist", dbname)
return False
def influx_event_listener(event):
""" Listen for new messages on the bus and sends them to Influx. """
state = event.data.get('new_state')
if state is None:
return
if state.state in (STATE_ON, STATE_LOCKED, STATE_ABOVE_HORIZON):
_state = 1
elif state.state in (STATE_OFF, STATE_UNLOCKED, STATE_UNKNOWN,
STATE_BELOW_HORIZON):
_state = 0
else:
_state = state.state
measurement = state.attributes.get('unit_of_measurement', state.domain)
json_body = [
{
'measurement': measurement,
'tags': {
'domain': state.domain,
'entity_id': state.object_id,
},
'time': event.time_fired,
'fields': {
'value': _state,
}
}
]
try:
influx.write_points(json_body)
except exceptions.InfluxDBClientError:
_LOGGER.exception('Error saving event to Influx')
hass.bus.listen(EVENT_STATE_CHANGED, influx_event_listener)
return True
+3 -4
View File
@@ -4,12 +4,11 @@ homeassistant.components.introduction
Component that will help guide the user taking its first steps.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/introduction.html
https://home-assistant.io/components/introduction/
"""
import logging
DOMAIN = 'introduction'
DEPENDENCIES = []
def setup(hass, config=None):
@@ -26,13 +25,13 @@ def setup(hass, config=None):
Here are some resources to get started:
- Configuring Home Assistant:
https://home-assistant.io/getting-started/configuration.html
https://home-assistant.io/getting-started/configuration/
- Available components:
https://home-assistant.io/components/
- Troubleshooting your configuration:
https://home-assistant.io/getting-started/troubleshooting-configuration.html
https://home-assistant.io/getting-started/troubleshooting-configuration/
- Getting help:
https://home-assistant.io/help/
+6 -3
View File
@@ -5,7 +5,7 @@ Connects to an ISY-994 controller and loads relevant components to control its
devices. Also contains the base classes for ISY Sensors, Lights, and Switches.
For configuration details please visit the documentation for this component at
https://home-assistant.io/components/isy994.html
https://home-assistant.io/components/isy994/
"""
import logging
from urllib.parse import urlparse
@@ -20,7 +20,6 @@ from homeassistant.const import (
ATTR_FRIENDLY_NAME)
DOMAIN = "isy994"
DEPENDENCIES = []
REQUIREMENTS = ['PyISY==1.0.5']
DISCOVER_LIGHTS = "isy994.lights"
DISCOVER_SWITCHES = "isy994.switches"
@@ -117,7 +116,6 @@ class ISYDeviceABC(ToggleEntity):
def __init__(self, node):
# setup properties
self.node = node
self.hidden = HIDDEN_STRING in self.raw_name
# track changes
self._change_handler = self.node.status. \
@@ -182,6 +180,11 @@ class ISYDeviceABC(ToggleEntity):
return self.raw_name.replace(HIDDEN_STRING, '').strip() \
.replace('_', ' ')
@property
def hidden(self):
""" Suggestion if the entity should be hidden from UIs. """
return HIDDEN_STRING in self.raw_name
def update(self):
""" Update state of the sensor. """
# ISY objects are automatically updated by the ISY's event stream
+1 -2
View File
@@ -4,7 +4,7 @@ homeassistant.components.keyboard
Provides functionality to emulate keyboard presses on host machine.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/keyboard.html
https://home-assistant.io/components/keyboard/
"""
import logging
@@ -15,7 +15,6 @@ from homeassistant.const import (
DOMAIN = "keyboard"
DEPENDENCIES = []
REQUIREMENTS = ['pyuserinput==0.1.9']
+43 -64
View File
@@ -1,58 +1,16 @@
"""
homeassistant.components.light
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to interact with lights.
It offers the following services:
TURN_OFF - Turns one or multiple lights off.
Supports following parameters:
- transition
Integer that represents the time the light should take to transition to
the new state.
- entity_id
String or list of strings that point at entity_ids of lights.
TURN_ON - Turns one or multiple lights on and change attributes.
Supports following parameters:
- transition
Integer that represents the time the light should take to transition to
the new state.
- entity_id
String or list of strings that point at entity_ids of lights.
- profile
String with the name of one of the built-in profiles (relax, energize,
concentrate, reading) or one of the custom profiles defined in
light_profiles.csv in the current working directory.
Light profiles define a xy color and a brightness.
If a profile is given and a brightness or xy color then the profile values
will be overwritten.
- xy_color
A list containing two floats representing the xy color you want the light
to be.
- rgb_color
A list containing three integers representing the xy color you want the
light to be.
- brightness
Integer between 0 and 255 representing how bright you want the light to be.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/light/
"""
import logging
import os
import csv
from homeassistant.components import group, discovery, wink, isy994
from homeassistant.components import group, discovery, wink, isy994, zwave
from homeassistant.config import load_yaml_config_file
from homeassistant.const import (
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
@@ -63,7 +21,6 @@ import homeassistant.util.color as color_util
DOMAIN = "light"
DEPENDENCIES = []
SCAN_INTERVAL = 30
GROUP_NAME_ALL_LIGHTS = 'all lights'
@@ -77,6 +34,7 @@ ATTR_TRANSITION = "transition"
# lists holding color values
ATTR_RGB_COLOR = "rgb_color"
ATTR_XY_COLOR = "xy_color"
ATTR_COLOR_TEMP = "color_temp"
# int with value 0 .. 255 representing brightness of the light
ATTR_BRIGHTNESS = "brightness"
@@ -92,6 +50,7 @@ FLASH_LONG = "long"
# Apply an effect to the light, can be EFFECT_COLORLOOP
ATTR_EFFECT = "effect"
EFFECT_COLORLOOP = "colorloop"
EFFECT_WHITE = "white"
LIGHT_PROFILES_FILE = "light_profiles.csv"
@@ -100,11 +59,14 @@ DISCOVERY_PLATFORMS = {
wink.DISCOVER_LIGHTS: 'wink',
isy994.DISCOVER_LIGHTS: 'isy994',
discovery.SERVICE_HUE: 'hue',
zwave.DISCOVER_LIGHTS: 'zwave',
}
PROP_TO_ATTR = {
'brightness': ATTR_BRIGHTNESS,
'color_xy': ATTR_XY_COLOR,
'color_temp': ATTR_COLOR_TEMP,
'rgb_color': ATTR_RGB_COLOR,
'xy_color': ATTR_XY_COLOR,
}
_LOGGER = logging.getLogger(__name__)
@@ -119,8 +81,8 @@ def is_on(hass, entity_id=None):
# pylint: disable=too-many-arguments
def turn_on(hass, entity_id=None, transition=None, brightness=None,
rgb_color=None, xy_color=None, profile=None, flash=None,
effect=None):
rgb_color=None, xy_color=None, color_temp=None, profile=None,
flash=None, effect=None):
""" Turns all or specified light on. """
data = {
key: value for key, value in [
@@ -130,6 +92,7 @@ def turn_on(hass, entity_id=None, transition=None, brightness=None,
(ATTR_BRIGHTNESS, brightness),
(ATTR_RGB_COLOR, rgb_color),
(ATTR_XY_COLOR, xy_color),
(ATTR_COLOR_TEMP, color_temp),
(ATTR_FLASH, flash),
(ATTR_EFFECT, effect),
] if value is not None
@@ -150,7 +113,7 @@ def turn_off(hass, entity_id=None, transition=None):
hass.services.call(DOMAIN, SERVICE_TURN_OFF, data)
# pylint: disable=too-many-branches, too-many-locals
# pylint: disable=too-many-branches, too-many-locals, too-many-statements
def setup(hass, config):
""" Exposes light control via statemachine and services. """
@@ -240,6 +203,15 @@ def setup(hass, config):
# ValueError if value could not be converted to float
pass
if ATTR_COLOR_TEMP in dat:
# color_temp should be an int of mirads value
colortemp = dat.get(ATTR_COLOR_TEMP)
# Without this check, a ctcolor with value '99' would work
# These values are based on Philips Hue, may need ajustment later
if isinstance(colortemp, int) and 154 <= colortemp <= 500:
params[ATTR_COLOR_TEMP] = colortemp
if ATTR_RGB_COLOR in dat:
try:
# rgb_color should be a list containing 3 ints
@@ -247,26 +219,17 @@ def setup(hass, config):
if len(rgb_color) == 3:
params[ATTR_RGB_COLOR] = [int(val) for val in rgb_color]
params[ATTR_XY_COLOR] = \
color_util.color_RGB_to_xy(int(rgb_color[0]),
int(rgb_color[1]),
int(rgb_color[2]))
except (TypeError, ValueError):
# TypeError if rgb_color is not iterable
# ValueError if not all values can be converted to int
pass
if ATTR_FLASH in dat:
if dat[ATTR_FLASH] == FLASH_SHORT:
params[ATTR_FLASH] = FLASH_SHORT
if dat.get(ATTR_FLASH) in (FLASH_SHORT, FLASH_LONG):
params[ATTR_FLASH] = dat[ATTR_FLASH]
elif dat[ATTR_FLASH] == FLASH_LONG:
params[ATTR_FLASH] = FLASH_LONG
if ATTR_EFFECT in dat:
if dat[ATTR_EFFECT] == EFFECT_COLORLOOP:
params[ATTR_EFFECT] = EFFECT_COLORLOOP
if dat.get(ATTR_EFFECT) in (EFFECT_COLORLOOP, EFFECT_WHITE):
params[ATTR_EFFECT] = dat[ATTR_EFFECT]
for light in target_lights:
light.turn_on(**params)
@@ -297,10 +260,20 @@ class Light(ToggleEntity):
return None
@property
def color_xy(self):
def xy_color(self):
""" XY color value [float, float]. """
return None
@property
def rgb_color(self):
""" RGB color value [int, int, int] """
return None
@property
def color_temp(self):
""" CT color value in mirads. """
return None
@property
def device_state_attributes(self):
""" Returns device specific state attributes. """
@@ -317,6 +290,12 @@ class Light(ToggleEntity):
if value:
data[attr] = value
if ATTR_RGB_COLOR not in data and ATTR_XY_COLOR in data and \
ATTR_BRIGHTNESS in data:
data[ATTR_RGB_COLOR] = color_util.color_xy_brightness_to_RGB(
data[ATTR_XY_COLOR][0], data[ATTR_XY_COLOR][1],
data[ATTR_BRIGHTNESS])
device_attr = self.device_state_attributes
if device_attr is not None:
@@ -4,24 +4,23 @@ homeassistant.components.light.blinksticklight
Support for Blinkstick lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.blinksticklight.html
https://home-assistant.io/components/light.blinksticklight/
"""
import logging
from blinkstick import blinkstick
from homeassistant.components.light import (Light, ATTR_RGB_COLOR)
from homeassistant.components.light import Light, ATTR_RGB_COLOR
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ["blinkstick==1.1.7"]
DEPENDENCIES = []
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Add device specified by serial number. """
from blinkstick import blinkstick
stick = blinkstick.find_by_serial(config['serial'])
add_devices_callback([BlinkStickLight(stick, config['name'])])
+24 -13
View File
@@ -1,37 +1,40 @@
"""
homeassistant.components.light.demo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo platform that implements lights.
"""
import random
from homeassistant.components.light import (
Light, ATTR_BRIGHTNESS, ATTR_XY_COLOR)
Light, ATTR_BRIGHTNESS, ATTR_RGB_COLOR, ATTR_COLOR_TEMP)
LIGHT_COLORS = [
[0.368, 0.180],
[0.460, 0.470],
[237, 224, 33],
[255, 63, 111],
]
LIGHT_TEMPS = [240, 380]
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Find and return demo lights. """
add_devices_callback([
DemoLight("Bed Light", False),
DemoLight("Ceiling Lights", True, LIGHT_COLORS[0]),
DemoLight("Kitchen Lights", True, LIGHT_COLORS[1])
DemoLight("Ceiling Lights", True, LIGHT_COLORS[0], LIGHT_TEMPS[1]),
DemoLight("Kitchen Lights", True, LIGHT_COLORS[1], LIGHT_TEMPS[0])
])
class DemoLight(Light):
""" Provides a demo switch. """
def __init__(self, name, state, xy=None, brightness=180):
# pylint: disable=too-many-arguments
def __init__(self, name, state, rgb=None, ct=None, brightness=180):
self._name = name
self._state = state
self._xy = xy or random.choice(LIGHT_COLORS)
self._rgb = rgb or random.choice(LIGHT_COLORS)
self._ct = ct or random.choice(LIGHT_TEMPS)
self._brightness = brightness
@property
@@ -50,9 +53,14 @@ class DemoLight(Light):
return self._brightness
@property
def color_xy(self):
""" XY color value. """
return self._xy
def rgb_color(self):
""" rgb color value. """
return self._rgb
@property
def color_temp(self):
""" CT color temperature. """
return self._ct
@property
def is_on(self):
@@ -63,8 +71,11 @@ class DemoLight(Light):
""" Turn the device on. """
self._state = True
if ATTR_XY_COLOR in kwargs:
self._xy = kwargs[ATTR_XY_COLOR]
if ATTR_RGB_COLOR in kwargs:
self._rgb = kwargs[ATTR_RGB_COLOR]
if ATTR_COLOR_TEMP in kwargs:
self._ct = kwargs[ATTR_COLOR_TEMP]
if ATTR_BRIGHTNESS in kwargs:
self._brightness = kwargs[ATTR_BRIGHTNESS]
+46 -16
View File
@@ -3,20 +3,24 @@ homeassistant.components.light.hue
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Hue lights.
https://home-assistant.io/components/light.hue.html
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.hue/
"""
import json
import logging
import os
import socket
from datetime import timedelta
from urllib.parse import urlparse
from homeassistant.loader import get_component
import homeassistant.util as util
import homeassistant.util.color as color_util
from homeassistant.const import CONF_HOST, DEVICE_DEFAULT_NAME
from homeassistant.components.light import (
Light, ATTR_BRIGHTNESS, ATTR_XY_COLOR, ATTR_TRANSITION,
ATTR_FLASH, FLASH_LONG, FLASH_SHORT, ATTR_EFFECT,
EFFECT_COLORLOOP)
Light, ATTR_BRIGHTNESS, ATTR_XY_COLOR, ATTR_COLOR_TEMP,
ATTR_TRANSITION, ATTR_FLASH, FLASH_LONG, FLASH_SHORT,
ATTR_EFFECT, EFFECT_COLORLOOP, ATTR_RGB_COLOR)
REQUIREMENTS = ['phue==0.8']
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
@@ -30,21 +34,37 @@ _CONFIGURING = {}
_LOGGER = logging.getLogger(__name__)
def _find_host_from_config(hass):
""" Attempt to detect host based on existing configuration. """
path = hass.config.path(PHUE_CONFIG_FILE)
if not os.path.isfile(path):
return None
try:
with open(path) as inp:
return next(json.loads(''.join(inp)).keys().__iter__())
except (ValueError, AttributeError, StopIteration):
# ValueError if can't parse as JSON
# AttributeError if JSON value is not a dict
# StopIteration if no keys
return None
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Gets the Hue lights. """
try:
# pylint: disable=unused-variable
import phue # noqa
except ImportError:
_LOGGER.exception("Error while importing dependency phue.")
return
if discovery_info is not None:
host = urlparse(discovery_info[1]).hostname
else:
host = config.get(CONF_HOST, None)
if host is None:
host = _find_host_from_config(hass)
if host is None:
_LOGGER.error('No host found in configuration')
return False
# Only act if we are not already configuring this host
if host in _CONFIGURING:
return
@@ -125,6 +145,7 @@ def request_configuration(host, hass, add_devices_callback):
return
# pylint: disable=unused-argument
def hue_configuration_callback(data):
""" Actions to do when our configuration callback is called. """
setup_bridge(host, hass, add_devices_callback)
@@ -164,10 +185,15 @@ class HueLight(Light):
return self.info['state']['bri']
@property
def color_xy(self):
def xy_color(self):
""" XY color value. """
return self.info['state'].get('xy')
@property
def color_temp(self):
""" CT color value. """
return self.info['state'].get('ct')
@property
def is_on(self):
""" True if device is on. """
@@ -180,15 +206,19 @@ class HueLight(Light):
command = {'on': True}
if ATTR_TRANSITION in kwargs:
# Transition time is in 1/10th seconds and cannot exceed
# 900 seconds.
command['transitiontime'] = min(9000, kwargs[ATTR_TRANSITION] * 10)
command['transitiontime'] = kwargs[ATTR_TRANSITION] * 10
if ATTR_BRIGHTNESS in kwargs:
command['bri'] = kwargs[ATTR_BRIGHTNESS]
if ATTR_XY_COLOR in kwargs:
command['xy'] = kwargs[ATTR_XY_COLOR]
elif ATTR_RGB_COLOR in kwargs:
command['xy'] = color_util.color_RGB_to_xy(
*(int(val) for val in kwargs[ATTR_RGB_COLOR]))
if ATTR_COLOR_TEMP in kwargs:
command['ct'] = kwargs[ATTR_COLOR_TEMP]
flash = kwargs.get(ATTR_FLASH)
+2 -1
View File
@@ -3,7 +3,8 @@ homeassistant.components.light.hyperion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Hyperion remotes.
https://home-assistant.io/components/light.hyperion.html
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.hyperion/
"""
import logging
import socket
+3
View File
@@ -2,6 +2,9 @@
homeassistant.components.light.isy994
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for ISY994 lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/isy994/
"""
import logging
+238 -133
View File
@@ -1,179 +1,284 @@
"""
homeassistant.components.light.limitlessled
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for LimitlessLED bulbs.
Support for LimitlessLED bulbs, also known as...
- EasyBulb
- AppLight
- AppLamp
- MiLight
- LEDme
- dekolight
- iLight
https://home-assistant.io/components/light.limitlessled.html
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.limitlessled/
"""
import logging
from homeassistant.const import DEVICE_DEFAULT_NAME
from homeassistant.components.light import (Light, ATTR_BRIGHTNESS,
ATTR_XY_COLOR)
from homeassistant.util.color import color_RGB_to_xy
ATTR_RGB_COLOR, ATTR_EFFECT,
ATTR_COLOR_TEMP, ATTR_TRANSITION,
ATTR_FLASH, FLASH_LONG,
EFFECT_COLORLOOP, EFFECT_WHITE)
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['ledcontroller==1.1.0']
REQUIREMENTS = ['limitlessled==1.0.0']
RGB_BOUNDARY = 40
DEFAULT_TRANSITION = 0
DEFAULT_PORT = 8899
DEFAULT_VERSION = 5
DEFAULT_LED_TYPE = 'rgbw'
WHITE = [255, 255, 255]
def rewrite_legacy(config):
""" Rewrite legacy configuration to new format. """
bridges = config.get('bridges', [config])
new_bridges = []
for bridge_conf in bridges:
groups = []
if 'groups' in bridge_conf:
groups = bridge_conf['groups']
else:
_LOGGER.warning("Legacy configuration format detected")
for i in range(1, 5):
name_key = 'group_%d_name' % i
if name_key in bridge_conf:
groups.append({
'number': i,
'type': bridge_conf.get('group_%d_type' % i,
DEFAULT_LED_TYPE),
'name': bridge_conf.get(name_key)
})
new_bridges.append({
'host': bridge_conf.get('host'),
'groups': groups
})
return {'bridges': new_bridges}
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Gets the LimitlessLED lights. """
import ledcontroller
from limitlessled.bridge import Bridge
# Handle old configuration format:
bridges = config.get('bridges', [config])
for bridge_id, bridge in enumerate(bridges):
bridge['id'] = bridge_id
pool = ledcontroller.LedControllerPool([x['host'] for x in bridges])
# Two legacy configuration formats are supported to
# maintain backwards compatibility.
config = rewrite_legacy(config)
# Use the expanded configuration format.
lights = []
for bridge in bridges:
for i in range(1, 5):
name_key = 'group_%d_name' % i
if name_key in bridge:
group_type = bridge.get('group_%d_type' % i, 'rgbw')
lights.append(LimitlessLED.factory(pool, bridge['id'], i,
bridge[name_key],
group_type))
for bridge_conf in config.get('bridges'):
bridge = Bridge(bridge_conf.get('host'),
port=bridge_conf.get('port', DEFAULT_PORT),
version=bridge_conf.get('version', DEFAULT_VERSION))
for group_conf in bridge_conf.get('groups'):
group = bridge.add_group(group_conf.get('number'),
group_conf.get('name'),
group_conf.get('type', DEFAULT_LED_TYPE))
lights.append(LimitlessLEDGroup.factory(group))
add_devices_callback(lights)
class LimitlessLED(Light):
""" Represents a LimitlessLED light """
def state(new_state):
""" State decorator.
Specify True (turn on) or False (turn off).
"""
def decorator(function):
""" Decorator function. """
# pylint: disable=no-member,protected-access
def wrapper(self, **kwargs):
""" Wrap a group state change. """
from limitlessled.pipeline import Pipeline
pipeline = Pipeline()
transition_time = DEFAULT_TRANSITION
# Stop any repeating pipeline.
if self.repeating:
self.repeating = False
self.group.stop()
# Not on and should be? Turn on.
if not self.is_on and new_state is True:
pipeline.on()
# Set transition time.
if ATTR_TRANSITION in kwargs:
transition_time = kwargs[ATTR_TRANSITION]
# Do group type-specific work.
function(self, transition_time, pipeline, **kwargs)
# Update state.
self._is_on = new_state
self.group.enqueue(pipeline)
self.update_ha_state()
return wrapper
return decorator
class LimitlessLEDGroup(Light):
""" LimitessLED group. """
def __init__(self, group):
""" Initialize a group. """
self.group = group
self.repeating = False
self._is_on = False
self._brightness = None
@staticmethod
def factory(pool, controller_id, group, name, group_type):
''' Construct a Limitless LED of the appropriate type '''
if group_type == 'white':
return WhiteLimitlessLED(pool, controller_id, group, name)
elif group_type == 'rgbw':
return RGBWLimitlessLED(pool, controller_id, group, name)
# pylint: disable=too-many-arguments
def __init__(self, pool, controller_id, group, name, group_type):
self.pool = pool
self.controller_id = controller_id
self.group = group
self.pool.execute(self.controller_id, "set_group_type", self.group,
group_type)
# LimitlessLEDs don't report state, we have track it ourselves.
self.pool.execute(self.controller_id, "off", self.group)
self._name = name or DEVICE_DEFAULT_NAME
self._state = False
def factory(group):
""" Produce LimitlessLEDGroup objects. """
from limitlessled.group.rgbw import RgbwGroup
from limitlessled.group.white import WhiteGroup
if isinstance(group, WhiteGroup):
return LimitlessLEDWhiteGroup(group)
elif isinstance(group, RgbwGroup):
return LimitlessLEDRGBWGroup(group)
@property
def should_poll(self):
""" No polling needed. """
""" No polling needed.
LimitlessLED state cannot be fetched.
"""
return False
@property
def name(self):
""" Returns the name of the device if any. """
return self._name
""" Returns the name of the group. """
return self.group.name
@property
def is_on(self):
""" True if device is on. """
return self._state
def turn_off(self, **kwargs):
""" Turn the device off. """
self._state = False
self.pool.execute(self.controller_id, "off", self.group)
self.update_ha_state()
class RGBWLimitlessLED(LimitlessLED):
""" Represents a RGBW LimitlessLED light """
def __init__(self, pool, controller_id, group, name):
super().__init__(pool, controller_id, group, name, 'rgbw')
self._brightness = 100
self._xy_color = color_RGB_to_xy(255, 255, 255)
# Build a color table that maps an RGB color to a color string
# recognized by LedController's set_color method
self._color_table = [(color_RGB_to_xy(*x[0]), x[1]) for x in [
((0xFF, 0xFF, 0xFF), 'white'),
((0xEE, 0x82, 0xEE), 'violet'),
((0x41, 0x69, 0xE1), 'royal_blue'),
((0x87, 0xCE, 0xFA), 'baby_blue'),
((0x00, 0xFF, 0xFF), 'aqua'),
((0x7F, 0xFF, 0xD4), 'royal_mint'),
((0x2E, 0x8B, 0x57), 'seafoam_green'),
((0x00, 0x80, 0x00), 'green'),
((0x32, 0xCD, 0x32), 'lime_green'),
((0xFF, 0xFF, 0x00), 'yellow'),
((0xDA, 0xA5, 0x20), 'yellow_orange'),
((0xFF, 0xA5, 0x00), 'orange'),
((0xFF, 0x00, 0x00), 'red'),
((0xFF, 0xC0, 0xCB), 'pink'),
((0xFF, 0x00, 0xFF), 'fusia'),
((0xDA, 0x70, 0xD6), 'lilac'),
((0xE6, 0xE6, 0xFA), 'lavendar'),
]]
return self._is_on
@property
def brightness(self):
""" Brightness property. """
return self._brightness
@state(False)
def turn_off(self, transition_time, pipeline, **kwargs):
""" Turn off a group. """
if self.is_on:
pipeline.transition(transition_time, brightness=0.0).off()
class LimitlessLEDWhiteGroup(LimitlessLEDGroup):
""" LimitlessLED White group. """
def __init__(self, group):
""" Initialize White group. """
super().__init__(group)
# Initialize group with known values.
self.group.on = True
self.group.temperature = 1.0
self.group.brightness = 0.0
self._brightness = _to_hass_brightness(1.0)
self._temperature = _to_hass_temperature(self.group.temperature)
self.group.on = False
@property
def color_xy(self):
return self._xy_color
def _xy_to_led_color(self, xy_color):
""" Convert an XY color to the closest LedController color string. """
def abs_dist_squared(p_0, p_1):
""" Returns the absolute value of the squared distance """
return abs((p_0[0] - p_1[0])**2 + (p_0[1] - p_1[1])**2)
candidates = [(abs_dist_squared(xy_color, x[0]), x[1]) for x in
self._color_table]
# First candidate in the sorted list is closest to desired color:
return sorted(candidates)[0][1]
def turn_on(self, **kwargs):
""" Turn the device on. """
self._state = True
def color_temp(self):
""" Temperature property. """
return self._temperature
@state(True)
def turn_on(self, transition_time, pipeline, **kwargs):
""" Turn on (or adjust property of) a group. """
# Check arguments.
if ATTR_BRIGHTNESS in kwargs:
self._brightness = kwargs[ATTR_BRIGHTNESS]
if ATTR_XY_COLOR in kwargs:
self._xy_color = kwargs[ATTR_XY_COLOR]
self.pool.execute(self.controller_id, "set_color",
self._xy_to_led_color(self._xy_color), self.group)
self.pool.execute(self.controller_id, "set_brightness",
self._brightness / 255.0, self.group)
self.update_ha_state()
if ATTR_COLOR_TEMP in kwargs:
self._temperature = kwargs[ATTR_COLOR_TEMP]
# Set up transition.
pipeline.transition(transition_time,
brightness=_from_hass_brightness(
self._brightness),
temperature=_from_hass_temperature(
self._temperature))
class WhiteLimitlessLED(LimitlessLED):
""" Represents a White LimitlessLED light """
class LimitlessLEDRGBWGroup(LimitlessLEDGroup):
""" LimitlessLED RGBW group. """
def __init__(self, group):
""" Initialize RGBW group. """
super().__init__(group)
# Initialize group with known values.
self.group.on = True
self.group.white()
self._color = WHITE
self.group.brightness = 0.0
self._brightness = _to_hass_brightness(1.0)
self.group.on = False
def __init__(self, pool, controller_id, group, name):
super().__init__(pool, controller_id, group, name, 'white')
@property
def rgb_color(self):
""" Color property. """
return self._color
def turn_on(self, **kwargs):
""" Turn the device on. """
self._state = True
self.pool.execute(self.controller_id, "on", self.group)
self.update_ha_state()
@state(True)
def turn_on(self, transition_time, pipeline, **kwargs):
""" Turn on (or adjust property of) a group. """
from limitlessled.presets import COLORLOOP
# Check arguments.
if ATTR_BRIGHTNESS in kwargs:
self._brightness = kwargs[ATTR_BRIGHTNESS]
if ATTR_RGB_COLOR in kwargs:
self._color = kwargs[ATTR_RGB_COLOR]
# White is a special case.
if min(self._color) > 256 - RGB_BOUNDARY:
pipeline.white()
self._color = WHITE
# Set up transition.
pipeline.transition(transition_time,
brightness=_from_hass_brightness(
self._brightness),
color=_from_hass_color(self._color))
# Flash.
if ATTR_FLASH in kwargs:
duration = 0
if kwargs[ATTR_FLASH] == FLASH_LONG:
duration = 1
pipeline.flash(duration=duration)
# Add effects.
if ATTR_EFFECT in kwargs:
if kwargs[ATTR_EFFECT] == EFFECT_COLORLOOP:
self.repeating = True
pipeline.append(COLORLOOP)
if kwargs[ATTR_EFFECT] == EFFECT_WHITE:
pipeline.white()
self._color = WHITE
def _from_hass_temperature(temperature):
""" Convert Home Assistant color temperature
units to percentage.
"""
return (temperature - 154) / 346
def _to_hass_temperature(temperature):
""" Convert percentage to Home Assistant
color temperature units.
"""
return int(temperature * 346) + 154
def _from_hass_brightness(brightness):
""" Convert Home Assistant brightness units
to percentage.
"""
return brightness / 255
def _to_hass_brightness(brightness):
""" Convert percentage to Home Assistant
brightness units.
"""
return int(brightness * 255)
def _from_hass_color(color):
""" Convert Home Assistant RGB list
to Color tuple.
"""
from limitlessled import Color
return Color(*tuple(color))
def _to_hass_color(color):
""" Convert from Color tuple to
Home Assistant RGB list.
"""
return list([int(c) for c in color])
+175
View File
@@ -0,0 +1,175 @@
"""
homeassistant.components.light.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Allows to configure a MQTT light.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.mqtt/
"""
import logging
import homeassistant.components.mqtt as mqtt
from homeassistant.components.light import (Light,
ATTR_BRIGHTNESS, ATTR_RGB_COLOR)
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "MQTT Light"
DEFAULT_QOS = 0
DEFAULT_PAYLOAD_ON = "on"
DEFAULT_PAYLOAD_OFF = "off"
DEFAULT_OPTIMISTIC = False
DEPENDENCIES = ['mqtt']
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Add MQTT Light. """
if config.get('command_topic') is None:
_LOGGER.error("Missing required variable: command_topic")
return False
add_devices_callback([MqttLight(
hass,
config.get('name', DEFAULT_NAME),
{
"state_topic": config.get('state_topic'),
"command_topic": config.get('command_topic'),
"brightness_state_topic": config.get('brightness_state_topic'),
"brightness_command_topic": config.get('brightness_command_topic'),
"rgb_state_topic": config.get('rgb_state_topic'),
"rgb_command_topic": config.get('rgb_command_topic')
},
config.get('qos', DEFAULT_QOS),
{
"on": config.get('payload_on', DEFAULT_PAYLOAD_ON),
"off": config.get('payload_off', DEFAULT_PAYLOAD_OFF)
},
config.get('optimistic', DEFAULT_OPTIMISTIC))])
class MqttLight(Light):
""" Provides a MQTT light. """
# pylint: disable=too-many-arguments,too-many-instance-attributes
def __init__(self, hass, name, topic, qos, payload, optimistic):
self._hass = hass
self._name = name
self._topic = topic
self._qos = qos
self._payload = payload
self._optimistic = optimistic or topic["state_topic"] is None
self._optimistic_rgb = optimistic or topic["rgb_state_topic"] is None
self._optimistic_brightness = (optimistic or
topic["brightness_state_topic"] is None)
self._state = False
def state_received(topic, payload, qos):
""" A new MQTT message has been received. """
if payload == self._payload["on"]:
self._state = True
elif payload == self._payload["off"]:
self._state = False
self.update_ha_state()
if self._topic["state_topic"] is not None:
mqtt.subscribe(self._hass, self._topic["state_topic"],
state_received, self._qos)
def brightness_received(topic, payload, qos):
""" A new MQTT message for the brightness has been received. """
self._brightness = int(payload)
self.update_ha_state()
if self._topic["brightness_state_topic"] is not None:
mqtt.subscribe(self._hass, self._topic["brightness_state_topic"],
brightness_received, self._qos)
self._brightness = 255
else:
self._brightness = None
def rgb_received(topic, payload, qos):
""" A new MQTT message has been received. """
self._rgb = [int(val) for val in payload.split(',')]
self.update_ha_state()
if self._topic["rgb_state_topic"] is not None:
mqtt.subscribe(self._hass, self._topic["rgb_state_topic"],
rgb_received, self._qos)
self._rgb = [255, 255, 255]
else:
self._rgb = None
@property
def brightness(self):
""" Brightness of this light between 0..255. """
return self._brightness
@property
def rgb_color(self):
""" RGB color value. """
return self._rgb
@property
def should_poll(self):
""" No polling needed for a MQTT light. """
return False
@property
def name(self):
""" Returns the name of the device if any. """
return self._name
@property
def is_on(self):
""" True if device is on. """
return self._state
def turn_on(self, **kwargs):
""" Turn the device on. """
should_update = False
if ATTR_RGB_COLOR in kwargs and \
self._topic["rgb_command_topic"] is not None:
mqtt.publish(self._hass, self._topic["rgb_command_topic"],
"{},{},{}".format(*kwargs[ATTR_RGB_COLOR]), self._qos)
if self._optimistic_rgb:
self._rgb = kwargs[ATTR_RGB_COLOR]
should_update = True
if ATTR_BRIGHTNESS in kwargs and \
self._topic["brightness_command_topic"] is not None:
mqtt.publish(self._hass, self._topic["brightness_command_topic"],
kwargs[ATTR_BRIGHTNESS], self._qos)
if self._optimistic_brightness:
self._brightness = kwargs[ATTR_BRIGHTNESS]
should_update = True
mqtt.publish(self._hass, self._topic["command_topic"],
self._payload["on"], self._qos)
if self._optimistic:
# optimistically assume that switch has changed state
self._state = True
should_update = True
if should_update:
self.update_ha_state()
def turn_off(self, **kwargs):
""" Turn the device off. """
mqtt.publish(self._hass, self._topic["command_topic"],
self._payload["off"], self._qos)
if self._optimistic:
# optimistically assume that switch has changed state
self._state = False
self.update_ha_state()
+52 -13
View File
@@ -4,15 +4,19 @@ homeassistant.components.light.rfxtrx
Support for RFXtrx lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.rfxtrx.html
https://home-assistant.io/components/light.rfxtrx/
"""
import logging
import homeassistant.components.rfxtrx as rfxtrx
import RFXtrx as rfxtrxmod
from homeassistant.components.light import Light
from homeassistant.util import slugify
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.components.rfxtrx import ATTR_STATE, ATTR_FIREEVENT, ATTR_PACKETID, \
ATTR_NAME, EVENT_BUTTON_PRESSED
DEPENDENCIES = ['rfxtrx']
_LOGGER = logging.getLogger(__name__)
@@ -20,14 +24,24 @@ _LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Setup the RFXtrx platform. """
import RFXtrx as rfxtrxmod
lights = []
devices = config.get('devices', None)
if devices:
for entity_id, entity_info in devices.items():
if entity_id not in rfxtrx.RFX_DEVICES:
_LOGGER.info("Add %s rfxtrx.light", entity_info['name'])
rfxobject = rfxtrx.get_rfx_object(entity_info['packetid'])
new_light = RfxtrxLight(entity_info['name'], rfxobject, False)
_LOGGER.info("Add %s rfxtrx.light", entity_info[ATTR_NAME])
# Check if i must fire event
fire_event = entity_info.get(ATTR_FIREEVENT, False)
datas = {ATTR_STATE: False, ATTR_FIREEVENT: fire_event}
rfxobject = rfxtrx.get_rfx_object(entity_info[ATTR_PACKETID])
new_light = RfxtrxLight(
entity_info[ATTR_NAME], rfxobject, datas
)
rfxtrx.RFX_DEVICES[entity_id] = new_light
lights.append(new_light)
@@ -53,18 +67,37 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
)
pkt_id = "".join("{0:02x}".format(x) for x in event.data)
entity_name = "%s : %s" % (entity_id, pkt_id)
new_light = RfxtrxLight(entity_name, event, False)
datas = {ATTR_STATE: False, ATTR_FIREEVENT: False}
new_light = RfxtrxLight(entity_name, event, datas)
rfxtrx.RFX_DEVICES[entity_id] = new_light
add_devices_callback([new_light])
# Check if entity exists or previously added automatically
if entity_id in rfxtrx.RFX_DEVICES:
if entity_id in rfxtrx.RFX_DEVICES \
and isinstance(rfxtrx.RFX_DEVICES[entity_id], RfxtrxLight):
_LOGGER.debug(
"EntityID: %s light_update. Command: %s",
entity_id,
event.values['Command']
)
if event.values['Command'] == 'On'\
or event.values['Command'] == 'Off':
if event.values['Command'] == 'On':
rfxtrx.RFX_DEVICES[entity_id].turn_on()
else:
rfxtrx.RFX_DEVICES[entity_id].turn_off()
# Update the rfxtrx device state
is_on = event.values['Command'] == 'On'
# pylint: disable=protected-access
rfxtrx.RFX_DEVICES[entity_id]._state = is_on
rfxtrx.RFX_DEVICES[entity_id].update_ha_state()
# Fire event
if rfxtrx.RFX_DEVICES[entity_id].should_fire_event:
rfxtrx.RFX_DEVICES[entity_id].hass.bus.fire(
EVENT_BUTTON_PRESSED, {
ATTR_ENTITY_ID:
rfxtrx.RFX_DEVICES[entity_id].entity_id,
ATTR_STATE: event.values['Command'].lower()
}
)
# Subscribe to main rfxtrx events
if light_update not in rfxtrx.RECEIVED_EVT_SUBSCRIBERS:
@@ -73,10 +106,11 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
class RfxtrxLight(Light):
""" Provides a RFXtrx light. """
def __init__(self, name, event, state):
def __init__(self, name, event, datas):
self._name = name
self._event = event
self._state = state
self._state = datas[ATTR_STATE]
self._should_fire_event = datas[ATTR_FIREEVENT]
@property
def should_poll(self):
@@ -88,6 +122,11 @@ class RfxtrxLight(Light):
""" Returns the name of the light if any. """
return self._name
@property
def should_fire_event(self):
""" Returns is the device must fire event"""
return self._should_fire_event
@property
def is_on(self):
""" True if light is on. """
@@ -20,6 +20,10 @@ turn_on:
description: Color for the light in XY-format
example: '[0.52, 0.43]'
color_temp:
description: Color temperature for the light in mireds (154-500)
example: '250'
brightness:
description: Number between 0..255 indicating brightness
example: 120
+24 -20
View File
@@ -4,37 +4,32 @@ homeassistant.components.light.tellstick
Support for Tellstick lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.tellstick.html
https://home-assistant.io/components/light.tellstick/
"""
import logging
# pylint: disable=no-name-in-module, import-error
from homeassistant.components.light import Light, ATTR_BRIGHTNESS
from homeassistant.const import (EVENT_HOMEASSISTANT_STOP,
ATTR_FRIENDLY_NAME)
import tellcore.constants as tellcore_constants
from tellcore.library import DirectCallbackDispatcher
REQUIREMENTS = ['tellcore-py==1.1.2']
SIGNAL_REPETITIONS = 1
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Find and return Tellstick lights. """
try:
import tellcore.telldus as telldus
except ImportError:
logging.getLogger(__name__).exception(
"Failed to import tellcore")
return []
import tellcore.telldus as telldus
from tellcore.library import DirectCallbackDispatcher
import tellcore.constants as tellcore_constants
core = telldus.TelldusCore(callback_dispatcher=DirectCallbackDispatcher())
signal_repetitions = config.get('signal_repetitions', SIGNAL_REPETITIONS)
switches_and_lights = core.devices()
lights = []
for switch in switches_and_lights:
if switch.methods(tellcore_constants.TELLSTICK_DIM):
lights.append(TellstickLight(switch))
lights.append(TellstickLight(switch, signal_repetitions))
def _device_event_callback(id_, method, data, cid):
""" Called from the TelldusCore library to update one device """
@@ -58,17 +53,22 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
class TellstickLight(Light):
""" Represents a Tellstick light. """
last_sent_command_mask = (tellcore_constants.TELLSTICK_TURNON |
tellcore_constants.TELLSTICK_TURNOFF |
tellcore_constants.TELLSTICK_DIM |
tellcore_constants.TELLSTICK_UP |
tellcore_constants.TELLSTICK_DOWN)
def __init__(self, tellstick_device):
def __init__(self, tellstick_device, signal_repetitions):
import tellcore.constants as tellcore_constants
self.tellstick_device = tellstick_device
self.state_attr = {ATTR_FRIENDLY_NAME: tellstick_device.name}
self.signal_repetitions = signal_repetitions
self._brightness = 0
self.last_sent_command_mask = (tellcore_constants.TELLSTICK_TURNON |
tellcore_constants.TELLSTICK_TURNOFF |
tellcore_constants.TELLSTICK_DIM |
tellcore_constants.TELLSTICK_UP |
tellcore_constants.TELLSTICK_DOWN)
self.update()
@property
def name(self):
""" Returns the name of the switch if any. """
@@ -86,7 +86,8 @@ class TellstickLight(Light):
def turn_off(self, **kwargs):
""" Turns the switch off. """
self.tellstick_device.turn_off()
for _ in range(self.signal_repetitions):
self.tellstick_device.turn_off()
self._brightness = 0
self.update_ha_state()
@@ -99,11 +100,14 @@ class TellstickLight(Light):
else:
self._brightness = brightness
self.tellstick_device.dim(self._brightness)
for _ in range(self.signal_repetitions):
self.tellstick_device.dim(self._brightness)
self.update_ha_state()
def update(self):
""" Update state of the light. """
import tellcore.constants as tellcore_constants
last_command = self.tellstick_device.last_sent_command(
self.last_sent_command_mask)
+35 -6
View File
@@ -4,15 +4,19 @@ homeassistant.components.light.vera
Support for Vera lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.vera.html
https://home-assistant.io/components/light.vera/
"""
import logging
import time
from requests.exceptions import RequestException
from homeassistant.components.switch.vera import VeraSwitch
REQUIREMENTS = ['https://github.com/balloob/home-assistant-vera-api/archive/'
'a8f823066ead6c7da6fb5e7abaf16fef62e63364.zip'
'#python-vera==0.1']
from homeassistant.components.light import ATTR_BRIGHTNESS
REQUIREMENTS = ['https://github.com/pavoni/home-assistant-vera-api/archive/'
'efdba4e63d58a30bc9b36d9e01e69858af9130b8.zip'
'#python-vera==0.1.1']
_LOGGER = logging.getLogger(__name__)
@@ -35,7 +39,10 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
controller = veraApi.VeraController(base_url)
devices = []
try:
devices = controller.get_devices(['Switch', 'On/Off Switch'])
devices = controller.get_devices([
'Switch',
'On/Off Switch',
'Dimmable Switch'])
except RequestException:
# There was a network related error connecting to the vera controller
_LOGGER.exception("Error communicating with Vera API")
@@ -47,6 +54,28 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
exclude = extra_data.get('exclude', False)
if exclude is not True:
lights.append(VeraSwitch(device, extra_data))
lights.append(VeraLight(device, extra_data))
add_devices_callback(lights)
class VeraLight(VeraSwitch):
""" Represents a Vera Light, including dimmable. """
@property
def state_attributes(self):
attr = super().state_attributes or {}
if self.vera_device.is_dimmable:
attr[ATTR_BRIGHTNESS] = self.vera_device.get_brightness()
return attr
def turn_on(self, **kwargs):
if ATTR_BRIGHTNESS in kwargs and self.vera_device.is_dimmable:
self.vera_device.set_brightness(kwargs[ATTR_BRIGHTNESS])
else:
self.vera_device.switch_on()
self.last_command_send = time.time()
self.is_on_status = True
+3 -3
View File
@@ -4,7 +4,7 @@ homeassistant.components.light.wink
Support for Wink lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.wink.html
https://home-assistant.io/components/light.wink/
"""
import logging
@@ -13,8 +13,8 @@ from homeassistant.components.wink import WinkToggleDevice
from homeassistant.const import CONF_ACCESS_TOKEN
REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/'
'c2b700e8ca866159566ecf5e644d9c297f69f257.zip'
'#python-wink==0.1']
'42fdcfa721b1bc583688e3592d8427f4c13ba6d9.zip'
'#python-wink==0.2']
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
+127
View File
@@ -0,0 +1,127 @@
"""
homeassistant.components.light.zwave
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Z-Wave lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.zwave/
"""
# Because we do not compile openzwave on CI
# pylint: disable=import-error
from threading import Timer
from homeassistant.const import STATE_ON, STATE_OFF
from homeassistant.components.light import (Light, ATTR_BRIGHTNESS)
import homeassistant.components.zwave as zwave
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Find and add Z-Wave lights. """
if discovery_info is None:
return
node = zwave.NETWORK.nodes[discovery_info[zwave.ATTR_NODE_ID]]
value = node.values[discovery_info[zwave.ATTR_VALUE_ID]]
if value.command_class != zwave.COMMAND_CLASS_SWITCH_MULTILEVEL:
return
if value.type != zwave.TYPE_BYTE:
return
if value.genre != zwave.GENRE_USER:
return
value.set_change_verified(False)
add_devices([ZwaveDimmer(value)])
def brightness_state(value):
"""
Returns the brightness and state according to the current data of given
value.
"""
if value.data > 0:
return (value.data / 99) * 255, STATE_ON
else:
return 255, STATE_OFF
class ZwaveDimmer(Light):
""" Provides a Z-Wave dimmer. """
# pylint: disable=too-many-arguments
def __init__(self, value):
from openzwave.network import ZWaveNetwork
from pydispatch import dispatcher
self._value = value
self._node = value.node
self._brightness, self._state = brightness_state(value)
# Used for value change event handling
self._refreshing = False
self._timer = None
dispatcher.connect(
self._value_changed, ZWaveNetwork.SIGNAL_VALUE_CHANGED)
def _value_changed(self, value):
""" Called when a value has changed on the network. """
if self._value.value_id != value.value_id:
return
if self._refreshing:
self._refreshing = False
self._brightness, self._state = brightness_state(value)
else:
def _refresh_value():
"""Used timer callback for delayed value refresh."""
self._refreshing = True
self._value.refresh()
if self._timer is not None and self._timer.isAlive():
self._timer.cancel()
self._timer = Timer(2, _refresh_value)
self._timer.start()
self.update_ha_state()
@property
def should_poll(self):
""" No polling needed for a light. """
return False
@property
def name(self):
""" Returns the name of the device if any. """
name = self._node.name or "{}".format(self._node.product_name)
return "{}".format(name or self._value.label)
@property
def brightness(self):
""" Brightness of this light between 0..255. """
return self._brightness
@property
def is_on(self):
""" True if device is on. """
return self._state == STATE_ON
def turn_on(self, **kwargs):
""" Turn the device on. """
if ATTR_BRIGHTNESS in kwargs:
self._brightness = kwargs[ATTR_BRIGHTNESS]
# Zwave multilevel switches use a range of [0, 99] to control
# brightness.
brightness = (self._brightness / 255) * 99
if self._node.set_dimmer(self._value.value_id, brightness):
self._state = STATE_ON
def turn_off(self, **kwargs):
""" Turn the device off. """
if self._node.set_dimmer(self._value.value_id, 0):
self._state = STATE_OFF
+112
View File
@@ -0,0 +1,112 @@
"""
homeassistant.components.lock
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component to interface with various locks that can be controlled remotely.
For more details about this component, please refer to the documentation
at https://home-assistant.io/components/lock/
"""
from datetime import timedelta
import logging
import os
from homeassistant.config import load_yaml_config_file
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.entity import Entity
from homeassistant.const import (
STATE_LOCKED, STATE_UNLOCKED, STATE_UNKNOWN, SERVICE_LOCK, SERVICE_UNLOCK,
ATTR_ENTITY_ID)
from homeassistant.components import (group, wink)
DOMAIN = 'lock'
SCAN_INTERVAL = 30
GROUP_NAME_ALL_LOCKS = 'all locks'
ENTITY_ID_ALL_LOCKS = group.ENTITY_ID_FORMAT.format('all_locks')
ENTITY_ID_FORMAT = DOMAIN + '.{}'
ATTR_LOCKED = "locked"
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
# Maps discovered services to their platforms
DISCOVERY_PLATFORMS = {
wink.DISCOVER_LOCKS: 'wink'
}
_LOGGER = logging.getLogger(__name__)
def is_locked(hass, entity_id=None):
""" Returns if the lock is locked based on the statemachine. """
entity_id = entity_id or ENTITY_ID_ALL_LOCKS
return hass.states.is_state(entity_id, STATE_LOCKED)
def lock(hass, entity_id=None):
""" Locks all or specified locks. """
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.services.call(DOMAIN, SERVICE_LOCK, data)
def unlock(hass, entity_id=None):
""" Unlocks all or specified locks. """
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.services.call(DOMAIN, SERVICE_UNLOCK, data)
def setup(hass, config):
""" Track states and offer events for locks. """
component = EntityComponent(
_LOGGER, DOMAIN, hass, SCAN_INTERVAL, DISCOVERY_PLATFORMS,
GROUP_NAME_ALL_LOCKS)
component.setup(config)
def handle_lock_service(service):
""" Handles calls to the lock services. """
target_locks = component.extract_from_service(service)
for item in target_locks:
if service.service == SERVICE_LOCK:
item.lock()
else:
item.unlock()
if item.should_poll:
item.update_ha_state(True)
descriptions = load_yaml_config_file(
os.path.join(os.path.dirname(__file__), 'services.yaml'))
hass.services.register(DOMAIN, SERVICE_UNLOCK, handle_lock_service,
descriptions.get(SERVICE_UNLOCK))
hass.services.register(DOMAIN, SERVICE_LOCK, handle_lock_service,
descriptions.get(SERVICE_LOCK))
return True
class LockDevice(Entity):
""" Represents a lock within Home Assistant. """
# pylint: disable=no-self-use
@property
def is_locked(self):
""" Is the lock locked or unlocked. """
return None
def lock(self):
""" Locks the lock. """
raise NotImplementedError()
def unlock(self):
""" Unlocks the lock. """
raise NotImplementedError()
@property
def state(self):
locked = self.is_locked
if locked is None:
return STATE_UNKNOWN
return STATE_LOCKED if locked else STATE_UNLOCKED
+49
View File
@@ -0,0 +1,49 @@
"""
homeassistant.components.lock.demo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo platform that has two fake locks.
"""
from homeassistant.components.lock import LockDevice
from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Find and return demo locks. """
add_devices_callback([
DemoLock('Front Door', STATE_LOCKED),
DemoLock('Kitchen Door', STATE_UNLOCKED)
])
class DemoLock(LockDevice):
""" Provides a demo lock. """
def __init__(self, name, state):
self._name = name
self._state = state
@property
def should_poll(self):
""" No polling needed for a demo lock. """
return False
@property
def name(self):
""" Returns the name of the device if any. """
return self._name
@property
def is_locked(self):
""" True if device is locked. """
return self._state == STATE_LOCKED
def lock(self, **kwargs):
""" Lock the device. """
self._state = STATE_LOCKED
self.update_ha_state()
def unlock(self, **kwargs):
""" Unlock the device. """
self._state = STATE_UNLOCKED
self.update_ha_state()
+68
View File
@@ -0,0 +1,68 @@
"""
homeassistant.components.lock.wink
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Wink locks.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/lock.wink/
"""
import logging
from homeassistant.components.lock import LockDevice
from homeassistant.const import CONF_ACCESS_TOKEN
REQUIREMENTS = ['https://github.com/balloob/python-wink/archive/'
'42fdcfa721b1bc583688e3592d8427f4c13ba6d9.zip'
'#python-wink==0.2']
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the Wink platform. """
import pywink
if discovery_info is None:
token = config.get(CONF_ACCESS_TOKEN)
if token is None:
logging.getLogger(__name__).error(
"Missing wink access_token. "
"Get one at https://winkbearertoken.appspot.com/")
return
pywink.set_bearer_token(token)
add_devices(WinkLockDevice(lock) for lock in pywink.get_locks())
class WinkLockDevice(LockDevice):
""" Represents a Wink lock. """
def __init__(self, wink):
self.wink = wink
@property
def unique_id(self):
""" Returns the id of this wink lock """
return "{}.{}".format(self.__class__, self.wink.deviceId())
@property
def name(self):
""" Returns the name of the lock if any. """
return self.wink.name()
def update(self):
""" Update the state of the lock. """
self.wink.updateState()
@property
def is_locked(self):
""" True if device is locked. """
return self.wink.state()
def lock(self):
""" Lock the device. """
self.wink.setState(True)
def unlock(self):
""" Unlock the device. """
self.wink.setState(False)

Some files were not shown because too many files have changed in this diff Show More