Compare commits

...

476 Commits

Author SHA1 Message Date
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 ab48a94d2a Version bump to 0.7.7.dev0 2015-10-26 21:32:07 -07:00
Paulus Schoutsen 27c6c27db6 Merge pull request #554 from balloob/dev
0.7.6-rc1
2015-10-26 21:31:41 -07:00
Paulus Schoutsen 55c0ee6b32 Version bump to 0.7.6 2015-10-26 21:27:50 -07:00
Paulus Schoutsen 6b881ce1cd Merge pull request #547 from krzynio/dev
Add new OpenWRT presence detection routine based on ubus instead of luci
2015-10-26 21:26:13 -07:00
Paulus Schoutsen 9ab9d0e383 Update netdisco requirement 2015-10-26 20:49:20 -07:00
pavoni dbc05450a0 Bump requirements_all.txt version, remove pylint disable 2015-10-26 16:32:12 +00: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
Krzysztof Koziarek 649124d162 Added ubus.py to .coveragerc 2015-10-26 11:55:20 +01:00
pavoni 49f4d92c62 Add dimmer as switch 2015-10-26 10:51:23 +00:00
Krzysztof Koziarek fbb73dd5da fixed pylint warnings 2015-10-26 11:50:09 +01:00
Krzysztof Koziarek c9f1dce6a2 Coding style fixes 2015-10-26 11:32:00 +01:00
pavoni ef6c209c6f Revise for clarity, disable pylink check 2015-10-26 09:03:57 +00:00
pavoni 0826ae2742 Revise pywemo version, update discovery.device_from_description parameters 2015-10-26 08:37:13 +00:00
Paulus Schoutsen 18747f8ae1 Update some docs 2015-10-25 23:12:10 -07:00
Paulus Schoutsen 06c8c1b168 Update to latest version frontend 2015-10-25 23:12:10 -07:00
Paulus Schoutsen 160fb6fcc8 Merge pull request #553 from balloob/download_relative
Download - relative / absolute path
2015-10-25 21:06:33 -07:00
Paulus Schoutsen f1aa685cf2 Add version to config API 2015-10-25 21:00:22 -07:00
Paulus Schoutsen da259d75a2 Update frontend with imprpved charts 2015-10-25 19:01:51 -07:00
Tom Duijf 9104ca815d Indentation 2015-10-26 00:13:47 +00:00
Tom Duijf 52193611cd Check for relative path 2015-10-26 00:10:32 +00:00
Paulus Schoutsen a2256f6c97 Update version frontend 2015-10-25 15:39:50 -07:00
Paulus Schoutsen 004bad7f00 Merge pull request #551 from balloob/mp_plex_discovery
Media_player/plex discovery
2015-10-25 15:38:42 -07: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
Paulus Schoutsen e490388843 Merge pull request #544 from MakeMeASandwich/hyperion
Hyperion ambilight remote support
2015-10-25 14:34:22 -07:00
Fabian Affolter fb8edca942 Add link to docs, fix typo, and update log output 2015-10-25 22:21:25 +01:00
root 469d0619ba mqtt light component 2015-10-25 21:48:01 +01:00
Tom Duijf bc8c5766d4 Logic fixes 2015-10-25 17:54:48 +00:00
Tom Duijf 5b25d9ccd6 flake8,pylint and other code cleanup 2015-10-25 17:00:54 +00:00
Fabian Affolter 0d05930765 Update 2015-10-25 15:58:58 +01:00
Fabian Affolter f93282d636 Add link to docs 2015-10-25 15:58:58 +01:00
Fabian Affolter 78ad2686d4 Add link to docs 2015-10-25 15:58:58 +01:00
Fabian Affolter 3c36d13e8d Add link to docs 2015-10-25 15:58:58 +01:00
Fabian Affolter 77ba0c0393 Add link to docs 2015-10-25 15:58:58 +01:00
Fabian Affolter 6a3316ed12 Add link to docs 2015-10-25 15:58:58 +01:00
Fabian Affolter 415d650860 Add link to docs 2015-10-25 15:58:58 +01:00
Fabian Affolter c3c248bc0a Add link to docs 2015-10-25 15:58:58 +01:00
Fabian Affolter bf027fcd48 Add link to docs 2015-10-25 15:58:58 +01:00
Fabian Affolter 5c79fc0ae3 Add link to docs 2015-10-25 15:58:58 +01:00
Fabian Affolter 0aaf280bf5 Add link to docs 2015-10-25 15:58:58 +01:00
Fabian Affolter 55de563511 Add link to docs 2015-10-25 15:58:58 +01:00
Fabian Affolter 1a018e3ee7 Remove configuration details 2015-10-25 15:58:58 +01:00
Fabian Affolter b023348795 Add link to docs 2015-10-25 15:58:58 +01:00
Tom Duijf 847d9736aa Configurator works, config saving basic implementation 2015-10-25 13:34:34 +00:00
Tom Duijf 884525df33 Basic discovery works, added plex logo for configurator. Missing configurator support for fields. Todo: config save on successful connect 2015-10-25 13:34:34 +00:00
Tom Duijf 6a82504e5e further discovery integration into plex 2015-10-25 13:34:34 +00:00
Tom Duijf db7e46abd1 Intermediate save 2015-10-25 13:33:47 +00:00
Tom Duijf 8e9cafd29d Updated requirements_all.txt. Added placeholder to the empty deviceClass filter. Will remove this if deemed unneeded, later 2015-10-25 13:32:15 +00:00
Tom Duijf a236b87ccf new attempt for PR 2015-10-25 13:32:15 +00:00
MakeMeASandwich e379e3d902 Merge branch 'dev' of https://github.com/balloob/home-assistant into hyperion 2015-10-25 11:29:02 +01:00
MakeMeASandwich 1be48f54c0 light/hyperion: close sockets, report setup success 2015-10-25 11:08:59 +01:00
Paulus Schoutsen 96181a555a Allow pipes in command sensors and services 2015-10-24 12:40:36 -07:00
Paulus Schoutsen e461ceae36 discovery: update Netdisco requirement 2015-10-24 12:18:48 -07:00
Paulus Schoutsen 83e6c24f18 Re-enable Z-Wave for Docker 2015-10-24 11:36:34 -07:00
Krzysztof Koziarek 50fbd83b3d corrected flake8 warnings 2015-10-24 11:20:57 +02:00
Fabian Affolter 649275044a Remove configuration details 2015-10-24 09:13:54 +02:00
Fabian Affolter 0f81fc60ad Remove configuration details 2015-10-24 09:10:31 +02:00
Paulus Schoutsen ade8681511 Exclude rest switch from coverage 2015-10-23 23:44:17 -07:00
Paulus Schoutsen 7a699fd819 Merge pull request #539 from nkgilley/forecastio-units
Forecastio: Added support for specifying unit system in the configuration file.
2015-10-23 22:54:31 -07:00
Paulus Schoutsen b0c0659acc Merge branch 'clean-up-heat-control' into dev
Conflicts:
	homeassistant/components/thermostat/heat_control.py
2015-10-23 22:51:00 -07:00
Paulus Schoutsen 80a9422a9a Merge pull request #545 from MakeMeASandwich/denon
Refactor denon remote
2015-10-23 22:40:37 -07:00
Fabian Affolter 060cbaf66b Add return value 2015-10-24 00:38:19 +02:00
Fabian Affolter c19120e012 Check import 2015-10-24 00:34:49 +02:00
Fabian Affolter 1e0e48fcd7 Use logger the same as other platforms do 2015-10-24 00:29:47 +02:00
Fabian Affolter f2fda2914a Fix continuation 2015-10-24 00:29:02 +02:00
Fabian Affolter 7e3483ab03 Remove configuration details 2015-10-24 00:24:14 +02:00
Fabian Affolter bffce11a9a Remove configuration details 2015-10-24 00:20:18 +02:00
Fabian Affolter 8a895390ef Merge pull request #534 from bachp/dev
Add simple REST switch
2015-10-23 23:52:40 +02:00
Fabian Affolter 97f81ad7a6 Add more details 2015-10-23 23:48:57 +02:00
Pascal Bach 67d5581a1b Add simple REST switch
The switch can get the state via GET and set the state via POST
on a given REST resource.
It is not able to control arbitrary urls but it allows controlling
switches exposed via "real" REST.
2015-10-23 23:40:14 +02:00
Fabian Affolter 3406b41b0c Fix return value 2015-10-23 23:08:27 +02:00
Fabian Affolter 2e7912157b Remove configuration details 2015-10-23 23:00:20 +02:00
Fabian Affolter 5dbdf82ec7 Fix typo 2015-10-23 22:58:00 +02:00
Fabian Affolter 9f4a3f4aea Use the logger the same way as other platforms do 2015-10-23 22:57:07 +02:00
Fabian Affolter 4f3b3a9e34 Use the logger the same way as other platforms 2015-10-23 22:53:58 +02:00
Fabian Affolter 3ea167203f Remove configuration details 2015-10-23 22:48:30 +02:00
Fabian Affolter 756cbe1b08 Remove configuration details 2015-10-23 22:41:13 +02:00
Fabian Affolter 87e55820e7 Add link docs 2015-10-23 22:39:04 +02:00
Fabian Affolter f828ee044d UPdate docstring 2015-10-23 22:34:23 +02:00
Fabian Affolter a8e2f9cbb7 Remove configuration details 2015-10-23 22:34:02 +02:00
Fabian Affolter 2e3f462474 Update docstring 2015-10-23 22:32:36 +02:00
Fabian Affolter 3f6780d9be Remove configuration details 2015-10-23 22:31:37 +02:00
Fabian Affolter e21921823e Update docstring 2015-10-23 22:29:22 +02:00
Fabian Affolter f9b2e0058e Fix typo 2015-10-23 19:01:38 +02:00
Fabian Affolter a155587693 Remove configuration details 2015-10-23 19:01:19 +02:00
Fabian Affolter 0e145ec130 Remove configuration details 2015-10-23 18:39:50 +02:00
Fabian Affolter 44b08a06e7 Remove configuration details 2015-10-23 18:26:36 +02:00
Fabian Affolter 75f737144a Remove configuration details 2015-10-23 18:24:07 +02:00
Fabian Affolter 170742b0a7 Remove configuration details 2015-10-23 18:15:12 +02:00
Fabian Affolter 6115be7c42 Remove configuration details 2015-10-23 18:13:45 +02:00
Fabian Affolter 84a9a300d6 Fix link 2015-10-23 18:13:28 +02:00
Fabian Affolter 55718aac66 Remove configuration details 2015-10-23 18:10:32 +02:00
MakeMeASandwich b6e6512367 media_player/denon: refactor
* connect only if necessary
* do not throw errors if offline
2015-10-23 17:35:08 +02:00
Krzysztof Koziarek 29c9c5a7ec Add new OpenWRT presence detection routine based on ubus instead of luci 2015-10-23 17:01:42 +02:00
Nolan Gilley dd787ea5ce remove suggestion for uk unit system. change default to use si or us based on default temperature. added more sensor types. 2015-10-23 10:10:44 -04:00
Paulus Schoutsen c2d75efb4d Add missing docstring to heat control thermo 2015-10-22 22:14:40 -07:00
Paulus Schoutsen 3d972abdab Clean up the heat control thermostat 2015-10-22 22:04:37 -07:00
Fabian Affolter 7801489149 Remove configuration details 2015-10-21 23:05:54 +02:00
Fabian Affolter 0fda89e983 Remove configuration details 2015-10-21 23:05:38 +02:00
Fabian Affolter 07a75c5eeb Remove configuration details 2015-10-21 23:05:13 +02:00
Fabian Affolter 0b7c407519 Remove configuration details 2015-10-21 22:54:42 +02:00
Fabian Affolter 3c34f3dac2 Remove configuration details 2015-10-21 22:53:26 +02:00
Fabian Affolter d45074f9dc Remove configuration details 2015-10-21 22:53:09 +02:00
sander 863955e1bd got the basics working 2015-10-21 21:48:21 +02:00
Fabian Affolter 4ff1b0fdb2 Add link to docs 2015-10-21 21:26:16 +02:00
Fabian Affolter ba13f13442 Remove configuration details 2015-10-21 21:12:25 +02:00
Fabian Affolter e615755eb9 Remove configuration details 2015-10-21 21:11:51 +02:00
Fabian Affolter 352d3532e7 Remove configuration details 2015-10-21 21:11:18 +02:00
Fabian Affolter 7b60f6ca77 Remove configuration details 2015-10-21 19:43:24 +02:00
Fabian Affolter a2e8fcbc77 Remove newline 2015-10-21 19:37:34 +02:00
Fabian Affolter e10fd0d28b Remove configuration details 2015-10-21 19:36:52 +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
Fabian Affolter 89964ad793 Remove configuration details 2015-10-21 16:46:31 +02:00
Fabian Affolter bddd02bd58 Remove configuration details 2015-10-21 16:45:45 +02:00
Fabian Affolter cfb3384ee3 Add link to docs 2015-10-21 16:38:33 +02:00
Fabian Affolter 490e9ee95d Add link to docs 2015-10-21 16:37:41 +02:00
Fabian Affolter 0d0eb7e7c0 Add link to docs 2015-10-21 16:10:47 +02:00
Fabian Affolter 3d4af8c229 Remove configuration details 2015-10-21 10:56:32 +02:00
Fabian Affolter 7e23c241da Update docstring 2015-10-21 10:49:25 +02:00
Fabian Affolter 7ec1424825 Add link to docs 2015-10-21 10:47:31 +02:00
Fabian Affolter 9162149598 Add link to docs 2015-10-21 10:47:12 +02:00
Fabian Affolter da31b54d06 Add link to docs 2015-10-21 10:45:08 +02:00
Fabian Affolter b20a757454 Remove configuration details 2015-10-21 10:44:29 +02:00
Fabian Affolter 761f225c86 Update link 2015-10-20 22:20:58 +02:00
Fabian Affolter 5580309d98 Remove configuration details 2015-10-20 22:20:58 +02:00
Fabian Affolter 52b4c3b5a2 Remove configuration details 2015-10-20 22:20:58 +02:00
Fabian Affolter aed61cecff Remove configuration details 2015-10-20 22:20:58 +02:00
Fabian Affolter ef129639bd Remove configuration details 2015-10-20 22:20:58 +02:00
Fabian Affolter f945a3a692 Move configuration details to docs 2015-10-20 22:20:58 +02:00
Fabian Affolter 5e56eae28f Move configuration details to docs 2015-10-20 22:20:58 +02:00
Fabian Affolter 72ad1387f0 Move configuration details to docs 2015-10-20 22:20:58 +02:00
Fabian Affolter 02cfc70ad5 Add link to component 2015-10-20 22:20:58 +02:00
Fabian Affolter 5a21b677a1 Add link to component 2015-10-20 22:20:58 +02:00
Fabian Affolter c1a73d250a Add link to component 2015-10-20 22:20:58 +02:00
Fabian Affolter 8c544a89c9 Remove configuration details 2015-10-20 22:20:58 +02:00
Fabian Affolter c473d426e3 Remove configuration details 2015-10-20 22:20:58 +02:00
Fabian Affolter f5a62f8381 Remove configuration details 2015-10-20 22:20:58 +02:00
Fabian Affolter 0e8e4a73fe Remove configuration details 2015-10-20 22:20:58 +02:00
Fabian Affolter 74700e4b10 Add link to doc and remove configuration details 2015-10-20 22:20:58 +02:00
Fabian Affolter 4d5c9581bf Add link to docs 2015-10-20 22:20:58 +02:00
Fabian Affolter f45e0eabe3 Add link to docs 2015-10-20 22:20:58 +02:00
Fabian Affolter bbed4a262c Fix typo 2015-10-20 22:20:44 +02:00
Fabian Affolter f8590f7d1d Include resource in error message 2015-10-20 22:20:44 +02:00
Nolan Gilley 293ed275ab Added support for specifying units in the configuration file. If no units are specified in the config file it will use location to determine the units. 2015-10-20 14:29:22 -04:00
MakeMeASandwich 2e9ee28637 light/hyperion: use RGB, clean code 2015-10-20 17:30:23 +02:00
Paulus Schoutsen 73cb23f599 Merge pull request #535 from toddeye/radiotherm-dev
radiotherm platform bug fix and configuration parameter
2015-10-19 23:28:10 -07:00
Todd Ingarfield 661f4c594e formatting 2015-10-19 16:54:42 -05:00
Todd Ingarfield 9464e2a13b Add hass configuration parameter hold_temp & config documentation 2015-10-19 16:18:45 -05:00
Todd Ingarfield 27d5248937 Fix configuration for multiple hosts and add example configuration.yaml section 2015-10-19 15:33:23 -05:00
MakeMeASandwich c5a7e3abd1 Merge branch 'dev' of https://github.com/balloob/home-assistant into dev 2015-10-19 20:09:38 +02:00
Paulus Schoutsen 0a6424a81d Merge pull request #529 from persandstrom/lms_pause
bugfix, LMS pause
2015-10-18 13:01:43 -07:00
Per Sandström 5b7389de55 bugfix, 1 = force pause 2015-10-18 21:05:30 +02:00
Paulus Schoutsen 0fe4e0330a Merge pull request #528 from fabaff/arest-sensor
Add pins feature to arest sensor
2015-10-18 10:32:57 -07:00
Fabian Affolter 40b095b866 Add option to use pins 2015-10-18 18:05:25 +02:00
MakeMeASandwich 7141a99927 fix flake warning 2015-10-18 09:10:41 +02:00
Fabian Affolter f01d2b1263 Allow to overwrite the device name 2015-10-18 00:42:02 +02:00
Fabian Affolter 3c6420c538 Allow to overwrite the device name 2015-10-18 00:41:12 +02:00
MakeMeASandwich e3304caf06 add hyperion light support 2015-10-17 19:36:52 +02:00
Fabian Affolter 91a1fb0240 Remove wrong file 2015-10-16 09:12:37 +02:00
Paulus Schoutsen 6fd32e83c8 Update .coveragerc 2015-10-15 13:50:06 -07:00
Paulus Schoutsen b41caa093c Merge pull request #503 from toddeye/radiotherm-platform
Add Radio Thermostat platform
2015-10-15 13:45:52 -07:00
Paulus Schoutsen 806c71c803 Merge pull request #522 from balloob/script-cleanup
Script clean up
2015-10-15 13:44:46 -07:00
Todd Ingarfield b0bafa32b7 fixed typo in requirements_all.txt 2015-10-15 11:44:19 -05:00
Fabian Affolter 332ac794a4 Modify the import style 2015-10-15 18:22:42 +02:00
Paulus Schoutsen 5dfd0d2502 Fix another manual alarm regression 2015-10-15 08:39:38 -07:00
Todd Ingarfield 3d838c307f merged upstream and fixed conflict 2015-10-15 10:13:02 -05:00
Paulus Schoutsen 2dd77f9477 Merge pull request #523 from fabaff/cpuinfo
CPU Speed sensor
2015-10-15 07:33:18 -07:00
sander 6c106a87f1 had to change to let this work on windows. 2015-10-15 15:02:09 +02:00
Fabian Affolter 1279bf7c68 Add py-cpuinfo 2015-10-15 12:13:35 +02:00
Fabian Affolter 323d301072 Add cpuspeed sensor 2015-10-15 12:13:16 +02:00
Fabian Affolter b1815075ac Add cpuspeed sensor 2015-10-15 12:13:04 +02:00
Paulus Schoutsen 7ba4263284 Fix regression manual alarm 2015-10-14 23:38:42 -07:00
Paulus Schoutsen 347597ebdc Base Script on entity 2015-10-14 23:15:48 -07:00
Todd Ingarfield ddeb84cb9c Removed name and netdisco functions, implemented update method to caches values, radiotherm lib to coveragerc and requirements_all.txt 2015-10-14 11:11:33 -05:00
Todd Ingarfield b2e39884f9 Removed name and netdisco functions, implemented update method to caches values, radiotherm lib to coveragerc and requirements_all.txt 2015-10-14 11:02:07 -05:00
Fabian Affolter 8d99c4a0cc Move configuration details to docs 2015-10-14 10:39:51 +02:00
Fabian Affolter 80e4f2f51f Add link to doc 2015-10-14 10:39:51 +02:00
Fabian Affolter 6064fffc8e Move configuration details to docs 2015-10-14 10:39:51 +02:00
Fabian Affolter 7da354c4c5 Move configuration details to docs 2015-10-14 10:39:51 +02:00
Paulus Schoutsen 49de153ecf Add alarm component to demo component 2015-10-13 23:21:47 -07:00
Paulus Schoutsen 716376081d Add tests for MQTT alarm 2015-10-13 23:08:12 -07:00
Paulus Schoutsen d37b70556d manual alarm: Test disarm with invalid code 2015-10-13 22:41:35 -07:00
Paulus Schoutsen 32bb950b5f Add tests for manual alarm control panel platform 2015-10-13 22:36:21 -07:00
Fabian Affolter 0e89418cbe Move configuration desciption to docs 2015-10-13 23:44:27 +02:00
Fabian Affolter fe032be352 Upgrade psutil to 3.2.2 2015-10-13 23:42:27 +02:00
Fabian Affolter 64a78d7b4f Upgrade psutil to 3.2.2 2015-10-13 23:41:46 +02:00
Fabian Affolter 24e4b9e012 Move configuration description to docs 2015-10-13 23:08:56 +02:00
Fabian Affolter a44a39003d Move configuration description to docs 2015-10-13 23:07:26 +02:00
Fabian Affolter f019b4f697 Move configuration details to docs 2015-10-13 22:56:12 +02:00
Fabian Affolter e353dae3a6 Move vonfiguration details to docs 2015-10-13 22:45:36 +02:00
Fabian Affolter fb84c0ce6b Move configuration details to docs 2015-10-13 22:41:53 +02:00
Fabian Affolter fd382871a1 Move configuration details to docs 2015-10-13 22:30:21 +02:00
Fabian Affolter 405025a00b Remove configuration details 2015-10-13 22:26:32 +02:00
Fabian Affolter 912ddbb4fc Add link to docs 2015-10-13 22:26:27 +02:00
Fabian Affolter 91138b8679 Move configuration details to docs 2015-10-13 22:16:26 +02:00
Fabian Affolter 893b9fc8ac Move configuration details to docs 2015-10-13 22:08:11 +02:00
Fabian Affolter 185ba000dd Add link to docs 2015-10-13 21:09:11 +02:00
Fabian Affolter 771118caaf Add link to docs 2015-10-13 21:08:51 +02:00
Fabian Affolter 17d9df0da5 Add link to docs 2015-10-13 21:08:34 +02:00
Fabian Affolter e067398134 Add link to docs 2015-10-13 21:08:18 +02:00
Fabian Affolter cb69ac30ec Add link to docs 2015-10-13 21:07:53 +02:00
Fabian Affolter 241ff45c5e Add link to docs 2015-10-13 21:07:40 +02:00
Fabian Affolter c5c2f0c5f3 Add link to docs 2015-10-13 21:07:24 +02:00
Fabian Affolter 0874cb364f Move configuration details to docs 2015-10-13 21:00:44 +02:00
Fabian Affolter 44418b509c Move configuration details to docs 2015-10-13 21:00:28 +02:00
Fabian Affolter 403889bbeb Move configuration details to docs 2015-10-13 20:55:45 +02:00
Fabian Affolter 6ca50d8b5c Move configuration details to docs 2015-10-13 20:55:15 +02:00
Fabian Affolter 0369a9ee0d Move configuration details to docs 2015-10-13 20:54:48 +02:00
Fabian Affolter 5a6ff9a69a Move configuration details to docs 2015-10-13 20:54:15 +02:00
Fabian Affolter 796cce78bc Move configuration details to docs 2015-10-13 20:52:30 +02:00
Fabian Affolter 77430c0687 Move configuration details to docs 2015-10-13 20:52:08 +02:00
Fabian Affolter c33942d6e2 Move configuration details to docs 2015-10-13 20:51:30 +02:00
Fabian Affolter 3b91f89173 Move configuration details to docs 2015-10-13 20:50:53 +02:00
Fabian Affolter c74f46794e Move configuration details to docs 2015-10-13 20:50:15 +02:00
Fabian Affolter 966fd8f24d Move configuration details to docs 2015-10-13 20:49:28 +02:00
Fabian Affolter 8253fdfc13 Add newline 2015-10-13 20:49:14 +02:00
Fabian Affolter cb7b5f8d15 Move configuration details to docs 2015-10-13 20:45:29 +02:00
Fabian Affolter b0d8eaeda9 Move configuration details to docs 2015-10-13 20:44:18 +02:00
Fabian Affolter 62cfb8aeb2 Move configuration details to docs 2015-10-13 20:42:05 +02:00
Fabian Affolter 47448d1dc0 Add link to docs 2015-10-13 20:40:59 +02:00
Fabian Affolter a583525110 Move configuration details to docs 2015-10-13 20:01:23 +02:00
Paulus Schoutsen 38e1cef30e Update frontend for style fix 2015-10-13 08:58:15 -07:00
Paulus Schoutsen e2f187879c Merge pull request #511 from wind-rider/geofancy
Geofancy
2015-10-13 00:05:17 -07:00
Paulus Schoutsen 925cde200f Merge pull request #514 from balloob/scene-turn-off-remove
Remove turning off scenes
2015-10-12 23:43:29 -07:00
Paulus Schoutsen 383efee470 Scene turn off for frontend 2015-10-12 23:40:09 -07:00
Paulus Schoutsen d5eb90160f Merge pull request #461 from sfam/manual-alarm
Add manual alarm
2015-10-12 23:13:37 -07:00
Paulus Schoutsen 2f946cc6de Merge pull request #516 from mKeRix/dev
Fix for newest tplink firmware, fixes #415
2015-10-12 23:10:30 -07:00
sfam 1b7ce2146c replace sleeps with track_point_in_time 2015-10-13 00:56:24 +00:00
Heiko Rothe 021a374a6a Merge branch 'dev' of https://github.com/mKeRix/home-assistant into dev 2015-10-12 22:44:20 +02:00
Heiko Rothe bbec34d0e6 Merge remote-tracking branch 'refs/remotes/balloob/dev' into dev 2015-10-12 22:43:55 +02:00
Heiko Rothe a6cb19b27d Fixed an issue with the initiation of the new attributes 2015-10-12 22:42:45 +02:00
Hans Bakker b74e70d4e0 Fixes based on balloob's comments 2015-10-12 20:58:24 +02:00
Paulus Schoutsen 5cd283e999 Merge pull request #513 from balloob/component-command
Add shell_command component
2015-10-12 08:43:32 -07:00
Heiko Rothe 2f2bd7a616 Fixed pylint and pep8 violations 2015-10-12 09:18:55 +02:00
Paulus Schoutsen cddc87b0ab Remove turn off from scene 2015-10-11 23:51:59 -07:00
Paulus Schoutsen d6bbc67112 Add tests for scene 2015-10-11 23:48:17 -07:00
Paulus Schoutsen 6d77b15e44 Few more tests 2015-10-11 21:41:44 -07:00
Paulus Schoutsen 916c453d2b Add test for shell command 2015-10-11 21:30:17 -07:00
Paulus Schoutsen 7786b52d93 Add shell_command component 2015-10-11 20:11:30 -07:00
Paulus Schoutsen 90d4a2c0b8 Update frontend version 2015-10-11 20:10:32 -07:00
Paulus Schoutsen b6d26597c0 Automation - state platfor: Flag if user makes config error 2015-10-11 18:30:25 -07:00
Paulus Schoutsen bf1970b78c Make thermostat more robust 2015-10-11 18:16:55 -07:00
Hans Bakker 1eb3610a11 Style fixes 2015-10-12 00:28:39 +02:00
Paulus Schoutsen f081f7c4ff Merge pull request #494 from andythigpen/mysensors-update
Update to latest mysensors library.
2015-10-11 15:14:23 -07:00
Hans Bakker 6a969208e9 Initial commit for Geofancy device tracker. 2015-10-12 00:14:05 +02:00
Andrew Thigpen 384b3d0d17 Update to latest mysensors library.
* Adds JSON persistence support.
* Adds documentation comments for configuration options.
2015-10-11 17:05:08 -05:00
Paulus Schoutsen ad5b650661 Merge pull request #504 from happyleavesaoc/dev
Amazon Fire TV device support
2015-10-11 14:54:55 -07:00
Paulus Schoutsen b05f2e3221 Fix style issue 2015-10-11 11:04:16 -07:00
Paulus Schoutsen dcfc91e71c Fix throttle applied to methods 2015-10-11 10:42:42 -07:00
Todd Ingarfield 6c1c243000 start away mode 2015-10-11 11:42:24 -05:00
Paulus Schoutsen c2117b3eaf Merge pull request #507 from gsabbe/dev
asuswrt gives a traceback when ipv6 is enabled on the router
2015-10-11 09:26:11 -07:00
Todd Ingarfield 84c72ebf63 Add support for multiple thermostats (via hass-config) and auto-discovery via ratiotherm module 2015-10-11 09:28:25 -05:00
Guillaume SABBE a1e5bea3ab When IPv6 is enabled, dnsmasq has a configuration line with the DUID.
This looks like this
61072 b8:27:eb:e1:4e:4d 192.168.0.4 domotycoon *
61072 b8:27:eb:b8:10:6b 192.168.0.5 pimonitor *
duid 00:03:00:01:ac:22:0b:e9:98:50
When using match.group() without testing if match != None, you get a traceback.
2015-10-11 15:21:53 +02:00
Hans Bakker bee5c0adfb Merge branch 'dev' of https://github.com/balloob/home-assistant 2015-10-10 23:40:59 +02:00
happyleavesaoc 7ca21f577d fixed merge conflict 2015-10-10 16:53:55 -04:00
happyleavesaoc 168516f5da addressed PR comments 2015-10-10 16:45:13 -04:00
Paulus Schoutsen 94df5acbf3 Version bump to 0.7.6.dev0 2015-10-10 11:45:25 -07:00
Todd Ingarfield 37278aab20 add set_time and begin discovery 2015-10-10 11:36:34 -05:00
happyleavesaoc d4d91bfdbb Amazon Fire TV device support 2015-10-09 17:06:35 -04:00
Todd Ingarfield a3d295d885 Correct formatting 2015-10-09 11:38:39 -05:00
Todd Ingarfield 0cf909cce9 Correct ci failed tests 2015-10-09 11:34:14 -05:00
Todd Ingarfield fc1cf49fd3 added REQUIREMENTS for radiotherm python module 2015-10-09 10:49:54 -05:00
Todd Ingarfield e5d68d8a1e set name of device through hass config 2015-10-09 10:43:14 -05:00
Todd Ingarfield 4ac9e9fc4c initial commit 2015-10-08 17:48:03 -05:00
sfam e57b3ae847 add manual alarm 2015-09-28 23:36:46 +00:00
Heiko Rothe 1553844279 Added support for the newest tp-link firmware
Currently this seemingly only applies to the Archer C9
2015-09-22 22:48:43 +02:00
Heiko Rothe 582ed1fc8d Merge remote-tracking branch 'balloob/dev' into dev 2015-09-22 19:48:39 +02:00
208 changed files with 7986 additions and 6620 deletions
+12
View File
@@ -36,9 +36,12 @@ omit =
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
@@ -47,10 +50,13 @@ omit =
homeassistant/components/downloader.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
homeassistant/components/media_player/cast.py
homeassistant/components/media_player/denon.py
homeassistant/components/media_player/firetv.py
homeassistant/components/media_player/itunes.py
homeassistant/components/media_player/kodi.py
homeassistant/components/media_player/mpd.py
@@ -61,6 +67,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
@@ -70,12 +77,14 @@ omit =
homeassistant/components/sensor/arest.py
homeassistant/components/sensor/bitcoin.py
homeassistant/components/sensor/command_sensor.py
homeassistant/components/sensor/cpuspeed.py
homeassistant/components/sensor/dht.py
homeassistant/components/sensor/efergy.py
homeassistant/components/sensor/forecast.py
homeassistant/components/sensor/glances.py
homeassistant/components/sensor/mysensors.py
homeassistant/components/sensor/openweathermap.py
homeassistant/components/switch/orvibo.py
homeassistant/components/sensor/rest.py
homeassistant/components/sensor/rpi_gpio.py
homeassistant/components/sensor/sabnzbd.py
@@ -89,10 +98,13 @@ omit =
homeassistant/components/switch/command_switch.py
homeassistant/components/switch/edimax.py
homeassistant/components/switch/hikvisioncam.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/honeywell.py
homeassistant/components/thermostat/nest.py
homeassistant/components/thermostat/radiotherm.py
[report]
+8 -8
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).
- Make sure all your code passes Pylint and flake8 (PEP8 and some more) validation. To generate reports, run `pylint homeassistant > pylint.txt` and `flake8 homeassistant --exclude bower_components,external > flake8.txt`.
- 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:
+5 -6
View File
@@ -10,11 +10,10 @@ 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/*
# Open Z-Wave disabled because broken
#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 && \
# scripts/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
CMD [ "python", "-m", "homeassistant", "--config", "/config" ]
+2 -3
View File
@@ -17,9 +17,8 @@ Check out [the website](https://home-assistant.io) for [a demo][demo], installat
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/), and iTunes (by way of [itunes-api](https://github.com/maddox/itunes-api))
* [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).
+33 -5
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):
@@ -167,6 +169,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 +255,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 +283,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
@@ -8,7 +8,7 @@ import os
from homeassistant.components import verisure
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_ENTITY_ID, SERVICE_ALARM_TRIGGER,
SERVICE_ALARM_DISARM, SERVICE_ALARM_ARM_HOME, SERVICE_ALARM_ARM_AWAY)
from homeassistant.config import load_yaml_config_file
from homeassistant.helpers.entity import Entity
@@ -29,6 +29,7 @@ SERVICE_TO_METHOD = {
SERVICE_ALARM_DISARM: 'alarm_disarm',
SERVICE_ALARM_ARM_HOME: 'alarm_arm_home',
SERVICE_ALARM_ARM_AWAY: 'alarm_arm_away',
SERVICE_ALARM_TRIGGER: 'alarm_trigger'
}
ATTR_CODE = 'code'
@@ -53,9 +54,9 @@ def setup(hass, config):
target_alarms = component.extract_from_service(service)
if ATTR_CODE not in service.data:
return
code = service.data[ATTR_CODE]
code = None
else:
code = service.data[ATTR_CODE]
method = SERVICE_TO_METHOD[service.service]
@@ -72,36 +73,50 @@ def setup(hass, config):
return True
def alarm_disarm(hass, code, entity_id=None):
def alarm_disarm(hass, code=None, entity_id=None):
""" Send the alarm the command for disarm. """
data = {ATTR_CODE: code}
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_DISARM, data)
def alarm_arm_home(hass, code, entity_id=None):
def alarm_arm_home(hass, code=None, entity_id=None):
""" Send the alarm the command for arm home. """
data = {ATTR_CODE: code}
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_ARM_HOME, data)
def alarm_arm_away(hass, code, entity_id=None):
def alarm_arm_away(hass, code=None, entity_id=None):
""" Send the alarm the command for arm away. """
data = {ATTR_CODE: code}
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_ARM_AWAY, data)
def alarm_trigger(hass, code=None, entity_id=None):
""" Send the alarm the command for trigger. """
data = {}
if code:
data[ATTR_CODE] = code
if entity_id:
data[ATTR_ENTITY_ID] = entity_id
hass.services.call(DOMAIN, SERVICE_ALARM_TRIGGER, data)
# pylint: disable=no-self-use
class AlarmControlPanel(Entity):
""" ABC for alarm control devices. """
@@ -123,6 +138,10 @@ class AlarmControlPanel(Entity):
""" Send arm away command. """
raise NotImplementedError()
def alarm_trigger(self, code=None):
""" Send alarm trigger command. """
raise NotImplementedError()
@property
def state_attributes(self):
""" Return the state attributes. """
@@ -0,0 +1,149 @@
"""
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/
"""
import logging
import datetime
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.helpers.event import track_point_in_time
import homeassistant.util.dt as dt_util
from homeassistant.const import (
STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED)
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = []
DEFAULT_ALARM_NAME = 'HA Alarm'
DEFAULT_PENDING_TIME = 60
DEFAULT_TRIGGER_TIME = 120
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the manual alarm platform. """
add_devices([ManualAlarm(
hass,
config.get('name', DEFAULT_ALARM_NAME),
config.get('code'),
config.get('pending_time', DEFAULT_PENDING_TIME),
config.get('trigger_time', DEFAULT_TRIGGER_TIME),
)])
# pylint: disable=too-many-arguments, too-many-instance-attributes
# pylint: disable=abstract-method
class ManualAlarm(alarm.AlarmControlPanel):
"""
Represents an alarm status.
When armed, will be pending for 'pending_time', after that armed.
When triggered, will be pending for 'trigger_time'. After that will be
triggered for 'trigger_time', after that we return to disarmed.
"""
def __init__(self, hass, name, code, pending_time, trigger_time):
self._state = STATE_ALARM_DISARMED
self._hass = hass
self._name = name
self._code = str(code) if code else None
self._pending_time = datetime.timedelta(seconds=pending_time)
self._trigger_time = datetime.timedelta(seconds=trigger_time)
self._state_ts = None
@property
def should_poll(self):
""" No polling needed. """
return False
@property
def name(self):
""" Returns the name of the device. """
return self._name
@property
def state(self):
""" Returns the state of the device. """
if self._state in (STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY) and \
self._pending_time and self._state_ts + self._pending_time > \
dt_util.utcnow():
return STATE_ALARM_PENDING
if self._state == STATE_ALARM_TRIGGERED and self._trigger_time:
if self._state_ts + self._pending_time > dt_util.utcnow():
return STATE_ALARM_PENDING
elif (self._state_ts + self._pending_time +
self._trigger_time) < dt_util.utcnow():
return STATE_ALARM_DISARMED
return self._state
@property
def code_format(self):
""" One or more characters. """
return None if self._code is None else '.+'
def alarm_disarm(self, code=None):
""" Send disarm command. """
if not self._validate_code(code, STATE_ALARM_DISARMED):
return
self._state = STATE_ALARM_DISARMED
self._state_ts = dt_util.utcnow()
self.update_ha_state()
def alarm_arm_home(self, code=None):
""" Send arm home command. """
if not self._validate_code(code, STATE_ALARM_ARMED_HOME):
return
self._state = STATE_ALARM_ARMED_HOME
self._state_ts = dt_util.utcnow()
self.update_ha_state()
if self._pending_time:
track_point_in_time(
self._hass, self.update_ha_state,
self._state_ts + self._pending_time)
def alarm_arm_away(self, code=None):
""" Send arm away command. """
if not self._validate_code(code, STATE_ALARM_ARMED_AWAY):
return
self._state = STATE_ALARM_ARMED_AWAY
self._state_ts = dt_util.utcnow()
self.update_ha_state()
if self._pending_time:
track_point_in_time(
self._hass, self.update_ha_state,
self._state_ts + self._pending_time)
def alarm_trigger(self, code=None):
""" Send alarm trigger command. No code needed. """
self._state = STATE_ALARM_TRIGGERED
self._state_ts = dt_util.utcnow()
self.update_ha_state()
if self._trigger_time:
track_point_in_time(
self._hass, self.update_ha_state,
self._state_ts + self._pending_time)
track_point_in_time(
self._hass, self.update_ha_state,
self._state_ts + self._pending_time + self._trigger_time)
def _validate_code(self, code, state):
""" Validate given code. """
check = self._code is None or code == self._code
if not check:
_LOGGER.warning('Invalid code given for %s', state)
return check
@@ -1,68 +1,18 @@
"""
homeassistant.components.alarm_control_panel.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This platform enables the possibility to control a MQTT alarm.
In this platform, 'state_topic' and 'command_topic' are required.
The alarm will only change state after receiving the a new state
from 'state_topic'. If these messages are published with RETAIN flag,
the MQTT alarm will receive an instant state update after subscription
and will start with correct state. Otherwise, the initial state will
be 'unknown'.
Configuration:
alarm_control_panel:
platform: mqtt
name: "MQTT Alarm"
state_topic: "home/alarm"
command_topic: "home/alarm/set"
qos: 0
payload_disarm: "DISARM"
payload_arm_home: "ARM_HOME"
payload_arm_away: "ARM_AWAY"
code: "mySecretCode"
Variables:
name
*Optional
The name of the alarm. Default is 'MQTT Alarm'.
state_topic
*Required
The MQTT topic subscribed to receive state updates.
command_topic
*Required
The MQTT topic to publish commands to change the alarm state.
qos
*Optional
The maximum QoS level of the state topic. Default is 0.
This QoS will also be used to publishing messages.
payload_disarm
*Optional
The payload do disarm alarm. Default is "DISARM".
payload_arm_home
*Optional
The payload to set armed-home mode. Default is "ARM_HOME".
payload_arm_away
*Optional
The payload to set armed-away mode. Default is "ARM_AWAY".
code
*Optional
If defined, specifies a code to enable or disable the alarm in the frontend.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.mqtt/
"""
import logging
import homeassistant.components.mqtt as mqtt
import homeassistant.components.alarm_control_panel as alarm
from homeassistant.const import (STATE_UNKNOWN)
from homeassistant.const import (
STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED, STATE_UNKNOWN)
_LOGGER = logging.getLogger(__name__)
@@ -99,6 +49,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
# pylint: disable=too-many-arguments, too-many-instance-attributes
# pylint: disable=abstract-method
class MqttAlarm(alarm.AlarmControlPanel):
""" represents a MQTT alarm status within home assistant. """
@@ -113,10 +64,15 @@ class MqttAlarm(alarm.AlarmControlPanel):
self._payload_disarm = payload_disarm
self._payload_arm_home = payload_arm_home
self._payload_arm_away = payload_arm_away
self._code = code
self._code = str(code) if code else None
def message_received(topic, payload, qos):
""" A new MQTT message has been received. """
if payload not in (STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_AWAY, STATE_ALARM_PENDING,
STATE_ALARM_TRIGGERED):
_LOGGER.warning('Received unexpected payload: %s', payload)
return
self._state = payload
self.update_ha_state()
@@ -144,24 +100,28 @@ class MqttAlarm(alarm.AlarmControlPanel):
def alarm_disarm(self, code=None):
""" Send disarm command. """
if code == str(self._code) or self.code_format is None:
mqtt.publish(self.hass, self._command_topic,
self._payload_disarm, self._qos)
else:
_LOGGER.warning("Wrong code entered while disarming!")
if not self._validate_code(code, 'disarming'):
return
mqtt.publish(self.hass, self._command_topic,
self._payload_disarm, self._qos)
def alarm_arm_home(self, code=None):
""" Send arm home command. """
if code == str(self._code) or self.code_format is None:
mqtt.publish(self.hass, self._command_topic,
self._payload_arm_home, self._qos)
else:
_LOGGER.warning("Wrong code entered while arming home!")
if not self._validate_code(code, 'arming home'):
return
mqtt.publish(self.hass, self._command_topic,
self._payload_arm_home, self._qos)
def alarm_arm_away(self, code=None):
""" Send arm away command. """
if code == str(self._code) or self.code_format is None:
mqtt.publish(self.hass, self._command_topic,
self._payload_arm_away, self._qos)
else:
_LOGGER.warning("Wrong code entered while arming away!")
if not self._validate_code(code, 'arming away'):
return
mqtt.publish(self.hass, self._command_topic,
self._payload_arm_away, self._qos)
def _validate_code(self, code, state):
""" Validate given code. """
check = self._code is None or code == self._code
if not check:
_LOGGER.warning('Wrong code entered for %s', state)
return check
@@ -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
@@ -33,6 +36,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
add_devices(alarms)
# pylint: disable=abstract-method
class VerisureAlarm(alarm.AlarmControlPanel):
""" Represents a Verisure alarm status. """
+16 -3
View File
@@ -1,8 +1,10 @@
"""
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/
"""
import re
import logging
@@ -12,13 +14,14 @@ 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,
EVENT_TIME_CHANGED, EVENT_HOMEASSISTANT_STOP, MATCH_ALL,
HTTP_OK, HTTP_CREATED, HTTP_BAD_REQUEST, HTTP_NOT_FOUND,
HTTP_UNPROCESSABLE_ENTITY)
HTTP_UNPROCESSABLE_ENTITY, CONTENT_TYPE_TEXT_PLAIN)
DOMAIN = 'api'
@@ -87,6 +90,9 @@ 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)
return True
@@ -339,6 +345,13 @@ 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. """
error_path = handler.server.hass.config.path(ERROR_LOG_FILENAME)
with open(error_path, 'rb') as error_log:
handler.write_file_pointer(CONTENT_TYPE_TEXT_PLAIN, error_log)
def _services_json(hass):
""" Generate services data to JSONify. """
return [{"domain": key, "services": value}
+2 -20
View File
@@ -4,26 +4,8 @@ components.arduino
Arduino component that connects to a directly attached Arduino board which
runs with the Firmata firmware.
Configuration:
To use the Arduino board you will need to add something like the following
to your configuration.yaml file.
arduino:
port: /dev/ttyACM0
Variables:
port
*Required
The port where is your board connected to your Home Assistant system.
If you are using an original Arduino the port will be named ttyACM*. The exact
number can be determined with 'ls /dev/ttyACM*' or check your 'dmesg'/
'journalctl -f' output. Keep in mind that Arduino clones are often using a
different name for the port (e.g. '/dev/ttyUSB*').
A word of caution: The Arduino is not storing states. This means that with
every initialization the pins are set to off/low.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/arduino/
"""
import logging
@@ -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
+3 -1
View File
@@ -1,8 +1,10 @@
"""
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/#event-trigger
"""
import logging
+3 -1
View File
@@ -1,8 +1,10 @@
"""
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/#mqtt-trigger
"""
import logging
@@ -1,8 +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/#numeric-state-trigger
"""
import logging
+8 -1
View File
@@ -1,8 +1,10 @@
"""
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/#state-trigger
"""
import logging
@@ -28,6 +30,11 @@ def trigger(hass, config, action):
from_state = config.get(CONF_FROM, MATCH_ALL)
to_state = config.get(CONF_TO) or config.get(CONF_STATE) or MATCH_ALL
if isinstance(from_state, bool) or isinstance(to_state, bool):
logging.getLogger(__name__).error(
'Config error. Surround to/from values with quotes.')
return False
def state_automation_listener(entity, from_s, to_s):
""" Listens for state changes and calls action. """
action()
+3 -1
View File
@@ -1,8 +1,10 @@
"""
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/#sun-trigger
"""
import logging
from datetime import timedelta
+3 -1
View File
@@ -1,8 +1,10 @@
"""
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/#time-trigger
"""
import logging
+3 -1
View File
@@ -1,8 +1,10 @@
"""
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/#zone-trigger
"""
import logging
+3 -1
View File
@@ -1,8 +1,10 @@
"""
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"
+8 -20
View File
@@ -4,24 +4,8 @@ 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
@@ -103,7 +87,10 @@ def setup(hass, config):
if camera:
response = camera.camera_image()
handler.wfile.write(response)
if response is not None:
handler.wfile.write(response)
else:
handler.send_response(HTTP_NOT_FOUND)
else:
handler.send_response(HTTP_NOT_FOUND)
@@ -145,7 +132,8 @@ def setup(hass, config):
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',
+3 -48
View File
@@ -3,51 +3,14 @@ homeassistant.components.camera.foscam
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This component provides basic support for Foscam IP cameras.
As part of the basic support the following features will be provided:
-MJPEG video streaming
To use this component, add the following to your configuration.yaml file.
camera:
platform: foscam
name: Door Camera
ip: 192.168.0.123
port: 88
username: YOUR_USERNAME
password: YOUR_PASSWORD
Variables:
ip
*Required
The IP address of your Foscam device.
username
*Required
The username of a visitor or operator of your camera. Oddly admin accounts
don't seem to have access to take snapshots.
password
*Required
The password for accessing your camera.
name
*Optional
This parameter allows you to override the name of your camera in homeassistant.
port
*Optional
The port that the camera is running on. The default is 88.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.foscam.html
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
_LOGGER = logging.getLogger(__name__)
@@ -76,7 +39,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')
@@ -86,17 +49,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
+14 -41
View File
@@ -3,43 +3,8 @@ homeassistant.components.camera.generic
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for IP Cameras.
This component provides basic support for IP cameras. For the basic support to
work you camera must support accessing a JPEG snapshot via a URL and you will
need to specify the "still_image_url" parameter which should be the location of
the JPEG image.
As part of the basic support the following features will be provided:
- MJPEG video streaming
- Saving a snapshot
- Recording(JPEG frame capture)
To use this component, add the following to your configuration.yaml file.
camera:
platform: generic
name: Door Camera
username: YOUR_USERNAME
password: YOUR_PASSWORD
still_image_url: http://YOUR_CAMERA_IP_AND_PORT/image.jpg
Variables:
still_image_url
*Required
The URL your camera serves the image on, eg. http://192.168.1.21:2112/
name
*Optional
This parameter allows you to override the name of your camera in Home
Assistant.
username
*Optional
The username for accessing your camera.
password
*Optional
The password for accessing your camera.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/camera.generic/
"""
import logging
from requests.auth import HTTPBasicAuth
@@ -77,11 +42,19 @@ class GenericCamera(Camera):
def camera_image(self):
""" Return a still image reponse 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
+71
View File
@@ -0,0 +1,71 @@
"""
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/
"""
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 contextlib import closing
_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
+3 -2
View File
@@ -1,9 +1,10 @@
"""
homeassistant.components.conversation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to have conversations with Home Assistant.
This is more a proof of concept.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/conversation/
"""
import logging
import re
+12 -22
View File
@@ -10,14 +10,15 @@ 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']
'device_tracker', 'light', 'media_player', 'notify', 'switch', 'sensor',
'thermostat']
def setup(hass, config):
@@ -63,6 +64,14 @@ def setup(hass, config):
'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',
@@ -102,25 +111,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
@@ -4,41 +4,8 @@ homeassistant.components.device_tracker.actiontec
Device tracker platform that supports scanning an Actiontec MI424WR
(Verizon FIOS) router for device presence.
This device tracker needs telnet to be enabled on the router.
Configuration:
To use the Actiontec tracker you will need to add something like the
following to your configuration.yaml file. If you experience disconnects
you can modify the home_interval variable.
device_tracker:
platform: actiontec
host: YOUR_ROUTER_IP
username: YOUR_ADMIN_USERNAME
password: YOUR_ADMIN_PASSWORD
# optional:
home_interval: 10
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.
home_interval
*Optional
If the home_interval is set then the component will not let a device
be AWAY if it has been HOME in the last home_interval minutes. This is
in addition to the 3 minute wait built into the device_tracker component.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.actiontec/
"""
import logging
from datetime import timedelta
@@ -50,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
@@ -73,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"])
@@ -91,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):
"""
@@ -133,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
@@ -186,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
@@ -4,33 +4,8 @@ homeassistant.components.device_tracker.aruba
Device tracker platform that supports scanning a Aruba Access Point for device
presence.
This device tracker needs telnet to be enabled on the router.
Configuration:
To use the Aruba tracker you will need to add something like the following
to your configuration.yaml file. You also need to enable Telnet in the
configuration page of your router.
device_tracker:
platform: aruba
host: YOUR_ACCESS_POINT_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.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,6 +134,10 @@ 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
@@ -174,6 +154,9 @@ class AsusWrtDeviceScanner(object):
for neighbor in neighbors:
match = _IP_NEIGH_REGEX.search(neighbor.decode('utf-8'))
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
@@ -4,30 +4,8 @@ homeassistant.components.device_tracker.ddwrt
Device tracker platform that supports scanning a DD-WRT router for device
presence.
Configuration:
To use the DD-WRT tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: ddwrt
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.ddwrt/
"""
import logging
from datetime import timedelta
@@ -1,7 +1,6 @@
"""
homeassistant.components.device_tracker.demo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo platform for the device tracker.
device_tracker:
@@ -0,0 +1,70 @@
"""
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/
"""
from homeassistant.const import (
HTTP_UNPROCESSABLE_ENTITY, HTTP_INTERNAL_SERVER_ERROR)
DEPENDENCIES = ['http']
_SEE = 0
URL_API_GEOFANCY_ENDPOINT = "/api/geofancy"
def setup_scanner(hass, config, see):
""" Set up an endpoint for the Geofancy app. """
# Use a global variable to keep setup_scanner compact when using a callback
global _SEE
_SEE = see
# POST would be semantically better, but that currently does not work
# since Geofancy sends the data as key1=value1&key2=value2
# in the request body, while Home Assistant expects json there.
hass.http.register_path(
'GET', URL_API_GEOFANCY_ENDPOINT, _handle_get_api_geofancy)
return True
def _handle_get_api_geofancy(handler, path_match, data):
""" Geofancy message received. """
if not isinstance(data, dict):
handler.write_json_message(
"Error while parsing Geofancy message.",
HTTP_INTERNAL_SERVER_ERROR)
return
if 'latitude' not in data or 'longitude' not in data:
handler.write_json_message(
"Location not specified.",
HTTP_UNPROCESSABLE_ENTITY)
return
if 'device' not in data or 'id' not in data:
handler.write_json_message(
"Device id or location id not specified.",
HTTP_UNPROCESSABLE_ENTITY)
return
try:
gps_coords = (float(data['latitude']), float(data['longitude']))
except ValueError:
# If invalid latitude / longitude format
handler.write_json_message(
"Invalid latitude / longitude format.",
HTTP_UNPROCESSABLE_ENTITY)
return
# entity id's in Home Assistant must be alphanumerical
device_uuid = data['device']
device_entity_id = device_uuid.replace('-', '')
_SEE(dev_id=device_entity_id, gps=gps_coords, location_name=data['id'])
handler.write_json_message("Geofancy message processed")
@@ -4,33 +4,8 @@ homeassistant.components.device_tracker.luci
Device tracker platform that supports scanning a OpenWRT router for device
presence.
It's required that the luci RPC package is installed on the OpenWRT router:
# opkg install luci-mod-rpc
Configuration:
To use the Luci tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: luci
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.luci/
"""
import logging
import json
@@ -1,15 +1,10 @@
"""
homeassistant.components.device_tracker.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MQTT platform for the device tracker.
device_tracker:
platform: mqtt
qos: 1
devices:
paulus_oneplus: /location/paulus
annetherese_n4: /location/annetherese
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.mqtt/
"""
import logging
from homeassistant import util
@@ -4,30 +4,8 @@ homeassistant.components.device_tracker.netgear
Device tracker platform that supports scanning a Netgear router for device
presence.
Configuration:
To use the Netgear tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: netgear
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.netgear/
"""
import logging
from datetime import timedelta
@@ -3,26 +3,8 @@ homeassistant.components.device_tracker.nmap
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Device tracker platform that supports scanning a network with nmap.
Configuration:
To use the nmap tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: nmap_tracker
hosts: 192.168.1.1/24
Variables:
hosts
*Required
The IP addresses to scan in the network-prefix notation (192.168.1.1/24) or
the range notation (192.168.1.1-255).
home_interval
*Optional
Number of minutes it will not scan devices that it found in previous results.
This is to save battery.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.nmap_scanner/
"""
import logging
from datetime import timedelta
@@ -1,11 +1,10 @@
"""
homeassistant.components.device_tracker.owntracks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OwnTracks platform for the device tracker.
device_tracker:
platform: owntracks
For more details about this platform, please refer to the documentation at
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)
@@ -4,32 +4,8 @@ homeassistant.components.device_tracker.thomson
Device tracker platform that supports scanning a THOMSON router for device
presence.
This device tracker needs telnet to be enabled on the router.
Configuration:
To use the THOMSON tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: thomson
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.thomson/
"""
import logging
from datetime import timedelta
@@ -4,36 +4,8 @@ homeassistant.components.device_tracker.tomato
Device tracker platform that supports scanning a Tomato router for device
presence.
Configuration:
To use the Tomato tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: tomato
host: YOUR_ROUTER_IP
username: YOUR_ADMIN_USERNAME
password: YOUR_ADMIN_PASSWORD
http_id: ABCDEFG
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.
http_id
*Required
The value can be obtained by logging in to the Tomato admin interface and
search for http_id in the page source code.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/device_tracker.tomato/
"""
import logging
import json
+122 -29
View File
@@ -4,30 +4,8 @@ homeassistant.components.device_tracker.tplink
Device tracker platform that supports scanning a TP-Link router for device
presence.
Configuration:
To use the TP-Link tracker you will need to add something like the following
to your configuration.yaml file.
device_tracker:
platform: tplink
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.tplink/
"""
import base64
import logging
@@ -54,10 +32,13 @@ def get_scanner(hass, config):
_LOGGER):
return None
scanner = Tplink2DeviceScanner(config[DOMAIN])
scanner = Tplink3DeviceScanner(config[DOMAIN])
if not scanner.success_init:
scanner = TplinkDeviceScanner(config[DOMAIN])
scanner = Tplink2DeviceScanner(config[DOMAIN])
if not scanner.success_init:
scanner = TplinkDeviceScanner(config[DOMAIN])
return scanner if scanner.success_init else None
@@ -156,7 +137,7 @@ class Tplink2DeviceScanner(TplinkDeviceScanner):
with self.lock:
_LOGGER.info("Loading wireless clients...")
url = 'http://{}/data/map_access_wireless_client_grid.json'\
url = 'http://{}/data/map_access_wireless_client_grid.json' \
.format(self.host)
referer = 'http://{}'.format(self.host)
@@ -166,7 +147,7 @@ class Tplink2DeviceScanner(TplinkDeviceScanner):
b64_encoded_username_password = base64.b64encode(
username_password.encode('ascii')
).decode('ascii')
cookie = 'Authorization=Basic {}'\
cookie = 'Authorization=Basic {}' \
.format(b64_encoded_username_password)
response = requests.post(url, headers={'referer': referer,
@@ -183,7 +164,119 @@ class Tplink2DeviceScanner(TplinkDeviceScanner):
self.last_results = {
device['mac_addr'].replace('-', ':'): device['name']
for device in result
}
}
return True
return False
class Tplink3DeviceScanner(TplinkDeviceScanner):
"""
This class queries the Archer C9 router running version 150811 or higher
of TP-Link firmware for connected devices.
"""
def __init__(self, config):
self.stok = ''
self.sysauth = ''
super(Tplink3DeviceScanner, self).__init__(config)
def scan_devices(self):
"""
Scans for new devices and return a list containing found device ids.
"""
self._update_info()
return self.last_results.keys()
# pylint: disable=no-self-use
def get_device_name(self, device):
"""
The TP-Link firmware doesn't save the name of the wireless device.
We are forced to use the MAC address as name here.
"""
return self.last_results.get(device)
def _get_auth_tokens(self):
"""
Retrieves auth tokens from the router.
"""
_LOGGER.info("Retrieving auth tokens...")
url = 'http://{}/cgi-bin/luci/;stok=/login?form=login' \
.format(self.host)
referer = 'http://{}/webpages/login.html'.format(self.host)
# if possible implement rsa encryption of password here
response = requests.post(url,
params={'operation': 'login',
'username': self.username,
'password': self.password},
headers={'referer': referer})
try:
self.stok = response.json().get('data').get('stok')
_LOGGER.info(self.stok)
regex_result = re.search('sysauth=(.*);',
response.headers['set-cookie'])
self.sysauth = regex_result.group(1)
_LOGGER.info(self.sysauth)
return True
except ValueError:
_LOGGER.error("Couldn't fetch auth tokens!")
return False
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Ensures the information from the TP-Link router is up to date.
Returns boolean if scanning successful.
"""
with self.lock:
if (self.stok == '') or (self.sysauth == ''):
self._get_auth_tokens()
_LOGGER.info("Loading wireless clients...")
url = 'http://{}/cgi-bin/luci/;stok={}/admin/wireless?form=statistics' \
.format(self.host, self.stok)
referer = 'http://{}/webpages/index.html'.format(self.host)
response = requests.post(url,
params={'operation': 'load'},
headers={'referer': referer},
cookies={'sysauth': self.sysauth})
try:
json_response = response.json()
if json_response.get('success'):
result = response.json().get('data')
else:
if json_response.get('errorcode') == 'timeout':
_LOGGER.info("Token timed out. "
"Relogging on next scan.")
self.stok = ''
self.sysauth = ''
return False
else:
_LOGGER.error("An unknown error happened "
"while fetching data.")
return False
except ValueError:
_LOGGER.error("Router didn't respond with JSON. "
"Check if credentials are correct.")
return False
if result:
self.last_results = {
device['mac'].replace('-', ':'): device['mac']
for device in result
}
return True
return False
@@ -0,0 +1,173 @@
"""
homeassistant.components.device_tracker.ubus
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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/
"""
import logging
import json
from datetime import timedelta
import re
import threading
import requests
from homeassistant.const import CONF_HOST, CONF_USERNAME, CONF_PASSWORD
from homeassistant.helpers import validate_config
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)
_LOGGER = logging.getLogger(__name__)
def get_scanner(hass, config):
""" Validates config and returns a Luci scanner. """
if not validate_config(config,
{DOMAIN: [CONF_HOST, CONF_USERNAME, CONF_PASSWORD]},
_LOGGER):
return None
scanner = UbusDeviceScanner(config[DOMAIN])
return scanner if scanner.success_init else None
# pylint: disable=too-many-instance-attributes
class UbusDeviceScanner(object):
"""
This class queries a wireless router running OpenWrt firmware
for connected devices. Adapted from Tomato scanner.
Configure your routers' ubus ACL based on following instructions:
http://wiki.openwrt.org/doc/techref/ubus
Read only access will be fine.
To use this class you have to install rpcd-mod-file package
in your OpenWrt router:
opkg install rpcd-mod-file
"""
def __init__(self, config):
host = config[CONF_HOST]
username, password = config[CONF_USERNAME], config[CONF_PASSWORD]
self.parse_api_pattern = re.compile(r"(?P<param>\w*) = (?P<value>.*);")
self.lock = threading.Lock()
self.last_results = {}
self.url = 'http://{}/ubus'.format(host)
self.session_id = _get_session_id(self.url, username, password)
self.hostapd = []
self.leasefile = None
self.mac2name = None
self.success_init = self.session_id is not None
def scan_devices(self):
"""
Scans for new devices and return a list containing found device ids.
"""
self._update_info()
return self.last_results
def get_device_name(self, device):
""" Returns the name of the given device or None if we don't know. """
with self.lock:
if self.leasefile is None:
result = _req_json_rpc(self.url, self.session_id,
'call', 'uci', 'get',
config="dhcp", type="dnsmasq")
if result:
values = result["values"].values()
self.leasefile = next(iter(values))["leasefile"]
else:
return
if self.mac2name is None:
result = _req_json_rpc(self.url, self.session_id,
'call', 'file', 'read',
path=self.leasefile)
if result:
self.mac2name = dict()
for line in result["data"].splitlines():
hosts = line.split(" ")
self.mac2name[hosts[1].upper()] = hosts[3]
else:
# Error, handled in the _req_json_rpc
return
return self.mac2name.get(device.upper(), None)
@Throttle(MIN_TIME_BETWEEN_SCANS)
def _update_info(self):
"""
Ensures the information from the Luci router is up to date.
Returns boolean if scanning successful.
"""
if not self.success_init:
return False
with self.lock:
_LOGGER.info("Checking ARP")
if not self.hostapd:
hostapd = _req_json_rpc(self.url, self.session_id,
'list', 'hostapd.*', '')
self.hostapd.extend(hostapd.keys())
self.last_results = []
results = 0
for hostapd in self.hostapd:
result = _req_json_rpc(self.url, self.session_id,
'call', hostapd, 'get_clients')
if result:
results = results + 1
self.last_results.extend(result['clients'].keys())
return bool(results)
def _req_json_rpc(url, session_id, rpcmethod, subsystem, method, **params):
""" Perform one JSON RPC operation. """
data = json.dumps({"jsonrpc": "2.0",
"id": 1,
"method": rpcmethod,
"params": [session_id,
subsystem,
method,
params]})
try:
res = requests.post(url, data=data, timeout=5)
except requests.exceptions.Timeout:
return
if res.status_code == 200:
response = res.json()
if rpcmethod == "call":
return response["result"][1]
else:
return response["result"]
def _get_session_id(url, username, password):
""" Get authentication token for the given host+username+password. """
res = _req_json_rpc(url, "00000000000000000000000000000000", 'call',
'session', 'login', username=username,
password=password)
return res["ubus_rpc_session"]
+4 -2
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.
@@ -19,7 +18,7 @@ from homeassistant.const import (
DOMAIN = "discovery"
DEPENDENCIES = []
REQUIREMENTS = ['netdisco==0.4.2']
REQUIREMENTS = ['netdisco==0.5.1']
SCAN_INTERVAL = 300 # seconds
@@ -28,6 +27,7 @@ SERVICE_HUE = 'philips_hue'
SERVICE_CAST = 'google_cast'
SERVICE_NETGEAR = 'netgear_router'
SERVICE_SONOS = 'sonos'
SERVICE_PLEX = 'plex_mediaserver'
SERVICE_HANDLERS = {
SERVICE_WEMO: "switch",
@@ -35,6 +35,7 @@ SERVICE_HANDLERS = {
SERVICE_HUE: "light",
SERVICE_NETGEAR: 'device_tracker',
SERVICE_SONOS: 'media_player',
SERVICE_PLEX: 'media_player',
}
@@ -88,6 +89,7 @@ def setup(hass, config):
ATTR_DISCOVERED: info
})
# pylint: disable=unused-argument
def start_discovery(event):
""" Start discovering. """
netdisco = DiscoveryService(SCAN_INTERVAL)
+7 -1
View File
@@ -1,8 +1,10 @@
"""
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/
"""
import os
import logging
@@ -42,6 +44,10 @@ def setup(hass, config):
download_path = config[DOMAIN][CONF_DOWNLOAD_DIR]
# If path is relative, we assume relative to HASS config dir
if not os.path.isabs(download_path):
download_path = hass.config.path(download_path)
if not os.path.isdir(download_path):
logger.error(
@@ -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. """
@@ -72,6 +74,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 +83,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)
@@ -46,6 +46,6 @@
</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 = "38EF63D0474411E4B3CF842B2B6CFE1B"
+1 -1
View File
@@ -1,2 +1,2 @@
""" DO NOT MODIFY. Auto-generated by build_frontend script """
VERSION = "c4722afa376379bc4457d54bb9a38cee"
VERSION = "b75e3c9ebd3de2dae0912a89499127a9"
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3 -2
View File
@@ -1,10 +1,11 @@
"""
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/
"""
import homeassistant.core as ha
from homeassistant.helpers import generate_entity_id
from homeassistant.helpers.event import track_state_change
+3 -1
View File
@@ -1,8 +1,10 @@
"""
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/
"""
import re
from datetime import timedelta
+4 -69
View File
@@ -1,76 +1,11 @@
"""
homeassistant.components.httpinterface
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
homeassistant.components.http
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This module provides an API and a HTTP interface for debug purposes.
By default it will run on port 8123.
All API calls have to be accompanied by an 'api_password' parameter and will
return JSON. If successful calls will return status code 200 or 201.
Other status codes that can occur are:
- 400 (Bad Request)
- 401 (Unauthorized)
- 404 (Not Found)
- 405 (Method not allowed)
The api supports the following actions:
/api - GET
Returns message if API is up and running.
Example result:
{
"message": "API running."
}
/api/states - GET
Returns a list of entities for which a state is available
Example result:
[
{ .. state object .. },
{ .. state object .. }
]
/api/states/<entity_id> - GET
Returns the current state from an entity
Example result:
{
"attributes": {
"next_rising": "07:04:15 29-10-2013",
"next_setting": "18:00:31 29-10-2013"
},
"entity_id": "weather.sun",
"last_changed": "23:24:33 28-10-2013",
"state": "below_horizon"
}
/api/states/<entity_id> - POST
Updates the current state of an entity. Returns status code 201 if successful
with location header of updated resource and as body the new state.
parameter: new_state - string
optional parameter: attributes - JSON encoded object
Example result:
{
"attributes": {
"next_rising": "07:04:15 29-10-2013",
"next_setting": "18:00:31 29-10-2013"
},
"entity_id": "weather.sun",
"last_changed": "23:24:33 28-10-2013",
"state": "below_horizon"
}
/api/events/<event_type> - POST
Fires an event with event_type
optional parameter: event_data - JSON encoded object
Example result:
{
"message": "Event download_file fired."
}
For more details about the RESTful API, please refer to the documentation at
https://home-assistant.io/developers/api/
"""
import json
import threading
import logging
+3 -16
View File
@@ -1,23 +1,10 @@
"""
homeassistant.components.ifttt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This component enable you to trigger Maker IFTTT recipes.
Check https://ifttt.com/maker for details.
Configuration:
To use Maker IFTTT you will need to add something like the following to your
config/configuration.yaml.
ifttt:
key: xxxxx-x-xxxxxxxxxxxxx
Variables:
key
*Required
Your api key
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/ifttt/
"""
import logging
import requests
+5 -3
View File
@@ -1,8 +1,10 @@
"""
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/
"""
import logging
@@ -24,13 +26,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/
+1 -1
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
+3 -1
View File
@@ -1,8 +1,10 @@
"""
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/
"""
import logging
+43 -63
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)
@@ -77,6 +35,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 +51,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 +60,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 +82,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 +93,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 +114,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 +204,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 +220,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 +261,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 +291,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,7 +4,7 @@ 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
+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 -12
View File
@@ -2,19 +2,25 @@
homeassistant.components.light.hue
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Hue lights.
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)
@@ -28,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
@@ -123,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)
@@ -162,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. """
@@ -187,6 +215,12 @@ class HueLight(Light):
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)
+126
View File
@@ -0,0 +1,126 @@
"""
homeassistant.components.light.hyperion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Hyperion remotes.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.hyperion/
"""
import logging
import socket
import json
from homeassistant.const import CONF_HOST
from homeassistant.components.light import (Light, ATTR_RGB_COLOR)
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = []
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Sets up a Hyperion server remote """
host = config.get(CONF_HOST, None)
port = config.get("port", 19444)
device = Hyperion(host, port)
if device.setup():
add_devices_callback([device])
return True
else:
return False
class Hyperion(Light):
""" Represents a Hyperion remote """
def __init__(self, host, port):
self._host = host
self._port = port
self._name = host
self._is_available = True
self._rgb_color = [255, 255, 255]
@property
def name(self):
""" Return the hostname of the server. """
return self._name
@property
def rgb_color(self):
""" Last RGB color value set. """
return self._rgb_color
@property
def is_on(self):
""" True if the device is online. """
return self._is_available
def turn_on(self, **kwargs):
""" Turn the lights on. """
if self._is_available:
if ATTR_RGB_COLOR in kwargs:
self._rgb_color = kwargs[ATTR_RGB_COLOR]
self.json_request({"command": "color", "priority": 128,
"color": self._rgb_color})
def turn_off(self, **kwargs):
""" Disconnect the remote. """
self.json_request({"command": "clearall"})
def update(self):
""" Ping the remote. """
# just see if the remote port is open
self._is_available = self.json_request()
def setup(self):
""" Get the hostname of the remote. """
response = self.json_request({"command": "serverinfo"})
if response:
self._name = response["info"]["hostname"]
return True
return False
def json_request(self, request=None, wait_for_response=False):
""" Communicate with the json server. """
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
try:
sock.connect((self._host, self._port))
except OSError:
sock.close()
return False
if not request:
# no communication needed, simple presence detection returns True
sock.close()
return True
sock.send(bytearray(json.dumps(request) + "\n", "utf-8"))
try:
buf = sock.recv(4096)
except socket.timeout:
# something is wrong, assume it's offline
sock.close()
return False
# read until a newline or timeout
buffering = True
while buffering:
if "\n" in str(buf, "utf-8"):
response = str(buf, "utf-8").split("\n")[0]
buffering = False
else:
try:
more = sock.recv(4096)
except socket.timeout:
more = None
if not more:
buffering = False
response = str(buf, "utf-8")
else:
buf += more
sock.close()
return json.loads(response)
+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
+53 -69
View File
@@ -1,44 +1,52 @@
"""
homeassistant.components.light.limitlessled
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for LimitlessLED bulbs.
Support for LimitlessLED bulbs, also known as...
- EasyBulb
- AppLight
- AppLamp
- MiLight
- LEDme
- dekolight
- iLight
Configuration:
To use limitlessled you will need to add the following to your
configuration.yaml file.
light:
platform: limitlessled
bridges:
- host: 192.168.1.10
group_1_name: Living Room
group_2_name: Bedroom
group_3_name: Office
group_3_type: white
group_4_name: Kitchen
- host: 192.168.1.11
group_2_name: Basement
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,
EFFECT_COLORLOOP, EFFECT_WHITE)
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['ledcontroller==1.1.0']
COLOR_TABLE = {
'white': [0xFF, 0xFF, 0xFF],
'violet': [0xEE, 0x82, 0xEE],
'royal_blue': [0x41, 0x69, 0xE1],
'baby_blue': [0x87, 0xCE, 0xFA],
'aqua': [0x00, 0xFF, 0xFF],
'royal_mint': [0x7F, 0xFF, 0xD4],
'seafoam_green': [0x2E, 0x8B, 0x57],
'green': [0x00, 0x80, 0x00],
'lime_green': [0x32, 0xCD, 0x32],
'yellow': [0xFF, 0xFF, 0x00],
'yellow_orange': [0xDA, 0xA5, 0x20],
'orange': [0xFF, 0xA5, 0x00],
'red': [0xFF, 0x00, 0x00],
'pink': [0xFF, 0xC0, 0xCB],
'fusia': [0xFF, 0x00, 0xFF],
'lilac': [0xDA, 0x70, 0xD6],
'lavendar': [0xE6, 0xE6, 0xFA],
}
def _distance_squared(rgb1, rgb2):
""" Return sum of squared distances of each color part. """
return sum((val1-val2)**2 for val1, val2 in zip(rgb1, rgb2))
def _rgb_to_led_color(rgb_color):
""" Convert an RGB color to the closest color string and color. """
return sorted((_distance_squared(rgb_color, color), name)
for name, color in COLOR_TABLE.items())[0][1]
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Gets the LimitlessLED lights. """
@@ -120,49 +128,15 @@ class RGBWLimitlessLED(LimitlessLED):
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'),
]]
self._led_color = 'white'
@property
def brightness(self):
return self._brightness
@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 rgb_color(self):
return COLOR_TABLE[self._led_color]
def turn_on(self, **kwargs):
""" Turn the device on. """
@@ -171,13 +145,23 @@ class RGBWLimitlessLED(LimitlessLED):
if ATTR_BRIGHTNESS in kwargs:
self._brightness = kwargs[ATTR_BRIGHTNESS]
if ATTR_XY_COLOR in kwargs:
self._xy_color = kwargs[ATTR_XY_COLOR]
if ATTR_RGB_COLOR in kwargs:
self._led_color = _rgb_to_led_color(kwargs[ATTR_RGB_COLOR])
self.pool.execute(self.controller_id, "set_color",
self._xy_to_led_color(self._xy_color), self.group)
effect = kwargs.get(ATTR_EFFECT)
if effect == EFFECT_COLORLOOP:
self.pool.execute(self.controller_id, "disco", self.group)
elif effect == EFFECT_WHITE:
self.pool.execute(self.controller_id, "white", self.group)
else:
self.pool.execute(self.controller_id, "set_color",
self._led_color, self.group)
# Brightness can be set independently of color
self.pool.execute(self.controller_id, "set_brightness",
self._brightness / 255.0, self.group)
self.update_ha_state()
+184
View File
@@ -0,0 +1,184 @@
"""
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.util.color as color_util
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_RGB_PATTERN = "%d,%d,%d"
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('rgb', None),
config.get('qos', DEFAULT_QOS),
{"on": config.get('payload_on', DEFAULT_PAYLOAD_ON),
"off": config.get('payload_off', DEFAULT_PAYLOAD_OFF)},
config.get('brightness'),
config.get('optimistic', DEFAULT_OPTIMISTIC))])
# pylint: disable=too-many-instance-attributes
class MqttLight(Light):
""" Provides a MQTT light. """
# pylint: disable=too-many-arguments
def __init__(self, hass, name,
topic,
rgb, qos,
payload,
brightness, optimistic):
self._hass = hass
self._name = name
self._topic = topic
self._rgb = rgb
self._qos = qos
self._payload = payload
self._brightness = brightness
self._optimistic = optimistic
self._state = False
self._xy = None
def message_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 None:
# force optimistic mode
self._optimistic = True
else:
# Subscribe the state_topic
mqtt.subscribe(self._hass, self._topic["state_topic"],
message_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()
def rgb_received(topic, payload, qos):
""" A new MQTT message has been received. """
self._rgb = [int(val) for val in payload.split(',')]
self._xy = color_util.color_RGB_to_xy(int(self._rgb[0]),
int(self._rgb[1]),
int(self._rgb[2]))
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
if self._topic["rgb_state_topic"] is not None:
mqtt.subscribe(self._hass, self._topic["rgb_state_topic"],
rgb_received, self._qos)
self._xy = [0, 0]
else:
self._xy = 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 color_xy(self):
""" RGB color value. """
return self._xy
@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. """
if ATTR_RGB_COLOR in kwargs and \
self._topic["rgb_command_topic"] is not None:
self._rgb = kwargs[ATTR_RGB_COLOR]
rgb = DEFAULT_RGB_PATTERN % tuple(self._rgb)
mqtt.publish(self._hass, self._topic["rgb_command_topic"],
rgb, self._qos)
if ATTR_BRIGHTNESS in kwargs and \
self._topic["brightness_command_topic"] is not None:
self._brightness = kwargs[ATTR_BRIGHTNESS]
mqtt.publish(self._hass, self._topic["brightness_command_topic"],
self._brightness, self._qos)
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
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()
+6 -1
View File
@@ -4,7 +4,7 @@ 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
@@ -59,6 +59,11 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
# Check if entity exists or previously added automatically
if entity_id in rfxtrx.RFX_DEVICES:
_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':
@@ -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
@@ -2,6 +2,9 @@
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/
"""
import logging
# pylint: disable=no-name-in-module, import-error
+37 -50
View File
@@ -1,60 +1,22 @@
"""
homeassistant.components.light.vera
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Support for Vera lights. This component is useful if you wish for switches
connected to your Vera controller to appear as lights in Home Assistant.
All switches will be added as a light unless you exclude them in the config.
Configuration:
To use the Vera lights you will need to add something like the following to
your configuration.yaml file.
light:
platform: vera
vera_controller_url: http://YOUR_VERA_IP:3480/
device_data:
12:
name: My awesome switch
exclude: true
13:
name: Another switch
Variables:
vera_controller_url
*Required
This is the base URL of your vera controller including the port number if not
running on 80. Example: http://192.168.1.21:3480/
device_data
*Optional
This contains an array additional device info for your Vera devices. It is not
required and if not specified all lights configured in your Vera controller
will be added with default values. You should use the id of your vera device
as the key for the device within device_data.
These are the variables for the device_data array:
name
*Optional
This parameter allows you to override the name of your Vera device in the HA
interface, if not specified the value configured for the device in your Vera
will be used.
exclude
*Optional
This parameter allows you to exclude the specified device from Home Assistant,
it should be set to "true" if you want this device excluded.
Support for Vera lights.
For more details about this platform, please refer to the documentation at
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__)
@@ -77,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")
@@ -89,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
+5 -2
View File
@@ -2,6 +2,9 @@
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/
"""
import logging
@@ -10,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']
'9eb39eaba0717922815e673ad1114c685839d890.zip'
'#python-wink==0.1.1']
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
+126
View File
@@ -0,0 +1,126 @@
"""
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/
"""
# pylint: disable=import-error
from openzwave.network import ZWaveNetwork
from pydispatch import dispatcher
import homeassistant.components.zwave as zwave
from homeassistant.const import STATE_ON, STATE_OFF
from homeassistant.components.light import (Light, ATTR_BRIGHTNESS)
from threading import Timer
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):
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
+3 -1
View File
@@ -1,8 +1,10 @@
"""
homeassistant.components.logbook
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Parses events and generates a human log.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/logbook/
"""
from datetime import timedelta
from itertools import groupby
+84
View File
@@ -0,0 +1,84 @@
"""
homeassistant.components.logger
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component that will help set the level of logging for components.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/logger/
"""
import logging
from collections import OrderedDict
DOMAIN = 'logger'
DEPENDENCIES = []
LOGSEVERITY = {
'CRITICAL': 50,
'FATAL': 50,
'ERROR': 40,
'WARNING': 30,
'WARN': 30,
'INFO': 20,
'DEBUG': 10,
'NOTSET': 0
}
LOGGER_DEFAULT = 'default'
LOGGER_LOGS = 'logs'
class HomeAssistantLogFilter(logging.Filter):
""" A log filter. """
# pylint: disable=no-init,too-few-public-methods
def __init__(self, logfilter):
super().__init__()
self.logfilter = logfilter
def filter(self, record):
# Log with filtered severity
if LOGGER_LOGS in self.logfilter:
for filtername in self.logfilter[LOGGER_LOGS]:
logseverity = self.logfilter[LOGGER_LOGS][filtername]
if record.name.startswith(filtername):
return record.levelno >= logseverity
# Log with default severity
default = self.logfilter[LOGGER_DEFAULT]
return record.levelno >= default
def setup(hass, config=None):
""" Setup the logger component. """
logfilter = dict()
# Set default log severity
logfilter[LOGGER_DEFAULT] = LOGSEVERITY['DEBUG']
if LOGGER_DEFAULT in config.get(DOMAIN):
logfilter[LOGGER_DEFAULT] = LOGSEVERITY[
config.get(DOMAIN)[LOGGER_DEFAULT].upper()
]
# Compute log severity for components
if LOGGER_LOGS in config.get(DOMAIN):
for key, value in config.get(DOMAIN)[LOGGER_LOGS].items():
config.get(DOMAIN)[LOGGER_LOGS][key] = LOGSEVERITY[value.upper()]
logs = OrderedDict(
sorted(
config.get(DOMAIN)[LOGGER_LOGS].items(),
key=lambda t: len(t[0]),
reverse=True
)
)
logfilter[LOGGER_LOGS] = logs
# Set log filter for all log handler
for handler in logging.root.handlers:
handler.addFilter(HomeAssistantLogFilter(logfilter))
return True
@@ -1,8 +1,10 @@
"""
homeassistant.components.media_player
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component to interface with various media players.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/media_player/
"""
import logging
import os
@@ -28,6 +30,7 @@ ENTITY_ID_FORMAT = DOMAIN + '.{}'
DISCOVERY_PLATFORMS = {
discovery.SERVICE_CAST: 'cast',
discovery.SERVICE_SONOS: 'sonos',
discovery.SERVICE_PLEX: 'plex',
}
SERVICE_YOUTUBE_VIDEO = 'play_youtube_video'
+2 -16
View File
@@ -3,22 +3,8 @@ homeassistant.components.media_player.chromecast
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to interact with Cast devices on the network.
WARNING: This platform is currently not working due to a changed Cast API.
Configuration:
To use the chromecast integration you will need to add something like the
following to your configuration.yaml file.
media_player:
platform: chromecast
host: 192.168.1.9
Variables:
host
*Optional
Use only if you don't want to scan for devices.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.cast/
"""
import logging
+56 -75
View File
@@ -2,42 +2,9 @@
homeassistant.components.media_player.denon
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides an interface to Denon Network Receivers.
Developed for a Denon DRA-N5, see
http://www.denon.co.uk/chg/product/compactsystems/networkmusicsystems/ceolpiccolo
A few notes:
- As long as this module is active and connected, the receiver does
not seem to accept additional telnet connections.
- Be careful with the volume. 50% or even 100% are very loud.
- To be able to wake up the receiver, activate the "remote" setting
in the receiver's settings.
- Play and pause are supported, toggling is not possible.
- Seeking cannot be implemented as the UI sends absolute positions.
Only seeking via simulated button presses is possible.
Configuration:
To use your Denon you will need to add something like the following to
your config/configuration.yaml:
media_player:
platform: denon
name: Music station
host: 192.168.0.123
Variables:
host
*Required
The ip of the player. Example: 192.168.0.123
name
*Optional
The name of the device.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.denon/
"""
import telnetlib
import logging
@@ -67,13 +34,15 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
CONF_HOST)
return False
add_devices([
DenonDevice(
config.get('name', 'Music station'),
config.get('host'))
])
return True
denon = DenonDevice(
config.get("name", "Music station"),
config.get("host")
)
if denon.update():
add_devices([denon])
return True
else:
return False
class DenonDevice(MediaPlayerDevice):
@@ -84,28 +53,41 @@ class DenonDevice(MediaPlayerDevice):
def __init__(self, name, host):
self._name = name
self._host = host
self._telnet = telnetlib.Telnet(self._host)
self._pwstate = "PWSTANDBY"
self._volume = 0
self._muted = False
self._mediasource = ""
def query(self, message):
""" Send request and await response from server """
@classmethod
def telnet_request(cls, telnet, command):
""" Executes `command` and returns the response. """
telnet.write(command.encode("ASCII") + b"\r")
return telnet.read_until(b"\r", timeout=0.2).decode("ASCII").strip()
def telnet_command(self, command):
""" Establishes a telnet connection and sends `command`. """
telnet = telnetlib.Telnet(self._host)
telnet.write(command.encode("ASCII") + b"\r")
telnet.read_very_eager() # skip response
telnet.close()
def update(self):
try:
# unspecified command, should be ignored
self._telnet.write("?".encode('UTF-8') + b'\r')
except (EOFError, BrokenPipeError, ConnectionResetError):
self._telnet.open(self._host)
telnet = telnetlib.Telnet(self._host)
except ConnectionRefusedError:
return False
self._telnet.read_very_eager() # skip what is not requested
self._pwstate = self.telnet_request(telnet, "PW?")
# PW? sends also SISTATUS, which is not interesting
telnet.read_until(b"\r", timeout=0.2)
self._telnet.write(message.encode('ASCII') + b'\r')
# timeout 200ms, defined by protocol
resp = self._telnet.read_until(b'\r', timeout=0.2)\
.decode('UTF-8').strip()
volume_str = self.telnet_request(telnet, "MV?")[len("MV"):]
self._volume = int(volume_str) / 60
self._muted = (self.telnet_request(telnet, "MU?") == "MUON")
self._mediasource = self.telnet_request(telnet, "SI?")[len("SI"):]
if message == "PW?":
# workaround; PW? sends also SISTATUS
self._telnet.read_until(b'\r', timeout=0.2)
return resp
telnet.close()
return True
@property
def name(self):
@@ -115,10 +97,9 @@ class DenonDevice(MediaPlayerDevice):
@property
def state(self):
""" Returns the state of the device. """
pwstate = self.query('PW?')
if pwstate == "PWSTANDBY":
if self._pwstate == "PWSTANDBY":
return STATE_OFF
if pwstate == "PWON":
if self._pwstate == "PWON":
return STATE_ON
return STATE_UNKNOWN
@@ -126,17 +107,17 @@ class DenonDevice(MediaPlayerDevice):
@property
def volume_level(self):
""" Volume level of the media player (0..1). """
return int(self.query('MV?')[len('MV'):]) / 60
return self._volume
@property
def is_volume_muted(self):
""" Boolean if volume is currently muted. """
return self.query('MU?') == "MUON"
return self._muted
@property
def media_title(self):
""" Current media source. """
return self.query('SI?')[len('SI'):]
return self._mediasource
@property
def supported_media_commands(self):
@@ -145,24 +126,24 @@ class DenonDevice(MediaPlayerDevice):
def turn_off(self):
""" turn_off media player. """
self.query('PWSTANDBY')
self.telnet_command("PWSTANDBY")
def volume_up(self):
""" volume_up media player. """
self.query('MVUP')
self.telnet_command("MVUP")
def volume_down(self):
""" volume_down media player. """
self.query('MVDOWN')
self.telnet_command("MVDOWN")
def set_volume_level(self, volume):
""" set volume level, range 0..1. """
# 60dB max
self.query('MV' + str(round(volume * 60)).zfill(2))
self.telnet_command("MV" + str(round(volume * 60)).zfill(2))
def mute_volume(self, mute):
""" mute (true) or unmute (false) media player. """
self.query('MU' + ('ON' if mute else 'OFF'))
self.telnet_command("MU" + ("ON" if mute else "OFF"))
def media_play_pause(self):
""" media_play_pause media player. """
@@ -170,22 +151,22 @@ class DenonDevice(MediaPlayerDevice):
def media_play(self):
""" media_play media player. """
self.query('NS9A')
self.telnet_command("NS9A")
def media_pause(self):
""" media_pause media player. """
self.query('NS9B')
self.telnet_command("NS9B")
def media_next_track(self):
""" Send next track command. """
self.query('NS9D')
self.telnet_command("NS9D")
def media_previous_track(self):
self.query('NS9E')
self.telnet_command("NS9E")
def media_seek(self, position):
raise NotImplementedError()
def turn_on(self):
""" turn the media player on. """
self.query('PWON')
self.telnet_command("PWON")
@@ -0,0 +1,190 @@
"""
homeassistant.components.media_player.firetv
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to interact with FireTV devices.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.firetv/
"""
import logging
import requests
from homeassistant.const import (
STATE_PLAYING, STATE_PAUSED, STATE_IDLE, STATE_OFF,
STATE_UNKNOWN, STATE_STANDBY)
from homeassistant.components.media_player import (
MediaPlayerDevice,
SUPPORT_PAUSE, SUPPORT_VOLUME_SET,
SUPPORT_TURN_ON, SUPPORT_TURN_OFF,
SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK)
SUPPORT_FIRETV = SUPPORT_PAUSE | \
SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PREVIOUS_TRACK | \
SUPPORT_NEXT_TRACK | SUPPORT_VOLUME_SET
DOMAIN = 'firetv'
DEVICE_LIST_URL = 'http://{0}/devices/list'
DEVICE_STATE_URL = 'http://{0}/devices/state/{1}'
DEVICE_ACTION_URL = 'http://{0}/devices/action/{1}/{2}'
_LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the FireTV platform. """
host = config.get('host', 'localhost:5556')
device_id = config.get('device', 'default')
try:
response = requests.get(DEVICE_LIST_URL.format(host)).json()
if device_id in response['devices'].keys():
add_devices([
FireTVDevice(
host,
device_id,
config.get('name', 'Amazon Fire TV')
)
])
_LOGGER.info(
'Device %s accessible and ready for control', device_id)
else:
_LOGGER.warn(
'Device %s is not registered with firetv-server', device_id)
except requests.exceptions.RequestException:
_LOGGER.error('Could not connect to firetv-server at %s', host)
class FireTV(object):
""" firetv-server client.
Should a native Python 3 ADB module become available, python-firetv can
support Python 3, it can be added as a dependency, and this class can be
dispensed of.
For now, it acts as a client to the firetv-server HTTP server (which must
be running via Python 2).
"""
def __init__(self, host, device_id):
self.host = host
self.device_id = device_id
@property
def state(self):
""" Get the device state. An exception means UNKNOWN state. """
try:
response = requests.get(
DEVICE_STATE_URL.format(
self.host,
self.device_id
)
).json()
return response.get('state', STATE_UNKNOWN)
except requests.exceptions.RequestException:
_LOGGER.error(
'Could not retrieve device state for %s', self.device_id)
return STATE_UNKNOWN
def action(self, action_id):
""" Perform an action on the device. """
try:
requests.get(
DEVICE_ACTION_URL.format(
self.host,
self.device_id,
action_id
)
)
except requests.exceptions.RequestException:
_LOGGER.error(
'Action request for %s was not accepted for device %s',
action_id, self.device_id)
class FireTVDevice(MediaPlayerDevice):
""" Represents an Amazon Fire TV device on the network. """
def __init__(self, host, device, name):
self._firetv = FireTV(host, device)
self._name = name
self._state = STATE_UNKNOWN
@property
def name(self):
""" Get the device name. """
return self._name
@property
def should_poll(self):
""" Device should be polled. """
return True
@property
def supported_media_commands(self):
""" Flags of media commands that are supported. """
return SUPPORT_FIRETV
@property
def state(self):
""" State of the player. """
return self._state
def update(self):
""" Update device state. """
self._state = {
'idle': STATE_IDLE,
'off': STATE_OFF,
'play': STATE_PLAYING,
'pause': STATE_PAUSED,
'standby': STATE_STANDBY,
'disconnected': STATE_UNKNOWN,
}.get(self._firetv.state, STATE_UNKNOWN)
def turn_on(self):
""" Turns on the device. """
self._firetv.action('turn_on')
def turn_off(self):
""" Turns off the device. """
self._firetv.action('turn_off')
def media_play(self):
""" Send play command. """
self._firetv.action('media_play')
def media_pause(self):
""" Send pause command. """
self._firetv.action('media_pause')
def media_play_pause(self):
""" Send play/pause command. """
self._firetv.action('media_play_pause')
def volume_up(self):
""" Send volume up command. """
self._firetv.action('volume_up')
def volume_down(self):
""" Send volume down command. """
self._firetv.action('volume_down')
def media_previous_track(self):
""" Send previous track command (results in rewind). """
self._firetv.action('media_previous')
def media_next_track(self):
""" Send next track command (results in fast-forward). """
self._firetv.action('media_next')
def media_seek(self, position):
raise NotImplementedError()
def mute_volume(self, mute):
raise NotImplementedError()
def play_youtube(self, media_id):
raise NotImplementedError()
def set_volume_level(self, volume):
raise NotImplementedError()
@@ -1,36 +1,10 @@
"""
homeassistant.components.media_player.itunes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides an interface to iTunes-API (https://github.com/maddox/itunes-api)
The iTunes media player will allow you to control your iTunes instance. You
can play/pause/next/previous/mute, adjust volume, etc.
In addition to controlling iTunes, your available AirPlay endpoints will be
added as media players as well. You can then individually address them append
turn them on, turn them off, or adjust their volume.
Configuration:
To use iTunes you will need to add something like the following to
your configuration.yaml file.
media_player:
platform: itunes
name: iTunes
host: http://192.168.1.16
port: 8181
Variables:
name
*Optional
The name of the device.
url
*Required
URL of your running version of iTunes-API. Example: http://192.168.1.50:8181
Provides an interface to iTunes API.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.itunes/
"""
import logging
@@ -157,11 +131,9 @@ class Itunes(object):
path = '/airplay_devices/' + device_id + '/volume'
return self._request('PUT', path, {'level': level})
# pylint: disable=unused-argument
# pylint: disable=abstract-method
# pylint: disable=unused-argument, abstract-method
# pylint: disable=too-many-instance-attributes
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the itunes platform. """
@@ -179,7 +151,6 @@ class ItunesDevice(MediaPlayerDevice):
""" Represents a iTunes-API instance. """
# pylint: disable=too-many-public-methods
def __init__(self, name, host, port, add_devices):
self._name = name
self._host = host
+2 -29
View File
@@ -3,35 +3,8 @@ homeassistant.components.media_player.kodi
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides an interface to the XBMC/Kodi JSON-RPC API
Configuration:
To use the Kodi you will need to add something like the following to
your configuration.yaml file.
media_player:
platform: kodi
name: Kodi
url: http://192.168.0.123/jsonrpc
user: kodi
password: my_secure_password
Variables:
name
*Optional
The name of the device.
url
*Required
The URL of the XBMC/Kodi JSON-RPC API. Example: http://192.168.0.123/jsonrpc
user
*Optional
The XBMC/Kodi HTTP username.
password
*Optional
The XBMC/Kodi HTTP password.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.kodi/
"""
import urllib
import logging
+2 -29
View File
@@ -3,35 +3,8 @@ homeassistant.components.media_player.mpd
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to interact with a Music Player Daemon.
Configuration:
To use MPD you will need to add something like the following to your
configuration.yaml file.
media_player:
platform: mpd
server: 127.0.0.1
port: 6600
location: bedroom
password: superSecretPassword123
Variables:
server
*Required
IP address of the Music Player Daemon. Example: 192.168.1.32
port
*Optional
Port of the Music Player Daemon, defaults to 6600. Example: 6600
location
*Optional
Location of your Music Player Daemon.
password
*Optional
Password for your Music Player Daemon.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.mpd/
"""
import logging
import socket
+145 -38
View File
@@ -4,40 +4,116 @@ homeassistant.components.media_player.plex
Provides an interface to the Plex API.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.plex.html
https://home-assistant.io/components/media_player.plex/
"""
import os
import json
import logging
from datetime import timedelta
from urllib.parse import urlparse
from homeassistant.loader import get_component
import homeassistant.util as util
from homeassistant.components.media_player import (
MediaPlayerDevice, SUPPORT_PAUSE, SUPPORT_PREVIOUS_TRACK,
SUPPORT_NEXT_TRACK, MEDIA_TYPE_TVSHOW, MEDIA_TYPE_VIDEO)
from homeassistant.const import (
STATE_IDLE, STATE_PLAYING, STATE_PAUSED, STATE_OFF, STATE_UNKNOWN)
import homeassistant.util as util
DEVICE_DEFAULT_NAME, STATE_IDLE, STATE_PLAYING,
STATE_PAUSED, STATE_OFF, STATE_UNKNOWN)
REQUIREMENTS = ['https://github.com/adrienbrault/python-plexapi/archive/'
'df2d0847e801d6d5cda920326d693cf75f304f1a.zip'
'#python-plexapi==1.0.2']
REQUIREMENTS = ['plexapi==1.1.0']
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(seconds=1)
PLEX_CONFIG_FILE = 'plex.conf'
# Map ip to request id for configuring
_CONFIGURING = {}
_LOGGER = logging.getLogger(__name__)
SUPPORT_PLEX = SUPPORT_PAUSE | SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK
# pylint: disable=abstract-method, unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
""" Sets up the plex platform. """
from plexapi.myplex import MyPlexUser
from plexapi.exceptions import BadRequest
def config_from_file(filename, config=None):
''' Small configuration file management function'''
if config:
# We're writing configuration
try:
with open(filename, 'w') as fdesc:
fdesc.write(json.dumps(config))
except IOError as error:
_LOGGER.error('Saving config file failed: %s', error)
return False
return True
else:
# We're reading config
if os.path.isfile(filename):
try:
with open(filename, 'r') as fdesc:
return json.loads(fdesc.read())
except IOError as error:
_LOGGER.error('Reading config file failed: %s', error)
# This won't work yet
return False
else:
return {}
# pylint: disable=abstract-method, unused-argument
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Sets up the plex platform. """
config = config_from_file(hass.config.path(PLEX_CONFIG_FILE))
if len(config):
# Setup a configured PlexServer
host, token = config.popitem()
token = token['token']
# Via discovery
elif discovery_info is not None:
# Parse discovery data
host = urlparse(discovery_info[1]).netloc
_LOGGER.info('Discovered PLEX server: %s', host)
if host in _CONFIGURING:
return
token = None
else:
return
setup_plexserver(host, token, hass, add_devices_callback)
# pylint: disable=too-many-branches
def setup_plexserver(host, token, hass, add_devices_callback):
''' Setup a plexserver based on host parameter'''
import plexapi.server
import plexapi.exceptions
try:
plexserver = plexapi.server.PlexServer('http://%s' % host, token)
except (plexapi.exceptions.BadRequest,
plexapi.exceptions.Unauthorized,
plexapi.exceptions.NotFound) as error:
_LOGGER.info(error)
# No token or wrong token
request_configuration(host, hass, add_devices_callback)
return
# If we came here and configuring this host, mark as done
if host in _CONFIGURING:
request_id = _CONFIGURING.pop(host)
configurator = get_component('configurator')
configurator.request_done(request_id)
_LOGGER.info('Discovery configuration done!')
# Save config
if not config_from_file(
hass.config.path(PLEX_CONFIG_FILE),
{host: {'token': token}}):
_LOGGER.error('failed to save config file')
_LOGGER.info('Connected to: htts://%s', host)
name = config.get('name', '')
user = config.get('user', '')
password = config.get('password', '')
plexuser = MyPlexUser.signin(user, password)
plexserver = plexuser.getResource(name).connect()
plex_clients = {}
plex_sessions = {}
@@ -45,34 +121,34 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
def update_devices():
""" Updates the devices objects. """
try:
devices = plexuser.devices()
except BadRequest:
devices = plexserver.clients()
except plexapi.exceptions.BadRequest:
_LOGGER.exception("Error listing plex devices")
return
new_plex_clients = []
for device in devices:
if (all(x not in ['client', 'player'] for x in device.provides)
or 'PlexAPI' == device.product):
# For now, let's allow all deviceClass types
if device.deviceClass in ['badClient']:
continue
if device.clientIdentifier not in plex_clients:
if device.machineIdentifier not in plex_clients:
new_client = PlexClient(device, plex_sessions, update_devices,
update_sessions)
plex_clients[device.clientIdentifier] = new_client
plex_clients[device.machineIdentifier] = new_client
new_plex_clients.append(new_client)
else:
plex_clients[device.clientIdentifier].set_device(device)
plex_clients[device.machineIdentifier].set_device(device)
if new_plex_clients:
add_devices(new_plex_clients)
add_devices_callback(new_plex_clients)
@util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
def update_sessions():
""" Updates the sessions objects. """
try:
sessions = plexserver.sessions()
except BadRequest:
except plexapi.exceptions.BadRequest:
_LOGGER.exception("Error listing plex sessions")
return
@@ -84,10 +160,34 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
update_sessions()
def request_configuration(host, hass, add_devices_callback):
""" Request configuration steps from the user. """
configurator = get_component('configurator')
# We got an error if this method is called while we are configuring
if host in _CONFIGURING:
configurator.notify_errors(
_CONFIGURING[host], "Failed to register, please try again.")
return
def plex_configuration_callback(data):
""" Actions to do when our configuration callback is called. """
setup_plexserver(host, data.get('token'), hass, add_devices_callback)
_CONFIGURING[host] = configurator.request_config(
hass, "Plex Media Server", plex_configuration_callback,
description=('Enter the X-Plex-Token'),
description_image="/static/images/config_plex_mediaserver.png",
submit_caption="Confirm",
fields=[{'id': 'token', 'name': 'X-Plex-Token', 'type': ''}]
)
class PlexClient(MediaPlayerDevice):
""" Represents a Plex device. """
# pylint: disable=too-many-public-methods
# pylint: disable=too-many-public-methods, attribute-defined-outside-init
def __init__(self, device, plex_sessions, update_devices, update_sessions):
self.plex_sessions = plex_sessions
self.update_devices = update_devices
@@ -99,17 +199,23 @@ class PlexClient(MediaPlayerDevice):
self.device = device
@property
def session(self):
""" Returns the session, if any. """
if self.device.clientIdentifier not in self.plex_sessions:
return None
return self.plex_sessions[self.device.clientIdentifier]
def unique_id(self):
""" Returns the id of this plex client """
return "{}.{}".format(
self.__class__, self.device.machineIdentifier or self.device.name)
@property
def name(self):
""" Returns the name of the device. """
return self.device.name or self.device.product or self.device.device
return self.device.name or DEVICE_DEFAULT_NAME
@property
def session(self):
""" Returns the session, if any. """
if self.device.machineIdentifier not in self.plex_sessions:
return None
return self.plex_sessions[self.device.machineIdentifier]
@property
def state(self):
@@ -120,7 +226,8 @@ class PlexClient(MediaPlayerDevice):
return STATE_PLAYING
elif state == 'paused':
return STATE_PAUSED
elif self.device.isReachable:
# This is nasty. Need to find a way to determine alive
elif self.device:
return STATE_IDLE
else:
return STATE_OFF
@@ -196,16 +303,16 @@ class PlexClient(MediaPlayerDevice):
def media_play(self):
""" media_play media player. """
self.device.play({'type': 'video'})
self.device.play()
def media_pause(self):
""" media_pause media player. """
self.device.pause({'type': 'video'})
self.device.pause()
def media_next_track(self):
""" Send next track command. """
self.device.skipNext({'type': 'video'})
self.device.skipNext()
def media_previous_track(self):
""" Send previous track command. """
self.device.skipPrevious({'type': 'video'})
self.device.skipPrevious()
+13 -20
View File
@@ -1,17 +1,11 @@
"""
homeassistant.components.media_player.sonos
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides an interface to Sonos players (via SoCo)
Configuration:
To use SoCo, add something like this to your configuration:
media_player:
platform: sonos
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.sonos/
"""
import logging
import datetime
@@ -56,8 +50,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
return True
# pylint: disable=too-many-instance-attributes
# pylint: disable=too-many-public-methods
# pylint: disable=too-many-instance-attributes, too-many-public-methods
# pylint: disable=abstract-method
class SonosDevice(MediaPlayerDevice):
""" Represents a Sonos device. """
@@ -74,7 +67,7 @@ class SonosDevice(MediaPlayerDevice):
return True
def update_sonos(self, now):
""" Updates state, called by track_utc_time_change """
""" Updates state, called by track_utc_time_change. """
self.update_ha_state(True)
@property
@@ -162,31 +155,31 @@ class SonosDevice(MediaPlayerDevice):
return SUPPORT_SONOS
def turn_off(self):
""" turn_off media player. """
""" Turn off media player. """
self._player.pause()
def volume_up(self):
""" volume_up media player. """
""" Volume up media player. """
self._player.volume += 1
def volume_down(self):
""" volume_down media player. """
""" Volume down media player. """
self._player.volume -= 1
def set_volume_level(self, volume):
""" set volume level, range 0..1. """
""" Set volume level, range 0..1. """
self._player.volume = str(int(volume * 100))
def mute_volume(self, mute):
""" mute (true) or unmute (false) media player. """
""" Mute (true) or unmute (false) media player. """
self._player.mute = mute
def media_play(self):
""" media_play media player. """
""" Send paly command. """
self._player.play()
def media_pause(self):
""" media_pause media player. """
""" Send pause command. """
self._player.pause()
def media_next_track(self):
@@ -202,5 +195,5 @@ class SonosDevice(MediaPlayerDevice):
self._player.seek(str(datetime.timedelta(seconds=int(position))))
def turn_on(self):
""" turn the media player on. """
""" Turn the media player on. """
self._player.play()
@@ -1,39 +1,11 @@
"""
homeassistant.components.media_player.squeezebox
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides an interface to the Logitech SqueezeBox API
Configuration:
To use SqueezeBox add something something like the following to your
configuration.yaml file.
media_player:
platform: squeezebox
host: 192.168.1.21
port: 9090
username: user
password: password
Variables:
host
*Required
The host name or address of the Logitech Media Server.
port
*Optional
Telnet port to Logitech Media Server, default 9090.
usermame
*Optional
Username, if password protection is enabled.
password
*Optional
Password, if password protection is enabled.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/media_player.squeezebox/
"""
import logging
import telnetlib
import urllib.parse
@@ -201,7 +173,7 @@ class SqueezeBoxDevice(MediaPlayerDevice):
def volume_level(self):
""" Volume level of the media player (0..1). """
if 'mixer volume' in self._status:
return int(self._status['mixer volume']) / 100.0
return int(float(self._status['mixer volume'])) / 100.0
@property
def is_volume_muted(self):
@@ -291,7 +263,7 @@ class SqueezeBoxDevice(MediaPlayerDevice):
def media_pause(self):
""" media_pause media player. """
self._lms.query(self._id, 'pause', '0')
self._lms.query(self._id, 'pause', '1')
self.update_ha_state()
def media_next_track(self):
+2 -21
View File
@@ -3,27 +3,8 @@ homeassistant.components.modbus
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Modbus component, using pymodbus (python3 branch).
Configuration:
To use the Modbus component you will need to add something like the following
to your configuration.yaml file.
#Modbus TCP
modbus:
type: tcp
host: 127.0.0.1
port: 2020
#Modbus RTU
modbus:
type: serial
method: rtu
port: /dev/ttyUSB0
baudrate: 9600
stopbits: 1
bytesize: 8
parity: N
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/modbus/
"""
import logging
+3 -45
View File
@@ -1,52 +1,10 @@
"""
homeassistant.components.mqtt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MQTT component, using paho-mqtt. This component needs a MQTT broker like
Mosquitto or Mosca. The Eclipse Foundation is running a public MQTT server
at iot.eclipse.org. If you prefer to use that one, keep in mind to adjust
the topic/client ID and that your messages are public.
MQTT component, using paho-mqtt.
Configuration:
To use MQTT you will need to add something like the following to your
config/configuration.yaml.
mqtt:
broker: 127.0.0.1
Or, if you want more options:
mqtt:
broker: 127.0.0.1
port: 1883
client_id: home-assistant-1
keepalive: 60
username: your_username
password: your_secret_password
certificate: /home/paulus/dev/addtrustexternalcaroot.crt
Variables:
broker
*Required
This is the IP address of your MQTT broker, e.g. 192.168.1.32.
port
*Optional
The network port to connect to. Default is 1883.
client_id
*Optional
Client ID that Home Assistant will use. Has to be unique on the server.
Default is a random generated one.
keepalive
*Optional
The keep alive in seconds for this client. Default is 60.
certificate
*Optional
Certificate to use for encrypting the connection to the broker.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/mqtt/
"""
import logging
import os
+12 -7
View File
@@ -1,15 +1,17 @@
"""
homeassistant.components.notify
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides functionality to notify people.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/notify/
"""
from functools import partial
import logging
import os
import homeassistant.bootstrap as bootstrap
from homeassistant.config import load_yaml_config_file
from homeassistant.loader import get_component
from homeassistant.helpers import config_per_platform
from homeassistant.const import CONF_NAME
@@ -21,6 +23,9 @@ DEPENDENCIES = []
ATTR_TITLE = "title"
ATTR_TITLE_DEFAULT = "Home Assistant"
# Target of the notification (user, device, etc)
ATTR_TARGET = 'target'
# Text to notify user of
ATTR_MESSAGE = "message"
@@ -43,16 +48,15 @@ def setup(hass, config):
for platform, p_config in config_per_platform(config, DOMAIN, _LOGGER):
# get platform
notify_implementation = get_component(
'notify.{}'.format(platform))
notify_implementation = bootstrap.prepare_setup_platform(
hass, config, DOMAIN, platform)
if notify_implementation is None:
_LOGGER.error("Unknown notification service specified.")
continue
# create platform service
notify_service = notify_implementation.get_service(
hass, {DOMAIN: p_config})
notify_service = notify_implementation.get_service(hass, p_config)
if notify_service is None:
_LOGGER.error("Failed to initialize notification service %s",
@@ -68,8 +72,9 @@ def setup(hass, config):
return
title = call.data.get(ATTR_TITLE, ATTR_TITLE_DEFAULT)
target = call.data.get(ATTR_TARGET)
notify_service.send_message(message, title=title)
notify_service.send_message(message, title=title, target=target)
# register service
service_call_handler = partial(notify_message, notify_service)
+5 -23
View File
@@ -3,26 +3,8 @@ homeassistant.components.notify.file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
File notification service.
Configuration:
To use the File notifier you will need to add something like the following
to your configuration.yaml file.
notify:
platform: file
filename: FILENAME
timestamp: 1 or 0
Variables:
filename
*Required
Name of the file to use. The file will be created if it doesn't exist and saved
in your config/ folder.
timestamp
*Required
Add a timestamp to the entry, valid entries are 1 or 0.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.file/
"""
import logging
import os
@@ -38,14 +20,14 @@ _LOGGER = logging.getLogger(__name__)
def get_service(hass, config):
""" Get the file notification service. """
if not validate_config(config,
if not validate_config({DOMAIN: config},
{DOMAIN: ['filename',
'timestamp']},
_LOGGER):
return None
filename = config[DOMAIN]['filename']
timestamp = config[DOMAIN]['timestamp']
filename = config['filename']
timestamp = config['timestamp']
return FileNotificationService(hass, filename, timestamp)
+23 -95
View File
@@ -3,56 +3,14 @@ homeassistant.components.notify.instapush
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Instapush notification service.
Configuration:
To use the Instapush notifier you will need to add something like the following
to your configuration.yaml file.
notify:
platform: instapush
api_key: YOUR_APP_KEY
app_secret: YOUR_APP_SECRET
event: YOUR_EVENT
tracker: YOUR_TRACKER
Variables:
api_key
*Required
To retrieve this value log into your account at https://instapush.im and go
to 'APPS', choose an app, and check 'Basic Info'.
app_secret
*Required
To get this value log into your account at https://instapush.im and go to
'APPS'. The 'Application ID' can be found under 'Basic Info'.
event
*Required
To retrieve a valid event log into your account at https://instapush.im and go
to 'APPS'. If you have no events to use with Home Assistant, create one event
for your app.
tracker
*Required
To retrieve the tracker value log into your account at https://instapush.im and
go to 'APPS', choose the app, and check the event entries.
Example usage of Instapush if you have an event 'notification' and a tracker
'home-assistant'.
curl -X POST \
-H "x-instapush-appid: YOUR_APP_KEY" \
-H "x-instapush-appsecret: YOUR_APP_SECRET" \
-H "Content-Type: application/json" \
-d '{"event":"notification","trackers":{"home-assistant":"Switch 1"}}' \
https://api.instapush.im/v1/post
Details for the API : https://instapush.im/developer/rest
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.instapush/
"""
import logging
import json
import requests
from homeassistant.helpers import validate_config
from homeassistant.components.notify import (
DOMAIN, ATTR_TITLE, BaseNotificationService)
@@ -65,7 +23,7 @@ _RESOURCE = 'https://api.instapush.im/v1/'
def get_service(hass, config):
""" Get the instapush notification service. """
if not validate_config(config,
if not validate_config({DOMAIN: config},
{DOMAIN: [CONF_API_KEY,
'app_secret',
'event',
@@ -73,52 +31,29 @@ def get_service(hass, config):
_LOGGER):
return None
headers = {'x-instapush-appid': config[CONF_API_KEY],
'x-instapush-appsecret': config['app_secret']}
try:
import requests
except ImportError:
_LOGGER.exception(
"Unable to import requests. "
"Did you maybe not install the 'Requests' package?")
response = requests.get(_RESOURCE + 'events/list',
headers=headers).json()
except ValueError:
_LOGGER.error('Unexpected answer from Instapush API.')
return None
# pylint: disable=unused-variable
try:
response = requests.get(_RESOURCE)
if 'error' in response:
_LOGGER.error(response['msg'])
return None
except requests.ConnectionError:
if len([app for app in response if app['title'] == config['event']]) == 0:
_LOGGER.error(
"Connection error "
"Please check if https://instapush.im is available.")
"No app match your given value. "
"Please create an app at https://instapush.im")
return None
instapush = requests.Session()
headers = {'x-instapush-appid': config[DOMAIN][CONF_API_KEY],
'x-instapush-appsecret': config[DOMAIN]['app_secret']}
response = instapush.get(_RESOURCE + 'events/list',
headers=headers)
try:
if response.json()['error']:
_LOGGER.error(response.json()['msg'])
# pylint: disable=bare-except
except:
try:
next(events for events in response.json()
if events['title'] == config[DOMAIN]['event'])
except StopIteration:
_LOGGER.error(
"No event match your given value. "
"Please create an event at https://instapush.im")
else:
return InstapushNotificationService(
config[DOMAIN].get(CONF_API_KEY),
config[DOMAIN]['app_secret'],
config[DOMAIN]['event'],
config[DOMAIN]['tracker']
)
return InstapushNotificationService(
config[CONF_API_KEY], config['app_secret'], config['event'],
config['tracker'])
# pylint: disable=too-few-public-methods
@@ -126,9 +61,6 @@ class InstapushNotificationService(BaseNotificationService):
""" Implements notification service for Instapush. """
def __init__(self, api_key, app_secret, event, tracker):
# pylint: disable=no-name-in-module, unused-variable
from requests import Session
self._api_key = api_key
self._app_secret = app_secret
self._event = event
@@ -138,8 +70,6 @@ class InstapushNotificationService(BaseNotificationService):
'x-instapush-appsecret': self._app_secret,
'Content-Type': 'application/json'}
self.instapush = Session()
def send_message(self, message="", **kwargs):
""" Send a message to a user. """
@@ -148,10 +78,8 @@ class InstapushNotificationService(BaseNotificationService):
data = {"event": self._event,
"trackers": {self._tracker: title + " : " + message}}
response = self.instapush.post(
_RESOURCE + 'post',
data=json.dumps(data),
headers=self._headers)
response = requests.post(_RESOURCE + 'post', data=json.dumps(data),
headers=self._headers)
if response.json()['status'] == 401:
_LOGGER.error(
+18 -48
View File
@@ -3,27 +3,14 @@ homeassistant.components.notify.nma
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NMA (Notify My Android) notification service.
Configuration:
To use the NMA notifier you will need to add something like the following
to your configuration.yaml file.
notify:
platform: nma
api_key: YOUR_API_KEY
Variables:
api_key
*Required
Enter the API key for NMA. Go to https://www.notifymyandroid.com and create a
new API key to use with Home Assistant.
Details for the API : https://www.notifymyandroid.com/api.jsp
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.nma/
"""
import logging
import xml.etree.ElementTree as ET
import requests
from homeassistant.helpers import validate_config
from homeassistant.components.notify import (
DOMAIN, ATTR_TITLE, BaseNotificationService)
@@ -36,31 +23,20 @@ _RESOURCE = 'https://www.notifymyandroid.com/publicapi/'
def get_service(hass, config):
""" Get the NMA notification service. """
if not validate_config(config,
if not validate_config({DOMAIN: config},
{DOMAIN: [CONF_API_KEY]},
_LOGGER):
return None
try:
# pylint: disable=unused-variable
from requests import Session
except ImportError:
_LOGGER.exception(
"Unable to import requests. "
"Did you maybe not install the 'Requests' package?")
return None
nma = Session()
response = nma.get(_RESOURCE + 'verify',
params={"apikey": config[DOMAIN][CONF_API_KEY]})
response = requests.get(_RESOURCE + 'verify',
params={"apikey": config[CONF_API_KEY]})
tree = ET.fromstring(response.content)
if tree[0].tag == 'error':
_LOGGER.error("Wrong API key supplied. %s", tree[0].text)
else:
return NmaNotificationService(config[DOMAIN][CONF_API_KEY])
return None
return NmaNotificationService(config[CONF_API_KEY])
# pylint: disable=too-few-public-methods
@@ -68,26 +44,20 @@ class NmaNotificationService(BaseNotificationService):
""" Implements notification service for NMA. """
def __init__(self, api_key):
# pylint: disable=no-name-in-module, unused-variable
from requests import Session
self._api_key = api_key
self._data = {"apikey": self._api_key}
self.nma = Session()
def send_message(self, message="", **kwargs):
""" Send a message to a user. """
title = kwargs.get(ATTR_TITLE)
data = {
"apikey": self._api_key,
"application": 'home-assistant',
"event": kwargs.get(ATTR_TITLE),
"description": message,
"priority": 0,
}
self._data['application'] = 'home-assistant'
self._data['event'] = title
self._data['description'] = message
self._data['priority'] = 0
response = self.nma.get(_RESOURCE + 'notify',
params=self._data)
response = requests.get(_RESOURCE + 'notify', params=data)
tree = ET.fromstring(response.content)
if tree[0].tag == 'error':
+86 -40
View File
@@ -3,73 +3,119 @@ homeassistant.components.notify.pushbullet
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PushBullet platform for notify component.
Configuration:
To use the PushBullet notifier you will need to add something like the
following to your configuration.yaml file.
notify:
platform: pushbullet
api_key: YOUR_API_KEY
Variables:
api_key
*Required
Enter the API key for PushBullet. Go to https://www.pushbullet.com/ to retrieve
your API key.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.pushbullet/
"""
import logging
from homeassistant.helpers import validate_config
from homeassistant.components.notify import (
DOMAIN, ATTR_TITLE, BaseNotificationService)
ATTR_TITLE, ATTR_TARGET, BaseNotificationService)
from homeassistant.const import CONF_API_KEY
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['pushbullet.py==0.7.1']
REQUIREMENTS = ['pushbullet.py==0.9.0']
# pylint: disable=unused-argument
def get_service(hass, config):
""" Get the PushBullet notification service. """
from pushbullet import PushBullet
from pushbullet import InvalidKeyError
if not validate_config(config,
{DOMAIN: [CONF_API_KEY]},
_LOGGER):
if CONF_API_KEY not in config:
_LOGGER.error("Unable to find config key '%s'", CONF_API_KEY)
return None
try:
# pylint: disable=unused-variable
from pushbullet import PushBullet, InvalidKeyError # noqa
except ImportError:
_LOGGER.exception(
"Unable to import pushbullet. "
"Did you maybe not install the 'pushbullet.py' package?")
return None
try:
return PushBulletNotificationService(config[DOMAIN][CONF_API_KEY])
pushbullet = PushBullet(config[CONF_API_KEY])
except InvalidKeyError:
_LOGGER.error(
"Wrong API key supplied. "
"Get it at https://www.pushbullet.com/account")
return None
return PushBulletNotificationService(pushbullet)
# pylint: disable=too-few-public-methods
class PushBulletNotificationService(BaseNotificationService):
""" Implements notification service for Pushbullet. """
def __init__(self, api_key):
from pushbullet import PushBullet
def __init__(self, pb):
self.pushbullet = pb
self.pbtargets = {}
self.refresh()
self.pushbullet = PushBullet(api_key)
def refresh(self):
'''
Refresh devices, contacts, channels, etc
def send_message(self, message="", **kwargs):
""" Send a message to a user. """
pbtargets stores all targets available from this pushbullet instance
into a dict. These are PB objects!. It sacrifices a bit of memory
for faster processing at send_message
'''
self.pushbullet.refresh()
self.pbtargets = {
'device':
{tgt.nickname: tgt for tgt in self.pushbullet.devices},
'contact':
{tgt.email: tgt for tgt in self.pushbullet.contacts},
'channel':
{tgt.channel_tag: tgt for tgt in self.pushbullet.channels},
}
def send_message(self, message=None, **kwargs):
"""
Send a message to a specified target.
If no target specified, a 'normal' push will be sent to all devices
linked to the PB account.
"""
targets = kwargs.get(ATTR_TARGET)
title = kwargs.get(ATTR_TITLE)
refreshed = False
self.pushbullet.push_note(title, message)
if not targets:
# Backward compatebility, notify all devices in own account
self.pushbullet.push_note(title, message)
_LOGGER.info('Sent notification to self')
return
# Make list if not so
if not isinstance(targets, list):
targets = [targets]
# Main loop, Process all targets specified
for target in targets:
# Allow for untargeted push, combined with other types
if target in ['device', 'device/']:
self.pushbullet.push_note(title, message)
_LOGGER.info('Sent notification to self')
continue
try:
ttype, tname = target.split('/', 1)
except ValueError:
_LOGGER.error('Invalid target syntax: %s', target)
continue
# Refresh if name not found. While awaiting periodic refresh
# solution in component, poor mans refresh ;)
if ttype not in self.pbtargets:
_LOGGER.error('Invalid target syntax: %s', target)
continue
if tname not in self.pbtargets[ttype] and not refreshed:
self.refresh()
refreshed = True
# Attempt push_note on a dict value. Keys are types & target
# name. Dict pbtargets has all *actual* targets.
try:
self.pbtargets[ttype][tname].push_note(title, message)
except KeyError:
_LOGGER.error('No such target: %s.%s', ttype, tname)
continue
except self.pushbullet.errors.PushError:
_LOGGER.error('Notify failed to: %s.%s', ttype, tname)
continue
_LOGGER.info('Sent notification to %s.%s', ttype, tname)
@@ -0,0 +1,63 @@
"""
homeassistant.components.notify.pushetta
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pushetta platform for notify component.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.pushetta/
"""
import logging
from homeassistant.helpers import validate_config
from homeassistant.components.notify import (
DOMAIN, ATTR_TITLE, BaseNotificationService)
from homeassistant.const import CONF_API_KEY
_LOGGER = logging.getLogger(__name__)
REQUIREMENTS = ['pushetta==1.0.15']
def get_service(hass, config):
""" Get the Pushetta notification service. """
from pushetta import Pushetta, exceptions
if not validate_config({DOMAIN: config},
{DOMAIN: [CONF_API_KEY, 'channel_name']},
_LOGGER):
return None
try:
pushetta = Pushetta(config[CONF_API_KEY])
pushetta.pushMessage(config['channel_name'], "Home Assistant started")
except exceptions.TokenValidationError:
_LOGGER.error("Please check your access token")
return None
except exceptions.ChannelNotFoundError:
_LOGGER.error("Channel '%s' not found", config['channel_name'])
return None
return PushettaNotificationService(config[CONF_API_KEY],
config['channel_name'])
# pylint: disable=too-few-public-methods
class PushettaNotificationService(BaseNotificationService):
""" Implements notification service for Pushetta. """
def __init__(self, api_key, channel_name):
from pushetta import Pushetta
self._api_key = api_key
self._channel_name = channel_name
self.pushetta = Pushetta(self._api_key)
def send_message(self, message="", **kwargs):
""" Send a message to a user. """
title = kwargs.get(ATTR_TITLE)
self.pushetta.pushMessage(self._channel_name,
"{} {}".format(title, message))
+9 -50
View File
@@ -3,35 +3,8 @@ homeassistant.components.notify.pushover
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pushover platform for notify component.
Configuration:
To use the Pushover notifier you will need to add something like the following
to your configuration.yaml file.
notify:
platform: pushover
api_key: ABCDEFGHJKLMNOPQRSTUVXYZ
user_key: ABCDEFGHJKLMNOPQRSTUVXYZ
Variables:
api_key
*Required
This parameter is optional but should be configured, in order to get an API
key you should go to https://pushover.net and register a new application.
This is a quote from the pushover website regarding free/open source apps:
"If you are creating a client-side library, application, or open source project
that will be redistributed and installed by end-users, you may want to require
each of your users to register their own application rather than including your
own API token with the software."
When setting up the application I recommend using the icon located here:
https://home-assistant.io/images/favicon-192x192.png
user_key
*Required
To retrieve this value log into your account at https://pushover.net
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.pushover/
"""
import logging
@@ -48,32 +21,21 @@ _LOGGER = logging.getLogger(__name__)
def get_service(hass, config):
""" Get the pushover notification service. """
if not validate_config(config,
if not validate_config({DOMAIN: config},
{DOMAIN: ['user_key', CONF_API_KEY]},
_LOGGER):
return None
try:
# pylint: disable=no-name-in-module, unused-variable
from pushover import InitError
except ImportError:
_LOGGER.exception(
"Unable to import pushover. "
"Did you maybe not install the 'python-pushover.py' package?")
return None
from pushover import InitError
try:
api_token = config[DOMAIN].get(CONF_API_KEY)
return PushoverNotificationService(
config[DOMAIN]['user_key'],
api_token)
return PushoverNotificationService(config['user_key'],
config[CONF_API_KEY])
except InitError:
_LOGGER.error(
"Wrong API key supplied. "
"Get it at https://pushover.net")
return None
# pylint: disable=too-few-public-methods
@@ -81,7 +43,6 @@ class PushoverNotificationService(BaseNotificationService):
""" Implements notification service for Pushover. """
def __init__(self, user_key, api_token):
# pylint: disable=no-name-in-module, unused-variable
from pushover import Client
self._user_key = user_key
self._api_token = api_token
@@ -90,11 +51,9 @@ class PushoverNotificationService(BaseNotificationService):
def send_message(self, message="", **kwargs):
""" Send a message to a user. """
# pylint: disable=no-name-in-module
from pushover import RequestError
title = kwargs.get(ATTR_TITLE)
try:
self.pushover.send_message(message, title=title)
self.pushover.send_message(message, title=kwargs.get(ATTR_TITLE))
except RequestError:
_LOGGER.exception("Could not send pushover notification")
@@ -0,0 +1,15 @@
notify:
description: Send a notification
fields:
message:
description: Message body of the notification.
example: The garage door has been open for 10 minutes.
title:
description: Optional title for your notification.
example: 'Your Garage Door Friend'
target:
description: Target of the notification. Optional depending on the platform
example: platform specific
+14 -45
View File
@@ -3,33 +3,13 @@ homeassistant.components.notify.slack
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Slack platform for notify component.
Configuration:
To use the Slack notifier you will need to add something like the following
to your configuration.yaml file.
notify:
platform: slack
api_key: ABCDEFGHJKLMNOPQRSTUVXYZ
default_channel: '#general'
Variables:
api_key
*Required
The slack API token to use for sending slack messages.
You can get your slack API token here https://api.slack.com/web?sudo=1
default_channel
*Required
The default channel to post to if no channel is explicitly specified when
sending the notification message.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/notify.slack/
"""
import logging
from homeassistant.helpers import validate_config
from homeassistant.components.notify import (
DOMAIN, BaseNotificationService)
from homeassistant.components.notify import DOMAIN, BaseNotificationService
from homeassistant.const import CONF_API_KEY
REQUIREMENTS = ['slacker==0.6.8']
@@ -39,34 +19,22 @@ _LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-variable
def get_service(hass, config):
""" Get the slack notification service. """
import slacker
if not validate_config(config,
if not validate_config({DOMAIN: config},
{DOMAIN: ['default_channel', CONF_API_KEY]},
_LOGGER):
return None
try:
# pylint: disable=no-name-in-module, unused-variable
from slacker import Error as SlackError
except ImportError:
_LOGGER.exception(
"Unable to import slacker. "
"Did you maybe not install the 'slacker.py' package?")
return None
try:
api_token = config[DOMAIN].get(CONF_API_KEY)
return SlackNotificationService(
config[DOMAIN]['default_channel'],
api_token)
config['default_channel'],
config[CONF_API_KEY])
except SlackError as ex:
_LOGGER.error(
except slacker.Error:
_LOGGER.exception(
"Slack authentication failed")
_LOGGER.exception(ex)
return None
# pylint: disable=too-few-public-methods
@@ -75,6 +43,7 @@ class SlackNotificationService(BaseNotificationService):
def __init__(self, default_channel, api_token):
from slacker import Slacker
self._default_channel = default_channel
self._api_token = api_token
self.slack = Slacker(self._api_token)
@@ -82,11 +51,11 @@ class SlackNotificationService(BaseNotificationService):
def send_message(self, message="", **kwargs):
""" Send a message to a user. """
import slacker
from slacker import Error as SlackError
channel = kwargs.get('channel', self._default_channel)
try:
self.slack.chat.post_message(channel, message)
except SlackError as ex:
except slacker.Error:
_LOGGER.exception("Could not send slack notification")
_LOGGER.exception(ex)

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