Script to Update all updateable devices (shelly/wled) at once

Hi all,

was very amazed, that HA now supports updating Shellies directly. What i’d like to do now is to create a script (to e.g. use in an automation) that updates all shellies (and WLED devices) at once. What i’m trying to do is create a data template, look for all button-entities and filter those whose devices class is “update”. These devices entity-id should be then put one after into a service call.

What i have so far:

alias: ShellyUpdate-Testscript
sequence:
  - service: button.press
    data_template:
      entity_id: >
        {%- for shellyupdate in states.button -%}  
          {%- if state_attr(shellyupdate.entity_id,'device_class') == 'update'  -%} 
            - {{ shellyupdate.entity_id +"\n"}} 
          {%- endif -%} 
        {%- endfor -%}
mode: single

of course, i did the coding of the loop in the developer tools, there it works as expected:

sadly, the script gives an error:

… not a valid value for dictionary value @ data[‘entity_id’]

What tiny little detail am i missing?

Thanks for your support! :slight_smile:

I don’t have any buttons, so I can’t test it fully, but I believe the tiny detail is that your YAML should look a little different. Specifically, data_template should be replaced with target.

Also, a couple notes on the template: entity_id accepts any form of a list object and, personally, I prefer the existing filters over Jinja logic.

So, I successfully ran this:

service: light.turn_on
data:
  brightness_pct: 100
target:
  entity_id: "{{ states.light | selectattr('entity_id', 'search', 'office') | map(attribute='entity_id') | list }}"

And, following suit, yours would look something like this:

service: button.press
target:
  entity_id: >
    {{
      states.button
      | selectattr('attribute.device_class', 'eq', 'update')
      | map(attribute='entity_id')
      | list
    }}

Hey! Thanks for your input. Now I get this error:

I‘ll play around with it tomorrow :slight_smile:

Maybe it is because device_class is not an attribute but a state.

Keep you updated

Thanks

Huh, all of my templates in the template editor just broke with similar errors… They all worked yesterday, I swear! :laughing: I only have one template in my editor, and I know it was working yesterday, and today it is giving me TypeError: unhashable type: 'TemplateState'.

I’m at a bit of a loss. I can’t find any info related to this and all I did in that time was update the HA OS. I didn’t see any changes in the release notes related to the template editor, and I don’t think the OS would affect that anyway. Hopefully someone comes along who knows what happened.

Does this approach help?

After i have played around with it a little bit more yesterday, this is my working code now for the script. :slight_smile:

service: button.press
target:
  entity_id: >
    {% for state in states.button %} {% if 'update' in state.entity_id %}  {{
    state.entity_id }} {% if not loop.last %}, {% endif %} {% endif %} {% endfor
    %}

@tom_l that also looks interesting, although it requires a lovelace plugin. but: a good starting point to now put this script into some automation, do auto-updates every week or show a button (which triggers al updates) once an update is available :slight_smile:

2 Likes

Doesn’t really matter now, but I just got around to “fixing” my template editor and could figure out why you saw that error: a simple typo :slight_smile: it should be attributes, not attribute.

I am 100% sure this template works, copied directly from my template editor:

{{ states.sensor | selectattr('attributes.device_class', 'eq', 'battery') | map(attribute='entity_id') | list }}

You should be able to specify any entity type or device class you want, I just don’t have any with type button or class update.

Now that both entities; firmware_update and OTA_update are deprecated and they’ve been replaced with update.entity_id_firmware_update (which is one of the hidden entities in the top pane now shown with a Shelly icon), is there an update to the scrip above that would still work to update all?

You can set up an auto-update…

If you don’t want to update other items, just select the exceptions.

https://community.home-assistant.io/t/scheduled-auto-update-for-home-assistant/459281/20

Thanks! didn’t know that existed. Will take a look.

1 Like

One suggestion…

Suggestion I made FOR UI to allow for updating ONLY core-Home Assistant This would seem to be critical if you are going to use this updater to update Shelly’s but NOT have it interfere with your docker container.

Thanks!
–Tom

Is there a way to filter only for shelly devices? When I run your script i get an error that “fritz_box_update_…” is not a valid id and i tried a “and not “fritz” in state.entity_id” filter but that doesnt work for me.

I played with the service call and if you don’t want to autoupdate but you would decide when you would install the updates for all your shelly devices it worked for me:

service: update.install
target:
  entity_id: >
    {%- for shellyupdate in states.update -%}
      {%- if state_attr(shellyupdate.entity_id, 'device_class') == 'firmware' -%}
        {%- set release_url = state_attr(shellyupdate.entity_id, 'release_url') -%}
        {%- if release_url is not none and 'shelly' in release_url and is_state(shellyupdate.entity_id, 'on') -%}
          {{ "\n" + "    - " + shellyupdate.entity_id }} 
        {%- endif -%}
      {%- endif -%}
    {%- endfor -%}

It could be even better:

service: update.install
target:
  entity_id: >
    {%- set entities = states.update
      | selectattr('attributes.device_class', 'eq', 'firmware')
      | selectattr('attributes.release_url', 'search', 'shelly')
      | selectattr('state', 'eq', 'on')
      | map(attribute='entity_id')
      | list -%}
    {{ entities | join(', ') }}

In 2025.5.3 I’m using this format to update all shelly devices once a new version come:

Developer tools > Actions > Action > Update: Install update

target:
  entity_id: |
    {%- set entities = states.update
      | selectattr('attributes.device_class', 'eq', 'firmware')
      | selectattr('attributes.release_url', 'search', 'shelly')
      | selectattr('state', 'eq', 'on')
      | map(attribute='entity_id')
      | list -%}
    {{ entities | join(', ') }}
action: update.install
1 Like

I had an issue with 'homeassistant.util.read_only_dict.ReadOnlyDict object' has no attribute 'release_url', so I had to modify your script as follows:

{%- set entities = states.update
      | selectattr('attributes.device_class', 'eq', 'firmware')
      | rejectattr('attributes.release_url', 'undefined')
      | selectattr('attributes.release_url', 'search', 'shelly')
      | selectattr('state', 'eq', 'on')
      | map(attribute='entity_id')
      | list -%}

How would I craft the same thing but for pressing the “reboot” button? I tried a few things but never got it to work.

Just want to add my working solution in 2025 for upgrading all Shelly products in my home realm which the Shelly integration identifies as upgradeable.

Create script and edit in .yaml. Copy/paste following:

sequence:
  - action: update.install
    target:
      entity_id: >
        {%- set find_integration = 'shelly' %}  
        {%- set entities = states | map(attribute='entity_id') | list %} 
        {%- set ns = namespace(entities = []) %} 
        {%- for entity_id in entities %}
          {%- set ids = device_attr(entity_id, 'identifiers') %}
            {%- if ids %} 
            {%- set ids = ids | list | first %}
              {%- if ids and ids | length == 2 and ids[0] == find_integration and 'update' in entity_id%}
              {%- set ns.entities = ns.entities + [ entity_id ] %}
            {%- endif %}
          {%- endif %}
        {%- endfor %} 
        {{ ns.entities }}
    data: {}
mode: single
icon: mdi:shield
alias: Update_all_Shelly
description: "Update Firmware of all Shelly"

In case a device has no FW update available, then an error occurs (actually it´s a Warning, since the script continues anyway). In my case the output trace is as follows:

Executed: March 26, 2025 at 11:01:25 PM
Error: No update available for update.eg_kuche_rechts_r_firmware
Result:
params:
  domain: update
  service: install
  service_data: {}
  target:
    entity_id:
      - update.ke_treppe_l_firmware
 ---------[... I cutted here the list of devices, since too long ...] -----------
      - update.og_flur_l_firmware
running_script: false

You need to run manually the script. If you wish, you could add it in your favorite dashboard with a button. For me it’s an overkill and I’m happy to run manually if I need it to.

Probably one could implement much simpler ways… However it works on my HA 2025.3.4.

Note: I merged the infos in this post and the ones here: https://community.home-assistant.io/t/how-to-enumerate-entities-belonging-to-an-integration/343748/6

Have fun!

that’s a very old template. This is how you do it now:

{{ integration_entities('shelly') | select('search', '^update.') | list }}
2 Likes

Thank you! The lean script would be then:

sequence:
  - action: update.install
    target:
      entity_id: >
        {{ integration_entities('shelly') | select('search', '^update.') | list
        }}
mode: single
icon: mdi:shield
alias: Update_all_Shelly
description: Update Firmware of all Shelly
2 Likes

Thanks @makejoint, This really helped me. Since I have had couple of devices that did not need any update, I tweaked the script a bit to simply ignore errors (rather than do version verification). here’s mine:

sequence:
  - action: update.install
    continue_on_error: true
    target:
      entity_id: >
        {{ integration_entities('shelly') | select('search', '^update.') | list }}
    data: {}
mode: single
icon: mdi:shield
alias: Update all Shelly
description: Update Firmware of all Shelly