Files
homelab/active/device_home_assistant/home_assistant.md

25 KiB
Raw Blame History

Home Assistant

Certificates

Note, self signed certs won't work on the hass android app.

# Generate the key/cert
# Note, 36159 days == 99 years
openssl req \
-sha256 \
-addext "subjectAltName = IP:10.2.0.230" \
-newkey rsa:4096 \
-nodes \
-keyout privkey.pem \
-x509 \
-days 36159 \
-out fullchain.pem

http:
  server_port: 8123
  ssl_certificate: /ssl/fullchain.pem
  ssl_key: /ssl/privkey.pem

Setup and Configuration

Schlage Door Lock

  1. Install Z-wave
  2. Install z-wave JS module
  3. Add device -> How do you want to add your device -> Legacy Secure
  4. Disconnect and Reconnect the battery on the lock
  5. Press and hold the zwave button until the light turns solid red, release and it should flash red
    1. (OR) Enter programming pin on lock -> 0 (this may take a few attempts, don't click the pair button)

If the lock ever disconnects you can safely delete it from home assistant and re-interview. It will set back up with the correct entity IDs and automations/dashboards will work just fine.

Philips Hue Lights

  1. I configure all philips hue lights through zigbee directly connected to HA

hue lights support color_temp in mireds, here are some mired-kelvin conversions:

Kelvin Mired
6000 167
4000 250
2600 385

Shelly

  1. Outbound Websocket wss://homeassistant.reeseapps.com/api/shelly/ws

Shelly devices can act as "passive" or "active" bluetooth scanners. Both of these configurations allow home assistant to proxy bluetooth connections through shelly devices, significantly extending the range of your home assistant's bluetooth capabilities. Active scanning uses more power but is quicker to pick up and transmit device information. Note that "gateway mode" is not required, just enable bluetooth and rpc or select "active" from the configuration menu for the shelly device.

Barometer

https://www.thoughtco.com/how-to-read-a-barometer-3444043

A barometric reading over 30.20 inHg is generally considered high, and high pressure is associated with clear skies and calm weather.

If the reading is over 30.20 inHg (102268.9 Pa or 1022.689 mb):

  • Rising or steady pressure means continued fair weather.
  • Slowly falling pressure means fair weather.
  • Rapidly falling pressure means cloudy and warmer conditions.

A barometric reading in the range of 29.80 and 30.20 inHg can be considered normal, and normal pressure is associated with steady weather.

If the reading falls between 29.80 and 30.20 inHg (100914.4102268.9 Pa or 1022.6891009.144 mb):

  • Rising or steady pressure means present conditions will continue.
  • Slowly falling pressure means little change in the weather.
  • Rapidly falling pressure means that rain is likely, or snow if it is cold enough.

A barometric reading below 29.80 inHg is generally considered low, and low pressure is associated with warm air and rainstorms.

If the reading is under 29.80 inHg (100914.4 Pa or 1009.144 mb):

  • Rising or steady pressure indicates clearing and cooler weather.
  • Slowly falling pressure indicates rain.
  • Rapidly falling pressure indicates a storm is coming.

A basic automation would look like

It's {{ int(states("sensor.grouse_temp")) }} degrees and {{ states("weather.grouse_weather") }}. The relative humidity is {{ states("sensor.grouse_humidity") }}%. I'm seeing {{ int(states("sensor.grouse_wind_speed")) }}mph wind with gusts up to {{ int(states("sensor.grouse_wind_gust")) }}mph.

{% set pressure = float(states("sensor.grouse_rel_pressure")) %}
The barometer reads {{ pressure }}inHg.
{% if pressure > 30.20 %}
Fair weather is expected
{% elif pressure > 29.80 %}
Rain is possible
{% else %}
Rain is coming.
{% endif %}

Relative Humidity Calculator

https://www.wikihow.com/Calculate-Humidity

You can calculate the relative humidity of the outdoor air if warmed to indoor temperatures like so:

{% set dew_point = state_attr("weather.forecast_home", "dew_point") %}
{% set air_temp_f = state_attr("climate.ecobee_thermostat", "current_temperature") %}
{% set air_temp = (5/9)*(air_temp_f-32) %}
{% set sat_vap_press = 6.11 * 10**((7.5*air_temp) / (237.3+air_temp)) %}
{% set act_vap_press = 6.11 * 10**((7.5*dew_point) / (237.3+dew_point)) %}
{% set rel_hum = 100*(act_vap_press / sat_vap_press) %}

{{ dew_point }}
{{ air_temp }}
{{ sat_vap_press }}
{{ act_vap_press }}
{{ rel_hum }}

Font Colors

<font color = {{ "green" if state_attr("climate.ecobee_thermostat", "current_humidity") > low_humidity and state_attr("climate.ecobee_thermostat", "current_humidity") < high_humidity else "red" }}>
HVAC Humidity: {{ state_attr("climate.ecobee_thermostat", "current_humidity") }}%
</font>

Light Indicator for Voice Assistant

alias: Flash Lights on Bedroom Voice Assistant Start
description: ""
triggers:
  - type: turned_on
    device_id: d50fa1ae499e88bf37225c7e82ed189b
    entity_id: 7ab2896ca3a55efd2e0ee9bba91fdf68
    domain: binary_sensor
    metadata:
      secondary: false
    trigger: device
conditions: []
actions:
  - action: scene.create
    metadata: {}
    data:
      scene_id: bedroombeforescene
      snapshot_entities:
        - light.main_bedroom_lamps
  - action: light.turn_on
    metadata: {}
    data:
      transition: 0.25
      brightness_step_pct: 5
    target:
      entity_id: light.main_bedroom_lamps
  - delay:
      hours: 0
      minutes: 0
      seconds: 0
      milliseconds: 250
  - action: scene.turn_on
    data:
      entity_id: scene.bedroombeforescene
      transition: 0.25
mode: single

Blank Button (Spacer)

- type: button
tap_action:
    action: none
show_state: false
show_name: false
show_icon: false
hold_action:
    action: none

Roku Remote

type: vertical-stack
cards:
  - type: entity
    entity: select.left_living_room_application
  - square: true
    type: grid
    cards:
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: power
        entity: remote.left_living_room
        icon: mdi:power
        name: power
        show_state: false
        hold_action:
          action: none
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: volume_down
        entity: remote.left_living_room
        icon: mdi:volume-minus
        name: volume down / hold mute
        show_state: false
        hold_action:
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: volume_mute
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: volume_up
        entity: remote.left_living_room
        icon: mdi:volume-plus
        name: volume up / hold mute
        show_state: false
        "hold_action:":
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: volume_mute
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: back
        entity: remote.left_living_room
        icon: mdi:undo
        name: back
        show_state: false
        hold_action:
          action: none
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: up
        entity: remote.left_living_room
        icon: mdi:arrow-up-bold
        name: up
        hold_action:
          action: none
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: home
        entity: remote.left_living_room
        icon: mdi:home
        name: home
        hold_action:
          action: none
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: left
        entity: remote.left_living_room
        icon: mdi:arrow-left-bold
        name: left
        hold_action:
          action: none
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: select
        entity: remote.left_living_room
        icon: mdi:select-all
        name: select
        hold_action:
          action: none
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: right
        entity: remote.left_living_room
        icon: mdi:arrow-right-bold
        name: right
        hold_action:
          action: none
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: play
        entity: remote.left_living_room
        icon: mdi:play-pause
        name: play/pause
        hold_action:
          action: none
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: down
        entity: remote.left_living_room
        icon: mdi:arrow-down-bold
        name: down
        hold_action:
          action: none
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: perform-action
          perform_action: remote.send_command
          target:
            entity_id: remote.left_living_room
          data:
            command: info
        entity: remote.left_living_room
        icon: mdi:wrench
        name: settings
        hold_action:
          action: none
title: Left Living Room TV

Flair Vent Battery

Flair vents report low battery at 2.4v. 3v is nominal/full.

{% set volt_min=2.4 %}
{% set volt_max=3.0 %}
{% set volt_diff_max=0.6 %}

{{ (min(float(states("sensor.main_bedroom_29bf_voltage")) - volt_min, volt_diff_max) / volt_diff_max) * 100 }}

Voice

Changing the Voice of TTS

Select a media player -> play TTS -> select voice -> copy voice ID.

options:
  voice: DavisNeural||chat

Custom Sentences

https://developers.home-assistant.io/docs/voice/intent-recognition/template-sentence-syntax/#sentence-templates-syntax

Overriding Default Sentences

  1. Identify if your sentence conflicts with Home Assistant's default sentences
  2. Create a new file at /config/custom_sentences/en/overrides.yaml
  3. As an example, to override the HassGetWeather sentence:
    1. Copy the contents of weather_HassGetWeather.yaml into overrides.yaml

    2. Rename HassGetWeather to HassGetWeather_Custom

    3. Delete the required context weather

    4. Now in configuration.yaml, under a section called intent_script, add the following

      HassGetWeather_Custom:
        speech:
          text: >-
            It's {{ int(states("sensor.backyard_weather_station_temp")) }} degrees
            with {{ states("sensor.backyard_weather_station_humidity") }}% humidity.
            I'm seeing {{ int(states("sensor.backyard_weather_station_wind_speed"))
            }}mph wind. It's rained {{
            int(states("sensor.backyard_weather_station_hourly_rain_rate")) }} inches
            in the last hour.
      
    5. Restart Home Assistant

    6. Navigate to Settings -> Voice Assistants -> Click the 3 dots next to your voice assistant -> Debug -> Click the icon in the top right -> Run text pipeline -> "What's the weather"

Notifications

Notification Information:

https://www.home-assistant.io/docs/automation/templating/

Triggered by {{ trigger.entity_id }}, Date: {{ now().strftime('%Y-%m-%d') }}, Time: {{ now().strftime('%H:%M') }}

Unifi Cameras

Create image/video previews of events with the following automation:

alias: Vehicle Driveway Notification
description: Sends a notification with video upon motion detection.
triggers:
  - entity_id:
      - binary_sensor.driveway_camera_vehicle_detected
    trigger: state
    from: "on"
    to: "off"
actions:
  - data:
      message: Vehicle detected on Driveway Camera
      data:
        image: >-
          /api/unifiprotect/thumbnail/{{ config_entry_id(trigger.entity_id)
          }}/{{ trigger.from_state.attributes.event_id }}
        video: >-
          /api/unifiprotect/video/{{ config_entry_id(trigger.entity_id) }}/{{
          trigger.from_state.attributes.event_id }}
    action: notify.notify
mode: single
max_exceeded: silent

Multiple Entity Triggers with Custom Names

You can set an "id" for a trigger that can be used as a human readable name.

alias: Notify when a Door Opened
description: ""
triggers:
  - trigger: state
    entity_id:
      - binary_sensor.my_front_door
    from: "off"
    to: "on"
    id: Front Door
  - trigger: state
    entity_id:
      - binary_sensor.my_back_door
    from: "off"
    to: "on"
    id: Back Door
  - trigger: state
    entity_id:
      - binary_sensor.super_secret_door
    from: "off"
    to: "on"
    id: Trap Door
conditions: []
actions:
  - action: notify.notify
    metadata: {}
    data:
      message: "{{ trigger.id }} Opened"
mode: single

Philips Hue Switches

Philips Hue Switches don't expose entities, but rather trigger "zha_event" events.

To see events fired by these devices: Developer tools -> Events -> Listen to events zha_event

You can use this in automations like so:

alias: Some Switch
description: ""
triggers:
  - device_id: bb54b111ec77fb7d5356bb600789098f
    domain: zha
    type: remote_button_short_press
    subtype: turn_on
    trigger: device
    id: "on"
  - device_id: bb54b111ec77fb7d5356bb600789098f
    domain: zha
    type: remote_button_long_press
    subtype: turn_on
    trigger: device
    id: on-con
conditions: []
actions:
  - action: scene.turn_on
    metadata: {}
    data: {}
    target:
      entity_id: scene.some_scene
mode: single

Datetimes

Stolen from Reddit

## Set placeholder templates for reference in this template
## 'dt' substitutes 'now()'
## eg. if currently 5 March 2024 at 09:08:07 (AM)
eg_now   = {% set eg_now = "2024-03-05 09:08:07.123456+00:00" %}{{ eg_now }}
dt       = {% set dt = eg_now | as_datetime %}{{ dt }}
ts       = {% set ts = eg_now | as_timestamp %}{{ ts }}

## Basic Time & Date Functions
time_now:         {{ now() }}
time_local:       {{ now() | as_local }}
time_timestamp:   {{ now() | as_timestamp }}

## Time Conversions
seconds_per_min : {% set spm = 60           | int %}{{ spm }}
seconds_per_hour: {% set sph = ( spm * 60 ) | int %}{{ sph }}
seconds_per_day : {% set spd = 86400        | int %}{{ spd }}
seconds_per_week: {% set spw = ( spd * 7  ) | int %}{{ spw }}
minutes_per_day : {% set mpd = ( spd / 60 ) | int %}{{ mpd }}
minutes_per_week: {% set mpw = ( mpd * 7  ) | int %}{{ mpw }}
hours_per_week  : {% set hpw = ( 24 * 7   ) | int %}{{ hpw }}

## Time Calculations
## with DATETIME use timedelta:
* CURRENT TIME :  {{ dt }}
+ 1 YEAR       :  {{ dt + timedelta(days=365) }}
- 1 DAY  (24H) :  {{ dt - timedelta(days=1) }}
+ 3 DAYS (72H) :  {{ dt + timedelta(days=3) }}
- 3 HOURS      :  {{ dt - timedelta(hours=3) }}
+ 1 HR 26 MIN  :  {{ dt + timedelta(hours=1, minutes=26) }}
+ 1D 2H 3M 4S  :  {{ dt + timedelta(days=1, hours=2, minutes=3, seconds=4) }}

## with TIMESTAMP use maths and then convert:
## Referencing earlier calculations for ease
* TIMESTAMP    :  {{ ts }}
* CURRENT TIME :  {{ ts | as_datetime  }}
+ 1 YEAR       :  {{ ( ts + (spd * 365) ) | as_datetime }}
- 1 DAY  (24H) :  {{ ( ts - spd ) | as_datetime }}
+ 3 DAYS (72H) :  {{ ( ts + (spd * 3) ) | as_datetime }}
- 3 HOURS      :  {{ ( ts - (sph * 3) ) | as_datetime }}
+ 1 HR 26 MIN  :  {{ ( ts + sph + (spm * 26) ) | as_datetime }}
+ 1D 2H 3M 4S  :  {{ ( ts + spd + (sph * 2) + (spm * 3) + 4 ) | as_datetime }}

## Adjusting Time & Date For Calculations
Start Of Today: {% set start_today = dt.replace(hour=0, minute=0, second=0, microsecond=0) %}{{ start_today }}
End Of Today  : {% set start_tomorrow = start_today + timedelta(days=1) %}{{ start_tomorrow }}

## Use Relative Time For DATETIME in the PAST
relative_time: {{ relative_time( start_today ) }} ago

## For time in the FUTURE you can use:
{% set current_time = dt  %}{% set future_time = as_local(dt) %}{% set time_distance = future_time - current_time %}
relative_future: In {{ relative_time(current_time - time_distance) }}

## Use Time Templates combined with History Stats Sensor:
sensor:
  - platform: history_stats
    name: Lamp ON today
    entity_id: light.my_lamp
    state: "on"

Stolen from https://www.fabriziomusacchio.com/blog/2021-08-15-strftime_Cheat_Sheet/

Format Example Description
%c Thu Jan 28 12:32:01 2014 locales appropriate date and time representation
%D 23/05/12 formats the date
%F 2002-01-30 date in ISO 8601 format YYYY-MM-DD
%x 02/10/11 locales appropriate date representation
%X 14:22:01 locales appropriate time representation
%r 3:44:12 AM 12-hour time
%R 15:21 24-hour time HH:MM
%T 15:21:59 time in ISO 8601 format HH:MM:SS
%A Monday full weekday name
%a Mon abbreviated weekday name
%w 0-6 day of the week with Sunday as 0
%d 01-31 day of the month (with a leading zero)
%e 1-31 day of the month (without a leading zero)
%B April full month name
%b Apr abbreviated month name
%m 01-12 month of the year (with a leading zero)
%-m 1-12 month of the year (without a leading zero)
%Y 2003 year
%y 00-99 year without a century (last two digits, with a leading zero)
%-y 0-99 year without a century (last two digits, without a leading zero)
%H 00-23 hour of the day, 24-hour time (with a leading zero)
%k 0-23 hour of the day, 24-hour time (without a leading zero)
%I 01-11 hour of the day, 12-hour time (with a leading zero)
%-I 1-11 hour of the day, 12-hour time (without a leading zero)
%P am, pm am or pm designation
%p AM, PM AM or PM designation
%M 00-59 minute of the hour (with a leading zero)
%-M 0-59 minute of the hour (without a leading zero)
%S 00-60 second of the minute (with a leading zero)
%-S 0-60 second of the minute (without a leading zero)
%f 000000-999999 microsecond of the second (with a leading zero)
%Z UTC timezone name or abbreviation
%z +0000 UTC offset in the form +HHMM or -HHMM
%s amount of seconds since 1970-01-01 00:00:00 UTC
%% % sign
%j 001-366 day of the year (with a leading zeroes)
%U 00-53 week number with the first Sunday as the first day of week one
%W 00-53 week number of the current year, starting with the first Monday as the first day of the first week
%V 01-53 week number in ISO 8601 format

LG TV Switch

- platform: wake_on_lan
  mac: b4:b2:91:8e:ce:20
  name: loft_lg_tv_wol
  turn_off:
    service: media_player.turn_off
    target:
      device_id: "{{device_id('media_player.loft_lg_tv')}}"

- platform: wake_on_lan
  mac: 60:8d:26:2c:4d:45
  name: living_room_lg_tv_wol
  turn_off:
    service: media_player.turn_off
    target:
      device_id: "{{device_id('media_player.living_room_lg_tv')}}"