jcallaghan / home-assistant-config

My Home Assistant configuration & documentation.
https://www.jcallaghan.com/
MIT License
175 stars 8 forks source link

Managing low batteries with dashboards, notifications and automations 🔋 #60

Open jcallaghan opened 4 years ago

jcallaghan commented 4 years ago

Objective

Receive a notification when batteries are getting critical < 10% or low 10%-20% or those that are unavailable.

Features

Related to #51, #103

jcallaghan commented 4 years ago

Lovelace

Firstly before I kick off creating any automation I decided to make a Lovelace panel to give me a view of things. What this has shown me is I have a sh*t load of batteries, yet I've never really had a problem with this.

image

Low and Critical Batteries

After getting all the devices into cards, I decided to add to filter cards to show me devices with low batteries (<20%) and those with critical batteries (unavailable or less than 10%). These two panels are worth their weight in gold, especially the critical battery filter. After creating this, I discovered I had a few devices that were unavailable due to recently running out of battery.

image

Critical battery filter card

The critical battery filter card uses two filters and looks like this:

card:
  show_header_toggle: false
  title: Critical Batteries
entities:
  - entity: sensor.battery
state_filter:
  - operator: <=
    value: 10
  - operator: ==
    value: unavailable
type: entity-filter

Low battery filter card

The low battery filter card looks like this:

card:
  show_header_toggle: false
  title: Critical Batteries
entities:
  - entity: sensor.battery
state_filter:
  - operator: regex
    value: '\b(1[1-9]|2[0])\b'
type: entity-filter
jcallaghan commented 4 years ago

Grafana

I was interested to see how long it was between batteries cycles so I've created a dashboard to report on battery levels. This example is of the devices in my back garden but I'm curious if I should do this on a room-by-room basis or by a thing-type basis such as Ring, Aqara, Hue etc.

Sample

image

Favourite dashboard style

For the keen eyes out there, yes the garden is showing a battery with 200% capacity. This is because the Ring spotlight camera has two batteries, therefore, reports 200% capacity.

image

image

image

I think I prefer the retro LCD for a realtime summary of each battery over the gauges. This really emphasises the critical (<10%) and low (<20%) levels that I monitor.

jcallaghan commented 4 years ago

Automation

Leverage examples such as:

jcallaghan commented 4 years ago

Observations

Few observations I have made during this exercise.

image

jcallaghan commented 4 years ago

Shared on Twitter.

jcallaghan commented 4 years ago

How to: Battery level gauges

Rui Espinho asked on Twitter how I made the batter level gauges. These are made by leveraging the bar gauge visualisation in a Grafana dashboard along with some thresholds to align to my low (20%) and critical levels (10%).

image

jcallaghan commented 4 years ago

How to: Grafana queries

Matthias Matousek (@m_matou) asked on Twitter how I achieve the queries for batteries.

Most of my sensors are Zigbee bases and connected to Home Assistant through a Conbee II stick and deCONZ. Each sensor typically has an entity where the battery level is available. Depending on how the battery data is reported you may need to try different queries.

% method

image

Attribute method

This is where I was trying to get the battery from an attribute of an entity. I haven't had much luck with this method just yet.

image

For the visualisations I make the following changes:

Graph

Call-outs: null values connected, unit (0-100).

image

Bar Guage

Calls: For the bar gauge, I show the last (not null) value. I also change the thresholds to the values I monitor against. These match my filters in Lovelace and in my automations.

image

jcallaghan commented 4 years ago

Todo

image

image

jcallaghan commented 4 years ago

Ideas

Package example

https://community.home-assistant.io/t/howto-create-battery-alert-without-creating-a-template-for-every-device/30576/675 https://github.com/notoriousbdg/Home-AssistantConfig/blob/master/packages/battery_alert.yaml#L231

History excludes

history:
  exclude:
    entities:
      - automation.battery_persistent_notification
      - automation.battery_persistent_notification_clear
      - automation.battery_notification_default
      - automation.battery_notification_slack
      - automation.battery_sensor_from_attributes
      - automation.update_battery_status_group_members
      - automation.update_battery_low_group_members
      - automation.remove_battery_low_group
      - automation.delete_battery_sensor
jcallaghan commented 4 years ago

GitHub API

Testing

So it was always going to end up here in my view. Automated maintenance tasks. It was more deciding to use issues in this repo or creating a task in Microsoft Todo. I may still do this for testing and fun anyway.

Leveraging Postman to test the GitHub API I was able to create a new issue. Postman is great for testing APIs! You can also use parameters in the URL to fill prepare an issue: https://github.com/jcallaghan/home-assistant-config/issues/newtitle=test&body=test&labels=battery,task:%20maintenance.

image

  1. Generate new personal access token (with full repo access) https://github.com/settings/tokens
  2. API POST endpoint https://api.github.com/repos/jcallaghan/home-assistant-config/issues
  3. Set authentication method to Oauth using the access token generated above
  4. Body
    {
    "title": "Test",
    "body": "Test",
    "labels": [
    "battery",
    "task: maintenance"
    ]
    }

    Rest command

    Using the rest_command integrated I created the following service.

    rest_command:
    new_github_issue_replace_battery:
    url: https://api.github.com/repos/jcallaghan/home-assistant-config/issues
    method: POST
    headers:
      Authorization: !secret github_token
    payload: '{"title":"{{ title }}","body":"{{ message }}","labels":["battery","task: maintenance"]}'

secrets.yaml

Don't forget to add Bearer in front of your access token in your secrets file.

github_token: "Bearer 000000000000000"

Automation/service

Service name: rest_command.new_github_issue_replace_battery Service data:

{ 
  "title": "Service test",
  "message": "Create via service call in Home Assistant"
}

image

Reference

jcallaghan commented 4 years ago

Filter error

I just noticed my low battery entity-filter card was not working as expected. Turns out I wasn't able to perform an AND filter so switched to using a regex pattern.

Using a great regex tool (https://regexr.com/)[https://regexr.com/] I was able to test an expression that would return numbers in the 11-20 range.

image

state_filter:
  - operator: regex
    value: \b(1[1-9]|2[0])\b'
jcallaghan commented 4 years ago

The big battery loop

I understand why folks use the big loop to check battery status dynamically as adding each battery-related entity and maintaining them manually is a real pain. But while creating a solution to notify me when I have a low battery today I came across a few things which have led me to create a hybrid approach building on @Carlos's work CCOSTAN/Home-AssistantConfig#269.

Template sensors

Carlos leverages an approach using a template sensor with a domain-based for loop where the word battery is either found in the entity name or a battery_level attribute is defined. The sensor value consists of the entity name and battery level which Carlos goes on to use with his TTS engine.

While experimenting with the template I found I had various text-based values being returned which I excluded and at the time due to the number of sensors being returned by the template I hit the sensor text limit causing an value of unknown to be thrown. This was when I decided to split out the sensor into three, critical batteries (0-10%), low batteries (10-20%), and those that are unavailable. To achieve this I added two variables to define a threshold range.

Once I created the sensor and move from the template developer tool I noticed that the sensor wasn't updating. This is because the sensor wasn't associated to any entities. To update the sensor you need to call the service_ homeassistant.update_entity service. Another alternative is binding it to sensor.date, sensor.hour or sensor.minute which will update the sensor daily, hourly, or every minute.

Binary sensor

To make things a little nicer on the UI side I created a binary sensor for each template sensor. The state of the binary sensor is true when a battery falls within the applicable range. I still need to settle on the right device_class.

image

I'm also tempted to use a template icon to make it more obvious when the sensor is on or not.

image

I also added the template sensor text as an attribute to each of the binary sensors. This provides much more detail when clicking on the entity detail screen.

image

Extensibility

I really like the extensibility of an approach shared in the community forum that leverages MQTT to maintain configuration. I don't plan to use this for batteries but I do like the concept for some other ideas I have.

Further considerations

Right now I have automations for all three of my ranges (critical, low, and unavailable) which send a notification through to my phone. This is great but I'd still like to build some automated DevOps into this although with this automations that won't be possible as these are generic i.e. any battery is with one of these ranges.

image

If I create an additional automation that triggers when a single entity falls into my low range I should be able to create a GitHub issue for me to replace the sensor battery. This will also provide more context in the message as it will be for a specific entity rather than the collection like in the others. The full string is more useful for TTS scenarios. I'll work on this tomorrow and commit the code to share with you all.

jcallaghan commented 4 years ago

GitHub issues for low batteries

Well with the additional automation I'm able to create a GitHub issue when a device has a low battery which is pretty cool. I might replicate this for sensors that have become unavailable for an extended time too.

image

image

jcallaghan commented 4 years ago

Closing out.

It has taken a few weeks but I've achieved everything I wanted to and some (for now at least). This single issue and idea has leveraged stuff I already knew about and a ton of new stuff I've learned about but most of all it was fun and has allowed me to build on the work and ideas of others and share something back with a little edge to it.

jcallaghan commented 4 years ago

Throttling required

Seems overnight a device (Hue remote) rushed my new automation. I disabled the automation as soon as I realised it was triggering over and over. On closer inspection, the battery level fluctuates enormously so I'll need to get my thinking cap on and work our how I deal with this as a simple numeric_state trigger with below: 20 and for: 00:01:00 isn't going to cut it.

image

jcallaghan commented 4 years ago

Further ideas > https://github.com/notoriousbdg/Home-AssistantConfig/blob/master/packages/battery_alert.yaml

Also factor in monitored and unmonitored devices.

GitHub
notoriousbdg/Home-AssistantConfig
Contribute to notoriousbdg/Home-AssistantConfig development by creating an account on GitHub.
jcallaghan commented 4 years ago

Template to help find sensors with a battery

{% set domains = ['light', 'switch', 'sensor', 'lock', 'binary_sensor'] %}
{%- for domain in domains -%}
{%- for item in states[domain] if (item.attributes.battery_level is defined) or ("battery" in item.name | lower) -%}
  - entity_id: {{ item.entity_id }}
{% endfor %}
{%- endfor -%}

Template to expand group

{%- for battery in expand('group.battery_all') -%}
{%- if battery.state | int < 100 -%}  
  {{ battery.entity_id }}
{%- if not loop.last -%}, {%- endif -%}
{%- endif -%}
{%- endfor -%}