Update notifications! Core, HACS, Supervisor and Addons

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

I am running docker too! So it’ll work :slight_smile:

Now this is cool too! Is there an automation you have for this? I dont use nodered.

Or is node red required to run any of this? Planning to remove old sensors i’ve built. And adding this as a package. Amazing!

Nope, Node RED not required for most of it. That’s why I separated the top post into two. The first post is all things you can do (almost) entirely within HA. The only addon dependency the packages in the first post have is on the Check Home Assistant configuration addon. There’s an automation in there that automatically starts that addon when there’s an update to core available. The second post is additions for people that use Node RED.

Without Node RED you’ll still get a notification any time there’s an update to core, supervisor, any add-on you have installed or any HACS component you have installed. You’ll also get a notification any time there’s an update to DNS, CLI or Audio if you use the second package instead (added that later).

The things I added that do depend on Node RED are whenever a HACS component or add-on you have installed updates instead of getting a generic message that says “you have this many HACS/Addon updates available” the notification says specifically which one updated. And now I added the “new addon” notification that depends on Node RED.

But it definitely doesn’t require Node RED, you can still get notifications for updates without it!

@CentralCommand Thanks for this awesome post!!! I’ve integrated this into my dashboard so thank you very much for sharing :slight_smile:

2 Likes

Hi, want to try using your sensors…

But have a quick question… the ‘“SUPERVISOR TOKEN”’… This will be what I’ve entered? (Bearer fdDGSg…) OR, what I get in result after that which is way longer…?

Thanks a lot :slight_smile:

If you scroll up a few posts here’s my description on how the SUPERVISOR_TOKEN bit works:

So basically if you’re running in Docker you should just be able to use that sensor as is. If you’re not running in Docker I’m not sure if it will work as is but it can’t hurt to try it anyway, worse that happens is you’ll get an unauthenticated error in the log. If you do have to or want to generate your own token for this sensor then you can just swap it in and remove the $(printenv SUPERVISOR_TOKEN) part

Where you put this?

I am trying to grt notification on Telegram and not sure in which file I shall store code

# 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

Those are alerts, see here for more info: https://www.home-assistant.io/integrations/alert/

There’s no default file to put alerts in like with automations, scripts, scenes, etc. They can either go into your configuration.yaml under alert: like it shows in that help link or you can use one of the options in splitting up the configuration to move them to a separate file. Using a package like I linked in my top post is one such option for splitting up the configuration.

I’m not super familiar with telegram but as long as you can make a notifier with platform: telegram (which it looks like you can) it should work. You can either make a telegram notifier called me or adjust this section above in all the alerts to the name you choose:

notifiers:
  - 'me'

I don’t know what kinds of options telegram notifiers accept for data but you’ll also probably need some adjustment there for each alert as that is specific to each type of notifier.

Will deal with it in following days.

Thank you for the prompt reply

Useful code, - thanks for sharing!

Any chance you know how to code a “new version” sensor for the System HassOS X.YZ…?

Cheers.

Haha yea I thought about that one too. So there is a /supervisor/host/info API but this is what I get back from it:

{
  "result": "ok",
  "data": {
    "chassis": "",
    "cpe": "",
    "features": [
      "reboot",
      "shutdown",
      "services",
      "hostname"
    ],
    "hostname": "hassio",
    "operating_system": "Raspbian GNU/Linux 10 (buster)",
    "deployment": "",
    "kernel": "4.19.66-v7l+"
  }
}

The problem here of course is that it doesn’t include anything about the version so there’s no way to tell from this API call if I need an update. This doesn’t make it impossible it just means I think I’d have to have something running on the host basically telling HA when its host has an update.

This was enough of a roadblock that it deterred me for now but I will probably revisit it at some point. Something like that would clearly be dependent on the host OS though so it would need to be modified per host type that HA can be deployed on.

That being said, you might actually want to try the API call for your own system first since I notice you have more info under Host System on yours then I do and it actually does list some version info (HassOS 3.13). From the HA CLI when you execute ha host info what do you see? Does the response include info on current version and newest version for you? If so that’s all you need to make a sensor like the ones above.

[EDIT] Wow, ok, you have identified a flaw in my plan my friend. I realized after you said this that I didn’t actually know how to update raspbian since I haven’t actually had it that long. Appears the answer is run apt update and now that I did it appears I have 280 upgradeable packages LOL

However I think this does make it scriptable as long as you can ssh into the host from HA so I’m going to dig into this. I think I can figure this out

The correct command would be:
sudo apt update && sudo apt upgrade -y

Update reads the package list and updates the ressources. Upgrade actually does the real process of upgrading software. The -y confirms all changes upfront (no interaction).

But, you have to be careful, this has some pitfalls in general. What you wouldn’t do with this, is a dist-upgrade (upgrading to a higher version of the OS). In theory you could do that as well, but I wouldn’t recommend that. Then it would be:
sudo apt update && sudo apt upgrade -y && sudo dist-upgrade -y

Oh, and there are a few more package managers out there, so apt is on some systems the way to go, others would need apt-get or aptitude.