Update notifications! Core, HACS, Supervisor and Addons (now a blueprint!)

Big update - 4/7/2022

As of release 2022.4.0 of HA, this package is now a blueprint!
Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

Now all you have to do to get update notifications for everything is this:

  1. Click the import button
  2. Create an automation out of the blueprint
  3. Fill in the inputs based on what features you want to enable (there’s a few options, the descriptions should explain them).

I’m going to leave the original package info below in a collapse for reference. For people not yet on 2022.4 or people that want to leverage the curling supervisor’s API technique for other use cases (I’ve seen it pop up in a few other places around the forum).

And definitely @ me if you have any issues. I did have to rewrite the entire thing to be a single automation which was quite a lot of yaml. I tested the various options but its possible I missed something. If you find something definitely let me know so I can get it fixed up.


Original Package for HA prior to 2022.4.0

Note: For those that have been following this project from the beginning, there used to be a lot more information here. Turns out posts have a limit of 32k characters so I chopped out everything besides the actual packages. If you’re interested in my explanation of the parts you’ll have to look at the post’s history, sorry about that.

Update Notifications package
sensor:
  # Sensor to track available updates for supervisor & addons
  - platform: command_line
    name: Supervisor updates
    command: 'curl http://supervisor/supervisor/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq ''{"newest_version":.data.version_latest,"current_version":.data.version,"update_available":.data.update_available,"addons":[.data.addons[] | select(.update_available)]}'''
    value_template: "{{ value_json.addons | length }}"
    unit_of_measurement: pending update(s)
    json_attributes:
    - update_available
    - newest_version
    - current_version
    - addons

binary_sensor:
  # True if there's updates available for any HACS components or Addons
  - platform: threshold
    name: Updater HACS
    entity_id: sensor.hacs
    upper: 0.5
  - platform: threshold
    name: Updater Addons
    entity_id: sensor.supervisor_updates
    upper: 0.5

  - platform: template
    sensors:
      # True if there's an update available for supervisor
      updater_supervisor:
        friendly_name: 'Updater Supervisor'
        device_class: problem
        value_template: "{{ state_attr('sensor.supervisor_updates', 'update_available') }}"
        availability_template: "{{ states('sensor.supervisor_updates') | int(-1) > -1 }}"

alert:
  # Update is available - un-acknowledgeble, auto-dismiss, me only
  # Wait 5 minutes before first to give core config check time to run
  ha_update_available:
    name: HA has an update
    entity_id: binary_sensor.updater
    state: 'on'
    can_acknowledge: false
    repeat: 
    - 5
    - 360
    skip_first: true
    title: 'Update for HA available'
    message: "New version is {{ state_attr('binary_sensor.updater', 'newest_version') }}. Currently on {{ states('sensor.current_version') }}"
    notifiers:
    - 'me'
    data:
      tag: 'ha-update-available'
      url: 'http://hassio.local/hassio/addon/core_check_config'
      ttl: 21600

  # Supervisor update is available - un-acknowledgeable, auto-dismiss, me only
  supervisor_update_available:
    name: Supervisor has an update
    entity_id: binary_sensor.updater_supervisor
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: 'Update for HA Supervisor available'
    message: "New version is {{ state_attr('sensor.supervisor_updates', 'newest_version') }}. Currently on {{ state_attr('sensor.supervisor_updates', 'current_version') }}"
    notifiers:
    - 'me'
    data:
      tag: 'supervisor-update-available'
      url: 'http://hassio.local/hassio/dashboard'
      ttl: 21600

  # HACS repos have updates available - unacknowledgeable, auto-dismiss, me only
  hacs_update_available:
    name: HACS repos have updates
    entity_id: binary_sensor.updater_hacs
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: "Updates available in {{ states('sensor.hacs') }} HACS repo{% if states('sensor.hacs') | int > 1 %}s{% endif %}"
    message: ""
    notifiers:
      - 'me'
    data:
      tag: 'hacs-update-available'
      url: 'http://hassio.local/hacs/installed'
      ttl: 21600

  # Addons have updates available - unacknowledgeable, auto-dismiss, me only
  addon_update_available:
    name: Addons have updates
    entity_id: binary_sensor.updater_addons
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: "Updates available for {{ states('sensor.supervisor_updates') }} HA addon{% if states('sensor.supervisor_updates') | int > 1 %}s{% endif %}"
    message: ""
    notifiers:
    - 'me'
    data:
      tag: 'addon-update-available'
      url: 'http://hassio.local/hassio/dashboard'
      ttl: 21600

automation:
  - id: '1585256741683'
    alias: Check config with update
    description: Starts the check config addon when an update becomes available
    trigger:
    - entity_id: binary_sensor.updater
      platform: state
      to: 'on'
    condition: []
    action:
    - data:
        addon: core_check_config
      service: hassio.addon_start

Package with additions for audio, dns and others

See this post for reasoning behind these additions.

Update Notifications package + audio, dns, cli, multicast and core
sensor:
  # Sensor to track available updates for supervisor & addons
  - platform: command_line
    name: Supervisor updates
    command: 'curl http://supervisor/supervisor/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq ''{"newest_version":.data.version_latest,"current_version":.data.version,"update_available":.data.update_available,"addons":[.data.addons[] | select(.update_available)]}'''
    value_template: "{{ value_json.addons | length }}"
    unit_of_measurement: pending update(s)
    json_attributes:
    - update_available
    - newest_version
    - current_version
    - addons

  # Sensors to track updates to other core components (audio, dns, CLI and multicast)
  - platform: command_line
    name: Updater Audio
    command: 'curl http://supervisor/audio/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq ''{"newest_version":.data.version_latest,"current_version":.data.version, "update_available":.data.update_available}'''
    value_template: "{% if value_json.update_available %}on{% else %}off{% endif %}"
    json_attributes:
    - update_available
    - newest_version
    - current_version
  - platform: command_line
    name: Updater DNS
    command: 'curl http://supervisor/dns/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq ''{"newest_version":.data.version_latest,"current_version":.data.version, "update_available":.data.update_available}'''
    value_template: "{% if value_json.update_available %}on{% else %}off{% endif %}"
    json_attributes:
    - update_available
    - newest_version
    - current_version
  - platform: command_line
    name: Updater CLI
    command: 'curl http://supervisor/cli/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq ''{"newest_version":.data.version_latest,"current_version":.data.version, "update_available":.data.update_available}'''
    value_template: "{% if value_json.update_available %}on{% else %}off{% endif %}"
    json_attributes:
    - update_available
    - newest_version
    - current_version
  - platform: command_line
    name: Updater Multicast
    command: 'curl http://supervisor/multicast/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq ''{"newest_version":.data.version_latest,"current_version":.data.version, "update_available":.data.update_available}'''
    value_template: "{% if value_json.update_available %}on{% else %}off{% endif %}"
    json_attributes:
    - update_available
    - newest_version
    - current_version
  - platform: command_line
    name: Updater Observer
    command: 'curl http://supervisor/observer/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq ''{"newest_version":.data.version_latest,"current_version":.data.version, "update_available":.data.update_available}'''
    value_template: "{% if value_json.update_available %}on{% else %}off{% endif %}"
    json_attributes:
    - update_available
    - newest_version
    - current_version
  # Alternate updater sensor for core since binary_sensor.updater is very slow to recognize updates
  - platform: command_line
    name: Updater Core
    command: 'curl http://supervisor/core/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq ''{"newest_version":.data.version_latest,"current_version":.data.version, "update_available":.data.update_available}'''
    value_template: "{% if value_json.update_available %}on{% else %}off{% endif %}"
    json_attributes:
    - update_available
    - newest_version
    - current_version  

binary_sensor:
  # True if there's updates available for any HACS components or Addons
  - platform: threshold
    name: Updater HACS
    entity_id: sensor.hacs
    upper: 0.5
  - platform: threshold
    name: Updater Addons
    entity_id: sensor.supervisor_updates
    upper: 0.5

  - platform: template
    sensors:
      # True if there's an update available for supervisor
      updater_supervisor:
        friendly_name: 'Updater Supervisor'
        device_class: problem
        value_template: "{{ state_attr('sensor.supervisor_updates', 'update_available') }}"
        availability_template: "{{ states('sensor.supervisor_updates') | int(-1) > -1 }}"

alert:
  # Update is available - un-acknowledgeble, auto-dismiss, me only
  # Wait 5 minutes before first to give core config check time to run
  ha_update_available:
    name: HA has an update
    entity_id: sensor.updater_core
    state: 'on'
    can_acknowledge: false
    repeat: 
    - 5
    - 360
    skip_first: true
    title: 'Update for HA available'
    message: "New version is {{ state_attr('sensor.updater_core', 'newest_version') }}. Currently on {{ state_attr('sensor.updater_core', 'current_version') }}"
    notifiers:
    - 'me'
    data:
      tag: 'ha-update-available'
      url: 'http://hassio.local/hassio/addon/core_check_config'

  # Supervisor update is available - un-acknowledgeable, auto-dismiss, me only
  supervisor_update_available:
    name: Supervisor has an update
    entity_id: binary_sensor.updater_supervisor
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: 'Update for HA Supervisor available'
    message: "New version is {{ state_attr('sensor.supervisor_updates', 'newest_version') }}. Currently on {{ state_attr('sensor.supervisor_updates', 'current_version') }}"
    notifiers:
    - 'me'
    data:
      tag: 'supervisor-update-available'
      url: 'http://hassio.local/hassio/dashboard'

  # Audio update is available - un-acknowledgeable, auto-dismiss, me only
  audio_update_available:
    name: Audio has an update
    entity_id: sensor.updater_audio
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: 'Update for HA Audio available'
    message: "New version is {{ state_attr('sensor.updater_audio', 'newest_version') }}. Currently on {{ state_attr('sensor.updater_audio', 'current_version') }}"
    notifiers:
    - 'me'
    data:
      tag: 'audio_update_available'
      url: 'http://hassio.local/hassio/dashboard'

  # DNS update is available - un-acknowledgeable, auto-dismiss, me only
  dns_update_available:
    name: DNS has an update
    entity_id: sensor.updater_dns
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: 'Update for HA DNS available'
    message: "New version is {{ state_attr('sensor.updater_dns', 'newest_version') }}. Currently on {{ state_attr('sensor.updater_dns', 'current_version') }}"
    notifiers:
    - 'me'
    data:
      tag: 'dns_update_available'
      url: 'http://hassio.local/hassio/dashboard'

  # CLI update is available - un-acknowledgeable, auto-dismiss, me only
  cli_update_available:
    name: CLI has an update
    entity_id: sensor.updater_cli
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: 'Update for HA CLI available'
    message: "New version is {{ state_attr('sensor.updater_cli', 'newest_version') }}. Currently on {{ state_attr('sensor.updater_cli', 'current_version') }}"
    notifiers:
    - 'me'
    data:
      tag: 'cli_update_available'
      url: 'http://hassio.local/hassio/dashboard'

  # Multicast update is available - un-acknowledgeable, auto-dismiss, me only
  multicast_update_available:
    name: Multicast has an update
    entity_id: sensor.updater_multicast
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: 'Update for HA Multicast available'
    message: "New version is {{ state_attr('sensor.updater_multicast', 'newest_version') }}. Currently on {{ state_attr('sensor.updater_multicast', 'current_version') }}"
    notifiers:
    - 'me'
    data:
      tag: 'multicast_update_available'
      url: 'http://hassio.local/hassio/dashboard'

  # Observer update is available - un-acknowledgeable, auto-dismiss, mike only
  observer_update_available:
    name: Observer has an update
    entity_id: sensor.updater_observer
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: 'Update for HA Observer available'
    message: "New version is {{ state_attr('sensor.updater_observer', 'newest_version') }}. Currently on {{ state_attr('sensor.updater_observer', 'current_version') }}"
    notifiers:
    - 'me'
    data:
      tag: 'observer_update_available'
      url: '/hassio/dashboard'

  # HACS repos have updates available - unacknowledgeable, auto-dismiss, me only
  hacs_update_available:
    name: HACS repos have updates
    entity_id: binary_sensor.updater_hacs
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: "Updates available in {{ states('sensor.hacs') }} HACS repo{% if states('sensor.hacs') | int > 1 %}s{% endif %}"
    message: ""
    notifiers:
      - 'me'
    data:
      tag: 'hacs-update-available'
      url: 'http://hassio.local/hacs/installed'

  # Addons have updates available - unacknowledgeable, auto-dismiss, me only
  addon_update_available:
    name: Addons have updates
    entity_id: binary_sensor.updater_addons
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: "Updates available for {{ states('sensor.supervisor_updates') }} HA addon{% if states('sensor.supervisor_updates') | int > 1 %}s{% endif %}"
    message: ""
    notifiers:
    - 'me'
    data:
      tag: 'addon-update-available'
      url: 'http://hassio.local/hassio/dashboard'

automation:
  - id: '1585256741683'
    alias: Check config with update
    description: Starts the check config addon when an update becomes available
    trigger:
    - entity_id: sensor.updater_core
      platform: state
      to: 'on'
    condition: []
    action:
    - data:
        addon: core_check_config
      service: hassio.addon_start

And now there’s host update notifications! There’s a bunch of caveats to this one though so please read this post below for details

Supervisor Integration (2/24/2022 Update)

This package uses the update_available binary sensors created by the supervisor integration instead of curling supervisor. This is preferred to the old way of curling supervisor for everything if you have these sensors. However you must remember to enable the update_available sensors for each addon, they all start disabled.

This package still includes a better update available sensor for core (the native updater only updates once a day) and the automation that starts the config check addon when a core update becomes available. Although the value of that check is still debatable since it returns a lot of false positives.

It drops all the sensors tracking updates for supervisor and the various supervisor plugins (audio, dns, cli, etc.) Those weren’t very helpful in reality since all those all auto-update, the sensors rarely even noticed an update before it happened. If you want to know about updates to those I suggest watching the repos for supervisor and each plugin instead.

Update Notifications, supervisor integration
sensor:
  # Alternate updater sensor for core since binary_sensor.updater is very slow to recognize updates
  - platform: command_line
    name: Updater Core
    command: 'curl http://supervisor/core/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" 2> /dev/null | jq ''{"newest_version":.data.version_latest,"current_version":.data.version, "update_available":.data.update_available}'''
    scan_interval: 300
    value_template: "{% if value_json.update_available %}on{% else %}off{% endif %}"
    json_attributes:
      - update_available
      - newest_version
      - current_version

  # Reads the log of the check config addon to see if it passed or failed, updated mainly via automation
  - platform: command_line
    name: Check config addon status
    scan_interval: 300
    command: 'curl http://supervisor/addons/core_check_config/logs -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" 2> /dev/null | grep -E ''\[[0-9]{2}:[0-9]{2}:[0-9]{2}\] (ERROR:.+?The configuration check did not pass!|INFO:.+?Configuration check finished - no error found! :\))'' | sed -r ''s/(.*) (ERROR|INFO):.*/\2 \1/'''
    value_template: "{{ value | lower | regex_replace('^info', 'pass') }}"

binary_sensor:
  # True if there's updates available for any HACS components or Addons
  - platform: threshold
    name: Updater HACS
    entity_id: sensor.hacs_updates
    upper: 0.5
  - platform: threshold
    name: Updater Addons
    entity_id: sensor.addon_updates
    upper: 0.5

template:
  binary_sensor:
    # True if there's an update available and the config check has completed or its been 20 minutes
    - name: core_has_update
      unique_id: '9108f22a9aac4ef6b167f20da7c476ec'
      device_class: problem
      state: >-
        {{ is_state('sensor.updater_core', 'on') and (
          states.sensor.updater_core.last_changed < states.sensor.check_config_addon_status.last_changed and
          not is_state('sensor.check_config_addon_status', '') or
          (now() - timedelta(minutes=20)) > states.sensor.updater_core.last_changed
        ) }}

  sensor:
    # Count of the number of addons with updates available
    - name: addon_updates
      unique_id: '85bdfbe83e534821950f0763f0a8b025_addon_updates'
      unit_of_measurement: update(s)
      state: >-
        {{ expand(
            integration_entities("hassio")
              | select('search', '_update_available(_\d+)?$')
              | reject('search', '_operating_system_')
          ) | selectattr('state', 'eq', 'on')
          | list | count }}

alert:
  # core_has_update sensor waits up to 20 minutes for config check addon to run before becoming true
  ha_core_update_available:
    name: Core has an update
    entity_id: binary_sensor.core_has_update
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: 'Update for HA Core available'
    message: >-
      New version is {{ state_attr('sensor.updater_core', 'newest_version') }}.
      Currently on {{ state_attr('sensor.updater_core', 'current_version') }}.
      Config check has
      {% if states('sensor.check_config_addon_status') | regex_search('^error') %}
        failed, check before updating.
      {% elif states('sensor.check_config_addon_status') | regex_search('^pass') %}
        passed, feel free to update.
      {% else %}
        not completed, check the addon to see what happened.
      {% endif %}
    notifiers: 'me'
    data:
      tag: 'ha_core_update_available'
      group: Updates
      channel: Updates
      ttl: 21600
      url: '/config/dashboard'
      sticky: 'true'
      actions:
      - action: URI
        title: Changelog
        uri: 'https://github.com/home-assistant/core/releases/latest'
      - action: URI
        title: Open config check
        uri: '/hassio/addon/core_check_config/logs'

  ha_os_update_available:
    name: OS has an update
    entity_id: binary_sensor.home_assistant_operating_system_update_available
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: 'Update for HA OS available'
    message: >-
      New version is {{ states('sensor.home_assistant_operating_system_newest_version')
      }}. Currently on {{ states('sensor.home_assistant_operating_system_version') }}
    notifiers: 'me'
    data:
      tag: 'ha_os_update_available'
      group: Updates
      channel: Updates
      ttl: 21600
      url: '/config/dashboard'
      sticky: 'true'
      actions:
      - action: URI
        title: Changelog
        uri: 'https://github.com/home-assistant/operating-system/releases/latest'

  hacs_update_available:
    name: HACS components have updates
    entity_id: binary_sensor.updater_hacs
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: >-
      Updates available for {{ states('sensor.hacs_updates')
      }} HACS component{% if states('sensor.hacs_updates') | int > 1 %}s{% endif %}
    message: "Click to see repositories"
    notifiers: 'me'
    data:
      tag: 'hacs_update_available'
      group: Updates
      channel: Updates
      ttl: 21600
      url: '/hacs'
      sticky: 'true'

  addon_update_available:
    name: Addons have updates
    entity_id: binary_sensor.updater_addons
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: >-
      Updates available for {{ states('sensor.addon_updates')
      }} HA addon{% if states('sensor.addon_updates') | int > 1 %}s{% endif %}
    message: "Click to see addons"
    notifiers: 'me'
    data:
      tag: 'addon_update_available'
      group: Updates
      channel: Updates
      ttl: 21600
      url: '/hassio/dashboard'
      sticky: 'true'

automation:
  - id: '1585256741683'
    alias: Check config with update
    description: Starts the check config addon when an update becomes available
    trigger:
    - entity_id: sensor.updater_core
      platform: state
      to: 'on'
    condition: []
    action:
    - data:
        addon: core_check_config
      service: hassio.addon_start
58 Likes

I haven’t updated this Node RED extension in a long time since there didn’t seem to be a lot of interest in it. I’m not really sure if it still works tbh.

But as of HA 2022.4 the blueprint makes all this unnecessary. All this was doing was giving you an notification per addon/hacs update instead of one notification that said “there are updates”. The blueprint does that. So I will leave this here but consider it all deprecated.

DEPRECATED - Node RED extensions to original package

For those using Node-RED I actually extended this a bit further. Not everyone uses Node RED so I wanted to keep the core stuff separate but I’ll take you through my related flows.

This is probably overboard but it was fun at least. I decided that I wanted a notification specific to each HACS component or Addon that updated rather then just a generic one saying how many things need updates. So basically as an update becomes available for one of these, send me an update that says exactly which component/add-on updated. This one is not going to repeat every 6 hours, its just once when the update first becomes available.

So first for people that do use Node RED I make heavy use of a add-on Node RED package called components. I’ll share pictures and explain my flows but to actually import my config you’ll need this package. You can read more about it on the github page but for a quick explanation, I like it because its like subflows except I can carefully control the inputs. Subflows bother me since the message object just gets passed in as is which makes it difficult to have reusable code. With components I define exactly what the input object looks like and callers use the typical options to map to those inputs. I personally prefer this but you don’t have to, the flows can be remade without it.

Now for the details. The main flows are these:
Screen Shot 2020-03-26 at 5.40.25 PM
They’re basically identical, one for sensor.hacs and one for the addon/supervisor one I described above sensor.supervisor_updates. They track state changes in those (which is a count of how many addons/components have updates) and when the new state is greater then the previous state they go on the upper path. The lower path is when the count has decreased (i.e. I updated things).

That nodes called “Filter out old updates” and “Filter out updates” are all calling the same component. It takes in two arrays where one is a subset of the other and the name of a field that is unique in each row. It then sets msg.payload to the set of values that are only in one array. The component is basically just a single function node, I just didn’t want to copy and paste the same javascript 4 times. It looks like this:
Screen Shot 2020-03-26 at 5.46.41 PM
And here’s the code in that function node for reference:

msg.payload = [];
for(let i = 0; i < msg.array_whole.length; i++){
    let elem = msg.array_whole[i];
    let add = true;
    for(let o = 0; o < msg.array_subset.length; o++ ){
        let inner_elem = msg.array_subset[o];
        if(elem[msg.field] === inner_elem[msg.field]){
            add = false;
            break;
        }
    }
    if(add){
        msg.payload.push(elem);
    }
}
return msg;

After that component completes if we’re on the top path we’ll be left with the set of components/addons that were just updated so we feed that into a split and send me a notifiation for each one. On the bottom path what we’re filtering out is the set of components/addons which I’ve updated and are no longer in the list so I feed that into a split and do a dismiss notification for each one of those to get rid of it.

The final components are basically just wrappers on service calls, notify.html5 and html5.dismiss. I made them components because then I can just lay out all the different options (html5 notifications have a lot) as inputs and don’t have to remember the schema JSON that goes in the data box every time. It also makes it easy for me to have my own defaults for all the many options as well as handling things like replacing all special characters in tags with underscores (otherwise they don’t work).

And that’s it. Here’s the JSON to import, just remember you need the component add-on first. Also if you choose to use the alerts I described above as well I would suggest adding skip_first: true to the hacs_update_available and addon_update_available alerts. As soon as an update becomes available in an addon or HACS component node-red will send you a notification so the alert is really just for the 6 hour reminder.

Distinct Set component:

[{"id":"79598795.12d6a","type":"comment","z":"f9be3564.a66948","name":"Find distinct set","info":"Takes in two arrays where one is a subset of the other. Finds the set of values that is only in one and sets payload to that array.","x":100,"y":2080,"wires":[]},{"id":"3841792.0037586","type":"component_in","z":"f9be3564.a66948","name":"Find distinct set","api":[{"name":"array_whole","type":"json","required":true},{"name":"array_subset","type":"json","required":true},{"name":"field","type":"string","required":true}],"x":100,"y":2120,"wires":[["4f9401a.a83b18"]]},{"id":"4f9401a.a83b18","type":"function","z":"f9be3564.a66948","name":"Filter out overlap values","func":"msg.payload = [];\nfor(let i = 0; i < msg.array_whole.length; i++){\n    let elem = msg.array_whole[i];\n    let add = true;\n    for(let o = 0; o < msg.array_subset.length; o++ ){\n        let inner_elem = msg.array_subset[o];\n        if(elem[msg.field] === inner_elem[msg.field]){\n            add = false;\n            break;\n        }\n    }\n    if(add){\n        msg.payload.push(elem);\n    }\n}\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":2120,"wires":[["4c51190f.efd728"]]},{"id":"4c51190f.efd728","type":"component_out","z":"f9be3564.a66948","name":"Return payload","x":520,"y":2120,"wires":[]}]

Notification components:

[{"id":"5e822b2d.90ea4c","type":"function","z":"f9be3564.a66948","name":"Set up payload","func":"if(!msg.hasOwnProperty('ttl') || msg.ttl > 0){\n    msg.ttl = 86400;\n}\nmsg.payload = {\n    \"data\" : {\n        \"title\": msg.title,\n        \"message\": msg.message,\n        \"data\":{\n            \"ttl\": msg.ttl\n        }\n    }\n};\nvar notify_data = msg.payload.data.data;\nif(msg.hasOwnProperty('tag') && msg.tag !== ''){\n    notify_data.tag = msg.tag.replace(/[^-\\w]/g, '_');\n}\nif(msg.hasOwnProperty('image_url') && msg.image_url !== ''){\n    notify_data.badge = msg.image_url;\n    notify_data.icon = msg.image_url;\n}\nif(msg.hasOwnProperty('ttl') && msg.ttl > 0){\n    notify_data.ttl = msg.ttl;\n}\nif(msg.hasOwnProperty('url') && msg.url !== ''){\n    notify_data.url = msg.url;\n}\nif(msg.hasOwnProperty('actions') && Array.isArray(msg.actions)){\n    notify_data.actions = msg.actions;\n}\nif(msg.hasOwnProperty('requireInteraction') && typeof msg.requireInteraction == 'boolean'){\n    notify_data.requireInteraction = msg.requireInteraction;\n}\nif(msg.hasOwnProperty('priority') && msg.priority !== ''){\n    notify_data.priority = msg.priority;\n}\nif(msg.hasOwnProperty('silent') && typeof msg.silent == 'boolean'){\n    notify_data.silent = msg.silent;\n}\nreturn msg;","outputs":1,"noerr":0,"x":260,"y":80,"wires":[["b41f9fed.00a388"]]},{"id":"3a1d9ae6.50d41e","type":"component_in","z":"f9be3564.a66948","name":"Notify me","api":[{"name":"title","type":"string","required":true},{"name":"message","type":"string","required":true},{"name":"tag","type":"string","required":false},{"name":"image_url","type":"string","required":false},{"name":"ttl","type":"number","required":false},{"name":"url","type":"string","required":false},{"name":"actions","type":"json","required":false},{"name":"requireInteraction","type":"boolean","required":false},{"name":"priority","type":"string","required":false},{"name":"silent","type":"boolean","required":false}],"x":100,"y":80,"wires":[["5e822b2d.90ea4c"]]},{"id":"9051503f.c1187","type":"component_out","z":"f9be3564.a66948","name":"End","x":550,"y":80,"wires":[]},{"id":"6274fe5f.88e86","type":"comment","z":"f9be3564.a66948","name":"Notify me","info":"Send a notification to my devices. ","x":100,"y":40,"wires":[]},{"id":"7b77e12b.8f43a8","type":"component_in","z":"f9be3564.a66948","name":"Dismiss notification","api":[{"name":"tag","type":"string","required":true}],"x":750,"y":80,"wires":[["843e2c06.175008"]]},{"id":"4ee84293.a9cca4","type":"comment","z":"f9be3564.a66948","name":"Dismiss notification","info":"Dismisses a notification previously sent out by tag. Handles escaping invalid characters in tag with underscore to match up with the notification component.","x":750,"y":40,"wires":[]},{"id":"843e2c06.175008","type":"change","z":"f9be3564.a66948","name":"Fix tag","rules":[{"t":"set","p":"tag","pt":"msg","to":"$replace(tag, /[^-\\w]/, '_')\t","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":910,"y":80,"wires":[["a2fc7af0.68539"]]},{"id":"a2fc7af0.68539","type":"api-call-service","z":"f9be3564.a66948","name":"Dismiss notification","server":"cc03735a.94933","version":1,"debugenabled":false,"service_domain":"html5","service":"dismiss","entityId":"","data":"{\"data\":{\"tag\":\"{{ tag }}\"}}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1070,"y":80,"wires":[["85c6a3f.61e006"]]},{"id":"85c6a3f.61e006","type":"component_out","z":"f9be3564.a66948","name":"End","x":1230,"y":80,"wires":[]},{"id":"b41f9fed.00a388","type":"api-call-service","z":"f9be3564.a66948","name":"Notify me","server":"cc03735a.94933","version":1,"debugenabled":false,"service_domain":"notify","service":"html5","entityId":"","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":420,"y":80,"wires":[["9051503f.c1187"]]},{"id":"cc03735a.94933","type":"server","z":"","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]

Main event flows:

[{"id":"f2f12f60.c558d","type":"trigger-state","z":"a74fee2d.ac9068","name":"HACS update available","server":"cc03735a.94933","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"sensor.hacs","entityidfiltertype":"exact","debugenabled":false,"constraints":[{"id":"h9meihjciqa","targetType":"this_entity","targetValue":"","propertyType":"current_state","propertyValue":"new_state.state","comparatorType":">","comparatorValueDatatype":"prevEntity","comparatorValue":"state"}],"constraintsmustmatch":"all","outputs":2,"customoutputs":[],"outputinitially":false,"state_type":"num","x":130,"y":480,"wires":[["9a24364d.905c9"],["ca233c8.8b0c2c"]]},{"id":"414e5c5e.a2ca84","type":"split","z":"a74fee2d.ac9068","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":550,"y":460,"wires":[["b626f660.eaa058"]]},{"id":"b626f660.eaa058","type":"component","z":"a74fee2d.ac9068","name":"Notify me","targetComponent":{"id":"3a1d9ae6.50d41e","name":"Notify me","api":[{"name":"title","type":"string","required":true},{"name":"message","type":"string","required":true},{"name":"tag","type":"string","required":false},{"name":"image_url","type":"string","required":false},{"name":"ttl","type":"number","required":false},{"name":"url","type":"string","required":false},{"name":"actions","type":"json","required":false},{"name":"requireInteraction","type":"boolean","required":false},{"name":"priority","type":"string","required":false},{"name":"silent","type":"boolean","required":false}]},"paramSources":{"title":{"name":"title","type":"string","required":true,"source":"\"Update for HACS repo '\" & payload.display_name & \"'\"","sourceType":"jsonata"},"message":{"name":"message","type":"string","required":true,"source":"\"Newest version of \" & payload.name & \" is \" & payload.available_version & \", installed version is \" & payload.installed_version","sourceType":"jsonata"},"tag":{"name":"tag","type":"string","required":false,"source":"payload.name","sourceType":"msg"},"image_url":{"name":"image_url","type":"string","required":false,"source":"","sourceType":"str"},"ttl":{"name":"ttl","type":"number","required":false,"source":"0","sourceType":"num"},"url":{"name":"url","type":"string","required":false,"source":"http://hassio.local/hacs/installed","sourceType":"str"},"actions":{"name":"actions","type":"json","required":false,"source":"null","sourceType":"json"},"requireInteraction":{"name":"requireInteraction","type":"boolean","required":false,"source":"null","sourceType":"json"},"priority":{"name":"priority","type":"string","required":false,"source":"","sourceType":"str"},"silent":{"name":"silent","type":"boolean","required":false,"source":"false","sourceType":"bool"}},"x":690,"y":460,"wires":[[]]},{"id":"9a24364d.905c9","type":"component","z":"a74fee2d.ac9068","name":"Filter out old updates","targetComponent":{"id":"3841792.0037586","name":"Find distinct set","api":[{"name":"array_whole","type":"json","required":true},{"name":"array_subset","type":"json","required":true},{"name":"field","type":"string","required":true}]},"paramSources":{"array_whole":{"name":"array_whole","type":"json","required":true,"source":"data.event.new_state.attributes.repositories","sourceType":"msg"},"array_subset":{"name":"array_subset","type":"json","required":true,"source":"data.event.old_state.attributes.repositories","sourceType":"msg"},"field":{"name":"field","type":"string","required":true,"source":"name","sourceType":"str"}},"x":380,"y":460,"wires":[["414e5c5e.a2ca84"]]},{"id":"ca233c8.8b0c2c","type":"component","z":"a74fee2d.ac9068","name":"Filter out updates","targetComponent":{"id":"3841792.0037586","name":"Find distinct set","api":[{"name":"array_whole","type":"json","required":true},{"name":"array_subset","type":"json","required":true},{"name":"field","type":"string","required":true}]},"paramSources":{"array_whole":{"name":"array_whole","type":"json","required":true,"source":"data.event.old_state.attributes.repositories","sourceType":"msg"},"array_subset":{"name":"array_subset","type":"json","required":true,"source":"data.event.new_state.attributes.repositories","sourceType":"msg"},"field":{"name":"field","type":"string","required":true,"source":"name","sourceType":"str"}},"x":370,"y":500,"wires":[["413e624c.d7945c"]]},{"id":"413e624c.d7945c","type":"split","z":"a74fee2d.ac9068","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":550,"y":500,"wires":[["89b8ab9.b8a5458"]]},{"id":"b8b5a32d.81a9d","type":"trigger-state","z":"a74fee2d.ac9068","name":"Addon update available","server":"cc03735a.94933","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"sensor.addon_updater","entityidfiltertype":"exact","debugenabled":false,"constraints":[{"id":"h9meihjciqa","targetType":"this_entity","targetValue":"","propertyType":"current_state","propertyValue":"new_state.state","comparatorType":">","comparatorValueDatatype":"prevEntity","comparatorValue":"state"}],"constraintsmustmatch":"all","outputs":2,"customoutputs":[],"outputinitially":false,"state_type":"num","x":130,"y":580,"wires":[["3cb3e090.e9036"],["fcd445fa.878de8"]]},{"id":"50618624.9ba708","type":"split","z":"a74fee2d.ac9068","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":550,"y":560,"wires":[["5f1757bf.a0746"]]},{"id":"5f1757bf.a0746","type":"component","z":"a74fee2d.ac9068","name":"Notify me","targetComponent":{"id":"3a1d9ae6.50d41e","name":"Notify me","api":[{"name":"title","type":"string","required":true},{"name":"message","type":"string","required":true},{"name":"tag","type":"string","required":false},{"name":"image_url","type":"string","required":false},{"name":"ttl","type":"number","required":false},{"name":"url","type":"string","required":false},{"name":"actions","type":"json","required":false},{"name":"requireInteraction","type":"boolean","required":false},{"name":"priority","type":"string","required":false},{"name":"silent","type":"boolean","required":false}]},"paramSources":{"title":{"name":"title","type":"string","required":true,"source":"\"Update for HA addon '\" & payload.name & \"'\"","sourceType":"jsonata"},"message":{"name":"message","type":"string","required":true,"source":"\"Newest version of \" & payload.name & \" is \" & payload.version_latest & \", installed version is \" & payload.version","sourceType":"jsonata"},"tag":{"name":"tag","type":"string","required":false,"source":"payload.slug","sourceType":"msg"},"image_url":{"name":"image_url","type":"string","required":false,"source":"\"http://hassio.local/api/hassio/addons/\" & payload.slug & \"/icon\"","sourceType":"jsonata"},"ttl":{"name":"ttl","type":"number","required":false,"source":"0","sourceType":"num"},"url":{"name":"url","type":"string","required":false,"source":"\"http://hassio.local/hassio/addon/\" & payload.slug","sourceType":"jsonata"},"actions":{"name":"actions","type":"json","required":false,"source":"null","sourceType":"json"},"requireInteraction":{"name":"requireInteraction","type":"boolean","required":false,"source":"null","sourceType":"json"},"priority":{"name":"priority","type":"string","required":false,"source":"","sourceType":"str"},"silent":{"name":"silent","type":"boolean","required":false,"source":"false","sourceType":"bool"}},"x":690,"y":560,"wires":[[]]},{"id":"3cb3e090.e9036","type":"component","z":"a74fee2d.ac9068","name":"Filter out old updates","targetComponent":{"id":"3841792.0037586","name":"Find distinct set","api":[{"name":"array_whole","type":"json","required":true},{"name":"array_subset","type":"json","required":true},{"name":"field","type":"string","required":true}]},"paramSources":{"array_whole":{"name":"array_whole","type":"json","required":true,"source":"data.event.new_state.attributes.addons","sourceType":"msg"},"array_subset":{"name":"array_subset","type":"json","required":true,"source":"data.event.old_state.attributes.addons","sourceType":"msg"},"field":{"name":"field","type":"string","required":true,"source":"slug","sourceType":"str"}},"x":380,"y":560,"wires":[["50618624.9ba708"]]},{"id":"fcd445fa.878de8","type":"component","z":"a74fee2d.ac9068","name":"Filter out updates","targetComponent":{"id":"3841792.0037586","name":"Find distinct set","api":[{"name":"array_whole","type":"json","required":true},{"name":"array_subset","type":"json","required":true},{"name":"field","type":"string","required":true}]},"paramSources":{"array_whole":{"name":"array_whole","type":"json","required":true,"source":"data.event.old_state.attributes.addons","sourceType":"msg"},"array_subset":{"name":"array_subset","type":"json","required":true,"source":"data.event.new_state.attributes.addons","sourceType":"msg"},"field":{"name":"field","type":"string","required":true,"source":"slug","sourceType":"str"}},"x":370,"y":600,"wires":[["6d43ea05.acfd84"]]},{"id":"6d43ea05.acfd84","type":"split","z":"a74fee2d.ac9068","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":550,"y":600,"wires":[["20fe10f2.0fb2e8"]]},{"id":"89b8ab9.b8a5458","type":"component","z":"a74fee2d.ac9068","name":"Dismiss notification","targetComponent":{"id":"7b77e12b.8f43a8","name":"Dismiss notification","api":[{"name":"tag","type":"string","required":true}]},"paramSources":{"tag":{"name":"tag","type":"string","required":true,"source":"payload.name","sourceType":"msg"}},"x":710,"y":500,"wires":[[]]},{"id":"20fe10f2.0fb2e8","type":"component","z":"a74fee2d.ac9068","name":"Dismiss notification","targetComponent":{"id":"7b77e12b.8f43a8","name":"Dismiss notification","api":[{"name":"tag","type":"string","required":true}]},"paramSources":{"tag":{"name":"tag","type":"string","required":true,"source":"payload.slug","sourceType":"msg"}},"x":710,"y":600,"wires":[[]]},{"id":"cc03735a.94933","type":"server","z":"","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]

[EDIT] Anyone interested in notifications for new addons, see below

3 Likes

i dont understand the supervisor curl command, it i do it from putty, i receive error below

1 Like

It looks like you copied and pasted the curl command from my sensor and executed it as. The problem is that in the sensor I have to wrap the entire command in single quotes which means I have to escape any single quotes inside the command. If you want to execute the same command on the commandline then you have to unescape the single quotes. Try it like this:

curl http://supervisor/supervisor/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq '{"newest_version":.data.version_latest,"current_version":.data.version,"addons":[.data.addons[] | select(.version != .installed)]}'
1 Like

Can you please put them on a package file? That would be very useful!
Thanks

Updated the original post to include package yaml at the bottom. Good call, I wasn’t really familiar with packages, I’ll remember that for next time. Definitely a lot easier to share that way.

1 Like

ok… so I included the package and then :see_no_evil:?

Just put this in a card

type: entities
entities:
  - alert.addon_update_available
  - alert.ha_update_available
  - automation.check_config_with_update
  - alert.hacs_update_available
  - alert.supervisor_update_available
  - sensor.supervisor_updates
  - binary_sensor.updater_addons
  - binary_sensor.updater_hacs
  - binary_sensor.updater_supervisor
1 Like

Clear! Cool!!!

Throwing it on a card works however the alerts will work best if you update the notification options to be specific to you. Each alert has a notification option here:

notifiers:
  - 'me'

For that to work and send you a notification you’ll need a notify.me service for it to call when it turns on. I can’t really write that part for you though since there are so many different kinds of notification services. The options I have in the data part above are specific to HTML5 notifications which is what I use. But there’s different options and configurations for each platform of notifier (IOS, pushbullet, REST, etc.) Alerts work with any of them you just have to have a notify service for it to call.

Sorry I probably wasn’t clear enough there. If you don’t want notifications at all though and just want to include the info in your UI then you can probably skip all the parts of the package about alerts. You really only need the sensor and the binary sensors for that.

device_class: problem

what do this do ? dont work with that , but when I move it work.

For template binary sensors, you can either list an icon_template (if you want to specifically define which icon to use in which state) or specify a device_class (which then uses a standardized icon in each state for that class of device). problem is one of the device classes listed in the docs:

problem : on means problem detected, off means no problem (OK)

I’m not really sure how that could be breaking your configuration but if it is feel free to remove it. All it does is set the icon, you can use a different device_class, specify an icon_template instead or just leave both out entirely and use the default icon.

ok thanks for info - i’ll remove it.

Hi Mike!
Awesome work.
Just wondering if you have worked out how to check the dns and audio containers as well as supervisor?
Cheers.

(I actually got caught out the other day with dns container not being the latest and it caused all kinds of stuff to fail till I manually updated)

NVM… it’s supervisor/dns/info and supervisor/audio/info

1 Like

Huh, interesting. I hadn’t actually thought about those since I never had to update them before. I made the supervisor version sensor since I had to manually update that one a few times before but I’ve never noticed an update for DNS or Audio.

But yea looks like the same technique works fine, just a different URL like you said. Version and version_latest are the same too so can keep the same jq statement minus the addon part.

Now that you pointed it out I think I’ll add update tracking for DNS, Audio, and CLI. Good to head off that problem before I run into it. Plus if I know when they update then I can read the changelog.

Actually they seem a bit different to supervisor. I started this thread a few days ago and posted my code there:

The problem I had is I have a VM that I play with in Proxmox. I fired it up the other day and the DNS container was only version 1. Then when I updated to the dev version of 0.108, a lot of components shat themselves and I thought 108 was going to have a bunch of breaking changes until I saw the errors in the supervisor log.

Had to make a small update to ha_update_available to add skip_first: true. I misunderstood the alert docs apparently, I thought when you gave the repeat list it waited until the first number for the first notification. It only does that if you have skip_first set to true so now it properly waits 5 minutes before the first notification.

Also for anyone interested, I made a few other updates you’re welcome to. After my conversation with @DavidFW1960 I added alerts for updates to audio, dns and CLI. And I personally was finding the binary_sensor.updater far too slow to react to updates to core being available so I replaced it with my own command_line sensor for that purpose.

Here’s an updated package that includes those changes as well (also will be added to the main post).

Update Notifications package + audio, dns, cli and core
sensor:
  # Sensor to track available updates for supervisor & addons
  - platform: command_line
    name: Supervisor updates
    command: 'curl http://supervisor/supervisor/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq ''{"newest_version":.data.version_latest,"current_version":.data.version,"addons":[.data.addons[] | select(.version != .installed)]}'''
    value_template: "{{ value_json.addons | length }}"
    json_attributes:
    - newest_version
    - current_version
    - addons

  # Sensors to track updates to other core components (audio, dns and CLI)
  - platform: command_line
    name: Updater Audio
    command: 'curl http://supervisor/audio/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq ''{"newest_version":.data.version_latest,"current_version":.data.version}'''
    value_template: "{% if value_json.newest_version != value_json.current_version %}on{% else %}off{% endif %}"
    json_attributes:
    - newest_version
    - current_version
  - platform: command_line
    name: Updater DNS
    command: 'curl http://supervisor/dns/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq ''{"newest_version":.data.version_latest,"current_version":.data.version}'''
    value_template: "{% if value_json.newest_version != value_json.current_version %}on{% else %}off{% endif %}"
    json_attributes:
    - newest_version
    - current_version
  - platform: command_line
    name: Updater CLI
    command: 'curl http://supervisor/cli/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq ''{"newest_version":.data.version_latest,"current_version":.data.version}'''
    value_template: "{% if value_json.newest_version != value_json.current_version %}on{% else %}off{% endif %}"
    json_attributes:
    - newest_version
    - current_version
  # Alternate updater sensor for core since binary_sensor.updater is very slow to recognize updates
  - platform: command_line
    name: Updater Core
    command: 'curl http://supervisor/core/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq ''{"newest_version":.data.version_latest,"current_version":.data.version}'''
    value_template: "{% if value_json.newest_version != value_json.current_version %}on{% else %}off{% endif %}"
    json_attributes:
    - newest_version
    - current_version
  

binary_sensor:
  - platform: template
    sensors:
      # True if there's an update available for supervisor
      updater_supervisor:
        friendly_name: 'Updater - Supervisor'
        device_class: problem
        entity_id:
        - sensor.supervisor_updates
        value_template: "{{ state_attr('sensor.supervisor_updates', 'current_version') != state_attr('sensor.supervisor_updates', 'newest_version') }}"
        availability_template: "{{ (states('sensor.supervisor_updates') | int(-1)) > -1 }}"

      # True if there's updates available for any HACS components
      updater_hacs:
        friendly_name: 'Updater - HACS'
        device_class: problem
        entity_id:
        - sensor.hacs
        value_template: "{{ states('sensor.hacs') | int > 0 }}"

      # True if there's updates available for any addons
      updater_addons:
        friendly_name: 'Updater - Addons'
        device_class: problem
        entity_id:
        - sensor.supervisor_updates
        value_template: "{{ states('sensor.supervisor_updates') | int > 0 }}"

alert:
  # Update is available - un-acknowledgeble, auto-dismiss, me only
  # Wait 5 minutes before first to give core config check time to run
  ha_update_available:
    name: HA has an update
    entity_id: sensor.updater_core
    state: 'on'
    can_acknowledge: false
    repeat: 
    - 5
    - 360
    skip_first: true
    title: 'Update for HA available'
    message: "New version is {{ state_attr('sensor.updater_core', 'newest_version') }}. Currently on {{ state_attr('sensor.updater_core', 'current_version') }}"
    notifiers:
    - 'me'
    data:
      tag: 'ha-update-available'
      url: 'http://hassio.local/hassio/addon/core_check_config'
      ttl: 21600

  # Supervisor update is available - un-acknowledgeable, auto-dismiss, me only
  supervisor_update_available:
    name: Supervisor has an update
    entity_id: binary_sensor.updater_supervisor
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: 'Update for HA Supervisor available'
    message: "New version is {{ state_attr('sensor.supervisor_updates', 'newest_version') }}. Currently on {{ state_attr('sensor.supervisor_updates', 'current_version') }}"
    notifiers:
    - 'me'
    data:
      tag: 'supervisor-update-available'
      url: 'http://hassio.local/hassio/dashboard'
      ttl: 21600

  # Audio update is available - un-acknowledgeable, auto-dismiss, me only
  audio_update_available:
    name: Audio has an update
    entity_id: sensor.updater_audio
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: 'Update for HA Audio available'
    message: "New version is {{ state_attr('sensor.updater_audio', 'newest_version') }}. Currently on {{ state_attr('sensor.updater_audio', 'current_version') }}"
    notifiers:
    - 'me'
    data:
      tag: 'audio_update_available'
      url: 'http://hassio.local/hassio/dashboard'
      ttl: 21600

  # DNS update is available - un-acknowledgeable, auto-dismiss, me only
  dns_update_available:
    name: DNS has an update
    entity_id: sensor.updater_dns
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: 'Update for HA DNS available'
    message: "New version is {{ state_attr('sensor.updater_dns', 'newest_version') }}. Currently on {{ state_attr('sensor.updater_dns', 'current_version') }}"
    notifiers:
    - 'me'
    data:
      target: ''
      tag: 'dns_update_available'
      url: 'http://hassio.local/hassio/dashboard'
      ttl: 21600

  # CLI update is available - un-acknowledgeable, auto-dismiss, me only
  cli_update_available:
    name: CLI has an update
    entity_id: sensor.updater_cli
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: 'Update for HA CLI available'
    message: "New version is {{ state_attr('sensor.updater_cli', 'newest_version') }}. Currently on {{ state_attr('sensor.updater_cli', 'current_version') }}"
    notifiers:
    - 'me'
    data:
      target: ''
      tag: 'cli_update_available'
      url: 'http://hassio.local/hassio/dashboard'
      ttl: 21600

  # HACS repos have updates available - unacknowledgeable, auto-dismiss, me only
  hacs_update_available:
    name: HACS repos have updates
    entity_id: binary_sensor.updater_hacs
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: "Updates available in {{ states('sensor.hacs') }} HACS repo{% if states('sensor.hacs') | int > 1 %}s{% endif %}"
    message: ""
    notifiers:
      - 'me'
    data:
      tag: 'hacs-update-available'
      url: 'http://hassio.local/hacs/installed'
      ttl: 21600

  # Addons have updates available - unacknowledgeable, auto-dismiss, me only
  addon_update_available:
    name: Addons have updates
    entity_id: binary_sensor.updater_addons
    state: 'on'
    can_acknowledge: false
    repeat: 360
    title: "Updates available for {{ states('sensor.supervisor_updates') }} HA addon{% if states('sensor.supervisor_updates') | int > 1 %}s{% endif %}"
    message: ""
    notifiers:
    - 'me'
    data:
      tag: 'addon-update-available'
      url: 'http://hassio.local/hassio/dashboard'
      ttl: 21600

automation:
  - id: '1585256741683'
    alias: Check config with update
    description: Starts the check config addon when an update becomes available
    trigger:
    - entity_id: binary_sensor.updater
      platform: state
      to: 'on'
    condition: []
    action:
    - data:
        addon: core_check_config
      service: hassio.addon_start

Also for anyone curious, yes sensor.updater_cli, sensor.updater_audio, sensor.updater_dns and sensor.updater_core are really binary_sensors not sensors since they only have state on or off. Unfortunately though the command line platform for binary sensors does not support the json_attributes field so if I made those actual binary sensors then I could not capture the newest_version and current_version information used in the notifications. So I just made them sensors for now

3 Likes

First of all thanks for sharing this! :smiley:

Question: should I replace SUPERVISOR_TOKEN with the actual token which I have generated? Or does this value work by itself?

I don’t think you have to but I will say I am running in Docker so I don’t know if it varies in other deployments.

When running in Docker the supervisor token HA uses is made available via an environmental variable called SUPERVISOR_TOKEN. So the $(printenv SUPERVISOR_TOKEN) part is literally going to run the command to print out the value of the environmental variable SUPERVISOR_TOKEN and insert it into the command at that spot. Since the commandline sensors run their command as HA that should work as is.

The easiest way I found to try it out is if you have the portainer add-on you can open the console for the HA docker image and just paste it in to make sure it works. Although if you do that make sure you unescape the single quotes like this:

curl http://supervisor/supervisor/info -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq '{"newest_version":.data.version_latest,"current_version":.data.version,"addons":[.data.addons[] | select(.version != .installed)]}'

But yea obvious and notable caveat here is I don’t know exactly how HA works in a non-docker scenario since I have no way to test that. If you generated your own supervisor token though I assume that would always be viable regardless of how you deployed HA.

1 Like

One other added bonus for anyone interested. I realized that the same technique I used for sending out a notification when an addon updates could also be used to send out a notification when a new addon gets listed.

Obviously knowing about new addons is not as important as keeping your current addons up to date but still it is nice to know when new things are available. HACS does a nice job of this by highlighting components that are new or updated since the last time you’ve been there, the add-on store doesn’t make as easy to figure out what’s new. You just kind of have to scan the list and click on things that seem unfamiliar or that the forum has directed you to.

So I closed this gap. Well half of it :slight_smile:. It will send you a notification whenever an add-on is added to any repo you have listed in the add-on store. It won’t do anything for updates to add-ons you don’t have installed. It probably could but that seemed like too much to me.

Anyway if you want to use it it requires Node-RED and that you have imported my other Node RED stuff above (since it depends on the same components). To use it first add this sensor to HA:

# Sensor to track details on new addons
- platform: command_line
  name: New addons
  command: 'curl http://supervisor/addons -H "Authorization: Bearer $(printenv SUPERVISOR_TOKEN)" | jq --slurpfile slugs found_addon_slugs.txt ''{"addons":[.data.addons[] | select(.slug as $slug | $slugs | index($slug) | not)], "repositories":.data.repositories}'''
  value_template: '{{ value_json.addons | length }}'
  json_attributes:
  - addons
  - repositories
  - addon_slugs

It’s similar to the other supervisor one above but it hits http://supervisor/addons which returns info on all available addons instead of http://supervisor/supervisor/info which only returns info on addons you have installed.

After that you will need this file notifier:

- name: 'Update found addon slugs'
  platform: file
  filename: 'found_addon_slugs.txt'

This will be used to keep track of the addons you’ve already seen, you can see the file is referenced in the sensor above. Technically you can do without this and just store details of all addons in sensor.new_addons and compare old state and new state on change. But if you do that the sensor will be huge so remember to tell recorder to exclude it.

Then after that you can import this config into Node RED:

[{"id":"fd65848.75a1178","type":"trigger-state","z":"a74fee2d.ac9068","name":"New addon","server":"cc03735a.94933","exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"sensor.new_addons","entityidfiltertype":"exact","debugenabled":false,"constraints":[{"id":"h9meihjciqa","targetType":"this_entity","targetValue":"","propertyType":"current_state","propertyValue":"new_state.state","comparatorType":">","comparatorValueDatatype":"prevEntity","comparatorValue":"state"}],"constraintsmustmatch":"all","outputs":2,"customoutputs":[],"outputinitially":false,"state_type":"num","x":170,"y":620,"wires":[["380c1702.666788"],[]]},{"id":"380c1702.666788","type":"component","z":"a74fee2d.ac9068","name":"Filter out seen addons","targetComponent":{"id":"3841792.0037586","name":"Find distinct set","api":[{"name":"array_whole","type":"json","required":true},{"name":"array_subset","type":"json","required":true},{"name":"field","type":"string","required":true}]},"paramSources":{"array_whole":{"name":"array_whole","type":"json","required":true,"source":"data.event.new_state.attributes.addons","sourceType":"msg"},"array_subset":{"name":"array_subset","type":"json","required":true,"source":"data.event.old_state.attributes.addons","sourceType":"msg"},"field":{"name":"field","type":"string","required":true,"source":"slug","sourceType":"str"}},"x":380,"y":620,"wires":[["d22ecf9e.0214a8"]]},{"id":"d22ecf9e.0214a8","type":"split","z":"a74fee2d.ac9068","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":550,"y":620,"wires":[["1af4d2ea.ecb0f5","f2e48257.2e042"]]},{"id":"1af4d2ea.ecb0f5","type":"component","z":"a74fee2d.ac9068","name":"Notify me","targetComponent":{"id":"3a1d9ae6.50d41e","name":"Notify me","api":[{"name":"title","type":"string","required":true},{"name":"message","type":"string","required":true},{"name":"tag","type":"string","required":false},{"name":"image_url","type":"string","required":false},{"name":"ttl","type":"number","required":false},{"name":"url","type":"string","required":false},{"name":"actions","type":"json","required":false},{"name":"requireInteraction","type":"boolean","required":false},{"name":"priority","type":"string","required":false},{"name":"silent","type":"boolean","required":false}]},"paramSources":{"title":{"name":"title","type":"string","required":true,"source":"\"New HA addon - \" & payload.name","sourceType":"jsonata"},"message":{"name":"message","type":"string","required":true,"source":"payload.description & \"\\n(in \" & \t$single(\t   $globalContext(\"homeassistant.homeAssistant.states['sensor.new_addons'].attributes.repositories\"),\t   function($repo) {\t       $repo.slug = $$.payload.repository\t    }\t).name & \")\"","sourceType":"jsonata"},"tag":{"name":"tag","type":"string","required":false,"source":"payload.slug","sourceType":"msg"},"image_url":{"name":"image_url","type":"string","required":false,"source":"payload.icon or payload.logo ? \t(\"http://hassio.local/api/hassio/addons/\" & payload.slug & \"/\" & \t(payload.icon ? \"icon\" : \"logo\")) : \"http://hassio.local/local/home-assistant.png\"","sourceType":"jsonata"},"ttl":{"name":"ttl","type":"number","required":false,"source":"0","sourceType":"num"},"url":{"name":"url","type":"string","required":false,"source":"\"http://hassio.local/hassio/addon/\" & payload.slug","sourceType":"jsonata"},"actions":{"name":"actions","type":"json","required":false,"source":"null","sourceType":"json"},"requireInteraction":{"name":"requireInteraction","type":"boolean","required":false,"source":"null","sourceType":"json"},"priority":{"name":"priority","type":"string","required":false,"source":"","sourceType":"str"},"silent":{"name":"silent","type":"boolean","required":false,"source":"false","sourceType":"bool"},"to_all":{"name":"to_all","type":"boolean","required":false,"source":"true","sourceType":"bool"}},"x":710,"y":620,"wires":[[]]},{"id":"f2e48257.2e042","type":"api-call-service","z":"a74fee2d.ac9068","name":"Add to found slugs list","server":"cc03735a.94933","version":1,"debugenabled":false,"service_domain":"notify","service":"update_found_addon_slugs","entityId":"","data":"{\"message\":\"\\\"{{ payload.slug }}\\\"\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":740,"y":660,"wires":[[]]},{"id":"cc03735a.94933","type":"server","z":"","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]

It looks like this:

And that’s it, enjoy!

1 Like