1
0
mirror of https://github.com/natekspencer/hacs-oasis_mini.git synced 2025-12-06 18:44:14 -05:00

Formatting

This commit is contained in:
Nathan Spencer
2025-11-24 04:37:10 +00:00
parent 14223bd1c9
commit 04be6626a7
11 changed files with 61 additions and 62 deletions

View File

@@ -1,7 +1,7 @@
repos: repos:
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version. # Ruff version.
rev: v0.9.10 rev: v0.14.6
hooks: hooks:
# Run the linter. # Run the linter.
- id: ruff - id: ruff

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2024 Nathan Spencer Copyright (c) Nathan Spencer
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -24,9 +24,9 @@ class OasisDeviceEntity(CoordinatorEntity[OasisDeviceCoordinator]):
) -> None: ) -> None:
""" """
Initialize an entity representing an Oasis device. Initialize an entity representing an Oasis device.
Sets the entity's unique_id from the device serial number and the provided description key, stores the given device on the entity, and constructs DeviceInfo containing identifiers, name, manufacturer, model, software version, and a network MAC connection if the device exposes a MAC address. Sets the entity's unique_id from the device serial number and the provided description key, stores the given device on the entity, and constructs DeviceInfo containing identifiers, name, manufacturer, model, software version, and a network MAC connection if the device exposes a MAC address.
Parameters: Parameters:
coordinator: The coordinator responsible for updating the device state. coordinator: The coordinator responsible for updating the device state.
device: OasisDevice instance providing metadata and identifiers (serial_number, mac_address, name, manufacturer, model, software_version). device: OasisDevice instance providing metadata and identifiers (serial_number, mac_address, name, manufacturer, model, software_version).
@@ -51,4 +51,4 @@ class OasisDeviceEntity(CoordinatorEntity[OasisDeviceCoordinator]):
model=device.model, model=device.model,
serial_number=serial_number, serial_number=serial_number,
sw_version=device.software_version, sw_version=device.software_version,
) )

View File

@@ -21,11 +21,11 @@ _LOGGER = logging.getLogger(__name__)
def create_client(hass: HomeAssistant, data: dict[str, Any]) -> OasisCloudClient: def create_client(hass: HomeAssistant, data: dict[str, Any]) -> OasisCloudClient:
""" """
Create an Oasis cloud client configured with the Home Assistant HTTP session and access token. Create an Oasis cloud client configured with the Home Assistant HTTP session and access token.
Parameters: Parameters:
hass: Home Assistant instance used to obtain the shared HTTP client session. hass: Home Assistant instance used to obtain the shared HTTP client session.
data: Configuration mapping; the function reads the `CONF_ACCESS_TOKEN` key for the cloud access token. data: Configuration mapping; the function reads the `CONF_ACCESS_TOKEN` key for the cloud access token.
Returns: Returns:
An `OasisCloudClient` initialized with the Home Assistant HTTP session and the configured access token. An `OasisCloudClient` initialized with the Home Assistant HTTP session and the configured access token.
""" """
@@ -36,13 +36,13 @@ def create_client(hass: HomeAssistant, data: dict[str, Any]) -> OasisCloudClient
async def add_and_play_track(device: OasisDevice, track: int) -> None: async def add_and_play_track(device: OasisDevice, track: int) -> None:
""" """
Ensure a track is present in the device playlist, position it as the next item, select it, and start playback if necessary. Ensure a track is present in the device playlist, position it as the next item, select it, and start playback if necessary.
Adds the specified track to the device playlist if missing, waits up to 10 seconds for the track to appear, moves it to be the next item after the current playlist index if needed, selects that track, and starts playback when the device is not already playing. Adds the specified track to the device playlist if missing, waits up to 10 seconds for the track to appear, moves it to be the next item after the current playlist index if needed, selects that track, and starts playback when the device is not already playing.
Parameters: Parameters:
device (OasisDevice): The target Oasis device. device (OasisDevice): The target Oasis device.
track (int): The track id to add and play. track (int): The track id to add and play.
Raises: Raises:
async_timeout.TimeoutError: If the operation does not complete within 10 seconds. async_timeout.TimeoutError: If the operation does not complete within 10 seconds.
""" """
@@ -68,10 +68,10 @@ async def add_and_play_track(device: OasisDevice, track: int) -> None:
def get_track_id(track: str) -> int | None: def get_track_id(track: str) -> int | None:
""" """
Convert a track identifier or title to its integer track id. Convert a track identifier or title to its integer track id.
Parameters: Parameters:
track: A track reference, either a numeric id as a string or a track title. track: A track reference, either a numeric id as a string or a track title.
Returns: Returns:
The integer track id if the input is a valid id or matches a known title, `None` if the input is invalid. The integer track id if the input is a valid id or matches a known title, `None` if the input is invalid.
""" """
@@ -85,4 +85,4 @@ def get_track_id(track: str) -> int | None:
return int(track) return int(track)
except ValueError: except ValueError:
_LOGGER.warning("Invalid track: %s", track) _LOGGER.warning("Invalid track: %s", track)
return None return None

View File

@@ -44,4 +44,4 @@
} }
} }
} }
} }

View File

@@ -39,10 +39,10 @@ async def async_setup_entry(
def make_entities(new_devices: list[OasisDevice]): def make_entities(new_devices: list[OasisDevice]):
""" """
Create OasisDeviceLightEntity instances for each provided Oasis device. Create OasisDeviceLightEntity instances for each provided Oasis device.
Parameters: Parameters:
new_devices (list[OasisDevice]): Devices to wrap as light entities. new_devices (list[OasisDevice]): Devices to wrap as light entities.
Returns: Returns:
list[OasisDeviceLightEntity]: A list of light entity instances corresponding to the input devices. list[OasisDeviceLightEntity]: A list of light entity instances corresponding to the input devices.
""" """
@@ -65,8 +65,8 @@ class OasisDeviceLightEntity(OasisDeviceEntity, LightEntity):
@property @property
def brightness(self) -> int: def brightness(self) -> int:
""" """
Get the light's brightness on a 0255 scale. Get the light's brightness on a 0-255 scale.
Returns: Returns:
int: Brightness value between 0 and 255. int: Brightness value between 0 and 255.
""" """
@@ -120,19 +120,19 @@ class OasisDeviceLightEntity(OasisDeviceEntity, LightEntity):
async def async_turn_on(self, **kwargs: Any) -> None: async def async_turn_on(self, **kwargs: Any) -> None:
""" """
Turn the light on and set its LED state. Turn the light on and set its LED state.
Processes optional keyword arguments to compute the device-specific LED parameters, then updates the device's LEDs with the resulting brightness, color, and effect. Processes optional keyword arguments to compute the device-specific LED parameters, then updates the device's LEDs with the resulting brightness, color, and effect.
Parameters: Parameters:
kwargs: Optional control parameters recognized by the method: kwargs: Optional control parameters recognized by the method:
ATTR_BRIGHTNESS (int): Brightness in the 0255 Home Assistant scale. When provided, ATTR_BRIGHTNESS (int): Brightness in the 0-255 Home Assistant scale. When provided,
it is converted and rounded up to the device's brightness scale (1..device.brightness_max). it is converted and rounded up to the device's brightness scale (1..device.brightness_max).
When omitted, uses self.device.brightness or self.device.brightness_on. When omitted, uses self.device.brightness or self.device.brightness_on.
ATTR_RGB_COLOR (tuple[int, int, int]): RGB tuple (R, G, B). When provided, it is ATTR_RGB_COLOR (tuple[int, int, int]): RGB tuple (R, G, B). When provided, it is
converted to a hex color string prefixed with '#'. converted to a hex color string prefixed with '#'.
ATTR_EFFECT (str): Human-readable effect name. When provided, it is mapped to the ATTR_EFFECT (str): Human-readable effect name. When provided, it is mapped to the
device's internal effect key; if no mapping exists, `None` is used. device's internal effect key; if no mapping exists, `None` is used.
Side effects: Side effects:
Updates the underlying device LED state with the computed `brightness`, `color`, and `led_effect`. Updates the underlying device LED state with the computed `brightness`, `color`, and `led_effect`.
""" """
@@ -152,4 +152,4 @@ class OasisDeviceLightEntity(OasisDeviceEntity, LightEntity):
await self.device.async_set_led( await self.device.async_set_led(
brightness=brightness, color=color, led_effect=led_effect brightness=brightness, color=color, led_effect=led_effect
) )

View File

@@ -35,10 +35,10 @@ async def async_setup_entry(
def make_entities(new_devices: list[OasisDevice]): def make_entities(new_devices: list[OasisDevice]):
""" """
Create media player entities for the given Oasis devices. Create media player entities for the given Oasis devices.
Parameters: Parameters:
new_devices (list[OasisDevice]): Devices to wrap as media player entities. new_devices (list[OasisDevice]): Devices to wrap as media player entities.
Returns: Returns:
list[OasisDeviceMediaPlayerEntity]: Media player entities corresponding to each device. list[OasisDeviceMediaPlayerEntity]: Media player entities corresponding to each device.
""" """
@@ -85,7 +85,7 @@ class OasisDeviceMediaPlayerEntity(OasisDeviceEntity, MediaPlayerEntity):
def media_image_url(self) -> str | None: def media_image_url(self) -> str | None:
""" """
URL of the image representing the currently playing media. URL of the image representing the currently playing media.
Returns: Returns:
The image URL as a string, or `None` if no image is available. The image URL as a string, or `None` if no image is available.
""" """
@@ -95,7 +95,7 @@ class OasisDeviceMediaPlayerEntity(OasisDeviceEntity, MediaPlayerEntity):
def media_position(self) -> int: def media_position(self) -> int:
""" """
Playback position of the current media in seconds. Playback position of the current media in seconds.
Returns: Returns:
int: Position in seconds of the currently playing media. int: Position in seconds of the currently playing media.
""" """
@@ -110,7 +110,7 @@ class OasisDeviceMediaPlayerEntity(OasisDeviceEntity, MediaPlayerEntity):
def media_title(self) -> str | None: def media_title(self) -> str | None:
""" """
Provide the title of the currently playing track. Provide the title of the currently playing track.
Returns: Returns:
str | None: The track title, or None if no title is available. str | None: The track title, or None if no title is available.
""" """
@@ -120,7 +120,7 @@ class OasisDeviceMediaPlayerEntity(OasisDeviceEntity, MediaPlayerEntity):
def repeat(self) -> RepeatMode: def repeat(self) -> RepeatMode:
""" """
Get the current repeat mode for the device. Get the current repeat mode for the device.
Returns: Returns:
`RepeatMode.ALL` if the device is configured to repeat the playlist, `RepeatMode.OFF` otherwise. `RepeatMode.ALL` if the device is configured to repeat the playlist, `RepeatMode.OFF` otherwise.
""" """
@@ -156,7 +156,7 @@ class OasisDeviceMediaPlayerEntity(OasisDeviceEntity, MediaPlayerEntity):
async def async_media_pause(self) -> None: async def async_media_pause(self) -> None:
""" """
Pause playback on the device. Pause playback on the device.
Raises: Raises:
ServiceValidationError: If the device is busy and cannot accept commands. ServiceValidationError: If the device is busy and cannot accept commands.
""" """
@@ -166,7 +166,7 @@ class OasisDeviceMediaPlayerEntity(OasisDeviceEntity, MediaPlayerEntity):
async def async_media_play(self) -> None: async def async_media_play(self) -> None:
""" """
Start playback on the device. Start playback on the device.
Raises: Raises:
ServiceValidationError: If the device is currently busy. ServiceValidationError: If the device is currently busy.
""" """
@@ -176,7 +176,7 @@ class OasisDeviceMediaPlayerEntity(OasisDeviceEntity, MediaPlayerEntity):
async def async_media_stop(self) -> None: async def async_media_stop(self) -> None:
""" """
Stop playback on the Oasis device. Stop playback on the Oasis device.
Raises: Raises:
ServiceValidationError: If the device is currently busy. ServiceValidationError: If the device is currently busy.
""" """
@@ -186,12 +186,12 @@ class OasisDeviceMediaPlayerEntity(OasisDeviceEntity, MediaPlayerEntity):
async def async_set_repeat(self, repeat: RepeatMode) -> None: async def async_set_repeat(self, repeat: RepeatMode) -> None:
""" """
Set the device playlist repeat behavior. Set the device playlist repeat behavior.
Enables or disables looping of the playlist according to the provided RepeatMode: Enables or disables looping of the playlist according to the provided RepeatMode:
- RepeatMode.OFF disables playlist repeat. - RepeatMode.OFF disables playlist repeat.
- RepeatMode.ALL enables playlist repeat for the entire playlist. - RepeatMode.ALL enables playlist repeat for the entire playlist.
- RepeatMode.ONE enables single-track repeat, except when the device is currently repeating the entire playlist; in that case the playlist repeat is disabled to preserve single-track semantics. - RepeatMode.ONE enables single-track repeat, except when the device is currently repeating the entire playlist; in that case the playlist repeat is disabled to preserve single-track semantics.
Parameters: Parameters:
repeat (RepeatMode): The desired repeat mode to apply to the device playlist. repeat (RepeatMode): The desired repeat mode to apply to the device playlist.
""" """
@@ -203,7 +203,7 @@ class OasisDeviceMediaPlayerEntity(OasisDeviceEntity, MediaPlayerEntity):
async def async_media_previous_track(self) -> None: async def async_media_previous_track(self) -> None:
""" """
Move playback to the previous track in the device's playlist, wrapping to the last track when currently at the first. Move playback to the previous track in the device's playlist, wrapping to the last track when currently at the first.
Raises: Raises:
ServiceValidationError: If the device is busy. ServiceValidationError: If the device is busy.
""" """
@@ -215,7 +215,7 @@ class OasisDeviceMediaPlayerEntity(OasisDeviceEntity, MediaPlayerEntity):
async def async_media_next_track(self) -> None: async def async_media_next_track(self) -> None:
""" """
Advance the device to the next track in its playlist, wrapping to the first track when at the end. Advance the device to the next track in its playlist, wrapping to the first track when at the end.
Raises: Raises:
ServiceValidationError: if the device is busy. ServiceValidationError: if the device is busy.
""" """
@@ -233,14 +233,14 @@ class OasisDeviceMediaPlayerEntity(OasisDeviceEntity, MediaPlayerEntity):
) -> None: ) -> None:
""" """
Play or enqueue one or more Oasis tracks on the device. Play or enqueue one or more Oasis tracks on the device.
Validates the media type and parses one or more track identifiers from `media_id`, then updates the device playlist according to `enqueue`. Depending on the enqueue mode the method can replace the playlist, append tracks, move appended tracks to the next play position, and optionally start playback. Validates the media type and parses one or more track identifiers from `media_id`, then updates the device playlist according to `enqueue`. Depending on the enqueue mode the method can replace the playlist, append tracks, move appended tracks to the next play position, and optionally start playback.
Parameters: Parameters:
media_type (MediaType | str): The media type being requested. media_type (MediaType | str): The media type being requested.
media_id (str): A comma-separated string of track identifiers. media_id (str): A comma-separated string of track identifiers.
enqueue (MediaPlayerEnqueue | None): How to insert the tracks into the playlist; if omitted defaults to NEXT. enqueue (MediaPlayerEnqueue | None): How to insert the tracks into the playlist; if omitted defaults to NEXT.
Raises: Raises:
ServiceValidationError: If the device is busy, if `media_type` is a playlist (playlists are unsupported), or if `media_id` does not contain any valid track identifiers. ServiceValidationError: If the device is busy, if `media_type` is a playlist (playlists are unsupported), or if `media_id` does not contain any valid track identifiers.
""" """
@@ -287,9 +287,9 @@ class OasisDeviceMediaPlayerEntity(OasisDeviceEntity, MediaPlayerEntity):
async def async_clear_playlist(self) -> None: async def async_clear_playlist(self) -> None:
""" """
Clear the device's playlist. Clear the device's playlist.
Raises: Raises:
ServiceValidationError: If the device is busy and cannot accept commands. ServiceValidationError: If the device is busy and cannot accept commands.
""" """
self.abort_if_busy() self.abort_if_busy()
await self.device.async_clear_playlist() await self.device.async_clear_playlist()

View File

@@ -418,7 +418,7 @@ class OasisDevice:
If the current track or its SVG content is unavailable, returns None. If the current track or its SVG content is unavailable, returns None.
Returns: Returns:
progress_percent (float | None): Percentage of the drawing completed (0100), clamped to 100; `None` if no track or SVG content is available. progress_percent (float | None): Percentage of the drawing completed (0-100), clamped to 100; `None` if no track or SVG content is available.
""" """
if not (self.track and (svg_content := self.track.get("svg_content"))): if not (self.track and (svg_content := self.track.get("svg_content"))):
return None return None

View File

@@ -24,11 +24,11 @@ AUTOPLAY_MAP_LIST = list(AUTOPLAY_MAP)
def playlists_update_handler(entity: OasisDeviceSelectEntity) -> None: def playlists_update_handler(entity: OasisDeviceSelectEntity) -> None:
""" """
Update the playlists select options and current option from the device's cloud playlists. Update the playlists select options and current option from the device's cloud playlists.
Iterates the device's cloud playlists to build a display list of playlist names (appending " (N)" for duplicate names) Iterates the device's cloud playlists to build a display list of playlist names (appending " (N)" for duplicate names)
and sets the entity's options to that list. If the device's current playlist matches a playlist's pattern IDs, and sets the entity's options to that list. If the device's current playlist matches a playlist's pattern IDs,
sets the entity's current option to that playlist's display name; otherwise leaves it None. sets the entity's current option to that playlist's display name; otherwise leaves it None.
Parameters: Parameters:
entity (OasisDeviceSelectEntity): The select entity to update. entity (OasisDeviceSelectEntity): The select entity to update.
""" """
@@ -52,9 +52,9 @@ def playlists_update_handler(entity: OasisDeviceSelectEntity) -> None:
def queue_update_handler(entity: OasisDeviceSelectEntity) -> None: def queue_update_handler(entity: OasisDeviceSelectEntity) -> None:
""" """
Update the select options and current selection for the device's playback queue. Update the select options and current selection for the device's playback queue.
Populate the entity's options from the device's current playlist and playlist details, disambiguating duplicate track names by appending a counter (e.g., "Title (2)"). Set the entity's current option to the track at device.playlist_index (or None if the queue is empty). Populate the entity's options from the device's current playlist and playlist details, disambiguating duplicate track names by appending a counter (e.g., "Title (2)"). Set the entity's current option to the track at device.playlist_index (or None if the queue is empty).
Parameters: Parameters:
entity (OasisDeviceSelectEntity): The select entity whose options and current option will be updated. entity (OasisDeviceSelectEntity): The select entity whose options and current option will be updated.
""" """
@@ -88,9 +88,9 @@ async def async_setup_entry(
) -> None: ) -> None:
""" """
Set up select entities for each Oasis device from a config entry. Set up select entities for each Oasis device from a config entry.
Creates OasisDeviceSelectEntity instances for every device and descriptor and registers them with Home Assistant via the platform setup. Creates OasisDeviceSelectEntity instances for every device and descriptor and registers them with Home Assistant via the platform setup.
Parameters: Parameters:
hass: Home Assistant instance. hass: Home Assistant instance.
entry: Oasis device config entry used to locate coordinator and runtime data. entry: Oasis device config entry used to locate coordinator and runtime data.
@@ -100,10 +100,10 @@ async def async_setup_entry(
def make_entities(new_devices: list[OasisDevice]): def make_entities(new_devices: list[OasisDevice]):
""" """
Create select entity instances for each provided Oasis device. Create select entity instances for each provided Oasis device.
Parameters: Parameters:
new_devices (list[OasisDevice]): Devices to create select entities for. new_devices (list[OasisDevice]): Devices to create select entities for.
Returns: Returns:
list[OasisDeviceSelectEntity]: A flat list of OasisDeviceSelectEntity objects created for every combination of device and descriptor. list[OasisDeviceSelectEntity]: A flat list of OasisDeviceSelectEntity objects created for every combination of device and descriptor.
""" """
@@ -169,7 +169,7 @@ class OasisDeviceSelectEntity(OasisDeviceEntity, SelectEntity):
) -> None: ) -> None:
""" """
Initialize the Oasis device select entity and perform an initial coordinator update. Initialize the Oasis device select entity and perform an initial coordinator update.
Parameters: Parameters:
coordinator (OasisDeviceCoordinator): Coordinator that manages device updates. coordinator (OasisDeviceCoordinator): Coordinator that manages device updates.
device (OasisDevice): The Oasis device this entity represents. device (OasisDevice): The Oasis device this entity represents.
@@ -181,7 +181,7 @@ class OasisDeviceSelectEntity(OasisDeviceEntity, SelectEntity):
async def async_select_option(self, option: str) -> None: async def async_select_option(self, option: str) -> None:
""" """
Select and apply the option identified by its display string. Select and apply the option identified by its display string.
Parameters: Parameters:
option (str): The display string of the option to select; the option's index in the current options list is used to apply the selection. option (str): The display string of the option to select; the option's index in the current options list is used to apply the selection.
""" """
@@ -191,7 +191,7 @@ class OasisDeviceSelectEntity(OasisDeviceEntity, SelectEntity):
def _handle_coordinator_update(self) -> None: def _handle_coordinator_update(self) -> None:
""" """
Update the entity's cached value and current option when coordinator data changes. Update the entity's cached value and current option when coordinator data changes.
If the derived current value differs from the stored value, update the stored value. If the derived current value differs from the stored value, update the stored value.
If the entity description provides an update_handler, call it with this entity; otherwise, If the entity description provides an update_handler, call it with this entity; otherwise,
set the entity's current option to the string form of the device attribute named by the set the entity's current option to the string form of the device attribute named by the
@@ -209,4 +209,4 @@ class OasisDeviceSelectEntity(OasisDeviceEntity, SelectEntity):
getattr(self.device, self.entity_description.key) getattr(self.device, self.entity_description.key)
) )
if self.hass: if self.hass:
return super()._handle_coordinator_update() return super()._handle_coordinator_update()

View File

@@ -77,7 +77,6 @@ DESCRIPTORS.extend(
entity_registry_enabled_default=False, entity_registry_enabled_default=False,
) )
for key in ("error", "led_color_id", "status") for key in ("error", "led_color_id", "status")
# for key in ("error_message", "led_color_id", "status")
) )

View File

@@ -31,7 +31,7 @@ async def async_setup_entry(
) -> None: ) -> None:
""" """
Set up update entities for Oasis devices from a configuration entry. Set up update entities for Oasis devices from a configuration entry.
Parameters: Parameters:
hass (HomeAssistant): Home Assistant core instance. hass (HomeAssistant): Home Assistant core instance.
entry (OasisDeviceConfigEntry): Config entry containing runtime data used to create device update entities. entry (OasisDeviceConfigEntry): Config entry containing runtime data used to create device update entities.
@@ -41,10 +41,10 @@ async def async_setup_entry(
def make_entities(new_devices: list[OasisDevice]): def make_entities(new_devices: list[OasisDevice]):
""" """
Create update entities for the given Oasis devices. Create update entities for the given Oasis devices.
Parameters: Parameters:
new_devices (list[OasisDevice]): Devices to create update entities for. new_devices (list[OasisDevice]): Devices to create update entities for.
Returns: Returns:
list: A list of OasisDeviceUpdateEntity instances corresponding to each device. list: A list of OasisDeviceUpdateEntity instances corresponding to each device.
""" """
@@ -90,9 +90,9 @@ class OasisDeviceUpdateEntity(OasisDeviceEntity, UpdateEntity):
) -> None: ) -> None:
""" """
Trigger installation of the latest available update on the device. Trigger installation of the latest available update on the device.
If the latest available version matches the device's currently installed software version, no action is taken. Otherwise an upgrade is started on the device. If the latest available version matches the device's currently installed software version, no action is taken. Otherwise an upgrade is started on the device.
Parameters: Parameters:
version (str | None): Ignored by this implementation; the entity uses its known latest version. version (str | None): Ignored by this implementation; the entity uses its known latest version.
backup (bool): Ignored by this implementation. backup (bool): Ignored by this implementation.
@@ -105,7 +105,7 @@ class OasisDeviceUpdateEntity(OasisDeviceEntity, UpdateEntity):
async def async_update(self) -> None: async def async_update(self) -> None:
""" """
Refreshes this entity's latest software metadata. Refreshes this entity's latest software metadata.
Fetches the latest software details from the coordinator's cloud client and updates Fetches the latest software details from the coordinator's cloud client and updates
the entity's `latest_version`, `release_summary`, and `release_url` attributes. the entity's `latest_version`, `release_summary`, and `release_url` attributes.
If no software details are returned, the entity's attributes are left unchanged. If no software details are returned, the entity's attributes are left unchanged.
@@ -116,4 +116,4 @@ class OasisDeviceUpdateEntity(OasisDeviceEntity, UpdateEntity):
return return
self._attr_latest_version = software["version"] self._attr_latest_version = software["version"]
self._attr_release_summary = software["description"] self._attr_release_summary = software["description"]
self._attr_release_url = f"https://app.grounded.so/software/{software['id']}" self._attr_release_url = f"https://app.grounded.so/software/{software['id']}"