I really like riding my bike. I also like being lazy. I also like getting kudos on Strava. I also like convoluted solutions to first world problems.
So...
I’ve hacked an old telephone, and my car. So that when I pick up the phone, it takes a random car trip that I’ve recently done, and remaps the speed from driving speed to cycling speed, adds fake heart-rate and cadence data, and then uploads it to Strava.
So instead of having to go for a ride, I can Phone It In™
from polyline.codec import PolylineCodec
import requests
import json
import pprint
import gpxpy
import gpxpy.gpx
import numpy
from geopy.distance import vincenty
from datetime import datetime, timedelta
from stravalib import Client
from io import BytesIO
import time
import StringIO
PHONE_URL='https://agent.electricimp.com/PRIVATE/data/'
print "Operators are standing by..."
while 1:
r = requests.get(PHONE_URL)
val = int(r.text)
if val != 65535:
break
time.sleep(0.5)
print "Hello?"
MY_STRAVA_CLIENT_ID = PRIVATE
MY_STRAVA_CLIENT_SECRET = 'PRIVATE'
MY_STRAVA_TOKEN = 'PRIVATE'
MY_AUTOMATIC_TOKEN = 'PRIVATE'
TRIPS_URL = 'https://api.automatic.com/trip/'
r = requests.get(TRIPS_URL,
headers = {'Authorization': 'Bearer ' + MY_AUTOMATIC_TOKEN}
)
trips = json.loads(r.text)
# Get the most recent trip
trip = trips['results'][0]
path = PolylineCodec().decode(trip['path'])
start_time = datetime.today()
miles = trip['distance_m'] / 1609.3;
miles_per_hour = 13;
miles_per_second = miles_per_hour / 3600.0;
miles_per_point = miles / len(path);
seconds_per_point = miles_per_point / miles_per_second;
gpx = gpxpy.gpx.GPX()
# Create first track in our GPX:
gpx_track = gpxpy.gpx.GPXTrack()
gpx.tracks.append(gpx_track)
# Create first segment in our GPX track:
gpx_segment = gpxpy.gpx.GPXTrackSegment()
gpx_track.segments.append(gpx_segment)
t = start_time
p = path[0]
gpx_segment.points.append(gpxpy.gpx.GPXTrackPoint(p[0], p[1], time=t, elevation=1236))
pp = p
speed = numpy.random.normal(miles_per_second, miles_per_second * 0.2)
for p in path:
distance = vincenty(pp, p).miles
speed = speed + numpy.random.normal(0, miles_per_second * 0.05)
random_mps = numpy.random.normal(miles_per_second, speed)
if (random_mps > miles_per_second * 1.5) | (random_mps < miles_per_second * 0.25):
speed = numpy.random.normal(miles_per_second, miles_per_second * 0.1)
random_mps = speed
t = t + timedelta(seconds = distance / random_mps)
gpx_segment.points.append(gpxpy.gpx.GPXTrackPoint(p[0], p[1], time=t, elevation=1236))
pp = p
gpx_str = gpx.to_xml()
hacked_gpx_str = ''
buf = StringIO.StringIO(gpx_str)
hr = 120
while True:
line = buf.readline()
if line == '':
break
if line.find('<ele>') == 0:
hr = hr + numpy.random.normal(0.1, 1)
cad = 80 + numpy.random.normal(0, 1)
hacked_gpx_str = hacked_gpx_str + "<extensions> <gpxtpx:TrackPointExtension> <gpxtpx:hr>" + \
str(hr) + "</gpxtpx:hr> <gpxtpx:cad>" + str(cad) +"</gpxtpx:cad> </gpxtpx:TrackPointExtension> </extensions>\n"
elif line.find('<gpx ') == 0:
hacked_gpx_str = hacked_gpx_str + '<gpx creator="StravaGPX" version="1.1" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3">'
else:
hacked_gpx_str = hacked_gpx_str + line
strava_client = Client(access_token=MY_STRAVA_TOKEN)
strava_client.upload_activity(
activity_file=BytesIO(hacked_gpx_str),
data_type='gpx',
name=None,
activity_type='ride')
print "Nice ride!"
Comments