Zwift Sensor Component - Feedback and Testers Needed

I was browsing the Share your Projects forum yesterday and saw someone had created a Zwift sensor using a separate Python script and MQTT.

Given that I hadn’t tried my hand at creating a custom component yet, I decided to take a whack at it for Zwift!

Installation

Preferred Method

  1. Install HACS https://hacs.netlify.com/installation/manual/
  2. Go to the HACS store, search for “Zwift”, and follow the installation instructions!

Manual Installation

  1. Grab all files from zwift_hass/custom_components/zwift at master · snicker/zwift_hass · GitHub and drop into your custom_components/sensor/zwift/ folder
  2. Add a configuration similar to the one below to your HA configuration. Players should be a list of “player_id” numbers that you wish to track. Your own player_id will be automatically included unless you specify the include_self directive in your sensor config and set it to false
  3. Restart HomeAssistant

Configuration Example

sensor:
  - platform: zwift
    username: !secret my_zwift_username
    password: !secret my_zwift_password
    players:
      - !secret my_friends_zwift_player_id

Issues

  1. Not sure how to create “binary” sensors from within a “sensor” platform, so currently the “online” binary sensor shows up as just a regular “sensor” even though I’m inheriting from BinarySensorDevice

Planned Improvements

  1. Documentation and direct integration into HA
4 Likes

A first finding before riding :slight_smile:

Cadence sensor reports as unit of measurement Hz. Which technically is correct, but more common unit is RPM (Rotations per minute) of cause be change in customization but perhaps will be more tidy to use RPM?

I wonder are there any in-game events available in the API (rideons, incoming power gates, etc) would be an interesting for integration with lights etc. Are there any documentation available online regarding this topic?

Not sure if is even possible but would be rather cool if sensors (cadence, power, hr etc) pool time would be driven by user online status. If online shorter pool time, if offline don’t pool at all…

Good call on rpm, changes have been made.

I’ll look into event streams… it might be possible. I haven’t spent but a few minutes playing around with their API, and as far as I can tell there is zero documentation available publicly, so it’s a lot of trial and error and exploration.

What do you mean by pool time?

I would like to change the interval for API calls to be longer if no player_ids are online to avoid hammering the Zwift servers and reduce web traffic. I am relying on the Throttle utility class for this now, but I could potentially have a separate thread going ala the Nest component.

What is default API call interval now? Will it be affected by “update_interval” instruction to the sensor?
Another proposal since you populating the units of measurement for each sensor perhaps icons would be a good idea as well here are my suggestions:

 sensor.zwift_cadence     icon: 'mdi:rotate-right'
 sensor.zwift_heart_rate  icon: 'mdi:heart-pulse'
 sensor.zwift_online         icon: 'mdi:radio-tower'
 sensor.zwift_power         icon: 'mdi:flash'
 sensor.zwift_speed         icon: 'mdi:speedometer'

P.S The component is working and I have successfully integrated with my fan control. Just super. Will add some extra lighting effect based on power.
P.P.S. Perhaps all values should be integer since we don’t really need such precision level but it will put extra demand on storage capacity.

Awesome work there! Thanks. Will wait for updates and improvements! Let me know if I can help with the project!

Right now the API calls are made no more frequently than every 15 seconds by default. This is controlled by the Throttle utility. Whenever any individual sensor is “updated” by HA, it will try to call the API unless it has already been called within the last 15 (or update_interval) seconds. When the API call is made, all sensors for the players on that sensor platform should be updated using the dispatcher. Hope that answers the question… but I’m honestly not sure if that’s the most optimal way to do things within the HomeAssistant codebase!

Thanks for all the hard work in picking out some icons, I implemented those directly!

I also enabled the feature to automatically include your own player_id without having to add it to the players list in the config, unless you set include_self to false in your platform config.

Cool ideas, please let me known when i can try it. Yes including own player is great idea to be frank I don’t see any other scenario when I woul add other player since you always can create separate instance of sensors for each player. Please consider change sensor values to integers. I will remove update_interval for today ride and check how this change sensor updates.

Great work, let me know if I can help with the project.

You can try it anytime, just download and add to your custom components, the repository should have the latest file. I’ve modified the sensor values to be integers as well.

If you’d like to add any features you may send a pull request as well!

Thanks @snicker! Had you chance to take a look on in-game events as well (rideons, level gain, PR etc)?

See you at Zwift. Rideon!

Doesn’t look like there are any ways to get data on PRs or Ride-Ons, but we could track XP and Level in a sensor, when level changes state that would be a good indicator of a level-up.

There is an API endpoint for events too, but it’s not implemented in the Python library, so I’d have to figure that out from the Node.js library and port it over. Then we could have an upcoming events sensor, possibly

Well, level might be fun to integrate with pain cave lighting, i guess :slight_smile:

as it turns out , I can’t actually find anywhere in the API data that returns the current player level! So maybe that is out the window too… really wish there was some documentation somewhere

I do see quite few Zwift integrations, so I don’t think it is just independent reverse engineering cases. There shoul be some common knowledge base. Will try to sniff around if something pops up I will let you know.

Some reference:

Yeah, that is the library that python-zwift is loosely based on. It still doesn’t provide documentation of available endpoints other than the ones we already know about, and it doesn’t provide documentation of the output of the API (ie, where can I find player levels? what the hell are the units of the altitude response?)

The one thing the Ogadai library has that the python library does not is the ability to check for events in game. That’s what I mentioned above as something that would need to be ported to the python library before we could add an “upcoming event” sensor.

In my mind more interesting part is this one:

You can contact Zwift at [email protected]to register interest and ask for further information.

After update of the component i suddenly get two copies of the each sensor. Strange…
sensor.zwift_power_XXXXX
sensor.zwift_power_XXXXX_2

Hi @snicker,

I think I have found a bug. Not sure should register an issue or just describe here. But here it is. As you probably aware Zwift is running Zwift tour which attracts massive amount of users simultaneously. Which seems to increase traffic on mobile interface. (for instance even companion app stops responding) As I have mentioned before the component seemed to work well before this but now I see a massive memory leak which later shuts the system completely. My initial theory was that component could fetch data to frequently and too much which could overload database backed, but blacklisting the sensors in recorder didn’t help. And issue seemed to be driven by in-game events. So now my theory this could be stack overflow issue or data parsing bug in case of unexpected interruption on Zwift API.

Hi @bachulator

Are you sure the Zwift component is causing a memory leak? Can you provide some logs or data? I have been using it on HA v 0.84.5 and have not experienced that issue. What hardware are you running on? What messages are in the log when your system shuts down?

1 Like

Can’t claim 100% but i had 2 isolated cases with same result. And obviously I had been on my bike so had no access to HA before it became unresponsive. Have roled to version which require player Id definition (which I had no problems with). Will continue to experiment. Will come back with updates. But again the issue seems to be in game event driven not sure will be able to reproduce. Runnig on RPI3.

Thanks for your work @snicker.

@bachulator I think I was able to reproduce the problem! It’s not a memory leak on my side though. It seemed to be how I was handling updates from Zwift and dispatching them using some in-built HASS utilities for asynchronous stuff. I was generating some race conditions without realizing it (because I didn’t understand the dispatching model).

Threading is hard.

Anyhow, I’ve updated the component now (pull from my repo) and it has been running just fine for me for the last couple days (I was testing before I wanted to let you know about the update). The update polling from Zwift now runs in a completely separate thread and dispatches updates to each of the sensors as required. Give it a shot and let me know if you have issues!