Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: remove @util.Throttle use #2573

Merged
merged 5 commits into from
Oct 3, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 65 additions & 5 deletions custom_components/alexa_media/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,11 @@ async def setup_alexa(hass, config_entry, login_obj: AlexaLogin):
# pylint: disable=too-many-statements,too-many-locals
"""Set up a alexa api based on host parameter."""

# Initialize throttling state and lock
last_dnd_update_times: dict[str, datetime] = {}
pending_dnd_updates: dict[str, bool] = {}
dnd_update_lock = asyncio.Lock()

async def async_update_data() -> Optional[AlexaEntityData]:
# noqa pylint: disable=too-many-branches
"""Fetch data from API endpoint.
Expand Down Expand Up @@ -843,21 +848,76 @@ async def update_bluetooth_state(login_obj, device_serial):
)
return None

@util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
async def schedule_update_dnd_state(email: str):
"""Schedule an update_dnd_state call after MIN_TIME_BETWEEN_FORCED_SCANS."""
await asyncio.sleep(MIN_TIME_BETWEEN_FORCED_SCANS)
async with dnd_update_lock:
if pending_dnd_updates.get(email, False):
pending_dnd_updates[email] = False
_LOGGER.debug(
"Executing scheduled forced DND update for %s", hide_email(email)
)
# Assume login_obj can be retrieved or passed appropriately
login_obj = hass.data[DATA_ALEXAMEDIA]["accounts"][email]["login_obj"]
await update_dnd_state(login_obj)

@_catch_login_errors
async def update_dnd_state(login_obj) -> None:
"""Update the dnd state on ws dnd combo event."""
dnd = await AlexaAPI.get_dnd_state(login_obj)
"""Update the DND state on websocket DND combo event."""
email = login_obj.email
now = datetime.utcnow()

async with dnd_update_lock:
last_run = last_dnd_update_times.get(email)
cooldown = timedelta(seconds=MIN_TIME_BETWEEN_SCANS)

if last_run and (now - last_run) < cooldown:
# If within cooldown, mark a pending update if not already marked
if not pending_dnd_updates.get(email, False):
pending_dnd_updates[email] = True
_LOGGER.debug(
"Throttling active for %s, scheduling a forced DND update.",
hide_email(email),
)
asyncio.create_task(schedule_update_dnd_state(email))
else:
_LOGGER.debug(
"Throttling active for %s, forced DND update already scheduled.",
hide_email(email),
)
return

# Update the last run time
last_dnd_update_times[email] = now

_LOGGER.debug("Updating DND state for %s", hide_email(email))

try:
# Fetch the DND state using the Alexa API
dnd = await AlexaAPI.get_dnd_state(login_obj)
except asyncio.TimeoutError:
_LOGGER.error(
"Timeout occurred while fetching DND state for %s", hide_email(email)
)
return
except Exception as e:
_LOGGER.error(
"Unexpected error while fetching DND state for %s: %s",
hide_email(email),
e,
)
return

# Check if DND data is valid and dispatch an update event
if dnd is not None and "doNotDisturbDeviceStatusList" in dnd:
async_dispatcher_send(
hass,
f"{DOMAIN}_{hide_email(email)}"[0:32],
{"dnd_update": dnd["doNotDisturbDeviceStatusList"]},
)
return
_LOGGER.debug("%s: get_dnd_state failed: dnd:%s", hide_email(email), dnd)
return
else:
_LOGGER.debug("%s: get_dnd_state failed: dnd:%s", hide_email(email), dnd)

async def http2_connect() -> HTTP2EchoClient:
"""Open HTTP2 Push connection.
Expand Down
Loading