commit 1baa895f41801155a4cdd0be7bf2046625650dfb Author: root Date: Mon Jan 1 19:00:45 2018 -0500 Massive Migration! #292 diff --git a/.HA_VERSION b/.HA_VERSION new file mode 100755 index 00000000..851b5917 --- /dev/null +++ b/.HA_VERSION @@ -0,0 +1 @@ +0.59.2 \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100755 index 00000000..3170c148 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,173 @@ +## GITATTRIBUTES FOR WEB PROJECTS +# +# These settings are for any web project. +# +# Details per file setting: +# text These files should be normalized (i.e. convert CRLF to LF). +# binary These files are binary and should be left untouched. +# +# Note that binary is a macro for -text -diff. +###################################################################### + +## AUTO-DETECT - Handle line endings automatically for files detected +## as text and leave all files detected as binary untouched. +## This will handle all files NOT defined below. +* text=auto + +## SOURCE CODE +*.bat text +*.coffee text +*.css text +*.htm text +*.html text +*.inc text +*.ini text +*.js text +*.jsx text +*.json text +*.less text +*.php text +*.pl text +*.py text +*.rb text +*.sass text +*.scm text +*.scss text +*.sh text +*.sql text +*.styl text +*.ts text +*.xml text +*.xhtml text + +## DOCUMENTATION +*.markdown text +*.md text +*.mdwn text +*.mdown text +*.mkd text +*.mkdn text +*.mdtxt text +*.mdtext text +*.txt text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +INSTALL text +license text +LICENSE text +NEWS text +readme text +*README* text +TODO text + +## TEMPLATES +*.dot text +*.ejs text +*.haml text +*.handlebars text +*.hbs text +*.hbt text +*.jade text +*.latte text +*.mustache text +*.phtml text +*.tmpl text + +## LINTERS +.csslintrc text +.eslintrc text +.jscsrc text +.jshintrc text +.jshintignore text +.stylelintrc text + +## CONFIGS +*.bowerrc text +*.cnf text +*.conf text +*.config text +.editorconfig text +.gitattributes text +.gitconfig text +.gitignore text +.htaccess text +*.npmignore text +*.yaml text +*.yml text +Makefile text +makefile text + +## HEROKU +Procfile text +.slugignore text + +## GRAPHICS +*.ai binary +*.bmp binary +*.eps binary +*.gif binary +*.ico binary +*.jng binary +*.jp2 binary +*.jpg binary +*.jpeg binary +*.jpx binary +*.jxr binary +*.pdf binary +*.png binary +*.psb binary +*.psd binary +*.svg text +*.svgz binary +*.tif binary +*.tiff binary +*.wbmp binary +*.webp binary + +## AUDIO +*.kar binary +*.m4a binary +*.mid binary +*.midi binary +*.mp3 binary +*.ogg binary +*.ra binary + +## VIDEO +*.3gpp binary +*.3gp binary +*.as binary +*.asf binary +*.asx binary +*.fla binary +*.flv binary +*.m4v binary +*.mng binary +*.mov binary +*.mp4 binary +*.mpeg binary +*.mpg binary +*.swc binary +*.swf binary +*.webm binary + +## ARCHIVES +*.7z binary +*.gz binary +*.rar binary +*.tar binary +*.zip binary + +## FONTS +*.ttf binary +*.eot binary +*.otf binary +*.woff binary +*.woff2 binary + +## EXECUTABLES +*.exe binary +*.pyc binary \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100755 index 00000000..8a323ab8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +*.pid +*.xml +*.csr +*.crt +*.key +*.conf +*.pickle +OZW_Log.txt +home-assistant.log +home-assistant_v2.db +*.db-journal +*.db-shm +*.db-wal +*.sqlite +deps +__pycache__ +tts +secrets.yaml +secrets +known_devices.yaml +phue.conf +ios.conf +pyozw.sqlite +nest.conf +.uuid +ipchange.yaml diff --git a/.travis.yml b/.travis.yml new file mode 100755 index 00000000..4729981f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: python +python: + - "3.4" +install: + - pip3 install homeassistant +script: + - hass -c . --script check_config +before_install: + - mv travis_secrets.yaml secrets.yaml diff --git a/README.md b/README.md new file mode 100755 index 00000000..95809e93 --- /dev/null +++ b/README.md @@ -0,0 +1,115 @@ +# [![Build Status](https://travis-ci.org/CCOSTAN/Home-AssistantConfig.svg?branch=master)](https://travis-ci.org/CCOSTAN/Home-AssistantConfig) Home-Assistant Config by [@ccostan](http://www.twitter.com/ccostan) +[Home Assistant](https://home-assistant.io/) configuration files (YAMLs) + +Be sure to :star: my repo so you can keep up to date on the daily progress! + +You can also vist my [Blog](http://www.vmwareinfo.com/search/label/iot) for all of my [Home Automation Posts](http://www.vmwareinfo.com/search/label/iot). + +You can follow my home's breaking news and tweet statistics via twitter [BearStoneHA](https://twitter.com/bearstoneha) + +![Screenshot of Home Assistant Header](https://i.imgur.com/vjDH1LJ.png) + +This is my Home Assistant Configuration created with the All In One installer [expanded to 16GB.](https://community.home-assistant.io/t/expanding-partition-on-sd-card-for-raspberry-pi-with-noobs-pre-installed/2036) I update it pretty regularly. :star: +Home Assistant runs on my [Raspberry Pi 3](http://amzn.to/2e3DOBY) with [Aeon Labs Z Wave Stick (GEN 5)](http://amzn.to/2eAiAP0). I've also added a [433Mhz Transmitter and receiver](http://amzn.to/2dceNY2). The main [SD Card](http://amzn.to/2xeBlgf) was upgraded to 16GB. (Order 2! - 1 for backup) +I use an [SD Card reader](http://amzn.to/2l2w9as) to swap SD cards between Pi and Windows for backups. + +**Software on the Pi :** +* [Home Assistant](https://home-assistant.io/) , +* [Dasher](https://github.com/maddox/dasher) to leverage those cheap [Amazon Dash Buttons](http://amzn.to/2dPKZhM) +* SSL via [SSLS](https://SSLS.com) - 5 Bucks A Year! - Keeps me safe! +* [HomeBridge](https://github.com/nfarina/homebridge) for full HA <-> Homekit compatibility. +* The amazing [Floorplan](https://github.com/pkozul/ha-floorplan) project to help visualize my smarthome. + +**Devices I have :** +* [Ubiquiti Networks Unifi 802.11ac Pro](http://amzn.to/2mBSfE9) This keeps me warm with it's Wifi rays blanketing the house. Also used as a presence Tracker for iPhones/People. +* Lots of iOS Devices ([iPads](http://amzn.to/2l2qyRb), iPods, [iPhones](http://amzn.to/2l9Yoq9)) +* [Nest Thermostats](http://amzn.to/2eAhB1k) - Smart Thermostat +* [Nest Protects](http://amzn.to/2poqKhu) - Smart Smoke Detectors - [Blog Post](http://www.vmwareinfo.com/2017/06/psa-check-out-your-smoke-detectors-once.html) +* [Amazon Echo](http://amzn.to/2dSVbK4) and [DOT](http://amzn.to/2e3vHFQ) +* [Amazon Echo Tap](http://amzn.to/2sz891k) +* [Amazon Dash Buttons](http://amzn.to/2dPKZhM) +* [Amazon Dash Wand](https://www.amazon.com/Amazon-Dash-Wand-With-Alexa/dp/B01MQMJFDK/ref=sr_1_1_a_it?ie=UTF8&qid=1498928735&sr=8-1&keywords=dash+wand) - Alexa outside by the pool area. +* [Amazon Fire TV](http://amzn.to/2iiuaNT) +* [Amazon Fire Tablets Gen 7](http://amzn.to/2tqlMCW)- Used for [Wall Mounted Controllers](http://www.vmwareinfo.com/2017/07/visualizing-smart-home-using-home.html) +* [Wink Hub](http://amzn.to/2orGEWo) - Used to connect certain Zwave outlets etc. +* [Phillips Hue Hub Gen 2](http://amzn.to/2eoQTJy) +* Mixture of [Hue Colored lights](http://amzn.to/2l2viGK), [White Lights](http://amzn.to/2lEf4Xq) and GE Link bulbs. +* [Hue Go](http://amzn.to/2iB36Ii) - Great lights for the kids since they have an actual button on them for control. +* [Circle by Disney](http://amzn.to/2eAgaA6) - Parental Monitor for internet and screentime. +* [Rachio Sprinkler system](http://amzn.to/2eoPKBW) - Smart Sprinkler controller +* [GE ZWave Outdoor Power Module](http://amzn.to/2q17R4S) - These control my Landscape lighting and connect up to my Wink. +* [Withings](http://amzn.to/2kr78nW) - Smart Weight scale +* [SkyBell HD](http://amzn.to/2dcexIB) +* [Rokus](http://amzn.to/2dpn89c) for all streaming +* [Samsung Smart TV](http://amzn.to/2efNNnq) +* [ChromeCast Audios](http://amzn.to/2lE9gNu) +* [AMPs](http://amzn.to/2j18dlT) - These are cheap but effective for the Dots, Chromecasts or other speakers. +* [Mixer](http://amzn.to/2v9Zp3x) - This allows me to mix in DOT, music and HA. [Blog Post](http://www.vmwareinfo.com/2017/07/giving-voice-to-smart-home.html) +* [Etekcity Outlets](http://amzn.to/2efNoBP) - Cheap 6 Buck RF outlet control! +* [Door Sensors (AEON Labs)](http://amzn.to/2e3xDxY) +* [Garadget](http://amzn.to/2jQLpVQ) - Garage Door opener/sensor - "[Siri, are my garage doors closed?](https://pbs.twimg.com/media/C3cyJZSWAAAalPm.jpg:large)" +* [Nintendo Wii](http://amzn.to/2l2qIYY) +* Emulated Hue pushes all Switch, Group, input_boolean, script and scene information to Alexa for First Class Control! +* [iTeadStudio](https://www.itead.cc/) [goodies](https://twitter.com/ccostan/status/793119824008384512) - [SonOff](http://amzn.to/2l2sx8g) and a [Slampher](http://amzn.to/2l2gmIx)! +* [LED RGB Wifi Controller - flux_led compatible](http://amzn.to/2jUBSBE) with [LED Strip kits](http://amzn.to/2gJYfZ5) - ~100 Feet. These are great [Power supplies](http://amzn.to/2mnmbk8) - [Outdoor Housing](http://amzn.to/2m2dG0X) - Finished Product [#71](https://github.com/CCOSTAN/Home-AssistantConfig/issues/71) - [Blog Post](http://www.vmwareinfo.com/2017/08/diy-outdoor-smart-home-led-strips.html) +* [Digital Smart Water Main ShutOff/Leak Detector] (http://www.providencecpc.org/wp-content/uploads/2016/01/work_in_progress.png) - Beta test to monitor Water usage and Leaks centrally. +* [Aeon Labs AEDSB09104ZWUS Aeotec Z-Wave Smart Energy Monitor Meter](http://amzn.to/2l5wEDo) to measure energy usage in the home. +* [SleepNumber Bed i8](http://amzn.to/2kxdXXI) - Has SleepIQ to track occupancy and sleep habits. Tied into HA. +* [MX8 Zodiac Pool Robot](http://amzn.to/2nAGvPf) - Not YET hooked up HA, but working on it. +* [Pi Zero](http://amzn.to/2ougZQ3) with [Wireless Nub](http://amzn.to/2q38rg4) running Pi-Hole and smacking down internet ads left and right! +* [NodeMCU Development Boards](http://amzn.to/2ou0NON) hooked into the alarm system wires for [DIY alarm system](http://www.vmwareinfo.com/2017/06/building-my-home-alarm-system-hardware.html). - [DIY Motion Sensors](http://www.vmwareinfo.com/2017/11/yet-another-inexpensive-motion-sensor.html) +* [JuiceBox Pro 40 EVSE](http://amzn.to/2AIdSdx) - Used to Charge the Bolt EV. + +Lots of my gear comes from [BetaBound](https://goo.gl/0vxT8A) for Beta Testing and reviews. + + Sponsor + + +**Automations:** +* Voice Notifications via the [AMPs](http://amzn.to/2j18dlT) connected to ChromeCast Audios and [Mixer](http://amzn.to/2v9Zp3x). Accomplished via the [~~Google~~ Amazon Polly TTS](https://home-assistant.io/components/tts/) component. +* Ability to ask Alexa to repeat the last Voice notification - 'Alexa, Turn on Last message'. +* Track garbage days and chore days for the kids. Voice reminders and Alexa intergration/request for info. +* Guest mode to disable certain interior automations. Trigger via Alexa & IFTTT. +* IFTTT and Slack Notifications for Offline Devices, BadLogins, HA Startups, new HA versions and [External IP changes](https://community.home-assistant.io/t/detect-if-ip-changes/6830) for DSN. +* Monitor the reflection rates of [Garadget](http://amzn.to/2jQLpVQ) and notify when they being to drop too low when closed (indicating a shift in the controller) +* Notifications when the garage door is left open at night or when we leave the house. +* (IFTTT) Logging entries in Logbooks for [Rachio Sprinkler system](http://amzn.to/2eoPKBW), and [SkyBell HD](http://amzn.to/2dcexIB). +* Auto Heal ZWave at 2:30am +* Using [Etekcity Outlets](http://amzn.to/2efNoBP) to control accent lighting above kitchen cabinets and room cutouts. +* Turn on Hallway light for no more than 20 minutes when Pantry door is opened. +* Turn on TV Time Lights (dim and color) at Sunset (if home and TV is on) +* Turn on Upstairs light if [Nest Thermostats](http://amzn.to/2eAhB1k) detects people and it's nighttime. +* Turn off lights when [Nest Thermostats](http://amzn.to/2eAhB1k) detects we are away. (Upstairs and Downstairs) +* Turn on some lights and switches when we get home +* Turn on some outdoor Lights at Sunset or if it gets darkish in the house, Turn off 4 hours before sunrise. Turn off interior lights when we go to sleep. +* Turn on lights during school days for a morning routine for the kids and wife. Has No School overide boolean in GUI. +* Rainy days trigger extra light inside the house. +* Check the UV Rays for the day and let us know if we need sun tan lotion over the TTS system. +* Detects when lights are turned on and adjusts them to correct brightness based on time of day. +* Leverage Alexa, IFTTT and Elekcity outlet to control Printer On/Off via Voice. Turns off automatically after 20 minutes. +* Turn on [AMPs](http://amzn.to/2j18dlT) when Chromecast reports 'Playing'. Turn them off when we are done streaming music. +* (IFTTT) Blink ALL lights at 9:30 to remind me to take medicine. (also Alexa Alert) +* (IFTTT) Blink Office lights 15 minutes before ANY meeting on my calendar (using IFTTT) +* (IFTTT) Stop watering grass via [Rachio Sprinkler system](http://amzn.to/2eoPKBW) if winds are greater than 20 MPH. +* (IFTTT) Add a 1 day rain delay to [Rachio Sprinkler system](http://amzn.to/2eoPKBW) if it is going to rain tomorrow. +* (IFTTT) Blink ALL lights if Winds get to 70MPH - Hurricance warning. +* (IFTTT) Trigger Good Night routine when I step on the [Withings](http://amzn.to/2kr78nW) scale after 10pm. +* Sets up the front lights in the house with preset colors depending on the ~~month~~ day!. +* On motion from [SkyBell HD Doorbell](http://amzn.to/2dcexIB) (IFTTT) Turn front lights to Bright White lights for 10 minutes and then back to original colors. Fake Dog barking when there is motion by the house. +* When someone rings the Doorbell (IFTTT), the backyard and Bathroom lights Flash - Since we might not hear the doorbell. Fake Dog barks as well (which can be snoozed for 30 minutes via Alexa). +* Watch and alert on Home Assistant's Disk usage. Get alerts before Pi runs out of space on the [SD Card](http://amzn.to/2kNttio). +* Digital Cuckoo Clock that goes off each hour and on the half just like a real Cuckoo Clock. Plays across the whole house on my [ChromeCast Audios](http://amzn.to/2lE9gNu) + +#Todo List +I've moved this entire section to the [issues section](https://github.com/CCOSTAN/Home-AssistantConfig/issues) on github. +Feel free to join the conversations there. +![Screenshot of SmartHome](https://lh3.googleusercontent.com/-vKGF5gdz_VY/WVpP7qjsmjI/AAAAAAADVZ4/sGyiS1PjouUQxrEbWVfot6raxcElv4r-wCHMYCw/s1600/clip_image001%255B4%255D) +![Screenshot of Alarm Clock View](https://i.imgur.com/mLMrky1.jpg) +![Screenshot of Alarm View](https://i.imgur.com/nad2gq0.png) + +**All files are now being edited with [Atom](https://atom.io/).** + +**All of my configuration files are tested against the most stable version of home-assistant using [Travis](https://travis-ci.org/CCOSTAN/Home-AssistantConfig).** + +#Still have questions on my Config? +Message me on twitter : [@CCostan](https://twitter.com/ccostan) diff --git a/automation/Pool_Deck_lights.yaml b/automation/Pool_Deck_lights.yaml new file mode 100755 index 00000000..a1684e85 --- /dev/null +++ b/automation/Pool_Deck_lights.yaml @@ -0,0 +1,39 @@ +#------------------------------------------- +# When the Sliding door opens, at night, turn on Pool deck lights. +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- + +- alias: Pool Deck light helper + trigger: + - platform: state + entity_id: binary_sensor.MCU2_GPIO12 + to: 'on' + for: '00:3:00' + - platform: state + entity_id: sun.sun + to: 'below_horizon' + from: 'above_horizon' + + condition: + - condition: state + entity_id: sun.sun + state: 'below_horizon' + - condition: state + entity_id: binary_sensor.MCU2_GPIO12 + state: 'on' + - condition: numeric_state + entity_id: sensor.dark_sky_temperature + below: 80 + + action: + - service: switch.turn_on + entity_id: switch.back_landscaping + - service: light.turn_on + entity_id: group.outdoor_pool_lights + data: + color_temp: 369 + - wait_template: >- + {{ states.binary_sensor.MCU2_GPIO12.state == 'off' }} + - service: light.turn_off + entity_id: group.outdoor_pool_lights diff --git a/automation/Speech/High_Wind_Speed_Check.yaml b/automation/Speech/High_Wind_Speed_Check.yaml new file mode 100755 index 00000000..8281ad8c --- /dev/null +++ b/automation/Speech/High_Wind_Speed_Check.yaml @@ -0,0 +1,37 @@ +################################### +## Tornados are no Joke. +################################### + +- alias: 'High Wind Speed Notification' + hide_entity: True + trigger: + - platform: numeric_state + entity_id: sensor.dark_sky_wind_speed + above: 50 + + action: + - service: script.notify_engine + data_template: + value1: 'VERY HIGH WINDS:' + value2: "{{ states('sensor.dark_sky_wind_speed')}}" + value3: ' ' + + - service: input_boolean.turn_on + entity_id: input_boolean.alert_mode + + - service: script.speech_engine + data_template: + value1: > + "ATTENTION: The wind speed is now {{ states('sensor.dark_sky_wind_speed')|round}} miles per hour. Please make sure everyone is inside for safety." + call_window_check: 1 + call_garage_check: 1 + + - service: script.emergency + + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "Wind speed is {{ states('sensor.dark_sky_wind_speed')|round}} miles per hour. For safety, I'm going to close the @garadget doors.", + "Getting pretty windy! {{ states('sensor.dark_sky_wind_speed')|round}}MPH. Time to ask @Garadget to close the garage doors." + ] | random + "(http://amzn.to/2jQLpVQ)"}} diff --git a/automation/Speech/README.md b/automation/Speech/README.md new file mode 100755 index 00000000..3a2a654e --- /dev/null +++ b/automation/Speech/README.md @@ -0,0 +1,15 @@ +# [![Build Status](https://travis-ci.org/CCOSTAN/Home-AssistantConfig.svg?branch=master)](https://travis-ci.org/CCOSTAN/Home-AssistantConfig) Home-Assistant Config by [@ccostan](http://www.twitter.com/ccostan) +[Home Assistant](https://home-assistant.io/) configuration files (YAMLs) + +Be sure to :star: my repo so you can keep up to date on the daily progress! + +This directory is for all the speech only Automations. These speech scripts use a speechengine in the scripts folder but the automations generate all the text (mostly). + +#Still have questions on my Config? +Follow me on twitter : [@CCostan](https://twitter.com/ccostan) + +You can also vist my [Blog](http://www.vmwareinfo.com/search/label/iot) for all of my [Home Automation Posts](http://www.vmwareinfo.com/search/label/iot). + + + Sponsor + diff --git a/automation/Speech/announcements.yaml b/automation/Speech/announcements.yaml new file mode 100755 index 00000000..37c75e35 --- /dev/null +++ b/automation/Speech/announcements.yaml @@ -0,0 +1,41 @@ +########## ############################################################ +## Announce when people come or go. +## Announce over all Chromecast Audios +###################################################################### +- alias: 'People Greeting' + + trigger: + - platform: state + entity_id: + - device_tracker.carlo + - device_tracker.stacey + - device_tracker.franco + - device_tracker.yolanda + from: 'not_home' + to: 'home' + for: '00:02:00' + + action: + - service: script.speech_engine + data_template: + personarriving: > + {% set person = trigger.entity_id.split('.')[1]|replace('_', ' ')%} + {%- macro greeting_sentence(person) -%} + {{ [ + "Welcome back home " ~ person, + "Guess who is home?" ~ person +" is!", + person + " is now in the house.", + "Welcome Home " ~ person + ". We have missed you. Or at least Molly did.", + "Our home is now complete, Rest your head and relax your feet! Welcome Back " ~ person, + "Life is like a song, you’re back where you belong. Welcome home " ~ person, + "Hey there " ~ person + " Welcome Home!", + "Knock Knock. Who is There? " ~ person +" is!", + person ~ "! You are home!", + "I know a secret! " ~ person +" is home!" + ] | random }} + {%- endmacro -%} + {{greeting_sentence(person)}} + call_responsibilities: 1 + call_no_announcement: 1 + call_garage_check: 1 + call_window_check: 1 diff --git a/automation/Speech/door_opened.yaml b/automation/Speech/door_opened.yaml new file mode 100755 index 00000000..259535c4 --- /dev/null +++ b/automation/Speech/door_opened.yaml @@ -0,0 +1,27 @@ +###################################################################### +## Garage Status Announcements +###################################################################### +- alias: 'Door Opened' + + trigger: + - platform: state + entity_id: + - binary_sensor.mcu2_gpio5 # back door # + - binary_sensor.MCU2_GPIO12 # Main Slider + - binary_sensor.MCU1_GPIO12 # Interior Garage Door # + to: 'Opened' + for: + minutes: 2 + + action: + - service: script.notify_engine + data_template: + value1: "The {{ trigger.to_state.attributes.friendly_name }} has been {{ (trigger.to_state.state)|replace('_', ' ') }}." + + - service: input_boolean.turn_on + entity_id: input_boolean.alert_mode + + - service: script.speech_engine + data_template: + call_window_check: 1 + call_inside_weather: 1 diff --git a/automation/Speech/garadget_Wind_Speed_Check.yaml b/automation/Speech/garadget_Wind_Speed_Check.yaml new file mode 100755 index 00000000..63c76ec4 --- /dev/null +++ b/automation/Speech/garadget_Wind_Speed_Check.yaml @@ -0,0 +1,48 @@ +################################### +## Garadget Stuff - [Garadget](http://amzn.to/2jQLpVQ) - Garage Door opener/sensor +################################### + +- alias: 'Wind Speed Garage Door Check' + hide_entity: True + trigger: + - platform: numeric_state + entity_id: sensor.dark_sky_wind_speed + above: 20 + + condition: + - condition: or + conditions: + - condition: template + value_template: "{{ states('cover.large_garage') == 'opened' }}" + - condition: template + value_template: "{{ states('cover.small_garage') == 'opened'}}" + + action: + - service: script.notify_engine + data_template: + value1: 'Check Garage Doors:' + value2: "Small: {{ states('cover.small_garage')}}" + value3: "Large: {{ states('cover.large_garage')}}" + + - service: input_boolean.turn_on + entity_id: input_boolean.alert_mode + + - service: script.speech_engine + data_template: + value1: > + "The winds are picking up outside. The wind speed is {{ states('sensor.dark_sky_wind_speed')|round}} miles per hour. For safety, please close the garage doors. + {% if is_state('cover.large_garage', 'open') -%} + The Large Garage Door is open + {% endif -%} + {% if is_state('cover.small_garage', 'open') -%} + {% if is_state('cover.large_garage', 'open') -%}and + {%- endif %} The small Garage Door is open. + {% endif %}" + + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "Wind speed is {{ states('sensor.dark_sky_wind_speed')|round}} miles per hour. For safety, I'm going to close the @garadget doors.", + "Getting pretty windy! {{ states('sensor.dark_sky_wind_speed')|round}}MPH. Time to ask @Garadget to close the garage doors." + ] | random + "(http://amzn.to/2jQLpVQ)"}} diff --git a/automation/Speech/garage_closed.yaml b/automation/Speech/garage_closed.yaml new file mode 100755 index 00000000..71653c7a --- /dev/null +++ b/automation/Speech/garage_closed.yaml @@ -0,0 +1,19 @@ +###################################################################### +## Garage Status Announcements - Only during normal hours. +###################################################################### +- alias: 'Garage Door closed' + + trigger: + - platform: state + entity_id: + - cover.large_garage + - cover.small_garage + from: 'open' + to: 'closed' + for: '00:02:00' + + action: + - service: script.speech_engine + data_template: + DoorClosed: "The {{ trigger.entity_id.split('.')[1]|replace('_', ' ') }} is now {{ (trigger.to_state.state)|replace('_', ' ') }}." + call_garage_check: 1 diff --git a/automation/Speech/garage_opened.yaml b/automation/Speech/garage_opened.yaml new file mode 100755 index 00000000..2a35c467 --- /dev/null +++ b/automation/Speech/garage_opened.yaml @@ -0,0 +1,28 @@ +###################################################################### +## Garage Status Announcements +###################################################################### +- alias: 'Garage Opened' + + trigger: + - platform: state + entity_id: + - cover.large_garage + - cover.small_garage + from: 'closed' + to: 'open' + for: '00:02:30' + + action: + - service_template: > + {% set hour=states("sensor.time").split(':')[0] | int %} + {% if hour >= 7 and hour <= 9 and states.input_boolean.school_mode.state == 'on'%} + input_boolean.turn_off + {% else %} + input_boolean.turn_on + {% endif %} + entity_id: input_boolean.alert_mode + + - service: script.speech_engine + data_template: + value1: "The {{ trigger.entity_id.split('.')[1]|replace('_', ' ') }} is now {{ (trigger.to_state.state)|replace('_', ' ') }}." + call_garage_check: 1 diff --git a/automation/Speech/home_stats.yaml b/automation/Speech/home_stats.yaml new file mode 100755 index 00000000..d639e295 --- /dev/null +++ b/automation/Speech/home_stats.yaml @@ -0,0 +1,32 @@ +###################################################################### +## Some home facts when we get back home from being away. +###################################################################### +- alias: 'Home Stats' + + trigger: + - platform: state + entity_id: + - group.family + from: 'not_home' + to: 'home' + for: '00:03:00' + + - platform: state + entity_id: input_boolean.home_stats + to: 'on' + from: 'off' + + action: + + - wait_template: >- + {{ is_state('group.garage_doors', 'closed') }} + timeout: 00:05:30 + + - service: script.speech_engine + data: + call_inside_weather: 1 + call_responsibilities: 1 + call_outside_weather: 1 + call_garage_check: 1 + call_window_check: 1 + call_light_check: 1 diff --git a/automation/Speech/nest.yaml b/automation/Speech/nest.yaml new file mode 100755 index 00000000..5eb9775d --- /dev/null +++ b/automation/Speech/nest.yaml @@ -0,0 +1,24 @@ +###################################################################### +## Announce when one of the nests kick in +## Announce over all Chromecast Audios +###################################################################### +- alias: 'Nest Status' + + trigger: + + - platform: state + entity_id: + - sensor.downstairs_thermostat_hvac_state + - sensor.upstairs_thermostat_hvac_state + from: 'off' + + # condition: + # - condition: template + # value_template: >- + # {{ as_timestamp(states.automation.nest_status.attributes.last_triggered) > as_timestamp(now()) - (1800) }} + + action: + - service: script.speech_engine + data_template: + NestStatus: "The {{ trigger.entity_id.split('.')[1].split('_')[0]}} {{ trigger.entity_id.split('.')[1].split('_')[1]}} has now been turned on for {{(trigger.to_state.state)}}." + call_window_check: 1 diff --git a/automation/Speech/new_device.yaml b/automation/Speech/new_device.yaml new file mode 100755 index 00000000..61d599dd --- /dev/null +++ b/automation/Speech/new_device.yaml @@ -0,0 +1,25 @@ +############################################################################## +### New Device has connected to the network. let everyone know. +############################################################################## + +- alias: "New device connected" + trigger: + - platform: event + event_type: device_tracker_new_device + + action: + - wait_template: >- + {{ not is_state('media_player.livingroomCC', 'playing') }} + + - service: script.speech_engine + data_template: + NewDevice: "There has been a new device detected on the network. Be sure to appropriately catagorize {{trigger.event.data.host_name}} within Circle." + + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "New Device on the Network! @MeetCircle has alerted me me and now it is locked down.", + "Constant monitoring of the network by @MeetCircle has detected a new device in the environment." + ] | random + " (http://amzn.to/2eAgaA6)"}} +############################################################################## diff --git a/automation/Speech/responsibilities.yaml b/automation/Speech/responsibilities.yaml new file mode 100755 index 00000000..a1aa2019 --- /dev/null +++ b/automation/Speech/responsibilities.yaml @@ -0,0 +1,15 @@ +###################################################################### +## Who's day is it anyway? Pretty sure my parent's didn't code to figure this out. +###################################################################### +- alias: 'responsibilities' + + trigger: + + - platform: state + entity_id: input_boolean.responsibilities + to: 'on' + + action: + - service: script.speech_engine + data: + call_responsibilities: 1 diff --git a/automation/System/CucKoo_Clock.yaml b/automation/System/CucKoo_Clock.yaml new file mode 100755 index 00000000..79750b2d --- /dev/null +++ b/automation/System/CucKoo_Clock.yaml @@ -0,0 +1,56 @@ +################################### +## cuckoo Clock simulation. +## Plays the number of cuckoos per hour and 1 on the half hour. +################################### + +- alias: Cuckoo Clock + trigger: + - platform: time + minutes: 00 + seconds: 20 + - platform: time + minutes: 30 + seconds: 00 + + condition: + - condition: time + after: '09:30:00' + before: '21:30:00' + - condition: state + entity_id: group.family + state: 'home' + - condition: template + value_template: > + {% if is_state('media_player.livingroomCC', 'playing') %} + false + {% else %} + true + {% endif %} + + action: + - service: media_player.turn_on + entity_id: media_player.livingroomCC + + - service: switch.turn_on + entity_id: switch.living_room_amp + - delay: '00:00:05' + + - service: media_player.volume_set + entity_id: + - media_player.livingroomCC + data: + volume_level: 0.22 + + - service: media_player.play_media + data_template: + entity_id: + - media_player.livingroomCC + - media_player.alarm_clock + # - media_player.bedroom_alarm_panel + media_content_id: > + {% if now().strftime("%M")|int == 30 %} + https://raw.githubusercontent.com/CCOSTAN/Home-AssistantConfig/master/sounds/cuckoo-clock-01.wav + {% else %} + https://raw.githubusercontent.com/CCOSTAN/Home-AssistantConfig/master/sounds/cuckoo-clock-{{now().strftime("%I")}}.wav + {% endif %} + media_content_type: audio/mp4 diff --git a/automation/System/README.md b/automation/System/README.md new file mode 100755 index 00000000..0d9fc02a --- /dev/null +++ b/automation/System/README.md @@ -0,0 +1,15 @@ +# [![Build Status](https://travis-ci.org/CCOSTAN/Home-AssistantConfig.svg?branch=master)](https://travis-ci.org/CCOSTAN/Home-AssistantConfig) Home-Assistant Config by [@ccostan](http://www.twitter.com/ccostan) +[Home Assistant](https://home-assistant.io/) configuration files (YAMLs) + +Be sure to :star: my repo so you can keep up to date on the daily progress! + +This directory is primarily used for automations that are just running in the background all the time. Little robots just doing thier thing to help make the house the smartest and most proactive it can be for us. + +#Still have questions on my Config? +Follow me on twitter : [@CCostan](https://twitter.com/ccostan) + +You can also vist my [Blog](http://www.vmwareinfo.com/search/label/iot) for all of my [Home Automation Posts](http://www.vmwareinfo.com/search/label/iot). + + + Sponsor + diff --git a/automation/System/Self_heal.yaml b/automation/System/Self_heal.yaml new file mode 100755 index 00000000..11b4c4fc --- /dev/null +++ b/automation/System/Self_heal.yaml @@ -0,0 +1,22 @@ +################################### +## Self Healing Section - +## Home Assistant runs on my [Raspberry Pi 3](http://amzn.to/2e3DOBY) with [Aeon Labs Z Wave Stick (GEN 5)](http://amzn.to/2eAiAP0). +################################### + +- alias: Heal ZWave Nightly + hide_entity: True + trigger: + platform: time + at: '2:31:00' + action: + - service: zwave.heal_network + + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "While they sleep, I self heal the Z-Wave network with Wink.", + "Nightly Z-WAVE Self heals keep all the gear in check! (http://amzn.to/2q17R4S)", + "Every night at 2:31am, I do my self-heal and rebuild the ZWAVE network.", + "Without my Nightly ZWave Self Heal, things get a little whackado." + ] | random + " #SelfHeal #ZWave"}} diff --git a/automation/System/Wink_update_notification.yaml b/automation/System/Wink_update_notification.yaml new file mode 100755 index 00000000..bafb9980 --- /dev/null +++ b/automation/System/Wink_update_notification.yaml @@ -0,0 +1,34 @@ +- alias: "Wink Update Available Notification" + hide_entity: True + trigger: + platform: template + value_template: "{{ is_state_attr('binary_sensor.carlowink', 'update needed', True) }} != False }}" + + action: + - service: script.notify_engine + data_template: + value1: 'Check the Wink Hub. Update is needed.' + value2: "{{ states.binary_sensor.carlowink.attributes }}" + value3: '' + who: 'carlo' + + - service: notify.html5 + data_template: + title: "Wink Update Available" + message: "Wink Update is available. - {{ as_timestamp(now()) | timestamp_custom('%I:%M:%S %p %d%b%Y', true) }}" + data: + url: "https://home-assistant.io/getting-started/installation-raspberry-pi-all-in-one/#upgrading" + + - service: persistent_notification.create + data: + title: "Wink Update Available" + message: "Wink Update is available. - {{ as_timestamp(now()) | timestamp_custom('%I:%M:%S %p %d%b%Y', true) }}" + notification_id: "update_available" + + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "Check @TheWinkApp Hub @CCostan. Update is needed. {{ states.binary_sensor.carlowink.attributes }}", + "New update from @TheWinkApp. Hop to it @CCostan" + ] | random + "(http://amzn.to/2orGEWo)"}} diff --git a/automation/System/bad_logins.yaml b/automation/System/bad_logins.yaml new file mode 100755 index 00000000..f8c1ead5 --- /dev/null +++ b/automation/System/bad_logins.yaml @@ -0,0 +1,26 @@ +################################### +## Uses IFTTT to notify me of bad logins. +################################### + +- alias: Login Failure + hide_entity: True + trigger: + platform: template + value_template: "{{ states('persistent_notification.httplogin') != 'unknown' }}" + + action: + - service: script.notify_engine + data_template: + value1: 'Bad Login: ' + value2: 'There was a Hack attempt!' + value3: 'Go Check the GUI for details.' + who: 'carlo' + + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "Seriously, I am a Smart Home. I am logging your hack attempt.", + "If you do not know the password, you get locked out and IP banned.", + "Three Strikes and you are OUT! IP Banned." + ] | random + "#Security"}} diff --git a/automation/System/detect_and_adjust_lights.yaml b/automation/System/detect_and_adjust_lights.yaml new file mode 100755 index 00000000..434e2014 --- /dev/null +++ b/automation/System/detect_and_adjust_lights.yaml @@ -0,0 +1,50 @@ +############################################################################## +### Detect when lights are turned on and adjust them accordingly based on time. +### Code by @JesseWebDotCom +############################################################################## +- alias: detect lights and adjust the brightness when turned on based on time + trigger: + - platform: event + event_type: state_changed + + condition: + - condition: state + entity_id: group.family + state: 'home' + - condition: state + entity_id: input_boolean.alert_mode + state: 'off' + - condition: template + value_template: "{{ trigger.event.data is not none }}" + - condition: template + value_template: "{{ trigger.event.data.entity_id is not none }}" + - condition: template + value_template: "{{ trigger.event.data.entity_id.split('.')[0] == 'light' }}" + - condition: template + value_template: "{{ trigger.event.data.entity_id.split('_')[0] != 'light.tv' }}" + - condition: template + value_template: "{{ trigger.event.data.entity_id.split('_')[0] != 'light.couch' }}" + - condition: template + value_template: "{{ trigger.event.data.entity_id.split('_')[0] != 'light.office' }}" + - condition: template + value_template: "{{ trigger.event.data.entity_id.split('_')[1] != 'screensaver' }}" + - condition: template + value_template: "{{ trigger.event.data.new_state.state == 'on' }}" + - condition: template + value_template: "{{ trigger.event.data.old_state.state == 'off' }}" + + action: + - service: light.turn_on + data_template: + entity_id: "{{ trigger.event.data.entity_id }}" + brightness: > + {% set hour=states("sensor.time").split(':')[0] | int %} + {%- if hour >= 5 and hour < 8 -%} + 50 + {%- elif hour >= 8 and hour <20 -%} + 255 + {%- elif hour >= 20 and hour <24 -%} + 40 + {%- else -%} + 15 + {%- endif %} diff --git a/automation/System/door_chime.yaml b/automation/System/door_chime.yaml new file mode 100755 index 00000000..00aec0bb --- /dev/null +++ b/automation/System/door_chime.yaml @@ -0,0 +1,40 @@ +################################### +## @CCOSTAN +## Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +################################### + +- alias: Door Chime + trigger: + - platform: state + entity_id: + - group.entry_points + + condition: + - condition: state + entity_id: group.family + state: 'home' + + action: + - service: script.amp_settings + data: + media_player: 'media_player.livingroomcc' + volume_level: 0.22 + - wait_template: >- + {{ states.switch.living_room_amp.state == 'on' }} + + - service: media_player.play_media + data_template: + entity_id: > + {% if states.group.bed.state == 'off' %} + media_player.livingroomCC + {% else %} + - media_player.alarm_clock + - media_player.bedroom_alarm_panel + {% endif %} + media_content_id: > + {% if trigger.to_state.state == 'on' %} + https://raw.githubusercontent.com/CCOSTAN/Home-AssistantConfig/master/sounds/one-tone-chime.mp3 + {% else %} + https://raw.githubusercontent.com/CCOSTAN/Home-AssistantConfig/master/sounds/two-tone-chime.mp3 + {% endif %} + media_content_type: audio/mp4 diff --git a/automation/System/ip_change.yaml b/automation/System/ip_change.yaml new file mode 100755 index 00000000..8ec89984 --- /dev/null +++ b/automation/System/ip_change.yaml @@ -0,0 +1,29 @@ +############################################################################## +### Detect when things are on and forgotten about. Like any Good Watchdog. +############################################################################## + +############################################################################## + +- alias: "NOTIFY IF IP CHANGES" + hide_entity: True + trigger: + - platform: state + entity_id: sensor.ipchange + from: 'False' + to: 'True' + action: + - service: script.notify_engine + data_template: + value1: 'Changed IP address:' + value2: "New IP: {{ states('sensor.exteral_ip') }}" + value3: ' - Be sure to Change DNS!' + who: 'carlo' + + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "That's weird. Looks like my IP address changed. @CCostan, please check it out.", + "Time to update @GoDaddy @CCostan. Looks like my IP address changed." + ] | random + " #HomeAutomation"}} +############################################################################## diff --git a/automation/System/rachio_rain_delay.yaml b/automation/System/rachio_rain_delay.yaml new file mode 100755 index 00000000..c2647add --- /dev/null +++ b/automation/System/rachio_rain_delay.yaml @@ -0,0 +1,29 @@ +################################### +## Uses IFTTT to trigger rain delay with rachio +################################### + +- alias: Rachio_Rain_Delay + hide_entity: True + trigger: + - platform: numeric_state + entity_id: + - sensor.dark_sky_precip_intensity_max + - sensor.dark_sky_precip_intensity + above: 0.5 + - platform: numeric_state + entity_id: sensor.dark_sky_wind_speed + above: 20 + + action: + - service: ifttt.trigger + data_template: {"event":"Rachio_Rain_Delay"} + + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "Looks like Rain, Pausing the @_Rachio for 24 hours. (http://amzn.to/2eoPKBW)", + "Since it is going to rain tomorrow, I'll pause @_Rachio for 24 hours.", + "No reason to water the grass if it's going to rain tomorrow. pausing @_Rachio for 24 hours.", + "Mother Nature is watering the grass today so I can pause @_Rachio for 24 hours." + ] | random + " #SavingWater"}} diff --git a/automation/System/trigger_dump.yaml b/automation/System/trigger_dump.yaml new file mode 100755 index 00000000..16e46ac7 --- /dev/null +++ b/automation/System/trigger_dump.yaml @@ -0,0 +1,70 @@ +################################### +## Trigger Dump +################################### + + - alias: Trigger dump - MQTT + trigger: + - platform: event + event_type: trigger_dump + action: + - service: mqtt.publish + data_template: + topic: '/dump/{{ trigger.platform }}' + retain: false + payload: >- + {%- macro dumpState(statePrefix, stateObj) -%} + {{statePrefix ~ ": "}} {{- stateObj.state }}{{- "\n" -}} + {{statePrefix ~ ".entity_id: "}} {{- stateObj.entity_id }}{{- "\n" -}} + {{statePrefix ~ ".domain: "}} {{- stateObj.domain }}{{- "\n" -}} + {{statePrefix ~ ".object_id: "}} {{- stateObj.object_id }}{{- "\n" -}} + {{statePrefix ~ ".name: "}} {{- stateObj.name }}{{- "\n" -}} + {{statePrefix ~ ".last_updated: "}} {{- stateObj.last_updated }}{{- "\n" -}} + {{statePrefix ~ ".last_changed: "}} {{- stateObj.last_changed }}{{- "\n" -}} + {%- for attrib in stateObj.attributes | sort() %} + {%- if attrib is defined -%} + {{- statePrefix ~ ".attributes." ~ attrib ~ ": " -}} {{- stateObj.attributes[attrib] -}} + {{- "\n" -}} + {%- endif -%} + {%- endfor -%} + {%- endmacro -%} + + {% set p = trigger.platform %} + {{"trigger.platform: "}} {{ p }}{{- "\n" -}} + + {%- if p == "mqtt" -%} + {{"trigger.topic: "}} {{ trigger.topic }}{{- "\n" -}} + {{"trigger.payload: "}} {{ trigger.payload }}{{- "\n" -}} + {{"trigger.payload_json: "}} {{ trigger.payload_json }}{{- "\n" -}} + {{"trigger.qos: "}} {{ trigger.qos }}{{- "\n" -}} + {%- endif -%} + + {%- if p == "event" or p == "sun" or p == "zone" -%} + {{"trigger.event: "}} {{ trigger.event }}{{- "\n" -}} + {%- endif -%} + + {%- if p == "numeric_state" -%} + {{"trigger.above: "}} {{ trigger.above }}{{- "\n" -}} + {{"trigger.below: "}} {{trigger.below }}{{- "\n" -}} + {%- endif -%} + + {%- if p == "state" -%} + {{"trigger.for: "}} {{ trigger.for }}{{- "\n" -}} + {%- endif -%} + + {%- if p == "time" -%} + {{"trigger.now: "}} {{ trigger.now }}{{- "\n" -}} + {%- endif -%} + + {%- if p == "zone" -%} + {{"trigger.zone: "}} {{ trigger.zone }}{{- "\n" -}} + {%- endif -%} + + {%- if p == "state" or p == "numeric_state" or p == "template" or p == "zone" -%} + {{"trigger.entity_id: "}} {{ trigger.entity_id }}{{- "\n" -}}{{- "\n" -}} + {{"trigger.from_state: "}} {{- "\n" -}} + -------------------{{- "\n" -}} + {{ dumpState("trigger.from_state", trigger.from_state) }} {{- "\n" -}} + trigger.to_state:{{- "\n" -}} + -----------------{{- "\n" -}} + {{ dumpState("trigger.to_state", trigger.to_state) }} + {%- endif -%} diff --git a/automation/System/update_notification.yaml b/automation/System/update_notification.yaml new file mode 100755 index 00000000..3b2e67a3 --- /dev/null +++ b/automation/System/update_notification.yaml @@ -0,0 +1,34 @@ +- alias: "Update Available Notification" + hide_entity: True + trigger: + platform: state + entity_id: updater.updater + + condition: + - condition: template + value_template: "{{ states('updater.updater') != 'unknown' }}" + + action: + - service: script.notify_engine + data_template: + value1: 'There is a new Version of Home-Assistant Available.' + value2: "{{ states('updater.updater') }}" + who: 'carlo' + + - service: script.tweet_engine + data: + tweet: "New version of @Home_Assistant! Cannot wait for @CCostan to install it! - {{ states('updater.updater') }} (http://www.vmwareinfo.com/2017/07/my-smart-home-look-at-parts-that-make.html)" + + + - service: notify.html5 + data_template: + title: "Update Available" + message: "Home Assistant {{ states('updater.updater') }} is available. - {{ as_timestamp(now()) | timestamp_custom('%I:%M:%S %p %d%b%Y', true) }}" + data: + url: "https://home-assistant.io/getting-started/installation-raspberry-pi-all-in-one/#upgrading" + + - service: persistent_notification.create + data: + title: "Update Available" + message: "Home Assistant {{ states('updater.updater') }} is available. - {{ as_timestamp(now()) | timestamp_custom('%I:%M:%S %p %d%b%Y', true) }}" + notification_id: "update_available" diff --git a/automation/System/watchdog_light.yaml b/automation/System/watchdog_light.yaml new file mode 100755 index 00000000..082217d7 --- /dev/null +++ b/automation/System/watchdog_light.yaml @@ -0,0 +1,27 @@ +############################################################################## +### Detect when things are on and forgotten about. Like any Good Watchdog. +############################################################################## + +- alias: Automated Light WatchDog! + trigger: + - platform: state + entity_id: + - light.hallway + - group.hallway_lights + - group.foyer_lights + - switch.printer_outlet + to: 'on' + for: '00:20:00' + + - platform: state + entity_id: + - group.upstairs + - switch.garage_outlet + to: 'on' + for: '02:00:00' + +#Turn it off! + action: + - service: homeassistant.turn_off + data_template: + entity_id: "{{ trigger.entity_id }}" diff --git a/automation/Timed_Triggers/0640.yaml b/automation/Timed_Triggers/0640.yaml new file mode 100755 index 00000000..5dd832b2 --- /dev/null +++ b/automation/Timed_Triggers/0640.yaml @@ -0,0 +1,31 @@ +###################################################################### +## Stuff that needs to happen at 06:30am. +###################################################################### + +- alias: 'Timed 640.' + trigger: + - platform: time + at: '06:40:00' + + condition: + - condition: state + entity_id: group.family + state: home + - condition: state + entity_id: input_boolean.school_mode + state: 'on' + - condition: time + weekday: + - mon + - tue + - wed + - thu + - fri + + action: + - service: light.turn_on + entity_id: + - light.d1 + - light.d2 + - service: switch.turn_on + entity_id: switch.kitchen_accents diff --git a/automation/Timed_Triggers/0650.yaml b/automation/Timed_Triggers/0650.yaml new file mode 100755 index 00000000..801b64da --- /dev/null +++ b/automation/Timed_Triggers/0650.yaml @@ -0,0 +1,38 @@ +###################################################################### +## Stuff that needs to happen at 08:30am. +###################################################################### + +- alias: 'Kids 650.' + trigger: + - platform: time + at: '06:50:00' + + condition: + - condition: state + entity_id: group.family + state: home + - condition: state + entity_id: input_boolean.school_mode + state: 'on' + - condition: time + weekday: + - mon + - tue + - wed + - thu + - fri + + action: + - service: light.turn_on + entity_id: + - light.d1 + - light.d2 + - group.kitchen_lights + - service: light.turn_off + entity_id: + - group.dining_room_lights + + - wait_template: >- + {{ states.sun.sun.state == 'above_horizon' }} + - service: switch.turn_off + entity_id: switch.kitchen_accents diff --git a/automation/Timed_Triggers/0830.yaml b/automation/Timed_Triggers/0830.yaml new file mode 100755 index 00000000..d52b9a64 --- /dev/null +++ b/automation/Timed_Triggers/0830.yaml @@ -0,0 +1,39 @@ +###################################################################### +## Stuff that needs to happen at 08:30am. +###################################################################### + +- alias: 'Kids left for the day.' + trigger: + - platform: time + at: '08:30:00' + + condition: + - condition: state + entity_id: group.family + state: home + - condition: state + entity_id: input_boolean.guest_mode + state: 'off' + - condition: state + entity_id: input_boolean.school_mode + state: 'on' + - condition: time + weekday: + - mon + - tue + - wed + - thu + - fri + action: + - wait_template: >- + {{ is_state('group.garage_doors', 'open') }} + - service: light.turn_off + entity_id: + - group.all_lights + - service: switch.turn_off + entity_id: switch.kitchen_accents + - wait_template: >- + {{ is_state('group.bed', 'off') }} + - service: light.turn_on + entity_id: + - group.kitchen_lights diff --git a/automation/Timed_Triggers/2200.yaml b/automation/Timed_Triggers/2200.yaml new file mode 100755 index 00000000..0dfee7d4 --- /dev/null +++ b/automation/Timed_Triggers/2200.yaml @@ -0,0 +1,52 @@ +###################################################################### +## Stuff that needs to happen at 10pm. +###################################################################### + +- alias: 'Shut down AMP in Living room' + trigger: + - platform: time + at: '22:00:00' + + action: + - wait_template: >- + {{ not is_state('media_player.livingroomCC', 'playing') }} + - wait_template: >- + {{ not is_state('media_player.whole_house', 'playing') }} + + - service: script.speech_engine + data_template: + call_no_announcement: 1 + call_garage_check: 1 + call_window_check: 1 + + - service: light.turn_on + entity_id: + - group.living_room_accents + data_template: + color_name: > + {% if states.group.entry_points.state == 'on' or states.group.all_covers.state != 'closed' -%} + red + {% else %} + gold + {% endif %} + + - wait_template: >- + {{ not is_state('group.entry_points', 'on') }} + - wait_template: >- + {{ is_state('group.all_covers', 'closed') }} + + - wait_template: >- + {{ not is_state('media_player.livingroomCC', 'playing') }} + - service: switch.turn_off + entity_id: switch.living_room_amp + + - service: light.turn_on + entity_id: + - group.living_room_accents + data_template: + color_name: > + {% if states.group.entry_points.state == 'on' or states.group.all_covers.state != 'closed' -%} + red + {% else %} + gold + {% endif %} diff --git a/automation/Timed_Triggers/README.md b/automation/Timed_Triggers/README.md new file mode 100755 index 00000000..5048a726 --- /dev/null +++ b/automation/Timed_Triggers/README.md @@ -0,0 +1,46 @@ +# [![Build Status](https://travis-ci.org/CCOSTAN/Home-AssistantConfig.svg?branch=master)](https://travis-ci.org/CCOSTAN/Home-AssistantConfig) Home-Assistant Config by [@ccostan](http://www.twitter.com/ccostan) +[Home Assistant](https://home-assistant.io/) configuration files (YAMLs) + +Be sure to :star: my repo so you can keep up to date on the daily progress! + +This directory is primarily used for automations that are triggered via time. Daily, monthly, seasonally or on the hour. + +**Time Based Automation TimeLine** + +ALL DAY LONG: +Checks to see if we are away. +Cuckoo Clock goes off each hour and on the half. + +SUNRISE minus 1 hour + Turn off ALL SWITCHES + Turn off ALL LIGHTS +05:00 AM ** Light Brightness helper 50 Brightness ** +06:00 AM ( on school days) : Turn on Dining Room lights, Kitchen Accents and start Kid's bedroom [Hue Go](http://amzn.to/2iB36Ii) wake up lights. +06:51 AM Turn on Dinette lights, Turn off Dining Room Lights and Kitchen Accents +07:51 AM Turn on Kitchen Lights +08:00 AM ** Light Brightness helper FULL 255 Brightness ** +08:31 AM (on school days) Turn off ALL interior lights. +09:00 AM Speech Notifications are enabled for the house. + +SUNSET: + Turn on Den Outlet, Living Room Outlet, Dining Room Outlet, Outdoor Bathroom light, TV lights + Activate Monthly Front Lighting Scene + Check if Garage Door is open (Every 60 minutes) + ** Kitchen Light/Accent Helper Activated ** + +08:00 PM ** Late Night Helper is active ** +08:00 PM ** Light Brightness helper 35 Brightness ** +08:00 PM TV time Scene triggered if the TV is on. +09:00 PM Turn on [Hue Go](http://amzn.to/2iB36Ii) lights for the kid's rooms and start fading down. +10:00 PM Speech Notifications are disabled for the house. (except under ALERT mode) and AMP is shut. +02:00 AM ** Late Night Help Deactivated ** +02:31 AM Heal ZWave Network + +#Still have questions on my Config? +Follow me on twitter : [@CCostan](https://twitter.com/ccostan) + +You can also vist my [Blog](http://www.vmwareinfo.com/search/label/iot) for all of my [Home Automation Posts](http://www.vmwareinfo.com/search/label/iot). + + + Sponsor + diff --git a/automation/Timed_Triggers/night_watchdog.yaml b/automation/Timed_Triggers/night_watchdog.yaml new file mode 100755 index 00000000..ffce5f3c --- /dev/null +++ b/automation/Timed_Triggers/night_watchdog.yaml @@ -0,0 +1,43 @@ +###################################################################### +## Stuff that needs to happen after 10pm. +###################################################################### + +- alias: Automated NIGHT WatchDog! + trigger: + - platform: state + entity_id: switch.living_room_amp + to: 'on' + for: '00:10:00' + - platform: state + entity_id: media_player.livingroomCC + to: 'off' + for: '00:02:00' + - platform: state + entity_id: media_player.whole_house + to: 'off' + for: '00:02:00' + + condition: + condition: or + conditions: + - condition: and + conditions: + - condition: state + entity_id: group.family + state: 'not_home' + - condition: state + entity_id: input_boolean.guest_mode + state: 'off' + - condition: and + conditions: + - condition: state + entity_id: input_boolean.guest_mode + state: 'off' + - condition: state + entity_id: group.bed + state: 'on' + + action: + - service: switch.turn_off + data_template: + entity_id: "{{ trigger.entity_id }}" diff --git a/automation/Timed_Triggers/startup_month.yaml b/automation/Timed_Triggers/startup_month.yaml new file mode 100755 index 00000000..b229cc55 --- /dev/null +++ b/automation/Timed_Triggers/startup_month.yaml @@ -0,0 +1,21 @@ +################################### +## Start Up Section +################################### + +- alias: Check if it's summer vacation on startup. + hide_entity: True + trigger: + - platform: homeassistant + event: start + + condition: + - condition: template + value_template: > + {% set month=states("sensor.date").split('-')[1] | int %} + {%- if month == 6 or month == 7 -%} + true + {%- endif -%} + + action: + - service: input_boolean.turn_off + entity_id: input_boolean.school_mode diff --git a/automation/Timed_Triggers/startup_notification.yaml b/automation/Timed_Triggers/startup_notification.yaml new file mode 100755 index 00000000..5c5e2639 --- /dev/null +++ b/automation/Timed_Triggers/startup_notification.yaml @@ -0,0 +1,17 @@ +################################### +## Start Up Section +################################### + +- alias: Startup Notification and Shut startup lights + hide_entity: True + trigger: + - platform: homeassistant + event: start + action: + - service: script.notify_engine + data_template: + value1: 'Startup: Home Assistant is Up and Running!' + who: 'carlo' + + - service: light.turn_off + entity_id: group.hallway_lights diff --git a/automation/Timed_Triggers/sunrise_turn_off.yaml b/automation/Timed_Triggers/sunrise_turn_off.yaml new file mode 100755 index 00000000..d37ec3fc --- /dev/null +++ b/automation/Timed_Triggers/sunrise_turn_off.yaml @@ -0,0 +1,46 @@ + ################################### +## Sunrise and Sunset stuff +################################### + +- alias: 'Sunset Stuff off' + trigger: + - platform: sun + event: sunrise + offset: '-02:00:00' + + action: + - service: script.interior_off + - service: homeassistant.turn_off + entity_id: + - group.landscaping + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "Even though they are sleeping, I still turn off the outdoor lights before sunrise.", + "It was a beautiful sunrise. Time to turn off the exterior lights. (http://www.vmwareinfo.com/2017/08/diy-outdoor-smart-home-led-strips.html)", + "If the sun is out, we do not need the exterior lights on. (http://amzn.to/2q17R4S)", + "The sun is up so it's time to turn the outside lights off. Lucky for my family, I have them covered!" + ] | random + "#HomeAutomation"}} + + - delay: '00:{{ (range(1, 55)|random|int) }}:00' + - service: light.turn_off + entity_id: + - group.exterior_lights + - group.outdoor_front_lights + - group.outdoor_pool_lights + - group.all_lights + + - wait_template: >- + {{ states.sun.sun.state == 'above_horizon' }} + - service: homeassistant.turn_off + entity_id: + - switch.master_bathroom_accents + - group.exterior_lights + - group.outdoor_front_lights + + - service: input_boolean.turn_off + entity_id: + - input_boolean.medicine + - input_boolean.daylight_override + - input_boolean.guest_mode diff --git a/automation/Timed_Triggers/sunset_turn_on.yaml b/automation/Timed_Triggers/sunset_turn_on.yaml new file mode 100755 index 00000000..ded38b4f --- /dev/null +++ b/automation/Timed_Triggers/sunset_turn_on.yaml @@ -0,0 +1,64 @@ +################################### +## Sunrise and Sunset stuff +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +################################### + +- alias: 'Sunset Stuff on' + trigger: + - platform: state + entity_id: sun.sun + to: 'below_horizon' + from: 'above_horizon' + + action: + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "Right before sunset, I turn on the outdoor lights.", + "Since it gets dark around sunset, I turn on the landscaping lights.", + "Since it is sunset, I will turn on the exterior lights." + ] | random + [ + "#Sunset", + "#HomeAutomation", + "AccentLighting", + "(http://www.vmwareinfo.com/2017/08/diy-outdoor-smart-home-led-strips.html)" + ] | random }} + - delay: '00:{{ (range(1, 20)|random|int) }}:00' + - service: script.speech_engine + data: + call_dark_outside: 1 + call_window_check: 1 + - service: homeassistant.turn_on + entity_id: + - switch.front_landscaping + - service: script.monthly_color_scene + - service: light.turn_on + data: + entity_id: + - light.outdoor_bathroom + brightness: 35 + + - wait_template: >- + {{ states.group.family.state == 'home' }} + - service: switch.turn_on + entity_id: + - switch.master_bathroom_accents + - switch.back_landscaping + - switch.front_door_outlet + - switch.living_room_outlet + - switch.den_outlet + - switch.foyer_outlet + - service: light.turn_on + entity_id: + - group.living_room_accents + - light.bedroom + - wait_template: >- + {{ is_state('group.garage_doors', 'closed') }} + - wait_template: >- + {{ is_state('group.entry_points', 'off') }} + - service: script.speech_engine + data: + call_garage_check: 1 + call_window_check: 1 diff --git a/automation/away.yaml b/automation/away.yaml new file mode 100755 index 00000000..7bf76cfb --- /dev/null +++ b/automation/away.yaml @@ -0,0 +1,25 @@ +###################################################################### +## Shut it all down. No one is here +###################################################################### + +- alias: 'Away Mode' + trigger: + - platform: state + entity_id: binary_sensor.downstairs_away_mode + to: 'on' + - platform: state + entity_id: group.family + to: 'not_home' + + condition: + - condition: state + entity_id: group.family + state: 'not_home' + - condition: state + entity_id: input_boolean.guest_mode + state: 'off' + + action: + - service: script.interior_off + - service: switch.turn_off + entity_id: switch.back_landscaping diff --git a/automation/carlo_left.yaml b/automation/carlo_left.yaml new file mode 100755 index 00000000..4c312eec --- /dev/null +++ b/automation/carlo_left.yaml @@ -0,0 +1,12 @@ +###################################################################### +## Turn off my Office light whenever I leave the house. +###################################################################### +- alias: 'Carlo has left the building' + trigger: + - platform: state + entity_id: device_tracker.carlo + to: not_home + + action: + - service: light.turn_off + entity_id: light.office_lamp diff --git a/automation/color_tornado.yaml b/automation/color_tornado.yaml new file mode 100755 index 00000000..4e045ad0 --- /dev/null +++ b/automation/color_tornado.yaml @@ -0,0 +1,25 @@ +###################################################################### +## Color Tornado! +###################################################################### +- alias: 'Color Tornado' + trigger: + - platform: state + entity_id: input_boolean.color_tornado + to: 'on' + from: 'off' + + action: + - service: light.turn_on + entity_id: + - light.justin_go + data: + effect: colorloop + + - service: light.turn_on + entity_id: + - light.justin_go + data: + effect: colorloop + + - service: input_boolean.turn_off + entity_id: input_boolean.color_tornado diff --git a/automation/dark_rainy_day.yaml b/automation/dark_rainy_day.yaml new file mode 100755 index 00000000..4bccda00 --- /dev/null +++ b/automation/dark_rainy_day.yaml @@ -0,0 +1,66 @@ +###################################################################### +## Dark House Little extra light - DARK and Cloudy or just rainy. +###################################################################### + +- alias: 'Dark House Little extra light' + trigger: + - platform: numeric_state + entity_id: sun.sun + value_template: '{{ state.attributes.elevation }}' + below: 20.0 + - platform: numeric_state + entity_id: sensor.dark_sky_cloud_coverage + above: 90 + - platform: numeric_state + entity_id: sensor.dark_sky_precip_intensity + above: 1 + - platform: state + entity_id: group.family + to: 'home' + from: 'not_home' + + condition: + condition: and + conditions: + - condition: or + conditions: + - condition: and + conditions: + - condition: numeric_state + entity_id: sun.sun + value_template: '{{ state.attributes.elevation }}' + below: 20.0 + - condition: numeric_state + entity_id: sensor.dark_sky_cloud_coverage + above: 90 + - condition: numeric_state + entity_id: sensor.dark_sky_precip_intensity + above: 1 + - condition: state + entity_id: binary_sensor.sleepnumber_carlo_carlo_is_in_bed + state: 'off' + - condition: state + entity_id: binary_sensor.sleepnumber_carlo_stacey_is_in_bed + state: 'off' + - condition: state + entity_id: sun.sun + state: 'above_horizon' + - condition: state + entity_id: group.family + state: 'home' + + action: + - service: light.turn_on + entity_id: + - light.couch_1 + - light.sink + - service: input_boolean.turn_on + entity_id: + - input_boolean.daylight_override + - service: script.speech_engine + data_template: + value1: "It is getting a little dark inside the house because of the {{trigger.entity_id.split('_')[2]|replace('precip','rain') }} {{trigger.entity_id.split('_')[3]|replace('intensity',' ')}} outside. I will turn on some extra lights in the living room." + call_window_check: 1 + call_garage_check: 1 + +###################################################################### diff --git a/automation/dash_buttons.yaml b/automation/dash_buttons.yaml new file mode 100755 index 00000000..fe1f3ae7 --- /dev/null +++ b/automation/dash_buttons.yaml @@ -0,0 +1,21 @@ +################################### +## Press an [Amazon Dash Buttons](http://amzn.to/2dPKZhM) and then stuff happens. +################################### + +- alias: 'Toggle Office Light on/off' + trigger: + - platform: event + event_type: office_lamp_dash + + action: + # Disable this automation + - service: automation.turn_off + entity_id: automation.toggle_office_light_onoff + - service: light.toggle + entity_id: light.office_lamp + - service: input_boolean.turn_on + entity_id: input_boolean.daylight_override + - delay: + minutes: 1 + # enable this automation - This prevents duplicate pushes. + - service: automation.turn_on diff --git a/automation/flash_all.yaml b/automation/flash_all.yaml new file mode 100755 index 00000000..0464f6d3 --- /dev/null +++ b/automation/flash_all.yaml @@ -0,0 +1,19 @@ +###################################################################### +## Flash all the lights! +###################################################################### +- alias: 'Flash all_lights' + trigger: + - platform: state + entity_id: input_boolean.flash + to: 'on' + from: 'off' + + action: + - service: light.turn_on + entity_id: + - group.all_lights + data: + flash: long + + - service: input_boolean.turn_off + entity_id: input_boolean.flash diff --git a/automation/garadget.yaml b/automation/garadget.yaml new file mode 100755 index 00000000..0136483f --- /dev/null +++ b/automation/garadget.yaml @@ -0,0 +1,86 @@ +################################### +## Garadget Stuff - [Garadget](http://amzn.to/2jQLpVQ) - Garage Door opener/sensor +## +################################### + +- alias: Garadget Reflection Rates + hide_entity: True + trigger: + - platform: numeric_state + entity_id: sensor.large_garage_reflection_rate + below: 85 +# for: '00:05:00' + - platform: numeric_state + entity_id: sensor.small_garage_reflection_rate + below: 85 +# for: '00:05:00' + + condition: + - condition: template + value_template: "{{ states('cover.large_garage') == 'closed' }}" + - condition: template + value_template: "{{ states('cover.small_garage') == 'closed' }}" + + action: + - service: script.notify_engine + data_template: + value1: 'Check Garage Doors Reflection:' + value2: "Small: {{ states('sensor.small_garage_reflection_rate')}}" + value3: "Large: {{ states('sensor.large_garage_reflection_rate')}}" + who: "carlo" + +############################################################################## + +- alias: Is the Garage door Open at night - Checks every 30 minutes or 5 minutes after we drive away. + hide_entity: True + trigger: + - platform: time + minutes: '/45' + seconds: 00 + - platform: state + entity_id: group.family + to: not_home + for: 00:05:00 + - platform: state + entity_id: input_boolean.tv_time + to: 'on' + from: 'off' + + condition: + condition: or + conditions: + - condition: and + conditions: + - condition: state + entity_id: group.family + state: not_home + for: 00:05:00 + - condition: or + conditions: + - condition: template + value_template: "{{ states('cover.large_garage') == 'opened' }}" + - condition: template + value_template: "{{ states('cover.small_garage') == 'opened' }}" + - condition: and + conditions: + - condition: state + entity_id: sun.sun + state: 'below_horizon' + - condition: or + conditions: + - condition: template + value_template: "{{ states('cover.large_garage') == 'opened' }}" + - condition: template + value_template: "{{ states('cover.small_garage') == 'opened'}}" + + action: + - service: script.notify_engine + data_template: + value1: 'Check Garage Doors:' + value2: "Small: {{ states('cover.small_garage')}}" + value3: "Large: {{ states('cover.large_garage')}}" + who: "family" + + - service: script.speech_engine + data_template: + value1: "Please check the garage doors. The Small garage is {{ states('cover.small_garage')}} and the large garage is {{ states('cover.large_garage')}}" diff --git a/automation/good_morning.yaml b/automation/good_morning.yaml new file mode 100755 index 00000000..c90ab0e9 --- /dev/null +++ b/automation/good_morning.yaml @@ -0,0 +1,43 @@ +###################################################################### +## Weekday Morning Routines for the Wife and Kiddos. +###################################################################### + +- alias: 'Good Morning Routine' + trigger: + - platform: state + entity_id: input_boolean.good_morning + to: 'on' + from: 'off' + - platform: state + entity_id: + - binary_sensor.sleepnumber_carlo_stacey_is_in_bed + to: 'off' + + condition: + - condition: state + entity_id: group.family + state: home + - condition: state + entity_id: input_boolean.school_mode + state: 'on' + - condition: time + after: '06:00:00' + before: '10:00:00' + - condition: time + weekday: + - mon + - tue + - wed + - thu + - fri + + action: + - delay: 00:20:00 + - service: light.turn_on + entity_id: + - light.s1 + - light.s4 + - service: switch.turn_on + entity_id: switch.kitchen_accents + - service: input_boolean.turn_off + entity_id: input_boolean.good_morning diff --git a/automation/good_night.yaml b/automation/good_night.yaml new file mode 100755 index 00000000..2ab6efb2 --- /dev/null +++ b/automation/good_night.yaml @@ -0,0 +1,49 @@ +###################################################################### +## Good night Routine +###################################################################### + +- alias: 'Good Night Trigger' + trigger: + - platform: state + entity_id: input_boolean.good_night + to: 'on' + from: 'off' + - platform: state + entity_id: + - binary_sensor.sleepnumber_carlo_carlo_is_in_bed + - binary_sensor.sleepnumber_carlo_stacey_is_in_bed + to: 'on' + + condition: + - condition: state + entity_id: sun.sun + state: 'below_horizon' + - condition: state + entity_id: input_boolean.guest_mode + state: 'off' + - condition: state + entity_id: binary_sensor.sleepnumber_carlo_carlo_is_in_bed + state: 'on' + - condition: state + entity_id: binary_sensor.sleepnumber_carlo_stacey_is_in_bed + state: 'on' + + action: + - service: input_boolean.turn_off + entity_id: input_boolean.good_night + + - service: script.speech_engine + data_template: + value1: > + {{ [ + "Sleep Tight, Don't let the bedbugs bite.", + "Have pleasant dreams", + "As they say in the Navy, See you in the rise." + "Dream pleasant dreams. Tomorrow is a new day.", + "Early sleep and early wake up gives health and makes you grow.", + "Good night, good night! Parting is such sweet sorrow that I shall say goodnight till it is Morrow.", + "There is a time for many words, and there is also a time for sleep.", + "This good night isn’t meant to bring an end to this day. It’s intended to wish you awesomeness in what lies ahead.", + "Stuff your worries in your pillow, wrap your troubles in your blanket and spread your anxieties on your sheets. When you wake up tomorrow, you may have dirty linen, but more importantly, you’ll have a fresh mind and a happy heart. Good night." + ] | random }} + - service: script.interior_off diff --git a/automation/guard_dog.yaml b/automation/guard_dog.yaml new file mode 100755 index 00000000..78563fc7 --- /dev/null +++ b/automation/guard_dog.yaml @@ -0,0 +1,24 @@ +###################################################################### +## Speak Max! Speak Max!! +###################################################################### + +- alias: Guard Dog + trigger: + - platform: state + entity_id: input_boolean.guard_dog + to: 'on' + from: 'off' + - platform: state + entity_id: binary_sensor.front_door_opened + to: 'on' + from: 'off' + + condition: + - condition: state + entity_id: group.all_covers + state: 'closed' + + action: + - service: script.dog_bark + - service: input_boolean.turn_off + entity_id: input_boolean.guard_dog diff --git a/automation/ifttt_calendar.yaml b/automation/ifttt_calendar.yaml new file mode 100755 index 00000000..7fd31a31 --- /dev/null +++ b/automation/ifttt_calendar.yaml @@ -0,0 +1,18 @@ +################################### +## IFTTT checks Office 365 Calendar and Notifies me of appointments. Flash lights but only at reasonable hours. +################################### +- alias: 'IFTTT Appointment reminder' + hide_entity: True + trigger: + - platform: event + event_type: IFTTT_Appointment + + condition: + - condition: time + after: '06:00:00' + before: '20:00:00' + + action: + - service: script.flash_notify + + diff --git a/automation/ifttt_logger.yaml b/automation/ifttt_logger.yaml new file mode 100755 index 00000000..36f30c77 --- /dev/null +++ b/automation/ifttt_logger.yaml @@ -0,0 +1,31 @@ +################################### +## LOG IFTTT Stuff - Rachio +################################### +- alias: 'Log Sprinkler Activity' + hide_entity: True + trigger: + - platform: event + event_type: rachio_water_stops + + action: + - service: logbook.log + data: + name: "Rachio Sprinkler:" + message: "The Lawn was watered just now." + + - service: mqtt.publish + data_template: + payload: '{{ states("sensor.date") }}' + topic: 'ifttt/rachio/watering_time' + retain: true + + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "Just finished watering the lawn with @_Rachio.", + "The lawn looked thirsty so I watered it.", + "My lawn looks great and we definately do not water it nearly as much as everyone else. (http://amzn.to/2eoPKBW)", + "No rain in the forecast? @_Rachio knows & chose to water the lawn.", + ".@CCostan does not even think about watering the lawn. Me and @_Rachio take care of that." + ] | random + " #SavingWater"}} diff --git a/automation/kitchen_lights_and_accents.yaml b/automation/kitchen_lights_and_accents.yaml new file mode 100755 index 00000000..12743bf2 --- /dev/null +++ b/automation/kitchen_lights_and_accents.yaml @@ -0,0 +1,61 @@ +##################################################################################### +### If the Kitchen Lights go on for more than 10 minutes, turn off the accent lights +### connected to [Etekcity Outlets](http://amzn.to/2efNoBP) +## [433Mhz Transmitter and receiver](http://amzn.to/2dceNY2) +##################################################################################### + +- alias: Kitchen lights on - Accent lights off + trigger: + - platform: state + entity_id: group.kitchen_lights + to: 'on' + for: '00:05:00' + + condition: + - condition: state + entity_id: switch.kitchen_accents + state: 'on' + + action: + - service: switch.turn_off + entity_id: switch.kitchen_accents + +############################################################################## + +- alias: Kitchen lights off - turn on Accent lights + trigger: + - platform: state + entity_id: group.kitchen_lights + to: 'off' + for: '00:05:00' + - platform: state + entity_id: sun.sun + to: 'below_horizon' + from: 'above_horizon' + + condition: + - condition: sun + after: 'sunset' + - condition: state + entity_id: group.kitchen_lights + state: 'off' + - condition: or + conditions: + - condition: state + entity_id: binary_sensor.sleepnumber_carlo_carlo_is_in_bed + state: 'off' + - condition: state + entity_id: binary_sensor.sleepnumber_carlo_stacey_is_in_bed + state: 'off' + - condition: or + conditions: + - condition: state + entity_id: group.family + state: 'home' + - condition: state + entity_id: input_boolean.guest_mode + state: 'on' + + action: + - service: switch.turn_on + entity_id: switch.kitchen_accents diff --git a/automation/late_night_helper.yaml b/automation/late_night_helper.yaml new file mode 100755 index 00000000..fc3be58d --- /dev/null +++ b/automation/late_night_helper.yaml @@ -0,0 +1,46 @@ +################################### +## Late Night lights Section +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +################################### +- alias: 'Late Night Helper' + trigger: + - platform: state + entity_id: + - binary_sensor.downstairs_away_mode + to: 'off' + - platform: state + entity_id: group.family + to: home + + condition: + condition: and + conditions: + - condition: state + entity_id: sun.sun + state: 'below_horizon' + - condition: state + entity_id: group.bed + state: 'off' + + action: + - service: light.turn_on + entity_id: + - light.living_room_slider + - light.foyer_door + - light.fridge + - light.M1_front_right + - light.S1 + - light.S4 + - service: switch.turn_on + entity_id: + - switch.kitchen_accents + - delay: '00:05:00' + - service: light.turn_off + entity_id: + - light.S1 + - light.S4 + - light.foyer_door + - light.fridge + - light.living_room_slider + - light.M1_front_right diff --git a/automation/late_night_outside_helper.yaml b/automation/late_night_outside_helper.yaml new file mode 100755 index 00000000..61f428eb --- /dev/null +++ b/automation/late_night_outside_helper.yaml @@ -0,0 +1,59 @@ +################################### +## Late Night lights Section +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +################################### +- alias: 'Late Night Helper outside' + trigger: + - platform: state + entity_id: group.all_covers + to: 'open' + - platform: state + entity_id: sun.sun + to: 'below_horizon' + from: 'above_horizon' + + condition: + condition: and + conditions: + - condition: state + entity_id: sun.sun + state: 'below_horizon' + - condition: state + entity_id: group.all_covers + state: 'open' + + action: + - service: scene.turn_on + entity_id: scene.front_full_brightness + - service: light.turn_on + entity_id: + - group.living_room_accents + data_template: + color_name: > + {% if states.group.entry_points.state == 'on' or states.group.all_covers.state != 'closed' -%} + red + {% else %} + gold + {% endif %} + - service: switch.turn_on + entity_id: + - switch.master_bathroom_accents + - switch.back_landscaping + - switch.front_door_outlet + - switch.living_room_outlet + - switch.den_outlet + - switch.foyer_outlet + - wait_template: >- + {{ states.group.garage_doors.state == 'closed' }} + - service: script.monthly_color_scene + - service: light.turn_on + entity_id: + - group.living_room_accents + data_template: + color_name: > + {% if states.group.entry_points.state == 'on' or states.group.all_covers.state != 'closed' -%} + red + {% else %} + gold + {% endif %} diff --git a/automation/master_bath_accents.yaml b/automation/master_bath_accents.yaml new file mode 100755 index 00000000..bb958276 --- /dev/null +++ b/automation/master_bath_accents.yaml @@ -0,0 +1,41 @@ +##################################################################################### +### When we get out of bed at night, turn on the accent lights in the bathroom +## and then turn off the lights when we are back in bed. +## Also turn on the lights sunset comes. (but only if we are home) +### connected to [Etekcity Outlets](http://amzn.to/2efNoBP) +## [433Mhz Transmitter and receiver](http://amzn.to/2dceNY2) +##################################################################################### + +- alias: Bedtime Accent Light + trigger: + - platform: state + entity_id: + - binary_sensor.sleepnumber_carlo_carlo_is_in_bed + - binary_sensor.sleepnumber_carlo_stacey_is_in_bed + to: 'off' + - platform: state + entity_id: sun.sun + to: 'below_horizon' + from: 'above_horizon' + - platform: state + entity_id: group.family + from: 'not_home' + to: 'home' + + condition: + - condition: state + entity_id: sun.sun + state: 'below_horizon' + - condition: state + entity_id: group.family + state: 'home' + + action: + - service: switch.turn_on + entity_id: switch.master_bathroom_accents + - wait_template: >- + {{ not is_state('binary_sensor.sleepnumber_carlo_stacey_is_in_bed', 'off') }} + - wait_template: >- + {{ not is_state('binary_sensor.sleepnumber_carlo_carlo_is_in_bed', 'off') }} + - service: switch.turn_off + entity_id: switch.master_bathroom_accents diff --git a/automation/mealtime.yaml b/automation/mealtime.yaml new file mode 100755 index 00000000..e47a38f0 --- /dev/null +++ b/automation/mealtime.yaml @@ -0,0 +1,21 @@ +###################################################################### +## Time to eat - Set it up! +###################################################################### + +- alias: Meal Time + trigger: + - platform: state + entity_id: input_boolean.meal_time + to: 'on' + from: 'off' + + action: + - service: light.turn_on + entity_id: + - group.dinette_lights + - group.kitchen_lights + - service: light.turn_off + entity_id: + - group.living_room_lights + - service: input_boolean.turn_off + entity_id: input_boolean.meal_time diff --git a/automation/medicine_logger.yaml b/automation/medicine_logger.yaml new file mode 100755 index 00000000..3879223f --- /dev/null +++ b/automation/medicine_logger.yaml @@ -0,0 +1,36 @@ +################################### +## LOG Medicine +################################### +- alias: 'Log Medicine Activity' + hide_entity: True + trigger: + - platform: event + event_type: medicine_dash + - platform: state + entity_id: input_boolean.medicine + to: 'on' + from: 'off' + + action: + - service: input_boolean.turn_on + entity_id: input_boolean.medicine + - service: automation.turn_off + entity_id: automation.log_medicine_activity + - service: logbook.log + data: + name: "Medicine Push" + message: "Took Medicine today." + + - service: mqtt.publish + data_template: + payload: '{{ states("sensor.date") }}' + topic: 'dash/medicine/medicine_time' + retain: true + + - service: script.notify_engine + data_template: + value1: 'Took Medicine today.' + who: "parents" + - delay: + minutes: 1 + - service: automation.turn_on diff --git a/automation/tv_time_on_and_off.yaml b/automation/tv_time_on_and_off.yaml new file mode 100755 index 00000000..1b02e1ec --- /dev/null +++ b/automation/tv_time_on_and_off.yaml @@ -0,0 +1,57 @@ +###################################################################### +## TV Time at sunset or 8pm. Whichever is later. +###################################################################### + +- alias: TV Time + trigger: + - platform: state + entity_id: input_boolean.TV_time + to: 'on' + from: 'off' + - platform: state + entity_id: sensor.samsungtv + to: 'Online' + from: 'Offline' + - platform: state + entity_id: sun.sun + to: 'below_horizon' + from: 'above_horizon' + - platform: state + entity_id: media_player.living_room_ultra + to: 'playing' + from: 'idle' + - platform: time + at: '20:00:00' + + condition: + condition: and + conditions: + - condition: state + entity_id: group.family + state: home + - condition: state + entity_id: sensor.samsungtv + state: 'Online' + - condition: state + entity_id: sun.sun + state: 'below_horizon' + - condition: state + entity_id: input_boolean.guest_mode + state: 'off' + - condition: time + after: '20:00:00' + + action: + - service: input_boolean.turn_off + entity_id: input_boolean.tv_time + + - service: light.turn_off + entity_id: + - group.dinette_lights + - group.kitchen_lights + + - service: switch.turn_on + entity_id: switch.kitchen_accents + + - service: scene.turn_on + entity_id: scene.tv_time diff --git a/automation/upstairs_motion_ifttt.yaml b/automation/upstairs_motion_ifttt.yaml new file mode 100755 index 00000000..27ca2c63 --- /dev/null +++ b/automation/upstairs_motion_ifttt.yaml @@ -0,0 +1,32 @@ +# Uses the Nest thermostat to turn on lights and turn them off upstairs. + +- alias: 'Upstairs Light Turn on' + trigger: + - platform: event + event_type: upstairs_light_on + - platform: state + entity_id: binary_sensor.upstairs_away_mode + to: 'off' + + condition: + - condition: state + entity_id: sun.sun + state: 'below_horizon' + - condition: time + before: '23:45' + + action: + - service: light.turn_on + entity_id: group.upstairs + +- alias: 'Upstairs Light Turn off' + trigger: + - platform: event + event_type: upstairs_light_off + - platform: state + entity_id: binary_sensor.upstairs_away_mode + to: 'on' + + action: + service: light.turn_off + entity_id: group.upstairs diff --git a/automation/work.yaml b/automation/work.yaml new file mode 100755 index 00000000..9945c6ff --- /dev/null +++ b/automation/work.yaml @@ -0,0 +1,22 @@ +###################################################################### +## Time to work - Set it up! +###################################################################### + +- alias: Time to Work + trigger: + - platform: state + entity_id: input_boolean.work + to: 'on' + from: 'off' + + action: + - service: light.turn_off + entity_id: + - group.dinette_lights + - group.kitchen_lights + - group.living_room_lights + - service: light.turn_on + entity_id: + - light.office_lamp + - service: input_boolean.turn_off + entity_id: input_boolean.work diff --git a/automation/zwave_hallway_door_sensor.yaml b/automation/zwave_hallway_door_sensor.yaml new file mode 100755 index 00000000..9a935554 --- /dev/null +++ b/automation/zwave_hallway_door_sensor.yaml @@ -0,0 +1,73 @@ +################################### +## ZWave Section - +## Home Assistant runs on my [Raspberry Pi 3](http://amzn.to/2e3DOBY) with [Aeon Labs Z Wave Stick (GEN 5)](http://amzn.to/2eAiAP0). +################################### + +############################################################## +- alias: Hallway ZWave Enerwave Door Sensors Open + hide_entity: True + trigger: + - platform: state + entity_id: binary_sensor.hallway_pantry_opened + to: 'on' + - platform: state + entity_id: binary_sensor.hallway_linen_opened + to: 'on' + + condition: + condition: or + conditions: + - condition: sun + after: sunset + after_offset: '-03:00:00' + - condition: numeric_state + entity_id: sensor.dark_sky_cloud_coverage + above: 50 + + action: + - service: light.turn_on + entity_id: + - light.kids_hallway + - light.k4 + - delay: 00:20:00 + - service: light.turn_off + entity_id: light.kids_hallway + +############################################################## +- alias: ZWave Enerwave Door Sensors Closed + hide_entity: True + trigger: + - platform: state + entity_id: binary_sensor.hallway_pantry_opened + to: 'off' + - platform: state + entity_id: binary_sensor.hallway_linen_opened + to: 'off' + + action: + service: light.turn_off + entity_id: light.kids_hallway + +############################################################## +- alias: Shutdown Helper light + hide_entity: True + trigger: + - platform: state + entity_id: light.k4 + to: 'on' + for: '00:20:00' + - platform: state + entity_id: binary_sensor.hallway_pantry_opened + to: 'off' + - platform: state + entity_id: binary_sensor.hallway_linen_opened + to: 'off' + + condition: + condition: state + entity_id: light.k1 + state: 'off' + + action: + - service: light.turn_off + entity_id: light.k4 diff --git a/configuration.yaml b/configuration.yaml new file mode 100755 index 00000000..b723463d --- /dev/null +++ b/configuration.yaml @@ -0,0 +1,267 @@ +homeassistant: + name: Bear Stone Run + latitude: !secret homeassistant_latitude + longitude: !secret homeassistant_longitude + elevation: !secret homeassistant_elevation + unit_system: imperial + time_zone: America/New_York + customize: !include_dir_merge_named customize + customize_domain: + automation: + initial_state: 'on' + customize_glob: + "automation.*watchdog*": + icon: mdi:timer + "sensor.dark_sky_*": + homebridge_hidden: true + "scene.month_*_colors": + hidden: true + emulated_hue_hidden: true + homebridge_hidden: true + + packages: !include_dir_named packages + +# cloud: +# alexa: +# filter: +# # include_entities: +# # - light.kitchen +# include_domains: +# - switch +# - covers +# - group +# # exclude_entities: +# # - light.living_room +# # exclude_domains: +# # - light +# # - media_player + +http: + base_url: !secret http_base_url + # server_port: !secret http_port + api_password: !secret http_api_password + ssl_certificate: !secret ssl_certificate + ssl_key: !secret ssl_key + trusted_networks: + - 192.168.10.0/24 + - !secret external_ip + ip_ban_enabled: True + login_attempts_threshold: 3 + +frontend: + javascript_version: latest + +panel_custom: + - name: floorplan + sidebar_title: Alarm Panel + sidebar_icon: mdi:security-home + url_path: floorplan + config: + hide_app_toolbar: + config: /local/custom_ui/floorplan/floorplan.yaml + + - name: clock + sidebar_title: Alarm Clock + sidebar_icon: mdi:alarm + url_path: clock + config: + hide_app_toolbar: + config: /local/custom_ui/floorplan/floorclock.yaml + +notify: + - platform: ios + - name: ios_family + platform: group + services: + - service: ios_staceys_iphone + - service: ios_carlo_6s + - name: ios_parents + platform: group + services: + - service: ios_staceys_iphone + - service: ios_carlo_6s + +discovery: + ignore: + - samsung_tv +# - roku +# - google_cast + +updater: + include_used_components: true + +sun: +# for when 0.60.1 is released. +# hue: +# bridges: +# - host: 192.168.10.75 +# filename: phue.conf +# allow_unreachable: true +# allow_in_emulated_hue: false +# allow_hue_groups: false +# - host: 192.168.10.76 +# filename: phue2.conf +# allow_unreachable: true +# allow_in_emulated_hue: false +# allow_hue_groups: false + +light: + - platform: hue + host: 192.168.10.75 + filename: phue.conf + allow_unreachable: true + allow_in_emulated_hue: false + allow_hue_groups: false + +light 2: + - platform: hue + host: 192.168.10.76 + filename: phue2.conf + allow_unreachable: true + allow_in_emulated_hue: false + allow_hue_groups: false + +# Reference : https://www.flexfireleds.com/pages/Comparison-between-3528-LEDs-and-5050-LEDs.html + - platform: flux_led + automatic_add: True + devices: + 192.168.10.148: + name: led_garage_snip + mode: "rgb" + 192.168.10.214: + name: led_outdoor_den + mode: "rgb" + 192.168.10.213: + name: led_garage_large + mode: "rgb" + 192.168.10.212: + name: led_garage_small + mode: "rgb" + +emulated_hue: + host_ip: 192.168.10.10 + listen_port: 8300 + expose_by_default: false + +ifttt: + key: !secret ifttt_key + +logbook: + exclude: + entities: + - automation.detect_lights_and_adjust_the_brightness_when_turned_on_based_on_time + - automation.cuckoo_clock + - binary_sensor.office_motion + - group.garage_doors + - media_player.LivingRoomCC + - py.warnings + - sensor.since_last_boot + - sensor.since_last_boot_templated + - sensor.small_garage_status + - sensor.large_garage_status + - sensor.small_garage_time_in_state + - sensor.large_garage_time_in_state + - sensor.large_garage_wifi_signal_strength + - sensor.small_garage_wifi_signal_strength + - sensor.small_garage_reflection_rate + - sensor.large_garage_reflection_rate + - sensor.pihole_ads_blocked_today + - sensor.pihole_ads_percentage_blocked_today + - sensor.pihole_dns_queries_today + - sensor.time + - sensor.date + - sensor.floorplan_date + - sensor.floorplan_time + - sensor.ha_uptime + +history: + include: + domains: + - sensor + - switch + - media_player + - light + - binary_sensor + - cover + + exclude: + entities: + - sensor.last_boot + - sensor.date + - sensor.pihole_ads_blocked_today + - sensor.pihole_ads_percentage_blocked_today + - sensor.pihole_dns_queries_today + - sensor.since_last_boot + - sensor.since_last_boot_templated + - sensor.floorplan_date + - sensor.floorplan_time + - sensor.ha_uptime + - sensor.time + +logger: !include logger.yaml +recorder: !include recorder.yaml + +mqtt: + broker: 127.0.0.1 + port: 1883 + client_id: home-assistant-Carlo + username: !secret MQTT_username + password: !secret MQTT_password + +# zwave: +# usb_path: /dev/ttyACM0 +# config_path: /srv/hass/hass_venv/lib/python3.4/site-packages/libopenzwave-0.3.1-py3.4-linux-armv7l.egg/config + +nest: + client_id: !secret nest_client_id + client_secret: !secret nest_client_secret + +climate: + platform: nest + +media_player: + - platform: cast + host: 192.168.10.209 #CCA1 + - platform: roku + + # - platform: samsungtv + # host: 192.168.10.207 + # port: 8001 + # name: Living Room TV + # scan_interval: 180 + +tts: + - platform: amazon_polly + aws_access_key_id: !secret aws_access_key_ID + aws_secret_access_key: !secret aws_secret_access_key + region_name: 'us-east-1' + text_type: ssml + cache: True +# cache_dir: /data/tts + +wink: + # email: !secret wink_username + # password: !secret wink_password + # local_control: True + +cover: + platform: garadget + covers: + !secret large_garage_id: + username: !secret garadget_username + password: !secret garadget_password + name: Large Garage + !secret small_garage_id: + username: !secret garadget_username + password: !secret garadget_password + name: Small Garage + +group: !include_dir_merge_named group +device_tracker: !include_dir_merge_list device_tracker +sensor: !include_dir_merge_list sensor +automation: !include_dir_merge_list automation +scene: !include_dir_merge_list scene +switch: !include_dir_merge_list switch +script: !include_dir_merge_named script +input_boolean: !include_dir_merge_named input_boolean +shell_command: !include_dir_merge_named shell_command diff --git a/custom_components/media_player/README.md b/custom_components/media_player/README.md new file mode 100755 index 00000000..1c79e254 --- /dev/null +++ b/custom_components/media_player/README.md @@ -0,0 +1,15 @@ +# [![Build Status](https://travis-ci.org/CCOSTAN/Home-AssistantConfig.svg?branch=master)](https://travis-ci.org/CCOSTAN/Home-AssistantConfig) Home-Assistant Config by [@ccostan](http://www.twitter.com/ccostan) +[Home Assistant](https://home-assistant.io/) configuration files (YAMLs) + +Be sure to :star: my repo so you can keep up to date on the daily progress! + +This is a Custom Component by pkozul to allow me to use my Floorplan installation as a Media Player. This allows me to send all TTS and home notifications to the Fire Tablets I use with Floorplan. + +#Still have questions on my Config? +Follow me on twitter : [@CCostan](https://twitter.com/ccostan) + +You can also vist my [Blog](http://www.vmwareinfo.com/search/label/iot) for all of my [Home Automation Posts](http://www.vmwareinfo.com/search/label/iot). + + + Sponsor + diff --git a/custom_components/media_player/cast.py b/custom_components/media_player/cast.py new file mode 100755 index 00000000..c37244f3 --- /dev/null +++ b/custom_components/media_player/cast.py @@ -0,0 +1,329 @@ +""" +Provide functionality to interact with Cast devices on the network. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/media_player.cast/ +""" +# pylint: disable=import-error +import logging + +import voluptuous as vol + +from homeassistant.components.media_player import ( + MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, MEDIA_TYPE_VIDEO, SUPPORT_NEXT_TRACK, + SUPPORT_PAUSE, SUPPORT_PLAY_MEDIA, SUPPORT_PREVIOUS_TRACK, + SUPPORT_TURN_OFF, SUPPORT_TURN_ON, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, + SUPPORT_STOP, SUPPORT_PLAY, MediaPlayerDevice, PLATFORM_SCHEMA) +from homeassistant.const import ( + CONF_HOST, STATE_IDLE, STATE_OFF, STATE_PAUSED, STATE_PLAYING, + STATE_UNKNOWN) +import homeassistant.helpers.config_validation as cv +import homeassistant.util.dt as dt_util + +# Do not upgrade to 1.0.2, it breaks a bunch of stuff +# https://github.com/home-assistant/home-assistant/issues/10926 +REQUIREMENTS = ['pychromecast==1.0.3'] + +_LOGGER = logging.getLogger(__name__) + +CONF_IGNORE_CEC = 'ignore_cec' +CAST_SPLASH = 'https://home-assistant.io/images/cast/splash.png' + +DEFAULT_PORT = 8009 + +SUPPORT_CAST = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \ + SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PREVIOUS_TRACK | \ + SUPPORT_NEXT_TRACK | SUPPORT_PLAY_MEDIA | SUPPORT_STOP | SUPPORT_PLAY + +KNOWN_HOSTS_KEY = 'cast_known_hosts' + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_HOST): cv.string, + vol.Optional(CONF_IGNORE_CEC): [cv.string], +}) + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices, discovery_info=None): + """Set up the cast platform.""" + import pychromecast + + # Import CEC IGNORE attributes + pychromecast.IGNORE_CEC += config.get(CONF_IGNORE_CEC, []) + + known_hosts = hass.data.get(KNOWN_HOSTS_KEY) + if known_hosts is None: + known_hosts = hass.data[KNOWN_HOSTS_KEY] = [] + + if discovery_info: + host = (discovery_info.get('host'), discovery_info.get('port')) + + if host in known_hosts: + return + + hosts = [host] + + elif CONF_HOST in config: + host = (config.get(CONF_HOST), DEFAULT_PORT) + + if host in known_hosts: + return + + hosts = [host] + + else: + hosts = [tuple(dev[:2]) for dev in pychromecast.discover_chromecasts() + if tuple(dev[:2]) not in known_hosts] + + casts = [] + + # get_chromecasts() returns Chromecast objects with the correct friendly + # name for grouped devices + all_chromecasts = pychromecast.get_chromecasts() + + for host in hosts: + (_, port) = host + found = [device for device in all_chromecasts + if (device.host, device.port) == host] + if found: + try: + casts.append(CastDevice(found[0])) + known_hosts.append(host) + except pychromecast.ChromecastConnectionError: + pass + + # do not add groups using pychromecast.Chromecast as it leads to names + # collision since pychromecast.Chromecast will get device name instead + # of group name + elif port == DEFAULT_PORT: + try: + # add the device anyway, get_chromecasts couldn't find it + casts.append(CastDevice(pychromecast.Chromecast(*host))) + known_hosts.append(host) + except pychromecast.ChromecastConnectionError: + pass + + add_devices(casts) + + +class CastDevice(MediaPlayerDevice): + """Representation of a Cast device on the network.""" + + def __init__(self, chromecast): + """Initialize the Cast device.""" + self.cast = chromecast + + self.cast.socket_client.receiver_controller.register_status_listener( + self) + self.cast.socket_client.media_controller.register_status_listener(self) + + self.cast_status = self.cast.status + self.media_status = self.cast.media_controller.status + self.media_status_received = None + + @property + def should_poll(self): + """No polling needed.""" + return False + + @property + def name(self): + """Return the name of the device.""" + return self.cast.device.friendly_name + + # MediaPlayerDevice properties and methods + @property + def state(self): + """Return the state of the player.""" + if self.media_status is None: + return STATE_UNKNOWN + elif self.media_status.player_is_playing: + return STATE_PLAYING + elif self.media_status.player_is_paused: + return STATE_PAUSED + elif self.media_status.player_is_idle: + return STATE_IDLE + elif self.cast.is_idle: + return STATE_OFF + return STATE_UNKNOWN + + @property + def volume_level(self): + """Volume level of the media player (0..1).""" + return self.cast_status.volume_level if self.cast_status else None + + @property + def is_volume_muted(self): + """Boolean if volume is currently muted.""" + return self.cast_status.volume_muted if self.cast_status else None + + @property + def media_content_id(self): + """Content ID of current playing media.""" + return self.media_status.content_id if self.media_status else None + + @property + def media_content_type(self): + """Content type of current playing media.""" + if self.media_status is None: + return None + elif self.media_status.media_is_tvshow: + return MEDIA_TYPE_TVSHOW + elif self.media_status.media_is_movie: + return MEDIA_TYPE_VIDEO + elif self.media_status.media_is_musictrack: + return MEDIA_TYPE_MUSIC + return None + + @property + def media_duration(self): + """Duration of current playing media in seconds.""" + return self.media_status.duration if self.media_status else None + + @property + def media_image_url(self): + """Image url of current playing media.""" + if self.media_status is None: + return None + + images = self.media_status.images + + return images[0].url if images else None + + @property + def media_title(self): + """Title of current playing media.""" + return self.media_status.title if self.media_status else None + + @property + def media_artist(self): + """Artist of current playing media (Music track only).""" + return self.media_status.artist if self.media_status else None + + @property + def media_album(self): + """Album of current playing media (Music track only).""" + return self.media_status.album_name if self.media_status else None + + @property + def media_album_artist(self): + """Album arist of current playing media (Music track only).""" + return self.media_status.album_artist if self.media_status else None + + @property + def media_track(self): + """Track number of current playing media (Music track only).""" + return self.media_status.track if self.media_status else None + + @property + def media_series_title(self): + """Return the title of the series of current playing media.""" + return self.media_status.series_title if self.media_status else None + + @property + def media_season(self): + """Season of current playing media (TV Show only).""" + return self.media_status.season if self.media_status else None + + @property + def media_episode(self): + """Episode of current playing media (TV Show only).""" + return self.media_status.episode if self.media_status else None + + @property + def app_id(self): + """Return the ID of the current running app.""" + return self.cast.app_id + + @property + def app_name(self): + """Name of the current running app.""" + return self.cast.app_display_name + + @property + def supported_features(self): + """Flag media player features that are supported.""" + return SUPPORT_CAST + + @property + def media_position(self): + """Position of current playing media in seconds.""" + if self.media_status is None or \ + not (self.media_status.player_is_playing or + self.media_status.player_is_paused or + self.media_status.player_is_idle): + return None + + return self.media_status.current_time + + @property + def media_position_updated_at(self): + """When was the position of the current playing media valid. + + Returns value from homeassistant.util.dt.utcnow(). + """ + return self.media_status_received + + def turn_on(self): + """Turn on the ChromeCast.""" + # The only way we can turn the Chromecast is on is by launching an app + if not self.cast.status or not self.cast.status.is_active_input: + import pychromecast + + if self.cast.app_id: + self.cast.quit_app() + + self.cast.play_media( + CAST_SPLASH, pychromecast.STREAM_TYPE_BUFFERED) + + def turn_off(self): + """Turn Chromecast off.""" + self.cast.quit_app() + + def mute_volume(self, mute): + """Mute the volume.""" + self.cast.set_volume_muted(mute) + + def set_volume_level(self, volume): + """Set volume level, range 0..1.""" + self.cast.set_volume(volume) + + def media_play(self): + """Send play command.""" + self.cast.media_controller.play() + + def media_pause(self): + """Send pause command.""" + self.cast.media_controller.pause() + + def media_stop(self): + """Send stop command.""" + self.cast.media_controller.stop() + + def media_previous_track(self): + """Send previous track command.""" + self.cast.media_controller.rewind() + + def media_next_track(self): + """Send next track command.""" + self.cast.media_controller.skip() + + def media_seek(self, position): + """Seek the media to a specific location.""" + self.cast.media_controller.seek(position) + + def play_media(self, media_type, media_id, **kwargs): + """Play media from a URL.""" + self.cast.media_controller.play_media(media_id, media_type) + + # Implementation of chromecast status_listener methods + def new_cast_status(self, status): + """Handle updates of the cast status.""" + self.cast_status = status + self.schedule_update_ha_state() + + def new_media_status(self, status): + """Handle updates of the media status.""" + self.media_status = status + self.media_status_received = dt_util.utcnow() + self.schedule_update_ha_state() \ No newline at end of file diff --git a/custom_components/media_player/floorplan_speaker.py b/custom_components/media_player/floorplan_speaker.py new file mode 100755 index 00000000..da8a4bc9 --- /dev/null +++ b/custom_components/media_player/floorplan_speaker.py @@ -0,0 +1,160 @@ +""" +Support for Floorplan Speaker + +""" +import voluptuous as vol + +from homeassistant.components.media_player import ( + ENTITY_ID_FORMAT, + SUPPORT_PLAY_MEDIA, + SUPPORT_VOLUME_SET, + PLATFORM_SCHEMA, + MediaPlayerDevice) +from homeassistant.const import ( + CONF_NAME, STATE_IDLE, STATE_PLAYING) +from homeassistant.components import http +from homeassistant.components.http import HomeAssistantView +from homeassistant.helpers.entity import async_generate_entity_id +import homeassistant.helpers.config_validation as cv + +import logging + +import os +import re +import sys +import time +import asyncio +import json + +DEFAULT_NAME = 'Floorplan Speaker' +DEFAULT_VOLUME = 1.0 + +SUPPORT_FLOORPLAN_SPEAKER = SUPPORT_PLAY_MEDIA | SUPPORT_VOLUME_SET + +CONF_ADDRESS = 'address' + +ATTR_ADDRESS = 'address' +ATTR_BATTERY_LEVEL = 'battery_level' +ATTR_SCREEN_BRIGHTNESS = 'screen_brightness' +ATTR_DEVICE_ID = 'device_id' +ATTR_SERIAL_NUMBER = 'serial_number' + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, +}) + +_LOGGER = logging.getLogger(__name__) + +def setup_platform(hass, config, add_devices, discovery_info=None): + name = config.get(CONF_NAME) + address = config.get(CONF_ADDRESS) + + device = FloorplanSpeakerDevice(hass, name, address) + + """Set up an endpoint for the media player.""" + hass.http.register_view(device) + + add_devices([device]) + + return True + +class FloorplanSpeakerDevice(MediaPlayerDevice, http.HomeAssistantView): + def __init__(self, hass, name, address): + self._hass = hass + self._name = name + self.entity_id = async_generate_entity_id(ENTITY_ID_FORMAT, name, hass=hass) + self._state = STATE_IDLE + self._media_content_id = None + self._address = address + self._volume = DEFAULT_VOLUME + self._battery_level = None + self._screen_brightness = None + self._device_id = None + self._serial_number = None + self.url = '/api/fully_kiosk/media_player/' + self.entity_id + _LOGGER.info('Setting endpoint: %s', self.url) + + @asyncio.coroutine + def post(self, request): + body = yield from request.text() + try: + data = json.loads(body) if body else None + except ValueError: + return self.json_message('Event data should be valid JSON', HTTP_BAD_REQUEST) + + if data is not None and not isinstance(data, dict): + return self.json_message('Event data should be a JSON object', HTTP_BAD_REQUEST) + + data = json.loads(body) if body else None + + _LOGGER.info("Received from Fully Kiosk: %s: %s", self.url, data) + + self._state = data['state'] + self._media_content_id = data['attributes']['media_content_id'] + self._volume = data['attributes']['volume_level'] + self._address = data['attributes'][ATTR_ADDRESS] + self._battery_level = data['attributes'][ATTR_BATTERY_LEVEL] + self._screen_brightness = data['attributes'][ATTR_SCREEN_BRIGHTNESS] + self._device_id = data['attributes'][ATTR_DEVICE_ID] + self._serial_number = data['attributes'][ATTR_SERIAL_NUMBER] + + @property + def name(self): + return self._name + + @property + def state(self): + return self._state + + @property + def supported_features(self): + return SUPPORT_FLOORPLAN_SPEAKER + + @property + def address(self): + return self._address + + @property + def volume_level(self): + return self._volume + + @property + def media_content_id(self): + return self._media_content_id + + @property + def battery_level(self): + return self._battery_level + + @property + def device_id(self): + return self._device_id + + @property + def serial_number(self): + return self._serial_number + + @property + def device_state_attributes(self): + return { + ATTR_ADDRESS: self._address, + ATTR_BATTERY_LEVEL: self._battery_level, + ATTR_SCREEN_BRIGHTNESS: self._screen_brightness, + ATTR_DEVICE_ID: self._device_id, + ATTR_SERIAL_NUMBER: self._serial_number, + } + + def set_volume_level(self, volume): + self._volume = volume + + def play_media(self, media_type, media_id, **kwargs): + _LOGGER.info('play_media: %s', media_id) + + def media_play(self): + _LOGGER.info('media_play') + + def media_pause(self): + _LOGGER.info('media_pause') + + def media_stop(self): + _LOGGER.info('media_stop') diff --git a/customize/binary_sensors.yaml b/customize/binary_sensors.yaml new file mode 100755 index 00000000..31cd2ac5 --- /dev/null +++ b/customize/binary_sensors.yaml @@ -0,0 +1,419 @@ +binary_sensor.bedroom_alarm_panel: + friendly_name: 'Bedroom Alarm Panel' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + + + + +binary_sensor.carlowink: + friendly_name: 'Carlo-Wink' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:router-wireless + + + +binary_sensor.downstairs_thermostat_fan: + friendly_name: 'Downstairs Thermostat Fan' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +binary_sensor.downstairs_thermostat_has_leaf: + friendly_name: 'Downstairs Thermostat Has Leaf' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +binary_sensor.downstairs_thermostat_is_locked: + friendly_name: 'Downstairs Thermostat Is Locked' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +binary_sensor.downstairs_thermostat_is_using_emergency_heat: + friendly_name: 'Downstairs Thermostat Is Using Emergency Heat' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +binary_sensor.downstairs_thermostat_online: + friendly_name: 'Downstairs Thermostat Online' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +binary_sensor.entry_alarm_panel: + friendly_name: 'Entry Alarm Panel' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + + + + +binary_sensor.hallway_linen_opened: + friendly_name: 'Hallway Linen Door' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:home-variant + + + +binary_sensor.hallway_nest_protect_kids_hallway_online: + friendly_name: 'Kids Hallway Protect' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:nest-protect + + + +binary_sensor.hallway_pantry_opened: + friendly_name: 'Hallway Pantry Door' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:home-variant + + + +binary_sensor.iss: + friendly_name: 'Iss Visibility' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:satellite-variant + + + +binary_sensor.justins_room_nest_protect_online: + friendly_name: 'Justins Room Protect' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:nest-protect + + + +binary_sensor.kitchen_door_opened: + friendly_name: 'Kitchen Door' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: False + icon: mdi:home-variant + + + +binary_sensor.kitchen_nest_protect_online: + friendly_name: 'Kitchen Protect' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:nest-protect + + + +binary_sensor.master_bedroom_nest_protect_online: + friendly_name: 'Master Bedroom Protect' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:nest-protect + + + +binary_sensor.master_hallway_nest_protect_online: + friendly_name: 'Master Hallway Protect' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:nest-protect + + + +binary_sensor.mcu1_gpio10: + friendly_name: 'Dining Room Windows' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu1_gpio12: + friendly_name: 'Interior Garage Door' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu1_gpio13: + friendly_name: 'Front Den Windows' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu1_gpio14: + friendly_name: 'Office Window' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu1_gpio4: + friendly_name: 'Paige Window' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu1_gpio5: + friendly_name: 'Front Door' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu2_gpio10: + friendly_name: 'Master Bathroom Window' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu2_gpio12: + friendly_name: 'Main Slider' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu2_gpio13: + friendly_name: 'Upstairs Bedroom Window' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu2_gpio14: + friendly_name: 'Justin Window' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu2_gpio4: + friendly_name: 'Dinette Windows' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu2_gpio5: + friendly_name: 'Back Door' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu2_gpio9: + friendly_name: 'Master Slider' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu3_gpio10: + friendly_name: 'Master Bedroom Window' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu3_gpio14: + friendly_name: 'Upstairs Windows' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu3_gpio4: + friendly_name: 'Stacey Bedroom Window' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu3_gpio5: + friendly_name: 'Carlo Bedroom Window' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.mcu3_light: + friendly_name: 'Panel Door' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:security-home + + + +binary_sensor.office_motion: + friendly_name: 'Office Motion Sensor' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:sensor + + + +binary_sensor.office_nest_protect_online: + friendly_name: 'Office Protect' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:nest-protect + + + +binary_sensor.paiges_room_nest_protect_paiges_room_online: + friendly_name: 'Paiges Room Protect' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:nest-protect + + + +binary_sensor.sleepnumber_carlo_carlo_is_in_bed: + friendly_name: 'Carlo Is In Bed' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: False + + + + +binary_sensor.sleepnumber_carlo_stacey_is_in_bed: + friendly_name: 'Stacey Is In Bed' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: False + + + + +binary_sensor.upstairs_bedroom_nest_protect_online: + friendly_name: 'Upstairs Bedroom Protect' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:nest-protect + + + +binary_sensor.upstairs_living_room_nest_protect_online: + friendly_name: 'Upstairs Living Room Protect' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:nest-protect + + + +binary_sensor.upstairs_thermostat_fan: + friendly_name: 'Upstairs Thermostat Fan' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +binary_sensor.upstairs_thermostat_has_leaf: + friendly_name: 'Upstairs Thermostat Has Leaf' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +binary_sensor.upstairs_thermostat_is_locked: + friendly_name: 'Upstairs Thermostat Is Locked' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +binary_sensor.upstairs_thermostat_is_using_emergency_heat: + friendly_name: 'Upstairs Thermostat Is Using Emergency Heat' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +binary_sensor.upstairs_thermostat_online: + friendly_name: 'Upstairs Thermostat Online' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True diff --git a/customize/covers.yaml b/customize/covers.yaml new file mode 100755 index 00000000..e75ddfbf --- /dev/null +++ b/customize/covers.yaml @@ -0,0 +1,12 @@ +cover.large_garage: + friendly_name: 'Large Garage' + emulated_hue_hidden: True + hidden: False + homebridge_cover_type: garage_door + + +cover.small_garage: + friendly_name: 'Small Garage' + emulated_hue_hidden: True + hidden: False + homebridge_cover_type: garage_door diff --git a/customize/device_tracker.yaml b/customize/device_tracker.yaml new file mode 100755 index 00000000..711f9f5f --- /dev/null +++ b/customize/device_tracker.yaml @@ -0,0 +1,389 @@ +device_tracker.actiontechap: + friendly_name: 'Actiontechap' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.bedroom_alarm_panel: + friendly_name: 'Bedroom Alarm Panel' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + +device_tracker.hue_hub_1: + friendly_name: 'Hue Hub 1' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + +device_tracker.hue_hub_2: + friendly_name: 'Hue Hub 2' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + +device_tracker.entry_alarm_panel: + friendly_name: 'Entry Alarm Panel' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +device_tracker.alexa_echo: + friendly_name: 'Alexa Echo' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.amazon_dot: + friendly_name: 'Amazon Dot' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.amazon_fire_stick: + friendly_name: '50f5da4cd5ec' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.carlo: + friendly_name: 'Carlo' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: False + + + +device_tracker.carlopihole: + friendly_name: 'Carlo-Pihole' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.chromecast_audio_1: + friendly_name: 'Chromecast Audio 1' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.chromecast_audio_2: + friendly_name: 'Chromecast Audio 2' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.circle: + friendly_name: 'Circle' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + +device_tracker.study_ap: + friendly_name: 'Ubiquity AP Study' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + +device_tracker.cisco_ap: + friendly_name: 'Cisco Ap' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.hue_h_1: + friendly_name: 'Hue H 1' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.hue_h_2: + friendly_name: 'Hue H 2' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.ipmdemounit: + friendly_name: 'Ipmdemounit' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.justin_dot: + friendly_name: 'Justin-Dot' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.large_garage: + friendly_name: 'Large Garage' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.living_room_roku: + friendly_name: 'Living Room Roku' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.master_bedroom_roku: + friendly_name: 'Master Bedroom Roku' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.nest_downstairs: + friendly_name: 'Nest Downstairs' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.nest_upstairs: + friendly_name: 'Nest Upstairs' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.nodemcu1: + friendly_name: 'Nodemcu1' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: mdi:chip + + + +device_tracker.nodemcu2: + friendly_name: 'Nodemcu2' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: mdi:chip + + + +device_tracker.nodemcu3: + friendly_name: 'Nodemcu3' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: mdi:chip + + + +device_tracker.nodemcu4: + friendly_name: 'A020a618077f' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: mdi:chip + + + +device_tracker.printer: + friendly_name: '001ba94e7b4a' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.rachio: + friendly_name: 'Rachio' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.rgb_led_garage_large: + friendly_name: 'Rgb Led Garage Large' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.rgb_led_garage_small: + friendly_name: 'Rgb Led Garage Small' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.rgb_led_outdoor_den: + friendly_name: 'Rgb Led Outdoor Den' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.samsungtv: + friendly_name: 'Samsung Tv' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.skybell: + friendly_name: 'Skybell' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.sleep_number_bed: + friendly_name: 'Sleep Number Bed' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.small_garage: + friendly_name: 'Small Garage' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.smart_water_meter: + friendly_name: 'Smart Water Meter' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.stacey: + friendly_name: 'Stacey' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: False + + + +device_tracker.staceyiphone_nat: + friendly_name: 'Stacey Iphone 2' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: true + + + + +device_tracker.tablotv: + friendly_name: 'Tablotv' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.trendnetap: + friendly_name: 'Trendnet Ap' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.unifi_ap: + friendly_name: 'Unifi Ap' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.wii: + friendly_name: 'Wii' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False + + + +device_tracker.withings_scale: + friendly_name: 'Withings Scale' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: False diff --git a/customize/groups.yaml b/customize/groups.yaml new file mode 100755 index 00000000..f1c5081d --- /dev/null +++ b/customize/groups.yaml @@ -0,0 +1,235 @@ +group.all_automations: + friendly_name: 'All Automations' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: true + + +group.all_covers: + friendly_name: 'All Covers' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: true + + +group.all_devices: + friendly_name: 'All Devices' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: true + + +group.all_lights: + friendly_name: 'All Lights' + emulated_hue_hidden: False + hidden: True + + + +group.all_scripts: + friendly_name: 'All Scripts' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: true + +group.all_switches: + friendly_name: 'All Switches' + emulated_hue_hidden: False + hidden: True + + + +group.amps: + friendly_name: 'Amps' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + + +group.sleep_number_bed: + friendly_name: 'Sleep Number Bed' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + + +group.bedroom_lights: + friendly_name: 'Bedroom Lights' + emulated_hue_hidden: False + hidden: False + + + +group.den_lights: + friendly_name: 'Den Lights' + emulated_hue_hidden: False + hidden: False + + + +group.dinette_lights: + friendly_name: 'Dinette Lights' + emulated_hue_hidden: False + hidden: False + + + +group.dining_room_lights: + friendly_name: 'Dining Room Lights' + emulated_hue_hidden: False + hidden: False + + + +group.exterior_lights: + friendly_name: 'Exterior Lights' + emulated_hue_hidden: False + hidden: False + + + +group.family: + friendly_name: 'Family' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + + +group.foyer_lights: + friendly_name: 'Foyer Lights' + emulated_hue_hidden: False + hidden: False + + + +group.garage_doors: + friendly_name: 'Garage Doors' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + + +group.garage_lights: + friendly_name: 'Garage Lights' + emulated_hue_hidden: False + hidden: False + + + +group.hallway_lights: + friendly_name: 'Hallway Lights' + emulated_hue_hidden: False + hidden: False + + + +group.home_modes: + friendly_name: 'Home Modes' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + + +group.interior_lights: + friendly_name: 'Interior Lights' + emulated_hue_hidden: False + hidden: False + + + +group.justins_room: + friendly_name: 'Justins Room' + emulated_hue_hidden: True + hidden: False + + + +group.kitchen_lights: + friendly_name: 'Kitchen Lights' + emulated_hue_hidden: False + hidden: False + + + +group.living_room_accents: + friendly_name: 'Living Room Accents' + emulated_hue_hidden: False + hidden: False + + + +group.living_room_lights: + friendly_name: 'Living Room Lights' + emulated_hue_hidden: False + hidden: False + + + +group.media_players: + friendly_name: 'Media Players' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + + +group.network: + friendly_name: 'Network' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + + +group.office_lights: + friendly_name: 'Office Lights' + emulated_hue_hidden: False + hidden: False + + + +group.outdoor_front_lights: + friendly_name: 'Outdoor Front Lights' + emulated_hue_hidden: False + hidden: False + + + +group.outdoor_pool_lights: + friendly_name: 'Outdoor Pool Lights' + emulated_hue_hidden: False + hidden: False + + + +group.paiges_room: + friendly_name: 'Paiges Room' + emulated_hue_hidden: True + hidden: False + + + +group.sensors: + friendly_name: 'Sensors' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + + +group.switches: + friendly_name: 'Switches' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + + +group.upstairs_lights: + friendly_name: 'Upstairs Lights' + emulated_hue_hidden: False + hidden: False + + + +group.weather: + friendly_name: 'Weather' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true diff --git a/customize/input_booleans.yaml b/customize/input_booleans.yaml new file mode 100755 index 00000000..107978d8 --- /dev/null +++ b/customize/input_booleans.yaml @@ -0,0 +1,177 @@ +input_boolean.alert_mode: + friendly_name: 'Alert Mode' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: True + icon: mdi:alert-octagram + + + +input_boolean.color_tornado: + friendly_name: 'Color Tornado' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: True + icon: mdi:invert-colors + + + +input_boolean.daylight_override: + friendly_name: 'Daylight Override' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + + + + +input_boolean.flash: + friendly_name: 'Flash' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:yin-yang + + + +input_boolean.good_morning: + friendly_name: 'Good Morning' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: True + icon: mdi:weather-sunset-up + + + +input_boolean.good_night: + friendly_name: 'Good Night' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:weather-night + + + +input_boolean.guard_dog: + friendly_name: 'Guard Dog' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:paw + + + +input_boolean.guest_mode: + friendly_name: 'Guest Mode' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:account-alert + + + +input_boolean.home_stats: + friendly_name: 'Home Stats' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:chart-bar + + + +input_boolean.house_station: + friendly_name: 'House Station' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:radio + + + +input_boolean.lastmsg: + friendly_name: 'Repeat Message' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:repeat-once + + + +input_boolean.meal_time: + friendly_name: 'Meal Time' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:food + + + +input_boolean.medicine: + friendly_name: 'Medicine' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + + + + +input_boolean.responsibilities: + friendly_name: 'Responsibilities' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:delete-sweep + + + +input_boolean.school_mode: + friendly_name: 'School Mode' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:school + + + +input_boolean.self_destruct: + friendly_name: 'Self Destruct' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:skull + + + +input_boolean.sleepy_dog: + friendly_name: 'Sleepy Dog' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:bell-sleep + + + +input_boolean.speech_notifications: + friendly_name: 'Speech Notifications' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:speaker-wireless + + + +input_boolean.tv_time: + friendly_name: 'Tv Time' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:television-guide + + + +input_boolean.work: + friendly_name: 'Work' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: true + icon: mdi:briefcase diff --git a/customize/lights.yaml b/customize/lights.yaml new file mode 100755 index 00000000..1812afa7 --- /dev/null +++ b/customize/lights.yaml @@ -0,0 +1,423 @@ +light.bedroom: + friendly_name: 'Bedroom' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.bedroom_hallway: + friendly_name: 'Bedroom Hallway' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.couch_1: + friendly_name: 'Couch 1' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.d1: + friendly_name: 'D1' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.d2: + friendly_name: 'D2' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.den_lamp: + friendly_name: 'Den Lamp' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.f1: + friendly_name: 'F1' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.f2: + friendly_name: 'F2' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.fridge: + friendly_name: 'Fridge' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.garage_attic: + friendly_name: 'Garage Attic' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + + + + +light.justin_go: + friendly_name: 'Justin Go' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.k1: + friendly_name: 'K1' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.k2: + friendly_name: 'K2' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.k3: + friendly_name: 'K3' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.k4: + friendly_name: 'K4' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.k5: + friendly_name: 'K5' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.k6: + friendly_name: 'K6' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.kids_hallway: + friendly_name: 'Kids Hallway' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.led_garage_large: + friendly_name: 'Garage Large Led' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: True + +light.led_garage_snip: + friendly_name: 'Garage Snip Led' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: True + + +light.led_garage_small: + friendly_name: 'Garage Small Led' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: True + + + + +light.led_outdoor_den: + friendly_name: 'Outdoor Den Led' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: True + + + + +light.m1_back_left: + friendly_name: 'M1 Back Left' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.m1_back_right: + friendly_name: 'M1 Back Right' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.m1_front_left: + friendly_name: 'M1 Front Left' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.m1_front_right: + friendly_name: 'M1 Front Right' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.m1_slider: + friendly_name: 'M1 Slider' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.master_toilet: + friendly_name: 'Master Toilet' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.office_lamp: + friendly_name: 'Office Lamp' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: False + + + + +light.outdoor_bathroom: + friendly_name: 'Outdoor Bathroom' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.outdoor_foyer: + friendly_name: 'Outdoor Foyer' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.outdoor_sconce_1: + friendly_name: 'Outdoor Sconce 1' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.outdoor_sconce_2: + friendly_name: 'Outdoor Sconce 2' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.outdoor_sconce_3: + friendly_name: 'Outdoor Sconce 3' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.outside_pool_lights: + friendly_name: 'Outside Pool Lights' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + + + + +light.p1_back_left: + friendly_name: 'P1 Back Left' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.p1_back_right: + friendly_name: 'P1 Back Right' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.p1_front_left: + friendly_name: 'P1 Front Left' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.p1_front_right: + friendly_name: 'P1 Front Right' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.paige_go: + friendly_name: 'Paige Go' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.s1: + friendly_name: 'S1' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.s2: + friendly_name: 'S2' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.s3: + friendly_name: 'S3' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.s4: + friendly_name: 'S4' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.sink: + friendly_name: 'Sink' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.tv_light: + friendly_name: 'Tv Light' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.tv_stand_light: + friendly_name: 'Tv Stand Light' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +light.upstairs_lamp: + friendly_name: 'Upstairs Lamp' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True diff --git a/customize/scenes.yaml b/customize/scenes.yaml new file mode 100755 index 00000000..8073c10d --- /dev/null +++ b/customize/scenes.yaml @@ -0,0 +1,79 @@ +scene.all_off: + friendly_name: 'All Off' + emulated_hue_hidden: True + hidden: False + + + + +scene.front_full_brightness: + friendly_name: 'Front Full Brightness' + emulated_hue_hidden: False + hidden: False + +scene.month_fathers_day_colors: + friendly_name: 'Fathers Day Colors' + emulated_hue_hidden: True + hidden: True + + +scene.month_cinco_de_mayo_colors: + friendly_name: 'Month Cinco De Mayo Colors' + emulated_hue_hidden: True + hidden: True + + + + +scene.month_easter_colors: + friendly_name: 'Month Easter Colors' + emulated_hue_hidden: True + hidden: True + + + + +scene.month_marti_gras_colors: + friendly_name: 'Month Marti Gras Colors' + emulated_hue_hidden: True + hidden: True + + + + +scene.month_rwb_colors: + friendly_name: 'Month Rwb Colors' + emulated_hue_hidden: True + hidden: True + + + + +scene.month_st_patty_colors: + friendly_name: 'Month St Patty Colors' + emulated_hue_hidden: True + hidden: True + + + + +scene.month_standard_colors: + friendly_name: 'Month Standard Colors' + emulated_hue_hidden: True + hidden: True + + + + +scene.month_valentine_colors: + friendly_name: 'Month Valentine Colors' + emulated_hue_hidden: True + hidden: True + + + + +scene.tv_time: + friendly_name: 'Tv Time' + emulated_hue_hidden: True + hidden: False diff --git a/customize/scripts.yaml b/customize/scripts.yaml new file mode 100755 index 00000000..233b7c78 --- /dev/null +++ b/customize/scripts.yaml @@ -0,0 +1,89 @@ +################################### +## Scripts Section +################################### + +script.amp_settings: + friendly_name: 'AMP Settings' + emulated_hue_hidden: True + hidden: True + +script.dog_bark: + friendly_name: 'Dog Bark' + emulated_hue_hidden: True + hidden: True + +script.flash_notify: + friendly_name: 'Flash Notify' + emulated_hue_hidden: True + hidden: True + +script.emergency: + friendly_name: 'Emergency' + emulated_hue_hidden: True + hidden: True + + +script.front_house_motion: + friendly_name: 'Front House Motion' + emulated_hue_hidden: True + hidden: True + + + + +script.notify_engine: + friendly_name: 'Ifttt Notify' + emulated_hue_hidden: True + hidden: True + + + + +script.interior_off: + friendly_name: 'Interior Off' + emulated_hue_hidden: True + hidden: False + + + + +script.monthly_color_scene: + friendly_name: 'Monthly Front House Scene' + emulated_hue_hidden: True + hidden: False + + + + +script.skybell_pressed: + friendly_name: 'Skybell Pressed' + emulated_hue_hidden: True + hidden: True + + + + +script.switch_turn_off_all: + friendly_name: 'Switch Turn Off All' + emulated_hue_hidden: True + hidden: False + +script.speechcon: + friendly_name: 'Speechcon' + emulated_hue_hidden: True + hidden: True + +script.speech_processing: + friendly_name: 'Voice Processing' + emulated_hue_hidden: True + hidden: True + +script.speech_engine: + friendly_name: 'Voice Notify' + emulated_hue_hidden: True + hidden: True + +script.tweet_engine: + friendly_name: 'Tweet Notify' + emulated_hue_hidden: True + hidden: True diff --git a/customize/sensors.yaml b/customize/sensors.yaml new file mode 100755 index 00000000..97a42d8f --- /dev/null +++ b/customize/sensors.yaml @@ -0,0 +1,1013 @@ +sensor.bedroom_alarm_panel: + friendly_name: 'Bedroom Alarm Panel' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +sensor.entry_alarm_panel: + friendly_name: 'Entry Alarm Panel' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +sensor.alexa_echo: + friendly_name: 'Alexa Echo' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:amazon + + + +sensor.amazon_dot: + friendly_name: 'Amazon Dot' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:amazon + + + +sensor.amazon_fire_stick: + friendly_name: 'Fire Stick' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:fire + + + +sensor.carlo_6s_battery_level: + friendly_name: 'Carlo 6s+ Battery Level' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:battery-40 + + + +sensor.carlo_6s_battery_state: + friendly_name: 'Carlo 6s+ Battery State' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:power-plug-off + + + +sensor.carlopihole: + friendly_name: 'Pi Hole Server' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:filter-variant + + + +sensor.chromecast_audio_1: + friendly_name: 'Chromecast Audio 1' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:music-circle + + + +sensor.chromecast_audio_2: + friendly_name: 'Chromecast Audio 2' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:music-circle + + + +sensor.circle: + friendly_name: 'Disney Circle' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:google-circles-group + + + +sensor.study_ap: + friendly_name: 'Cisco Main Ap' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:router-wireless + + + +sensor.dark_sky_cloud_coverage: + friendly_name: 'Dark Sky Cloud Coverage' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:weather-partlycloudy + + + +sensor.dark_sky_daily_max_precip_intensity: + friendly_name: 'Dark Sky Daily Max Precip Intensity' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:thermometer + + + +sensor.dark_sky_humidity: + friendly_name: 'Outdoor Humidity' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:water-percent + + + +sensor.dark_sky_minutely_summary: + friendly_name: 'Current Conditions' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: mdi:beach + + + +sensor.dark_sky_precip_intensity: + friendly_name: 'Rainfall' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:weather-rainy + + + +sensor.dark_sky_temperature: + friendly_name: 'Outdoor Temp' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:thermometer + + + +sensor.dark_sky_wind_speed: + friendly_name: 'Dark Sky Wind Speed' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:weather-windy + + + +sensor.date: + friendly_name: 'Date' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: mdi:calendar + + + +sensor.disk_used_: + friendly_name: 'Disk Usage' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:harddisk + + + +sensor.downstairs_away_mode: + friendly_name: 'Downstairs Away Mode' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.downstairs_thermostat_humidity: + friendly_name: 'Downstairs Thermostat Humidity' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:water-percent + + + +sensor.downstairs_thermostat_hvac_state: + friendly_name: 'Downstairs Thermostat Hvac State' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.downstairs_thermostat_operation_mode: + friendly_name: 'Downstairs Thermostat Operation Mode' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.downstairs_thermostat_target: + friendly_name: 'Downstairs Thermostat Target' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.downstairs_thermostat_temperature: + friendly_name: 'Downstairs Thermostat Temperature' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.external_ip: + friendly_name: 'External Ip' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.floorplan_date: + friendly_name: 'Date' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.floorplan_time: + friendly_name: 'Time' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.ha_installed_version: + friendly_name: 'Ha Installed Version' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +sensor.ha_uptime: + friendly_name: 'Ha Uptime' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +sensor.hallway_nest_protect_kids_hallway_battery_health: + friendly_name: 'Hallway Nest Protect Kids Hallway Battery Health' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.hallway_nest_protect_kids_hallway_co_status: + friendly_name: 'Hallway Nest Protect Kids Hallway Co Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.hallway_nest_protect_kids_hallway_smoke_status: + friendly_name: 'Hallway Nest Protect Kids Hallway Smoke Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.hue_hub_1: + friendly_name: 'Hue Hub 1' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:router-wireless + + + +sensor.hue_hub_2: + friendly_name: 'Hue Hub 2' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:router-wireless + + + +sensor.ipchange: + friendly_name: 'Ipchange' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.justins_room_nest_protect_battery_health: + friendly_name: 'Justins Room Nest Protect Battery Health' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.justins_room_nest_protect_co_status: + friendly_name: 'Justins Room Nest Protect Co Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.justins_room_nest_protect_smoke_status: + friendly_name: 'Justins Room Nest Protect Smoke Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.kitchen_nest_protect_battery_health: + friendly_name: 'Kitchen Nest Protect Battery Health' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.kitchen_nest_protect_co_status: + friendly_name: 'Kitchen Nest Protect Co Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.kitchen_nest_protect_smoke_status: + friendly_name: 'Kitchen Nest Protect Smoke Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.large_garage: + friendly_name: 'Large Garage' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:car-connected + + + +sensor.large_garage_reflection_rate: + friendly_name: 'Reflection Rate' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +sensor.large_garage_status: + friendly_name: 'State Of The Door' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +sensor.large_garage_time_in_state: + friendly_name: 'Time In State' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:timer-sand + + + +sensor.large_garage_wifi_signal_strength: + friendly_name: 'Wifi Strength' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:wifi + + + +sensor.last_message: + friendly_name: 'Last Message' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +sensor.master_bedroom_nest_protect_battery_health: + friendly_name: 'Master Bedroom Nest Protect Battery Health' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.master_bedroom_nest_protect_co_status: + friendly_name: 'Master Bedroom Nest Protect Co Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.master_bedroom_nest_protect_smoke_status: + friendly_name: 'Master Bedroom Nest Protect Smoke Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.master_hallway_nest_protect_battery_health: + friendly_name: 'Master Hallway Nest Protect Battery Health' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.master_hallway_nest_protect_co_status: + friendly_name: 'Master Hallway Nest Protect Co Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.master_hallway_nest_protect_smoke_status: + friendly_name: 'Master Hallway Nest Protect Smoke Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.medicine_time: + friendly_name: 'Medicine Time' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +sensor.moon: + friendly_name: 'Moon' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:brightness-3 + + + +sensor.nest_downstairs: + friendly_name: 'Downstairs Nest' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: mdi:air-conditioner + + + +sensor.nest_upstairs: + friendly_name: 'Upstairs Nest' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: mdi:air-conditioner + + + +sensor.nodemcu1: + friendly_name: 'Nodemcu1' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:alarm-bell + + + +sensor.nodemcu2: + friendly_name: 'Nodemcu2' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:alarm-bell + + + +sensor.nodemcu3: + friendly_name: 'Nodemcu3' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:alarm-bell + + + +sensor.office_nest_protect_battery_health: + friendly_name: 'Office Nest Protect Battery Health' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.office_nest_protect_co_status: + friendly_name: 'Office Nest Protect Co Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.office_nest_protect_smoke_status: + friendly_name: 'Office Nest Protect Smoke Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.paiges_room_nest_protect_paiges_room_battery_health: + friendly_name: 'Paiges Room Nest Protect Battery Health' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.paiges_room_nest_protect_paiges_room_co_status: + friendly_name: 'Paiges Room Nest Protect Co Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.paiges_room_nest_protect_paiges_room_smoke_status: + friendly_name: 'Paiges Room Nest Protect Smoke Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.pihole_ads_blocked_today: + friendly_name: 'Ads Blocked Today' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:do-not-disturb + + + +sensor.pihole_ads_percentage_blocked_today: + friendly_name: 'Pi-Hole Ads Percentage Blocked Today' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:close-octagon-outline + + + +sensor.pihole_dns_queries_today: + friendly_name: 'Dns Queries Today' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:note-text + + + +sensor.pihole_dns_unique_clients: + friendly_name: 'Pi-Hole Dns Unique Clients' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:account-outline + + + +sensor.printer: + friendly_name: 'Printer' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:printer + + + +sensor.process_homebridge: + friendly_name: 'Apple Homekit' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:memory + + + +sensor.process_mosquitto: + friendly_name: 'Mosquitto' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:memory + + + +sensor.process_node: + friendly_name: 'Dash Button Monitor' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + icon: mdi:memory + + + +sensor.rachio: + friendly_name: 'Rachio Sprinklers' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:spray + + + +sensor.rachio_watering_time: + friendly_name: 'Rachio Watering Time' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +sensor.rgb_led_garage_large: + friendly_name: 'Rgb Led Garage Large' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:led-on + + + +sensor.rgb_led_garage_small: + friendly_name: 'Rgb Led Garage Small' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:led-on + + + +sensor.rgb_led_outdoor_den: + friendly_name: 'Rgb Led Outdoor Den' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:led-on + + + +sensor.samsungtv: + friendly_name: 'Samsung Tv' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:television + + + +sensor.since_last_boot: + friendly_name: 'Since Last Boot' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: mdi:clock + + + +sensor.since_last_boot_templated: + friendly_name: 'Raspberry Pi Uptime' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:clock-start + + +sensor.sleep_number_bed: + friendly_name: 'Sleep Number Bed' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:hotel + + + +sensor.sleepnumber_carlo_carlo_sleepnumber: + friendly_name: 'Carlo Sleepnumber' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:hotel + + + +sensor.sleepnumber_carlo_stacey_sleepnumber: + friendly_name: 'Stacey Sleepnumber' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:hotel + + + +sensor.small_garage: + friendly_name: 'Small Garage' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:car-connected + + + +sensor.small_garage_reflection_rate: + friendly_name: 'Reflection Rate' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +sensor.small_garage_status: + friendly_name: 'State Of The Door' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + + + + +sensor.small_garage_time_in_state: + friendly_name: 'Time In State' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:timer-sand + + + +sensor.small_garage_wifi_signal_strength: + friendly_name: 'Wifi Strength' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:wifi + + + +sensor.smart_water_meter: + friendly_name: 'Smart Water Meter' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:water + + + +sensor.speedtest_download: + friendly_name: 'Download' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:speedometer + + + +sensor.speedtest_upload: + friendly_name: 'Upload' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:speedometer + + + +sensor.tablotv: + friendly_name: 'Tablo Tv' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:television-guide + + + +sensor.time: + friendly_name: 'Time' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + icon: mdi:clock + + + +sensor.unifi_ap: + friendly_name: 'Unifi Ap' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:router-wireless + + + +sensor.upstairs_away_mode: + friendly_name: 'Upstairs Away Mode' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.upstairs_bedroom_nest_protect_battery_health: + friendly_name: 'Upstairs Bedroom Nest Protect Battery Health' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.upstairs_bedroom_nest_protect_co_status: + friendly_name: 'Upstairs Bedroom Nest Protect Co Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.upstairs_bedroom_nest_protect_smoke_status: + friendly_name: 'Upstairs Bedroom Nest Protect Smoke Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.upstairs_living_room_nest_protect_battery_health: + friendly_name: 'Upstairs Living Room Nest Protect Battery Health' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.upstairs_living_room_nest_protect_co_status: + friendly_name: 'Upstairs Living Room Nest Protect Co Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.upstairs_living_room_nest_protect_smoke_status: + friendly_name: 'Upstairs Living Room Nest Protect Smoke Status' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.upstairs_thermostat_humidity: + friendly_name: 'Upstairs Thermostat Humidity' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:water-percent + + + +sensor.upstairs_thermostat_hvac_state: + friendly_name: 'Upstairs Thermostat Hvac State' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.upstairs_thermostat_operation_mode: + friendly_name: 'Upstairs Thermostat Operation Mode' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.upstairs_thermostat_target: + friendly_name: 'Upstairs Thermostat Target' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.upstairs_thermostat_temperature: + friendly_name: 'Upstairs Thermostat Temperature' + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + + + + +sensor.wii: + friendly_name: 'Wii' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:gamepad-variant + + + +sensor.withings_scale: + friendly_name: 'Withings Scale' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + icon: mdi:scale-bathroom diff --git a/customize/switches.yaml b/customize/switches.yaml new file mode 100755 index 00000000..1d05c969 --- /dev/null +++ b/customize/switches.yaml @@ -0,0 +1,117 @@ +################################### +## Switches Section +################################### +switch.den_outlet: + friendly_name: 'Den Outlet' + emulated_hue_hidden: False + hidden: False + icon: mdi:power-plug + assumed_state: true + + +switch.foyer_outlet: + friendly_name: 'Foyer Outlet' + emulated_hue_hidden: False + hidden: False + icon: mdi:power-plug + assumed_state: true + + +switch.front_door_outlet: + friendly_name: 'Front Door Outlet' + emulated_hue_hidden: False + hidden: False + icon: mdi:power-plug + assumed_state: true + +switch.garage_outlet: + friendly_name: 'Garage Outlet' + emulated_hue_hidden: False + hidden: False + icon: mdi:power-plug + assumed_state: true + +switch.landscaping: + friendly_name: 'Landscaping Lights' + emulated_hue_hidden: False + hidden: True + homebridge_hidden: True + +switch.back_landscaping: + friendly_name: 'Back Landscaping' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: false + icon: mdi:flower + + +switch.front_landscaping: + friendly_name: 'Front Landscaping' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: False + icon: mdi:flower + +switch.pool_deck: + friendly_name: 'Pool Deck' + emulated_hue_hidden: False + hidden: False + homebridge_hidden: False + +switch.kitchen_accent_2: + friendly_name: 'Kitchen Accents 2' + emulated_hue_hidden: True + hidden: False + icon: mdi:lightbulb-outline + assumed_state: true + + +switch.kitchen_accents: + friendly_name: 'Kitchen Accents' + emulated_hue_hidden: False + hidden: False + icon: mdi:lightbulb-outline + assumed_state: true + + +switch.living_room_amp: + friendly_name: 'Living Room Amp' + emulated_hue_hidden: False + hidden: False + icon: mdi:music-circle + +switch.living_room_outlet: + friendly_name: 'Living Room Outlet' + emulated_hue_hidden: False + hidden: False + icon: mdi:power-plug + assumed_state: true + + +switch.master_bathroom_accents: + friendly_name: 'Master Bathroom Accents' + emulated_hue_hidden: False + hidden: False + icon: mdi:lightbulb-outline + assumed_state: true + + +switch.outlet_304_2: + friendly_name: 'Outlet 304 2' + emulated_hue_hidden: True + hidden: False + icon: mdi:power-plug + assumed_state: true + +switch.printer_outlet: + friendly_name: 'Printer Outlet' + emulated_hue_hidden: False + hidden: False + icon: mdi:printer + assumed_state: true + +switch.pihole_temp_disable: + friendly_name: 'Pihole Temp Disable' + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true diff --git a/customize/weather.yaml b/customize/weather.yaml new file mode 100755 index 00000000..9f288c14 --- /dev/null +++ b/customize/weather.yaml @@ -0,0 +1,18 @@ + +################################### +## Nest Section +################################### +climate.downstairs: + friendly_name: 'Nest Downstairs' + icon: mdi:air-conditioner +climate.upstairs: + friendly_name: 'Nest Upstairs' + icon: mdi:air-conditioner + + +################################### +## Sun Section +################################### +sun.sun: + hidden: true + \ No newline at end of file diff --git a/dasher/dasher b/dasher/dasher new file mode 100755 index 00000000..5f28fb2f --- /dev/null +++ b/dasher/dasher @@ -0,0 +1,98 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start daemon at boot time +# Description: Enable service provided by daemon. +### END INIT INFO + +dir="/home/pi/dasher" +cmd="DEBUG=* node app.js" +user="root" + +name=`basename $0` +pid_file="/var/run/$name.pid" +stdout_log="/var/log/$name.log" +stderr_log="/var/log/$name.err" + +get_pid() { + cat "$pid_file" +} + +is_running() { + [ -f "$pid_file" ] && ps `get_pid` > /dev/null 2>&1 +} + +case "$1" in + start) + if is_running; then + echo "Already started" + else + echo "Starting $name" + cd "$dir" + if [ -z "$user" ]; then + sudo $cmd >> "$stdout_log" 2>> "$stderr_log" & + else + sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" & + fi + echo $! > "$pid_file" + if ! is_running; then + echo "Unable to start, see $stdout_log and $stderr_log" + exit 1 + fi + fi + ;; + stop) + if is_running; then + echo -n "Stopping $name.." + kill `get_pid` + for i in {1..10} + do + if ! is_running; then + break + fi + + echo -n "." + sleep 1 + done + echo + + if is_running; then + echo "Not stopped; may still be shutting down or shutdown may have failed" + exit 1 + else + echo "Stopped" + if [ -f "$pid_file" ]; then + rm "$pid_file" + fi + fi + else + echo "Not running" + fi + ;; + restart) + $0 stop + if is_running; then + echo "Unable to stop, will not attempt to start" + exit 1 + fi + $0 start + ;; + status) + if is_running; then + echo "Running" + else + echo "Stopped" + exit 1 + fi + ;; + *) + echo "Usage: $0 {start|stop|restart|status}" + exit 1 + ;; +esac + +exit 0 diff --git a/device_tracker/README.md b/device_tracker/README.md new file mode 100755 index 00000000..9f58e501 --- /dev/null +++ b/device_tracker/README.md @@ -0,0 +1,15 @@ +# [![Build Status](https://travis-ci.org/CCOSTAN/Home-AssistantConfig.svg?branch=master)](https://travis-ci.org/CCOSTAN/Home-AssistantConfig) Home-Assistant Config by [@ccostan](http://www.twitter.com/ccostan) +[Home Assistant](https://home-assistant.io/) configuration files (YAMLs) + +Be sure to :star: my repo so you can keep up to date on the daily progress! + +For presence detection, I basically just use NMAP. I've used it from the beginning and it's been rock solid ever since. No issues at all and if it ain't broken, why fix it? + +#Still have questions on my Config? +Follow me on twitter : [@CCostan](https://twitter.com/ccostan) + +You can also vist my [Blog](http://www.vmwareinfo.com/search/label/iot) for all of my [Home Automation Posts](http://www.vmwareinfo.com/search/label/iot). + + + Sponsor + diff --git a/device_tracker/nmap.yaml b/device_tracker/nmap.yaml new file mode 100755 index 00000000..a8b8780b --- /dev/null +++ b/device_tracker/nmap.yaml @@ -0,0 +1,7 @@ +- platform: nmap_tracker + hosts: 192.168.10.1/24 + track_new_devices: no + exclude: + - 192.168.10.10 +# scan_options: " --privileged -sP " +# consider_home: 1800 - Added to known_devices.yaml instead on a device by device basis. diff --git a/device_tracker/ping.yaml.disabled b/device_tracker/ping.yaml.disabled new file mode 100755 index 00000000..09b3a7eb --- /dev/null +++ b/device_tracker/ping.yaml.disabled @@ -0,0 +1,5 @@ +- platform: ping + hosts: + chromecast_2: 192.168.1.231 + camera_driveway: 192.168.1.15 + access_point: 192.168.1.59 diff --git a/device_tracker/unifi.yaml.disabled b/device_tracker/unifi.yaml.disabled new file mode 100755 index 00000000..35c7de67 --- /dev/null +++ b/device_tracker/unifi.yaml.disabled @@ -0,0 +1,6 @@ +- platform: unifi + username: !secret unifi_username + password: !secret unifi_password + host: !secret unifi_host + verify_ssl: false + track_new_devices: no diff --git a/emulated_hue_ids.json b/emulated_hue_ids.json new file mode 100755 index 00000000..aad65acb --- /dev/null +++ b/emulated_hue_ids.json @@ -0,0 +1 @@ +{"52": "light.led_garage_small", "54": "light.led_outdoor_den", "31": "group.outdoor_lights", "49": "input_boolean.guard_dog", "13": "group.kitchen_lights", "17": "input_boolean.guest_mode", "60": "input_boolean.sleepy_dog", "29": "group.amps", "37": "input_boolean.alert_mode", "65": "switch.computer_screens", "20": "switch.garage_outlet", "24": "group.outdoor_pool_lights", "67": "group.fire_tablet", "41": "input_boolean.home_stats", "38": "scene.front_full_brightness", "5": "switch.living_room_amp", "12": "group.all_lights", "39": "input_boolean.last_message", "21": "group.bedroom_lights", "33": "group.office_lights", "50": "input_boolean.flash", "9": "switch.living_room_outlet", "61": "switch.front_landscaping", "40": "input_boolean.responsibilities", "62": "switch.back_landscaping", "18": "group.den_lights", "42": "input_boolean.meal_time", "70": "switch.pool_deck", "58": "input_boolean.radio", "63": "group.landscaping", "10": "group.garage_lights", "14": "switch.den_outlet", "64": "input_boolean.lastmsg", "26": "scene.living_room_tv_time", "71": "light.led_garage_snip", "53": "input_boolean.color_tornado", "8": "switch.printer_outlet", "48": "switch.ge_outdoor_outle_switch_8_0", "46": "light.garage_large", "16": "switch.kitchen_accent_2", "69": "switch.landscaping", "1": "switch.front_door_outlet", "28": "switch.foyer_outlet", "66": "input_boolean.self_destruct", "45": "input_boolean.work", "30": "switch.outlet_304_4", "19": "group.all_switches", "51": "light.led_garage_large", "34": "group.exterior_lights", "11": "group.foyer_lights", "57": "input_boolean.garage_check", "2": "group.outdoor_front_lights", "59": "input_boolean.house_station", "7": "group.living_room_accents", "43": "input_boolean.tv_time", "15": "group.hallway_lights", "47": "switch.ge_outdoor_outle_switch_7_0", "56": "input_boolean.medicine", "22": "light.outdoor_den", "4": "group.dinette_lights", "55": "input_boolean.outside_weather", "3": "switch.kitchen_accents", "68": "switch.master_bathroom_accents", "44": "input_boolean.good_morning", "35": "input_boolean.school_mode", "23": "light.garage_left", "6": "group.dining_room_lights", "25": "group.interior_lights", "27": "group.upstairs_lights", "32": "group.living_room_lights", "36": "input_boolean.speech_notifications", "72": "input_boolean.clock_snooze"} \ No newline at end of file diff --git a/group/Indoor_Outdoor.yaml b/group/Indoor_Outdoor.yaml new file mode 100755 index 00000000..84ec73b9 --- /dev/null +++ b/group/Indoor_Outdoor.yaml @@ -0,0 +1,25 @@ +Interior_Lights: + entities: + - group.bedroom_lights + - group.living_room_lights + - group.living_room_accents + - group.dinette_lights + - group.dining_room_lights + - group.den_lights + - group.foyer_lights + - group.office_lights + - group.hallway_lights + - group.kitchen_lights + - group.upstairs_lights + - group.outdoor_pool_lights + - group.garage_lights + - group.paiges_room + - group.justins_room + +Exterior_Lights: + entities: + - light.outdoor_bathroom + - light.outside_pool_lights + - group.outdoor_pool_lights + - group.outdoor_front_lights + - group.landscaping diff --git a/group/MQTT.yaml b/group/MQTT.yaml new file mode 100755 index 00000000..54f085e7 --- /dev/null +++ b/group/MQTT.yaml @@ -0,0 +1,5 @@ +MQTT: + entities: + - sensor.rachio_watering_time + - sensor.medicine_time + - sensor.last_message diff --git a/group/amps.yaml b/group/amps.yaml new file mode 100755 index 00000000..16dcbc75 --- /dev/null +++ b/group/amps.yaml @@ -0,0 +1,4 @@ +AMPs: + entities: + - switch.living_room_amp +# - switch.bathroom_amp \ No newline at end of file diff --git a/group/doors.yaml b/group/doors.yaml new file mode 100755 index 00000000..18128d61 --- /dev/null +++ b/group/doors.yaml @@ -0,0 +1,8 @@ +doors: + name: Doors + entities: + - binary_sensor.hallway_linen_opened + - binary_sensor.hallway_pantry_opened + - binary_sensor.kitchen_door_opened + - binary_sensor.MCU2_GPIO12 # Main Slider + - binary_sensor.MCU3_Light # Alarm Door diff --git a/group/garage.yaml b/group/garage.yaml new file mode 100755 index 00000000..f96bacba --- /dev/null +++ b/group/garage.yaml @@ -0,0 +1,13 @@ +garage_doors: + name: Garage doors + entities: + - cover.large_garage + - sensor.large_garage_status + - sensor.large_garage_time_in_state + - sensor.large_garage_wifi_signal_strength + - sensor.large_garage_reflection_rate + - cover.small_garage + - sensor.small_garage_status + - sensor.small_garage_time_in_state + - sensor.small_garage_wifi_signal_strength + - sensor.small_garage_reflection_rate \ No newline at end of file diff --git a/group/home_mode.yaml b/group/home_mode.yaml new file mode 100755 index 00000000..191862cb --- /dev/null +++ b/group/home_mode.yaml @@ -0,0 +1,8 @@ +home_modes: + control: hidden + entities: + - input_boolean.guest_mode + - input_boolean.school_mode + - input_boolean.alert_mode + - input_boolean.speech_notifications + - input_boolean.last_message diff --git a/group/lights.yaml b/group/lights.yaml new file mode 100755 index 00000000..9e4fe8b1 --- /dev/null +++ b/group/lights.yaml @@ -0,0 +1,97 @@ +Bedroom lights: + entities: + - light.bedroom + +kitchen lights: + entities: + - light.k1 + - light.k2 + - light.k3 + - light.k4 + - light.k5 + - light.k6 + - light.sink + - light.fridge + +Living Room lights: + entities: + - light.m1_back_left + - light.m1_back_right + - light.m1_front_left + - light.m1_front_right + - light.m1_slider + +Living Room Accents: + entities: + - light.couch_1 + - light.tv_light + - light.tv_stand_light + +Dinette lights: + entities: + - light.d1 + - light.d2 + +Den lights: + entities: + - light.den_lamp + +Foyer lights: + entities: + - light.f1 + - light.f2 + +Office lights: + entities: + - light.office_lamp + +Upstairs lights: + entities: + - light.upstairs_lamp + - light.upstairs_hallway + +Dining Room lights: + entities: + - light.s1 + - light.s2 + - light.s3 + - light.s4 + +Outdoor Pool Lights: + entities: + - light.p1_front_left + - light.p1_front_right + - light.p1_back_left + - light.p1_back_right + +Outdoor Front Lights: + entities: + - light.outdoor_foyer + - light.outdoor_sconce_1 + - light.outdoor_sconce_2 + - light.outdoor_sconce_3 + - light.led_garage_large + - light.led_garage_snip + - light.led_garage_small + - light.led_outdoor_den + - light.stone_door + +Garage lights: + control: hidden + entities: + - light.garage_attic + - switch.garage_outlet + +Hallway Lights: + entities: + - light.kids_hallway + - light.bedroom_hallway + - light.upstairs_hallway + +Justins Room: + entities: + - light.justin_go + +Paiges Room: + entities: + - light.paige_go diff --git a/group/media_players.yaml b/group/media_players.yaml new file mode 100755 index 00000000..506f3872 --- /dev/null +++ b/group/media_players.yaml @@ -0,0 +1,9 @@ +media_players: + entities: + - media_player.livingroomcc + - media_player.whole_house + - media_player.living_room_tv + - media_player.living_room_ultra + - media_player.upstairs_living_room + - media_player.alarm_clock + - media_player.bedroom_alarm_panel diff --git a/group/motion.yaml b/group/motion.yaml new file mode 100755 index 00000000..aa3b0c8d --- /dev/null +++ b/group/motion.yaml @@ -0,0 +1,6 @@ +motion: + name: Motion Detectors + entities: + - binary_sensor.office_motion + - binary_sensor.entry_alarm_panel + - binary_sensor.bedroom_alarm_panel diff --git a/group/people.yaml b/group/people.yaml new file mode 100755 index 00000000..dab333eb --- /dev/null +++ b/group/people.yaml @@ -0,0 +1,7 @@ +Family: + entities: + - device_tracker.carlo + - device_tracker.stacey + - device_tracker.franco + - device_tracker.yolanda + - device_tracker.joyce_ipad \ No newline at end of file diff --git a/group/sensors.yaml b/group/sensors.yaml new file mode 100755 index 00000000..1b11c263 --- /dev/null +++ b/group/sensors.yaml @@ -0,0 +1,3 @@ +Sensors: + entities: + - binary_sensor.aeotec_dsb04100_doorwindow_sensor_sensor_3_0 diff --git a/group/switches.yaml b/group/switches.yaml new file mode 100755 index 00000000..103000d5 --- /dev/null +++ b/group/switches.yaml @@ -0,0 +1,16 @@ +Interior Switches: + entities: + - switch.den_outlet + - switch.living_room_outlet + - switch.foyer_outlet + - switch.kitchen_Accents + - switch.kitchen_accent_2 + - switch.printer_outlet + - switch.front_door_outlet + - switch.garage_outlet + - switch.living_room_amp + - switch.master_bathroom_accents + - switch.master_bathroom_accents_2 + - switch.pool_deck + - switch.1412_2_Outlet + - switch.1412_3_Outlet diff --git a/group/triggers.yaml b/group/triggers.yaml new file mode 100755 index 00000000..34f7936a --- /dev/null +++ b/group/triggers.yaml @@ -0,0 +1,14 @@ +Triggers: + control: hidden + entities: + - input_boolean.house_station + - input_boolean.responsibilities + - input_boolean.home_stats + - input_boolean.flash + - input_boolean.guard_dog + - input_boolean.sleepy_dog + - input_boolean.good_morning + - input_boolean.good_night + - input_boolean.meal_time + - input_boolean.tv_time + - input_boolean.work diff --git a/group/views.yaml.old b/group/views.yaml.old new file mode 100755 index 00000000..52f28b66 --- /dev/null +++ b/group/views.yaml.old @@ -0,0 +1,74 @@ +Bear Stone View: + name: Bear Stone Run + view: yes + icon: mdi:home + entities: + - persistent_notification.update_available + - group.home_modes + - group.family + - group.weather + - group.amps + - group.Bedroom_lights + - group.Kitchen_lights + - group.Dinette_lights + - group.living_room_lights + - group.living_room_accents + - group.dining_room_lights + - group.foyer_lights + - group.upstairs_lights + - group.den_lights + - group.hallway + - group.office_lights + - group.garage_lights + - group.outdoor_pool_lights + - group.outdoor_lights + - group.all_switches + - group.media_players + +Doors: + view: yes + icon: mdi:security-home + entities: + - group.family + - group.garage_doors + + +Lights: + view: yes + icon: mdi:lightbulb + entities: + - group.home_modes + - group.amps + - group.interior_lights + - group.outdoor_lights + - group.Bedroom_lights + - group.Kitchen_lights + - group.Dinette_lights + - group.living_room_lights + - group.living_room_accents + - group.dining_room_lights + - group.foyer_lights + - group.upstairs_lights + - group.den_lights + - group.office_lights + - group.garage_lights + - group.outdoor_pool_lights + - group.outdoor_front_lights + - group.all_switches + +Info: + view: yes + icon: mdi:settings + entities: + - group.family + - group.home_modes + - group.network + - group.sensors + - group.garage_doors + - sun.sun + - group.media_players + - group.weather + - group.all_lights + - group.all_switches + - group.all_automations + - group.all_scripts diff --git a/group/weather.yaml b/group/weather.yaml new file mode 100755 index 00000000..1fe15113 --- /dev/null +++ b/group/weather.yaml @@ -0,0 +1,19 @@ +Weather: + entities: + - climate.downstairs + - sensor.downstairs_thermostat_humidity + - climate.upstairs + - sensor.upstairs_thermostat_humidity + - sensor.dark_sky_cloud_coverage + - sensor.dark_sky_minutely_summary +# - sensor.dark_sky_nearest_storm_distance + - sensor.dark_sky_precip_intensity + - sensor.dark_sky_daily_max_precip_intensity + - sensor.dark_sky_wind_speed + - sensor.dark_sky_humidity + - sensor.dark_sky_temperature + - sensor.dark_sky_uv_index + - sensor.moon + - binary_sensor.iss + - sensor.launch_window + - camera.wu_doppler_weather diff --git a/input_boolean/hidden_booleans.yaml b/input_boolean/hidden_booleans.yaml new file mode 100755 index 00000000..2532f064 --- /dev/null +++ b/input_boolean/hidden_booleans.yaml @@ -0,0 +1,7 @@ +home_stats: + name: Home Stats + initial: off + +responsibilities: + name: responsibilities + initial: off diff --git a/input_boolean/home_modes.yaml b/input_boolean/home_modes.yaml new file mode 100755 index 00000000..987792f8 --- /dev/null +++ b/input_boolean/home_modes.yaml @@ -0,0 +1,19 @@ +guest_mode: + name: Guest Mode + icon: mdi:account-alert + initial: off + +school_mode: + name: School Mode + icon: mdi:school + initial: on + +alert_mode: + name: Alert Mode + icon: mdi:alert-octagram + initial: off + +speech_notifications: + name: Speech Notifications + icon: mdi:speaker-wireless + initial: on diff --git a/input_boolean/trigger_booleans.yaml b/input_boolean/trigger_booleans.yaml new file mode 100755 index 00000000..70e75612 --- /dev/null +++ b/input_boolean/trigger_booleans.yaml @@ -0,0 +1,32 @@ +#triggers +good_night: + name: Good Night + initial: off + +good_morning: + name: Good Morning + initial: off + +meal_time: + name: Meal Time + initial: off + +tv_time: + name: TV Time + initial: off + +work: + name: Work + initial: off + +flash: + name: Flash + initial: off + +color_tornado: + name: Color Tornado! + initial: off + +guard_dog: + name: Guard Dog + initial: off diff --git a/json_data/holidays.json b/json_data/holidays.json new file mode 100755 index 00000000..b20cf4e9 --- /dev/null +++ b/json_data/holidays.json @@ -0,0 +1,85 @@ +{ + "MAJOR_US": { + "static": { + "1/1": "New Year's Day", + "2/2": "Groundhog Day", + "2/3": "Stacey's Birthday", + "2/14": "Valentine's Day", + "3/14": "Pi Day", + "3/17": "St. Patrick's Day", + "3/26": "Justin's Birthday", + "4/22": "Earth Day", + "5/4": "Star Wars Day", + "5/5": "Cinco de Mayo", + "7/4": "Independence Day", + "8/30": "Paige's Birthday", + "9/11": "Patriot Day", + "10/31": "Halloween", + "11/11": "Veterans' Day", + "11/16": "Carlo's Birthday", + "12/7": "Pearl Harbor Day", + "12/24": "Christmas Eve", + "12/25": "Christmas Day", + "12/31": "New Year's Eve" + }, + "dynamic": { + "1/19/2015": "MLK Day", + "1/18/2016": "MLK Day", + "1/16/2017": "MLK Day", + "1/15/2018": "MLK Day", + "1/21/2019": "MLK Day", + "1/20/2020": "MLK Day", + "2/16/2015": "Presidents' Day", + "2/15/2016": "Presidents' Day", + "2/20/2017": "Presidents' Day", + "2/19/2018": "Presidents' Day", + "2/18/2019": "Presidents' Day", + "2/17/2020": "Presidents' Day", + "3/25/2018": "Palm Sunday", + "4/14/2019": "Palm Sunday", + "4/5/2020": "Palm Sunday", + "3/30/2018": "Good Friday", + "4/19/2019": "Good Friday", + "4/10/2020": "Good Friday", + "4/1/2018": "Easter Sunday", + "4/21/2019": "Easter Sunday", + "4/12/2020": "Easter Sunday", + "5/10/2015": "Mother's Day", + "5/8/2016": "Mother's Day", + "5/14/2017": "Mother's Day", + "5/13/2018": "Mother's Day", + "5/12/2019": "Mother's Day", + "5/10/2020": "Mother's Day", + "5/25/2015": "Memorial Day", + "5/30/2016": "Memorial Day", + "5/29/2017": "Memorial Day", + "5/28/2018": "Memorial Day", + "5/27/2019": "Memorial Day", + "5/25/2020": "Memorial Day", + "6/21/2015": "Father's Day", + "6/19/2016": "Father's Day", + "6/18/2017": "Father's Day", + "6/17/2018": "Father's Day", + "6/16/2019": "Father's Day", + "6/21/2020": "Father's Day", + "9/7/2015": "Labor Day", + "9/5/2016": "Labor Day", + "9/4/2017": "Labor Day", + "9/3/2018": "Labor Day", + "9/2/2019": "Labor Day", + "9/7/2020": "Labor Day", + "10/12/2015": "Columbus Day", + "10/10/2016": "Columbus Day", + "10/9/2017": "Columbus Day", + "10/8/2018": "Columbus Day", + "10/14/2019": "Columbus Day", + "10/12/2020": "Columbus Day", + "11/26/2015": "Thanksgiving Day", + "11/24/2016": "Thanksgiving Day", + "11/23/2017": "Thanksgiving Day", + "11/22/2018": "Thanksgiving Day", + "11/28/2019": "Thanksgiving Day", + "11/26/2020": "Thanksgiving Day" + } + } +} diff --git a/json_data/test_launch.json b/json_data/test_launch.json new file mode 100755 index 00000000..c976330d --- /dev/null +++ b/json_data/test_launch.json @@ -0,0 +1,109 @@ +{ + "total": 1, + "launches": [ + { + "id": 1079, + "name": "Minotaur-C (Taurus XL) | 6 x SkySat & 4 x Dove", + "windowstart": "November 1, 2017 21:22:00 UTC", + "windowend": "November 1, 2017 22:22:00 UTC", + "net": "October 31, 2017 21:37:00 UTC", + "wsstamp": 1509589742, + "westamp": 1509488520, + "netstamp": 1509485820, + "isostart": "2017111T152200Z", + "isoend": "20171111T222200Z", + "isonet": "20171031T213700Z", + "status": 3, + "inhold": 0, + "tbdtime": 0, + "vidURLs": [ + "https://www.youtube.com/watch?v=xP_xWX9RqYU", + "https://www.youtube.com/watch?v=eWsxNGD3fPE" + ], + "vidURL": null, + "infoURLs": [], + "infoURL": null, + "holdreason": null, + "failreason": null, + "tbddate": 0, + "probability": 100, + "hashtag": null, + "location": { + "pads": [ + { + "id": 179, + "name": "Space Launch Complex 576E, Vandenberg AFB, CA", + "infoURL": null, + "wikiURL": null, + "mapURL": "http://maps.google.com/maps?q=34.739444+N,+120.619167+W", + "latitude": 34.739444, + "longitude": -120.619167, + "agencies": [ + { + "id": 161, + "name": "United States Air Force", + "abbrev": "USAF", + "countryCode": "USA", + "type": 1, + "infoURL": "http://www.af.mil", + "wikiURL": "http://en.wikipedia.org/wiki/United_States_Air_Force", + "infoURLs": [ + "http://www.af.mil" + ] + } + ] + } + ], + "id": 16, + "name": "Carlo's house, FL, USA", + "infoURL": "", + "wikiURL": "", + "countryCode": "USA" + }, + "rocket": { + "id": 105, + "name": "Minotaur-C", + "configuration": "Minotaur-C", + "familyname": "Pegasus", + "agencies": [ + { + "id": 179, + "name": "Orbital ATK", + "abbrev": "OA", + "countryCode": "USA", + "type": 3, + "infoURL": "https://www.orbitalatk.com/", + "wikiURL": "https://en.wikipedia.org/wiki/Orbital_ATK", + "infoURLs": [ + "https://www.orbitalatk.com/" + ] + } + ], + "wikiURL": "https://en.wikipedia.org/wiki/Minotaur-C", + "infoURLs": [], + "imageSizes": [ + 320 + ], + "imageURL": "Array" + }, + "missions": [ + { + "id": 348, + "name": "Dedicated rideshare", + "description": "Dedicated rideshare", + "type": 14, + "typeName": "Dedicated Rideshare" + }, + { + "id": 605, + "name": "6 x SkySat & 4 x Dove", + "description": "SkySat is a series of commercial Earth observation satellites, which operate in 500 km sun-synchronous orbit. Each satellite weighs about 120 kg and is intended for 6 years of operation.", + "type": 1, + "typeName": "Earth Science" + } + ] + } + ], + "offset": 0, + "count": 1 +} diff --git a/logger.yaml b/logger.yaml new file mode 100755 index 00000000..f3ef4e2a --- /dev/null +++ b/logger.yaml @@ -0,0 +1,31 @@ +############################################################ +# +# Logger You can filter anything betwen the []'s in the logger. +# +############################################################ + +# Log Severities: notset, debug, info, warn, warning, error, fatal, critical + +default: info +logs: + aiohttp.access: critical + aiohttp.server: critical + custom_components.media_player.floorplan_speaker: error + homeassistant.core: error + homeassistant.components.automation: warn + homeassistant.components.binary_sensor: error + homeassistant.components.climate.nest: warn + homeassistant.components.device_tracker: error + homeassistant.components.discovery: warn + homeassistant.components.feedreader: warn + homeassistant.components.http: warn + homeassistant.components.media_player: warn + homeassistant.components.sensor.pi_hole: critical + homeassistant.components.recorder: error + homeassistant.components.sensor.darksky: warn + homeassistant.components.zwave: warn + homeassistant.helpers.script: info + homeassistant.helpers.entity: critical + homeassistant.exceptions: info + py.warnings: error + root: warn diff --git a/packages/README.md b/packages/README.md new file mode 100755 index 00000000..6796b9d3 --- /dev/null +++ b/packages/README.md @@ -0,0 +1,35 @@ +# [![Build Status](https://travis-ci.org/CCOSTAN/Home-AssistantConfig.svg?branch=master)](https://travis-ci.org/CCOSTAN/Home-AssistantConfig) Home-Assistant Config by [@ccostan](http://www.twitter.com/ccostan) +[Home Assistant](https://home-assistant.io/) configuration files (YAMLs) + +Be sure to :star: my repo so you can keep up to date on the daily progress! + +This section is for the packages. (It's being slowly built out) + +**Twitter Account** + -You can see my home in action by following it's Twitter account [@BearStoneHA](https://twitter.com/BearStoneHA) + -Home Assistant live tweets activities in the house on it's own dedicated Social Media Account. + +**Alarm System** +You can find out about how I swapped out my ADT for 3 NodeMCUs [here](http://www.vmwareinfo.com/2017/06/building-my-home-alarm-system-hardware.html). + +**Landscape Lighting** +For the ladnscape lights, I have 2 12v transformers in the backyard. One powers the front landscape lights and the other the backyard landscaping lights. +I have put 2 [GE ZWave Outdoor Power Module](http://amzn.to/2q17R4S) conneted to the transformers and controlled by my [Wink Hub](http://amzn.to/2orGEWo). They are set to turn on landscape lighting at sunset and turn off at random times before sunrise. +![Screenshot of Landscape Lighting](https://i.imgur.com/CFSWGXW.png) + +**Nest Protects** +You can find my [Nest protects](http://amzn.to/2poqKhu) write up [here](http://www.vmwareinfo.com/2017/06/psa-check-out-your-smoke-detectors-once.html). +![Screenshot of Protects](https://i.imgur.com/hUAaIiF.png) + +**Neato Vacuum** +I can control my [Neato Vacuum](http://amzn.to/2kqnnqu) with Home Assistant. +![Screenshot of D7 Vacuum](https://i.imgur.com/jLikEk6.png) + +#Still have questions on my Config? +Follow me on twitter : [@CCostan](https://twitter.com/ccostan) + +You can also vist my [Blog](http://www.vmwareinfo.com/search/label/iot) for all of my [Home Automation Posts](http://www.vmwareinfo.com/search/label/iot). + + + Sponsor + diff --git a/packages/alarm.yaml b/packages/alarm.yaml new file mode 100755 index 00000000..12a2a267 --- /dev/null +++ b/packages/alarm.yaml @@ -0,0 +1,305 @@ +#------------------------------------------- +# ALarm Related Packages +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- +homeassistant: + customize_glob: + "device_tracker.nodemcu*": + icon: mdi:chip + emulated_hue_hidden: True + hidden: True + "sensor.nodemcu*": + icon: mdi:alarm-bell + emulated_hue_hidden: True + hidden: False + "binary_sensor.mcu?_gpio*": + icon: mdi:security-home + emulated_hue_hidden: True + hidden: False + + customize: + binary_sensor.MCU1_GPIO4: + friendly_name: 'Paige Window' + binary_sensor.MCU1_GPIO5: + friendly_name: 'Front Door' + binary_sensor.MCU1_GPIO10: + friendly_name: 'Dining Room Windows' + binary_sensor.MCU1_GPIO12: + friendly_name: 'Interior Garage Door' + binary_sensor.MCU1_GPIO13: + friendly_name: 'Front Den Windows' + binary_sensor.MCU1_GPIO14: + friendly_name: 'Office Window' + + + binary_sensor.MCU2_GPIO4: + friendly_name: 'Dinette Windows' + binary_sensor.MCU2_GPIO5: + friendly_name: 'Back Door' + binary_sensor.MCU2_GPIO9: + friendly_name: 'Master Slider' + binary_sensor.MCU2_GPIO10: + friendly_name: 'Master Bathroom Window' + binary_sensor.MCU2_GPIO12: + friendly_name: 'Main Slider' + binary_sensor.MCU2_GPIO13: + friendly_name: 'Upstairs Bedroom Window' + binary_sensor.MCU2_GPIO14: + friendly_name: 'Justin Window' + + binary_sensor.MCU3_GPIO4: + friendly_name: 'Stacey Bedroom Window' + binary_sensor.MCU3_GPIO5: + friendly_name: 'Carlo Bedroom Window' + binary_sensor.MCU3_GPIO10: + friendly_name: 'Master Bedroom Window' + binary_sensor.MCU3_GPIO14: + friendly_name: 'Upstairs Windows' + binary_sensor.MCU3_Light: + friendly_name: 'Panel Door' + + group.entry_points: + friendly_name: Alarm Entry Points + homebridge_hidden: true + group.interior_door: + friendly_name: Interior doors + homebridge_hidden: true +#------------------------------------------- +binary_sensor: + - platform: mqtt + state_topic: "NodeMCU1/GPIO4/Status" + name: "MCU1_GPIO4" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU1/GPIO5/Status" + name: "MCU1_GPIO5" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU1/GPIO10/Status" + name: "MCU1_GPIO10" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU1/GPIO12/Status" + name: "MCU1_GPIO12" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU1/GPIO13/Status" + name: "MCU1_GPIO13" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU1/GPIO14/Status" + name: "MCU1_GPIO14" + payload_on: 1 + payload_off: 0 + device_class: opening + + - platform: mqtt + state_topic: "NodeMCU2/GPIO4/Status" + name: "MCU2_GPIO4" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU2/GPIO5/Status" + name: "MCU2_GPIO5" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU2/GPIO9/Status" + name: "MCU2_GPIO9" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU2/GPIO10/Status" + name: "MCU2_GPIO10" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU2/GPIO12/Status" + name: "MCU2_GPIO12" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU2/GPIO13/Status" + name: "MCU2_GPIO13" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU2/GPIO14/Status" + name: "MCU2_GPIO14" + payload_on: 1 + payload_off: 0 + device_class: opening + + - platform: mqtt + state_topic: "NodeMCU3/GPIO4/Status" + name: "MCU3_GPIO4" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU3/GPIO5/Status" + name: "MCU3_GPIO5" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU3/GPIO10/Status" + name: "MCU3_GPIO10" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU3/GPIO14/Status" + name: "MCU3_GPIO14" + payload_on: 1 + payload_off: 0 + device_class: opening + - platform: mqtt + state_topic: "NodeMCU3/Light/Status" + name: "MCU3_Light" + payload_on: 1 + payload_off: 0 + device_class: opening + +# input_boolean: +# elephant: +# name: Elephant +# initial: off +#------------------------------------------- +sensor: + - platform: template + sensors: + nodemcu1: + friendly_name: 'NodeMCU1' + value_template: "{{ 'Online' if is_state('device_tracker.NodeMCU1', 'home') else 'Offline' }}" + - platform: template + sensors: + nodemcu2: + friendly_name: 'NodeMCU2' + value_template: "{{ 'Online' if is_state('device_tracker.NodeMCU2', 'home') else 'Offline' }}" + - platform: template + sensors: + nodemcu3: + friendly_name: 'NodeMCU3' + value_template: "{{ 'Online' if is_state('device_tracker.NodeMCU3', 'home') else 'Offline' }}" + +#------------------------------------------- +group: + entry_points: + entities: + - binary_sensor.MCU1_GPIO4 + - binary_sensor.MCU1_GPIO5 + - binary_sensor.MCU1_GPIO10 + - binary_sensor.MCU1_GPIO12 + - binary_sensor.MCU1_GPIO13 + - binary_sensor.MCU1_GPIO14 + - binary_sensor.MCU2_GPIO4 + - binary_sensor.MCU2_GPIO5 + - binary_sensor.MCU2_GPIO9 + - binary_sensor.MCU2_GPIO10 + - binary_sensor.MCU2_GPIO12 + - binary_sensor.MCU2_GPIO13 + - binary_sensor.MCU2_GPIO14 + - binary_sensor.MCU2_GPIO15 + - binary_sensor.MCU3_GPIO4 + - binary_sensor.MCU3_GPIO5 + - binary_sensor.MCU3_GPIO10 + - binary_sensor.MCU3_GPIO14 + # interior_door: - Moved out to Doors Group. + # entities: + # - binary_sensor.kitchen_door_opened + # - binary_sensor.MCU3_Light +#-------------------------------------------#------------------------------------------- +automation: + - alias: 'Turn off HVAC in window/door is opened' + trigger: + - platform: state + entity_id: + - binary_sensor.MCU1_GPIO4 + - binary_sensor.MCU1_GPIO5 + - binary_sensor.MCU1_GPIO10 + - binary_sensor.MCU1_GPIO12 + - binary_sensor.MCU1_GPIO13 + - binary_sensor.MCU1_GPIO14 + - binary_sensor.MCU2_GPIO4 + - binary_sensor.MCU2_GPIO5 + - binary_sensor.MCU2_GPIO9 + - binary_sensor.MCU2_GPIO10 + - binary_sensor.MCU2_GPIO12 + - binary_sensor.MCU2_GPIO13 + - binary_sensor.MCU2_GPIO14 + - binary_sensor.MCU3_GPIO4 + - binary_sensor.MCU3_GPIO5 + - binary_sensor.MCU3_GPIO10 + - binary_sensor.MCU3_GPIO14 + to: 'on' + from: 'off' + for: + minutes: 5 + + condition: + - condition: template + value_template: "{{ states('climate.downstairs') != 'off' }}" + + action: + - service: climate.set_operation_mode + data: + entity_id: climate.downstairs + operation_mode: 'off' + - service: script.speech_engine + data_template: + value1: "The {{ trigger.to_state.attributes.friendly_name }} has been opened for about 5 minutes. I will shut down the Air Conditioner so you can enjoy the fresh air." + call_outside_weather: 1 + call_inside_weather: 1 +#-------------------------------------------#------------------------------------------- + - alias: 'Turn HVAC back on when all doors/windows are closed.' + trigger: + - platform: state + entity_id: + - group.entry_points + to: 'off' + from: 'on' + for: + minutes: 5 + + condition: + - condition: template + value_template: "{{ states('climate.downstairs') == 'off' }}" + + action: + - service: climate.set_operation_mode + data: + entity_id: climate.downstairs + operation_mode: 'auto' + +#-------------------------------------------#--- + - alias: "Panel Door opened" + hide_entity: True + trigger: + - platform: state + entity_id: + - binary_sensor.MCU3_Light + to: 'off' + from: 'on' + + action: + - service: script.notify_engine + data_template: + value1: 'Someone has opened up the Alarm Panel Door!' diff --git a/packages/alarm_clock.yaml b/packages/alarm_clock.yaml new file mode 100755 index 00000000..516df43c --- /dev/null +++ b/packages/alarm_clock.yaml @@ -0,0 +1,138 @@ +#------------------------------------------- +# Fire Tablet Alarm Panel - +# http://www.vmwareinfo.com/2017/07/visualizing-smart-home-using-home.html +#------------------------------------------- +# +homeassistant: + customize_glob: + "input_boolean.clock_snooze": + emulated_hue_hidden: False + hidden: False + +media_player: + - platform: floorplan_speaker + name: Alarm Clock + +#---Sensors for Fire Tablet----------------------------- + +binary_sensor: + - platform: mqtt + state_topic: floorplan/clock_motion + name: Clock Motion + device_class: motion + retain: true + emulated_hue_hidden: True + hidden: False + + - platform: mqtt + state_topic: floorplan/clock_plugged + name: Clock Plugged + retain: true + emulated_hue_hidden: True + hidden: False + +light: + - platform: mqtt_json + name: Clock Screensaver + state_topic: floorplan/clock_screensaver + command_topic: floorplan/clock_screensaver/set + brightness: true + +sensor: + - platform: mqtt + state_topic: "clock/stacey_alarm_time" + name: clock_stacey_alarm_time + retain: true + emulated_hue_hidden: True + hidden: true + +input_boolean: + clock_snooze: + name: Clock Snooze + initial: off + +automation: + - alias: 'Snooze Button off in 10 minutes' + trigger: + - platform: state + entity_id: + - input_boolean.clock_snooze + to: 'on' + from: 'off' + action: + - delay: + minutes: 10 + - service: input_boolean.turn_off + entity_id: input_boolean.clock_snooze + +#Turn on the clock - turn off the screensaver so we can see it. + - alias: Turn off Screensaver so we can see the time + trigger: + - platform: state + entity_id: + - binary_sensor.sleepnumber_carlo_carlo_is_in_bed + - binary_sensor.sleepnumber_carlo_stacey_is_in_bed + - light.bedroom_screensaver + to: 'off' + + action: + - service: light.turn_off + entity_id: light.clock_screensaver + - wait_template: "{{ is_state(trigger.entity_id, 'on') }}" + - service: light.turn_on + entity_id: light.clock_screensaver + +#-----Turn on the Music-------------------------------------- + - alias: 'Play Radio when Snooze button is turned off.' + + trigger: + - platform: state + entity_id: + - input_boolean.clock_snooze + to: 'off' + from: 'on' + - platform: template + value_template: '{{states.sensor.time.state == states.sensor.clock_stacey_alarm_time.state}}' + condition: + - condition: state + entity_id: input_boolean.school_mode + state: 'on' + - condition: time + weekday: + - mon + - tue + - wed + - thu + - fri + - condition: state + entity_id: group.family + state: 'home' + action: + - service: media_player.volume_set + data_template: + entity_id: + - media_player.alarm_clock + volume_level: 0.3 + - service: media_player.play_media + data_template: + entity_id: + - media_player.alarm_clock + #media_content_id: "http://listen.181fm.com/181-kickincountry_128k.mp3" + media_content_id: "http://listen.djcmedia.com:80/americascountryhigh" + media_content_type: audio/mp4 + - service: light.turn_off + entity_id: light.clock_screensaver + +#-----Turn off the Music-------------------------------------- + - alias: 'Turn off the Radio when the snooze is turned on.' + + trigger: + - platform: state + entity_id: + - input_boolean.clock_snooze + to: 'on' + from: 'off' + + action: + - service: media_player.media_stop + entity_id: media_player.alarm_clock diff --git a/packages/battery_levels.yaml b/packages/battery_levels.yaml new file mode 100755 index 00000000..ca097f72 --- /dev/null +++ b/packages/battery_levels.yaml @@ -0,0 +1,58 @@ +#------------------------------------------- +# Fire Tablet Alarm Panel - +# http://www.vmwareinfo.com/2017/07/visualizing-smart-home-using-home.html +#------------------------------------------- +# +# homeassistant: +# customize_glob: +# "sensor.*_alarm_panel*": +# emulated_hue_hidden: True +# hidden: False +# "binary_sensor.*_alarm_panel*": +# emulated_hue_hidden: True +# hidden: False + +sensor: + - platform: template + sensors: + low_battery: + friendly_name: 'Low Battery' + value_template: > + {%- set threshold = 15 -%} + {%- set domains = ['light', 'switch', 'sensor', 'zwave', 'lock', 'binary_sensor'] -%} + {%- for domain in domains -%} + {%- for item in states[domain] if ((item.attributes.battery_level is defined and item.attributes['battery_level'] | int < threshold) or ("battery" in item.name | lower and ((item.state | int < threshold and item.state|int != 0) or item.state | lower == "low" or item.state | lower == "unknown"))) -%} + {{ item.attributes.friendly_name }} ( + {%- if item.attributes.battery_level is defined -%} + {{ item.attributes.battery_level}} + {%- else -%} + {{item.state}} + {%- endif -%}%) + {%- if not loop.last -%} + {{', '}} + {%- endif -%} + {%- endfor -%} + {%- endfor -%} + + +automation: + - alias: 'Battery Alert' + initial_state: 'on' + trigger: + - platform: time + at: '10:00:00' + - platform: time + at: '18:00:00' + condition: + condition: template + value_template: "{% if states('sensor.low_battery') %}true{% endif %}" + action: + - service: persistent_notification.create + data_template: + title: Low Battery + message: "{{ states('sensor.low_battery') }}" + notification_id: low-battery-alert + - service: script.notify_engine + data_template: + value1: "Low battery levels: {{ states('sensor.low_battery') }}" + who: 'carlo' diff --git a/packages/epson_printer.yaml b/packages/epson_printer.yaml new file mode 100755 index 00000000..819ef276 --- /dev/null +++ b/packages/epson_printer.yaml @@ -0,0 +1,90 @@ +#------------------------------------------- +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +# inspired by https://community.home-assistant.io/t/epson-wf-3540-ink-level-monitoring/21813 +#------------------------------------------- +homeassistant: + customize_glob: + "sensor.epson_ink_level_*": + icon: mdi:cup-water + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True +#------------------------------------------- +sensor: + - platform: command_line + name: Epson Ink Level Black + command: /usr/bin/curl -X GET http://192.168.10.105/PRESENTATION/HTML/TOP/PRTINFO.HTML | awk -F"'" '/Ink_K.PNG/ && $6+0 == $6 { printf "%.0f\n", $6 / 50 * 100; exit }' + unit_of_measurement: '%' + scan_interval: 14400 + + - platform: command_line + name: Epson Ink Level Magenta + command: /usr/bin/curl -X GET http://192.168.10.105/PRESENTATION/HTML/TOP/PRTINFO.HTML | awk -F"'" '/Ink_M.PNG/ && $6+0 == $6 { printf "%.0f\n", $6 / 50 * 100 }' + unit_of_measurement: '%' + scan_interval: 14400 + + - platform: command_line + name: Epson Ink Level Yellow + command: /usr/bin/curl -X GET http://192.168.10.105/PRESENTATION/HTML/TOP/PRTINFO.HTML | awk -F"'" '/Ink_Y.PNG/ && $6+0 == $6 { printf "%.0f\n", $6 / 50 * 100 }' + unit_of_measurement: '%' + scan_interval: 14400 + + - platform: command_line + name: Epson Ink Level Cyan + command: /usr/bin/curl -X GET http://192.168.10.105/PRESENTATION/HTML/TOP/PRTINFO.HTML | awk -F"'" '/Ink_C.PNG/ && $6+0 == $6 { printf "%.0f\n", $6 / 50 * 100 }' + unit_of_measurement: '%' + scan_interval: 14400 + + - platform: command_line + name: Epson Ink Level Photo Black + command: /usr/bin/curl -X GET http://192.168.10.105/PRESENTATION/HTML/TOP/PRTINFO.HTML | awk -F"'" '/Ink_K.PNG/ {i++}i==2 && $6+0 == $6 { printf "%.0f\n", $6 / 50 * 100; exit }' + unit_of_measurement: '%' + scan_interval: 14400 +#------------------------------------------- +group: + epson_printer: + name: Epson Printer Info + control: hidden + entities: + - sensor.epson_ink_level_black + - sensor.epson_ink_level_cyan + - sensor.epson_ink_level_magenta + - sensor.epson_ink_level_yellow + - sensor.epson_ink_level_photo_black +#------------------------------------------- +############################################################################## +### Automations - Detect when things are not right. Like any Good Watchdog. +############################################################################## + +automation: + - alias: 'Printer Ink Alert' + initial_state: 'on' + trigger: + - platform: numeric_state + entity_id: + - sensor.epson_ink_level_black + - sensor.epson_ink_level_magenta + - sensor.epson_ink_level_photo_black + - sensor.epson_ink_level_yellow + - sensor.epson_ink_level_cyan + below: 25 + condition: + condition: time + weekday: + - wed + action: + - service: persistent_notification.create + data_template: + title: Low Ink + message: "{{ trigger.to_state.attributes.friendly_name }} is at {{ trigger.to_state.state }} " + notification_id: low-battery-alert + - service: script.notify_engine + data_template: + value1: "{{ trigger.to_state.attributes.friendly_name }} is at {{ trigger.to_state.state }} " + who: 'carlo' + - service: script.tweet_engine + data: + tweet: 'Looks like my {{ trigger.to_state.attributes.friendly_name }} is LOW. @CCostan - Get me some more (http://amzn.to/2AnpFwD)' + +#------------------------------------------- diff --git a/packages/fire_tablet.yaml b/packages/fire_tablet.yaml new file mode 100755 index 00000000..7b3e5d1d --- /dev/null +++ b/packages/fire_tablet.yaml @@ -0,0 +1,38 @@ +#------------------------------------------- +# Global Fire Tablet settings - +# http://www.vmwareinfo.com/2017/07/visualizing-smart-home-using-home.html +#------------------------------------------- +# We block the auto adjust brightness routines for the tablets. +# Use ALARM and Floorplan for the security system. + +group: + firetablets: + entities: + - binary_sensor.bedroom_motion + - binary_sensor.bedroom_plugged + - binary_sensor.clock_motion + - binary_sensor.clock_plugged + +# automation: +# +# - alias: 'Enable battery help!' +# trigger: +# - platform: state +# entity_id: +# - binary_sensor.clock_plugged +# - binary_sensor.bedroom_plugged +# to: 'off' +# from: 'on' +# +# - alias: 'Cry when the Battery is about to die. ' +# trigger: +# - platform: state +# entity_id: +# - input_boolean.clock_snooze +# to: 'on' +# from: 'off' +# action: +# - delay: +# minutes: 10 +# - service: input_boolean.turn_off +# entity_id: input_boolean.clock_snooze diff --git a/packages/fitbit.yaml b/packages/fitbit.yaml new file mode 100755 index 00000000..1c10c007 --- /dev/null +++ b/packages/fitbit.yaml @@ -0,0 +1,64 @@ +#------------------------------------------- +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +# Neato Support for D7 Connected Botvac - control my [Neato Vacuum](http://amzn.to/2kqnnqu) with Home Assistant. +#------------------------------------------- +# homeassistant: +# customize_glob: +# "*.*_sleep_hours": +# unit_of_measurement: hours +# icon: mdi:sleep +# emulated_hue_hidden: True +# hidden: False +#------------------------------------------- +sensor: + - platform: fitbit + clock_format: 12H + monitored_resources: + - "body/weight" + - "activities/steps" + - "devices/battery" +#------------------------------------------- +group: + fitbit: + entities: + - sensor.steps + - sensor.weight + - sensor.one_battery +############################################################################## +### Automations - Detect when things are not right. Like any Good Watchdog. +############################################################################## +automation: + - alias: 'Missing Fitbit Alert' + initial_state: 'on' + trigger: + - platform: time + at: '11:00:00' + condition: + condition: template + value_template: > + {%- if sensor.steps < 1000 -%} + true + {%- endif -%} + action: + - service: script.notify_engine + data_template: + value1: "Your current fitbit steps are {{ states('sensor.steps') }} - You probably do not have it." + who: 'carlo' + + - alias: 'Fitbit 10k' + initial_state: 'on' + trigger: + - platform: numeric_state + entity_id: sensor.steps + above: 10000 + + action: + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "Somebody just hit {{ states('sensor.steps') }} steps on the #Fitbit!", + "Keep on moving. Somebody just hit {{ states('sensor.steps') }} steps.", + "#Fitness Tracking at home BY the home. Somebody just hit {{ states('sensor.steps') }} steps" + ] | random + " Battery Level:{{ states('sensor.one_battery') }} #Self #Data"}} diff --git a/packages/floorplan.yaml b/packages/floorplan.yaml new file mode 100755 index 00000000..6e4cd027 --- /dev/null +++ b/packages/floorplan.yaml @@ -0,0 +1,44 @@ +#------------------------------------------- +# Fire Tablet Alarm Panel - +# http://www.vmwareinfo.com/2017/07/visualizing-smart-home-using-home.html +#------------------------------------------- +# +homeassistant: + customize_glob: + "sensor.*_alarm_panel*": + emulated_hue_hidden: True + hidden: False + "binary_sensor.*_alarm_panel*": + emulated_hue_hidden: True + hidden: False + +media_player: + - platform: floorplan_speaker + name: Bedroom Alarm Panel + +#---Sensors for Fire Tablet----------------------------- + +light: + + - platform: mqtt_json + name: Bedroom Screensaver + state_topic: floorplan/bedroom_screensaver + command_topic: floorplan/bedroom_screensaver/set + brightness: true + +binary_sensor: + + - platform: mqtt + state_topic: floorplan/bedroom_motion + name: Bedroom Motion + device_class: motion + retain: true + emulated_hue_hidden: True + hidden: False + + - platform: mqtt + state_topic: floorplan/bedroom_plugged + name: Bedroom Plugged + retain: true + emulated_hue_hidden: True + hidden: False diff --git a/packages/hasspodcast.yaml b/packages/hasspodcast.yaml new file mode 100755 index 00000000..c49028b3 --- /dev/null +++ b/packages/hasspodcast.yaml @@ -0,0 +1,47 @@ +#------------------------------------------- +# RSS Podcast Alerting function Packages +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- + +#------------------------------------------- +feedreader: + urls: + - https://hasspodcast.io/feed/podcast +#------------------------------------------- + +automation: + - alias: Send notification of RSS feed title when updated + trigger: + platform: event + event_type: feedreader + + action: + - service: script.notify_engine + data_template: + value1: 'There is a new HA Podcast available for {{trigger.event.data.title}}.' + value2: 'https://hasspodcast.io/' + who: 'carlo' + + - service: notify.html5 + data_template: + title: "New HA Podcast available" + message: "New HA Podcast - {{ as_timestamp(now()) | timestamp_custom('%I:%M:%S %p %d%b%Y', true) }} {{trigger.event.data.title}}" + data: + url: "https://hasspodcast.io/" + + - service: persistent_notification.create + data_template: + title: "{{trigger.event.data.title}}" + message: "New Podcast available - {{ as_timestamp(now()) | timestamp_custom('%I:%M:%S %p %d%b%Y', true) }}" + notification_id: "update_available" + + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "There is a new HA Podcast available! @DanGeek, @rohank9, @philhawthorne & Crew rock it out (#HomeAutomation Style!)!", + "Mine and @DanGeek Favorite Podcast just came out!", + "Listen to @rohank9 and the HA Podcast crew on thier new #HomeAutomation episode!", + "Mine & @CCostan Favorite Podcast just came out! Thanks @DanGeek!" + ] | random + "(https://hasspodcast.io/)"}} diff --git a/packages/holiday.yaml b/packages/holiday.yaml new file mode 100755 index 00000000..338a0f56 --- /dev/null +++ b/packages/holiday.yaml @@ -0,0 +1,91 @@ +############################################################################### +# @author : Mahasri Kalavala +# @date : 10/28/2017 +# @package : Holidays +# @description : Retrieves the holiday +############################################################################### +## Modified for my own fun stuff! + +homeassistant: + customize: + + sensor.holiday: + hidden: true + icon: mdi:beach + friendly_name: US Holiday + sensor.flag: + hidden: true + icon: mdi:flag + friendly_name: Flag Day + +############################################################################### +# Sensor updates once every 4 hours (14400 seconds) & runs 6 times in 24 hours +# +# First it checks for holiday in static section, if that doesn't exist, +# it checks in the dynamic section. If neither exists, the value will be empty +############################################################################### +sensor: + - platform: rest + resource: https://raw.githubusercontent.com/CCOSTAN/Home-AssistantConfig/master/json_data/holidays.json + name: Holiday + scan_interval: 14400 + value_template: > + {% set today = now().month ~ '/' ~ now().day %} + {% set holiday = value_json.MAJOR_US.static[ today ] %} + {% if holiday | trim == "" %} + {% set today = now().month ~ '/' ~ now().day ~ '/' ~ now().year %} + {% set holiday = value_json.MAJOR_US.dynamic[ today ] %} + {% endif %} + {{ holiday }} + + - platform: rest + resource: http://www.webcal.fi/cal.php?id=335&format=json&start_year=current_year&end_year=2017&tz=America%2FNew_York + name: Flag + scan_interval: 14400 + value_template: >- + {% set is_flag_day = False %} + {%- for day_val in value_json -%} + {% set now_string = now().strftime('%Y-%m-%d') %} + {%- if day_val.date == now_string and day_val.flag_day == 1-%} + {% set is_flag_day = True %} + {%- endif -%} + {% endfor %} + {{is_flag_day}} + +############################################################################### +# Automation that notifies of a Holiday "state" change +############################################################################### +automation: + - alias: Notify Holiday State Change + hide_entity: false + initial_state: true + trigger: + - platform: state + entity_id: + - sensor.holiday + condition: + - condition: template + value_template: "{{ states('sensor.holiday') != 'unknown' }}" + - condition: template + value_template: "{{ states.sensor.holiday.state | trim != '' }}" + action: + - service: persistent_notification.create + data: + message: 'Today is {{ states.sensor.holiday.state }}.' + title: '{{ states.sensor.holiday.state }}' + + - delay: '{{ (range(4, 8)|random|int) }}:{{ (range(1, 50)|random|int) }}:00' + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "Today is {{ states.sensor.holiday.state }}. Time to adjust the outside light colors!", + "Today is {{ states.sensor.holiday.state }}.", + "Is today {{ states.sensor.holiday.state }}?", + "Just checked with Alexa & today is {{ states.sensor.holiday.state }}." + ] | random + [ + " #DayOff", + "(http://www.vmwareinfo.com/2017/07/my-smart-home-look-at-parts-that-make.html)", + "(http://www.vmwareinfo.com/2017/08/diy-outdoor-smart-home-led-strips.html)", + "#{{ states.sensor.holiday.state }}" + ] | random }} diff --git a/packages/ios.yaml b/packages/ios.yaml new file mode 100755 index 00000000..e5773e27 --- /dev/null +++ b/packages/ios.yaml @@ -0,0 +1,110 @@ +#------------------------------------------- +# Realtime Debugging Related Packages +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- +homeassistant: + customize_glob: + "sensor.carlo_6*": + emulated_hue_hidden: True + "sensor.staceys_iphone_*": + emulated_hue_hidden: True + +group: + Phones: + entities: + - sensor.carlo_6s_battery_level + - sensor.carlo_6s_battery_state + - sensor.staceys_iphone_battery_level + - sensor.staceys_iphone_battery_state + +ios: + push: + categories: + - name: Medicine + identifier: 'tablet' + actions: + - identifier: 'TABLET_TAKEN' + title: 'Tablet Taken' + activationMode: 'background' + authenticationRequired: no + destructive: yes + + - identifier: 'NOT_HOME' + title: 'I am not Home' + activationMode: 'background' + authenticationRequired: no + destructive: no + +## - Reminders to take my medicine +input_boolean: + medicine: + name: Medicine Reminder + initial: off + icon: mdi:tablet + +automation: + - alias: Tablet Already taken + trigger: + platform: event + event_type: ios.notification_action_fired + event_data: + actionName: TABLET_TAKEN + action: + - service: notify.ios_carlo_6s + data: + message: "Great job!" + - service: input_boolean.turn_on + entity_id: input_boolean.medicine + + - alias: Remind Me Later + trigger: + platform: event + event_type: ios.notification_action_fired + event_data: + actionName: NOT_HOME + action: + - service: notify.ios_carlo_6s + data: + message: "Ok. I will remind you when you get home." + - wait_template: >- + {{ states.device_tracker.carlo.state == 'home' }} + - service: notify.ios_carlo_6s + data: + message: "Now that your home, please take your medicine!" + + - alias: Medicine Reminder + initial_state: true + trigger: + - platform: time + minutes: '45' + seconds: '00' + - platform: time + at: '21:30:00' + - platform: state + entity_id: device_tracker.carlo + to: 'home' + + condition: + - condition: time + after: '21:30:00' + - condition: state + entity_id: device_tracker.carlo + state: 'home' + - condition: state + entity_id: input_boolean.medicine + state: 'off' + + action: + - service: notify.ios_carlo_6s + data: + title: "Medicine Alert!" + message: "Please take your Medicine!" + data: + push: + category: "tablet" + action_data: + entity_id: light.test + my_custom_data: foo_bar + +## Reminders to take my Medicine! - End. diff --git a/packages/juicenet.yaml b/packages/juicenet.yaml new file mode 100755 index 00000000..66215825 --- /dev/null +++ b/packages/juicenet.yaml @@ -0,0 +1,79 @@ +#------------------------------------------- +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +# Neato Support for D7 Connected Botvac - control my [Neato Vacuum](http://amzn.to/2kqnnqu) with Home Assistant. +#------------------------------------------- +homeassistant: + customize_glob: + "*.carlojuice*": + emulated_hue_hidden: True + homebridge_hidden: True + hidden: False +#------------------------------------------- +juicenet: + access_token: !secret juicenet_access_token + +group: + juicenet: + name: JuiceBox Charger + control: hidden + entities: + - sensor.carlojuice_amps + - sensor.carlojuice_charge_time + - sensor.carlojuice_charging_status + - sensor.carlojuice_energy_added + - sensor.carlojuice_temperature + - sensor.carlojuice_voltage + - sensor.carlojuice_watts + +############################################################################# +### Automations - Alerts related to the JuiceBox (http://amzn.to/2AZVQ37) +############################################################################## +automation: + - alias: 'Car Charging Alerts' + initial_state: 'on' + trigger: + - platform: state + entity_id: sensor.carlojuice_charging_status + + action: + - service: script.notify_engine + data_template: + value1: "The Garage charger is now in {{ states('sensor.carlojuice_charging_status') }} mode." + who: 'parents' + + - alias: 'JuiceBox AMP Alert!' + initial_state: 'on' + trigger: + - platform: numeric_state + entity_id: sensor.carlojuice_amps + above: 24 + action: + - service: input_boolean.turn_on + entity_id: input_boolean.alert_mode + + - service: script.notify_engine + data_template: + value1: "The Juice Box Charger is pulling {{ states('sensor.carlojuice_amps') }} AMPs. This is above the safety mark of 30. Please unplug charger immediately." + who: 'parents' + + - service: script.speech_engine + data_template: + value1: "The Juice Box Charger is pulling {{ states('sensor.carlojuice_amps') }} AMPs. This is above the safety mark of 30. Please unplug charger immediately." + + - alias: 'JuiceBox Tweet Stat!' + initial_state: 'on' + trigger: + - platform: state + entity_id: sensor.carlojuice_charging_status + from: 'charging' + action: + - delay: '0{{ range(0,4) | random | int }}:00:00' + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "The #Chevy Bolt Charged for {{(states.sensor.carlojuice_charge_time.state | int /60) | round() }} minutes and Juiced up add {{states.sensor.carlojuice_energy_added.state |int /1000}} KwHs.", + "The last charging session was {{(states.sensor.carlojuice_charge_time.state | int /60) | round() }} minutes. Added {{states.sensor.carlojuice_energy_added.state |int /1000}} KwHs ", + "The Juice Box Pro add {{states.sensor.carlojuice_energy_added.state |int /1000}} KwHs to the #Chevy #BoltEV in {{(states.sensor.carlojuice_charge_time.state | int /60) | round() }} minutes." + ] | random + " (http://amzn.to/2zlQIUI) #Electric #Solar"}} diff --git a/packages/landscape_lighting.yaml b/packages/landscape_lighting.yaml new file mode 100755 index 00000000..5a0bfebe --- /dev/null +++ b/packages/landscape_lighting.yaml @@ -0,0 +1,55 @@ +#------------------------------------------- +# Landscape Lighting Packages +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- +homeassistant: + customize: + switch.back_landscaping: + friendly_name: 'Back Landscaping' + icon: mdi:flower + emulated_hue_hidden: False + hidden: False + switch.front_landscaping: + friendly_name: 'Front Landscaping' + icon: mdi:flower + emulated_hue_hidden: False + hidden: False + group.landscaping: + friendly_name: 'Landscaping Lights' + emulated_hue_hidden: False + hidden: False +#------------------------------------------- +group: + landscaping: + entities: + - switch.front_landscaping + - switch.back_landscaping +#------------------------------------------- +# Automation : Added to Sunset_ON +# Automation : Added to Sunset_OFF +# Automation : Added to Away. (Switches off Back Landscaping) +# Automation : Added to Late Night Helper Outside (Switches Back lights on) +automation: + - alias: 'Back Landscape lights off' + trigger: + - platform: state + entity_id: + - binary_sensor.sleepnumber_carlo_carlo_is_in_bed + - binary_sensor.sleepnumber_carlo_stacey_is_in_bed + to: 'on' + + condition: + - condition: state + entity_id: sun.sun + state: 'below_horizon' + - condition: state + entity_id: binary_sensor.sleepnumber_carlo_carlo_is_in_bed + state: 'on' + - condition: state + entity_id: binary_sensor.sleepnumber_carlo_stacey_is_in_bed + state: 'on' + + action: + - service: switch.turn_off + entity_id: switch.back_landscaping diff --git a/packages/light_sensor.yaml.old b/packages/light_sensor.yaml.old new file mode 100755 index 00000000..ae45b1a1 --- /dev/null +++ b/packages/light_sensor.yaml.old @@ -0,0 +1,19 @@ +#------------------------------------------- +# Bruh Light Sensor Related Packages +#------------------------------------------- +#------LightSensor Node---http://amzn.to/2oUgj5i +homeassistant: + customize: + sensor.sn1_ldr: + icon: mdi:sensor + friendly_name: Light Sensor + #emulated_hue_hidden: False + hidden: False +#---Sensor for Light----------------------------- +sensor: + - platform: mqtt + state_topic: "home/sensornode1" + name: "SN1 LDR" + ##This sensor is not calibrated to actual LUX. Rather, this a map of the input voltage ranging from 0 - 1023. + unit_of_measurement: "LUX" + value_template: '{{ value_json.ldr }}' diff --git a/packages/logger.yaml b/packages/logger.yaml new file mode 100755 index 00000000..9eed1c25 --- /dev/null +++ b/packages/logger.yaml @@ -0,0 +1,46 @@ +#------------------------------------------- +# Realtime Debugging Related Packages +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- +homeassistant: + customize_glob: + "input_select.log_*": + icon: mdi:bug + emulated_hue_hidden: True + hidden: False + +#------------------------------------------- +input_select: + log_level: + name: Log Level + options: + - critical + - fatal + - error + - warning + - warn + - info + - debug + - notset + initial: warn + +################################### +## Dynamically set the log levels without having to restart HASS or edit configuration.yaml +#- Thanks @VDRainer +################################### +automation: + - alias: Log Level + trigger: + platform: state + entity_id: + - input_select.log_level +# - input_select.log_component + action: + - service: logger.set_level + data_template: + homeassistant.components: "{{ states.input_select.log_level.state }}" + + - service: script.tweet_engine + data: + tweet: "My logging level has just been set to {{ states.input_select.log_level.state }}" diff --git a/packages/neato.yaml b/packages/neato.yaml new file mode 100755 index 00000000..1a81daae --- /dev/null +++ b/packages/neato.yaml @@ -0,0 +1,48 @@ +#------------------------------------------- +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +# Neato Support for D7 Connected Botvac - control my [Neato Vacuum](http://amzn.to/2kqnnqu) with Home Assistant. +#------------------------------------------- +# homeassistant: +# customize_glob: +# "*.*_sleep_hours": +# unit_of_measurement: hours +# icon: mdi:sleep +# emulated_hue_hidden: True +# hidden: False +#------------------------------------------- +neato: + username: !secret neato_username + password: !secret neato_password +#------------------------------------------- +group: + Neato: + entities: + - camera.carloneato_cleaning_map + - switch.carloneato_schedule + - vacuum.carloneato +############################################################################## +### Automations - Detect when things are not right. Like any Good Watchdog. +############################################################################## +automation: + - alias: 'Vacuum -Tweet' + trigger: + - platform: state + entity_id: vacuum.carloneato + to: 'off' + from: 'on' + + condition: + - condition: template + value_template: "{{ states.vacuum.carloneato.attributes.battery_level |int < 20 }}" + + action: + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "#Neato returning to base. Vacuumed up a TON. (http://amzn.to/2CKHZya)", + "Everyday I have the Neato Botvac go out and clean the house on its own.", + "Since we have a cat that sheds all day, we have @Neato go out daily to clean.", + "Time to recharge the @Neato Vacuum." + ] | random + " Battery Level:{{states.vacuum.carloneato.attributes.battery_level }} #Robots"}} diff --git a/packages/nest_protects.yaml b/packages/nest_protects.yaml new file mode 100755 index 00000000..a5665217 --- /dev/null +++ b/packages/nest_protects.yaml @@ -0,0 +1,141 @@ +###################################################################################################### +# Nest Protect Package +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +# - Write up- http://www.vmwareinfo.com/2017/06/psa-check-out-your-smoke-detectors-once.html +###################################################################################################### +#----------------------------------- +homeassistant: + customize: + + binary_sensor.hallway_nest_protect_kids_hallway_online: + friendly_name: Kids Hallway Protect + icon: mdi:nest-protect + + binary_sensor.justins_room_nest_protect_online: + friendly_name: Justins Room Protect + icon: mdi:nest-protect + + binary_sensor.kitchen_nest_protect_online: + friendly_name: Kitchen Protect + icon: mdi:nest-protect + + binary_sensor.master_bedroom_nest_protect_online: + friendly_name: Master Bedroom Protect + icon: mdi:nest-protect + + binary_sensor.master_hallway_nest_protect_online: + friendly_name: Master Hallway Protect + icon: mdi:nest-protect + + binary_sensor.paiges_room_nest_protect_paiges_room_online: + friendly_name: Paiges Room Protect + icon: mdi:nest-protect + + binary_sensor.upstairs_bedroom_nest_protect_online: + friendly_name: Upstairs Bedroom Protect + icon: mdi:nest-protect + + binary_sensor.upstairs_living_room_nest_protect_online: + friendly_name: Upstairs Living Room Protect + icon: mdi:nest-protect + + binary_sensor.office_nest_protect_online: + friendly_name: Office Protect + icon: mdi:nest-protect + + group.protects: + homebridge_hidden: true +#------------------------------------------- + +#------------------------------------------- +group: + protects: + name: Nest Protects + entities: + - binary_sensor.upstairs_living_room_nest_protect_online + - binary_sensor.hallway_nest_protect_kids_hallway_online + - binary_sensor.justins_room_nest_protect_online + - binary_sensor.kitchen_nest_protect_online + - binary_sensor.master_bedroom_nest_protect_online + - binary_sensor.master_hallway_nest_protect_online + - binary_sensor.paiges_room_nest_protect_paiges_room_online + - binary_sensor.upstairs_bedroom_nest_protect_online + - binary_sensor.office_nest_protect_online + +#------------------------------------------- +automation: + - alias: Nest protect emergency + hide_entity: true + trigger: + platform: state + entity_id: + - sensor.hallway_nest_protect_kids_hallway_smoke_status + - sensor.hallway_nest_protect_kids_hallway_co_status + - sensor.justins_room_nest_protect_smoke_status + - sensor.justins_room_nest_protect_co_status + - sensor.kitchen_nest_protect_smoke_status + - sensor.kitchen_nest_protect_co_status + - sensor.master_bedroom_nest_protect_smoke_status + - sensor.master_bedroom_nest_protect_co_status + - sensor.master_hallway_nest_protect_smoke_status + - sensor.master_hallway_nest_protect_co_status + - sensor.office_nest_protect_smoke_status + - sensor.office_nest_protect_co_status + - sensor.paiges_room_nest_protect_paiges_room_smoke_status + - sensor.paiges_room_nest_protect_paiges_room_co_status + - sensor.upstairs_bedroom_nest_protect_smoke_status + - sensor.upstairs_bedroom_nest_protect_co_status + - sensor.upstairs_living_room_nest_protect_smoke_status + - sensor.upstairs_living_room_nest_protect_co_status + to: 'Emergency' + + condition: + - condition: state + entity_id: group.family + state: 'home' + + action: + - service: script.emergency + data_template: + call_garage_open: 1 + - service: script.notify_engine + data_template: + value1: "An emergency has been detected on {{ trigger.to_state.attributes.friendly_name }} Please investigate IMMEDIATELY." + + - service: script.tweet_engine + data_template: + tweet: "An emergency has been detected on {{ trigger.to_state.attributes.friendly_name }} @CCostan (http://www.vmwareinfo.com/2017/06/psa-check-out-your-smoke-detectors-once.html)" + + - alias: Nest Protect Offline Notify + hide_entity: true + trigger: + platform: state + entity_id: + - binary_sensor.upstairs_living_room_nest_protect_online + - binary_sensor.hallway_nest_protect_kids_hallway_online + - binary_sensor.justins_room_nest_protect_online + - binary_sensor.kitchen_nest_protect_online + - binary_sensor.master_bedroom_nest_protect_online + - binary_sensor.master_hallway_nest_protect_online + - binary_sensor.paiges_room_nest_protect_paiges_room_online + - binary_sensor.upstairs_bedroom_nest_protect_online + - binary_sensor.office_nest_protect_online + from: 'on' + + action: + - service: input_boolean.turn_on + entity_id: input_boolean.alert_mode + + - service: script.speech_engine + data_template: + value1: "The {{ trigger.to_state.attributes.friendly_name }} is now {{ (trigger.to_state.state)|replace('_', ' ') }}. Please check immediately." + + - service: script.notify_engine + data_template: + value1: "The {{ trigger.to_state.attributes.friendly_name }} is now {{ (trigger.to_state.state)|replace('_', ' ') }}. Please check immediately." + who: "parents" + + - service: script.tweet_engine + data: + tweet: "Oh NO! {{ trigger.to_state.attributes.friendly_name }} is now in {{ (trigger.to_state.state)|replace('_', ' ') }} mode. @Nest. (http://www.vmwareinfo.com/2017/06/psa-check-out-your-smoke-detectors-once.html) #Safety" diff --git a/packages/network.yaml b/packages/network.yaml new file mode 100755 index 00000000..3b2dc474 --- /dev/null +++ b/packages/network.yaml @@ -0,0 +1,218 @@ +#------------------------------------------- +# Network Related Packages +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- + +#------------------------------------------- +sensor: + - platform: template + sensors: + wii: + friendly_name: 'Wii' + value_template: "{{ 'Online' if is_state('device_tracker.wii', 'home') else 'Offline' }}" + + tablotv: + friendly_name: 'Tablo TV' + value_template: "{{ 'Online' if is_state('device_tracker.tablotv', 'home') else 'Offline' }}" + + study_ap: + friendly_name: 'Unifi Study AP' + value_template: "{{ 'Online' if is_state('device_tracker.study_ap', 'home') else 'Offline' }}" + + unifi_ap: + friendly_name: 'Unifi Office AP' + value_template: "{{ 'Online' if is_state('device_tracker.unifi_ap', 'home') else 'Offline' }}" + + hue_hub_1: + friendly_name: 'Hue Hub 1' + value_template: "{{ 'Online' if is_state('device_tracker.hue_hub_1', 'home') else 'Offline' }}" + + hue_hub_2: + friendly_name: 'Hue Hub 2' + value_template: "{{ 'Online' if is_state('device_tracker.hue_hub_2', 'home') else 'Offline' }}" + + bedroom_alarm_panel: + friendly_name: 'Bedroom Alarm Panel' + value_template: "{{ 'Online' if is_state('device_tracker.bedroom_alarm_panel', 'home') else 'Offline' }}" + + entry_alarm_panel: + friendly_name: 'Entry Alarm Panel' + value_template: "{{ 'Online' if is_state('device_tracker.entry_alarm_panel', 'home') else 'Offline' }}" + + alexa_echo: + friendly_name: 'Alexa Echo' + value_template: "{{ 'Online' if is_state('device_tracker.alexa_echo', 'home') else 'Offline' }}" + + amazon_dot: + friendly_name: 'Amazon Dot' + value_template: "{{ 'Online' if is_state('device_tracker.amazon_dot', 'home') else 'Offline' }}" + + amazon_fire_stick: + friendly_name: 'Amazon Fire Stick' + value_template: "{{ 'Online' if is_state('device_tracker.amazon_fire_stick', 'home') else 'Offline' }}" + + printer: + friendly_name: 'Printer' + value_template: "{{ 'Online' if is_state('device_tracker.printer', 'home') else 'Offline' }}" + + circle: + friendly_name: 'Disney Circle' + value_template: "{{ 'Online' if is_state('device_tracker.circle', 'home') else 'Offline' }}" + + nest_downstairs: + friendly_name: 'Downstairs Nest' + value_template: "{{ 'Online' if is_state('device_tracker.nest_downstairs', 'home') else 'Offline' }}" + + nest_upstairs: + friendly_name: 'Upstairs Nest' + value_template: "{{ 'Online' if is_state('device_tracker.nest_upstairs', 'home') else 'Offline' }}" + + rachio: + friendly_name: 'Rachio Sprinklers' + value_template: "{{ 'Online' if is_state('device_tracker.rachio', 'home') else 'Offline' }}" + + samsungtv: + friendly_name: 'Samsung TV' + value_template: "{{ 'Online' if is_state('device_tracker.samsungtv', 'home') else 'Offline' }}" + + chromecast_audio_1: + friendly_name: 'ChromeCast Audio 1' + value_template: "{{ 'Online' if is_state('device_tracker.chromecast_audio_1', 'home') else 'Offline' }}" + + chromecast_audio_2: + friendly_name: 'ChromeCast Audio 2' + value_template: "{{ 'Online' if is_state('device_tracker.chromecast_audio_2', 'home') else 'Offline' }}" + + large_garage: + friendly_name: 'Large Garage' + value_template: "{{ 'Online' if is_state('device_tracker.large_garage', 'home') else 'Offline' }}" + + small_garage: + friendly_name: 'Small Garage' + value_template: "{{ 'Online' if is_state('device_tracker.small_garage', 'home') else 'Offline' }}" + + rgb_led_outdoor_den: + friendly_name: 'RGB LED Outdoor Den' + value_template: "{{ 'Online' if is_state('device_tracker.rgb_led_outdoor_den', 'home') else 'Offline' }}" + + rgb_led_garage_large: + friendly_name: 'RGB LED Garage Large' + value_template: "{{ 'Online' if is_state('device_tracker.rgb_led_garage_large', 'home') else 'Offline' }}" + + rgb_led_garage_small: + friendly_name: 'RGB LED Garage Small' + value_template: "{{ 'Online' if is_state('device_tracker.rgb_led_garage_small', 'home') else 'Offline' }}" + + smart_water_meter: + friendly_name: 'Smart Water Meter' + value_template: "{{ 'Online' if is_state('device_tracker.smart_water_meter', 'home') else 'Offline' }}" + + sleep_number_bed: + friendly_name: 'Sleep Number Bed' + value_template: "{{ 'Online' if is_state('device_tracker.sleep_number_bed', 'home') else 'Offline' }}" + + withings_scale: + friendly_name: 'WiThings Scale' + value_template: "{{ 'Online' if is_state('device_tracker.withings_scale', 'home') else 'Offline' }}" + +#------------------------------------------- +group: + network: + entities: + - sensor.ha_installed_version + - sensor.ha_uptime + - sensor.since_last_boot_templated + - sensor.disk_used_ + - sensor.speedtest_download + - sensor.speedtest_upload + - sensor.study_ap + - sensor.actiontechap + - sensor.unifi_ap + - sensor.wii + - sensor.hue_hub_1 + - sensor.hue_hub_2 + - binary_sensor.carlowink + - sensor.tablotv + - sensor.alexa_echo + - sensor.amazon_dot + - sensor.circle + - sensor.rachio + - sensor.skybell + - sensor.samsungtv + - sensor.chromecast_audio_1 + - sensor.chromecast_audio_2 + - sensor.amazon_fire_stick + - sensor.nest_upstairs + - sensor.nest_downstairs + - sensor.large_garage + - sensor.small_garage + - sensor.rgb_led_garage_large + - sensor.rgb_led_garage_small + - sensor.rgb_led_outdoor_den + - sensor.withings_scale + - sensor.smart_water_meter + - sensor.sleep_number_bed + - sensor.printer + - sensor.bedroom_alarm_panel + - sensor.entry_alarm_panel + - sensor.NodeMCU1 + - sensor.NodeMCU2 + - sensor.NodeMCU3 + - sensor.carlopihole + + +#------------------------------------------------------------------------------------- +automation: + - alias: 'Device Status' + hide_entity: True + trigger: + - platform: state + entity_id: + - sensor.wii + - sensor.Hue_Hub_1 + - sensor.Hue_Hub_2 + - sensor.tablotv + - sensor.alexa_echo + - sensor.amazon_dot + - sensor.circle + - sensor.rachio + - sensor.skybell + - sensor.printer + - sensor.chromecast_audio_1 + - sensor.chromecast_audio_2 + - sensor.nest_upstairs + - sensor.nest_downstairs + - sensor.study_ap + - sensor.actiontechap + - sensor.trendnetap + - sensor.unifi_ap + - sensor.small_garage + - sensor.large_garage + - sensor.rgb_led_garage_large + - sensor.rgb_led_garage_small + - sensor.rgb_led_outdoor_den + #- sensor.withings_scale + - sensor.smart_water_meter + - sensor.sleep_number_bed + - sensor.bedroom_alarm_panel + - sensor.entry_alarm_panel + - sensor.nodemcu1 + - sensor.nodemcu2 + - sensor.nodemcu3 + - sensor.carlopihole + to: 'offline' + for: + minutes: 5 + + action: + - service: script.notify_engine + data_template: + value1: 'Device Status:' + value2: "{{ trigger.to_state.attributes.friendly_name }} is " + value3: "{{ trigger.to_state.state }}" + who: 'carlo' + + - service: script.speech_engine + data_template: + value1: "{{ trigger.to_state.attributes.friendly_name }} is now {{ trigger.to_state.state }}" diff --git a/packages/office_motion.yaml b/packages/office_motion.yaml new file mode 100755 index 00000000..200ec9b8 --- /dev/null +++ b/packages/office_motion.yaml @@ -0,0 +1,79 @@ +#------------------------------------------- +# Motion Sensor in the office. +# Find more recipes @ https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- +#------LightSensor Node---http://amzn.to/2oUgj5i +homeassistant: + customize: + binary_sensor.office_motion: + friendly_name: Office Motion Sensor + emulated_hue_hidden: True + hidden: False +#---Sensor for Light----------------------------- +binary_sensor: + - platform: mqtt + state_topic: "NodeMCU4/Motion/Motion" + name: "Office_Motion" + payload_on: 1 + payload_off: 0 + device_class: motion + +# This boolean gets reset every night in the sunset automation. +# Gets turned on by dash button automation primarily. +input_boolean: + daylight_override: + name: Daylight Override + initial: off + +automation: + - alias: 'Motion in the Office - Turn on Light' + trigger: + - platform: state + entity_id: + - binary_sensor.office_motion + to: 'on' + from: 'off' + + condition: + - condition: state + entity_id: binary_sensor.sleepnumber_carlo_carlo_is_in_bed + state: 'off' + - condition: state + entity_id: group.family + state: 'home' + - condition: state + entity_id: light.office_lamp + state: 'off' + - condition: or + conditions: + - condition: time + after: '18:00:00' + - condition: state + entity_id: sun.sun + state: 'below_horizon' + - condition: state + entity_id: input_boolean.daylight_override + state: 'on' + + action: + - service: light.turn_on + entity_id: light.office_lamp + + - alias: 'Motion in the Office - Turn off Light' + trigger: + - platform: state + entity_id: + - binary_sensor.office_motion + to: 'off' + from: 'on' + for: + minutes: 3 + + condition: + - condition: state + entity_id: light.office_lamp + state: 'on' + + action: + - service: light.turn_off + entity_id: light.office_lamp diff --git a/packages/pihole.yaml b/packages/pihole.yaml new file mode 100755 index 00000000..65987751 --- /dev/null +++ b/packages/pihole.yaml @@ -0,0 +1,124 @@ +#------------------------------------------- +# PiHole ad Blocking Related Packages +#------------------------------------------- +homeassistant: + customize: + + sensor.pihole_ads_percentage_today: + friendly_name: Percentage of Ad Traffic Blocked + unit_of_measurement: '%' + icon: mdi:ticket-percent + + sensor.pihole_domains_being_blocked: + friendly_name: Total Domains Blocking + icon: mdi:do-not-disturb + + sensor.pihole_dns_unique_clients: + friendly_name: Unique Clients + icon: mdi:desktop-classic + + sensor.pihole_ads_blocked_today: + friendly_name: Ads Blocked Today + icon: mdi:do-not-disturb + + sensor.pihole_dns_queries_today: + friendly_name: DNS Queries Today + icon: mdi:note-text + + sensor.carlopihole: + friendly_name: Pi Hole Server + icon: mdi:filter-variant + + group.pihole: + homebridge_hidden: true +#------------------------------------------- +sensor: + - platform: pi_hole + host: 192.168.10.11 + monitored_conditions: + - dns_queries_today + - ads_blocked_today + - ads_percentage_today + - unique_clients + +######Custom Version sensor + # - platform: command_line + # command: "pihole -v -p -c" + # name: 'pihole_version_current' + # value_template: '{{ value[28:] }}' + # scan_interval: 86400 + # + # - platform: command_line + # command: "pihole -v -p -l" + # name: 'pihole_version_latest' + # value_template: '{{ value[27:] }}' + # scan_interval: 86400 + + - platform: template + sensors: + carlopihole: + friendly_name: 'Carlo-PiHole' + value_template: "{{ 'Online' if is_state('device_tracker.carlopihole', 'home') else 'Offline' }}" + + # pi_hole_version: + # value_template: "{%- if states.sensor.pihole_version_current.state == states.sensor.pihole_version_latest.state -%}{{states.sensor.pihole_version_current.state}} {% else %}{{states.sensor.pihole_version_latest.state}} Available{% endif%}" + # icon_template: >- + # {% if states.sensor.pihole_version_current.state == states.sensor.pihole_version_latest.state %} + # mdi:checkbox-marked + # {% else %} + # mdi:checkbox-blank-outline + # {% endif %} + +# Pi-Hole switch +switch: + - platform: command_line + switches: + pihole_temp_disable: + command_on: "curl -X GET 'http://192.168.10.11/admin/api.php?enable&auth='" + command_off: "curl -X GET 'http://192.168.10.11/admin/api.php?disable=3600&auth='" +# command_state: "curl -X GET 'http://192.168.10.11/admin/api.php?status'| grep enabled" +# value_template: "{{ value_json.status == 'enabled' }} + +#------------------------------------------- +group: + pihole: + entities: + - sensor.carlopihole + - sensor.pi_hole_version + - sensor.pihole_dns_unique_clients + - sensor.pihole_dns_queries_today + - sensor.pihole_ads_blocked_today + - sensor.pihole_ads_percentage_today + - sensor.pihole_ads_percentage_blocked_today + - switch.pihole_temp_disable +#------------------------------------------- + + +automation: + - alias: PiHole Daily stats Tweet! + trigger: + platform: time + at: '23:50:00' + action: + - delay: '00:{{ (range(1, 9)|random|int) }}:00' + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "I blocked {{states.sensor.pihole_ads_blocked_today.state}} ads. That is {{states.sensor.pihole_ads_percentage_blocked_today.state}}% of my internet traffic.", + "Today was a good day! Why, you ask? Because I blocked {{states.sensor.pihole_ads_blocked_today.state}} ads via Pi-Hole!", + ] | random + " #PiHole #Security Status:({{states.sensor.carlopihole.state}})"}} + + - alias: PiHole Daily Client Tweet! + trigger: + platform: time + at: '04:30:00' + action: + - delay: '{{ (range(1, 6)|random|int) }}:{{ (range(1, 50)|random|int) }}:00' + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "There are currently {{states.sensor.pihole_dns_unique_clients.state}} clients on my network.", + "As reported by #Ubiquity Routers, There are {{states.sensor.pihole_dns_unique_clients.state}} clients on my network.", + ] | random + "#Security http://amzn.to/2D2AfXS"}} diff --git a/packages/processmonitor.yaml b/packages/processmonitor.yaml new file mode 100755 index 00000000..15690d13 --- /dev/null +++ b/packages/processmonitor.yaml @@ -0,0 +1,106 @@ +#------------------------------------------- +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- +homeassistant: + customize: + sensor.process_mosquitto: + friendly_name: 'Mosquitto' + emulated_hue_hidden: True + hidden: False + sensor.process_homebridge: + friendly_name: 'Apple HomeKit' + emulated_hue_hidden: True + hidden: False + sensor.process_node: + friendly_name: 'Dash Button Monitor' + emulated_hue_hidden: True + hidden: False + group.processes: + homebridge_hidden: true +#------------------------------------------- +sensor: + - platform: systemmonitor + resources: + # - type: last_boot + - type: since_last_boot + - type: disk_use_percent + arg: / + - type: process + arg: mosquitto + - type: process + arg: homebridge + - type: process + arg: node +#------------------------------------------- +group: + processes: + name: Processes + control: hidden + entities: + - sensor.process_mosquitto + - sensor.process_homebridge + - sensor.process_node +#------------------------------------------- +############################################################################## +### Automations - Detect when things are not right. Like any Good Watchdog. +############################################################################## + +automation: + - alias: 'Device Status' + hide_entity: True + trigger: + - platform: state + entity_id: + - sensor.process_mosquitto + - sensor.process_homebridge + - sensor.process_dasher + to: 'off' + for: + minutes: 1 + + action: + - service: script.notify_engine + data_template: + value1: 'Process Status:' + value2: "{{ trigger.to_state.attributes.friendly_name }} is " + value3: "{{ trigger.to_state.state }}" + who: 'carlo' + + - service: script.tweet_engine + data: + tweet: "Oh NO! {{ trigger.to_state.attributes.friendly_name }} is now {{ trigger.to_state.state }}. #ProcessMonitor" + +#------------------------------------------- + + - alias: "Self Heal Disk Use Alarm" + trigger: + - platform: numeric_state + entity_id: sensor.disk_used_ + above: 80 + action: + - service: script.notify_engine + data_template: + value1: 'Hard Drive Monitor:' + value2: "Your harddrive is running out of Space! /dev/root:{{ states.sensor.disk_used_.state }}%!" + value3: 'Attempting to clean' + who: 'carlo' + - service: tts.clear_cache + + - alias: "Disk Use Alarm" + trigger: + - platform: numeric_state + entity_id: sensor.disk_used_ + above: 90 + action: + - service: script.notify_engine + data_template: + value1: 'Hard Drive Monitor:' + value2: "Your harddrive is running out of Space! /dev/root:{{ states.sensor.disk_used_.state }}%!" + who: 'carlo' + + - service: persistent_notification.create + data: + title: "Hard Drive Monitor:" + message: "Your harddrive is running out of Space! /dev/root:{{ states.sensor.disk_used_.state }}%!" + notification_id: "Critical Alert" diff --git a/packages/radio.yaml b/packages/radio.yaml new file mode 100755 index 00000000..4c0abdfb --- /dev/null +++ b/packages/radio.yaml @@ -0,0 +1,69 @@ +#------------------------------------------- +# Radio Related Packages +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- +#------Whole House Radio Enabled via Emulated Hue---------------------------- +homeassistant: + customize: + input_boolean.house_station: + icon: mdi:radio + friendly_name: House Station + emulated_hue_hidden: False + hidden: False +#---Use this Boolean to trigger via GUI or Alexa------------------------------ +input_boolean: + house_station: + name: House Station + initial: off + +#Moved to the Alarm Clock Package. + +# #-----Turn on the Music-------------------------------------- +# automation: +# - alias: 'Play Americas Country on ChromeCast Audio' +# +# trigger: +# - platform: state +# entity_id: +# - input_boolean.house_station +# to: 'on' +# from: 'off' +# +# action: +# - service: media_player.turn_off +# entity_id: media_player.living_room_tv +# +# - service: media_player.turn_on +# entity_id: media_player.livingroomCC +# +# - service: media_player.volume_set +# entity_id: +# - media_player.livingroomCC +# data_template: +# volume_level: 0.2 +# +# - service: media_player.play_media +# data_template: +# entity_id: +# - media_player.LivingRoomCC +# media_content_id: "http://listen.181fm.com/181-kickincountry_128k.mp3" +# #media_content_id: "http://listen.djcmedia.com:80/americascountryhigh" +# media_content_type: audio/mp4 +# +# #-----Turn off the Music-------------------------------------- +# - alias: 'Turn off the Radio' +# +# trigger: +# - platform: state +# entity_id: +# - input_boolean.house_station +# to: 'off' +# from: 'on' +# +# action: +# - service: media_player.turn_off +# entity_id: media_player.livingroomCC +# +# - service: input_boolean.turn_off +# entity_id: input_boolean.house_station diff --git a/packages/skybellhd.yaml b/packages/skybellhd.yaml new file mode 100755 index 00000000..ac8669dd --- /dev/null +++ b/packages/skybellhd.yaml @@ -0,0 +1,126 @@ +#------------------------------------------- +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +################################### +## [SkyBell HD](http://amzn.to/2dcexIB) +################################### + +homeassistant: + customize_glob: + "sensor.skybell_*": + icon: mdi:camera-front + emulated_hue_hidden: True + hidden: False + homebridge_hidden: True + +group: + skybell: + name: Skybell HD Front Door + control: hidden + entities: + - binary_sensor.skybell_stone_door_button + - binary_sensor.skybell_stone_door_motion + - camera.stone_door + - sensor.skybell_stone_door_chime_level + - sensor.skybell_stone_door_motion_sensor + - switch.skybell_stone_door_do_not_disturb + - switch.skybell_stone_door_motion_sensor + +skybell: + username: !secret skybell_username + password: !secret skybell_password + +camera: + - platform: skybell + +binary_sensor: + - platform: skybell + monitored_conditions: + - button + - motion + +light: + - platform: skybell # Part of the Outdoor Front Lights Group + +sensor: + - platform: skybell + monitored_conditions: + - chime_level + + - platform: template + sensors: + skybell: + entity_id: binary_sensor.skybell_stone_door_button + value_template: "{{ 'Online' if is_state_attr('binary_sensor.skybell_stone_door_button', 'status', 'up') else 'Offline' }}" + +switch: + - platform: skybell + monitored_conditions: + - do_not_disturb + - motion_sensor + +################################### +## Automations +################################### +## Doorbell Press +automation: + - alias: 'Log SkyBell Pressed Activity' + hide_entity: True + trigger: + - platform: state + entity_id: + - binary_sensor.skybell_stone_door_button + to: 'on' + - platform: event + event_type: skybell_pressed + + action: + # Disable this automation + - service: automation.turn_off + - service: script.skybell_pressed + - delay: + minutes: 1 + # enable this automation - This prevents duplicate pushes. + - service: automation.turn_on + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "Oh, that tickled. Someone just pressed the @MySkyBell.", + "Ouch! That hurt. Who touched the SkyBell Doorbell?", + "Someone just poked me in the @MySkybell!", + "I see you! You are at the @MySkyBell and you just pressed it.", + "Someone answer my door. Someone just pressed the doorbell." + ] | random + [ + " #Security", + " (http://amzn.to/2dcexIB)", + " (http://www.vmwareinfo.com/2017/07/my-smart-home-look-at-parts-that-make.html)", + " #HomeAutomation" + ] | random }} + +# Motion Sensing + - alias: 'Log SkyBell Motion detection' + hide_entity: True + trigger: + - platform: event + event_type: skybell_motion + + action: + - service: script.front_house_motion + +# Turn SkyBell Light and Neato Schedule back on if it's turned off. Like any Good Watchdog. + + - alias: Automated Mismatch WatchDog! + hide_entity: True + trigger: + - platform: state + entity_id: + - light.stone_door + - switch.carloneato_schedule + to: 'off' + + #Turn it back on! + action: + - service: homeassistant.turn_on + data_template: + entity_id: "{{ trigger.entity_id }}" diff --git a/packages/sleepiq.yaml b/packages/sleepiq.yaml new file mode 100755 index 00000000..6e961def --- /dev/null +++ b/packages/sleepiq.yaml @@ -0,0 +1,54 @@ +#------------------------------------------- +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- +homeassistant: + customize_glob: + "sensor.*_sleep_hours": + unit_of_measurement: hours + icon: mdi:sleep + emulated_hue_hidden: True + hidden: False + # customize: + # sensor.Carlo_sleep_hours: + # friendly_name: 'Carlo Slept last night' + # sensor.Stacey_sleep_hours: + # friendly_name: 'Stacey Slept last night' + +#------------------------------------------- +sleepiq: + username: !secret sleepiq_username + password: !secret sleepiq_password +#------------------------------------------- +# sensor: +# - platform: history_stats +# name: Carlo_sleep_hours +# entity_id: binary_sensor.sleepnumber_carlo_carlo_is_in_bed +# state: 'on' +# type: time +# end: '{{ now() }}' +# duration: +# hours: 24 +# +# - platform: history_stats +# name: Stacey_sleep_hours +# entity_id: binary_sensor.sleepnumber_carlo_stacey_is_in_bed +# state: 'on' +# type: time +# end: '{{ now() }}' +# duration: +# hours: 24 + +group: + bed: + entities: + - binary_sensor.sleepnumber_carlo_carlo_is_in_bed + - sensor.sleepnumber_carlo_carlo_sleepnumber +# - sensor.Carlo_sleep_hours + - binary_sensor.sleepnumber_carlo_stacey_is_in_bed + - sensor.sleepnumber_carlo_stacey_sleepnumber +# - sensor.Stacey_sleep_hours + +############################################################################## +### Automations - Detect when things are not right. Like any Good Watchdog. +############################################################################## diff --git a/packages/space.yaml b/packages/space.yaml new file mode 100755 index 00000000..b84fce2c --- /dev/null +++ b/packages/space.yaml @@ -0,0 +1,115 @@ +#------------------------------------------- +# Space Related Packages +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- +#------ISS---------------------------------- +homeassistant: + customize: + binary_sensor.iss: + icon: mdi:satellite-variant + friendly_name: ISS Visibility + emulated_hue_hidden: True + hidden: False + homebridge_hidden: true + sensor.launch_window: + hidden: False + icon: mdi:rocket + friendly_name: Rocket Launch Window +#------------------------------------------- +binary_sensor: + - platform: iss + show_on_map: False +#------------------------------------------- + +sensor: + - platform: rest + scan_interval: 3600 + resource: https://launchlibrary.net/1.2.2/launch/next/10 + # resource: https://raw.githubusercontent.com/cribbstechnologies/ha_config/master/www/test_launch.json + name: launch window + # if the current timestamp is in the launch window + # this sensor will return the UTC timestamp of the launch + value_template: >- + {%- for launch in value_json.launches %} + {% if launch.location.id == 16 or launch.location.id == 17 %} + {% if strptime(launch.isostart, '%Y%m%dT%H%M%SZ').strftime('%Y-%m-%d') == now().strftime('%Y-%m-%d') %} + {% set utc_offset_string = now().strftime('%z') %} + {% set utc_offset_direction = utc_offset_string[:1] %} + {% set utc_offset_hours = now().strftime('%z')[-4:] %} + {% set utc_offset_seconds = (utc_offset_hours| int /100) * 60 * 60 %} + {% if utc_offset_direction == '-' %} + {{ launch.wsstamp - utc_offset_seconds}} + {% else %} + {{ launch.wsstamp + utc_offset_seconds}} + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + +automation: + - alias: Launch Window Approaching + trigger: + - platform: state + entity_id: sensor.launch_window + condition: + condition: and + conditions: + - condition: template + value_template: "{{states('sensor.launch_window') != 'unknown'}}" + - condition: template + value_template: "{{as_timestamp(now()) < (states('sensor.launch_window') | float)}}" + + action: + - service: script.notify_engine + data_template: + value1: 'There will be a rocket Launch today - I will notify you later when the launch window starts' + - wait_template: >- + {{as_timestamp(now()) >= (states('sensor.launch_window') | float)}} + - service: script.notify_engine + data_template: + value1: 'Go Outside! There is a Rocket Launch!' + + - service: script.tweet_engine + data_template: + tweet: 'There is a Rocket launch happening right now! I can see it if I look closely. @BrianCribbs #SpaceX #Space' + +# This automation was also moved to a macro in the speech_engine. +# It's a random fact now. + + - alias: 'ISS is above Me -Tweet' + + trigger: + - platform: state + entity_id: + - binary_sensor.iss + to: 'on' + from: 'off' + + action: + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "The ISS is above me right now!", + "The International Space Station flys by once a day & that time is NOW! (For me)", + "I can look up RIGHT NOW and see the ISS.", + "The International Space Station Rocks! And it's above me RIGHT NOW!" + ] | random + " #Space"}} + + - alias: 'Full Moon -Tweet' + trigger: + - platform: state + entity_id: sensor.moon + to: 'Full Moon' + action: + - delay: '{{ (range(1, 6)|random|int) }}:{{ (range(1, 50)|random|int) }}:00' + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "There is a Full Moon out tonight!", + "Wish my solar panels picked up Moon rays. Full Moon out tonight.", + "Turn down the lights, there is a Full Moon out tonight.", + "Get out your telescopes, it'll be a Full Moon out tonight!" + ] | random + "#Space"}} diff --git a/packages/time_date_sensors.yaml b/packages/time_date_sensors.yaml new file mode 100755 index 00000000..31be6151 --- /dev/null +++ b/packages/time_date_sensors.yaml @@ -0,0 +1,60 @@ +#------------------------------------------- +# Clean data for the Floorplan UI. +#------------------------------------------- +homeassistant: + customize_glob: + "sensor.floorplan_*": + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True + "sensor.clock_*": + emulated_hue_hidden: True + hidden: True + homebridge_hidden: True +#---Sensor for Time and Date.----------------------------- +sensor: + - platform: template + scan_interval: 30000 + sensors: + floorplan_date: + friendly_name: 'Date' + value_template: >- + {{now().strftime("%A")}}, {{now().strftime("%B")}} {{now().strftime("%d")}} + + - platform: template + sensors: + floorplan_time: + friendly_name: 'Time' + value_template: >- + {{now().strftime("%-I")}}:{{now().strftime("%M")}} {{now().strftime("%p")}} + + - platform: template + sensors: + clock_time: + friendly_name: 'Clock Time' + value_template: >- + {{now().strftime("%-I")}}:{{now().strftime("%M")}} + + - platform: template + scan_interval: 30000 + sensors: + clock_am_pm: + friendly_name: 'AM/PM' + value_template: >- + {{now().strftime("%p")}} + + - platform: template + scan_interval: 30000 + sensors: + clock_day: + friendly_name: 'Day' + value_template: >- + {{now().strftime("%A")}} + + - platform: template + scan_interval: 30000 + sensors: + clock_date: + friendly_name: 'Clock Date' + value_template: >- + {{now().strftime("%B")}} {{now().strftime("%d")}} {{now().year}} diff --git a/packages/triggers/last_message.yaml b/packages/triggers/last_message.yaml new file mode 100755 index 00000000..f6a646b1 --- /dev/null +++ b/packages/triggers/last_message.yaml @@ -0,0 +1,49 @@ +#------------------------------------------- +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- +homeassistant: + customize: + input_boolean.lastmsg: + friendly_name: 'Repeat Message' + icon: mdi:repeat-once + emulated_hue_hidden: False + hidden: False +#------------------------------------------- +input_boolean: + lastmsg: + name: Last Message + initial: off +#------------------------------------------- +sensor: + - platform: mqtt + state_topic: "polly/lastmsg" + name: "Last Message" +############################################################################## +### Automations - +############################################################################## + +automation: + - alias: 'Repeat Last Message' + + trigger: + - platform: state + entity_id: input_boolean.lastmsg + to: 'on' + + action: + - service: tts.amazon_polly_say + entity_id: + - media_player.livingroomCC + - media_player.entry_alarm_panel + - media_player.bedroom_alarm_panel + data_template: + message: > + + {{states.sensor.last_message.state}} + + cache: true + + - service: input_boolean.turn_off + entity_id: + - input_boolean.lastmsg diff --git a/packages/triggers/mqtt_screens.yaml.disabled b/packages/triggers/mqtt_screens.yaml.disabled new file mode 100755 index 00000000..e2cd4efb --- /dev/null +++ b/packages/triggers/mqtt_screens.yaml.disabled @@ -0,0 +1,23 @@ +#------------------------------------------- +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +# More information : https://github.com/SmilyOrg/screenmqtt +#------------------------------------------- +homeassistant: + customize: + switch.computer_screens: + friendly_name: 'Computer Screens' + icon: mdi:monitor-multiple + emulated_hue_hidden: False + hidden: False + homebridge_hidden: False + +#------------------------------------------- +switch: + - platform: mqtt + name: computer_screens + state_topic: 'carlo-ultra/monitor/all/power/state' + command_topic: 'carlo-ultra/monitor/all/power/command' + +#------------------------------------------- +#group - Added to group.interior_switches diff --git a/packages/triggers/self_destruct.yaml b/packages/triggers/self_destruct.yaml new file mode 100755 index 00000000..1013308e --- /dev/null +++ b/packages/triggers/self_destruct.yaml @@ -0,0 +1,66 @@ +#------------------------------------------- +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- +homeassistant: + customize: + input_boolean.self_destruct: + friendly_name: 'Self Destruct' + icon: mdi:skull + emulated_hue_hidden: False + hidden: False +#------------------------------------------- +input_boolean: + self_destruct: + name: Self Destruct + initial: off + +#------------------------------------------- +############################################################################## +### Pretend to blow up the house.. +############################################################################## + +automation: + - alias: 'Self Destruct sequence' + trigger: + - platform: state + entity_id: input_boolean.self_destruct + to: 'on' + + action: + - service: media_player.turn_on + entity_id: media_player.livingroomCC + + - service: switch.turn_on + entity_id: switch.living_room_amp + - delay: '00:00:05' + + - service: media_player.volume_set + entity_id: + - media_player.livingroomCC + data: + volume_level: 0.22 + + - service: media_player.play_media + entity_id: + - media_player.livingroomCC + - media_player.entry_alarm_panel + - media_player.bedroom_alarm_panel + data_template: + media_content_id: > + "https://raw.githubusercontent.com/CCOSTAN/Home-AssistantConfig/master/sounds/speechcons/self_destruct.mp3" + media_content_type: audio/mp4 + - service: light.turn_on + entity_id: + - group.all_lights + data: + flash: long + - service: switch.turn_off + entity_id: + - group.all_switches + - service: light.turn_off + entity_id: + - group.all_lights + - service: input_boolean.turn_off + entity_id: + - input_boolean.self_destruct diff --git a/packages/triggers/sleepy_dog.yaml b/packages/triggers/sleepy_dog.yaml new file mode 100755 index 00000000..c971440e --- /dev/null +++ b/packages/triggers/sleepy_dog.yaml @@ -0,0 +1,49 @@ +#------------------------------------------- +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- +homeassistant: + customize: + input_boolean.sleepy_dog: + friendly_name: 'Sleepy Dog' + icon: mdi:bell-sleep + emulated_hue_hidden: False + hidden: False +#------------------------------------------- +input_boolean: + sleepy_dog: + name: Sleep Dog + initial: off + +#------------------------------------------- +############################################################################## +### Automations - Detect when things are not right. Like any Good Watchdog. +############################################################################## + +automation: + - alias: 'Snooze the Dog for 30 minutes' + trigger: + - platform: state + entity_id: input_boolean.sleepy_dog + to: 'on' + + action: + # Disable automation for 30 minutes + - service: automation.turn_off + entity_id: automation.guard_dog + - service: input_boolean.turn_off + entity_id: input_boolean.sleepy_dog + - service: script.speech_engine + data_template: + call_no_announcement: 1 + value1: > + {{ [ + "The dogs have been put away for the next 30 minutes.", + "I will let sleeping dogs lie for the next 30 minutes.", + "You will not be bothered by the sound of dogs barking for at least 30 minutes.", + "Sleepy Dog activated. Molly is our only watch cat for the next 30 minutes." + ] |random }} + - delay: + minutes: 30 + - service: automation.turn_on + entity_id: automation.guard_dog diff --git a/packages/twitter.yaml b/packages/twitter.yaml new file mode 100755 index 00000000..e8901e3b --- /dev/null +++ b/packages/twitter.yaml @@ -0,0 +1,144 @@ +#------------------------------------------- +# This is the configuration account for @BearStoneHA - My Home's automated twitter account. +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#------------------------------------------- +# homeassistant: +# customize_glob: +# "input_select.log_*": +# icon: mdi:bug +# emulated_hue_hidden: True +# hidden: False + +#Random number - https://www.random.org/integers/?num=1&min=1&max=10&col=1&base=10&format=plain&rnd=new + +notify: + - name: BearStoneHA + platform: twitter + consumer_key: !secret twitter_consumer_key + consumer_secret: !secret twitter_consumer_secret + access_token: !secret twitter_access_token + access_token_secret: !secret twitter_access_token_secret + +### Building out some Historical stats for tweeting. ##################### +sensor: + + - platform: history_stats + name: Doorbell Presses + entity_id: binary_sensor.skybell_stone_door_button + state: 'on' + type: count + end: '{{ now() }}' + duration: + hours: 24 + + - platform: history_stats + name: Landscaping Light time + entity_id: group.landscaping + state: 'on' + type: time + end: '{{ now() }}' + duration: + hours: 24 + +############################################################# + +automation: + - alias: 'New Twitter follower!' + hide_entity: True + trigger: + - platform: event + event_type: new_follower + + condition: + - condition: state + entity_id: group.bed + state: 'off' + action: + - service: media_player.play_media + data_template: + entity_id: + - media_player.livingroomCC + - media_player.bedroom_alarm_panel + media_content_id: "https://raw.githubusercontent.com/CCOSTAN/Home-AssistantConfig/master/sounds/twitter-chirp.mp3" + media_content_type: audio/mp4 + + - service: script.tweet_engine + data_template: + tweet: >- + {% set handle = trigger.event.data.value1 %} + {% set location = trigger.event.data.location %} + {% set phrases = [ + "Thanks for the Follow " ~ handle ~ "! Chirp the Bird from " ~ location ~ "!!", + "Hey " ~ handle ~ "Thanks for the Follow from " ~ location ~ " !", + "New follower " ~ handle ~ " from " ~ location ~ ", I just sounded a chirp in the house.", + "Boom! The " ~ location ~ " follow from " ~ handle ~ " makes me sound a chirp in the house.", + "Wanna know who is super cool? "~ handle ~" IS!!! Thanks for making me CHIRP!", + "If the AMP (http://amzn.to/2j18dlT) is on & I get a new follower like " ~ handle ~ ", I sound a chirp!" + ] %} + {% set hashtags = [ + "#ThanksForTheFollow", + "#FollowBack", + "#ChirpTheHouse", + "#FollowMe", + "#MakingitChirp", + "(http://www.vmwareinfo.com/2017/11/building-digital-cuckoo-clock-with-home.html)" + ] %} + {{ phrases|random ~ " " ~ hashtags|random }} + + - alias: 'Closed Github Issue' + hide_entity: True + trigger: + - platform: event + event_type: closed_github + + action: + - service: script.tweet_engine + data_template: + tweet: >- + {% set repo = trigger.event.data.repo %} + {% set issue = trigger.event.data.issue %} + {% set issueurl = trigger.event.data.issueurl %} + {% set phrases = [ + "New Code Alert: " ~ issue ~ "(" ~ issueurl ~ "). Repo: (https://github.com/CCOSTAN/Home-AssistantConfig/commits/master) " + ] %} + {% set hashtags = [ + "#Github", + "#HomeAutomation", + "#SmartHomeCode" + ] %} + {{ phrases|random ~ " " ~ hashtags|random }} + + + - alias: 'Random House stats' + hide_entity: True + trigger: + - platform: time + hours: '/4' + minutes: 01 + seconds: 00 + + action: + - service: automation.turn_off + - delay: '0{{ range(0,2) | random | int }}:{{ range(10,59) | random | int }}:00' + - service: script.tweet_engine + data_template: + tweet: > + {{ [ + "The number of Doorbell presses today was {{states.sensor.doorbell_presses.state}}", + "The #Landscaping lights where on for about {{states.sensor.landscaping_lights_time.state}} yesterday.", + "So far, I have prevented {{states.sensor.pihole_ads_blocked_today.state}} ads from hitting the network via Pi-hole! http://www.pi-hole.net", + "{{states.sensor.doorbell_presses.state}} people came to the door today and pressed the bell.", + "The Pi has been running for {{states.sensor.since_last_boot_templated.state}}", + "I am running Home Assistant version {{states.sensor.ha_installed_version.state}} (https://github.com/CCOSTAN/Home-AssistantConfig)", + "{{states.sensor.doorbell_presses.state}} doorbell presses occurred in the last 24 hours.", + "I keep the average humidity of the house at {{states.sensor.downstairs_thermostat_humidity.state}} percent. Outside is {{states.sensor.dark_sky_humidity.state}} #Nest (http://amzn.to/2BWNk5N)", + "Outside is {{states.sensor.dark_sky_temperature.state}}. I keep the average temperature at {{states.sensor.downstairs_thermostat_temperature.state}}. #Nest (http://amzn.to/2BWNk5N)", + "Average internet stats are Download: {{states.sensor.speedtest_download.state}} Mbit/s & Upload {{states.sensor.speedtest_upload.state}} Mbit/s.", + "Todays Sleep Number is {{states.sensor.sleepnumber_carlo_stacey_sleepnumber.state}}. Wifi connected Bed! #SleepStat (http://amzn.to/2D10BcQ)", + "Our Sleep Number is {{states.sensor.sleepnumber_carlo_carlo_sleepnumber.state}}. Wifi connected Bed! #SleepStat (http://amzn.to/2D10BcQ)", + "The current UV index is {{states.sensor.dark_sky_uv_index.state}} and the Moon is {{states.sensor.moon.state}}. #Space", + "Home Assistant has been running for {{states.sensor.ha_uptime.state}} minutes. (https://github.com/CCOSTAN/Home-AssistantConfig)", + "My @getspectrum internet download speed is about {{states.sensor.speedtest_download.state}} Mbit/s and I am a #cordcutter. @ " + ] | random + " #RandomStat"}} + - service: automation.turn_on diff --git a/packages/usps.yaml.disabled b/packages/usps.yaml.disabled new file mode 100755 index 00000000..25c49c27 --- /dev/null +++ b/packages/usps.yaml.disabled @@ -0,0 +1,20 @@ +#------------------------------------------- +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +#---Sensor Mail and Packages----------------------------- +usps: + username: !secret myusps_username + password: !secret myusps_password + +camera: + - platform: usps + scan_interval: 5 + +group: + mail: + name: Mailbox Information + control: hidden + entities: + - sensor.usps_mail + - sensor.usps_packages + - camera.usps_mail diff --git a/packages/weather_camera.yaml.disabled b/packages/weather_camera.yaml.disabled new file mode 100755 index 00000000..793a2d09 --- /dev/null +++ b/packages/weather_camera.yaml.disabled @@ -0,0 +1,11 @@ +#------------------------------------------- +# Camera Related Packages +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig + +#---Sensor for Light----------------------------- +camera: + - platform: generic + still_image_url: 'https://icons.wxug.com/data/weather-maps/radar/united-states/saint-petersburg-florida-region-current-radar.gif' +# still_image_url: 'https://radblast.wunderground.com/cgi-bin/radar/WUNIDS_map?station=MCO&brand=wui&num=1&delay=15&type=TR0&frame=0&scale=1.000&noclutter=0&showstorms=0&mapx=400&mapy=240¢erx=400¢ery=240&transx=0&transy=0&showlabels=1&severe=0&rainsnow=0&lightning=0&smooth=0&rand=25183060&lat=0&lon=0&label=you' + name: WU Doppler Weather diff --git a/panels/clock.html b/panels/clock.html new file mode 100755 index 00000000..8b2933d2 --- /dev/null +++ b/panels/clock.html @@ -0,0 +1,58 @@ + + + + + + + + + diff --git a/panels/floorplan.html b/panels/floorplan.html new file mode 100755 index 00000000..8065edc0 --- /dev/null +++ b/panels/floorplan.html @@ -0,0 +1,58 @@ + + + + + + + + + diff --git a/recorder.yaml b/recorder.yaml new file mode 100755 index 00000000..ac2f99be --- /dev/null +++ b/recorder.yaml @@ -0,0 +1,28 @@ +############################################################ +# recorder +############################################################ +#db_url: sqlite:///data/home-assistant_v2.db +purge_interval: 1 +purge_keep_days: 5 +exclude: + domains: + - updater + - automation + entities: + - group.motion + - group.doors + - sensor.floorplan_date + - sensor.floorplan_time + - sensor.ha_uptime + - sensor.time + - sensor.weather_apparent_temperature + - sensor.weather_humidity + - sensor.weather_icon + - sensor.weather_precip_intensity + - sensor.weather_precip_probability + - sensor.weather_summary + - sensor.weather_temperature + - sensor.weather_hourly_summary + - sensor.weather_daily_summary + - sensor.weather_wind_speed + - sun.sun diff --git a/scene/monthly_colors.yaml b/scene/monthly_colors.yaml new file mode 100755 index 00000000..56c28797 --- /dev/null +++ b/scene/monthly_colors.yaml @@ -0,0 +1,370 @@ +#Color Table +# http://www.colorhexa.com/color-names + +# service: scene.turn_on +# entity_id: scene.month_standard_colors + +- name: month_standard_colors + entities: + group.outdoor_front_lights: + state: 'on' + color_name: 'Gold' + +- name: front_full_brightness + entities: + group.outdoor_front_lights: + state: 'on' + color_name: 'White' + brightness: 250 + +- name: month_RWB_colors + entities: + light.outdoor_foyer: + state: 'on' + #color_name: 'Cream' + rgb_color: [255,253,208] + brightness: 30 + light.stone_door: + state: 'on' + #color_name: 'Cream' + rgb_color: [204,0,0] + light.outdoor_sconce_3: + state: 'on' + #color_name: 'Red' + rgb_color: [204,0,0] + light.outdoor_sconce_2: + state: 'on' + #color_name: 'White' Smoke + rgb_color: [245,245,245] + light.outdoor_sconce_1: + state: 'on' + color_name: 'Blue' + light.led_garage_large: + state: 'on' + #color_name: 'Red' + rgb_color: [204,0,0] + light.led_garage_snip: + state: 'on' + #color_name: 'Red' + rgb_color: [204,0,0] + light.led_garage_small: + state: 'on' + #color_name: 'White' Smoke + rgb_color: [245,245,245] + light.led_outdoor_den: + state: 'on' + color_name: 'Blue' + +- name: month_valentine_colors + entities: + group.outdoor_front_lights: + state: 'on' + color_name: 'Crimson' + +- name: month_marti_gras_colors + entities: + light.outdoor_foyer: + state: 'on' + color_name: 'Gold' + light.stone_door: + state: 'on' + color_name: 'Purple' + light.outdoor_sconce_1: + state: 'on' + color_name: 'Purple' + light.outdoor_sconce_2: + state: 'on' + color_name: 'Gold' + light.outdoor_sconce_3: + state: 'on' + color_name: 'Purple' + light.led_garage_large: + state: 'on' + color_name: 'Green' + light.led_garage_snip: + state: 'on' + color_name: 'Green' + light.led_garage_small: + state: 'on' + color_name: 'Green' + light.led_outdoor_den: + state: 'on' + color_name: 'Green' + +- name: month_st_patty_colors + entities: + group.outdoor_front_lights: + state: 'on' + #color_name: 'Dark Spring Green' + rgb_color: [23,114,69] + +- name: month_pi_colors + entities: + group.outdoor_front_lights: + state: 'on' + rgb_color: [3,14,159] + +- name: month_easter_colors + entities: + light.outdoor_foyer: + state: 'on' + # color_name: 'Lavender' + rgb_color: [244,187,255] + light.stone_door: + state: 'on' + color_name: 'yellow' + light.outdoor_sconce_1: + state: 'on' + #color_name: 'Bubble Gum' + rgb_color: [255,193,204] + light.outdoor_sconce_2: + state: 'on' + #color_name: 'Lavender' + rgb_color: [244,187,255] + light.outdoor_sconce_3: + state: 'on' + #color_name: 'Bubble Gum' + rgb_color: [255,193,204] + light.led_garage_large: + state: 'on' + color_name: 'Green' + light.led_garage_snip: + state: 'on' + color_name: 'Green' + light.led_garage_small: + state: 'on' + color_name: 'Green' + light.led_outdoor_den: + state: 'on' + color_name: 'Green' + +- name: month_starwars_colors + entities: + light.outdoor_foyer: + state: 'on' + # color_name: 'Red' + rgb_color: [204,0,0] + light.stone_door: + state: 'on' + color_name: 'yellow' + light.outdoor_sconce_1: + state: 'on' + #color_name: 'White' Smoke + rgb_color: [245,245,245] + light.outdoor_sconce_2: + state: 'on' + #color_name: 'White' Smoke + rgb_color: [245,245,245] + light.outdoor_sconce_3: + state: 'on' + #color_name: 'White' Smoke + rgb_color: [245,245,245] + light.led_garage_large: + state: 'on' + # color_name: 'Red' + rgb_color: [204,0,0] + light.led_garage_snip: + state: 'on' + # color_name: 'Red' + rgb_color: [204,0,0] + light.led_garage_small: + state: 'on' + # color_name: 'Red' + rgb_color: [204,0,0] + light.led_outdoor_den: + state: 'on' + # color_name: 'Red' + rgb_color: [204,0,0] + +- name: month_cinco_de_mayo_colors + entities: + light.outdoor_foyer: + state: 'on' + # color_name: 'Red' + rgb_color: [204,0,0] + light.stone_door: + state: 'on' + # color_name: 'Red' + rgb_color: [204,0,0] + light.outdoor_sconce_1: + state: 'on' + # color_name: 'Red' + rgb_color: [204,0,0] + light.outdoor_sconce_2: + state: 'on' + #color_name: 'White' Smoke + rgb_color: [245,245,245] + light.outdoor_sconce_3: + state: 'on' + #color_name: 'Dark Spring Green' + rgb_color: [23,114,69] + light.led_garage_large: + state: 'on' + color_name: 'Red' + light.led_garage_snip: + state: 'on' + color_name: 'Red' + light.led_garage_small: + state: 'on' + color_name: 'Green' + light.led_outdoor_den: + state: 'on' + color_name: 'white' + +- name: month_fathers_day_colors + entities: + light.outdoor_foyer: + state: 'on' + color_name: 'Orange' + light.stone_door: + state: 'on' + color_name: 'Orange' + light.outdoor_sconce_1: + state: 'on' + color_name: 'Blue' + light.outdoor_sconce_2: + state: 'on' + color_name: 'Orange' + light.outdoor_sconce_3: + state: 'on' + color_name: 'Blue' + +- name: month_halloween_colors + entities: + light.outdoor_foyer: + state: 'on' + color_name: 'purple' + light.stone_door: + state: 'on' + #color_name: 'orange' + rgb_color: [127,14,0] + light.outdoor_sconce_1: + state: 'on' + color_name: 'purple' + light.outdoor_sconce_2: + state: 'on' + color_name: 'purple' + light.outdoor_sconce_3: + state: 'on' + color_name: 'purple' + light.led_garage_large: + state: 'on' + #color_name: 'orange' + rgb_color: [127,14,0] + brightness: 150 + light.led_garage_snip: + state: 'on' + #color_name: 'orange' + rgb_color: [127,14,0] + brightness: 150 + light.led_garage_small: + state: 'on' + #color_name: 'orange' + rgb_color: [127,14,0] + brightness: 150 + light.led_outdoor_den: + state: 'on' + #color_name: 'orange' + rgb_color: [127,14,0] + brightness: 150 + +- name: month_thanksgiving_colors + entities: + group.outdoor_front_lights: + state: 'on' + color_name: 'orange' + + +- name: month_hanukkah_colors + entities: + light.outdoor_foyer: + state: 'on' + color_name: 'white' + light.stone_door: + state: 'on' + color_name: 'blue' + light.outdoor_sconce_1: + state: 'on' + color_name: 'blue' + light.outdoor_sconce_2: + state: 'on' + color_name: 'white' + light.outdoor_sconce_3: + state: 'on' + color_name: 'blue' + light.led_garage_large: + state: 'on' + color_name: 'Blue' + light.led_garage_snip: + state: 'on' + color_name: 'Blue' + light.led_garage_small: + state: 'on' + color_name: 'white' + light.led_outdoor_den: + state: 'on' + color_name: 'blue' + +- name: month_christmas_colors + entities: + light.outdoor_foyer: + state: 'on' + color_name: 'red' + light.stone_door: + state: 'on' + color_name: 'green' + light.outdoor_sconce_1: + state: 'on' + color_name: 'red' + light.outdoor_sconce_2: + state: 'on' + color_name: 'red' + light.outdoor_sconce_3: + state: 'on' + color_name: 'red' + light.led_garage_large: + state: 'on' + color_name: 'green' + effect: green_fade + light.led_garage_snip: + state: 'on' + color_name: 'green' + effect: green_fade + light.led_garage_small: + state: 'on' + color_name: 'green' + effect: green_fade + light.led_outdoor_den: + state: 'on' + color_name: 'green' + effect: green_fade + +- name: month_new_years_day_colors + entities: + light.outdoor_foyer: + state: 'on' + color_name: 'red' + light.stone_door: + state: 'on' + color_name: 'yellow' + light.outdoor_sconce_1: + state: 'on' + color_name: 'blue' + light.outdoor_sconce_2: + state: 'on' + color_name: 'yellow' + light.outdoor_sconce_3: + state: 'on' + color_name: 'orange' + light.led_garage_large: + state: 'on' + color_name: 'green' + light.led_garage_snip: + state: 'on' + color_name: 'green' + light.led_garage_small: + state: 'on' + color_name: 'purple' + light.led_outdoor_den: + state: 'on' + color_name: 'violet' diff --git a/scene/tv_time.yaml b/scene/tv_time.yaml new file mode 100755 index 00000000..00a68e0d --- /dev/null +++ b/scene/tv_time.yaml @@ -0,0 +1,34 @@ +- name: TV Time + entities: + light.M1_front_left: + state: off + transition: 10 + light.M1_front_right: + state: off + transition: 10 + light.M1_slider: + state: off + transition: 10 + light.M1_back_right: + state: on + transition: 10 + brightness: 1 + light.M1_back_left: + state: on + transition: 40 + brightness: 1 + light.tv_stand_light: + state: on + transition: 400 + color_name: 'Gold' + brightness: 150 + light.tv_light: + state: on + transition: 400 + color_name: 'Gold' + brightness: 125 + light.couch_1: + state: on + transition: 400 + color_name: 'Gold' + brightness: 255 diff --git a/script/README.md b/script/README.md new file mode 100755 index 00000000..fabd7f86 --- /dev/null +++ b/script/README.md @@ -0,0 +1,202 @@ +# [![Build Status](https://travis-ci.org/CCOSTAN/Home-AssistantConfig.svg?branch=master)](https://travis-ci.org/CCOSTAN/Home-AssistantConfig) Home-Assistant Config by [@ccostan](http://www.twitter.com/ccostan) +[Home Assistant](https://home-assistant.io/) configuration files (YAMLs) + +Be sure to :star: my repo so you can keep up to date on the daily progress! + +All of my Scripts are in this directory. These scripts can be used over and over by different automations. I try to modulize most of my scripts so that they can be passed variables from different automations and still keep all the settings normailized and centralized. + +#Still have questions on my Config? +Follow me on twitter : [@CCostan](https://twitter.com/ccostan) + +You can also vist my [Blog](http://www.vmwareinfo.com/search/label/iot) for all of my [Home Automation Posts](http://www.vmwareinfo.com/search/label/iot). + + + Sponsor + + +Original mapping work by @beed2112 +Modified by [@CCOSTAN](https://twitter.com/ccostan) +Repo : https://github.com/beed2112/condo +This is a map of the script references from my repo. + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/amp_settings.yaml + + amp_settings + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/System/door_chime.yaml: - service: script.amp_settings + + + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/dog_bark.yaml + + dog_bark + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/customize/scripts.yaml:script.dog_bark: + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/dog_bark.yaml: # service: script.dog_bark + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/front_house_motion.yaml: - service: script.dog_bark + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/guard_dog.yaml: - service: script.dog_bark + + + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/emergency.yaml + + emergency + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/emergency.yaml:# - service: script.emergency + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/nest_protects.yaml: - service: script.emergency + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/High_Wind_Speed_Check.yaml: - service: script.emergency + + + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/flash_notify.yaml + + flash_notify + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/customize/scripts.yaml:script.flash_notify: + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/skybell_pressed.yaml: - service: script.flash_notify + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/flash_notify.yaml:# - service: script.flash_notify + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/ifttt_calendar.yaml: - service: script.flash_notify + + + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/front_house_motion.yaml + + front_house_motion + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/customize/scripts.yaml:script.front_house_motion: + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/front_house_motion.yaml:# - service: script.front_house_motion + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/skybellhd.yaml: - service: script.front_house_motion + + + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/interior_off.yaml + + interior_off + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/customize/scripts.yaml:script.interior_off: + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/interior_off.yaml:# - service: script.interior_off + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/away.yaml: - service: script.interior_off + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/good_night.yaml: - service: script.interior_off + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Timed_Triggers/sunrise_turn_off.yaml: - service: script.interior_off + + + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/monthly_color_scene.yaml + + monthly_color_scene + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/customize/scripts.yaml:script.monthly_color_scene: + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/front_house_motion.yaml: - service: script.monthly_color_scene + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/monthly_color_scene.yaml:# - service: script.monthly_color_scene + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/late_night_outside_helper.yaml: - service: script.monthly_color_scene + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Timed_Triggers/sunset_turn_on.yaml: - service: script.monthly_color_scene + + + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/notify_engine.yaml + + notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/customize/scripts.yaml:script.notify_engine: + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/notify_engine.yaml: # service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/hasspodcast.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/epson_printer.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/network.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/nest_protects.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/nest_protects.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/battery_levels.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/processmonitor.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/processmonitor.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/processmonitor.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/space.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/space.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/fitbit.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/alarm.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/juicenet.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/juicenet.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/garadget.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/garadget.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/garadget_Wind_Speed_Check.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/door_opened.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/High_Wind_Speed_Check.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/medicine_logger.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/System/update_notification.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/System/bad_logins.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/System/ip_change.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/System/Wink_update_notification.yaml: - service: script.notify_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Timed_Triggers/startup_notification.yaml: - service: script.notify_engine + + + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/skybell_pressed.yaml + + skybell_pressed + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/customize/scripts.yaml:script.skybell_pressed: + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/skybell_pressed.yaml:# - service: script.skybell_pressed + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/skybellhd.yaml: - service: script.skybell_pressed + + + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/speech_engine.yaml + + speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/customize/scripts.yaml:script.speech_engine: + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/speech_engine.yaml: # service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/speech_processing.yaml: # service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/skybell_pressed.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/front_house_motion.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/triggers/sleepy_dog.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/network.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/nest_protects.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/alarm.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/juicenet.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/garadget.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/new_device.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/garadget_Wind_Speed_Check.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/garage_closed.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/responsibilities.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/announcements.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/garage_opened.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/door_opened.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/High_Wind_Speed_Check.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/nest.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/home_stats.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/good_night.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/dark_rainy_day.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Timed_Triggers/sunset_turn_on.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Timed_Triggers/sunset_turn_on.yaml: - service: script.speech_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Timed_Triggers/2200.yaml: - service: script.speech_engine + + + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/speech_processing.yaml + + speech_processing + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/customize/scripts.yaml:script.speech_processing: + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/speech_engine.yaml: - service: script.speech_processing + + + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/switch_turn_off_all.yaml + + switch_turn_off_all + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/customize/scripts.yaml:script.switch_turn_off_all: + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/interior_off.yaml: - service: script.switch_turn_off_all + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/switch_turn_off_all.yaml:# - service: script.switch_turn_off_all + + + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/script/tweet.yaml + + tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/logger.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/hasspodcast.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/epson_printer.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/skybellhd.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/neato.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/pihole.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/pihole.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/nest_protects.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/nest_protects.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/processmonitor.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/space.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/space.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/space.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/fitbit.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/twitter.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/twitter.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/twitter.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/packages/holiday.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/new_device.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/garadget_Wind_Speed_Check.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Speech/High_Wind_Speed_Check.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/ifttt_logger.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/System/update_notification.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/System/Self_heal.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/System/bad_logins.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/System/ip_change.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/System/rachio_rain_delay.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/System/Wink_update_notification.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Timed_Triggers/sunrise_turn_off.yaml: - service: script.tweet_engine + https://github.com/CCOSTAN/Home-AssistantConfig/blob/master/automation/Timed_Triggers/sunset_turn_on.yaml: - service: script.tweet_engine + + diff --git a/script/amp_settings.yaml b/script/amp_settings.yaml new file mode 100755 index 00000000..c2660060 --- /dev/null +++ b/script/amp_settings.yaml @@ -0,0 +1,43 @@ +###################################################################################################### +###Standardize AMP settings. +## @CCOSTAN +## Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +###################################################################################################### + +amp_settings: + sequence: + - service: media_player.volume_set + data_template: + entity_id: >- + {% if media_player | length == 0 %} + {% set media_player = [ + 'media_player.livingroomcc', + 'media_player.alarm_clock', + 'media_player.bedroom_alarm_panel' + ] %} + {% endif %} + + {% if media_player is not string and media_player is sequence %} + {% set media_player = media_player|join(', ') %} + {% endif %} + + {{ media_player }} + volume_level: >- + {% if volume_level is none %} + {% if now().strftime('%H')|int < 12 and now().strftime('%H')|int > 6 %} + 0.3 + {% elif now().strftime('%H')|int > 12 and now().strftime('%H')|int < 20 %} + 0.5 + {% else %} + 0.3 + {% endif %} + {% endif %} + {{volume_level}} + + - condition: state + entity_id: switch.living_room_amp + state: 'off' + + - service: switch.turn_on + data: + entity_id: switch.living_room_amp diff --git a/script/dog_bark.yaml b/script/dog_bark.yaml new file mode 100755 index 00000000..00119844 --- /dev/null +++ b/script/dog_bark.yaml @@ -0,0 +1,51 @@ +###################################################################################################### +###Script to send notifications to the ChromeCast Audios during normal hours and only when we are home! Call like this: + # action: + # service: script.dog_bark + # data_template: + # value1: 'Startup: Home Assistant is Up and Running!' + +###################################################################################################### + +dog_bark: + sequence: + - wait_template: >- + {{ not is_state('media_player.livingroomCC', 'playing') }} + timeout: 00:01:30 + - condition: template + value_template: > + {% if is_state('media_player.livingroomCC', 'playing') %} + false + {% else %} + true + {% endif %} + - condition: state + entity_id: input_boolean.speech_notifications + state: 'on' + - service: switch.turn_on + entity_id: switch.living_room_amp + + - service: media_player.turn_on + entity_id: media_player.livingroomCC + + - service: media_player.volume_set + entity_id: + - media_player.livingroomCC + data_template: + volume_level: > + {% if now().strftime("%H")|int < 12 and now().strftime("%H")|int > 6%} + 0.45 + {% elif now().strftime("%H")|int > 12 and now().strftime("%H")|int < 17%} + 0.7 + {% else %} + 0.40 + {% endif %} + + - service: media_player.play_media + data_template: + entity_id: + - media_player.livingroomCC + - media_player.entry_alarm_panel + - media_player.bedroom_alarm_panel + media_content_id: "https://raw.githubusercontent.com/CCOSTAN/Home-AssistantConfig/master/sounds/dog-barking-2-bullmastiff.mp3" + media_content_type: audio/mp4 diff --git a/script/emergency.yaml b/script/emergency.yaml new file mode 100755 index 00000000..ce489e8c --- /dev/null +++ b/script/emergency.yaml @@ -0,0 +1,42 @@ +###################################################################################################### +###Script to turn on Front light FULL bright for 15m when motion is detected and then return to the normal colors. +# action: +# - service: script.emergency +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +###################################################################################################### + +emergency: + sequence: +# Switch all outside front lights to Red to indicate emergency + - service: light.turn_on + entity_id: + - group.outdoor_front_lights + data: + color_name: 'red' + # Flash All LIGHTS + - service: light.turn_on + entity_id: + - group.all_lights + data: + flash: long + # Rachio is already inergrated Natively with Protects to run SPRINKLERS with smoke conditions.. +# - service: ifttt.trigger +# data_template: {"event":"rachio_start_front"} + + # Turn on All LIGHTS 100% Brightness + - service: light.turn_on + entity_id: + - group.all_lights + data: + brightness: 255 + + # Turn on Outside LED lights strobing White + - service: light.turn_on + entity_id: + - light.led_garage_large + - light.led_garage_small + - light.led_outdoor_den + - light.led_garage_snip + data: + effect: white_strobe diff --git a/script/flash_notify.yaml b/script/flash_notify.yaml new file mode 100755 index 00000000..f6eabe87 --- /dev/null +++ b/script/flash_notify.yaml @@ -0,0 +1,16 @@ +###################################################################################################### +###Script to turn on Front light FULL bright for 15m when motion is detected and then return to the normal colors. +# action: +# - service: script.flash_notify +# +###################################################################################################### + +flash_notify: + sequence: + - service: light.turn_on + entity_id: + - light.m1_slider + - light.office_lamp + - light.outdoor_foyer + data: + flash: long diff --git a/script/front_house_motion.yaml b/script/front_house_motion.yaml new file mode 100755 index 00000000..3357a887 --- /dev/null +++ b/script/front_house_motion.yaml @@ -0,0 +1,48 @@ +###################################################################################################### +###[SkyBell HD](http://amzn.to/2dcexIB) Script to turn on Front light FULL bright for 5 to 20m when motion is detected and then return to the normal colors. +# action: +# - service: script.front_house_motion +# +###################################################################################################### + +front_house_motion: + sequence: + - service: logbook.log + data: + name: "SkyBell HD Doorbell:" + message: "Someone is by the door." + + - condition: state + entity_id: sun.sun + state: 'below_horizon' + + - service: input_boolean.turn_on + entity_id: input_boolean.alert_mode + + - service: script.speech_engine + data: + value1: 'Motion has been detected by the front door.' + - service: scene.turn_on + entity_id: scene.front_full_brightness + - service: switch.turn_on + entity_id: + - switch.back_landscaping + - switch.front_landscaping + - service: light.turn_on + data: + entity_id: + - light.outdoor_bathroom + - group.outdoor_pool_lights + brightness: 255 + - service: script.dog_bark + - delay: '00:{{ (range(5, 20)|random|int) }}:00' + - service: light.turn_off + entity_id: + - group.outdoor_front_lights + - group.outdoor_pool_lights + - service: light.turn_on + entity_id: light.outdoor_bathroom + data: + brightness: 15 + - delay: '00:00:10' + - service: script.monthly_color_scene diff --git a/script/header.md b/script/header.md new file mode 100755 index 00000000..18e43d34 --- /dev/null +++ b/script/header.md @@ -0,0 +1,23 @@ +# [![Build Status](https://travis-ci.org/CCOSTAN/Home-AssistantConfig.svg?branch=master)](https://travis-ci.org/CCOSTAN/Home-AssistantConfig) Home-Assistant Config by [@ccostan](http://www.twitter.com/ccostan) +[Home Assistant](https://home-assistant.io/) configuration files (YAMLs) + +Be sure to :star: my repo so you can keep up to date on the daily progress! + +All of my Scripts are in this directory. These scripts can be used over and over by different automations. I try to modulize most of my scripts so that they can be passed variables from different automations and still keep all the settings normailized and centralized. + +#Still have questions on my Config? +Follow me on twitter : [@CCostan](https://twitter.com/ccostan) + +You can also vist my [Blog](http://www.vmwareinfo.com/search/label/iot) for all of my [Home Automation Posts](http://www.vmwareinfo.com/search/label/iot). + +Original mapping work by @beed2112 + +Modified by [@CCOSTAN](https://twitter.com/ccostan) + +Repo : https://github.com/beed2112/condo + +This is a map of the script references from my repo. + + + Sponsor + diff --git a/script/interior_off.yaml b/script/interior_off.yaml new file mode 100755 index 00000000..d16fa35c --- /dev/null +++ b/script/interior_off.yaml @@ -0,0 +1,16 @@ +###################################################################################################### +###Script to shut switches with a 30 second delay to not trample codes +### Sample Call +# action: +# - service: script.interior_off +###################################################################################################### + +interior_off: + sequence: + - service: light.turn_off + entity_id: + - group.interior_lights + - service: script.switch_turn_off_all + - service: media_player.turn_off + entity_id: + - group.media_players diff --git a/script/monthly_color_scene.yaml b/script/monthly_color_scene.yaml new file mode 100755 index 00000000..2b3040b6 --- /dev/null +++ b/script/monthly_color_scene.yaml @@ -0,0 +1,94 @@ +###################################################################################################### +###Script to turn on scene for the appropriate month for the front of the house but only when the sun is down. +# action: +# - service: script.monthly_color_scene +# +# scenes should be named month_[01-12]_colors (month_06_colors) +# Color help - http://www.esbnyc.com/explore/tower-lights/calendar +###################################################################################################### + +monthly_color_scene: + sequence: + - condition: state + entity_id: sun.sun + state: 'below_horizon' + + - service: scene.turn_on + data_template: + entity_id: > + scene.month_ + {%- if states.sensor.flag.state == "True" -%} + RWB + {%- elif now().strftime("%m%d")|int == 101 -%} + new_years_day + {%- elif now().strftime("%m%d")|int >= 210 + and now().strftime("%m%d")|int <= 214-%} + valentine + {%- elif now().strftime("%m%d")|int == 228 -%} + marti_gras + {%- elif now().strftime("%m%d")|int == 314 -%} + pi + {%- elif now().strftime("%m%d")|int >= 315 + and now().strftime("%m%d")|int <= 317-%} + st_patty + {%- elif now().strftime("%m%d")|int >= 414 + and now().strftime("%m%d")|int <= 416-%} + easter + {%- elif now().strftime("%m%d")|int == 422 -%} + st_patty + {%- elif now().strftime("%m%d")|int == 504 -%} + starwars + {%- elif now().strftime("%m%d")|int == 505 -%} + cinco_de_mayo + {%- elif now().strftime("%m%d")|int == 514 -%} + valentine + {%- elif now().strftime("%m%d")|int == 618 -%} + fathers_day + {%- elif now().strftime("%m%d")|int >= 1001 + and now().strftime("%m%d")|int <= 1031-%} + halloween + {%- elif now().strftime("%m%d")|int >= 1123 + and now().strftime("%m%d")|int <= 1124-%} + thanksgiving + {%- elif now().strftime("%m%d")|int >= 1125 + and now().strftime("%m%d")|int <= 1211-%} + christmas + {%- elif now().strftime("%m%d")|int >= 1212 + and now().strftime("%m%d")|int <= 1220-%} + hanukkah + {%- elif now().strftime("%m%d")|int >= 1221 + and now().strftime("%m%d")|int <= 1230-%} + christmas + {%- elif now().strftime("%m%d")|int == 1231 -%} + new_years_day + {%- else -%} + standard + {%- endif -%}_colors + + +# http://www.calendar-365.com/holidays/2017.html +# 101 New_years_day (colorloop) +# RWB 212 Lincoln's Birthday +# 214 Valentine's Day (pink, red) +# RWB 220 President's Day +# 228 Mardi Gras (purple, green, gold ) +# 317 st Patty (green) +# 414 Good Friday +# 416 Easter +# 422 Earth Day +# 505 Cinco de Mayo (green, white, red) +# 514 Mother's Day (pink, red) - Same as Valentine +# RWB 520 Armed Forces Day +# RWB 529 Memorial Day +# RWB 614 Flag Day +# 618 Fathers day (Orange, Blue) +# RWB 704 July 4th +# RWB 904 Labor Day +# RWB 911 Patriots day +# RWB 1009 columbus day +# 1005 - 1031 halloween +# RWB 1111 veterans day +# 1123 Thanksgiving +# 1212 Hanukkah start 8 days. +# 1225 Chrismas +# 1231 New years eve diff --git a/script/notify_engine.yaml b/script/notify_engine.yaml new file mode 100755 index 00000000..e05e25ce --- /dev/null +++ b/script/notify_engine.yaml @@ -0,0 +1,32 @@ +###################################################################################################### +###Script to send notifications to IFTTT to notify me on the mobile Phone! Call like this: + # action: + # service: script.notify_engine + # data_template: + # value1: 'Startup: Home Assistant is Up and Running!' + # value2: '' + # value3: "{{ trigger.to_state.state }}" + # who: "stacey | carlo | paige | family | parents" + + # IFTTT Maker channel should look like this: https://files.gitter.im/home-assistant/home-assistant/phkx/blob +###################################################################################################### + +notify_engine: + sequence: + # - service: ifttt.trigger + # data_template: {"event":"notify_engine", "value1":"{{ value1 }}", "value2":"{{ value2 }}", "value3":"{{ value3 }}"} + + - service_template: > + {% if who == 'stacey' %} + notify.ios_staceys_iphone + {% elif who == 'carlo' %} + notify.ios_carlo_6s + {% elif who == 'parents' %} + notify.ios_parents + {% else %} + notify.ios_family + {% endif %} + data_template: + message: "{{ value1 }} {{ value2 }} {{ value3 }}" + data: + subtitle: "Home Assistant Notify" diff --git a/script/skybell_pressed.yaml b/script/skybell_pressed.yaml new file mode 100755 index 00000000..5d6bcc75 --- /dev/null +++ b/script/skybell_pressed.yaml @@ -0,0 +1,27 @@ +###################################################################################################### +###[SkyBell HD](http://amzn.to/2dcexIB) +# Script to turn on Front light FULL bright for 15m when motion is detected and then return to the normal colors. +# action: +# - service: script.skybell_pressed +# +###################################################################################################### + +skybell_pressed: + sequence: + - service: logbook.log + data: + name: "SkyBell HD Doorbell:" + message: "Someone Pressed the Doorbell." + + - service: script.flash_notify + - service: script.speech_engine + data: + value1: 'Please check the Front Door. Someone Pressed the Doorbell.' + + - service: notify.ios_family + data: + message: Someone Pressed the Doorbell! + data: + push: + category: camera + entity_id: camera.stone_door diff --git a/script/speech_engine.yaml b/script/speech_engine.yaml new file mode 100755 index 00000000..26a384ba --- /dev/null +++ b/script/speech_engine.yaml @@ -0,0 +1,232 @@ +###################################################################################################### +###Script to send notifications to the ChromeCast Audios during normal hours and only when we are home! Call like this: + # action: + # service: script.speech_engine + # data: + # call_no_announcement: + # call_dark_outside: + # call_window_check: + # call_garage_check: + # call_responsibilities + # call_light_check + # call_inside_weather + # call_outside_weather +# # @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +###################################################################################################### + +speech_engine: + sequence: + - condition: or + conditions: + - condition: state + entity_id: group.family + state: 'home' + - condition: state + entity_id: input_boolean.guest_mode + state: 'on' + + - service: script.speech_processing + data_template: + media_player: >- + {% if media_player | length == 0 %} + {% set media_player = [ + 'media_player.livingroomcc', + 'media_player.alarm_clock', + 'media_player.bedroom_alarm_panel' + ] %} + {% endif %} + + {% if media_player is not string and media_player is sequence %} + {% set media_player = media_player|join(', ') %} + {% endif %} + + {{ media_player }} + + speech_message: >- + {%- macro dark_outside() -%} + {{ [ + 'It is pretty dark outside. I will turn on the outside lights now.', + 'It is a little past Sunset. Time to turn on the outside lights. I am on it.', + 'I will switch on the outside lights. It is getting dark outside.', + 'Time to turn on the front lights. I will take care of it.' + ]|random }} + {%- endmacro -%} + + {%- macro responsibilities() -%} + {% if now().strftime('%a') == 'Wed' or now().strftime('%a') == 'Sun' %} + Today is {{ now().strftime('%A') }} and {{ now().strftime('%A') }} is garbage day. + {% endif %} + {% if now().strftime('%a') == 'Wed' %} + Both Recycling and regular Garbage goes out. Please take out all of the garbage cans tonight. + {% endif %} + {% if now().strftime('%j')|int % 2 != 0 %} + Today is Justin's day to do the chores. + {% else %} + Today is Paige's day to do the chores. + {% endif %} + {%- endmacro -%} + + {%- macro inside_weather() -%} + Inside the house, it is {{ states.climate.downstairs.attributes['current_temperature'] }} degrees with around {{ states('sensor.downstairs_thermostat_humidity') }} percent humidity. + {%- endmacro -%} + + {%- macro outside_weather() -%} + Outside, it is going to be {{ states('sensor.dark_sky_minutely_summary') }} + {%- endmacro -%} + + {%- macro light_check() -%} + {% if states.group.all_lights.state != 'off' -%} + There are + {% for state in states.light if state.state == 'on' -%} + {%- if loop.last -%} + {{ loop.index }} + {%- endif -%} + {%- endfor %} + lights on right now. + + {% set comma = joiner(', ') %} + The + {% for group in states.group|groupby('state') -%} + {%- for entity in group.list if entity.state == 'on' and entity.name.split(' ')[1]|lower == 'lights' and entity.name.split(' ')[0]|lower != 'all' and entity.name.split(' ')[0]|lower != 'interior' -%} + {{ ' and' if loop.last and not loop.first else comma() }} + {{ entity.name }} + {%- endfor -%} + {%- endfor -%} + . + {%- endif -%} + {%- endmacro -%} + + {%- macro window_check() -%} + {% if states.group.entry_points.state != 'off' -%} + {% set comma = joiner(', ') %} + The + {% for state in states.binary_sensor if state.state == 'on' and state.attributes.device_class == 'opening' -%} + {%- endfor %} + {% for group in states.binary_sensor|groupby('state') -%} + {%- for entity in group.list if entity.state == 'on' and entity.attributes.device_class == 'opening' -%} + {{ ' and' if loop.last and not loop.first else comma() }} + {{ entity.attributes.friendly_name }} + {%- endfor -%} + {% endfor %} + need to be closed. + {%- endif -%} + {%- endmacro -%} + + {%- macro garage_check() -%} + {% if states.group.garage_doors.state !='closed' -%} + The + {%- for state in states.cover -%} + {%- endfor %} + {% for group in states.cover|groupby('state') -%} + {%- for entity in group.list if entity.state == 'open' and entity.attributes.device_class == 'garage' -%} + {{ ' and' if loop.last and not loop.first }} + {{ entity.attributes.friendly_name }} + {%- endfor -%} + {%- endfor %} + need to be closed. + {%- endif -%} + {%- endmacro -%} + + {%- macro medicine() -%} + {% if is_state('input_boolean.medicine', 'off') -%} + It looks like Carlo has not taken his medicine yet. Please make sure Carlo takes his medicine now. + {% endif -%} + {%- endmacro -%} + + {%- macro iss() -%} + {% if is_state('binary_sensor.iss', 'on') -%} + Here is something interesting. The international space station is above us now. There are {{ states.binary_sensor.iss.attributes['number_of_people_in_space'] }} people in space right now. + {{ outside_weather() }} + {% endif -%} + {%- endmacro -%} + + {%- macro pihole() -%} + {% if states.sensor.pihole_ads_blocked_today.state|int > 10000 -%} + We blocked {{ states.sensor.pihole_ads_blocked_today.state }} ads. That is {{ states.sensor.pihole_ads_percentage_blocked_today.state }}% of our internet traffic. + {% endif -%} + {%- endmacro -%} + + {%- macro moon() -%} + {%- if states.sensor.moon.state == 'Full moon' -%} + Check out the full moon tonight! + {%- endif -%} + {%- endmacro -%} + + {%- macro holiday() -%} + {% if states.sensor.holiday.state != '' %} + Today is {{ states.sensor.holiday.state }}. + {% endif %} + {%- endmacro -%} + + {# ********************************************* #} + {# ******** Start the Speech routines ******** #} + {# ********************************************* #} + + {% if call_no_announcement != 1 %} + {% if now().strftime('%H')|int < 12 and now().strftime('%H')|int > 6 %} + Good morning. + {% elif now().strftime('%H')|int >= 12 and now().strftime('%H')|int < 17 %} + Good afternoon. + {% else %} + Good evening. + {% endif %} + {% endif %} + + {# Called from Annoucenments #} + {{ personarriving }} + + {# Called from Nest when thermostats turn on #} + {{ NestStatus }} + + {% if call_inside_weather == 1 %} + {{ inside_weather() }} + {% endif %} + + {% if call_outside_weather == 1 and is_state('sun.sun', 'above_horizon') %} + {{ outside_weather() }} + {% endif %} + + {{ DoorOpened }} + {{ DoorClosed }} + + {% if call_dark_outside == 1 %} + {{ dark_outside() }} + {% endif %} + + {% if call_garage_check == 1 or is_state('sun.sun', 'below_horizon') %} + {{ garage_check() }} + {% endif %} + + {% if (call_window_check == 1 or is_state('sun.sun', 'below_horizon')) or is_state('group.entry_points', 'on') %} + {{ window_check() }} + {% endif %} + + {{ NewDevice }} + + {% if call_light_check == 1 %} + {{ light_check() }} + {% endif %} + + {% if call_responsibilities == 1 %} + {{ responsibilities() }} + {% endif %} + + {% if now().strftime('%H')|int > 21 %} + {{ medicine() }} + {% endif %} + + {% if value1 is not none %} + {{ value1 }} + {% endif %} + + {# call a Random fact about the house #} + {{ ([iss, pihole, moon]|random)() }} + + {{ holiday() }} + + - service: input_boolean.turn_off + data: + entity_id: + - input_boolean.home_stats + - input_boolean.responsibilities diff --git a/script/speech_processing.yaml b/script/speech_processing.yaml new file mode 100755 index 00000000..a2c9a211 --- /dev/null +++ b/script/speech_processing.yaml @@ -0,0 +1,76 @@ +###################################################################################################### +###Script to actually send notifications to the ChromeCast Audios during normal hours and only when we are home! Call like this: + # action: + # service: script.speech_engine + # message: +# # @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +###################################################################################################### + +speech_processing: + sequence: + - service: mqtt.publish + data_template: + topic: 'polly/lastmsg' + payload: "This message is from {{ now().strftime('%-I') }}:{{ now().strftime('%M') }} {{ now().strftime('%p') }}. {{ speech_message }}" + retain: true + + - condition: and + conditions: + - condition: or + conditions: + - condition: state + entity_id: group.family + state: 'home' + - condition: state + entity_id: input_boolean.guest_mode + state: 'on' + - condition: or + conditions: + - condition: and + conditions: + - condition: state + entity_id: group.bed + state: 'off' + - condition: time + after: '08:00:00' + before: '20:00:00' + - condition: state + entity_id: input_boolean.alert_mode + state: 'on' + - condition: state + entity_id: input_boolean.speech_notifications + state: 'on' + + - service: switch.turn_on + data: + entity_id: switch.living_room_amp + + - service: media_player.volume_set + data_template: + entity_id: > + {{ media_player }} + volume_level: >- + {% if now().strftime('%H')|int < 12 and now().strftime('%H')|int > 6 %} + 0.3 + {% elif now().strftime('%H')|int > 12 and now().strftime('%H')|int < 20 %} + 0.5 + {% else %} + 0.3 + {% endif %} + + - service: tts.amazon_polly_say + data_template: + entity_id: > + {{ media_player }} + message: >- + + {{ speech_message }} + + cache: true + + - service: input_boolean.turn_off + data: + entity_id: + - input_boolean.alert_mode + - input_boolean.lastmsg diff --git a/script/speechcons.yaml.disabled b/script/speechcons.yaml.disabled new file mode 100755 index 00000000..1922beb9 --- /dev/null +++ b/script/speechcons.yaml.disabled @@ -0,0 +1,48 @@ +###################################################################################################### +###Script to send notifications to the ChromeCast Audios during normal hours and only when we are home! Call like this: + # action: + # service: script.speechcons + # data_template: + # speechcon: 'Bazinga' +# @CCOSTAN +# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig +###################################################################################################### + +speechcon: + sequence: + - condition: template + value_template: > + {% if is_state('media_player.livingroomCC', 'playing') %} + false + {% else %} + true + {% endif %} + - condition: state + entity_id: input_boolean.speech_notifications + state: 'on' + - service: switch.turn_on + entity_id: switch.living_room_amp + + - service: media_player.turn_on + entity_id: media_player.livingroomCC + + - service: media_player.volume_set + entity_id: + - media_player.livingroomCC + data_template: + volume_level: > + {% if now().strftime("%H")|int < 12 and now().strftime("%H")|int > 6%} + 0.3 + {% elif now().strftime("%H")|int > 12 and now().strftime("%H")|int < 17%} + 0.6 + {% else %} + 0.3 + {% endif %} + + - service: media_player.play_media + entity_id: + - media_player.LivingRoomCC + data_template: + media_content_id: > + "https://raw.githubusercontent.com/CCOSTAN/Home-AssistantConfig/master/sounds/speechcons/{{speechcon}}._TTH_.mp3" + media_content_type: audio/mp4 diff --git a/script/switch_turn_off_all.yaml b/script/switch_turn_off_all.yaml new file mode 100755 index 00000000..c9f9b8c3 --- /dev/null +++ b/script/switch_turn_off_all.yaml @@ -0,0 +1,13 @@ +###################################################################################################### +###Script to shut switches with a 30 second delay to not trample codes +### Sample Call +# action: +# - service: script.switch_turn_off_all +###################################################################################################### + +switch_turn_off_all: + sequence: + - service: switch.turn_off + entity_id: group.interior_switches + - service: switch.turn_off + entity_id: switch.living_room_amp diff --git a/script/tweet.yaml b/script/tweet.yaml new file mode 100755 index 00000000..27cdf432 --- /dev/null +++ b/script/tweet.yaml @@ -0,0 +1,11 @@ +###################################################################################################### +###Script to send notifications to Twitter as @BearStoneHA. +## Enhancements by @dale3h +###################################################################################################### + +tweet_engine: + sequence: + - service: notify.BearStoneHA + data_template: + message: >- + {{ tweet }} #IOT #SmartHome diff --git a/sensor/MQTT.yaml b/sensor/MQTT.yaml new file mode 100755 index 00000000..c25513c5 --- /dev/null +++ b/sensor/MQTT.yaml @@ -0,0 +1,11 @@ +################################################### +## Various MQTT sensors +################################################### + +- platform: mqtt + state_topic: "ifttt/rachio/watering_time" + name: "Rachio_watering_time" + +- platform: mqtt + state_topic: "dash/medicine/medicine_time" + name: "Medicine time" diff --git a/sensor/date_time.yaml b/sensor/date_time.yaml new file mode 100755 index 00000000..1534808f --- /dev/null +++ b/sensor/date_time.yaml @@ -0,0 +1,4 @@ +- platform: time_date + display_options: + - 'time' + - 'date' \ No newline at end of file diff --git a/sensor/garadget.yaml b/sensor/garadget.yaml new file mode 100755 index 00000000..5889a548 --- /dev/null +++ b/sensor/garadget.yaml @@ -0,0 +1,36 @@ +################################### +## Garadget_Stuff - [Garadget](http://amzn.to/2jQLpVQ) - Garage Door opener/sensor +################################### + +- platform: template + sensors: + small_garage_status: + friendly_name: 'State of the door' + value_template: '{{ states.cover.small_garage.state }}' + small_garage_time_in_state: + friendly_name: 'Time Since Change' + value_template: '{{ states.cover.small_garage.attributes["time_in_state"] }}' + small_garage_wifi_signal_strength: + friendly_name: 'WiFi strength' + value_template: '{{ states.cover.small_garage.attributes["wifi_signal_strength"] }}' + unit_of_measurement: 'dB' + small_garage_reflection_rate: + friendly_name: 'Reflection Rate' + value_template: '{{ states.cover.small_garage.attributes["sensor_reflection_rate"] }}' + + +- platform: template + sensors: + large_garage_status: + friendly_name: 'State of the door' + value_template: '{{ states.cover.large_garage.state }}' + large_garage_time_in_state: + friendly_name: 'Time Since Change' + value_template: '{{ states.cover.large_garage.attributes["time_in_state"] }}' + large_garage_wifi_signal_strength: + friendly_name: 'WiFi strength' + value_template: '{{ states.cover.large_garage.attributes["wifi_signal_strength"] }}' + unit_of_measurement: 'dB' + large_garage_reflection_rate: + friendly_name: 'Reflection Rate' + value_template: '{{ states.cover.large_garage.attributes["sensor_reflection_rate"] }}' diff --git a/sensor/hass_stats.yaml b/sensor/hass_stats.yaml new file mode 100755 index 00000000..c4b53ddd --- /dev/null +++ b/sensor/hass_stats.yaml @@ -0,0 +1,27 @@ +################################################### +## * Special HASS related sensors - Thanks @torn8o +################################################### + +- platform: version + name: HA Installed Version + scan_interval: 86400 + +- platform: command_line + name: "HA Uptime" + command: echo "$(($(date +%s) - $(date -d "$(head -n1 /config/home-assistant.log | cut -d' ' -f-2)" +%s)))" + scan_interval: 720 + value_template: >- + {% set uptime = value | int %} + {% set seconds = uptime % 60 %} + {% set minutes = ((uptime % 3600) / 60) | int %} + {% set hours = ((uptime % 86400) / 3600) | int %} + {% set days = (uptime / 86400) | int %} + {%- if days > 0 -%} + {%- if days == 1 -%} + 1 day + {%- else -%} + {{ days }} days + {%- endif -%} + {{ ', ' }} + {%- endif -%} + {{ '%02d' % hours }}:{{ '%02d' % minutes }} diff --git a/sensor/nest.yaml b/sensor/nest.yaml new file mode 100755 index 00000000..ca94582b --- /dev/null +++ b/sensor/nest.yaml @@ -0,0 +1,15 @@ +################################################### +## * [Nest Thermostats](http://amzn.to/2eAhB1k) +################################################### + +- platform: template + sensors: + upstairs_away_mode: + entity_id: climate.upstairs + value_template: "{{ is_state_attr('climate.upstairs', 'away_mode', 'on') }}" + +- platform: template + sensors: + downstairs_away_mode: + entity_id: climate.downstairs + value_template: "{{ is_state_attr('climate.downstairs', 'away_mode', 'on') }}" \ No newline at end of file diff --git a/sensor/speedtest.yaml b/sensor/speedtest.yaml new file mode 100755 index 00000000..54b6558e --- /dev/null +++ b/sensor/speedtest.yaml @@ -0,0 +1,10 @@ +- platform: speedtest + minute: 30 + hour: + - 0 + - 6 + - 12 + - 18 + monitored_conditions: + - download + - upload diff --git a/sensor/systemmonitor.yaml b/sensor/systemmonitor.yaml new file mode 100755 index 00000000..b21d722c --- /dev/null +++ b/sensor/systemmonitor.yaml @@ -0,0 +1,58 @@ +- platform: template + sensors: + since_last_boot_templated: + value_template: >- + {%- set slb = states.sensor.since_last_boot.state.split(' ') -%} + {%- set count = slb | length -%} + {%- set hms = slb[count - 1] -%} + {%- set hms_trimmed = hms.split('.')[0] -%} + {%- set hms_split = hms_trimmed.split(':') -%} + {%- set hours = hms_split[0] | int -%} + {%- set minutes = hms_split[1] | int -%} + {%- set seconds = hms_split[2] | int -%} + + {%- if count == 3 -%} + {{ slb[0] ~ ' ' ~ slb[1] ~ ' ' }} + {%- endif -%} + {%- if hours > 0 -%} + {%- if hours == 1 -%} + 1 hour + {%- else -%} + {{ hours }} hours + {%- endif -%} + {%- endif -%} + {%- if minutes > 0 -%} + {%- if hours > 0 -%} + {{ ', ' }} + {%- endif -%} + {%- if minutes == 1 -%} + 1 minute + {%- else -%} + {{ minutes }} minutes + {%- endif -%} + {%- endif -%} + {%- if seconds > 0 -%} + {%- if hours > 0 or minutes > 0 -%} + {{ ', ' }} + {%- endif -%} + {%- if seconds == 1 -%} + 1 second + {%- else -%} + {{ seconds }} seconds + {%- endif -%} + {%- endif -%} + +- platform: rest + scan_interval: 86400 + resource: http://ip.jsontest.com + name: External IP + value_template: '{{ value_json.ip }}' + +############################################################################################################# +### This part of the automation is hidden due to the IP address exposed ## +# - platform: template + # sensors: + # ipchange: + # entity_id: sensor.external_ip + # value_template: "{%- if is_state('sensor.external_ip', 'xxx.xxx.xxx.xxx') -%} False {%- elif is_state('sensor.external_ip', 'unknown' ) -%} False {%- else -%} True {%- endif %}" +############################################################################################################# diff --git a/sensor/weather.yaml b/sensor/weather.yaml new file mode 100755 index 00000000..743da063 --- /dev/null +++ b/sensor/weather.yaml @@ -0,0 +1,31 @@ +- platform: darksky + api_key: !secret forecast_key + monitored_conditions: +# - summary +# - precip_type + - precip_intensity + - precip_intensity_max + - temperature +# - dew_point + - wind_speed +# - wind_bearing + - cloud_cover + - humidity +# - nearest_storm_distance + - minutely_summary +# - pressure +# - visibility +# - ozone + - uv_index + +- platform: nest + monitored_conditions: +# - 'temperature' +# - 'target' + - 'humidity' +# - 'operation_mode' +# - 'last_connection' +# - 'co_status' +# - 'smoke_status' + +- platform: moon diff --git a/shell_command/flush_pm2_logs.yaml b/shell_command/flush_pm2_logs.yaml new file mode 100755 index 00000000..d1f84e89 --- /dev/null +++ b/shell_command/flush_pm2_logs.yaml @@ -0,0 +1,2 @@ +flush_pm2_logs: >- + sudo -u pi -H /usr/bin/pm2 flush diff --git a/shell_command/restart_homebridge.yaml b/shell_command/restart_homebridge.yaml new file mode 100755 index 00000000..d841fc2d --- /dev/null +++ b/shell_command/restart_homebridge.yaml @@ -0,0 +1,2 @@ +restart_homebridge: >- + sudo -u pi -H /usr/bin/pm2 restart homebridge diff --git a/shell_scripts/HAUpdate.sh b/shell_scripts/HAUpdate.sh new file mode 100755 index 00000000..0a9d9ad0 --- /dev/null +++ b/shell_scripts/HAUpdate.sh @@ -0,0 +1,12 @@ +## These scripts are run from /home/pi + +#!/bin/bash + +cd /home/hass/.homeassistant +source /srv/hass/hass_venv/bin/activate + +echo "Processing update" +pip3 install --upgrade homeassistant + +hass --script check_config +exit diff --git a/shell_scripts/HAUpdateDev.sh b/shell_scripts/HAUpdateDev.sh new file mode 100755 index 00000000..d3e86a43 --- /dev/null +++ b/shell_scripts/HAUpdateDev.sh @@ -0,0 +1,14 @@ +## These scripts are run from /home/pi + +#!/bin/bash + +echo "Setting up Environment" +cd /home/hass/.homeassistant +source /srv/hass/hass_venv/bin/activate + +echo "Processing update" +pip3 install --upgrade git+git://github.com/balloob/home-assistant.git@dev + +echo "Code Check" +hass --script check_config +exit diff --git a/shell_scripts/Jinja Code.py b/shell_scripts/Jinja Code.py new file mode 100755 index 00000000..cd06a957 --- /dev/null +++ b/shell_scripts/Jinja Code.py @@ -0,0 +1,44 @@ +You can use this code to quickly create files from the template editor in HA. I use it mainly for `emulated_hue` and to quickly add in new Customize options to all things HA! + +For the sandbox. +{% set trigger = {'entity_id':'sensor.downstairs_thermostat_hvac_state','to_state':'cooling'} %} + +######################################################### +Create fast Customize for groups, sensors, covers etc... Just change that first line below 'sensor' to 'group', 'covers' etc.. + +{% for state in states.sensor -%} + {% if loop.first %} +{% elif loop.last %} +{% else %} +{% endif %} +{{- state.entity_id }}: + friendly_name: '{{ state.attributes.friendly_name|replace("_"," ",)|title() if state.attributes.friendly_name is defined else state.name|replace("_"," ",)|title() }}' + emulated_hue_hidden: {{state.attributes.emulated_hue_hidden if state.attributes.emulated_hue_hidden is defined else 'False' }} + hidden: {{state.attributes.hidden if state.attributes.hidden is defined else "False"}} + homebridge_hidden: {{state.attributes.homebridge_hidden if state.attributes.homebridge_hidden is defined else "true"}} + {{'icon: '+ state.attributes.icon if state.attributes.icon is defined}} + {{'homebridge_cover_type: '+ state.attributes.homebridge_cover_type if state.attributes.homebridge_cover_type is defined}} + {{'assumed_state: '+ state.attributes.assumed_state if state.attributes.assumed_state is defined}} +{% endfor -%} + +######################################################### +#This code lists out EVERY possible entity and attribute for that entity. +# source: https://github.com/skalavala/smarthome/blob/master/Entities.md +######################################################### + +{{ "_".ljust(90, "_") }} +{%- set domains = [states.light, states.switch, states.automation, states.device_tracker, states.group, states.media_player, states.proximity, states.script, states.zone, states.zwave, states.sensor, states.calendar ] %} +{{ "Entity ID".ljust(50) }}{{ "Entity Name" }} +{%- for domain in domains -%} +{% for item in domain %} +{{ "_".ljust(90, "_") }} +{{ item.entity_id.ljust(50) }}{{ item.name }} +{% for attrib in item.attributes %} +{%- if attrib is defined %} + {{attrib.ljust(50)}}: {{ item.attributes[attrib] }} +{%- endif %} +{%- endfor %} +{%- endfor %} +{%- endfor %} + +######################################################### diff --git a/shell_scripts/codesend b/shell_scripts/codesend new file mode 100755 index 00000000..0f40b5ef Binary files /dev/null and b/shell_scripts/codesend differ diff --git a/shell_scripts/gitupdate.sh b/shell_scripts/gitupdate.sh new file mode 100755 index 00000000..06606526 --- /dev/null +++ b/shell_scripts/gitupdate.sh @@ -0,0 +1,16 @@ +## These scripts are run from /home/pi + +#!/bin/bash + +cd /home/hass/.homeassistant +source /srv/hass/hass_venv/bin/activate +hass --script check_config + +git add . +git status +echo -n "Enter the Description for the Change: " [Minor Update] +read CHANGE_MSG +git commit -m "${CHANGE_MSG}" +git push origin master + +exit diff --git a/shell_scripts/hassuser.sh b/shell_scripts/hassuser.sh new file mode 100755 index 00000000..44b7db5d --- /dev/null +++ b/shell_scripts/hassuser.sh @@ -0,0 +1,17 @@ +## These scripts are run from /home/pi + +#!/bin/bash +cat hassuser + +sudo su -s /bin/bash hass + +# source /srv/hass/hass_venv/bin/activate + +# to Upgrade: + +# pip3 install --upgrade homeassistant - Use HAUpdate.sh script + +# To view The HA logs realtime +# sudo journalctl -u home-assistant -f | ccze + + diff --git a/shell_scripts/homebridge_commands.txt b/shell_scripts/homebridge_commands.txt new file mode 100755 index 00000000..3f3de0e3 --- /dev/null +++ b/shell_scripts/homebridge_commands.txt @@ -0,0 +1,6 @@ +# Restart Homebridge on HASS start +# shell_command: + # restart_homebridge: 'sudo su pi -c "pm2 restart homebridge"' + # start_homebridge: 'sudo su pi -c "pm2 start homebridge"' + # stop_homebridge: 'sudo su pi -c "pm2 stop homebridge"' + \ No newline at end of file diff --git a/shell_scripts/script_notations.sh b/shell_scripts/script_notations.sh new file mode 100755 index 00000000..08165b5c --- /dev/null +++ b/shell_scripts/script_notations.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +# this script uses hard-coded paths +# This deletes the readme file and begins rebuilding it.. + +cat /home/hass/.homeassistant/script/header.md > /home/hass/.homeassistant/script/README.md + +grep -e '^[a-z]' /home/hass/.homeassistant/script/*.yaml | tr : '\n' > /tmp/scriptnames.txt + +sed -i '/^$/d' /tmp/scriptnames.txt + + +for item in `cat /tmp/scriptnames.txt` +do + + res=`grep -R script.$item /home/hass/.homeassistant/. --include=*.yaml` + echo "\n $item \n" | sed 's|/home/hass/\.homeassistant/| https://github\.com/CCOSTAN/Home-AssistantConfig/blob/master/|g'>> /home/hass/.homeassistant/script/README.md + echo "\n $res \n" | sed 's|/home/hass/\.homeassistant/\.| https://github\.com/CCOSTAN/Home-AssistantConfig/blob/master|g' >> /home/hass/.homeassistant/script/README.md + +sed -i '/^$/d' /home/hass/.homeassistant/script/README.md + +done +cat /home/hass/.homeassistant/script/README.md diff --git a/shell_scripts/zwave_commands.txt b/shell_scripts/zwave_commands.txt new file mode 100755 index 00000000..053f9c5e --- /dev/null +++ b/shell_scripts/zwave_commands.txt @@ -0,0 +1,11 @@ +Turn off Disco lights +echo -e -n "\x01\x08\x00\xF2\x51\x01\x00\x05\x01\x51" > /dev/serial/by-id/usb-0658_0200-if00 + +Turn on Disco lights +echo -e -n "\x01\x08\x00\xF2\x51\x01\x01\x05\x01\x50" > /dev/serial/by-id/usb-0658_0200-if00 + + +USING THE OZWCP WEB APPLICATION +cd /srv/hass/src/open-zwave-control-panel/; sudo ./ozwcp -p 8888 + +Specify your zwave controller, for example /dev/ttyACM0 and hit initialize \ No newline at end of file diff --git a/sounds/cuckoo-clock-01.wav b/sounds/cuckoo-clock-01.wav new file mode 100755 index 00000000..bbaa59f7 Binary files /dev/null and b/sounds/cuckoo-clock-01.wav differ diff --git a/sounds/cuckoo-clock-02.wav b/sounds/cuckoo-clock-02.wav new file mode 100755 index 00000000..5970198e Binary files /dev/null and b/sounds/cuckoo-clock-02.wav differ diff --git a/sounds/cuckoo-clock-03.wav b/sounds/cuckoo-clock-03.wav new file mode 100755 index 00000000..e41eaae4 Binary files /dev/null and b/sounds/cuckoo-clock-03.wav differ diff --git a/sounds/cuckoo-clock-04.wav b/sounds/cuckoo-clock-04.wav new file mode 100755 index 00000000..cd996eca Binary files /dev/null and b/sounds/cuckoo-clock-04.wav differ diff --git a/sounds/cuckoo-clock-05.wav b/sounds/cuckoo-clock-05.wav new file mode 100755 index 00000000..1e332113 Binary files /dev/null and b/sounds/cuckoo-clock-05.wav differ diff --git a/sounds/cuckoo-clock-06.wav b/sounds/cuckoo-clock-06.wav new file mode 100755 index 00000000..6afaa447 Binary files /dev/null and b/sounds/cuckoo-clock-06.wav differ diff --git a/sounds/cuckoo-clock-07.wav b/sounds/cuckoo-clock-07.wav new file mode 100755 index 00000000..6efb2068 Binary files /dev/null and b/sounds/cuckoo-clock-07.wav differ diff --git a/sounds/cuckoo-clock-08.wav b/sounds/cuckoo-clock-08.wav new file mode 100755 index 00000000..bfb8a24c Binary files /dev/null and b/sounds/cuckoo-clock-08.wav differ diff --git a/sounds/cuckoo-clock-09.wav b/sounds/cuckoo-clock-09.wav new file mode 100755 index 00000000..d333c8b2 Binary files /dev/null and b/sounds/cuckoo-clock-09.wav differ diff --git a/sounds/cuckoo-clock-10.wav b/sounds/cuckoo-clock-10.wav new file mode 100755 index 00000000..6cd648f5 Binary files /dev/null and b/sounds/cuckoo-clock-10.wav differ diff --git a/sounds/cuckoo-clock-11.wav b/sounds/cuckoo-clock-11.wav new file mode 100755 index 00000000..c363b2d2 Binary files /dev/null and b/sounds/cuckoo-clock-11.wav differ diff --git a/sounds/cuckoo-clock-12.wav b/sounds/cuckoo-clock-12.wav new file mode 100755 index 00000000..ed6d762f Binary files /dev/null and b/sounds/cuckoo-clock-12.wav differ diff --git a/sounds/dog-barking-2-bullmastiff.mp3 b/sounds/dog-barking-2-bullmastiff.mp3 new file mode 100755 index 00000000..1f730822 Binary files /dev/null and b/sounds/dog-barking-2-bullmastiff.mp3 differ diff --git a/sounds/german-shephard.mp3 b/sounds/german-shephard.mp3 new file mode 100755 index 00000000..2c04ac17 Binary files /dev/null and b/sounds/german-shephard.mp3 differ diff --git a/sounds/one-tone-chime.mp3 b/sounds/one-tone-chime.mp3 new file mode 100755 index 00000000..907f6a40 Binary files /dev/null and b/sounds/one-tone-chime.mp3 differ diff --git a/sounds/speechcons/bon_appetit._TTH_.mp3 b/sounds/speechcons/bon_appetit._TTH_.mp3 new file mode 100755 index 00000000..af69fe72 Binary files /dev/null and b/sounds/speechcons/bon_appetit._TTH_.mp3 differ diff --git a/sounds/speechcons/ouch._TTH_.mp3 b/sounds/speechcons/ouch._TTH_.mp3 new file mode 100755 index 00000000..51e6f47d Binary files /dev/null and b/sounds/speechcons/ouch._TTH_.mp3 differ diff --git a/sounds/speechcons/self_destruct.mp3 b/sounds/speechcons/self_destruct.mp3 new file mode 100755 index 00000000..cd561ad8 Binary files /dev/null and b/sounds/speechcons/self_destruct.mp3 differ diff --git a/sounds/twitter-chirp.mp3 b/sounds/twitter-chirp.mp3 new file mode 100755 index 00000000..0cb41796 Binary files /dev/null and b/sounds/twitter-chirp.mp3 differ diff --git a/sounds/two-tone-chime.mp3 b/sounds/two-tone-chime.mp3 new file mode 100755 index 00000000..636e94fc Binary files /dev/null and b/sounds/two-tone-chime.mp3 differ diff --git a/switch/rachio.yaml.disabled b/switch/rachio.yaml.disabled new file mode 100755 index 00000000..ccd7cf0c --- /dev/null +++ b/switch/rachio.yaml.disabled @@ -0,0 +1,6 @@ +###################################################################### +## [Rachio Sprinkler system](http://amzn.to/2eoPKBW) - Smart Sprinkler controller +###################################################################### + +- platform: rachio + access_token: !secret rachio_api diff --git a/switch/rf_outlets.yaml b/switch/rf_outlets.yaml new file mode 100755 index 00000000..549145ab --- /dev/null +++ b/switch/rf_outlets.yaml @@ -0,0 +1,135 @@ +###################################################################### +## Awesome [Etekcity Outlets](http://amzn.to/2efNoBP) control via RF +### connected to +## [433Mhz Transmitter and receiver](http://amzn.to/2dceNY2) +###################################################################### + +- platform: tplink + name: Living_Room_Amp + host: 192.168.10.116 + +# Thanks to @ZOMBU2 for providing me with the right firmware - http://cn-fwversions.ibroadlink.com/firmware/download/10026/20028.bin +- platform: broadlink + host: 192.168.10.218 + mac: '34:EA:34:CC:CE:25' + switches: + kitchen_accents: + friendly_name: "Kitchen Accents" + command_on: 'sjcyAAcSBxMHEgcSBxIUBgcTBxIIEhMGBxITBggSFAYHEhQGBxIHExQGFAYIEwcSFAYTBge8AAAAAAAA' + command_off: 'stgyAAcTBxMHEwcSBxMTBgcTBxMHExMHBxMUBgcTEwcHExMHBxMHExMHEwcTBxMHBxMHEwe9AAAAAAAA' + + kitchen_accents_2: + friendly_name: "Kitchen Accents 2" + command_on: 'sjcyAAcSBxMHEgcSBxIUBgcTBxIIEhMGBxITBggSFAYHEhQGBxIHExQGFAYIEwcSFAYTBge8AAAAAAAA' + command_off: 'stgyAAcTBxMHEwcSBxMTBgcTBxMHExMHBxMUBgcTEwcHExMHBxMHExMHEwcTBxMHBxMHEwe9AAAAAAAA' + + den_outlet: + friendly_name: "Den Outlet" + command_on: 'sjgyAAgSEwYHEhQGBxIIEgcSFAYHEhMGBxIUBgcSFAYUBhMGBxMHEggSBxIHEgcSFAYUBge+AAAAAAAA' + command_off: 'slUyAAcSFAYHEhQGBxMHEgcTFAYHEhQGBxIUBgcSFAYTBhMHBxIHEwcSBxMTBhMHBxMHEwe+AAAAAAAA' + + foyer_outlet: + friendly_name: "Foyer Outlet" + command_on: 'sh8yAAcSBxMHEwcTBxIUBgcTBxMHExMGEwcTBwcTFAYHExMHBxMHEwcSBxMHEgcSEwcTBge9AAAAAAAA' + command_off: 'skIyAAcTBxIHEgcSBxMTBgcTBxIHExQGEwYUBgcTEwcHExQGBxMHEgcTBxITBxMGBxMHEge8AAAAAAAA' + + +# - platform: rpi_rf +# gpio: 17 +# switches: +# # Outlet 1412_1 - ALSO Controls # Outlet 304_1 +# master_bathroom_accents: +# protocol: 1 +# pulselength: 186 +# code_on: 5264691 +# code_off: 5264700 +# signal_repetitions: 40 +# +# # Outlet 304_1 Controlled by Outlet 1412_1 +# master_bathroom_accents_2: +# protocol: 1 +# pulselength: 186 +# code_on: 5330227 +# code_off: 5330236 +# signal_repetitions: 40 +# +# # Outlet 1412_3 +# # Living_Room_Amp: +# 1412_3_Outlet: +# protocol: 1 +# pulselength: 186 +# code_on: 5265155 +# code_off: 5265164 +# signal_repetitions: 40 +# +# # Outlet 1412_2 +# 1412_2_Outlet: +# protocol: 1 +# pulselength: 186 +# code_on: 5264835 +# code_off: 5264844 +# signal_repetitions: 40 +# +# # # Outlet 311_5 +# # Foyer_Outlet: +# # protocol: 1 +# # pulselength: 186 +# # code_on: 292099 +# # code_off: 292108 +# # signal_repetitions: 40 +# +# # # Outlet 311_1 +# # Kitchen_Accents: +# # protocol: 1 +# # pulselength: 186 +# # code_on: 283955 +# # code_off: 283964 +# # signal_repetitions: 40 +# # +# # # Outlet 311_2 : Responds to 311_1 as well. +# # Kitchen_Accent_2: +# # protocol: 1 +# # pulselength: 186 +# # code_on: 284099 +# # code_off: 284108 +# # signal_repetitions: 40 +# +# # Outlet 311_3 +# Printer_Outlet: +# protocol: 1 +# pulselength: 186 +# code_on: 284419 +# code_off: 284428 +# signal_repetitions: 40 +# +# # Outlet 311_4 +# Front_Door_Outlet: +# protocol: 1 +# pulselength: 186 +# code_on: 285955 +# code_off: 285964 +# signal_repetitions: 50 +# +# # Outlet 304_2 +# Living_Room_Outlet: +# protocol: 1 +# pulselength: 186 +# code_on: 5330371 +# code_off: 5330380 +# signal_repetitions: 40 +# +# # # Outlet 304_3 +# # Den_Outlet: +# # protocol: 1 +# # pulselength: 186 +# # code_on: 5330691 +# # code_off: 5330700 +# # signal_repetitions: 50 +# +# # Outlet_304_4 +# Garage_Outlet: +# protocol: 1 +# pulselength: 186 +# code_on: 5332227 +# code_off: 5332236 +# signal_repetitions: 40 diff --git a/travis_secrets.yaml b/travis_secrets.yaml new file mode 100755 index 00000000..9f5e9c06 --- /dev/null +++ b/travis_secrets.yaml @@ -0,0 +1,51 @@ +homeassistant_latitude: 000.0000000 +homeassistant_longitude: 000.0000000 +homeassistant_elevation: 00 +http_api_password: password +http_port: 80 +external_ip: 10.10.10.10 +MQTT_username: MQTT_username +MQTT_password: password +ssl_certificate: 'www_traviswebsite_dot_com.fake_crt' +ssl_key: 'www_traviswebsite.fake_key' +http_base_url: your.website.com +ifttt_key: iftttKEYPassphrase +forecast_key: ForcastKeyphrase +fitbit_user: User@email.com +fitbit_password: abcdefghijklmnopqrstuvwxyz0123456789 +juicenet_access_token: abcdefghijklmnopqrstuvwxyz0123456789 +nest_client_id: secret_nest_client_id +nest_client_secret: secretnestclientid +neato_username: user@email.com +neato_password: password +large_garage_id: 00000000000000000000000 +small_garage_id: 00000000000000000000001 +garadget_username: user@email.com +garadget_password: password +google_cal_clientid: clientidsecretsecretsecret.apps.googleusercontent.com +google_cal_clientsecret: more-secretstuff +sleepiq_username: user@email.com +sleepiq_password: password +aws_access_key_ID: 'AWSACCESSKEYID' +aws_secret_access_key: 'AWSACCESSKEYIDandSECRET' +unifi_username: username +unifi_password: password +unifi_host: host.domain.local +myusps_username: username +myusps_password: password +upsmychoice_username: username +upsmychoice_password: password +wink_username: user@email.com +wink_password: password +uv_mate_key: 933ecdfb-BurnBabyBurn-8237j2d +uv_mate_resource: https://uvimate.herokuapp.com/api/getUVI/82.6341/-83.0211 +rachio_api: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +skybell_username: user@email.com +skybell_password: password +twitter_consumer_key: LotsOfNumbers +twitter_consumer_secret: LotsOfLetters +twitter_access_token: Access-to-BearStoneHA +twitter_access_token_secret: AtBearStoneHASecretAccessTokenCode +cloud_client_id: 'SuperSecretCode' +cloud_user_pool: 'SuperSecretPlace' +cloud_relayer: 'SuperSecretWebThingy' diff --git a/www/custom_ui/floorplan/README.md b/www/custom_ui/floorplan/README.md new file mode 100755 index 00000000..66230fb1 --- /dev/null +++ b/www/custom_ui/floorplan/README.md @@ -0,0 +1,17 @@ +# [![Build Status](https://travis-ci.org/CCOSTAN/Home-AssistantConfig.svg?branch=master)](https://travis-ci.org/CCOSTAN/Home-AssistantConfig) Home-Assistant Config by [@ccostan](http://www.twitter.com/ccostan) +[Home Assistant](https://home-assistant.io/) configuration files (YAMLs) + +Be sure to :star: my repo so you can keep up to date on the daily progress! + +![Screenshot of SmartHome](https://lh3.googleusercontent.com/-vKGF5gdz_VY/WVpP7qjsmjI/AAAAAAADVZ4/sGyiS1PjouUQxrEbWVfot6raxcElv4r-wCHMYCw/s1600/clip_image001%255B4%255D) + +This is the first directory you need for a successful Floorplan installation! + +#Still have questions on my Config? +Follow me on twitter : [@CCostan](https://twitter.com/ccostan) + +You can also vist my [Blog](http://www.vmwareinfo.com/search/label/iot) for all of my [Home Automation Posts](http://www.vmwareinfo.com/search/label/iot). + + + Sponsor + diff --git a/www/custom_ui/floorplan/alarm.css b/www/custom_ui/floorplan/alarm.css new file mode 100755 index 00000000..1bd2d4c5 --- /dev/null +++ b/www/custom_ui/floorplan/alarm.css @@ -0,0 +1,194 @@ + SVG shapes */ + +svg, svg * { + vector-effect: non-scaling-stroke !important; + pointer-events: all !important; +} +/* +/* Hover over */ + +/* Interior Garage */ +#binary_sensor\.mcu1_gpio12.window-opened { + transform: rotate(270deg); + transform-origin: left; +} +/* Back Door */ +#binary_sensor\.mcu2_gpio5.window-opened { + transform: rotate(270deg); + transform-origin: right; +} +#binary_sensor\.kitchen_door_opened.window-opened { + transform: rotate(270deg); + transform-origin: right; +} + +#sensor\.dark_sky_minutely_summary { + fill: #231F26 !important; + fill-opacity: 1.0; +} + +.entity:hover:not(.static-text):not(.static-temp):not(.static-text-date):not:(.static-text-time) { + stroke: #03A9F4 !important; + stroke-width: 1px !important; + stroke-opacity: 1 !important; +} + + +.warning-background, .warning-text-background { + fill: #fcf8e3 !important; + fill-opacity: 1 !important; + stroke: #faebcc !important; + stroke-width: 1px !important; +} + +.static-text +{ + fill: #FFFFA6 !important; + font-family : Helvetica !important; + font-weight : bold !important; + font-size : 15px !important; +} + +.static-text-date +{ + font-family : Helvetica !important; + font-weight : bold !important; + font-size : 16px !important; + fill : #FFFFA6 !important; +} + +.static-text-time +{ + font-family : Helvetica !important; + font-weight : bold !important; + font-size : 35px !important; + fill: #FFFFA6 !important; +} + +.static-temp +{ + font-family: Helvetica !important; + font-size: 22px !important; + fill: #FFFFA6 !important; +} +/* Last motion entity */ + +.last-motion { + stroke: #808080 !important; + stroke-width: 1px !important; + stroke-opacity: 1 !important; +} + +/* Presence */ +.presence-on { + fill: #BDF271 !important; +} + +.presence-off { + fill: #3D3B3F !important; +} + +/* Text Home/Away */ + +.text-home { + fill: #BDF271 !important; +} + +.text-away { + fill: #E7376B !important; +} + +/* switches */ + +.switch-on { + fill: orange !important; +} + +.switch-on-blue { + fill: blue !important; +} + +.switch-off { + fill: #cccccc !important; +} +/* Buttons */ + +.button-on { + fill: #FFFFA6 !important; + fill-opacity: 0.25; +} + +.button-off { + fill: #3D3B3F !important; + fill-opacity: 0.5; +} + +/* Nest Protects */ + +.protect-on { + fill: green !important; +} + +.protect-off { + fill: red !important; +} + +/* Windows / Doors / Entry Points */ + +.window-open { + fill: #c60919 !important; + +} + +.window-closed { + fill: #00FFFF !important; +} + +/* Light */ + +.light-off { + fill: #231F26 !important; + fill-opacity: 1.0; + stroke: black !important; + stroke-width: 1; + stroke-opacity:0.1; +} +.light-off:hover { + transform-origin: center; + transform: scale(2); +} + +.outdoor-light-off { + fill: grey !important; + fill-opacity: 1.0; + stroke: black !important; + stroke-width: 1; + stroke-opacity:0.1; +} +.outdoor-light-off:hover { + transform-origin: center; + transform: scale(2); +} +.light-blue-on { + fill: blue !important; + fill-opacity: 1.0; + stroke: #FFFFA6 !important; + stroke-width: 10; + stroke-opacity: 0.25; +} +.light-blue-on:hover { + transform-origin: center; + transform: scale(3); +} + +.light-on { + fill: yellow !important; + fill-opacity: 1.0; + stroke: #FFFFA6 !important; + stroke-width: 10; + stroke-opacity: 0.25; +} +.light-on:hover { + transform-origin: center; + transform: scale(3); +} diff --git a/www/custom_ui/floorplan/alarm.svg b/www/custom_ui/floorplan/alarm.svg new file mode 100755 index 00000000..47a482a1 --- /dev/null +++ b/www/custom_ui/floorplan/alarm.svg @@ -0,0 +1,1040 @@ + + + + + + + + + + Friday, June 30 + + + + 9:36 PM + + + + + + + + SECOND FLOOR + + LIVING ROOM + + BEDROOM + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MASTER BEDROOM + + LIVING ROOM + + DINING ROOM + + KITCHEN + + BEDROOM + + BEDROOM + + GARAGE + + DINING ROOM + + + STUD + + Y + + + + STUD + + Y + + + + B + + A + + THROOM + + + + B + + A + + THROOM + + + + + + + REFRESH + + + + + + Carlo + + Stacey + + Alarm + + + First Floor + + + Second Floor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OFF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + XX + + + XX + + + away + + home + + + + + XX + + + + XX + + + XX + + XX + + + XX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Bathroom +Master + + + diff --git a/www/custom_ui/floorplan/alarm.yaml b/www/custom_ui/floorplan/alarm.yaml new file mode 100755 index 00000000..046915e8 --- /dev/null +++ b/www/custom_ui/floorplan/alarm.yaml @@ -0,0 +1,285 @@ +name: Alarm Panel +image: /local/custom_ui/floorplan/alarm.svg +stylesheet: /local/custom_ui/floorplan/alarm.css + +rules: + - name: input_booleans + entities: + - input_boolean.guest_mode + - input_boolean.good_night + - group.kitchen_lights + - group.living_room_lights + + states: + - state: 'on' + class: 'button-on' + - state: 'off' + class: 'button-off' + action: + service: homeassistant.toggle + + - name: thermostats_temp + entities: + - climate.downstairs + - climate.upstairs + text_template: '${entity.attributes.current_temperature ? Math.ceil(entity.attributes.current_temperature) + "°": "undefined"}' + class_template: 'return "static-temp";' + + - name: temp_darksky + entities: + - sensor.dark_sky_temperature + text_template: '${entity.state ? Math.ceil(entity.state) + "°": "undefined"}' + class_template: 'return "static-temp";' + + - name: temp_round + entities: + - sensor.downstairs_thermostat_humidity + - sensor.upstairs_thermostat_humidity + - sensor.dark_sky_humidity + text_template: '${entity.state ? Math.ceil(entity.state) : "undefined"}' + class_template: 'return "static-temp";' + + - name: text_states + entities: + - sensor.last_message + text_template: '${entity.state ? entity.state.replace(/\s{3,}/g,"") : "undefined"}' + class_template: 'return "static-text";' + + - name: text_font_date + entities: + - sensor.floorplan_date + text_template: '${entity.state ? entity.state : "undefined"}' + class_template: 'return "static-text-date";' + + - name: text_font_time + entities: + - sensor.floorplan_time + text_template: '${entity.state ? entity.state : "undefined"}' + class_template: 'return "static-text-time";' + + - name: Alarm + entities: + - input_boolean.alert_mode + text_template: '${entity.state ? entity.state : "undefined"}' + states: + - state: 'on' + class: 'text-home' + - state: 'off' + class: 'text-away' + + - name: Family + entities: + - device_tracker.carlo + - device_tracker.stacey + text_template: '${entity.state ? entity.state.replace("not_home", "away") : "undefined"}' + + states: + - state: 'home' + class: 'text-home' + - state: 'not_home' + class: 'text-away' + + - name: switches + entities: + - switch.front_landscaping + - switch.back_landscaping + - switch.printer_outlet + - switch.kitchen_accents + - switch.master_bathroom_accents + - switch.front_door_outlet + - switch.foyer_outlet + - switch.living_room_amp + - switch.garage_outlet + states: + - state: 'on' + class: 'switch-on' + - state: 'off' + class: 'switch-off' + action: + service: homeassistant.toggle + + - name: custom_switches + entities: + - switch.pool_deck + states: + - state: 'on' + class: 'light-blue-on' + - state: 'off' + class: 'outdoor-light-off' + action: + service: homeassistant.toggle + + - name: Lights + entities: + - light.kids_hallway + - light.bedroom_hallway + - light_upstairs_hallway + - light.m1_back_left + - light.m1_back_right + - light.m1_front_left + - light.m1_front_right + - light.m1_slider + - light.office_lamp + - light.den_lamp + - light.f2 + - light.f1 + - light.s1 + - light.s2 + - light.s3 + - light.s4 + - light.d1 + - light.d2 + - light.k1 + - light.k2 + - light.k3 + - light.k4 + - light.k5 + - light.k6 + - light.sink + - light.fridge + - light.couch_1 + - light.tv_light + - light.bedroom + - light.justin_go + - light.paige_go + - light.garage_attic + - light.upstairs_lamp + states: + - state: 'on' + class: 'light-on' + - state: 'off' + class: 'light-off' + action: + service: homeassistant.toggle + + - name: Outdoor Lights + entities: + - light.p1_front_left + - light.p1_front_right + - light.p1_back_left + - light.p1_back_right + - light.outdoor_bathroom + - light.outdoor_foyer + - light.outdoor_sconce_1 + - light.outdoor_sconce_2 + - light.outdoor_sconce_3 + - light.led_garage_large + - light.led_garage_small + - light.led_outdoor_den + - light.stone_door + states: + - state: 'on' + class: 'light-on' + - state: 'off' + class: 'outdoor-light-off' + action: + service: homeassistant.toggle + + - name: Nest Protects + entities: + - binary_sensor.upstairs_living_room_nest_protect_online + - binary_sensor.hallway_nest_protect_kids_hallway_online + - binary_sensor.justins_room_nest_protect_online + - binary_sensor.kitchen_nest_protect_online + - binary_sensor.master_bedroom_nest_protect_online + - binary_sensor.master_hallway_nest_protect_online + - binary_sensor.paiges_room_nest_protect_paiges_room_online + - binary_sensor.upstairs_bedroom_nest_protect_online + - binary_sensor.office_nest_protect_online + states: + - state: 'off' + class: 'protect-off' + - state: 'on' + class: 'protect-on' + + - name: Entry Points + entities: + - binary_sensor.mcu1_gpio4 + - binary_sensor.mcu1_gpio5 + - binary_sensor.mcu1_gpio10 + - binary_sensor.mcu1_gpio12 + - binary_sensor.mcu1_gpio13 + - binary_sensor.mcu1_gpio14 + - binary_sensor.mcu2_gpio4 + - binary_sensor.mcu2_gpio5 + - binary_sensor.mcu2_gpio9 + - binary_sensor.mcu2_gpio10 + - binary_sensor.mcu2_gpio12 + - binary_sensor.mcu2_gpio13 + - binary_sensor.mcu2_gpio14 + - binary_sensor.mcu3_gpio4 + - binary_sensor.mcu3_gpio5 + - binary_sensor.mcu3_gpio10 + - binary_sensor.mcu3_gpio14 + - binary_sensor.kitchen_door_opened + - binary_sensor.mcu3_light + states: + - state: 'off' + class: 'window-closed' + - state: 'on' + class: 'window-open' + + - name: Presence + entities: + - binary_sensor.sleepnumber_carlo_carlo_is_in_bed + - binary_sensor.sleepnumber_carlo_stacey_is_in_bed + states: + - state: 'on' + class: 'presence-on' + - state: 'off' + class: 'presence-off' + + - name: Garage Doors + entities: + - cover.large_garage + - cover.small_garage + states: + - state: 'closed' + class: 'window-closed' + - state: 'open' + class: 'window-open' + + - name: Dark Sky Sensors + entities: + - sensor.dark_sky_minutely_summary + image_template: ' + var imageName = ""; + + switch (entity.attributes.entity_picture) { + case "/static/images/darksky/weather-sunny.svg": + imageName = "sunny-1"; + break; + + case "/static/images/darksky/weather-night.svg": + imageName = "night-1"; + break; + + case "/static/images/darksky/weather-partlycloudy.svg": + imageName = "partlycloudy-day-1"; + break; + + case "/static/images/darksky/weather-cloudy.svg": + imageName = "partlycloudy-night-1"; + break; + + case "/static/images/darksky/weather-cloudy.svg": + imageName = "cloudy-day-1"; + break; + + case "/static/images/darksky/weather-pouring.svg": + imageName = "thunder"; + break; + + case "/static/images/darksky/weather-snowy.svg": + imageName = "snowy-day-1"; + break; + } + + return "/local/custom_ui/floorplan/images/weather/" + imageName + ".svg"; + ' + + - name: Camera Images + entities: + - camera.stone_door + image_template: '${entity.attributes.entity_picture}' + # image_refresh_interval: 20 # in seconds - Future options if needed. diff --git a/www/custom_ui/floorplan/buttons/radio_on.svg b/www/custom_ui/floorplan/buttons/radio_on.svg new file mode 100755 index 00000000..dca8485a --- /dev/null +++ b/www/custom_ui/floorplan/buttons/radio_on.svg @@ -0,0 +1,32 @@ + + + +Radio Green + + + + + + + + + + + diff --git a/www/custom_ui/floorplan/buttons/school_off.svg b/www/custom_ui/floorplan/buttons/school_off.svg new file mode 100755 index 00000000..4177fcc5 --- /dev/null +++ b/www/custom_ui/floorplan/buttons/school_off.svg @@ -0,0 +1 @@ +No Shcool Tom \ No newline at end of file diff --git a/www/custom_ui/floorplan/buttons/school_on.svg b/www/custom_ui/floorplan/buttons/school_on.svg new file mode 100755 index 00000000..9db228d0 --- /dev/null +++ b/www/custom_ui/floorplan/buttons/school_on.svg @@ -0,0 +1,40 @@ + + + +Artboard 4 + + + + + + + + diff --git a/www/custom_ui/floorplan/buttons/snooze.svg b/www/custom_ui/floorplan/buttons/snooze.svg new file mode 100755 index 00000000..492d7287 --- /dev/null +++ b/www/custom_ui/floorplan/buttons/snooze.svg @@ -0,0 +1 @@ +Artboard 1 \ No newline at end of file diff --git a/www/custom_ui/floorplan/buttons/snooze_on.svg b/www/custom_ui/floorplan/buttons/snooze_on.svg new file mode 100755 index 00000000..418d415d --- /dev/null +++ b/www/custom_ui/floorplan/buttons/snooze_on.svg @@ -0,0 +1 @@ +Artboard 3 \ No newline at end of file diff --git a/www/custom_ui/floorplan/buttons/stop.svg b/www/custom_ui/floorplan/buttons/stop.svg new file mode 100755 index 00000000..4fc9b900 --- /dev/null +++ b/www/custom_ui/floorplan/buttons/stop.svg @@ -0,0 +1,32 @@ + + + +Stop Red + + + + + + + + diff --git a/www/custom_ui/floorplan/clock.css b/www/custom_ui/floorplan/clock.css new file mode 100755 index 00000000..52c50580 --- /dev/null +++ b/www/custom_ui/floorplan/clock.css @@ -0,0 +1,166 @@ +/* @import url('https://fonts.googleapis.com/css?family=Black+Ops+One'); + + SVG shapes */ + +svg, svg * { + vector-effect: non-scaling-stroke !important; + pointer-events: all !important; +} +/* +/* Hover over */ + +.entity:hover:not(.static-text):not(.static-temp):not(.static-text-date):not(.static-text-time) { + stroke: #03A9F4 !important; + stroke-width: 1px !important; + stroke-opacity: 1 !important; +} + + +.warning-background, .warning-text-background { + fill: #fcf8e3 !important; + fill-opacity: 1 !important; + stroke: #faebcc !important; + stroke-width: 1px !important; +} + +.static-text +{ + font-size : 47px !important; + font-family : Helvetica !important; + color : rgb(128, 128, 128) !important; +} + +.static-text-date +{ + font-family : Helvetica !important; + font-size : 47px !important; + color : rgb(128, 128, 128) !important; +} + +.static-temp +{ + font-size: 47.57px !important; + font-family: Helvetica !important; + fill: rgb(128, 128, 128) !important; +} + +.static-text-time +{ + font-family: "Rockwell Extra Bold", "Rockwell Bold", monospace !important; + font-size : 280px !important; + color : rgb(0, 173, 238) !important; + text-shadow: 0 0 30px #00adee; + text-align: center; !important; +} + +.static-text-am_pm +{ + font-family: "Rockwell Extra Bold", "Rockwell Bold", monospace !important; + font-size : 60px !important; + color : rgb(0, 173, 238) !important; + text-shadow: 0 0 30px #00adee; +} + + +/* Last motion entity */ + +.last-motion { + stroke: #808080 !important; + stroke-width: 1px !important; + stroke-opacity: 1 !important; +} + +/* Presence */ +.presence-on { + fill: #BDF271 !important; +} + +.presence-off { + fill: #3D3B3F !important; +} + +/* Text Home/Away */ + +.text-home { + fill: #BDF271 !important; +} + +.text-away { + fill: #E7376B !important; +} + +/* switches */ + +.switch-on { + fill: orange !important; +} + +.switch-on-blue { + fill: blue !important; +} + +.switch-off { + fill: #cccccc !important; +} +/* Buttons */ + +.button-on { + fill: #FFFFA6 !important; + fill-opacity: 0.25; +} + +.button-off { + fill: #3D3B3F !important; + fill-opacity: 0.5; +} + + + +/* Light */ + +.light-off { + fill: #231F26 !important; + fill-opacity: 1.0; + stroke: black !important; + stroke-width: 1; + stroke-opacity:0.1; +} +.light-off:hover { + transform-origin: center; + transform: scale(2); +} + +.outdoor-light-off { + fill: grey !important; + fill-opacity: 1.0; + stroke: black !important; + stroke-width: 1; + stroke-opacity:0.1; +} +.outdoor-light-off:hover { + transform-origin: center; + transform: scale(2); +} +.light-blue-on { + fill: blue !important; + fill-opacity: 1.0; + stroke: #FFFFA6 !important; + stroke-width: 10; + stroke-opacity: 0.25; +} +.light-blue-on:hover { + transform-origin: center; + transform: scale(3); +} + +.light-on { + fill: yellow !important; + fill-opacity: 1.0; + stroke: #FFFFA6 !important; + stroke-width: 10; + stroke-opacity: 0.25; +} +.light-on:hover { + transform-origin: center; + transform: scale(3); +} diff --git a/www/custom_ui/floorplan/clock.svg b/www/custom_ui/floorplan/clock.svg new file mode 100755 index 00000000..7dc97a9d --- /dev/null +++ b/www/custom_ui/floorplan/clock.svg @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +10:36 +NedNesDay +November 33 + + + + + + + + + + + + + + +XX + + + + + + +72 +72 +1st Floor +2ndFloor + + + + +Hell Fire for the next 2 hours +72 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +00:00 + + + diff --git a/www/custom_ui/floorplan/clock.yaml b/www/custom_ui/floorplan/clock.yaml new file mode 100755 index 00000000..677ca7ac --- /dev/null +++ b/www/custom_ui/floorplan/clock.yaml @@ -0,0 +1,144 @@ +page_id: clock +image: /local/custom_ui/floorplan/clock.svg +stylesheet: /local/custom_ui/floorplan/clock.css + +variables: + - name: floorplan.hours + - name: floorplan.minutes + +defaults: + hover_over: false + more_info: false + +rules: + + - element: floorplan.clock_button + action: + service: floorplan.page_navigate + data: + page_id: clock_config + + - entity: sensor.clock_stacey_alarm_time + text_template: '${entity.state.slice(0, 5)}' + + + - entity: input_boolean.clock_snooze + image_template: '/local/custom_ui/floorplan/buttons/${(entity.state === "on") ? "snooze_on" : "snooze"}.svg' + action: + service: homeassistant.toggle + + - entity: input_boolean.school_mode + image_template: '/local/custom_ui/floorplan/buttons/${(entity.state === "on") ? "school_on" : "school_off"}.svg' + action: + service: homeassistant.toggle + + - entity: media_player.alarm_clock + image_template: '/local/custom_ui/floorplan/buttons/${(entity.state === "playing") ? "stop" : "radio_on"}.svg' + action: + service_template: '${(entity.state === "playing") ? "media_player.media_stop" : "media_player.play_media"}' + data: + media_content_id: http://listen.djcmedia.com:80/americascountryhigh + media_content_type: audio/mp4 + + - name: thermostats_temp + entities: + - climate.downstairs + - climate.upstairs + text_template: '${entity.attributes.current_temperature ? Math.ceil(entity.attributes.current_temperature) + "°": "undefined"}' + class_template: 'return "static-temp";' + + - name: temp_darksky + entities: + - sensor.dark_sky_temperature + text_template: '${entity.state ? Math.ceil(entity.state) + "°": "undefined"}' + class_template: 'return "static-temp";' + + - name: text_states + entities: + - sensor.dark_sky_minutely_summary + hover_over: false + more_info: false + text_template: '${entity.state ? entity.state : "undefined"}' + class_template: 'return "static-text";' + + - name: text_font_date + entities: + - sensor.clock_date + - sensor.clock_day + hover_over: false + more_info: false + text_template: '${entity.state ? entity.state : "undefined"}' + class_template: 'return "static-text-date";' + + - name: text_font_time + entities: + - sensor.clock_time + hover_over: false + more_info: false + text_template: '${entity.state ? entity.state : "undefined"}' + class_template: 'return "static-text-time";' + + - name: text_font_am_pm + entities: + - sensor.clock_am_pm + hover_over: false + more_info: false + text_template: '${entity.state ? entity.state : "undefined"}' + class_template: 'return "static-text-am_pm";' + + + # - name: Presence + # entities: + # - binary_sensor.sleepnumber_carlo_carlo_is_in_bed + # - binary_sensor.sleepnumber_carlo_stacey_is_in_bed + # states: + # - state: 'on' + # class: 'presence-on' + # - state: 'off' + # class: 'presence-off' + + - name: Dark Sky Sensors + entities: + - entity: sensor.dark_sky_minutely_summary + element: sensor.dark_sky_minutely_summary_icon + + image_template: ' + var imageName = ""; + + switch (entity.attributes.entity_picture) { + case "/static/images/darksky/weather-sunny.svg": + imageName = "sunny-1"; + break; + + case "/static/images/darksky/weather-night.svg": + imageName = "night-1"; + break; + + case "/static/images/darksky/weather-partlycloudy.svg": + imageName = "partlycloudy-day-1"; + break; + + case "/static/images/darksky/weather-cloudy.svg": + imageName = "partlycloudy-night-1"; + break; + + case "/static/images/darksky/weather-cloudy.svg": + imageName = "cloudy-day-1"; + break; + + case "/static/images/darksky/weather-pouring.svg": + imageName = "thunder"; + break; + + case "/static/images/darksky/weather-snowy.svg": + imageName = "snowy-day-1"; + break; + } + + return "/local/custom_ui/floorplan/images/weather/" + imageName + ".svg"; + ' + + - name: Camera Images + entities: + - camera.stone_door + image_template: '${entity.attributes.entity_picture}' diff --git a/www/custom_ui/floorplan/clock_config.svg b/www/custom_ui/floorplan/clock_config.svg new file mode 100755 index 00000000..38f004b7 --- /dev/null +++ b/www/custom_ui/floorplan/clock_config.svg @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hell Fire for the next 2 hours +72 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 00 + + + 00 + + + : + + + + + + + + Save + + Save + +00:00 + + + diff --git a/www/custom_ui/floorplan/clock_config.yaml b/www/custom_ui/floorplan/clock_config.yaml new file mode 100755 index 00000000..044c7716 --- /dev/null +++ b/www/custom_ui/floorplan/clock_config.yaml @@ -0,0 +1,172 @@ +page_id: clock_config +image: /local/custom_ui/floorplan/clock_config.svg +stylesheet: /local/custom_ui/floorplan/clock.css + +variables: + - name: floorplan.hours + - name: floorplan.minutes + +defaults: + hover_over: false + more_info: false + +startup: + action: + - service: floorplan.variable_set + data: + variable: floorplan.hours + value_template: 'return parseInt(entities["sensor.clock_stacey_alarm_time"].state.slice(0, 2));' + - service: floorplan.variable_set + data: + variable: floorplan.minutes + value_template: 'return parseInt(entities["sensor.clock_stacey_alarm_time"].state.slice(3, 5));' + +rules: + + - element: floorplan.clock_button + action: + service: floorplan.page_navigate + data: + page_id: clock + + - entity: sensor.clock_stacey_alarm_time + text_template: '${entity.state.slice(0, 5)}' + + - entities: + - floorplan.hours + - floorplan.minutes + text_template: '${("0" + entity.state).slice(-2)}' + + - entity: floorplan.hours + element: input_number.alarm_time_hours_up + action: + service: floorplan.variable_set + data: + variable: floorplan.hours + value_template: '${(parseInt(entity.state) + 1) % 24}' + + - entity: floorplan.hours + element: input_number.alarm_time_hours_down + action: + service: floorplan.variable_set + data: + variable: floorplan.hours + value_template: '${((parseInt(entity.state) - 1) + 24) % 24}' + + - entity: floorplan.minutes + element: input_number.alarm_time_minutes_up + action: + service: floorplan.variable_set + data: + variable: floorplan.minutes + value_template: '${((parseInt(entity.state / 5) * 5) + 5) % 60}' + + - entity: floorplan.minutes + element: input_number.alarm_time_minutes_down + action: + service: floorplan.variable_set + data: + variable: floorplan.minutes + value_template: '${(((parseInt(entity.state / 5) * 5) - 5) + 60) % 60}' + + - element: floorplan.save_alarm_time_button + action: + service: mqtt.publish + data_template: '{ + "payload": "${("0"+ entities[`floorplan.hours`].state).slice(-2)}:${("0" + entities[`floorplan.minutes`].state).slice(-2)}", + "topic": "clock/stacey_alarm_time", + "retain": true + }' + + - entity: input_boolean.clock_snooze + image_template: '/local/custom_ui/floorplan/buttons/${(entity.state === "on") ? "snooze_on" : "snooze"}.svg' + action: + service: homeassistant.toggle + + - entity: input_boolean.school_mode + image_template: '/local/custom_ui/floorplan/buttons/${(entity.state === "on") ? "school_on" : "school_off"}.svg' + action: + service: homeassistant.toggle + + - entity: media_player.alarm_clock + image_template: '/local/custom_ui/floorplan/buttons/${(entity.state === "playing") ? "stop" : "radio_on"}.svg' + action: + service_template: '${(entity.state === "playing") ? "media_player.media_stop" : "media_player.play_media"}' + data: + media_content_id: http://listen.djcmedia.com:80/americascountryhigh + media_content_type: audio/mp4 + + - name: temp_darksky + entities: + - sensor.dark_sky_temperature + text_template: '${entity.state ? Math.ceil(entity.state) + "°": "undefined"}' + class_template: 'return "static-temp";' + + - name: text_states + entities: + - sensor.dark_sky_minutely_summary + text_template: '${entity.state ? entity.state : "undefined"}' + class_template: 'return "static-text";' + + - name: text_font_date + entities: + - sensor.clock_date + - sensor.clock_day + hover_over: false + more_info: false + text_template: '${entity.state ? entity.state : "undefined"}' + class_template: 'return "static-text-date";' + + - name: text_font_time + entities: + - sensor.clock_time + hover_over: false + more_info: false + text_template: '${entity.state ? entity.state : "undefined"}' + class_template: 'return "static-text-time";' + + - name: Dark Sky Sensors + entities: + - entity: sensor.dark_sky_minutely_summary + element: sensor.dark_sky_minutely_summary_icon + + image_template: ' + var imageName = ""; + + switch (entity.attributes.entity_picture) { + case "/static/images/darksky/weather-sunny.svg": + imageName = "sunny-1"; + break; + + case "/static/images/darksky/weather-night.svg": + imageName = "night-1"; + break; + + case "/static/images/darksky/weather-partlycloudy.svg": + imageName = "partlycloudy-day-1"; + break; + + case "/static/images/darksky/weather-cloudy.svg": + imageName = "partlycloudy-night-1"; + break; + + case "/static/images/darksky/weather-cloudy.svg": + imageName = "cloudy-day-1"; + break; + + case "/static/images/darksky/weather-pouring.svg": + imageName = "thunder"; + break; + + case "/static/images/darksky/weather-snowy.svg": + imageName = "snowy-day-1"; + break; + } + + return "/local/custom_ui/floorplan/images/weather/" + imageName + ".svg"; + ' + + - name: Camera Images + entities: + - camera.stone_door + image_template: '${entity.attributes.entity_picture}' diff --git a/www/custom_ui/floorplan/floorclock.yaml b/www/custom_ui/floorplan/floorclock.yaml new file mode 100755 index 00000000..f0da73ed --- /dev/null +++ b/www/custom_ui/floorplan/floorclock.yaml @@ -0,0 +1,19 @@ +## This is the main Floorplan configuration page. To define the pages. +## This one is called Floorclock since this is for my Clock application. +## log_level: which can be set to one these: error, warning, info or debug + +date_format: MMM-DD-YYYY +#log_level: debug + +fully_kiosk: + + - name: Alarm Clock + address: 00:FC:8B:4A:D5:CF + motion_sensor: binary_sensor.clock_motion + plugged_sensor: binary_sensor.clock_plugged + screensaver_light: light.clock_screensaver + media_player: media_player.alarm_clock + +pages: + - /local/custom_ui/floorplan/clock.yaml + - /local/custom_ui/floorplan/clock_config.yaml diff --git a/www/custom_ui/floorplan/floorplan.yaml b/www/custom_ui/floorplan/floorplan.yaml new file mode 100755 index 00000000..e87c93ec --- /dev/null +++ b/www/custom_ui/floorplan/floorplan.yaml @@ -0,0 +1,21 @@ +date_format: MMM-DD-YYYY +#log_level: error + +fully_kiosk: + + - name: Bedroom Alarm Panel + address: B4:7C:9C:9E:85:90 + motion_sensor: binary_sensor.bedroom_motion + plugged_sensor: binary_sensor.bedroom_plugged + screensaver_light: light.bedroom_screensaver + media_player: media_player.bedroom_alarm_panel + + # - name: Entry Alarm Panel + # address: 00:FC:8B:4A:D5:CF + # entities: + # - binary_sensor.entry_motion + # - binary_sensor.entry_plugged + # - media_player.entry_alarm_panel + +pages: + - /local/custom_ui/floorplan/alarm.yaml diff --git a/www/custom_ui/floorplan/floorplan_original.svg b/www/custom_ui/floorplan/floorplan_original.svg new file mode 100755 index 00000000..295d47d2 --- /dev/null +++ b/www/custom_ui/floorplan/floorplan_original.svg @@ -0,0 +1,10729 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Carlo + Stacey + TEMP + TEMP + Guest Mode + House Station + + + + + + + + + + + + + + THIS IS A LOT OF SAMPLE TEXT - IT IS WHATEVER WAS SAID LAST BY JOANNA - WITH ALL WHITE SPACE REMOVED. MOST OF IT. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Second Floor + + + + + Created by Richard Slater + from the Noun Project + + + + Created by Richard Slater + from the Noun Project + + + + Created by Richard Slater + from the Noun Project + + + + Created by Richard Slater + from the Noun Project + + + + Created by Richard Slater + from the Noun Project + + + + Created by Richard Slater + from the Noun Project + + + + Created by Richard Slater + from the Noun Project + + + + Created by Richard Slater + from the Noun Project + + + + Created by Richard Slater + from the Noun Project + + + + + + + XX + + + XX + Outdoor + + + + + + + XX + + + XX + 1st FL + + + + + + + + + + + 2nd FL + XX + XX + + diff --git a/www/custom_ui/floorplan/ha-floorplan.html b/www/custom_ui/floorplan/ha-floorplan.html new file mode 100755 index 00000000..4d5b831f --- /dev/null +++ b/www/custom_ui/floorplan/ha-floorplan.html @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + diff --git a/www/custom_ui/floorplan/images/fonts/Digital-Dismay.otf b/www/custom_ui/floorplan/images/fonts/Digital-Dismay.otf new file mode 100755 index 00000000..af43ceba Binary files /dev/null and b/www/custom_ui/floorplan/images/fonts/Digital-Dismay.otf differ diff --git a/www/custom_ui/floorplan/images/weather/cloudy-day-1.svg b/www/custom_ui/floorplan/images/weather/cloudy-day-1.svg new file mode 100755 index 00000000..c411617f --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/cloudy-day-1.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/www/custom_ui/floorplan/images/weather/night-1.svg b/www/custom_ui/floorplan/images/weather/night-1.svg new file mode 100755 index 00000000..9b287d74 --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/night-1.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/www/custom_ui/floorplan/images/weather/partlycloudy-day-1.svg b/www/custom_ui/floorplan/images/weather/partlycloudy-day-1.svg new file mode 100755 index 00000000..ce0dcd07 --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/partlycloudy-day-1.svg @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/www/custom_ui/floorplan/images/weather/partlycloudy-night-1.svg b/www/custom_ui/floorplan/images/weather/partlycloudy-night-1.svg new file mode 100755 index 00000000..6bab5eb0 --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/partlycloudy-night-1.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/www/custom_ui/floorplan/images/weather/partlysunny-day-1.svg b/www/custom_ui/floorplan/images/weather/partlysunny-day-1.svg new file mode 100755 index 00000000..ad9bb656 --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/partlysunny-day-1.svg @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/www/custom_ui/floorplan/images/weather/pouring-day-1.svg b/www/custom_ui/floorplan/images/weather/pouring-day-1.svg new file mode 100755 index 00000000..513cf211 --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/pouring-day-1.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + diff --git a/www/custom_ui/floorplan/images/weather/rain-day-1.svg b/www/custom_ui/floorplan/images/weather/rain-day-1.svg new file mode 100755 index 00000000..899216f4 --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/rain-day-1.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + diff --git a/www/custom_ui/floorplan/images/weather/rainbow.svg b/www/custom_ui/floorplan/images/weather/rainbow.svg new file mode 100755 index 00000000..4f443c8a --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/rainbow.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + diff --git a/www/custom_ui/floorplan/images/weather/snowy-day-1.svg b/www/custom_ui/floorplan/images/weather/snowy-day-1.svg new file mode 100755 index 00000000..578d2989 --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/snowy-day-1.svg @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/www/custom_ui/floorplan/images/weather/sunny-1.svg b/www/custom_ui/floorplan/images/weather/sunny-1.svg new file mode 100755 index 00000000..d372eb1f --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/sunny-1.svg @@ -0,0 +1,17 @@ + + + + +Weather_Icons_1B + + diff --git a/www/custom_ui/floorplan/images/weather/sunrise-1.svg b/www/custom_ui/floorplan/images/weather/sunrise-1.svg new file mode 100755 index 00000000..168fdffe --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/sunrise-1.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + diff --git a/www/custom_ui/floorplan/images/weather/sunset-1.svg b/www/custom_ui/floorplan/images/weather/sunset-1.svg new file mode 100755 index 00000000..30ccdebd --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/sunset-1.svg @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/www/custom_ui/floorplan/images/weather/thunder.svg b/www/custom_ui/floorplan/images/weather/thunder.svg new file mode 100755 index 00000000..fb6d5f2f --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/thunder.svg @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/www/custom_ui/floorplan/images/weather/windy.svg b/www/custom_ui/floorplan/images/weather/windy.svg new file mode 100755 index 00000000..35b4fe06 --- /dev/null +++ b/www/custom_ui/floorplan/images/weather/windy.svg @@ -0,0 +1,19 @@ + + + + + + + + + + diff --git a/www/custom_ui/floorplan/lib/floorplan.js b/www/custom_ui/floorplan/lib/floorplan.js new file mode 100755 index 00000000..b911fe4c --- /dev/null +++ b/www/custom_ui/floorplan/lib/floorplan.js @@ -0,0 +1,2099 @@ +/* + Floorplan for Home Assistant + Version: 1.0.7.57 + By Petar Kozul + https://github.com/pkozul/ha-floorplan +*/ + +'use strict'; + +(function () { + if (typeof window.Floorplan === 'function') { + return; + } + + class Floorplan { + constructor() { + this.version = '1.0.7.57'; + this.doc = {}; + this.hass = {}; + this.openMoreInfo = () => { }; + this.setIsLoading = () => { }; + this.config = {}; + this.timeDifference = undefined; + this.pageInfos = []; + this.entityInfos = []; + this.elementInfos = []; + this.cssRules = []; + this.entityTransitions = {}; + this.lastMotionConfig = {}; + this.logLevels = []; + this.handleEntitiesDebounced = {}; + this.variables = []; + + //this.setIsLoading(true); + } + + hassChanged(newHass, oldHass) { + this.hass = newHass; + + if (!this.config) { + return; + } + + this.handleEntitiesDebounced(); // use debounced wrapper + } + + /***************************************************************************************************************************/ + /* Startup + /***************************************************************************************************************************/ + + init(options) { + this.doc = options.doc; + this.hass = options.hass; + this.openMoreInfo = options.openMoreInfo; + this.setIsLoading = options.setIsLoading; + + window.onerror = this.handleWindowError.bind(this); + + this.handleEntitiesDebounced = this.debounce(() => { + return this.handleEntities(); + }, 100); + + this.initTimeDifference(); + + return this.loadConfig(options.config) + .then(config => { + this.config = config; + + this.getLogLevels(); + this.logInfo('VERSION', `Floorplan v${this.version}`); + + if (!this.validateConfig(this.config)) { + this.setIsLoading(false); + return Promise.resolve(); + } + + return this.loadLibraries() + .then(() => { + this.initFullyKiosk(); + return this.config.pages ? this.initMultiPage() : this.initSinglePage(); + }); + }) + .catch(error => { + this.setIsLoading(false); + this.handleError(error); + }); + } + + initMultiPage() { + return this.loadPages() + .then(() => { + this.setIsLoading(false); + this.initPageDisplay(); + this.initVariables(); + this.initStartupActions(); + return this.handleEntities(true); + }); + } + + initSinglePage() { + let imageUrl = this.getBestImage(this.config); + return this.loadFloorplanSvg(imageUrl) + .then((svg) => { + this.config.svg = svg; + return this.loadStyleSheet(this.config.stylesheet) + .then(() => { + return this.initFloorplan(svg, this.config) + .then(() => { + this.setIsLoading(false); + this.initPageDisplay(); + this.initVariables(); + this.initStartupActions(); + return this.handleEntities(true); + }) + }); + }); + } + + getLogLevels() { + if (!this.config.log_level) { + return; + } + + let allLogLevels = { + error: ['error'], + warning: ['error', 'warning'], + info: ['error', 'warning', 'info'], + debug: ['error', 'warning', 'info', 'debug'], + }; + + this.logLevels = allLogLevels[this.config.log_level.toLowerCase()]; + } + + /***************************************************************************************************************************/ + /* Loading resources + /***************************************************************************************************************************/ + + loadConfig(configUrl) { + return this.fetchTextResource(configUrl, false) + .then(config => { + return Promise.resolve(YAML.parse(config)); + }); + } + + loadLibraries() { + let promises = []; + + if (this.isOptionEnabled(this.config.pan_zoom)) { + promises.push(this.loadScript('/local/custom_ui/floorplan/lib/svg-pan-zoom.min.js')); + } + + if (this.isOptionEnabled(this.config.fully_kiosk)) { + promises.push(this.loadScript('/local/custom_ui/floorplan/lib/fully-kiosk.js')); + } + + return promises.length ? Promise.all(promises) : Promise.resolve(); + } + + loadScript(scriptUrl) { + return new Promise((resolve, reject) => { + let script = document.createElement('script'); + script.src = this.cacheBuster(scriptUrl); + script.onload = () => { + return resolve(); + }; + script.onerror = (err) => { + reject(new URIError(`${err.target.src}`)); + }; + + this.doc.appendChild(script); + }); + } + + loadPages() { + let configPromises = [Promise.resolve()] + .concat(this.config.pages.map(pageConfigUrl => { + return this.loadPageConfig(pageConfigUrl, this.config.pages.indexOf(pageConfigUrl)); + })); + + return Promise.all(configPromises) + .then(() => { + let pageInfos = Object.keys(this.pageInfos).map(key => this.pageInfos[key]); + pageInfos.sort((a, b) => a.index - b.index); // sort ascending + + let masterPageInfo = pageInfos.find(pageInfo => pageInfo.config.master_page); + if (masterPageInfo) { + masterPageInfo.isMaster = true; + } + + let defaultPageInfo = pageInfos.find(pageInfo => !pageInfo.config.master_page); + if (defaultPageInfo) { + defaultPageInfo.isDefault = true; + } + + let svgPromises = [Promise.resolve()] + .concat(pageInfos.map(pageInfo => this.loadPageFloorplanSvg(pageInfo, masterPageInfo))); + + return Promise.all(svgPromises); + }); + } + + loadPageConfig(pageConfigUrl, index) { + return this.loadConfig(pageConfigUrl) + .then((pageConfig) => { + let pageInfo = this.createPageInfo(pageConfig); + pageInfo.index = index; + return Promise.resolve(pageInfo); + }); + } + + loadPageFloorplanSvg(pageInfo, masterPageInfo) { + let imageUrl = this.getBestImage(pageInfo.config); + return this.loadFloorplanSvg(imageUrl, pageInfo, masterPageInfo) + .then((svg) => { + svg.id = pageInfo.config.page_id; // give the SVG an ID so it can be styled (i.e. background color) + pageInfo.svg = svg; + return this.loadStyleSheet(pageInfo.config.stylesheet) + .then(() => { + return this.initFloorplan(pageInfo.svg, pageInfo.config); + }); + }); + } + + getBestImage(config) { + let imageUrl = ''; + + if (typeof config.image === 'string') { + imageUrl = config.image; + } + else { + if (config.image.sizes) { + config.image.sizes.sort((a, b) => b.min_width - a.min_width); // sort descending + for (let pageSize of config.image.sizes) { + if (screen.width >= pageSize.min_width) { + imageUrl = pageSize.location; + break; + } + } + } + } + + return imageUrl; + } + + createPageInfo(pageConfig) { + let pageInfo = { config: pageConfig }; + + // Merge the page's rules with the main config's rules + if (pageInfo.config.rules && this.config.rules) { + pageInfo.config.rules = pageInfo.config.rules.concat(this.config.rules); + } + + this.pageInfos[pageInfo.config.page_id] = pageInfo; + + return pageInfo; + } + + loadStyleSheet(stylesheetUrl) { + if (!stylesheetUrl) { + return Promise.resolve(); + } + + return this.fetchTextResource(stylesheetUrl, false) + .then(stylesheet => { + let link = document.createElement('style'); + link.type = 'text/css'; + link.innerHTML = stylesheet; + this.doc.appendChild(link); + + let cssRules = this.getArray(link.sheet.cssRules); + this.cssRules = this.cssRules.concat(cssRules); + + return Promise.resolve(); + }); + } + + loadFloorplanSvg(imageUrl, pageInfo, masterPageInfo) { + return this.fetchTextResource(imageUrl, true) + .then(result => { + let svg = $(result).siblings('svg')[0]; + svg = svg ? svg : $(result); + + if (pageInfo) { + $(svg).attr('id', pageInfo.config.page_id); + } + + $(svg).height('100%'); + $(svg).width('100%'); + $(svg).css('position', this.isPanel ? 'absolute' : 'relative'); + $(svg).css('cursor', 'default'); + $(svg).css('opacity', 0); + $(svg).attr('xmlns:xlink', 'http://www.w3.org/1999/xlink'); + + if (pageInfo && masterPageInfo) { + let masterPageId = masterPageInfo.config.page_id; + let contentElementId = masterPageInfo.config.master_page.content_element; + + if (pageInfo.config.page_id === masterPageId) { + $(this.doc).find('#floorplan').append(svg); + } + else { + let $masterPageElement = $(this.doc).find('#' + masterPageId); + let $contentElement = $(this.doc).find('#' + contentElementId); + + let height = Number.parseFloat($(svg).attr('height')); + let width = Number.parseFloat($(svg).attr('width')); + if (!$(svg).attr('viewBox')) { + $(svg).attr('viewBox', `0 0 ${width} ${height}`); + } + + $(svg) + .attr('preserveAspectRatio', 'xMinYMin meet') + .attr('height', $contentElement.attr('height')) + .attr('width', $contentElement.attr('width')) + .attr('x', $contentElement.attr('x')) + .attr('y', $contentElement.attr('y')); + + $contentElement.parent().append(svg); + } + } + else { + $(this.doc).find('#floorplan').append(svg); + } + + // Enable pan / zoom if enabled in config + if (this.isOptionEnabled(this.config.pan_zoom)) { + svgPanZoom($(svg)[0], { + zoomEnabled: true, + controlIconsEnabled: true, + fit: true, + center: true, + }); + } + + return Promise.resolve(svg); + }); + } + + loadImage(imageUrl, svgElementInfo, entityId, rule) { + if (imageUrl.toLowerCase().indexOf('.svg') >= 0) { + return this.loadSvgImage(imageUrl, svgElementInfo, entityId, rule); + } + else { + return this.loadBitmapImage(imageUrl, svgElementInfo, entityId, rule); + } + } + + loadBitmapImage(imageUrl, svgElementInfo, entityId, rule) { + return this.fetchImageResource(imageUrl, false, true) + .then(imageData => { + this.logDebug('IMAGE', `${entityId} (setting image: ${imageUrl})`); + + let svgElement = svgElementInfo.svgElement; // assume the target element already exists + + if (!$(svgElement).is('image')) { + svgElement = this.createImageElement(svgElementInfo.originalSvgElement); + + $(svgElement).append(document.createElementNS('http://www.w3.org/2000/svg', 'title')) + .off('click') + .on('click', this.onEntityClick.bind({ instance: this, svgElementInfo: svgElementInfo, entityId: entityId, rule: rule })) + .css('cursor', 'pointer') + .addClass('ha-entity'); + + svgElementInfo.svgElement = this.replaceElement(svgElementInfo.svgElement, svgElement); + } + + let existingHref = svgElement.getAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href'); + if (existingHref !== imageData) { + svgElement.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', imageUrl); + } + + return Promise.resolve(svgElement); + }); + } + + loadSvgImage(imageUrl, svgElementInfo, entityId, rule) { + return this.fetchTextResource(imageUrl, true) + .then(result => { + this.logDebug('IMAGE', `${entityId} (setting image: ${imageUrl})`); + + let svgElement = $(result).siblings('svg')[0]; + svgElement = svgElement ? svgElement : $(result); + + let height = Number.parseFloat($(svgElement).attr('height')); + let width = Number.parseFloat($(svgElement).attr('width')); + if (!$(svgElement).attr('viewBox')) { + $(svgElement).attr('viewBox', `0 0 ${width} ${height}`); + } + + $(svgElement) + .attr('id', svgElementInfo.svgElement.id) + .attr('preserveAspectRatio', 'xMinYMin meet') + .attr('height', svgElementInfo.originalBBox.height) + .attr('width', svgElementInfo.originalBBox.width) + .attr('x', svgElementInfo.originalBBox.x) + .attr('y', svgElementInfo.originalBBox.y); + + $(svgElement).find('*').append(document.createElementNS('http://www.w3.org/2000/svg', 'title')) + .off('click') + .on('click', this.onEntityClick.bind({ instance: this, svgElementInfo: svgElementInfo, entityId: entityId, rule: rule })) + .css('cursor', 'pointer') + .addClass('ha-entity'); + + svgElementInfo.svgElement = this.replaceElement(svgElementInfo.svgElement, svgElement); + + return Promise.resolve(svgElement); + }) + } + + replaceElement(prevousSvgElement, svgElement) { + let $parent = $(prevousSvgElement).parent(); + + $(prevousSvgElement).find('*') + .off('click'); + + $(prevousSvgElement) + .off('click') + .remove(); + + $parent.append(svgElement); + + return svgElement; + } + + /***************************************************************************************************************************/ + /* Initialization + /***************************************************************************************************************************/ + + initTimeDifference() { + this.hass.connection.socket.addEventListener('message', event => { + let data = JSON.parse(event.data); + + // Store the time difference between the local web browser and the Home Assistant server + if (data.event && data.event.time_fired) { + let lastEventFiredTime = moment(data.event.time_fired).toDate(); + this.timeDifference = moment().diff(moment(lastEventFiredTime), 'milliseconds'); + } + }); + } + + initFullyKiosk() { + if (this.isOptionEnabled(this.config.fully_kiosk)) { + this.fullyKiosk = new FullyKiosk(this); + this.fullyKiosk.init(); + } + } + + initPageDisplay() { + if (this.config.pages) { + Object.keys(this.pageInfos).map(key => { + let pageInfo = this.pageInfos[key]; + + $(pageInfo.svg).css('opacity', 1); + $(pageInfo.svg).css('display', pageInfo.isMaster || pageInfo.isDefault ? 'initial' : 'none'); // Show the first page + }); + } + else { + // Show the SVG + $(this.config.svg).css('opacity', 1); + $(this.config.svg).css('display', 'initial'); + } + } + + initVariables() { + if (this.config.variables) { + for (let variable of this.config.variables) { + this.initVariable(variable); + } + } + + if (this.config.pages) { + for (let key of Object.keys(this.pageInfos)) { + let pageInfo = this.pageInfos[key]; + + if (pageInfo.config.variables) { + for (let variable of pageInfo.config.variables) { + this.initVariable(variable); + } + } + } + } + } + + initVariable(variable) { + let variableName; + let value; + + if (typeof variable === 'string') { + variableName = variable; + } + else { + variableName = variable.name; + + value = variable.value; + if (variable.value_template) { + value = this.evaluate(variable.value_template, variableName, undefined); + } + } + + if (!this.entityInfos[variableName]) { + let entityInfo = { entityId: variableName, ruleInfos: [], lastState: undefined }; + this.entityInfos[variableName] = entityInfo; + } + + if (!this.hass.states[variableName]) { + this.hass.states[variableName] = { + entity_id: variableName, + state: value, + last_changed: new Date(), + attributes: [], + }; + } + + this.setVariable(variableName, value, [], true); + } + + initStartupActions() { + let actions = []; + + let startup = this.config.startup; + if (startup && startup.action) { + actions = actions.concat(Array.isArray(startup.action) ? startup.action : [startup.action]); + } + + if (this.config.pages) { + for (let key of Object.keys(this.pageInfos)) { + let pageInfo = this.pageInfos[key]; + + let startup = pageInfo.config.startup; + if (startup && startup.action) { + actions = actions.concat(Array.isArray(startup.action) ? startup.action : [startup.action]); + } + } + } + + for (let action of actions) { + if (action.service || action.service_template) { + let actionService = this.getActionService(action, undefined, undefined); + + switch (this.getDomain(actionService)) { + case 'floorplan': + this.callFloorplanService(action, undefined, undefined); + break; + + default: + this.callHomeAssistantService(action, undefined, undefined); + break; + } + } + } + } + + /***************************************************************************************************************************/ + /* SVG initialization + /***************************************************************************************************************************/ + + initFloorplan(svg, config) { + if (!config.rules) { + return Promise.resolve();; + } + + let svgElements = $(svg).find('*').toArray(); + + this.initLastMotion(config, svg, svgElements); + this.initRules(config, svg, svgElements); + + return Promise.resolve();; + } + + initLastMotion(config, svg, svgElements) { + // Add the last motion entity if required + if (config.last_motion && config.last_motion.entity && config.last_motion.class) { + this.lastMotionConfig = config.last_motion; + + let entityInfo = { entityId: config.last_motion.entity, ruleInfos: [], lastState: undefined }; + this.entityInfos[config.last_motion.entity] = entityInfo; + } + } + + initRules(config, svg, svgElements) { + // Apply default options to rules that don't override the options explictly + if (config.defaults) { + for (let rule of config.rules) { + rule.hover_over = (rule.hover_over === undefined) ? config.defaults.hover_over : rule.hover_over; + rule.more_info = (rule.more_info === undefined) ? config.defaults.more_info : rule.more_info; + } + } + + for (let rule of config.rules) { + if (rule.entity || rule.entities) { + this.initEntityRule(rule, svg, svgElements); + } + else if (rule.element || rule.elements) { + this.initElementRule(rule, svg, svgElements); + } + } + } + + initEntityRule(rule, svg, svgElements) { + let entities = this.initGetEntityRuleEntities(rule); + for (let entity of entities) { + let entityId = entity.entityId; + let elementId = entity.elementId; + + let entityInfo = this.entityInfos[entityId]; + if (!entityInfo) { + entityInfo = { entityId: entityId, ruleInfos: [], lastState: undefined }; + this.entityInfos[entityId] = entityInfo; + } + + let ruleInfo = { rule: rule, svgElementInfos: {}, }; + entityInfo.ruleInfos.push(ruleInfo); + + let svgElement = svgElements.find(svgElement => svgElement.id === elementId); + if (!svgElement) { + this.logWarning('CONFIG', `Cannot find element '${elementId}' in SVG file`); + continue; + } + + let svgElementInfo = this.addSvgElementToRule(svg, svgElement, ruleInfo); + + let $svgElement = $(svgElementInfo.svgElement); + if ($svgElement.length) { + svgElementInfo.svgElement = $svgElement[0]; + + // Create a title element (to support hover over text) + $svgElement.append(document.createElementNS('http://www.w3.org/2000/svg', 'title')); + + $svgElement.off('click').on('click', this.onEntityClick.bind({ instance: this, svgElementInfo: svgElementInfo, entityId: entityId, rule: ruleInfo.rule })); + $svgElement.css('cursor', 'pointer'); + $svgElement.addClass('ha-entity'); + + if ($svgElement.is('text') && ($svgElement[0].id === elementId)) { + let backgroundSvgElement = svgElements.find(svgElement => svgElement.id === ($svgElement[0].id + '.background')); + if (!backgroundSvgElement) { + this.addBackgroundRectToText(svgElementInfo); + } + else { + svgElementInfo.alreadyHadBackground = true; + $(backgroundSvgElement).css('fill-opacity', 0); + } + } + } + } + } + + initGetEntityRuleEntities(rule) { + let targetEntities = []; + + // Split out HA entity groups into separate entities + if (rule.groups) { + for (let entityId of rule.groups) { + let group = this.hass.states[entityId]; + if (group) { + for (let entityId of group.attributes.entity_id) { + targetEntities.push({ entityId: entityId, elementId: entityId }); + } + } + else { + this.logWarning('CONFIG', `Cannot find '${entityId}' in Home Assistant groups`); + } + } + } + + // HA entity treated as is + if (rule.entity) { + rule.entities = [rule.entity]; + } + + // HA entities treated as is + if (rule.entities) { + let entityIds = rule.entities.filter(x => (typeof x === 'string')); + for (let entityId of entityIds) { + let entity = this.hass.states[entityId]; + let isFloorplanVariable = (entityId.split('.')[0] === 'floorplan'); + + if (entity || isFloorplanVariable) { + let elementId = rule.element ? rule.element : entityId; + targetEntities.push({ entityId: entityId, elementId: elementId }); + } + else { + this.logWarning('CONFIG', `Cannot find '${entityId}' in Home Assistant entities`); + } + } + + let entityObjects = rule.entities.filter(x => (typeof x !== 'string')); + for (let entityObject of entityObjects) { + let entity = this.hass.states[entityObject.entity]; + let isFloorplanVariable = (entityObject.entity.split('.')[0] === 'floorplan'); + + if (entity || isFloorplanVariable) { + targetEntities.push({ entityId: entityObject.entity, elementId: entityObject.element }); + } + else { + this.logWarning('CONFIG', `Cannot find '${entityObject.entity}' in Home Assistant entities`); + } + } + } + + return targetEntities; + } + + initElementRule(rule, svg, svgElements) { + if (rule.element) { + rule.elements = [rule.element]; + } + + for (let elementId of rule.elements) { + let svgElement = svgElements.find(svgElement => svgElement.id === elementId); + if (svgElement) { + let elementInfo = this.elementInfos[elementId]; + if (!elementInfo) { + elementInfo = { ruleInfos: [], lastState: undefined }; + this.elementInfos[elementId] = elementInfo; + } + + let ruleInfo = { rule: rule, svgElementInfos: {}, }; + elementInfo.ruleInfos.push(ruleInfo); + + let svgElementInfo = this.addSvgElementToRule(svg, svgElement, ruleInfo); + + let $svgElement = $(svgElementInfo.svgElement); + + $svgElement.off('click').on('click', this.onElementClick.bind({ instance: this, svgElementInfo: svgElementInfo, elementId: elementId, rule: rule })); + $svgElement.css('cursor', 'pointer'); + + if ($svgElement.is('text') && ($svgElement[0].id === elementId)) { + let backgroundSvgElement = svgElements.find(svgElement => svgElement.id === ($svgElement[0].id + '.background')); + if (!backgroundSvgElement) { + this.addBackgroundRectToText(svgElementInfo); + } + else { + svgElementInfo.alreadyHadBackground = true; + $(backgroundSvgElement).css('fill-opacity', 0); + } + } + + let actions = Array.isArray(rule.action) ? rule.action : [rule.action]; + for (let action of actions) { + if (action) { + switch (action.service) { + case 'toggle': + for (let otherElementId of action.data.elements) { + let otherSvgElement = svgElements.find(svgElement => svgElement.id === otherElementId); + $(otherSvgElement).addClass(action.data.default_class); + } + break; + + default: + break; + } + } + } + } + else { + this.logWarning('CONFIG', `Cannot find '${elementId}' in SVG file`); + } + } + } + + addBackgroundRectToText(svgElementInfo) { + let svgElement = svgElementInfo.svgElement; + + let bbox = svgElement.getBBox(); + + let rect = $(document.createElementNS('http://www.w3.org/2000/svg', 'rect')) + .attr('id', svgElement.id + '.background') + .attr('height', bbox.height + 1) + .attr('width', bbox.width + 2) + .attr('x', bbox.x - 1) + .attr('y', bbox.y - 0.5) + .css('fill-opacity', 0); + + $(rect).insertBefore(svgElement); + } + + addSvgElementToRule(svg, svgElement, ruleInfo) { + let svgElementInfo = { + entityId: svgElement.id, + svg: svg, + svgElement: svgElement, + originalSvgElement: svgElement, + originalStroke: svgElement.style.stroke, + originalFill: svgElement.style.fill, + originalClasses: this.getArray(svgElement.classList), + originalBBox: svgElement.getBBox(), + originalClientRect: svgElement.getBoundingClientRect(), + }; + ruleInfo.svgElementInfos[svgElement.id] = svgElementInfo; + + this.addNestedSvgElementsToRule(svgElement, ruleInfo); + + return svgElementInfo; + } + + addNestedSvgElementsToRule(svgElement, ruleInfo) { + $(svgElement).find('*').each((i, svgNestedElement) => { + ruleInfo.svgElementInfos[svgNestedElement.id] = { + entityId: svgElement.id, + svgElement: svgNestedElement, + originalSvgElement: svgNestedElement, + originalStroke: svgNestedElement.style.stroke, + originalFill: svgNestedElement.style.fill, + originalClasses: this.getArray(svgNestedElement.classList), + //originalBBox: svgNestedElement.getBBox(), + //originalClientRect: svgNestedElement.getBoundingClientRect(), + }; + }); + } + + createImageElement(svgElement) { + return $(document.createElementNS('http://www.w3.org/2000/svg', 'image')) + .attr('id', $(svgElement).attr('id')) + .attr('x', $(svgElement).attr('x')) + .attr('y', $(svgElement).attr('y')) + .attr('height', $(svgElement).attr('height')) + .attr('width', $(svgElement).attr('width'))[0]; + /* + return $('object') + .attr('type', $(svgElement).attr('image/svg+xml')) + .attr('id', $(svgElement).attr('id')) + .attr('x', $(svgElement).attr('x')) + .attr('y', $(svgElement).attr('y')) + .attr('height', $(svgElement).attr('height')) + .attr('width', $(svgElement).attr('width'))[0]; + */ + } + + addClass(entityId, svgElement, className) { + if ($(svgElement).hasClass('ha-leave-me-alone')) { + return; + } + + if (!$(svgElement).hasClass(className)) { + this.logDebug('CLASS', `${entityId} (adding class: ${className})`); + $(svgElement).addClass(className); + + if ($(svgElement).is('text')) { + $(svgElement).parent().find(`[id="${entityId}.background"]`).each((i, rectElement) => { + if (!$(rectElement).hasClass(className + '-background')) { + $(rectElement).addClass(className + '-background'); + } + }); + } + } + + $(svgElement).find('*').each((i, svgNestedElement) => { + if (!$(svgNestedElement).hasClass('ha-leave-me-alone')) { + if (!$(svgNestedElement).hasClass(className)) { + $(svgNestedElement).addClass(className); + } + } + }); + } + + removeClasses(entityId, svgElement, classes) { + for (let className of classes) { + if ($(svgElement).hasClass(className)) { + this.logDebug('CLASS', `${entityId} (removing class: ${className})`); + $(svgElement).removeClass(className); + + if ($(svgElement).is('text')) { + $(svgElement).parent().find(`[id="${entityId}.background"]`).each((i, rectElement) => { + if ($(rectElement).hasClass(className + '-background')) { + $(rectElement).removeClass(className + '-background'); + } + }); + } + + $(svgElement).find('*').each((i, svgNestedElement) => { + if ($(svgNestedElement).hasClass(className)) { + $(svgNestedElement).removeClass(className); + } + }); + } + } + } + + setEntityStyle(svgElementInfo, svgElement, entityInfo, ruleInfo) { + let stateConfig = ruleInfo.rule.states.find(stateConfig => (stateConfig.state === entityInfo.lastState.state)); + if (stateConfig) { + let stroke = this.getStroke(stateConfig); + if (stroke) { + svgElement.style.stroke = stroke; + } + else { + if (svgElementInfo.originalStroke) { + svgElement.style.stroke = svgElementInfo.originalStroke; + } + else { + // ??? + } + } + + let fill = this.getFill(stateConfig); + if (fill) { + svgElement.style.fill = fill; + } + else { + if (svgElementInfo.originalFill) { + svgElement.style.fill = svgElementInfo.originalFill; + } + else { + // ??? + } + } + } + } + + /***************************************************************************************************************************/ + /* Entity handling (when states change) + /***************************************************************************************************************************/ + + handleEntities(isInitialLoad) { + this.handleElements(isInitialLoad); + + let changedEntityIds = this.getChangedEntities(isInitialLoad); + changedEntityIds = changedEntityIds.concat(Object.keys(this.variables)); // always assume variables need updating + + if (changedEntityIds && changedEntityIds.length) { + let promises = changedEntityIds.map(entityId => this.handleEntity(entityId, isInitialLoad)); + return Promise.all(promises) + .then(() => { + return Promise.resolve(changedEntityIds); + }); + } + else { + return Promise.resolve(); + } + } + + getChangedEntities(isInitialLoad) { + let changedEntityIds = []; + + let entityIds = Object.keys(this.hass.states); + + let lastMotionEntityInfo, oldLastMotionState, newLastMotionState; + + if (this.lastMotionConfig) { + lastMotionEntityInfo = this.entityInfos[this.lastMotionConfig.entity]; + if (lastMotionEntityInfo && lastMotionEntityInfo.lastState) { + oldLastMotionState = lastMotionEntityInfo.lastState.state; + newLastMotionState = this.hass.states[this.lastMotionConfig.entity].state; + } + } + + for (let entityId of entityIds) { + let entityInfo = this.entityInfos[entityId]; + if (entityInfo) { + let entityState = this.hass.states[entityId]; + + if (isInitialLoad) { + this.logDebug('STATE', `${entityId}: ${entityState.state} (initial load)`); + if (changedEntityIds.indexOf(entityId) < 0) { + changedEntityIds.push(entityId); + } + } + else if (entityInfo.lastState) { + let oldState = entityInfo.lastState.state; + let newState = entityState.state; + + if (entityState.last_changed !== entityInfo.lastState.last_changed) { + this.logDebug('STATE', `${entityId}: ${newState} (last changed ${moment(entityInfo.lastState.last_changed).format("DD-MMM-YYYY HH:mm:ss")})`); + if (changedEntityIds.indexOf(entityId) < 0) { + changedEntityIds.push(entityId); + } + } + else { + if (!this.equal(entityInfo.lastState.attributes, entityState.attributes)) { + this.logDebug('STATE', `${entityId}: attributes (last updated ${moment(entityInfo.lastState.last_changed).format("DD-MMM-YYYY HH:mm:ss")})`); + if (changedEntityIds.indexOf(entityId) < 0) { + changedEntityIds.push(entityId); + } + } + } + + if (this.lastMotionConfig) { + if ((newLastMotionState !== oldLastMotionState) && (entityId.indexOf('binary_sensor') >= 0)) { + let friendlyName = entityState.attributes.friendly_name; + + if (friendlyName === newLastMotionState) { + this.logDebug('LAST_MOTION', `${entityId} (new)`); + if (changedEntityIds.indexOf(entityId) < 0) { + changedEntityIds.push(entityId); + } + } + else if (friendlyName === oldLastMotionState) { + this.logDebug('LAST_MOTION', `${entityId} (old)`); + if (changedEntityIds.indexOf(entityId) < 0) { + changedEntityIds.push(entityId); + } + } + } + } + } + } + } + + return changedEntityIds; + } + + handleEntity(entityId, isInitialLoad) { + let entityState = this.hass.states[entityId]; + let entityInfo = this.entityInfos[entityId]; + + entityInfo.lastState = Object.assign({}, entityState); + + return this.handleEntityUpdateDom(entityInfo) + .then(() => { + this.handleEntityUpdateCss(entityInfo, isInitialLoad); + this.handleEntityUpdateLastMotionCss(entityInfo); + this.handleEntitySetHoverOver(entityInfo); + + return Promise.resolve(); + }); + } + + handleEntityUpdateDom(entityInfo) { + let promises = []; + + let entityId = entityInfo.entityId; + let entityState = this.hass.states[entityId]; + + for (let ruleInfo of entityInfo.ruleInfos) { + for (let svgElementId in ruleInfo.svgElementInfos) { + let svgElementInfo = ruleInfo.svgElementInfos[svgElementId]; + + if ($(svgElementInfo.svgElement).is('text')) { + this.handleEntityUpdateText(entityId, ruleInfo, svgElementInfo); + } + else if (ruleInfo.rule.image || ruleInfo.rule.image_template) { + promises.push(this.handleEntityUpdateImage(entityId, ruleInfo, svgElementInfo)); + } + } + } + + return promises.length ? Promise.all(promises) : Promise.resolve(); + } + + handleElements(isInitialLoad) { + let promises = []; + + Object.keys(this.elementInfos).map(key => { + let elementInfo = this.elementInfos[key]; + let promise = this.handleElementUpdateDom(elementInfo) + .then(() => { + return this.handleElementUpdateCss(elementInfo, isInitialLoad); + }); + + promises.push(promise); + }); + + return promises.length ? Promise.all(promises) : Promise.resolve(); + } + + handleElementUpdateDom(elementInfo) { + let promises = []; + + for (let ruleInfo of elementInfo.ruleInfos) { + for (let svgElementId in ruleInfo.svgElementInfos) { + let svgElementInfo = ruleInfo.svgElementInfos[svgElementId]; + + if ($(svgElementInfo.svgElement).is('text')) { + this.handleEntityUpdateText(svgElementId, ruleInfo, svgElementInfo); + } + else if (ruleInfo.rule.image || ruleInfo.rule.image_template) { + promises.push(this.handleEntityUpdateImage(svgElementId, ruleInfo, svgElementInfo)); + } + } + } + + return promises.length ? Promise.all(promises) : Promise.resolve(); + } + + handleEntityUpdateText(entityId, ruleInfo, svgElementInfo) { + let svgElement = svgElementInfo.svgElement; + let state = this.hass.states[entityId] ? this.hass.states[entityId].state : undefined; + + let text = ruleInfo.rule.text_template ? this.evaluate(ruleInfo.rule.text_template, entityId, svgElement) : state; + + let tspan = $(svgElement).find('tspan'); + if (tspan.length) { + $(tspan).text(text); + } + else { + let title = $(svgElement).find('title'); + $(svgElement).text(text); + if (title.length) { + $(svgElement).append(title); + } + } + + if (!svgElementInfo.alreadyHadBackground) { + let rect = $(svgElement).parent().find(`[id="${entityId}.background"]`); + if (rect.length) { + if ($(svgElement).css('display') != 'none') { + let parentSvg = $(svgElement).parents('svg').eq(0); + if ($(parentSvg).css('display') !== 'none') { + let bbox = svgElement.getBBox(); + $(rect) + .attr('x', bbox.x - 1) + .attr('y', bbox.y - 0.5) + .attr('height', bbox.height + 1) + .attr('width', bbox.width + 2) + .height(bbox.height + 1) + .width(bbox.width + 2); + } + } + } + } + } + + handleEntityUpdateImage(entityId, ruleInfo, svgElementInfo) { + let svgElement = svgElementInfo.svgElement; + + let imageUrl = ruleInfo.rule.image ? ruleInfo.rule.image : this.evaluate(ruleInfo.rule.image_template, entityId, svgElement); + + if (imageUrl && (ruleInfo.imageUrl !== imageUrl)) { + ruleInfo.imageUrl = imageUrl; + + if (ruleInfo.imageLoader) { + clearInterval(ruleInfo.imageLoader); // cancel any previous image loading for this rule + } + + if (ruleInfo.rule.image_refresh_interval) { + let refreshInterval = parseInt(ruleInfo.rule.image_refresh_interval); + + ruleInfo.imageLoader = setInterval((imageUrl, svgElement) => { + this.loadImage(imageUrl, svgElementInfo, entityId, ruleInfo.rule) + .catch(error => { + this.handleError(error); + }); + }, refreshInterval * 1000, imageUrl, svgElement); + } + + return this.loadImage(imageUrl, svgElementInfo, entityId, ruleInfo.rule) + .catch(error => { + this.handleError(error); + }); + } + else { + return Promise.resolve(); + } + } + + handleEntitySetHoverOver(entityInfo) { + let entityId = entityInfo.entityId; + let entityState = this.hass.states[entityId]; + + for (let ruleInfo of entityInfo.ruleInfos) { + if (ruleInfo.rule.hover_over !== false) { + for (let svgElementId in ruleInfo.svgElementInfos) { + let svgElementInfo = ruleInfo.svgElementInfos[svgElementId]; + + this.handlEntitySetHoverOverText(svgElementInfo.svgElement, entityState); + } + } + } + } + + handlEntitySetHoverOverText(element, entityState) { + let dateFormat = this.config.date_format ? this.config.date_format : 'DD-MMM-YYYY'; + + $(element).find('title').each((i, titleElement) => { + let lastChangedElapsed = moment().to(moment(entityState.last_changed)); + let lastChangedDate = moment(entityState.last_changed).format(dateFormat); + let lastChangedTime = moment(entityState.last_changed).format('HH:mm:ss'); + + let lastUpdatedElapsed = moment().to(moment(entityState.last_updated)); + let lastUpdatedDate = moment(entityState.last_updated).format(dateFormat); + let lastUpdatedTime = moment(entityState.last_updated).format('HH:mm:ss'); + + let titleText = `${entityState.attributes.friendly_name}\n`; + titleText += `State: ${entityState.state}\n\n`; + + Object.keys(entityState.attributes).map(key => { + titleText += `${key}: ${entityState.attributes[key]}\n`; + }); + titleText += '\n'; + + titleText += `Last changed: ${lastChangedDate} ${lastChangedTime}\n`; + titleText += `Last updated: ${lastUpdatedDate} ${lastUpdatedTime}`; + + $(titleElement).html(titleText); + }); + } + + handleElementUpdateCss(elementInfo, isInitialLoad) { + if (!this.cssRules || !this.cssRules.length) { + return; + } + + for (let ruleInfo of elementInfo.ruleInfos) { + for (let svgElementId in ruleInfo.svgElementInfos) { + let svgElementInfo = ruleInfo.svgElementInfos[svgElementId]; + + this.handleUpdateElementCss(svgElementInfo, ruleInfo); + } + } + } + + handleEntityUpdateCss(entityInfo, isInitialLoad) { + if (!this.cssRules || !this.cssRules.length) { + return; + } + + for (let ruleInfo of entityInfo.ruleInfos) { + for (let svgElementId in ruleInfo.svgElementInfos) { + let svgElementInfo = ruleInfo.svgElementInfos[svgElementId]; + + if (svgElementInfo.svgElement) { // images may not have been updated yet + let wasTransitionApplied = this.handleEntityUpdateTransitionCss(entityInfo, ruleInfo, svgElementInfo, isInitialLoad); + this.handleUpdateCss(entityInfo, svgElementInfo, ruleInfo, wasTransitionApplied); + } + } + } + } + + handleEntityUpdateTransitionCss(entityInfo, ruleInfo, svgElementInfo, isInitialLoad) { + let entityId = entityInfo.entityId; + let entityState = this.hass.states[entityId]; + let svgElement = svgElementInfo.svgElement; + + let wasTransitionApplied = false; + + if (ruleInfo.rule.states && ruleInfo.rule.state_transitions) { + let transitionConfig = ruleInfo.rule.state_transitions.find(transitionConfig => (transitionConfig.to_state === entityState.state)); + if (transitionConfig && transitionConfig.from_state && transitionConfig.to_state && transitionConfig.duration) { + let elapsed = Math.max(moment().diff(moment(entityState.last_changed), 'milliseconds'), 0); + let remaining = (transitionConfig.duration * 1000) - elapsed; + + let fromStateConfig = ruleInfo.rule.states.find(stateConfig => (stateConfig.state === transitionConfig.from_state)); + let toStateConfig = ruleInfo.rule.states.find(stateConfig => (stateConfig.state === transitionConfig.to_state)); + + let fromColor = this.getFill(fromStateConfig); + let toColor = this.getFill(toStateConfig); + + if (fromColor && toColor) { + if (remaining > 0) { + let transition = this.entityTransitions[entityId]; + if (!transition) { + this.logDebug('TRANSITION', `${entityId} (created)`); + transition = { + entityId: entityId, + svgElementInfo: svgElementInfo, + ruleInfo: ruleInfo, + duration: transitionConfig.duration, + fromStateConfig: fromStateConfig, + toStateConfig: toStateConfig, + fromColor: fromColor, + toColor: toColor, + startMoment: undefined, + endMoment: undefined, + isActive: false, + }; + this.entityTransitions[entityId] = transition; + } + + // Assume the transition starts (or started) when the origin state change occurred + transition.startMoment = this.serverToLocalMoment(moment(entityState.last_changed)); + transition.endMoment = transition.startMoment.clone(); + transition.endMoment.add(transition.duration, 'seconds'); + + // If the transition is not currently running, kick it off + if (!transition.isActive) { + // If this state change just occurred, the transition starts as of now + if (!isInitialLoad) { + let nowMoment = moment(); + transition.startMoment = nowMoment.clone(); + transition.endMoment = transition.startMoment.clone(); + transition.endMoment.add(transition.duration, 'seconds'); + } + + this.logDebug('TRANSITION', `${transition.entityId}: (start)`); + transition.isActive = true; + this.handleEntityTransition(transition); + } + else { + // If the transition is currently running, it will be extended with latest start / end times + this.logDebug('TRANSITION', `${transition.entityId} (continue)`); + } + } + else { + this.setEntityStyle(svgElementInfo, svgElement, entityInfo, ruleInfo); + } + } + else { + this.setEntityStyle(svgElementInfo, svgElement, entityInfo, ruleInfo); + } + wasTransitionApplied = true; + } + } + + return wasTransitionApplied; + } + + handleUpdateCss(entityInfo, svgElementInfo, ruleInfo, wasTransitionApplied) { + let entityId = entityInfo.entityId; + let svgElement = svgElementInfo.svgElement; + + let targetClass = undefined; + let obsoleteClasses = []; + + if (ruleInfo.rule.class_template) { + targetClass = this.evaluate(ruleInfo.rule.class_template, entityId, svgElement); + } + + // Get the config for the current state + if (ruleInfo.rule.states) { + let entityState = this.hass.states[entityId]; + + let stateConfig = ruleInfo.rule.states.find(stateConfig => (stateConfig.state === entityState.state)); + if (stateConfig && stateConfig.class && !wasTransitionApplied) { + targetClass = stateConfig.class; + } + + // Remove any other previously-added state classes + for (let otherStateConfig of ruleInfo.rule.states) { + if (!stateConfig || (otherStateConfig.state !== stateConfig.state)) { + if (otherStateConfig.class && (otherStateConfig.class !== targetClass) && (otherStateConfig.class !== 'ha-entity') && $(svgElement).hasClass(otherStateConfig.class)) { + if (svgElementInfo.originalClasses.indexOf(otherStateConfig.class) < 0) { + obsoleteClasses.push(otherStateConfig.class); + } + } + } + } + } + else { + if (svgElement.classList) { + for (let otherClassName of this.getArray(svgElement.classList)) { + if ((otherClassName !== targetClass) && (otherClassName !== 'ha-entity')) { + if (svgElementInfo.originalClasses.indexOf(otherClassName) < 0) { + obsoleteClasses.push(otherClassName); + } + } + } + } + } + + // Remove any obsolete classes from the entity + if (obsoleteClasses.length) { + //this.logDebug(`${entityId}: Removing obsolete classes: ${obsoleteClasses.join(', ')}`); + this.removeClasses(entityId, svgElement, obsoleteClasses); + } + + // Add the target class to the entity + if (targetClass && !$(svgElement).hasClass(targetClass)) { + let hasTransitionConfig = ruleInfo.rule.states && ruleInfo.rule.state_transitions; + if (hasTransitionConfig && !wasTransitionApplied) { + let transition = this.entityTransitions[entityId]; + if (transition && transition.isActive) { + this.logDebug('TRANSITION', `${transition.entityId} (cancel)`); + transition.isActive = false; + } + } + + this.addClass(entityId, svgElement, targetClass); + } + } + + handleUpdateElementCss(svgElementInfo, ruleInfo) { + let entityId = svgElementInfo.entityId; + let svgElement = svgElementInfo.svgElement; + + let targetClass = undefined; + if (ruleInfo.rule.class_template) { + targetClass = this.evaluate(ruleInfo.rule.class_template, entityId, svgElement); + } + + let obsoleteClasses = []; + for (let otherClassName of this.getArray(svgElement.classList)) { + if ((otherClassName !== targetClass) && (otherClassName !== 'ha-entity')) { + if (svgElementInfo.originalClasses.indexOf(otherClassName) < 0) { + obsoleteClasses.push(otherClassName); + } + } + } + + // Remove any obsolete classes from the entity + if (obsoleteClasses.length) { + this.removeClasses(entityId, svgElement, obsoleteClasses); + } + + // Add the target class to the entity + if (targetClass && !$(svgElement).hasClass(targetClass)) { + this.addClass(entityId, svgElement, targetClass); + } + } + + handleEntityTransition(transition) { + if (!transition.isActive) { + return; + } + + let nowMoment = moment(); + + let isExpired = (nowMoment >= transition.endMoment); + + let ratio = isExpired ? 1 : (nowMoment - transition.startMoment) / (transition.endMoment - transition.startMoment); + let color = this.getTransitionColor(transition.fromColor, transition.toColor, ratio); + //this.logDebug('TRANSITION', `${transition.entityId} (ratio: ${ratio}, element: ${transition.svgElementInfo.svgElement.id}, fill: ${color})`); + transition.svgElementInfo.svgElement.style.fill = color; + + if (isExpired) { + transition.isActive = false; + this.logDebug('TRANSITION', `${transition.entityId} (end)`); + return; + } + + setTimeout(() => { + this.handleEntityTransition(transition); + }, 100); + } + + handleEntityUpdateLastMotionCss(entityInfo) { + if (!this.lastMotionConfig || !this.cssRules || !this.cssRules.length) { + return; + } + + let entityId = entityInfo.entityId; + let entityState = this.hass.states[entityId]; + + for (let ruleInfo of entityInfo.ruleInfos) { + for (let svgElementId in ruleInfo.svgElementInfos) { + let svgElementInfo = ruleInfo.svgElementInfos[svgElementId]; + let svgElement = svgElementInfo.svgElement; + + if (this.hass.states[this.lastMotionConfig.entity] && + (entityState.attributes.friendly_name === this.hass.states[this.lastMotionConfig.entity].state)) { + if (!$(svgElement).hasClass(this.lastMotionConfig.class)) { + //this.logDebug(`${entityId}: Adding last motion class '${this.lastMotionConfig.class}'`); + $(svgElement).addClass(this.lastMotionConfig.class); + } + } + else { + if ($(svgElement).hasClass(this.lastMotionConfig.class)) { + //this.logDebug(`${entityId}: Removing last motion class '${this.lastMotionConfig.class}'`); + $(svgElement).removeClass(this.lastMotionConfig.class); + } + } + } + } + } + + /***************************************************************************************************************************/ + /* Floorplan helper functions + /***************************************************************************************************************************/ + + isOptionEnabled(option) { + return ((option === null) || (option !== undefined)); + } + + isLastMotionEnabled() { + return this.lastMotionConfig && this.config.last_motion.entity && this.config.last_motion.class; + } + + validateConfig(config) { + let isValid = true; + + if (!config.pages && !config.rules) { + this.setIsLoading(false); + this.logWarning('CONFIG', `Cannot find 'pages' nor 'rules' in floorplan configuration`); + isValid = false; + } + else { + if (config.pages) { + if (!config.pages.length) { + this.logWarning('CONFIG', `The 'pages' section must contain one or more pages in floorplan configuration`); + isValid = false; + } + } + else { + if (!config.rules) { + this.logWarning('CONFIG', `Cannot find 'rules' in floorplan configuration`); + isValid = false; + } + + let invalidRules = config.rules.filter(x => x.entities && x.elements); + if (invalidRules.length) { + this.logWarning('CONFIG', `A rule cannot contain both 'entities' and 'elements' in floorplan configuration`); + isValid = false; + } + + invalidRules = config.rules.filter(x => !(x.entity || x.entities) && !(x.element || x.elements)); + if (invalidRules.length) { + this.logWarning('CONFIG', `A rule must contain either 'entities' or 'elements' in floorplan configuration`); + isValid = false; + } + } + } + + return isValid; + } + + localToServerMoment(localMoment) { + let serverMoment = localMoment.clone(); + if (this.timeDifference >= 0) + serverMoment.subtract(this.timeDifference, 'milliseconds'); + else + serverMoment.add(Math.abs(this.timeDifference), 'milliseconds'); + return serverMoment; + } + + serverToLocalMoment(serverMoment) { + let localMoment = serverMoment.clone(); + if (this.timeDifference >= 0) + localMoment.add(Math.abs(this.timeDifference), 'milliseconds'); + else + localMoment.subtract(this.timeDifference, 'milliseconds'); + return localMoment; + } + + evaluate(code, entityId, svgElement) { + let entityState = this.hass.states[entityId]; + let functionBody = (code.indexOf('${') >= 0) ? `\`${code}\`;` : code; + functionBody = (functionBody.indexOf('return') >= 0) ? functionBody : `return ${functionBody};`; + let func = new Function('entity', 'entities', 'hass', 'config', 'element', functionBody); + return func(entityState, this.hass.states, this.hass, this.config, svgElement); + } + + /***************************************************************************************************************************/ + /* Event handlers + /***************************************************************************************************************************/ + + onElementClick(e) { + e.stopPropagation(); + this.instance.onActionClick(this.svgElementInfo, this.elementId, this.elementId, this.rule); + } + + onEntityClick(e) { + e.stopPropagation(); + this.instance.onActionClick(this.svgElementInfo, this.entityId, this.elementId, this.rule); + } + + onActionClick(svgElementInfo, entityId, elementId, rule) { + if (!rule || !rule.action) { + if (entityId && (rule.more_info !== false)) { + this.openMoreInfo(entityId); + } + return; + } + + let calledServiceCount = 0; + + let svgElement = svgElementInfo.svgElement; + + let actions = Array.isArray(rule.action) ? rule.action : [rule.action]; + for (let action of actions) { + if (action.service || action.service_template) { + let actionService = this.getActionService(action, entityId, svgElement); + + switch (this.getDomain(actionService)) { + case 'floorplan': + this.callFloorplanService(action, entityId, svgElementInfo); + break; + + default: + this.callHomeAssistantService(action, entityId, svgElementInfo); + break; + } + + calledServiceCount++; + } + } + + if (!calledServiceCount) { + if (entityId && (rule.more_info !== false)) { + this.openMoreInfo(entityId); + } + } + } + + callFloorplanService(action, entityId, svgElementInfo) { + let svgElement = svgElementInfo ? svgElementInfo.svgElement : undefined; + + let actionService = this.getActionService(action, entityId, svgElement); + let actionData = this.getActionData(action, entityId, svgElement); + + switch (this.getService(actionService)) { + case 'class_toggle': + if (actionData) { + let classes = actionData.classes; + + for (let otherElementId of actionData.elements) { + let otherSvgElement = $(svgElementInfo.svg).find(`[id="${otherElementId}"]`); + + if ($(otherSvgElement).hasClass(classes[0])) { + $(otherSvgElement).removeClass(classes[0]); + $(otherSvgElement).addClass(classes[1]); + } + else if ($(otherSvgElement).hasClass(classes[1])) { + $(otherSvgElement).removeClass(classes[1]); + $(otherSvgElement).addClass(classes[0]); + } + else { + $(otherSvgElement).addClass(actionData.default_class); + } + } + } + break; + + case 'page_navigate': + let page_id = actionData.page_id; + let targetPageInfo = page_id && this.pageInfos[page_id]; + + if (targetPageInfo) { + Object.keys(this.pageInfos).map(key => { + let pageInfo = this.pageInfos[key]; + + if (!pageInfo.isMaster) { + if ($(pageInfo.svg).css('display') !== 'none') { + $(pageInfo.svg).css('display', 'none'); + } + } + }); + + $(targetPageInfo.svg).css('display', 'initial'); + } + break; + + case 'variable_set': + if (actionData.variable) { + let attributes = []; + + if (actionData.attributes) { + for (let attribute of actionData.attributes) { + let attributeValue = this.getActionValue(attribute, entityId, svgElement); + attributes.push({ name: attribute.attribute, value: attributeValue }); + } + } + + let value = this.getActionValue(actionData, entityId, svgElement); + this.setVariable(actionData.variable, value, attributes); + } + break; + + default: + // Unknown floorplan service + break; + } + } + + getActionValue(action, entityId, svgElement) { + let value = action.value; + if (action.value_template) { + value = this.evaluate(action.value_template, entityId, svgElement); + } + return value; + } + + setVariable(variableName, value, attributes, isInitialLoad) { + this.variables[variableName] = value; + + if (this.hass.states[variableName]) { + this.hass.states[variableName].state = value; + + for (let attribute of attributes) { + this.hass.states[variableName].attributes[attribute.name] = attribute.value; + } + } + + for (let otherVariableName of Object.keys(this.variables)) { + this.hass.states[otherVariableName].last_changed = new Date(); // mark all variables as changed + } + + // Simulate an event change to all entities + if (!isInitialLoad) { + this.handleEntitiesDebounced(); // use debounced wrapper + } + } + + /***************************************************************************************************************************/ + /* Home Assisant helper functions + /***************************************************************************************************************************/ + + callHomeAssistantService(action, entityId, svgElementInfo) { + let svgElement = svgElementInfo ? svgElementInfo.svgElement : undefined; + + let actionService = this.getActionService(action, entityId, svgElement); + let actionData = this.getActionData(action, entityId, svgElement); + + /* + if (!actionData.entity_id && entityId) { + actionData.entity_id = entityId; + } + */ + + this.hass.callService(this.getDomain(actionService), this.getService(actionService), actionData); + } + + getActionData(action, entityId, svgElement) { + let data = action.data ? action.data : {}; + if (action.data_template) { + let result = this.evaluate(action.data_template, entityId, svgElement); + data = (typeof result === 'string') ? JSON.parse(result) : result; + } + return data; + } + + getActionService(action, entityId, svgElement) { + let service = action.service; + if (action.service_template) { + service = this.evaluate(action.service_template, entityId, svgElement); + } + return service; + } + + getDomain(actionService) { + return actionService.split(".")[0]; + } + + getService(actionService) { + return actionService.split(".")[1]; + } + + /***************************************************************************************************************************/ + /* Logging / error handling functions + /***************************************************************************************************************************/ + + handleWindowError(msg, url, lineNo, columnNo, error) { + this.setIsLoading(false); + + if (msg.toLowerCase().indexOf("script error") >= 0) { + this.logError('Script error: See browser console for detail'); + } + else { + let message = [ + msg, + 'URL: ' + url, + 'Line: ' + lineNo + ', column: ' + columnNo, + 'Error: ' + JSON.stringify(error) + ].join('
'); + + this.logError(message); + } + + return false; + } + + handleError(error) { + let message = error; + if (error.stack) { + message = `${error.stack}`; + } + else if (error.message) { + message = `${error.message}`; + } + + this.log('error', message); + } + + logError(message) { + this.log('error', message); + } + + logWarning(area, message) { + this.log('warning', `${area} ${message}`); + } + + logInfo(area, message) { + this.log('info', `${area} ${message}`); + } + + logDebug(area, message) { + this.log('debug', `${area} ${message}`); + } + + log(level, message) { + let text = `${moment().format("DD-MM-YYYY HH:mm:ss")} ${level.toUpperCase()} ${message}`; + + switch (level) { + case 'error': + console.error(text); + break; + + case 'warning': + console.warn(text); + break; + + case 'error': + console.info(text); + break; + + default: + console.log(text); + break; + } + + if (!this.config) { + // Always log messages before the config has been loaded + } + else if (!this.logLevels || !this.logLevels.length || (this.logLevels.indexOf(level) < 0)) { + return; + } + + let log = $(this.doc).find('#log'); + $(log).find('ul').prepend(`
  • ${text}
  • `) + $(log).css('display', 'block'); + } + + /***************************************************************************************************************************/ + /* CSS helper functions + /***************************************************************************************************************************/ + + getStroke(stateConfig) { + let stroke = undefined; + + for (let cssRule of this.cssRules) { + if (cssRule.selectorText && cssRule.selectorText.indexOf(`.${stateConfig.class}`) >= 0) { + if (cssRule.style && cssRule.style.stroke) { + if (cssRule.style.stroke[0] === '#') { + stroke = cssRule.style.stroke; + } + else { + let rgb = cssRule.style.stroke.substring(4).slice(0, -1).split(',').map(x => parseInt(x)); + stroke = `#${rgb[0].toString(16)[0]}${rgb[1].toString(16)[0]}${rgb[2].toString(16)[0]}`; + } + } + } + } + + return stroke; + } + + getFill(stateConfig) { + let fill = undefined; + + for (let cssRule of this.cssRules) { + if (cssRule.selectorText && cssRule.selectorText.indexOf(`.${stateConfig.class}`) >= 0) { + if (cssRule.style && cssRule.style.fill) { + if (cssRule.style.fill[0] === '#') { + fill = cssRule.style.fill; + } + else { + let rgb = cssRule.style.fill.substring(4).slice(0, -1).split(',').map(x => parseInt(x)); + fill = `#${rgb[0].toString(16)}${rgb[1].toString(16)}${rgb[2].toString(16)}`; + } + } + } + } + + return fill; + } + + getTransitionColor(fromColor, toColor, value) { + return (value <= 0) ? fromColor : + ((value >= 1) ? toColor : this.rgbToHex(this.mix(this.hexToRgb(toColor), this.hexToRgb(fromColor), value))); + } + + /***************************************************************************************************************************/ + /* General helper functions + /***************************************************************************************************************************/ + + fetchTextResource(resourceUrl, useCache) { + resourceUrl = this.cacheBuster(resourceUrl); + useCache = false; + + return new Promise((resolve, reject) => { + let request = new Request(resourceUrl, { + cache: (useCache === true) ? 'reload' : 'no-cache', + }); + + fetch(request) + .then((response) => { + if (response.ok) { + return response.text(); + } + else { + throw new Error(`Error fetching resource`); + } + }) + .then((result) => resolve(result)) + .catch((err) => { + reject(new URIError(`${resourceUrl}: ${err.message}`)); + }); + }); + } + + fetchImageResource(resourceUrl, useCache) { + resourceUrl = this.cacheBuster(resourceUrl); + useCache = false; + + return new Promise((resolve, reject) => { + let request = new Request(resourceUrl, { + cache: (useCache === true) ? 'reload' : 'no-cache', + headers: new Headers({ 'Content-Type': 'text/plain; charset=x-user-defined' }), + }); + + fetch(request) + .then((response) => { + if (response.ok) { + return response.arrayBuffer(); + } + else { + throw new Error(`Error fetching resource`); + } + }) + .then((result) => resolve(`data:image/jpeg;base64,${this.arrayBufferToBase64(result)}`)) + .catch((err) => { + reject(new URIError(`${resourceUrl}: ${err.message}`)); + }); + }); + } + + /***************************************************************************************************************************/ + /* Utility functions + /***************************************************************************************************************************/ + + getArray(list) { + return Array.isArray(list) ? list : Object.keys(list).map(key => list[key]); + } + + arrayBufferToBase64(buffer) { + let binary = ''; + let bytes = [].slice.call(new Uint8Array(buffer)); + + bytes.forEach((b) => binary += String.fromCharCode(b)); + + let base64 = window.btoa(binary); + + // IOS / Safari will not render base64 images unless length is divisible by 4 + while ((base64.length % 4) > 0) { + base64 += '='; + } + + return base64; + } + + base64Encodebase64Encode(str) { + let CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + let out = "", i = 0, len = str.length, c1, c2, c3; + while (i < len) { + c1 = str.charCodeAt(i++) & 0xff; + if (i === len) { + out += CHARS.charAt(c1 >> 2); + out += CHARS.charAt((c1 & 0x3) << 4); + out += "=="; + break; + } + c2 = str.charCodeAt(i++); + if (i === len) { + out += CHARS.charAt(c1 >> 2); + out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); + out += CHARS.charAt((c2 & 0xF) << 2); + out += "="; + break; + } + c3 = str.charCodeAt(i++); + out += CHARS.charAt(c1 >> 2); + out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); + out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)); + out += CHARS.charAt(c3 & 0x3F); + } + + // IOS / Safari will not render base64 images unless length is divisible by 4 + while ((out.length % 4) > 0) { + out += '='; + } + + return out; + } + + cacheBuster(url) { + return `${url}${(url.indexOf('?') >= 0) ? '&' : '?'}_=${new Date().getTime()}`; + } + + debounce(func, wait, immediate) { + let timeout; + return function () { + let context = this, args = arguments; + + let later = function () { + timeout = null; + if (!immediate) func.apply(context, args); + }; + + let callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + + if (callNow) func.apply(context, args); + }; + } + + equal(a, b) { + if (a === b) return true; + + let arrA = Array.isArray(a) + , arrB = Array.isArray(b) + , i; + + if (arrA && arrB) { + if (a.length != b.length) return false; + for (i = 0; i < a.length; i++) + if (!this.equal(a[i], b[i])) return false; + return true; + } + + if (arrA != arrB) return false; + + if (a && b && typeof a === 'object' && typeof b === 'object') { + let keys = Object.keys(a); + if (keys.length !== Object.keys(b).length) return false; + + let dateA = a instanceof Date + , dateB = b instanceof Date; + if (dateA && dateB) return a.getTime() == b.getTime(); + if (dateA != dateB) return false; + + let regexpA = a instanceof RegExp + , regexpB = b instanceof RegExp; + if (regexpA && regexpB) return a.toString() == b.toString(); + if (regexpA != regexpB) return false; + + for (i = 0; i < keys.length; i++) + if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false; + + for (i = 0; i < keys.length; i++) + if (!this.equal(a[keys[i]], b[keys[i]])) return false; + + return true; + } + + return false; + } + + /***************************************************************************************************************************/ + /* Color functions + /***************************************************************************************************************************/ + + rgbToHex(rgb) { + return "#" + ((1 << 24) + (rgb[0] << 16) + (rgb[1] << 8) + rgb[2]).toString(16).slice(1); + } + + hexToRgb(hex) { + // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") + let shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + hex = hex.replace(shorthandRegex, (m, r, g, b) => { + return r + r + g + g + b + b; + }); + + let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; + } + + mix(color1, color2, weight) { + let p = weight; + let w = p * 2 - 1; + let w1 = ((w / 1) + 1) / 2; + let w2 = 1 - w1; + let rgb = [ + Math.round(color1.r * w1 + color2.r * w2), + Math.round(color1.g * w1 + color2.g * w2), + Math.round(color1.b * w1 + color2.b * w2) + ]; + return rgb; + } + + wrap(svgTextElement, width, content) { + let $text = $(svgTextElement); + + let words = content.split(/\s+/).reverse(); + let line = []; + let lineNumber = 0; + let lineHeight = 1.1; // ems + let x = $text.attr("x"); + let y = $text.attr("y"); + //let dy = 0; //parseFloat($text.attr("dy")), + + let $tspan = $text.append("tspan") + .attr("x", x) + .attr("y", y) + .attr("dy", dy + "em") + .text(null); + + let word; + while (word = words.pop()) { + line.push(word); + $tspan.text(line.join(" ")); + if ($tspan.node().getComputedTextLength() > width) { + line.pop(); + $tspan.text(line.join(" ")); + line = [word]; + $tspan = $text.append("tspan") + .attr("x", x) + .attr("y", y) + .attr("dy", ++lineNumber * lineHeight + dy + "em") + .text(word); + } + } + } + } + + window.Floorplan = Floorplan; +}).call(this); diff --git a/www/custom_ui/floorplan/lib/fully-kiosk.js b/www/custom_ui/floorplan/lib/fully-kiosk.js new file mode 100755 index 00000000..daef8c93 --- /dev/null +++ b/www/custom_ui/floorplan/lib/fully-kiosk.js @@ -0,0 +1,591 @@ +/* + Floorplan Fully Kiosk for Home Assistant + Version: 1.0.7.42 + By Petar Kozul + https://github.com/pkozul/ha-floorplan +*/ + +'use strict'; + +(function () { + if (typeof window.FullyKiosk === 'function') { + return; + } + + class FullyKiosk { + constructor(floorplan) { + this.version = '1.0.7.42'; + + this.floorplan = floorplan; + this.authToken = (window.localStorage && window.localStorage.authToken) ? window.localStorage.authToken : ''; + + this.fullyInfo = {}; + this.fullyState = {}; + this.iBeacons = {}; + } + + /***************************************************************************************************************************/ + /* Initialization + /***************************************************************************************************************************/ + + init() { + this.logInfo('VERSION', `Fully Kiosk v${this.version}`); + + if (typeof fully === "undefined") { + this.logInfo('FULLY_KIOSK', `Fully Kiosk is not running or not enabled. You can enable it via Settings > Other Settings > Enable Website Integration (PLUS).`); + return; + } + + let macAddress = fully.getMacAddress().toLowerCase(); + + let device = this.floorplan.config && this.floorplan.config.fully_kiosk && + this.floorplan.config.fully_kiosk.find(x => x.address.toLowerCase() == macAddress); + if (!device) { + return; + } + + if (!navigator.geolocation) { + this.logInfo('FULLY_KIOSK', "Geolocation is not supported or not enabled. You can enable it via Settings > Web Content Settings > Enable Geolocation Access (PLUS) and on the device via Google Settings > Location > Fully Kiosk Browser."); + } + + this.fullyInfo = this.getFullyInfo(device); + + this.updateFullyState(); + this.updateCurrentPosition(); + + this.initAudio(); + this.addAudioEventHandlers(); + this.addFullyEventHandlers(); + this.subscribeHomeAssistantEvents(); + + this.sendMotionState(); + this.sendPluggedState(); + this.sendScreensaverState(); + this.sendMediaPlayerState(); + } + + initAudio() { + this.audio = new Audio(); + this.isAudioPlaying = false; + } + + getFullyInfo(device) { + return { + motionBinarySensorEntityId: device.motion_sensor, + pluggedBinarySensorEntityId: device.plugged_sensor, + screensaverLightEntityId: device.screensaver_light, + mediaPlayerEntityId: device.media_player, + + startUrl: fully.getStartUrl(), + currentLocale: fully.getCurrentLocale(), + ipAddressv4: fully.getIp4Address(), + ipAddressv6: fully.getIp6Address(), + macAddress: fully.getMacAddress(), + wifiSSID: fully.getWifiSsid(), + serialNumber: fully.getSerialNumber(), + deviceId: fully.getDeviceId(), + + isMotionDetected: false, + isScreensaverOn: false, + + supportsGeolocation: (navigator.geolocation != undefined), + }; + } + + updateFullyState() { + this.fullyState.batteryLevel = fully.getBatteryLevel(); + this.fullyState.screenBrightness = fully.getScreenBrightness(); + this.fullyState.isScreenOn = fully.getScreenOn(); + this.fullyState.isPluggedIn = fully.isPlugged(); + } + + /***************************************************************************************************************************/ + /* Set up event handlers + /***************************************************************************************************************************/ + + addAudioEventHandlers() { + this.audio.addEventListener('play', this.onAudioPlay.bind(this)); + this.audio.addEventListener('playing', this.onAudioPlaying.bind(this)); + this.audio.addEventListener('pause', this.onAudioPause.bind(this)); + this.audio.addEventListener('ended', this.onAudioEnded.bind(this)); + this.audio.addEventListener('volumechange', this.onAudioVolumeChange.bind(this)); + } + + addFullyEventHandlers() { + window['onFullyEvent'] = (e) => { window.dispatchEvent(new Event(e)); } + + window['onFullyIBeaconEvent'] = (e, uuid, major, minor, distance) => { + let event = new CustomEvent(e, { + detail: { uuid: uuid, major: major, minor: minor, distance: distance, timestamp: new Date() } + }); + window.dispatchEvent(event); + } + + window.addEventListener('fully.screenOn', this.onScreenOn.bind(this)); + window.addEventListener('fully.screenOff', this.onScreenOff.bind(this)); + window.addEventListener('fully.networkDisconnect', this.onNetworkDisconnect.bind(this)); + window.addEventListener('fully.networkReconnect', this.onNetworkReconnect.bind(this)); + window.addEventListener('fully.internetDisconnect', this.onInternetDisconnect.bind(this)); + window.addEventListener('fully.internetReconnect', this.onInternetReconnect.bind(this)); + window.addEventListener('fully.unplugged', this.onUnplugged.bind(this)); + window.addEventListener('fully.pluggedAC', this.onPluggedAC.bind(this)); + window.addEventListener('fully.pluggedUSB', this.onPluggedUSB.bind(this)); + window.addEventListener('fully.onScreensaverStart', this.onScreensaverStart.bind(this)); + window.addEventListener('fully.onScreensaverStop', this.onScreensaverStop.bind(this)); + window.addEventListener('fully.onBatteryLevelChanged', this.onBatteryLevelChanged.bind(this)); + window.addEventListener('fully.onMotion', this.onMotion.bind(this)); + window.addEventListener('fully.onMovement', this.onMovement.bind(this)); + window.addEventListener('fully.onIBeacon', this.onIBeacon.bind(this)); + + fully.bind('screenOn', 'onFullyEvent("fully.screenOn");') + fully.bind('screenOff', 'onFullyEvent("fully.screenOff");') + fully.bind('networkDisconnect', 'onFullyEvent("fully.networkDisconnect");') + fully.bind('networkReconnect', 'onFullyEvent("fully.networkReconnect");') + fully.bind('internetDisconnect', 'onFullyEvent("fully.internetDisconnect");') + fully.bind('internetReconnect', 'onFullyEvent("fully.internetReconnect");') + fully.bind('unplugged', 'onFullyEvent("fully.unplugged");') + fully.bind('pluggedAC', 'onFullyEvent("fully.pluggedAC");') + fully.bind('pluggedUSB', 'onFullyEvent("fully.pluggedUSB");') + fully.bind('onScreensaverStart', 'onFullyEvent("fully.onScreensaverStart");') + fully.bind('onScreensaverStop', 'onFullyEvent("fully.onScreensaverStop");') + fully.bind('onBatteryLevelChanged', 'onFullyEvent("fully.onBatteryLevelChanged");') + fully.bind('onMotion', 'onFullyEvent("fully.onMotion");') // Max. one per second + fully.bind('onMovement', 'onFullyEvent("fully.onMovement");') + fully.bind('onIBeacon', 'onFullyIBeaconEvent("fully.onIBeacon", "$id1", "$id2", "$id3", $distance);') + } + + /***************************************************************************************************************************/ + /* Fully Kiosk events + /***************************************************************************************************************************/ + + onScreenOn() { + this.logDebug('FULLY_KIOSK', 'Screen turned on'); + } + + onScreenOff() { + this.logDebug('FULLY_KIOSK', 'Screen turned off'); + } + + onNetworkDisconnect() { + this.logDebug('FULLY_KIOSK', 'Network disconnected'); + } + + onNetworkReconnect() { + this.logDebug('FULLY_KIOSK', 'Network reconnected'); + } + + onInternetDisconnect() { + this.logDebug('FULLY_KIOSK', 'Internet disconnected'); + } + + onInternetReconnect() { + this.logDebug('FULLY_KIOSK', 'Internet reconnected'); + } + + onUnplugged() { + this.logDebug('FULLY_KIOSK', 'Unplugged AC'); + this.fullyState.isPluggedIn = false; + this.sendPluggedState(); + } + + onPluggedAC() { + this.logDebug('FULLY_KIOSK', 'Plugged AC'); + this.fullyState.isPluggedIn = true; + this.sendPluggedState(); + } + + onPluggedUSB() { + this.logDebug('FULLY_KIOSK', 'Unplugged USB'); + this.logDebug('FULLY_KIOSK', 'Device plugged into USB'); + } + + onScreensaverStart() { + this.fullyState.isScreensaverOn = true; + this.logDebug('FULLY_KIOSK', 'Screensaver started'); + this.sendScreensaverState(); + } + + onScreensaverStop() { + this.fullyState.isScreensaverOn = false; + this.logDebug('FULLY_KIOSK', 'Screensaver stopped'); + this.sendScreensaverState(); + } + + onBatteryLevelChanged() { + this.logDebug('FULLY_KIOSK', 'Battery level changed'); + } + + onMotion() { + this.fullyState.isMotionDetected = true; + this.logDebug('FULLY_KIOSK', 'Motion detected'); + this.sendMotionState(); + } + + onMovement() { + this.logDebug('FULLY_KIOSK', 'Movement detected'); + + if (this.fullyInfo.supportsGeolocation) { + this.updateCurrentPosition() + .then(() => { + this.sendMotionState(); + }); + } + } + + onIBeacon(e) { + let iBeacon = e.detail; + + this.logDebug('FULLY_KIOSK', `iBeacon (${JSON.stringify(iBeacon)})`); + + let iBeaconId = iBeacon.uuid; + iBeaconId += (iBeacon.major ? `_${iBeacon.major}` : ''); + iBeaconId += (iBeacon.minor ? `_${iBeacon.minor}` : ''); + + this.iBeacons[iBeaconId] = iBeacon; + + this.sendMotionState(); + + this.sendIBeaconState(iBeacon); + } + + /***************************************************************************************************************************/ + /* HTML5 Audio + /***************************************************************************************************************************/ + + onAudioPlay() { + this.isAudioPlaying = true; + this.sendMediaPlayerState(); + } + + onAudioPlaying() { + this.isAudioPlaying = true; + this.sendMediaPlayerState(); + } + + onAudioPause() { + this.isAudioPlaying = false; + this.sendMediaPlayerState(); + } + + onAudioEnded() { + this.isAudioPlaying = false; + this.sendMediaPlayerState(); + } + + onAudioVolumeChange() { + this.sendMediaPlayerState(); + } + + /***************************************************************************************************************************/ + /* Send state to Home Assistant + /***************************************************************************************************************************/ + + sendMotionState() { + if (!this.fullyInfo.motionBinarySensorEntityId) { + return; + } + + clearTimeout(this.sendMotionStateTimer); + let timeout = this.fullyState.isMotionDetected ? 5000 : 10000; + + let state = this.fullyState.isMotionDetected ? "on" : "off"; + this.PostToHomeAssistant(`/api/states/${this.fullyInfo.motionBinarySensorEntityId}`, this.newPayload(state), () => { + this.sendMotionStateTimer = setTimeout(() => { + this.fullyState.isMotionDetected = false; + this.sendMotionState(); + + // Send other states as well + this.sendPluggedState(); + this.sendScreensaverState(); + this.sendMediaPlayerState(); + }, timeout); + }); + } + + sendPluggedState() { + if (!this.fullyInfo.pluggedBinarySensorEntityId) { + return; + } + + let state = this.fullyState.isPluggedIn ? "on" : "off"; + this.PostToHomeAssistant(`/api/states/${this.fullyInfo.pluggedBinarySensorEntityId}`, this.newPayload(state)); + } + + sendScreensaverState() { + if (!this.fullyInfo.screensaverLightEntityId) { + return; + } + + let state = this.fullyState.isScreensaverOn ? "on" : "off"; + this.PostToHomeAssistant(`/api/states/${this.fullyInfo.screensaverLightEntityId}`, this.newPayload(state)); + } + + sendMediaPlayerState() { + if (!this.fullyInfo.mediaPlayerEntityId) { + return; + } + + let state = this.isAudioPlaying ? "playing" : "idle"; + this.PostToHomeAssistant(`/api/fully_kiosk/media_player/${this.fullyInfo.mediaPlayerEntityId}`, this.newPayload(state)); + } + + sendIBeaconState(iBeacon) { + if (!this.fullyInfo.motionBinarySensorEntityId) { + return; + } + + let payload = { + mac: undefined, + dev_id: iBeacon.uuid.replace(/-/g, '_'), + host_name: undefined, + location_name: this.fullyInfo.macAddress, + gps: this.position ? [this.position.coords.latitude, this.position.coords.longitude] : undefined, + gps_accuracy: undefined, + battery: undefined, + + uuid: iBeacon.uuid, + major: iBeacon.major, + minor: iBeacon.minor, + }; + + //this.PostToHomeAssistant(`/api/services/device_tracker/see`, payload); + + let fullyId = this.fullyInfo.macAddress.replace(/[:-]/g, "_"); + payload = { topic: `room_presence/${fullyId}`, payload: `{ \"id\": \"${iBeacon.uuid}\", \"distance\": ${iBeacon.distance} }` }; + this.floorplan.hass.callService('mqtt', 'publish', payload); + } + + newPayload(state) { + this.updateFullyState(); + + let payload = { + state: state, + brightness: this.fullyState.screenBrightness, + attributes: { + volume_level: this.audio.volume, + media_content_id: this.audio.src, + address: this.fullyInfo.macAddress, + mac_address: this.fullyInfo.macAddress, + serial_number: this.fullyInfo.serialNumber, + device_id: this.fullyInfo.deviceId, + battery_level: this.fullyState.batteryLevel, + screen_brightness: this.fullyState.screenBrightness, + _isScreenOn: this.fullyState.isScreenOn, + _isPluggedIn: this.fullyState.isPluggedIn, + _isMotionDetected: this.fullyState.isMotionDetected, + _isScreensaverOn: this.fullyState.isScreensaverOn, + _latitude: this.position && this.position.coords.latitude, + _longitude: this.position && this.position.coords.longitude, + _iBeacons: JSON.stringify(Object.keys(this.iBeacons).map(iBeaconId => this.iBeacons[iBeaconId])), + } + }; + + return payload; + } + + /***************************************************************************************************************************/ + /* Geolocation + /***************************************************************************************************************************/ + + setScreenBrightness(brightness) { + fully.setScreenBrightness(brightness); + } + + startScreensaver() { + this.logInfo('FULLY_KIOSK', `Starting screensaver`); + fully.startScreensaver(); + } + + stopScreensaver() { + this.logInfo('FULLY_KIOSK', `Stopping screensaver`); + fully.stopScreensaver(); + } + + playTextToSpeech(text) { + this.logInfo('FULLY_KIOSK', `Playing text-to-speech: ${text}`); + fully.textToSpeech(text); + } + + playMedia(mediaUrl) { + this.audio.src = mediaUrl; + + this.logInfo('FULLY_KIOSK', `Playing media: ${this.audio.src}`); + this.audio.play(); + } + + pauseMedia() { + this.logInfo('FULLY_KIOSK', `Pausing media: ${this.audio.src}`); + this.audio.pause(); + } + + setVolume(level) { + this.audio.volume = level; + } + + PostToHomeAssistant(url, payload, onSuccess) { + let options = { + type: 'POST', + url: url, + headers: { "X-HA-Access": this.authToken }, + data: JSON.stringify(payload), + success: function (result) { + this.logDebug('FULLY_KIOSK', `Posted state: ${url} ${JSON.stringify(payload)}`); + if (onSuccess) { + onSuccess(); + } + }.bind(this), + error: function (error) { + this.handleError(new URIError(`Error posting state: ${url}`)); + }.bind(this) + }; + + jQuery.ajax(options); + } + + subscribeHomeAssistantEvents() { + /* + this.floorplan.hass.connection.subscribeEvents((event) => { + }, + 'state_changed'); + */ + + this.floorplan.hass.connection.subscribeEvents((event) => { + if (this.fullyInfo.screensaverLightEntityId && (event.data.domain === 'light')) { + if (event.data.service_data.entity_id.toString() === this.fullyInfo.screensaverLightEntityId) { + switch (event.data.service) { + case 'turn_on': + this.startScreensaver(); + break; + + case 'turn_off': + this.stopScreensaver(); + break; + } + + let brightness = event.data.service_data.brightness; + if (brightness) { + this.setScreenBrightness(brightness); + } + } + } + else if (this.fullyInfo.mediaPlayerEntityId && (event.data.domain === 'media_player')) { + let targetEntityId; + let serviceEntityId = event.data.service_data.entity_id; + + if (Array.isArray(serviceEntityId)) { + targetEntityId = serviceEntityId.find(entityId => (entityId === this.fullyInfo.mediaPlayerEntityId)); + } + else { + targetEntityId = (serviceEntityId === this.fullyInfo.mediaPlayerEntityId) ? serviceEntityId : undefined; + } + + if (targetEntityId) { + switch (event.data.service) { + case 'play_media': + this.playMedia(event.data.service_data.media_content_id); + break; + + case 'media_play': + this.playMedia(); + break; + + case 'media_pause': + case 'media_stop': + this.pauseMedia(); + break; + + case 'volume_set': + this.setVolume(event.data.service_data.volume_level); + break; + + default: + this.logWarning('FULLY_KIOSK', `Service not supported: ${event.data.service}`); + break; + } + } + } + + /* + if ((event.data.domain === 'tts') && (event.data.service === 'google_say')) { + if (this.fullyInfo.mediaPlayerEntityId === event.data.service_data.entity_id) { + this.logDebug('FULLY_KIOSK', 'Playing TTS using Fully Kiosk'); + this.playTextToSpeech(event.data.service_data.message); + } + } + */ + }, + 'call_service'); + } + + /***************************************************************************************************************************/ + /* Geolocation + /***************************************************************************************************************************/ + + updateCurrentPosition() { + if (!navigator.geolocation) { + return Promise.resolve(undefined); + } + + return new Promise((resolve, reject) => { + navigator.geolocation.getCurrentPosition( + (position) => { + this.logDebug('FULLY_KIOSK', `Current location: latitude: ${position.coords.latitude}, longitude: ${position.coords.longitude}`); + this.position = position; + resolve(position); + }, + (err) => { + this.logError('FULLY_KIOSK', 'Unable to retrieve location'); + reject(err); + }); + }) + } + + /***************************************************************************************************************************/ + /* Errors / logging + /***************************************************************************************************************************/ + + handleError(message) { + this.floorplan.handleError(message); + } + + logError(area, message) { + this.floorplan.logError(message); + } + + logWarning(area, message) { + this.floorplan.logWarning(area, message); + } + + logInfo(area, message) { + this.floorplan.logInfo(area, message); + } + + logDebug(area, message) { + this.floorplan.logDebug(area, message); + } + + /***************************************************************************************************************************/ + /* Utility functions + /***************************************************************************************************************************/ + + debounce(func, wait, immediate) { + let timeout; + return function () { + let context = this, args = arguments; + + let later = function () { + timeout = null; + if (!immediate) func.apply(context, args); + }; + + let callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + + if (callNow) func.apply(context, args); + }; + } + } + + window.FullyKiosk = FullyKiosk; +}).call(this); diff --git a/www/custom_ui/floorplan/lib/jquery-3.2.1.min.js b/www/custom_ui/floorplan/lib/jquery-3.2.1.min.js new file mode 100755 index 00000000..bcd3956c --- /dev/null +++ b/www/custom_ui/floorplan/lib/jquery-3.2.1.min.js @@ -0,0 +1,4 @@ +/*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S), +a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b), +null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&B(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),lb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):nb.test(a.nodeName)||ob.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function pb(a){var b=a.match(L)||[];return b.join(" ")}function qb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,qb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,qb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,qb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=qb(this),b&&W.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":W.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+pb(qb(c))+" ").indexOf(b)>-1)return!0;return!1}});var rb=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:pb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var sb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!sb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,sb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,"events")||{})[b.type]&&W.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var tb=a.location,ub=r.now(),vb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\/\//,Ib={},Jb={},Kb="*/".concat("*"),Lb=d.createElement("a");Lb.href=tb.href;function Mb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:"GET",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+"").replace(Hb,tb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(L)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+"//"+Lb.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(Bb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,"$1"),n=(vb.test(f)?"&":"?")+"_="+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Kb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&"withCredentials"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("