Skip to content

Conversation

@NoahCornell
Copy link
Contributor

@NoahCornell NoahCornell commented Aug 18, 2025

Check all that apply

Type of Change

  • WWST Certification Request
    • If this is your first time contributing code:
      • I have reviewed the README.md file
      • I have reviewed the CODE_OF_CONDUCT.md file
      • I have signed the CLA
    • I plan on entering a WWST Certification Request or have entered a request through the WWST Certification console at developer.smartthings.com
  • Bug fix
  • New feature
  • Refactor

Checklist

  • I have performed a self-review of my code
  • I have commented my code in hard-to-understand areas
  • I have verified my changes by testing with a device or have communicated a plan for testing
  • I am adding new behavior, such as adding a sub-driver, and have added and run new unit tests to cover the new behavior

Description of Change

This fixes two issues regarding sonos oauth expiration.

**Better Preemptive Token Refreshing:**

~~This is ensuring that we correctly preemptively refresh the oauth token. We were not setting refresh to true when calling security.get_sonos_oauth. Setting this to true ends up setting a query parameter to force refresh the token when making the API calls to get an ISA token. ~~

This change also increases the period where we will attempt to refresh the token to 2 hours. This is done to match up with the SSDP event handler which checks auth hourly so we should never end up in a situation where the token expires. If the token does expire, then our next call on the websocket will fail and we will not handle the next capability command.

Removed due to potential issues with force refresh. Will open a new PR to handle.

Reconnect Task Race Condition:

If we don't have the proper auth to make websocket requests, then we will receive a ERROR_NOT_AUTHORIZED error. The handling for this error calls Router.close_socket_for_player.

Router.close_socket_for_player will immediately call the on_close callbacks for any listeners. For the sonos_connection, this calls _spawn_reconnect_task.

Both the legacy and oauth flavors of the reconnect task check if the connection is running before attempting to reconnect. This ends up checking in the websocket router if we are connected.

Since there are several tasks at play here, we might do the check if we are connected before this runs. The reconnect task will then exit early since it appears as we are already connected. The fix is to call the on_close when the socket is actually closed, rather than immediately, so that the reconnect task doesn't exit early.

Summary of Completed Tests

I have been testing by using the hedge endpoints to manually set the token and it's expiration. I can let it sit and let the expiration naturally hit as well to make sure things are working.

  • Test with valid token that is about to expire and modifying SSDP event handler to always check auth. Confirmed that the token is properly refreshed and subsequent capability commands are handled.
  • Test with invalid token and modifying SSDP event handler to always check auth. Confirmed that the token is properly refreshed and subsequent capability commands are handled.
  • Test with invalid token and sending capability command. Command is dropped but websocket is reconnected succesfully, subsequent commands are handled.
  • Test with valid token that is about to expire and sending capability command. Command is handled and token is refreshed.
  • Test with unplugging speaker. on_close still only called a single time. Reconnects successfully when plugged back in.

@github-actions
Copy link

github-actions bot commented Aug 18, 2025

Channel deleted.

@github-actions
Copy link

github-actions bot commented Aug 18, 2025

Test Results

   68 files  ±0    447 suites  ±0   0s ⏱️ ±0s
2 325 tests ±0  2 325 ✅ ±0  0 💤 ±0  0 ❌ ±0 
3 924 runs  ±0  3 924 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 0095654. ± Comparison against base commit fcdc5f8.

♻️ This comment has been updated with latest results.

@github-actions
Copy link

github-actions bot commented Aug 18, 2025

Minimum allowed coverage is 90%

Generated by 🐒 cobertura-action against 0095654

local result, err = security.get_sonos_oauth()
if math.abs(expiration - now) < PREEMPTIVE_OAUTH_REFRESH_PERIOD_S then
-- Passing in true here forces refresh of the token.
local result, err = security.get_sonos_oauth(true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you quantify what the API pressure was before when compared with what it is now? We probably should get someone who wrote those apis to signoff on this. IIRC there was discussion of when force_refresh was appropriate to use, and I worry that this may be too aggressive and cause undue stress on our cloud and the sonos auth service.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talking with Ingvar it sounds like there are some reasons why we don't want to use force refresh here so I'll remove that commit because the other commit is still valid and a bigger issue. I'll open up a new PR to deal with the token expiration issue and missing capability commands.

There is a race condition when a sonos connection calls close on itself.
It immediately calls on_close which will spawn a task to reconnect. The
reconnect task checks if the connection is running which depends on
the socket being closed and cleaned up. Instead, call on_close
after the socket has been closed and cleaned up.
@NoahCornell NoahCornell force-pushed the bugfix/sonos-oauth-reconnect branch from 42d8093 to 0095654 Compare August 19, 2025 15:20
@NoahCornell NoahCornell merged commit c642728 into main Aug 20, 2025
11 checks passed
@NoahCornell NoahCornell deleted the bugfix/sonos-oauth-reconnect branch August 20, 2025 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants