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:
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.
Huh, all of my templates in the template editor just broke with similar errors… They all worked yesterday, I swear! 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.
After i have played around with it a little bit more yesterday, this is my working code now for the script.
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
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 it should be attributes, not attribute.
I am 100% sure this template works, copied directly from my template editor:
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?
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 -%}
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.
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