Zwift Sensor Component - Feedback and Testers Needed

updated to v3.1

  • Fix issue with credentials/authentication decaying and logging out (hopefully)
  • Stop using a dedicated thread for updating and rely on Home Assistant to schedule updates accordingly

cc @badguy and @flipdream1

1 Like

Thanks snicker, install and try this new version.

@snicker I’ve slapped up a PR for the deprecation warning seen in the HA 110 logs:

WARNING (MainThread) [homeassistant.components.binary_sensor] BinarySensorDevice is deprecated, modify ZwiftBinarySensorDevice to extend BinarySensorEntity

:smile:

Thanks Guy! I have a couple things that need to get figured out before that migration, I’ll comment on the PR!

@snicker, I’ve just installed the component and it’s mostly working well, thanks for your efforts in putting this together!

I’m seeing one odd thing, where the online flag goes to True when I start Zwifting, but then never goes back to False. I’m using Zwift on iOS, would that make a difference?

Thanks again!

This happened to me yesterday as well, but I also had several 503 errors from Zwift saying that their servers were overloaded. Could you take a look at your logs and let me know if you see anything?

@snicker Thanks for looking into this! I’m looking at the logs in ‘developer tools’ part of home assistant, I see one occurrence each of:

  • BinarySensorDevice is deprecated, modify ZwiftBinarySensorDevice to extend BinarySensorEntity

  • Unexpected exception occurred: File “/usr/local/lib/python3.7/site-packages/zwift/request.py”, line 45, in protobuf resp.status_code, resp.reason)) zwift.error.RequestException: 404 - Not Found

No errors since then but the online state is still ‘True’. Does this mean the 404 error has stopped the component?

I have only changed all “BinarySensorDevice” to “BinarySensorEntity” in sensor.py, now it’s working like before and without errors.

Thanks @flipdream1 - I tried this, didn’t make any difference for me (yes, the deprecated message is now gone). I keep getting 404 errors. The full error is here:

Unexpected exception occurred:
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/usr/local/lib/python3.7/asyncio/base_events.py", line 574, in run_until_complete
    self.run_forever()
  File "/usr/local/lib/python3.7/asyncio/base_events.py", line 541, in run_forever
    self._run_once()
  File "/usr/local/lib/python3.7/asyncio/base_events.py", line 1786, in _run_once
    handle._run()
  File "/usr/local/lib/python3.7/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/config/custom_components/zwift/sensor.py", line 114, in update_data
    await hass.async_add_executor_job(zwift_data.update)
  File "/usr/local/lib/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/zwift/sensor.py", line 338, in update
    player_state = world.player_status(player_id)
  File "/usr/local/lib/python3.7/site-packages/zwift/world.py", line 25, in player_status
    '/relay/worlds/{}/players/{}'.format(self.world_id, player_id))
  File "/usr/local/lib/python3.7/site-packages/zwift/request.py", line 45, in protobuf
    resp.status_code, resp.reason))
zwift.error.RequestException: 404 - Not Found

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/plexwebsocket.py", line 79, in listen
    async for message in ws_client:
  File "/usr/local/lib/python3.7/site-packages/aiohttp/client_ws.py", line 296, in __anext__
    msg = await self.receive()
  File "/usr/local/lib/python3.7/site-packages/aiohttp/client_ws.py", line 227, in receive
    msg = await self._reader.read()
  File "/usr/local/lib/python3.7/site-packages/aiohttp/streams.py", line 631, in read
    return await super().read()
  File "/usr/local/lib/python3.7/site-packages/aiohttp/streams.py", line 591, in read
    await self._waiter
concurrent.futures._base.CancelledError
Connection lost. Reconnecting…

I noticed that I get the error when I start Zwifting… Happy to continue testing, just le me know where to look! :slight_smile:

1 Like

The odd thing about this is that the second error is thrown by the Plex integration during handling of the 404 exception from Zwift (which should be handled properly). I have had some similar errors, but I’ve been very confused as to how one component can raise an exception inside of the exception handler for another component. I’ll have to dig into this more, as the only code I recall being present is a logging call.

Thanks - let me know if there’s anything I can do to help track this down!

Just to add some more info, although you may have enough already, I use the component to turn my Sonos on and off based on Zwift Online status. I also use Zwift Heart Rate status to control a linked Smartthings dimming plug for my Lasko fan. HA seem to have an issue when it tries to use Zwift Online as a trigger to turn off the Sonos. Probably started around HA update 0.109.5, I think, and maybe around the time I upgraded to Zwift Sensor v3.0.

Let me know if I can provide anything else.

2020-05-22 09:18:14 INFO (MainThread) [homeassistant.components.automation] Executing HR 90-109
2020-05-22 09:18:14 INFO (MainThread) [homeassistant.components.automation] HR 90-109: Running script
2020-05-22 09:18:14 INFO (MainThread) [homeassistant.components.automation] HR 90-109: Executing step device automation
2020-05-22 09:18:14 INFO (MainThread) [homeassistant.components.automation] HR 90-109: Executing step device automation
2020-05-22 09:18:14 INFO (MainThread) [homeassistant.components.automation] HR 90-109: Executing step device automation
2020-05-22 09:18:14 INFO (MainThread) [homeassistant.components.automation] HR 90-109: Executing step device automation
2020-05-22 09:18:14 INFO (MainThread) [homeassistant.components.automation] HR 90-109: Executing step device automation
2020-05-22 09:21:24 ERROR (MainThread) [root] Uncaught exception
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/local/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/usr/src/homeassistant/homeassistant/__main__.py", line 364, in <module>
    sys.exit(main())
  File "/usr/src/homeassistant/homeassistant/__main__.py", line 356, in main
    exit_code = asyncio.run(setup_and_run_hass(config_dir, args), debug=args.debug)
  File "/usr/local/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/usr/local/lib/python3.7/asyncio/base_events.py", line 574, in run_until_complete
    self.run_forever()
  File "/usr/local/lib/python3.7/asyncio/base_events.py", line 541, in run_forever
    self._run_once()
  File "/usr/local/lib/python3.7/asyncio/base_events.py", line 1786, in _run_once
    handle._run()
  File "/usr/local/lib/python3.7/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/config/custom_components/zwift/sensor.py", line 114, in update_data
    await hass.async_add_executor_job(zwift_data.update)
  File "/usr/local/lib/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/zwift/sensor.py", line 338, in update
    player_state = world.player_status(player_id)
  File "/usr/local/lib/python3.7/site-packages/zwift/world.py", line 25, in player_status
    '/relay/worlds/{}/players/{}'.format(self.world_id, player_id))
  File "/usr/local/lib/python3.7/site-packages/zwift/request.py", line 45, in protobuf
    resp.status_code, resp.reason))
zwift.error.RequestException: 404 - Not Found
/usr/local/lib/python3.7/site-packages/pysonos/events_base.py:608: RuntimeWarning: coroutine 'Entity.async_update_ha_state' was never awaited
  log.debug('Error putting event %s, ex=%s', event, ex)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
/usr/local/lib/python3.7/site-packages/pysonos/discovery.py:170: RuntimeWarning: coroutine 'SonosEntity.async_seen' was never awaited
  _LOG.debug('Error handling discovery response, ex=%s', ex)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

have you updated to 3.1 @piaccarino? The issue in your logs I believe should have been resolved in that version.

Yep, I upgraded as soon as I noticed it was available. Definitely before I rode this morning though.

I don’t know why the 404 is coming out - it seems a bit odd, but I guess that is between Zwift servers and the zwift python client. But I think as it is a custom exception, you need to import it, e.g.

    def update(self):
        from zwift.error import RequestException
        if self._client:

Then it can be caught / ignored and update should try again on the next go around…

                    online_player.update(player_profile)
                    self.players[player_id].player_profile = online_player
                except RequestException as e:
                    if '401' in str(e):
                        self._client = None
                        _LOGGER.warning('Zwift credentials are wrong or expired')
                    elif '404' in str(e):
                        _LOGGER.warning('Upstream Zwift 404 - will try later')
                        pass
                    else:
                        _LOGGER.exception('something went wrong in Zwift python library - {} while updating zwift sensor for player {}'.format(str(e), player_id))
                except Exception as e:
                    _LOGGER.exception('something went major wrong while updating zwift sensor for player {}'.format(player_id))
                self.players[player_id].data = data

I should add, this is because zwift.error.RequestException is inheriting from BaseException rather than Exception :neutral_face: https://github.com/jsmits/zwift-client/blob/02effd3d08c9c14b2d739ce2be6e1a133f3b430d/zwift/error.py

I haven’t been able to replicate this in a few days… anyone else still having issues?

The problem with catching zwift.error.RequestException is that the upstream library uses this for all non-200 status codes coming from the server, including the 401 authentication error that means we need to refresh the key.

Still trying to chase this down.

I was still having issues with it on Saturday night. Haven’t been online on Zwift more recently though.

I’m seeing this issue as well. Latest HA, HACS, and Zwift. Let me know what I can do to help.

Could you post your logs please?