New blog post on Home Assistant

This commit is contained in:
Correl Roush 2019-06-27 18:13:54 -04:00
parent c66f121f8c
commit 46933271bf
6 changed files with 375 additions and 1 deletions

376
blog.org
View file

@ -1,7 +1,7 @@
#+STARTUP: indent inlineimages hideblocks #+STARTUP: indent inlineimages hideblocks
#+HUGO_BASE_DIR: . #+HUGO_BASE_DIR: .
#+HUGO_SECTION: blog #+HUGO_SECTION: blog
#+OPTIONS: toc:nil num:nil todo:nil #+OPTIONS: toc:nil num:nil todo:nil d:(not "HIDDEN")
#+PROPERTY: header-args :cache yes :eval never-export :output-dir static/ox-hugo/ #+PROPERTY: header-args :cache yes :eval never-export :output-dir static/ox-hugo/
#+COLUMNS: %TODO %50ITEM %CLOSED %EXPORT_FILE_NAME %CATEGORY %TAGS #+COLUMNS: %TODO %50ITEM %CLOSED %EXPORT_FILE_NAME %CATEGORY %TAGS
#+LINK: relref file:{{< relref "%s.md" >}} #+LINK: relref file:{{< relref "%s.md" >}}
@ -2718,3 +2718,377 @@ trigger each other.
If I get around to building my rolling sunrise, I'll be sure to get a If I get around to building my rolling sunrise, I'll be sure to get a
post up on it :) post up on it :)
* DONE Automating My Apartment With Home Assistant :home_automation:
CLOSED: [2019-06-27 Thu 18:13]
:PROPERTIES:
:EXPORT_FILE_NAME: automating-my-apartment-with-home-assistant
:END:
A while ago, I [[relref:hue-wake-up][posted about]] my experiments with the Phillips Hue API
to create an automated morning sunrise effect. The end result was
nice, but all that mucking about with their HTTP APIs was a hassle any
time I wanted to tweak something. I wanted to define what I wanted in
a more declarative style, and have all the API calls managed behind
the scenes. [[https://www.home-assistant.io/][Home Assistant]] allowed me to do exactly that, and more.
While the Home Assistant docs are geared heavily towards setting up a
raspberry pi appliance to run everything 24/7, I don't own one, and I
already have a server going. I opted instead to get the home assistant
server running using [[https://www.home-assistant.io/docs/installation/docker/][Docker]], and setting up a git repository to hold
my configuration.
** A Brand New Day
Setting up my sunrise was actually /really/ easy. I already had the
scenes I wanted from my [[relref:hue-wake-up][previous attempt]], so it was just a matter of
codifying them in the YAML config. I split them into four scenes - a
start (dawn) and end (daylight) pair for the standing lamp at the wall
beyond the foot of the bed, and a pair for the two nightstand lights.
The end scenes include the transition time to fade in (30 minutes).
#+begin_src yaml
scene:
- name: Dawn Sun
entities:
light.standing_lamp:
state: on
brightness: 1
xy_color: [0.6042, 0.3739]
- name: Dawn Daylight
entities:
light.correls_nightstand:
state: on
brightness: 1
xy_color: [0.2376, 0.1186]
light.stephanies_nightstand:
state: on
brightness: 1
xy_color: [0.2376, 0.1186]
- name: Sunrise Sun
entities:
light.standing_lamp:
state: on
transition: 1800
brightness: 254
xy_color: [0.3769, 0.3639]
- name: Sunrise Daylight
entities:
light.correls_nightstand:
state: on
transition: 1800
brightness: 203
xy_color: [0.2698, 0.295]
light.stephanies_nightstand:
state: on
transition: 1800
brightness: 203
xy_color: [0.2698, 0.295]
#+end_src
Breaking them apart this way means I can trigger the "sun" first for a
splash of orange, then start up the nightstand "daylight" lights a
little bit later! This worked out well, too, since even at the lowest
brightness, having them turn on right at the start when the room is
totally dark had a tendency to jolt me awake. Staggering them produces
a much gentler effect. Scripting all of this took very little work...
#+begin_src yaml
script:
sunrise:
alias: Sunrise
sequence:
- service: scene.turn_on
data:
entity_id: scene.dawn_sun
- service: scene.turn_on
data:
entity_id: scene.sunrise_sun
- delay:
seconds: 180
- service: scene.turn_on
data:
entity_id: scene.dawn_daylight
- service: scene.turn_on
data:
entity_id: scene.sunrise_daylight
#+end_src
... and the end result really is quite pleasant:
#+begin_src ditaa :file ha-lights-1.png :exports none
+----+
|cA20|
| |
|{o} |
+----+
+----+ Z +----+
|cBLK| z |cBLK|
| | z | |
|{o} | |{o} |
+----+ +----+
630 AM
#+end_src
#+RESULTS[bb260c3d0d038bb1fdcd6cba2076efeff57bad80]:
[[file:static/ox-hugo/ha-lights-1.png]]
#+begin_src ditaa :file ha-lights-2.png :exports none
+----+
|cB50|
| |
|{o} |
+----+
+----+ +----+
|c327| z |c327|
| | z | |
|{o} | |{o} |
+----+ +----+
633 AM
#+end_src
#+RESULTS[07189ab694076463b9a88997b2f8be6427ea6950]:
[[file:static/ox-hugo/ha-lights-2.png]]
#+begin_src ditaa :file ha-lights-3.png :exports none
+----+
|cFFD|
| |
|{o} |
+----+
\o/
|
|
/ \
+----+ +----+
|cDDF| |cDDF|
| | | |
|{o} | |{o} |
+----+ +----+
700 AM
#+end_src
#+RESULTS[b22835dedc7d706f3f8ff6826040349decbb5d1a]:
[[file:static/ox-hugo/ha-lights-3.png]]
#+begin_center
[[file:static/ox-hugo/ha-lights-1.png]]
[[file:static/ox-hugo/ha-lights-2.png]]
[[file:static/ox-hugo/ha-lights-3.png]]
#+end_center
That just leaves the automation, which fires a half an hour before the
/actual/ sunrise, so long as the lights aren't already on and somebody
is home (using a binary sensor I defined elsewhere based on phones
detected in the house plus an override toggle).
#+begin_src yaml
automation:
- alias: Sunrise
action:
- service: script.sunrise
data: {}
trigger:
- platform: sun
event: sunrise
offset: '-00:30:00'
condition:
- condition: state
entity_id: binary_sensor.occupied
state: 'on'
- condition: state
entity_id: group.bedroom_lights
state: 'off'
#+end_src
I later extended the automation with some configuration inputs, which
tie into some new triggers and conditions. I added a "latest start
time" to make sure it always gets me up in time for me to get ready
for work, and an option to disable the wake-up on weekends.
#+begin_src yaml
input_select:
sunrise_days:
name: Days to wake up
options:
- Every Day
- Weekdays
initial: Every Day
icon: mdi:weather-sunset
input_datetime:
sunrise_time:
name: Latest start time
has_date: false
has_time: true
initial: '06:30'
automation:
- alias: Sunrise
action:
- service: script.sunrise
data: {}
trigger:
- platform: sun
event: sunrise
offset: '-00:30:00'
- platform: template
value_template: >-
{{ states('sensor.time') == (
states.input_datetime.sunrise_time.attributes.timestamp
| int | timestamp_custom('%H:%M', False)
)
}}
condition:
- condition: state
entity_id: binary_sensor.occupied
state: 'on'
- condition: state
entity_id: group.bedroom_lights
state: 'off'
- condition: or
conditions:
- condition: state
entity_id: input_select.sunrise_days
state: Every Day
- condition: and
conditions:
- condition: state
entity_id: input_select.sunrise_days
state: Weekdays
- condition: time
weekday:
- mon
- tue
- wed
- thu
- fri
#+end_src
Sprinkle in some groups, and I've got a nice panel in my Home
Assistant UI to manage everything:
#+CAPTION: The completed sunrise panel
#+ATTR_ORG: :width 800
[[file:static/images/ha-sunrise-ui.png]]
** Keep It Down!
Determined to find more things to automate, I realized that since I
have my TV audio going through a Sonos sound bar, I could very easily
automate the rather annoying ritual of leaping for the app on my phone
to turn on night mode when a movie I'm watching is getting explodey
and I realize it's a bit late in the evening to be shaking my
neighbor's walls.
#+begin_src yaml
automation:
- alias: Toggle Sonos night mode
action:
- service: media_player.sonos_set_option
entity_id: media_player.den
data_template:
night_sound: >-
{{ now().hour >= 22 }}
trigger:
- platform: time
at: '22:30:00'
- platform: time
at: '08:00:00'
#+end_src
Boom. Happier neighbors, and I can fall asleep in front of movies
without worry!
Just because I could, I also added some configurability to this
automation as well. The logic got a bit tricky, since I wanted to
configure a window that crosses a 24-hour boundary. I also added a
binary sensor so I could see when night mode was enabled from Home
Assistant.
#+begin_src yaml
automation:
- alias: Toggle Sonos night mode
action:
- service: media_player.sonos_set_option
entity_id: media_player.den
data_template:
night_sound: >-
{% set start = states.input_datetime.sonos_nightmode_start.attributes %}
{% set end = states.input_datetime.sonos_nightmode_end.attributes %}
{% set now_ = (now().hour, now().minute, now().second) %}
{% set start_ = (start.hour, start.minute, start.second) %}
{% set end_ = (end.hour, end.minute, end.second) %}
{% if start_ > end_ -%}
{{ now_ >= start_ or now_ < end_ }}
{%- else -%}
{{ now_ >= start_ and now_ < end_ }}
{%- endif -%}
trigger:
- platform: template
value_template: "{{ states('sensor.time') == (states.input_datetime.sonos_nightmode_start.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"
- platform: template
value_template: "{{ states('sensor.time') == (states.input_datetime.sonos_nightmode_end.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}"
sensor:
- platform: time_date
display_options:
- time
input_datetime:
sonos_nightmode_start:
name: Start Night Mode
has_date: false
has_time: true
initial: '22:30'
sonos_nightmode_end:
name: End Night Mode
has_date: false
has_time: true
initial: '08:00'
binary_sensor:
- platform: template
sensors:
den_night_mode:
friendly_name: Sonos Den Night Mode
value_template: >-
{{ state_attr('media_player.den', 'night_sound') }}
#+end_src
And, voilà, a dashboard for my speakers, which I pretty much never
need to look at anymore!
[[file:static/images/ha-sonos-ui.png]]
** But Wait, There's More!
It's a too much to cover in a single blog post, but there's plenty
more going on in my config. Over time, I've tweaked and added to my
device tracking to make sure Home Assistant knows when someone's home.
I set up some text-to-speech to announce the weather in the morning,
and welcome the first person to get home. I even re-purposed an old
phone as a webcam so I can check on the cat while I'm out. My config
is on my personal gitlab server, feel free to check it out and see if
there's anything there you can use or learn from:
http://git.phoenixinquis.net/correlr/home-assistant
* TODO Types in Python :programming:python:
:PROPERTIES:
:EXPORT_FILE_NAME: types-in-python
:END:
** TODO Why Use Types?
** TODO Success Typing
** TODO Running Mypy
** TODO Specifying Types

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB