Add service ota_update to shelly integration#48448
Add service ota_update to shelly integration#48448mib1185 wants to merge 8 commits intohome-assistant:devfrom
Conversation
| resp = await rest.device.http_request("get", "ota", {"update": "true"}) | ||
| _LOGGER.debug("OTA update service - response: %s", resp) | ||
|
|
||
| hass.services.async_register(DOMAIN, SERVICE_OTA_UPDATE, async_service_ota_update) |
There was a problem hiding this comment.
This should be implemented as an entity service:
https://developers.home-assistant.io/docs/dev_101_services#entity-services
There was a problem hiding this comment.
Hi @frenck
sorry but I'm not sure if I get it correct 😕
The service I want to implement is not related to a specific entity/sensor or platform, but to a device - therefore I added this service as integration service.
To be honest I was also wondering why I have to extract the device_ids from area_id (and filter them to get only shelly devices) to get afterwards the (config_)entry_id from the devices and in addition have to care about that no duplicated device_ids were processed 🤔
Nevertheless it works as expected - yesterday I have already updated 5 Shelly devices at the same time with one service call 😎
Surely it is more realistic that I'm total wrong and have missed something essential 🙈
I would be very grateful for hints on this, also about extended examples.
There was a problem hiding this comment.
When implemented as an entity service, it will support a target, in that case Home Assistant will resolve/handle devices, areas and entity ID references for you, and call the matching entity services (no matter what the user has put in).
The example is in the link above. If you search the codebase for async_register_entity_service, you'll find dozens of examples.
bdraco
left a comment
There was a problem hiding this comment.
Please use entity services as they can target an area, device, or entity_id when using target: in services.yaml
|
Is this a service that we want? Or is this something that should be part of device actions (which we don't currently have)? |
|
@bdraco to be honest until now I do not get it in my mind how to implement/use an entity service for a device (not for a specific entity/sensor/platform of this device). I would be very grateful for hints on this. I have also already searched the codebase for |
@balloob mhhh ... device actions sounds like it is what I'm looking for 🤔 |
mhhh ... as I understand from the docs the base for an device action is at least always a service ... so the main question remains - how to implement an entity service for a device 😕 |
In the service call we get the Here are some examples: |
|
Sorry @bdraco but your reply did not help me, to get it 🙈 async def async_setup(hass: HomeAssistant, config: dict):
component = EntityComponent(_LOGGER, DOMAIN, hass)
await component.async_setup(config)
component.async_register_entity_service(...)But the Shelly integration does not go this way - so for me the entry-point to implement an entity service seems missing. Maybe it is an language related issue on my end (i do net get it, because i misunderstood something/the docs) or simply i miss something essential from the mechanic (i do net get it, because lag of knowledge about some related thing) 🤔 😕 |
|
I don't believe an entity service is correct in this case since we're not targeting a specific platform. It's a config entry specific service. Paulus has a point: Do users want to automate OTA updates? If yes, a service is relevant. If no, maybe this should just be a websocket command and a frontend card? |
This comment has been minimized.
This comment has been minimized.
|
Hi @MartinHjelmare |
| for device in devices: | ||
| entry_id = next(iter(device.config_entries)) | ||
| entry_data = hass.data[DOMAIN][DATA_CONFIG_ENTRY][entry_id] | ||
| rest: ShellyDeviceRestWrapper = entry_data[REST] |
There was a problem hiding this comment.
Note that ShellyDeviceRestWrapper is not created if the device is a sleeping device, the service should not rely on this wrapper, but on the main wrapper - ShellyDeviceWrapper
| rest: ShellyDeviceRestWrapper = entry_data[REST] | |
| device_wrapper: ShellyDeviceWrapper = entry_data[COAP] |
see:
In addition we should not try to trigger update for a sleeping devices, as I see it we have two options:
- (preferred option) For a sleeping device, store a flag that we need to trigger an update and trigger an update upon CoAP event from the device, can be done here:
- For a sleeping device log a message that device is skipped since it is a sleeping device
There was a problem hiding this comment.
- the method is now moved into
ShellyDeviceRestWrapperasasync_trigger_ota_update() async_trigger_ota_update()uses the flagself._ota_update_pendingfor scheduling an ota update for sleeping devices
| entry_id = next(iter(device.config_entries)) | ||
| entry_data = hass.data[DOMAIN][DATA_CONFIG_ENTRY][entry_id] | ||
| rest: ShellyDeviceRestWrapper = entry_data[REST] | ||
| update_data = rest.device.status["update"] |
There was a problem hiding this comment.
If REST sensors are not enabled, the status will be the status of the first init of the device which may not reflect it's current state, even a REST sensor is enabled, the update period for it is 60 seconds, so the status may not reflect the correct device state, since it is used to decide if device needs an update, it would be better to first pull the device latest status:
Example can be found here (need to wrap with timeout and catch the error):
await self.device.update_status()There was a problem hiding this comment.
async_trigger_ota_update() use now async_refresh() from DataUpdateCoordinator to update status data
| update_data["old_version"], | ||
| update_data["new_version"], | ||
| ) | ||
| resp = await rest.device.http_request("get", "ota", {"update": "true"}) |
There was a problem hiding this comment.
Also here, need to wrap with timeout and catch the error.
Note: We intentionally don't do any http request directly from HA, but add a method in aioshelly library and call it from HA, might be a better option to do the same here
There was a problem hiding this comment.
yeah for sure ... I've created an PR home-assistant-libs/aioshelly#90 to add a new device method ... this is already used in async_trigger_ota_update() wraped with timeout in try-except-block
| @@ -0,0 +1,10 @@ | |||
| # shelly service descriptions. | |||
|
|
|||
| ota_update: | |||
There was a problem hiding this comment.
I think we should add a flag named beta which will allow updating to beta firmware, since the OTA command support triggering update to beta FW.
https://shelly-api-docs.shelly.cloud/#ota
Might also need to consider if we allow specifying a URL for a direct update file in the service call
There was a problem hiding this comment.
url and beta parameter were added
In addition there is now a force parameter which allows to downgrade from beta-version to release-version and also to reinstall current version
|
wait for upstream PR home-assistant-libs/aioshelly#90 to be merged and released |
d622ac6 to
3d8a159
Compare
3d8a159 to
901d494
Compare
|
Hi @mib1185, |
495f460 to
2a3bdc5
Compare
|
There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days. |
|
still waiting for upstream ... |
|
accidental deleted the branch |
|
Close this PR in respect to ongoing architecture discussion home-assistant/architecture#566 |
Proposed change
This PR adds a new service
ota_updateto the shelly integration, which is intended to trigger OTA updates to a single or multiple devices at the same time.Type of change
Additional information
Checklist
black --fast homeassistant tests)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest.requirements_all.txt.Updated by running
python3 -m script.gen_requirements_all..coveragerc.The integration reached or maintains the following Integration Quality Scale:
To help with the load of incoming pull requests: