Strava sensors

I am getting an error trying to Link Strava Account. I see the correct client_id in the URL. Don’t see reference to the client_secret.

{"message":"Bad Request","errors":[{"resource":"Application","field":"redirect_uri","code":"invalid"}]}

Hi @popboxgun,

You will need to change the “Auhtorization Callback Domain” setting for your App at the Strava Developer website to the IP address or hostname of your HA instance:

1 Like

Thanks, the problem appeared to be that the redirection is getting the ip 10.72.10.6 from somewhere as the callback domain. Not sure where that IP came from, it’s not on my local network.

This error was solved, I keep for other’s reference.


Hi

not sure if I’m doing well.

I created custom_components/strava/init.py and sensor.py files from your repo (just those two). Also, added this into configuration.yaml:

strava:
client_id: myaccesstoken
client_secret: myclientsecret

Finally I added some sensors, and configured My Applitcation API at Strava Developer website as you indicated above. I got at the site an Access Token and ClientSecret, and I set them in my config as indicated (not sure if they are OK…¿?)

I still get "
{“message”:“Bad Request”,“errors”:[{“resource”:“Application”,“field”:“redirect_uri”,“code”:“invalid”}]}
"

I guess I’m missing something in my setup.

Any help is much appreciated!
KR

Got it- Though I got the 500, sensors were present at <> in HA :slight_smile:


changed client_ID to 12345 (as retrned in Strava Developer website). Then at HA I followed the “Link Strava Account” link and got to Authorize (great!).

Unfortunatelly, then I got an “500 Internal Server Error. Server got itself in trouble” message.

Ummm…not sure what else I can try ?

Does this still work ?

This was working fine for me for 2 years plus but noticed thats todays ride was not showing up in HA. After checking my API I noticed that this all stopped on 15th Oct 2019 and a search on Strava’s site I found this

## Update: The migration period ended on October 15, 2019

The migration period ended on October 15, 2019 and forever tokens will no longer work. If you did not migrate you will need to reauthorize your users in order to get new tokens. When your users log in, we recommend sending them to authorize with Strava again. If you are having trouble implementing OAuth, please view this guide: https://developers.strava.com/docs/getting-started/#oauth

Looks as if we will need a new way to get to this data - with no known Add-on that I can see it will stop working until a new way is found to exchange tokens on a regular basis.

1 Like

You just need to create a new token and give it access to a specific scope i had the same error.

@stv0g: Sorry for coming here “begging” but it is still almost x-mas :slight_smile: Any plans to pick up the Strava sensor again (https://github.com/home-assistant/home-assistant/pull/22151)? I do of course understand you have a busy life. A completed component in HA would have been much appreciated. I don’t know where to start myself, but if I can be of any help let me know. Happy new year!

Just picked up my HA project on the side. Got HA with Appdeamon. I am familiar (albeit still class myself as a beginner/hobbyist) with Python. I suspect this has died because of the switch to OAuth2 which will require either programmatic login or a program to request refresh every 6 hours. I’d be keen to get this working. Anyone had another go at this?

As far as I understand this has been completely abandoned. I have recently linked strava to HA using IFTTT webhooks to send data to Home Assistant variables then use a few automation a to interpret and arrange that data nicely.

It looks great!
Just yesterday I started looking for information to integrate strava into HA, and it seems that the issue is stopped by Strava API changes. Can anyone still read the Strava data? Could you share how you did it with IFTTT?
Cheers!

Hello,
I think this can be managed with some steps in order to obtain a long-time token. I am not pretty sure but I have obtained the distance. I will monitor it some days to see if the token expires.

Perfect! I hope you explain your results as soon as possible :slight_smile:
Agur!

Well, looks like there are no “long-time” tokens any more. Strava has replaced them for short-time tokens. The good news are that there is a refresh token to reauthorize the app periodically. I am not sure if I can write an app for this but it looks feasible for someone with experience.
agur!

SCREENSHOT-2020-06-17 at 15-34-46

Hey I got Strava working, with a couple of python scripts:

  1. You need to get all necessary tokens, here is a really good video that explains how to get them
    (you need to install Postman, but curl should also work)

    https://www.youtube.com/watch?v=sgscChKfGyg&t=791s

    for the Python Script: https://www.youtube.com/watch?v=2FPNb1XECGs&t=611s

  2. make sure you have python_script: in your configuration.yaml and folder named python_scripts

  3. create a python script for each data, for example, distance of last ride is called strava_distance.py,
    with this content: (replace all three XXX with your data)

import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

auth_url = "https://www.strava.com/oauth/token"
activites_url = "https://www.strava.com/api/v3/athlete/activities"

payload = {
    'client_id': "XXX",
    'client_secret': 'XXX',
    'refresh_token': 'XXX',
    'grant_type': "refresh_token",
    'f': 'json'
}

# print("Requesting Token...\n")
res = requests.post(auth_url, data=payload, verify=False)
access_token = res.json()['access_token']
# print("Access Token = {}\n".format(access_token))

header = {'Authorization': 'Bearer ' + access_token}
param = {'per_page': 200, 'page': 1}
my_dataset = requests.get(activites_url, headers=header, params=param).json()

print(my_dataset[0]["distance"])
  1. add this sensor to your yaml:
  - platform: command_line
    name: Strava Distanz
    command: "python3 /config/python_scripts/strava_distance.py"
    command_timeout: 60
    scan_interval: 180

that’s it! you need to restart Home Assistant but all sensors should work, tested it now for a couple of weeks and it works without problems or API errors


here some useful template sensors:

distance in kilometers:

  - platform: template
    sensors:
     strava_distanz_km:
      friendly_name: "Strava Distanz Km"
      value_template: >
        {{ (states('sensor.strava_distanz') |int  / 1000) | round(2) }}

average speed in km/h:

  - platform: command_line
    name: Strava Average Speed
    command: "python3 /config/python_scripts/strava_average_speed.py"
    value_template: '{{ (value | multiply(3600) / 1000) | round(2) }}'
    unit_of_measurement: km/h
    command_timeout: 60
    scan_interval: 180

duration time in HH:MM:SS:

  - platform: template
    sensors:
      strava_duration_insgesamt_hh_mm_ss:
        friendly_name: Strecke Insgesamt
        icon_template: mdi:bike
        entity_id: sensor.time
        value_template: >-
          {% set t = states('sensor.strava_elapsed_time') | int %}
          {{ '{:02d}:{:02d}:{:02d}'.format((t // 3600) % 24, (t % 3600) // 60, (t % 3600) % 60) }}

arrive time in HH:MM:SS:

  - platform: template
    sensors:
      strava_ankunft_uhrzeit:
        friendly_name: Startzeit
        icon_template: mdi:timer-off-outline
        entity_id: sensor.time
        value_template: >-
          {% set minutes = states('sensor.strava_elapsed_time') | int %}
          {{ (as_timestamp(strptime(states.sensor.strava_start_time.state, "%Y-%m-%dT%XZ")) + (minutes)) | timestamp_custom('%H:%M:%S') }}
2 Likes

Great! I was doing the same thing but inside an addon. Have you think about putting that in one of them?
I will continue doing it but it is my first one.

Continuing with the idea of @drimpart, I have done the following to avoid creating several python files and many sensors.

  1. As before, you need to obtain all the data: the client_ID and client_secret from the Strava API, and a refresh_token with the proper scope (I used “activity:read_all”).
  2. Create one py file as @drimpart says. I have just modified it a little:
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
import logging
logging.basicConfig(level=logging.DEBUG)

auth_url = "https://www.strava.com/oauth/token"
activites_url = "https://www.strava.com/api/v3/athlete/activities"

payload = {
    'client_id': "XXXXX",
    'client_secret': 'XXXXX',
    'refresh_token': 'XXXXX',
    'grant_type': "refresh_token",
    'f': 'json'
}

res = requests.post(auth_url, data=payload, verify=False)
access_token = res.json()['access_token']
print(access_token)
  1. Create a main sensor which executes the script and obtains the new token:
  - platform: command_line
    name: Strava Access Token
    command: "python3 /config/python_scripts/strava.py"
    scan_interval: 900
  1. Create a second sensor that uses the token and obtains many data at once (wait for the scan interval after restarting HA):
  - platform: rest
    name: Strava Last Activity
    json_attributes_path: "$.[0]"
    json_attributes:
      - distance
      - total_elevation_gain
      - average_speed
      - average_heartrate
      - moving_time
    resource_template: https://www.strava.com/api/v3/athlete/activities?access_token={{ states('sensor.strava_access_token') }}
    method: GET
    value_template: '{{ value_json[0].name }}'
    scan_interval: 300
  1. Create as many templates as you want:
  - platform: template
    sensors:  
      strava_last_distance:
        friendly_name: 'Strava Last Distance'
        value_template: "{{ ((state_attr('sensor.strava_last_activity', 'distance'))/1000) | round(2) }}"
        unit_of_measurement: "km"
        entity_id: sensor.strava_last_activity
      strava_last_elevation:
        friendly_name: 'Strava Last Elevation'
        value_template: "{{ (state_attr('sensor.strava_last_activity', 'total_elevation_gain')) | round(1) }}"
        unit_of_measurement: "m"
        entity_id: sensor.strava_last_activity

image
Thank you @drimpart for sharing.

I think the pro of this way is that requires less files and lines, the contra is that you expose the token in a sensor value.

I am still thinking about doing an addon for the first step (granting authorization).

EDIT: I have seen that there are two limits: 100 requests per 15min and 1000 requests per day.
Check the “scan_interval” of your py script files and rest commands, to avoid reaching the daily limit.
If you have 2 urls (one for last activity and another for your total stats), you could have an interval of 300s = 5min -> 288 times a day * 2 urls = 576 requests for the rest + 96 more for the refresh token.

4 Likes

thanks @icaballero, the json_attributes makes it definitely more compact and easier, I tried something similar, but id didn’t work out, I might change it to this version.
Unfortunately, I have no idea how to create an addon, but it would make the whole process definitely easier to have one, maybe somebody else can help.
Also, it seems I have different request limits (Premium Account), so my scan_interval of 180 seconds is no problem. you can always check if you are on the limit on your profile https://www.strava.com/settings/api

SCREENSHOT-2020-06-18 at 21-16-12

Is the Premium Account the same as having a summit subscription?
I have one but my limits are the standard ones.

Rhythm (min per km) for runners using the speed:

  - platform: template
    sensors:  
      strava_last_rhythm:
        friendly_name: 'Strava Last Rhythm'
        value_template: >-
         {% set t = (100/ (state_attr('sensor.strava_last_activity', 'average_speed')|multiply(0.06)) ) %}
         {{ '{:02d}:{:02d}'.format((t//100)|int,((t%100)*0.6) |int) }}
        unit_of_measurement: "min/km"