Sensor for latest docker image versions

Hi,

I’m running Home Assistant along with a couple of other services such as Influx, Grafana, Pilight, and MySQL in docker containers. Instead of manually checking for upgrades for these images I’ve created sensors in Home Assistant that pull the latest image versions.

Especially for Home Assistant itself this is more useful to me than the other update notifications since it always takes a couple of days until the docker images are available.

Up until now I used a simple REST sensor that gets all available tags of a certain docker image and grabs the name of the first result which is the newest version.

  - platform: rest
    name: Home Assistant Latest Version
    resource: https://registry.hub.docker.com/v2/repositories/homeassistant/raspberrypi2-homeassistant/tags
    scan_interval: 28800
    value_template: '{{ value_json.results[0].name }}'    

This works for other non-HA images as well. However, sometimes the tag list begins with “latest” which needs to be skipped. Sometimes, the version contains more characters than necessary, e.g. “v.1.2”. By adapting the value template these things can be dealt with.

Now, with the latest release of home assistant and the introduction of beta releases my sensor naturally still showed the latest version which last week were the different beta releases. Since I’m not interested in those, I want to display the latest stable release.

The tag order of my HA image looks like this currently:

0.66.0b3
0.66.0.b2
0.66.0.beta1
0.66.0.beta0
0.65.6

With HA’s beta naming scheme being all over the place I’ve run out of ideas on how to do this with simple value templates.

So I’ve switched from a REST sensor to a command line sensor that curls the address above and then pipes the output through some regex expressions to isolate the latest stable version (0.65.6) in the case above.

Unfortunately, my HA container’s grep utility lacks the ability to execute perl regexes which would have been a more presentable solution. So I had to fall back to slightly different approach:

  - platform: command_line
    name:  Home Assistant Latest Docker
    command:  curl -s -L https://registry.hub.docker.com/v2/repositories/homeassistant/raspberrypi2-homeassistant/tags/ | grep -Eo '"name":\s"[0-9.]*"' | head -1 | sed -e "s/\"name\":\s\"/${replace}/g" | sed -e "s/\"/${replace}/g"
    scan_interval: 28800

What it does is isolate the JSON parts that have the pattern “name”: “” , taking the first result and then extracting the version number by replacing the excess characters with “”. Since the pattern for only includes numbers and dots ([0-9.]*), the beta versions are skipped.

Voila:

image

Hope this helps other to save some time.

Cheers
Jochen

Sidenote: It would of course be even cooler if homeassistant would recognize how it was installed (pip, docker, …) and only notify of updates when the relevant distribution channel has received the upgrade.

4 Likes

Nice one, Jochen!

Another useful feature would be to compare the sensor version number with the version currently installed and send a notification if they differ. For HASS it’s pretty simple, it’s available as an attribute, but I’m not sure how to do it with other containers.

I did something like this. For other containers it depends on whats running in them.
The services I mentioned (and that I care about regarding updates) have REST apis that also exposes the version somewhere. In this case you can put
a REST sensor in HA pointing to the the docker host IP with the exposed port of the other service.

If you can’t do it this way and there is no other easy way to retrieve it then you could have a cron job in your host system that executes some command (in the other docker containers or whatever) and either push it to HA via REST or put the result in a file and have it read by HA using a file sensor. I used the last approach to get the number of upgradable apt packages of the host system.

Hi, could you please explain some details about the installation of your pilight docker image?

I am currently running Hass.io in docker (inside intel VM) and would like to migrate my docker installation (raspbian based) to the same platform.

Thanks!

Hi,
I’ve built my own docker image for pilight which uses an Arduino-based “pilight usb nano” connected to the RPI’s USB port as communication device for 433mhz switches and sensors.

The docker file I use is the following:

FROM resin/rpi-raspbian:stretch

RUN apt-get update && apt-get install -y libunwind8 libpcap0.8 wget
RUN echo "deb http://apt.pilight.org/ stable main" > /etc/apt/sources.list.d/pilight.list
RUN wget -O - http://apt.pilight.org/pilight.key | apt-key add -
RUN apt-get update && apt-get install -y pilight

EXPOSE 5001

VOLUME \
/pilight \
/etc/pilight \
/usr/local/lib/pilight \
/usr/local/share/pilight

CMD pilight-daemon -F

Can’t remember the source exactly, but it is based on the manual installation steps.

I build and run it like this:

docker build -t pilight /home/pi/docker/pilight

docker run --name pilight --restart always -d -p 5000:5000 -p 5001:5001 --device /dev/ttyUSBpilight:/dev/ttyUSB1 -v /home/pi/docker/data/pilight:/pilight -v /home/pi/docker/data/pilight/config.json:/etc/pilight/config.json -v /etc/localtime:/etc/localtime:ro pilight

Hope this helps

Thank you!

I use two cmd lines sensors to probe the timestamp of the docker container and repositories to check for updates.

#component
- platform: command_line
  name: influxdb_container
  command: 'docker inspect influxdb:latest|jq .[].Created'
  scan_interval: 3600
- platform: command_line
  name: influxdb_repositories
  command: 'curl -L -s https://registry.hub.docker.com/v2/repositories/library/influxdb/tags|jq .results[0].last_updated'
  scan_interval: 3600
- platform: command_line
  name: grafana_container
  command: 'docker inspect grafana/grafana:latest|jq .[].Created'
  scan_interval: 3600
- platform: command_line
  name: grafana_repositories
  command: 'curl -L -s https://registry.hub.docker.com/v2/repositories/grafana/grafana/tags|jq .results[0].last_updated'
  scan_interval: 3600


#automation
- alias: Notify docker updates
  trigger:
  - platform: template
    value_template: >
      {{ states.sensor.influxdb_repositories.state > states.sensor.influxdb_container.state
      or states.sensor.grafana_repositories.state > states.sensor.grafana_container.state
      }}
  action:
  - service: notify.user
    data_template:
      message: 'update beschikbaar ({{ trigger.to_state.attributes.friendly_name }})'

Using docker on unRaid myself so it automatically updates the images I want and/or sends me notifications to update images manually (based on my configs). I have seen several folks mention Watchtower for automating some of the docker container update maintenance along with Portainer to manage it all. I’m not sure if Portainer does the notification thing though with updates.


Well, unless you can specify some kind of tag name regex you’re still left with potentially unwanted notifcations or updates because there is no reliable tag for the latest stable image…
The “latest” tag contains the last published image which can also be a beta version.

IMO, this needs to be changed by the HA devs so that there is a latest-stable tag or something.

Portainer does not notify afaik, but it has the option to “recreate” a container and do an image pull in the process. That also only works if there is a reliable tag that points to the latest stable version.

Here is my approach:

  - platform: rest
    name: ha_docker_version
    resource: 'https://registry.hub.docker.com/v2/repositories/homeassistant/raspberrypi3-homeassistant/tags'
    value_template: >-
      {% set results = value_json.results %}
      {%-set res-%}
      {%-set pipe = joiner('|')-%}
      {% for result in results if not result.name |regex_search("[a-z]",ignorecase=TRUE) -%} 
        {{ pipe()}}{{result.name}}      
      {% else %}        
        -1 
      {% endfor -%}
      {% endset -%}
      {% set res = res.split('|')|list -%}
      {{res[0]}}
    scan_interval: 1800
3 Likes

Interesting what you can do with value templates :grin:

But isn’t the if condition inverted?
It looks like it pipes the version only if it is empty or alphanumeric.

Without pipes you could probably just exit the loop on the first match.

For my purposes it’s not. I want to get latest stable release version.

Condition checks if version not includes any letters than it put it in the list.

Here is the result
image

Ah ok, I did not get the syntax right. I thought it was a logical OR in the condition, but instead it’s a pipe symbol, right?

It’s jinja2 filter symbol

Very nice. The docker build are sometimes very slow compared to github releases.
How/where did you find the resource url? I would like to see if I can use this for some of the other docker containers I use.

This is standard docker hub API https://docs.docker.com/registry/spec/api/#overview

Great, thanks.
I’ve got it working for 5 out of 6 containers.

One of them have tags like “5.10”, “5.10.17” and “5.10.19” (https://hub.docker.com/r/jacobalberty/unifi/tags)
The first tag is usually the latest/newest, but the one I’m really interested in this case is actually 5.10.19
Is it possible to adapt the rest sensor to find the latest tag in this format?

I think yes. You have to play with regex filter

I’ve been playing around with regex and here are some examples in case others would like to use them.
Use with @Lapatoc’s code.

Find the latest tag that does not include characters (original):
{% for result in results if not result.name |regex_search("[a-z]",ignorecase=TRUE) -%}

Find the latest tag named #.#.# (eg. 0.88.2)
{% for result in results if result.name |regex_search("\d+\.\d+\.\d+$") -%}

Find the latest tag named #.#.#something (eg. 0.89.2b2)
{% for result in results if result.name |regex_search("\d+\.\d+\.\d+") -%}

Find the latest tag named #.# (eg. 2.6)
{% for result in results if result.name |regex_search("\d+\.\d+$") -%}

Find the latest version named amd64-#.#.# (eg. amd64-2.05.59)
{% for result in results if result.name |regex_search("amd64-\d+\.\d+\.\d+$") -%}

Example notification for @Lapatoc’s code:

- alias: 'Notify - Home Assistant docker tag changed'
  trigger:
    - platform: state
      entity_id: sensor.ha_docker_version
  action:
    - service: persistent_notification.create
      data_template:
        message: "Home Assistant docker tag changed from {{ trigger.from_state.state }} to {{ trigger.to_state.state }}"
2 Likes

Minor tweak: Don’t trigger if sensor is unavailable.

  condition:
    condition: template
    value_template: >
      {{ trigger.to_state.state not in [trigger.from_state.state, 'unavailable'] }}