mirror of
https://github.com/correl/correl.github.io.git
synced 2024-12-28 19:19:17 +00:00
New blog post on Home Assistant
This commit is contained in:
parent
c66f121f8c
commit
46933271bf
6 changed files with 375 additions and 1 deletions
376
blog.org
376
blog.org
|
@ -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} |
|
||||||
|
+----+ +----+
|
||||||
|
|
||||||
|
6꞉30 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} |
|
||||||
|
+----+ +----+
|
||||||
|
|
||||||
|
6꞉33 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} |
|
||||||
|
+----+ +----+
|
||||||
|
|
||||||
|
7꞉00 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
|
||||||
|
|
BIN
static/images/ha-sonos-ui.png
Normal file
BIN
static/images/ha-sonos-ui.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
BIN
static/images/ha-sunrise-ui.png
Normal file
BIN
static/images/ha-sunrise-ui.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
BIN
static/ox-hugo/ha-lights-1.svg
Normal file
BIN
static/ox-hugo/ha-lights-1.svg
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.9 KiB |
BIN
static/ox-hugo/ha-lights-2.svg
Normal file
BIN
static/ox-hugo/ha-lights-2.svg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6 KiB |
BIN
static/ox-hugo/ha-lights-3.svg
Normal file
BIN
static/ox-hugo/ha-lights-3.svg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
Loading…
Reference in a new issue