Zwift Sensor Component - Feedback and Testers Needed

@snicker. Awesome news. After last discussion I have been running latest version ironically without any issues. I have suspected something went horribly wrong with my setyp for a second. But two isolated cases suggested it is not. Very cool you have identified the culprit so back to testing. Thanks for effort! Ride on!

Another big update… I fooled around with the API some more and was able to figure out where the “total experience points” for a player, and I was able to find a table online dictating the total XP per level, so now we can have a “level” sensor. This will be cool if you want to flash your lights or play a song or something when you level up.

oh AND, I was able to add the entire player profile object as attributes to the ‘Online’ sensor… this opens up the opportunity for people to add template sensors for whatever they want. It’s kind of … information overload at this point, but it can be pared down on request.

So I went for a ride and just leveled up from 9 to 10 (woohoo!) and it seems that the profile data (experience etc) takes a bit of time to update in the API. I did not notice my level change on HA for probably two minutes. Just something to consider. This is with an update interval of 15 seconds.

With the recent changes it seems that I should be able to change that update interval to be faster depending on whether or not players are online so data refreshes are happening more frequently.

@bachulator: what did you end up overriding your refresh interval to? Have you noticed any issues?

Yes I have played with update intervals and after first system crash I have decided to roll with default update interval (not defining one). As you said the update interval was about 20 seconds which is good enough for ERG workouts since input data is more static then in free ride. Excited to see new features and conditional update interval.

Interesting work! Thanks a lot for this! At the moment I only control my fan. But imagination knows no bounds. Kudos

Unlimited indeed. I have pre-ride routine for room ventilation then fan is controlled accordingly to HR zone and lighting is changed based on powerzone. That fits the purpose for me for now. Let’s hope you will come up with even more sensors so we will have even more scenarios. Thanks for your time @snicker. Ride on!

Hey guys,

Awesome work! My first thought when I did the first version was to decouple frequent updates of the sensor from the HA. Now I think that maybe I shouldnt had worried too much about that. As I use power to incresase/decrease fan speed, I’d like to have the small update interval as possible (think about those 15s or less all out sprints). I’m just wondering about another strategy… What you think if the sensor generates HA “events”. Maybe using Zwift own power zone information (blue, orange, red)? Would this make HA detecting/reacting faster?

@clyra I have been using this power as fan control, but later came to conclusion that heart rate might be better driver since it more represents actual status of your core temperature and need to cool it done. But to each it’s own :slight_smile:

@clyra it would still require polling to generate those events in a timely manner. Zwift doesn’t have any kind of “push” API, and i think even the native application works by frequently polling the server. I have been trying to play nice by starting the polling interval used by the component higher, but I think we may be able to dial it to 2-3 seconds when online.

I may be trying to optimize prematurely but i also have concerns of polling too frequently causing issues within HA.

I’m going to implement the dynamic refresh interval this week and test how it goes.

sure, you are right. Maybe 5 seconds should be enough. But I was also concerned about the automations that consume those values, this is why I suggested the event approach.

This is great. It takes a few moments to refresh which is fine :+1:

I do have one problem in that it doesn’t go back to offline when finished but that’s not a big problem.

If it helps anyone I’m using this to pull FTP out of my online status and then get the Power Zone as the text name. (change [id] to your zwift id)

Edit: Updated from suggestions below

- platform: template
  sensors:
    zwift_ftp_[id]:
      friendly_name: "Zwift FTP"
      entity_id: sensor.zwift_online_[id]
      unit_of_measurement: 'watts'
      value_template: "{{states.sensor.zwift_online_[id].attributes.ftp}}"
        
    zwift_power_zone_[id]:
      friendly_name: "Zwift Power Zone"   
      entity_id: sensor.zwift_power_[id]
      value_template: >-
        {% set ftp = states('sensor.zwift_ftp_[id]') | float %}
        {% set power = states('sensor.zwift_power_[id]') | float %}
        {% set zone1 = ftp | float * 0.55 %}
        {% set zone2 = ftp | float * 0.76 %}
        {% set zone3 = ftp | float * 0.90 %}
        {% set zone4 = ftp | float * 1.05 %}
        {% set zone5 = ftp | float * 1.2 %}
        {% set zone6 = ftp | float * 1.5 %}
        
        {% if power < 1 %}Off
        {% elif zone1 > power %}Active Recovery
        {% elif zone2 > power %}Endurance
        {% elif zone3 > power %}Tempo
        {% elif zone4 > power %}Threshold
        {% elif zone5 > power %}VO2 Max
        {% elif zone6 > power %}Anaerobic capacity
        {% elif zone6 < power %}Neuromuscular Power{% endif %}

I then have these to change a nearby light, just because (RGB colours are from whatsonzwift.com, Zone 7 is a guess).

- id: '1547677303860'
  alias: Zwift Zone 1 Light
  trigger:
  - entity_id: sensor.zwift_power_zone_[id]
    platform: state
    to: Active Recovery
  condition: []
  action:
  - data:
      entity_id: light.zwift_light
      rgb_color:
      - 127
      - 127
      - 127
    service: light.turn_on

- id: '1547677303861'
  alias: Zwift Zone 2 Light
  trigger:
  - entity_id: sensor.zwift_power_zone_[id]
    platform: state
    to: Endurance
  condition: []
  action:
  - data:
      entity_id: light.zwift_light
      rgb_color:
      - 51
      - 140
      - 255
    service: light.turn_on
- id: '1547677303862'
  alias: Zwift Zone 3 Light
  trigger:
  - entity_id: sensor.zwift_power_zone_[id]
    platform: state
    to: Temp
  condition: []
  action:
  - data:
      entity_id: light.zwift_light
      rgb_color:
      - 89
      - 191
      - 89
    service: light.turn_on
- id: '1547677303863'
  alias: Zwift Zone 4 Light
  trigger:
  - entity_id: sensor.zwift_power_zone_[id]
    platform: state
    to: Threshold
  condition: []
  action:
  - data:
      entity_id: light.zwift_light
      rgb_color:
      - 255
      - 204
      - 63
    service: light.turn_on
- id: '1547677303864'
  alias: Zwift Zone 5 Light
  trigger:
  - entity_id: sensor.zwift_power_zone_[id]
    platform: state
    to: VO2 Max
  condition: []
  action:
  - data:
      entity_id: light.zwift_light
      rgb_color:
      - 255
      - 102
      - 57
    service: light.turn_on
- id: '1547677303865'
  alias: Zwift Zone 6 Light
  trigger:
  - entity_id: sensor.zwift_power_zone_[id]
    platform: state
    to: Anaerobic capacity
  condition: []
  action:
  - data:
      entity_id: light.zwift_light
      rgb_color:
      - 255
      - 51
      - 12
    service: light.turn_on
- id: '1547677303866'
  alias: Zwift Zone 7 Light
  trigger:
  - entity_id: sensor.zwift_power_zone_[id]
    platform: state
    to: Neuromuscular Power
  condition: []
  action:
  - data:
      entity_id: light.zwift_light
      color_name: indigo
    service: light.turn_on
5 Likes

damn that is awesome! That’s the kind of stuff I was hoping people would use this for

@phillprice: looking at your sensors a bit more, I think you can fix a couple issues you might be having.

  1. You can set the refresh_interval in the Zwift sensor config to be 3-4 seconds instead of the default of 15. You will get more frequent updates. I do intend to make the refresh interval dynamic depending on online status in the future, but this works for now.
  2. if you set the entity_id on the zwift_power_zone_[id] sensor to be sensor.zwift_power_[id], HA will recalculate the sensor value every time the power sensor changes. I’ve found this to be extremely responsive. Right now it will only change when the attributes on the zwift_online_[id] sensor state changes which is not as frequent. This may not help at all as HA can usually extract entity IDs to monitor from the template code pretty well, but I’m always explicit just in case.
  3. you might want to add another elif to check the online sensor to show “Offline” in the power zone sensor, otherwise it might always read “active recovery”
1 Like

Very nice! Who will be the first to build a tasmotized front wheel elevator? :slight_smile:

I am considering. Physical restrictions for most of trainers. The trainer skewer should allow rotation in lock state. So basically limited to newest kickr trainers. And yeah gradient sensor woul be nice as well.

I’ll crawl around the API data to see if we can get current gradient. Might be there.

@snicker I have seen gradient in app so shoul be there. Meanwhile I have created sensor which calculate value localy: elevation / distance *100. But again the value is ctitical to update period.

it’s there. From the PlayerStateWrapper class:

“Fields provided by wrapped player_state:
id, worldTime, distance, roadTime, laps, speed, roadPosition, cadenceUHz,
heartrate, power, heading, lean, climbing, time, f19, f20, progress,
customisationId, justWatching, calories, x, altitude, y, watchingRiderId,
groupId, sport”

awesome new developments (pull from my repo):

  1. If any players are online, sensors will now update approximately every 1-2 seconds. If not, the API will only be polled every update_interval seconds (15s is default).
  2. three new sensors exist:
    1. altitude: this is kind of iffy right now and might only work in Wattopia. I got some information from another Zwift API afficionado on the Zwift Coders facebook group that the altitude units are in half-centimeters and sea level is offset by 9000 half-centimeters in wattopia. I tested it and it works in Wattopia.
    2. distance: total distance in kilometers on the current ride
    3. gradient: the instantaneous gradient on the current ride
  3. Sensor names will now show the player’s first name instead of just the ID in the default friendly name of the device, ie. “Zwift Distance (snicker)” instead of “Zwift Distance (123456)”. This requires you to go online at least once after booting HA as the player information will not persist between reboots. It will still show the ID until then.

the gradient sensor was tough to figure out! it is not actually available in the player_state like @clyra noted. I am computing this manually based on the deltas between altitude and distance between API updates. That means it should be pretty damn close to correct and looked spot on for the most part when I compared my last ride to the sensor.

give it a shot!