Thanks! Yea I agree, auto-updating the host in the background seems a bit dangerous, I wouldn’t want to put that on a command_line
sensor. I choose to put the actual update command onto a shell_command
that I run when I know there are updates. Although just now when I did it it took down home assistant, I assume because a package it was using was updated. So yea, I definitely wouldn’t want to run that command automatically.
That being said @Tomahawk I did figure it out
I’ll share it below but I’m not going to add this one to the package because of a few important caveats:
- This is completely OS dependent. It looks specifically at the output of
apt
to see if there’s updates so if apt
is the package manager your host uses it will need to be adjusted
-
apt
pops out this lovely warning message when you use it in this way WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
So yea, it appears they don’t really encourage this kind of usage and it may break in the future and require fixing. Just FYI
- It relies on being able to
ssh
into the host. To do this you’ll need to replace parts of the sensor with the username and address of your particular host, it won’t just work out of the box like the others above
- I set up my HA to be able to SSH into the host without a password. For anyone that doesn’t know how to do this, here’s a quick guide. Alternatively you can include your password but password-less SSH is the best practice for security.
With that out of the way, here it is. So like the others, first we need a sensor to tell us when there’s updates. And in this case since we’re using apt
our sensor
is going to return us a count of packages that need updates so I added a binary_sensor
to go with it and then obviously an alert
. Here’s those three:
sensor:
# Sensor to track info on updates available for host
# Warning: apt returns a message that its CLI is not stable enough for scripting. So be warned, this could break
- platform: command_line
name: Host updates
scan_interval: 900
command: 'ssh -o UserKnownHostsFile=/config/.ssh/known_hosts <INSERT HOST USERNAME>@<INSERT HOST ADDRESS> -i /config/.ssh/id_ed25519 ''sudo apt update > /dev/null && sudo apt list --upgradeable'' | jq --raw-input --slurp ''{ "packages": split("\n") | del(.[] | select(. == "" or . == "Listing...")) }'''
value_template: '{{ value_json.packages | length }}'
json_attributes:
- packages
binary_sensor:
- platform: template
sensors:
# True if there's updates available for the host
updater_host:
friendly_name: 'Updater - Host'
device_class: problem
value_template: "{{ states('sensor.host_updates') | int > 0 }}"
availability_template: "{{ (states('sensor.host_updates') | int(-1)) > -1 }}"
alert:
# Host update is available - un-acknowledgeable, auto-dismiss, me only
host_updates_available:
name: Host has updates
entity_id: binary_sensor.updater_host
state: 'on'
can_acknowledge: false
repeat: 360
title: "Update{% if states('sensor.host_updates') | int > 1 %}s{% endif %} for HA Host available"
message: "Updates available for {{ states('sensor.host_updates') }} package{% if states('sensor.host_updates') | int > 1 %}s{% endif %} on host"
notifiers:
- 'me'
data:
tag: 'host_updates_available'
ttl: 21600
NOTE: Run the ssh
command in the host updates sensor once manually in the portainer add-on to get your known_hosts
file updated, otherwise it won’t work. Or alternatively copy the necessary line into /config/.ssh/known_hosts
file manually from some other machine so its set up. Otherwise the SSH command will fail behind the scenes.
So, what does this sensor do? It’s going to
- SSH into the host
- Run
sudo apt update
first to update the package list (ignoring any stdout of that command)
- If that went successfully, run
sudo apt list --upgradeable
to get the list of packages to update
- Use
jq
to create a JSON array out of that output and stick it in a field called packages
ignoring rows that just say “Listing…” or are blank (since apt
does that, remember, it doesn’t like being scripted)
- Set the value of the sensor to the length of that JSON array and store the list of packages into the
packages
attribute
Note that I set the scan_interval
to 15 minutes since this one is doing a lot more work then the others.
But of course there is one difference with this one from the others, unlike the others we have no UI to send this to. There’s no place in Home Assistant that allows you to update the host. So let’s make one. With shell command we can make a service that tells our host to update all packages needing updates like so:
shell_command:
# Updates packages on host
update_host: 'ssh <INSERT HOST USERNAME>@<INSERT HOST ADDRESS> -i /config/.ssh/id_ed25519 ''sudo apt upgrade -y'''
Then you can include UI showing what needs updates with an update button up top. Here’s what I made for anyone interested. Note that it does depend on two HACS packages though, vertical stack in card and flex table. You’ll need to install them to use this as is. Or make a different UI, there’s lots of options
cards:
- cards:
- entity: sensor.host_updates
name: Host packages with updates
type: entity
- icon: 'mdi:update'
icon_height: 30px
name: Update all
tap_action:
action: call-service
service: notify.update_host
service_data:
message: Ignore
type: button
horizontal: true
type: 'custom:vertical-stack-in-card'
- columns:
- attr_as_list: packages
id: name
modify: 'x.replace(/^(\S+)(\s.*)$/, ''$1'')'
name: Name
- attr_as_list: packages
modify: 'x.replace(/^(\S+)(\s.*)$/, ''$2'')'
name: Details
entities:
include: sensor.host_updates
sort_by: name-
strict: true
type: 'custom:flex-table-card'
title: Host packages with updates
type: 'custom:vertical-stack-in-card'
And there we go! Now hopefully I’ll never build up that many host updates again haha.