Ejemplo n.º 1
0
    def create_random_activity(svc=None,
                               actType=ActivityType.Other,
                               tz=False,
                               record=None,
                               withPauses=True,
                               withLaps=True):
        ''' creates completely random activity with valid waypoints and data '''
        act = TestTools.create_blank_activity(svc, actType, record=record)

        if tz is True:
            tz = pytz.timezone("America/Atikokan")
            act.TZ = tz
        elif tz is not False:
            act.TZ = tz

        if act.CountTotalWaypoints() > 0:
            raise ValueError("Waypoint list already populated")
        # this is entirely random in case the testing account already has events in it (API doesn't support delete, etc)
        act.StartTime = datetime(2011, 12, 13, 14, 15, 16)
        if tz is not False:
            if hasattr(tz, "localize"):
                act.StartTime = tz.localize(act.StartTime)
            else:
                act.StartTime = act.StartTime.replace(tzinfo=tz)
        act.EndTime = act.StartTime + timedelta(
            0, random.randint(60 * 5, 60 * 60)
        )  # don't really need to upload 1000s of pts to test this...
        act.Stats.Distance = ActivityStatistic(ActivityStatisticUnit.Meters,
                                               value=random.random() * 10000)
        act.Name = str(random.random())
        paused = False
        waypointTime = act.StartTime
        backToBackPauses = False
        act.Laps = []
        lap = Lap(startTime=act.StartTime)
        while waypointTime < act.EndTime:
            wp = Waypoint()
            if waypointTime == act.StartTime:
                wp.Type = WaypointType.Start
            wp.Timestamp = waypointTime
            wp.Location = Location(
                random.random() * 180 - 90,
                random.random() * 180 - 90,
                random.random() *
                1000)  # this is gonna be one intense activity

            if not (wp.HR == wp.Cadence == wp.Calories == wp.Power == wp.Temp
                    == None):
                raise ValueError("Waypoint did not initialize cleanly")
            if svc.SupportsHR:
                wp.HR = float(random.randint(90, 180))
            if svc.SupportsPower:
                wp.Power = float(random.randint(0, 1000))
            if svc.SupportsCalories:
                wp.Calories = float(random.randint(0, 500))
            if svc.SupportsCadence:
                wp.Cadence = float(random.randint(0, 100))
            if svc.SupportsTemp:
                wp.Temp = float(random.randint(0, 100))

            if withPauses and (random.randint(40, 50) == 42 or backToBackPauses
                               ) and not paused:  # pause quite often
                wp.Type = WaypointType.Pause
                paused = True

            elif paused:
                paused = False
                wp.Type = WaypointType.Resume
                backToBackPauses = not backToBackPauses

            waypointTime += timedelta(0, int(random.random() +
                                             9.5))  # 10ish seconds

            lap.Waypoints.append(wp)
            if waypointTime > act.EndTime:
                wp.Timestamp = act.EndTime
                wp.Type = WaypointType.End
            elif withLaps and wp.Timestamp < act.EndTime and random.randint(
                    40, 60) == 42:
                # occasionally start new laps
                lap.EndTime = wp.Timestamp
                act.Laps.append(lap)
                lap = Lap(startTime=waypointTime)

        # Final lap
        lap.EndTime = act.EndTime
        act.Laps.append(lap)
        if act.CountTotalWaypoints() == 0:
            raise ValueError("No waypoints populated")

        act.CalculateUID()
        act.EnsureTZ()

        return act
Ejemplo n.º 2
0
    def DownloadActivity(self, svcRecord, activity):
        if activity.ServiceData["Manual"]:  # I should really add a param to DownloadActivity for this value as opposed to constantly doing this
            # We've got as much information as we're going to get - we need to copy it into a Lap though.
            activity.Laps = [Lap(startTime=activity.StartTime, endTime=activity.EndTime, stats=activity.Stats)]
            return activity
        activityID = activity.ServiceData["ActivityID"]

        self._globalRateLimit()
        streamdata = requests.get("https://www.strava.com/api/v3/activities/" + str(activityID) + "/streams/time,altitude,heartrate,cadence,watts,temp,moving,latlng", headers=self._apiHeaders(svcRecord))
        if streamdata.status_code == 401:
            raise APIException("No authorization to download activity", block=True, user_exception=UserException(UserExceptionType.Authorization, intervention_required=True))

        try:
            streamdata = streamdata.json()
        except:
            raise APIException("Stream data returned is not JSON")

        if "message" in streamdata and streamdata["message"] == "Record Not Found":
            raise APIException("Could not find activity")

        ridedata = {}
        for stream in streamdata:
            ridedata[stream["type"]] = stream["data"]

        lap = Lap(stats=activity.Stats, startTime=activity.StartTime, endTime=activity.EndTime) # Strava doesn't support laps, but we need somewhere to put the waypoints.
        activity.Laps = [lap]
        lap.Waypoints = []

        hasHR = "heartrate" in ridedata and len(ridedata["heartrate"]) > 0
        hasCadence = "cadence" in ridedata and len(ridedata["cadence"]) > 0
        hasTemp = "temp" in ridedata and len(ridedata["temp"]) > 0
        hasPower = ("watts" in ridedata and len(ridedata["watts"]) > 0)
        hasAltitude = "altitude" in ridedata and len(ridedata["altitude"]) > 0

        if "error" in ridedata:
            raise APIException("Strava error " + ridedata["error"])

        waypointCt = len(ridedata["time"])
        for idx in range(0, waypointCt - 1):

            waypoint = Waypoint(activity.StartTime + timedelta(0, ridedata["time"][idx]))
            if "latlng" in ridedata:
                latlng = ridedata["latlng"][idx]
                waypoint.Location = Location(latlng[0], latlng[1], None)
                if waypoint.Location.Longitude == 0 and waypoint.Location.Latitude == 0:
                    waypoint.Location.Longitude = None
                    waypoint.Location.Latitude = None

            if hasAltitude:
                if not waypoint.Location:
                    waypoint.Location = Location(None, None, None)
                waypoint.Location.Altitude = float(ridedata["altitude"][idx])

            if idx == 0:
                waypoint.Type = WaypointType.Start
            elif idx == waypointCt - 2:
                waypoint.Type = WaypointType.End

            if hasHR:
                waypoint.HR = ridedata["heartrate"][idx]
            if hasCadence:
                waypoint.Cadence = ridedata["cadence"][idx]
            if hasTemp:
                waypoint.Temp = ridedata["temp"][idx]
            if hasPower:
                waypoint.Power = ridedata["watts"][idx]
            lap.Waypoints.append(waypoint)

        return activity
Ejemplo n.º 3
0
    def DownloadActivity(self, svcRecord, activity):
        if activity.ServiceData[
                "Manual"]:  # I should really add a param to DownloadActivity for this value as opposed to constantly doing this
            # We've got as much information as we're going to get - we need to copy it into a Lap though.
            activity.Laps = [
                Lap(startTime=activity.StartTime,
                    endTime=activity.EndTime,
                    stats=activity.Stats)
            ]
            return activity
        activityID = activity.ServiceData["ActivityID"]

        self._globalRateLimit()
        streamdata = requests.get(
            "https://www.strava.com/api/v3/activities/" + str(activityID) +
            "/streams/time,altitude,heartrate,cadence,watts,temp,moving,latlng,distance,velocity_smooth",
            headers=self._apiHeaders(svcRecord))
        if streamdata.status_code == 401:
            raise APIException("No authorization to download activity",
                               block=True,
                               user_exception=UserException(
                                   UserExceptionType.Authorization,
                                   intervention_required=True))

        try:
            streamdata = streamdata.json()
        except:
            raise APIException("Stream data returned is not JSON")

        if "message" in streamdata and streamdata[
                "message"] == "Record Not Found":
            raise APIException("Could not find activity")

        ridedata = {}
        for stream in streamdata:
            ridedata[stream["type"]] = stream["data"]

        lap = Lap(
            stats=activity.Stats,
            startTime=activity.StartTime,
            endTime=activity.EndTime
        )  # Strava doesn't support laps, but we need somewhere to put the waypoints.
        activity.Laps = [lap]
        lap.Waypoints = []

        hasHR = "heartrate" in ridedata and len(ridedata["heartrate"]) > 0
        hasCadence = "cadence" in ridedata and len(ridedata["cadence"]) > 0
        hasTemp = "temp" in ridedata and len(ridedata["temp"]) > 0
        hasPower = ("watts" in ridedata and len(ridedata["watts"]) > 0)
        hasAltitude = "altitude" in ridedata and len(ridedata["altitude"]) > 0
        hasDistance = "distance" in ridedata and len(ridedata["distance"]) > 0
        hasVelocity = "velocity_smooth" in ridedata and len(
            ridedata["velocity_smooth"]) > 0

        if "error" in ridedata:
            raise APIException("Strava error " + ridedata["error"])

        inPause = False

        waypointCt = len(ridedata["time"])
        for idx in range(0, waypointCt - 1):

            waypoint = Waypoint(activity.StartTime +
                                timedelta(0, ridedata["time"][idx]))
            if "latlng" in ridedata:
                latlng = ridedata["latlng"][idx]
                waypoint.Location = Location(latlng[0], latlng[1], None)
                if waypoint.Location.Longitude == 0 and waypoint.Location.Latitude == 0:
                    waypoint.Location.Longitude = None
                    waypoint.Location.Latitude = None

            if hasAltitude:
                if not waypoint.Location:
                    waypoint.Location = Location(None, None, None)
                waypoint.Location.Altitude = float(ridedata["altitude"][idx])

            # When pausing, Strava sends this format:
            # idx = 100 ; time = 1000; moving = true
            # idx = 101 ; time = 1001; moving = true  => convert to Pause
            # idx = 102 ; time = 2001; moving = false => convert to Resume: (2001-1001) seconds pause
            # idx = 103 ; time = 2002; moving = true

            if idx == 0:
                waypoint.Type = WaypointType.Start
            elif idx == waypointCt - 2:
                waypoint.Type = WaypointType.End
            elif idx < waypointCt - 2 and ridedata["moving"][idx +
                                                             1] and inPause:
                waypoint.Type = WaypointType.Resume
                inPause = False
            elif idx < waypointCt - 2 and not ridedata["moving"][
                    idx + 1] and not inPause:
                waypoint.Type = WaypointType.Pause
                inPause = True

            if hasHR:
                waypoint.HR = ridedata["heartrate"][idx]
            if hasCadence:
                waypoint.Cadence = ridedata["cadence"][idx]
            if hasTemp:
                waypoint.Temp = ridedata["temp"][idx]
            if hasPower:
                waypoint.Power = ridedata["watts"][idx]
            if hasVelocity:
                waypoint.Speed = ridedata["velocity_smooth"][idx]
            if hasDistance:
                waypoint.Distance = ridedata["distance"][idx]
            lap.Waypoints.append(waypoint)

        return activity
Ejemplo n.º 4
0
    def _process_lap_waypoints(self, activity, ridedata, lapdata):

        hasHR = "heartrate" in ridedata and len(ridedata["heartrate"]) > 0
        hasCadence = "cadence" in ridedata and len(ridedata["cadence"]) > 0
        hasTemp = "temp" in ridedata and len(ridedata["temp"]) > 0
        hasPower = ("watts" in ridedata and len(ridedata["watts"]) > 0)
        hasAltitude = "altitude" in ridedata and len(ridedata["altitude"]) > 0
        hasDistance = "distance" in ridedata and len(ridedata["distance"]) > 0
        hasVelocity = "velocity_smooth" in ridedata and len(
            ridedata["velocity_smooth"]) > 0

        inPause = False
        waypointCt = len(ridedata["time"])

        lapWaypoints = []
        waypoinStartIndex = lapdata["start_index"]
        waypoinEndIndex = lapdata["end_index"]

        powerSum = 0
        hrSum = 0
        hrMax = 0

        for idx in range(waypoinStartIndex, waypoinEndIndex):

            waypoint = Waypoint(activity.StartTime +
                                timedelta(0, ridedata["time"][idx]))
            if "latlng" in ridedata:
                latlng = ridedata["latlng"][idx]
                waypoint.Location = Location(latlng[0], latlng[1], None)
                if waypoint.Location.Longitude == 0 and waypoint.Location.Latitude == 0:
                    waypoint.Location.Longitude = None
                    waypoint.Location.Latitude = None

            if hasAltitude:
                if not waypoint.Location:
                    waypoint.Location = Location(None, None, None)
                waypoint.Location.Altitude = float(ridedata["altitude"][idx])

            # When pausing, Strava sends this format:
            # idx = 100 ; time = 1000; moving = true
            # idx = 101 ; time = 1001; moving = true  => convert to Pause
            # idx = 102 ; time = 2001; moving = false => convert to Resume: (2001-1001) seconds pause
            # idx = 103 ; time = 2002; moving = true

            if idx == 0:
                waypoint.Type = WaypointType.Start
            elif idx == waypointCt - 2:
                waypoint.Type = WaypointType.End
            elif idx < waypointCt - 2 and ridedata["moving"][idx +
                                                             1] and inPause:
                waypoint.Type = WaypointType.Resume
                inPause = False
            elif idx < waypointCt - 2 and not ridedata["moving"][
                    idx + 1] and not inPause:
                waypoint.Type = WaypointType.Pause
                inPause = True

            if hasHR:
                waypoint.HR = ridedata["heartrate"][idx]
                hrSum += waypoint.HR if waypoint.HR else 0
                hrMax = waypoint.HR if waypoint.HR > hrMax else hrMax
            if hasCadence:
                waypoint.Cadence = ridedata["cadence"][idx]
            if hasTemp:
                waypoint.Temp = ridedata["temp"][idx]
            if hasPower:
                waypoint.Power = ridedata["watts"][idx]
                powerSum += waypoint.Power if waypoint.Power else 0
            if hasVelocity:
                waypoint.Speed = ridedata["velocity_smooth"][idx]
            if hasDistance:
                waypoint.Distance = ridedata["distance"][idx]
            lapWaypoints.append(waypoint)

        pointsCount = len(lapWaypoints)
        stats = ActivityStatistics()

        stats.Distance = ActivityStatistic(ActivityStatisticUnit.Meters,
                                           value=lapdata["distance"])
        if "max_speed" in lapdata or "average_speed" in lapdata:
            stats.Speed = ActivityStatistic(
                ActivityStatisticUnit.MetersPerSecond,
                avg=lapdata["average_speed"]
                if "average_speed" in lapdata else None,
                max=lapdata["max_speed"] if "max_speed" in lapdata else None)
        stats.MovingTime = ActivityStatistic(
            ActivityStatisticUnit.Seconds,
            value=lapdata["moving_time"] if "moving_time" in lapdata
            and lapdata["moving_time"] > 0 else None)
        if "average_cadence" in lapdata:
            stats.Cadence.update(
                ActivityStatistic(ActivityStatisticUnit.RevolutionsPerMinute,
                                  avg=lapdata["average_cadence"]))
        # Activity could have laps with no trackpoints
        if pointsCount > 0:
            if hasHR:
                stats.HR.update(
                    ActivityStatistic(ActivityStatisticUnit.BeatsPerMinute,
                                      avg=hrSum / pointsCount,
                                      max=hrMax))
            if hasPower:
                stats.Power = ActivityStatistic(ActivityStatisticUnit.Watts,
                                                avg=powerSum / pointsCount)

        return lapWaypoints, stats
Ejemplo n.º 5
0
    def create_random_activity(svc=None, actType=ActivityType.Other, tz=False, record=None):
        ''' creates completely random activity with valid waypoints and data '''
        act = TestTools.create_blank_activity(svc, actType, record=record)

        if tz is True:
            tz = pytz.timezone(pytz.all_timezones[random.randint(0, len(pytz.all_timezones) - 1)])
            act.TZ = tz
        elif tz is not False:
            act.TZ = tz

        if len(act.Waypoints) > 0:
            raise ValueError("Waypoint list already populated")
        # this is entirely random in case the testing account already has events in it (API doesn't support delete, etc)
        act.StartTime = datetime(random.randint(2000, 2020), random.randint(1, 12), random.randint(1, 28), random.randint(0, 23), random.randint(0, 59), random.randint(0, 59))
        if tz is not False:
            if hasattr(tz, "localize"):
                act.StartTime = tz.localize(act.StartTime)
            else:
                act.StartTime = act.StartTime.replace(tzinfo=tz)
        act.EndTime = act.StartTime + timedelta(0, random.randint(60 * 5, 60 * 60))  # don't really need to upload 1000s of pts to test this...
        act.Stats.Distance = ActivityStatistic(ActivityStatisticUnit.Meters, value=random.random() * 10000)
        act.Name = str(random.random())
        paused = False
        waypointTime = act.StartTime
        backToBackPauses = False
        while waypointTime < act.EndTime:
            wp = Waypoint()
            if waypointTime == act.StartTime:
                wp.Type = WaypointType.Start
            wp.Timestamp = waypointTime
            wp.Location = Location(random.random() * 180 - 90, random.random() * 180 - 90, random.random() * 1000)  # this is gonna be one intense activity

            if not (wp.HR == wp.Cadence == wp.Calories == wp.Power == wp.Temp == None):
                raise ValueError("Waypoint did not initialize cleanly")
            if svc.SupportsHR:
                wp.HR = float(random.randint(90, 180))
            if svc.SupportsPower:
                wp.Power = float(random.randint(0, 1000))
            if svc.SupportsCalories:
                wp.Calories = float(random.randint(0, 500))
            if svc.SupportsCadence:
                wp.Cadence = float(random.randint(0, 100))
            if svc.SupportsTemp:
                wp.Temp = float(random.randint(0, 100))

            if (random.randint(40, 50) == 42 or backToBackPauses) and not paused:  # pause quite often
                wp.Type = WaypointType.Pause
                paused = True

            elif paused:
                paused = False
                wp.Type = WaypointType.Resume
                backToBackPauses = not backToBackPauses

            waypointTime += timedelta(0, int(random.random() + 9.5))  # 10ish seconds

            if waypointTime > act.EndTime:
                wp.Timestamp = act.EndTime
                wp.Type = WaypointType.End
            act.Waypoints.append(wp)
        if len(act.Waypoints) == 0:
            raise ValueError("No waypoints populated")
        return act
Ejemplo n.º 6
0
    def DownloadActivity(self, svcRecord, activity):
        if activity.ServiceData["Manual"]:  # I should really add a param to DownloadActivity for this value as opposed to constantly doing this
            # We've got as much information as we're going to get - we need to copy it into a Lap though.
            activity.Laps = [Lap(startTime=activity.StartTime, endTime=activity.EndTime, stats=activity.Stats)]
            return activity
        activityID = activity.ServiceData["ActivityID"]

        streamdata = requests.get("https://www.strava.com/api/v3/activities/" + str(activityID) + "/streams/time,altitude,heartrate,cadence,watts,temp,moving,latlng", headers=self._apiHeaders(svcRecord))
        if streamdata.status_code == 401:
            self._logAPICall("download", (svcRecord.ExternalID, str(activity.StartTime)), "auth")
            raise APIException("No authorization to download activity", block=True, user_exception=UserException(UserExceptionType.Authorization, intervention_required=True))

        try:
            streamdata = streamdata.json()
        except:
            raise APIException("Stream data returned is not JSON")

        if "message" in streamdata and streamdata["message"] == "Record Not Found":
            self._logAPICall("download", (svcRecord.ExternalID, str(activity.StartTime)), "missing")
            raise APIException("Could not find activity")

        ridedata = {}
        for stream in streamdata:
            ridedata[stream["type"]] = stream["data"]

        lap = Lap(stats=activity.Stats, startTime=activity.StartTime, endTime=activity.EndTime) # Strava doesn't support laps, but we need somewhere to put the waypoints.
        activity.Laps = [lap]
        lap.Waypoints = []

        hasHR = "heartrate" in ridedata and len(ridedata["heartrate"]) > 0
        hasCadence = "cadence" in ridedata and len(ridedata["cadence"]) > 0
        hasTemp = "temp" in ridedata and len(ridedata["temp"]) > 0
        hasPower = ("watts" in ridedata and len(ridedata["watts"]) > 0)
        hasAltitude = "altitude" in ridedata and len(ridedata["altitude"]) > 0
        hasMovingData = "moving" in ridedata and len(ridedata["moving"]) > 0
        moving = True

        if "error" in ridedata:
            self._logAPICall("download", (svcRecord.ExternalID, str(activity.StartTime)), "data")
            raise APIException("Strava error " + ridedata["error"])

        hasLocation = False
        waypointCt = len(ridedata["time"])
        for idx in range(0, waypointCt - 1):
            latlng = ridedata["latlng"][idx]

            waypoint = Waypoint(activity.StartTime + timedelta(0, ridedata["time"][idx]))
            latlng = ridedata["latlng"][idx]
            waypoint.Location = Location(latlng[0], latlng[1], None)
            if waypoint.Location.Longitude == 0 and waypoint.Location.Latitude == 0:
                waypoint.Location.Longitude = None
                waypoint.Location.Latitude = None
            else:  # strava only returns 0 as invalid coords, so no need to check for null (update: ??)
                hasLocation = True
            if hasAltitude:
                waypoint.Location.Altitude = float(ridedata["altitude"][idx])

            if idx == 0:
                waypoint.Type = WaypointType.Start
            elif idx == waypointCt - 2:
                waypoint.Type = WaypointType.End
            elif hasMovingData and not moving and ridedata["moving"][idx] is True:
                waypoint.Type = WaypointType.Resume
                moving = True
            elif hasMovingData and ridedata["moving"][idx] is False:
                waypoint.Type = WaypointType.Pause
                moving = False

            if hasHR:
                waypoint.HR = ridedata["heartrate"][idx]
            if hasCadence:
                waypoint.Cadence = ridedata["cadence"][idx]
            if hasTemp:
                waypoint.Temp = ridedata["temp"][idx]
            if hasPower:
                waypoint.Power = ridedata["watts"][idx]
            lap.Waypoints.append(waypoint)
        if not hasLocation:
            self._logAPICall("download", (svcRecord.ExternalID, str(activity.StartTime)), "faulty")
            raise APIExcludeActivity("No waypoints with location", activityId=activityID, userException=UserException(UserExceptionType.Corrupt))
        self._logAPICall("download", (svcRecord.ExternalID, str(activity.StartTime)), None)
        return activity
Ejemplo n.º 7
0
    def DownloadActivity(self, svcRecord, activity):
        # thanks to Cosmo Catalano for the API reference code
        activityID = [
            x["ActivityID"] for x in activity.UploadedTo
            if x["Connection"] == svcRecord
        ][0]

        streamdata = requests.get(
            "https://www.strava.com/api/v3/activities/" + str(activityID) +
            "/streams/time,altitude,heartrate,cadence,watts,watts_calc,temp,resting,latlng",
            headers=self._apiHeaders(svcRecord))
        if streamdata.status_code == 401:
            raise APIException("No authorization to download activity",
                               block=True,
                               user_exception=UserException(
                                   UserExceptionType.Authorization,
                                   intervention_required=True))

        streamdata = streamdata.json()

        if "message" in streamdata and streamdata[
                "message"] == "Record Not Found":
            raise APIException("Could not find activity")

        ridedata = {}
        for stream in streamdata:
            ridedata[stream["type"]] = stream["data"]

        activity.Waypoints = []

        hasHR = "heartrate" in ridedata and len(ridedata["heartrate"]) > 0
        hasCadence = "cadence" in ridedata and len(ridedata["cadence"]) > 0
        hasTemp = "temp" in ridedata and len(ridedata["temp"]) > 0
        hasPower = ("watts" in ridedata and len(ridedata["watts"]) > 0)
        hasAltitude = "altitude" in ridedata and len(ridedata["altitude"]) > 0
        hasRestingData = "resting" in ridedata and len(ridedata["resting"]) > 0
        moving = True

        if "error" in ridedata:
            raise APIException("Strava error " + ridedata["error"])

        hasLocation = False
        waypointCt = len(ridedata["time"])
        for idx in range(0, waypointCt - 1):
            latlng = ridedata["latlng"][idx]

            waypoint = Waypoint(activity.StartTime +
                                timedelta(0, ridedata["time"][idx]))
            latlng = ridedata["latlng"][idx]
            waypoint.Location = Location(latlng[0], latlng[1], None)
            if waypoint.Location.Longitude == 0 and waypoint.Location.Latitude == 0:
                waypoint.Location.Longitude = None
                waypoint.Location.Latitude = None
            else:  # strava only returns 0 as invalid coords, so no need to check for null (update: ??)
                hasLocation = True
            if hasAltitude:
                waypoint.Location.Altitude = float(ridedata["altitude"][idx])

            if idx == 0:
                waypoint.Type = WaypointType.Start
            elif idx == waypointCt - 2:
                waypoint.Type = WaypointType.End
            elif hasRestingData and not moving and ridedata["resting"][
                    idx] is False:
                waypoint.Type = WaypointType.Resume
                moving = True
            elif hasRestingData and ridedata["resting"][idx] is True:
                waypoint.Type = WaypointType.Pause
                moving = False

            if hasHR:
                waypoint.HR = ridedata["heartrate"][idx]
            if hasCadence:
                waypoint.Cadence = ridedata["cadence"][idx]
            if hasTemp:
                waypoint.Temp = ridedata["temp"][idx]
            if hasPower:
                waypoint.Power = ridedata["watts"][idx]
            activity.Waypoints.append(waypoint)
        if not hasLocation:
            raise APIExcludeActivity("No waypoints with location",
                                     activityId=activityID)
        return activity
Ejemplo n.º 8
0
    def DownloadActivity(self, svcRecord, activity):
        # thanks to Cosmo Catalano for the API reference code
        activityID = [x["ActivityID"] for x in activity.UploadedTo if x["Connection"] == svcRecord][0]

        streamdata = requests.get("https://www.strava.com/api/v3/activities/" + str(activityID) + "/streams/time,altitude,heartrate,cadence,watts,watts_calc,temp,resting,latlng", headers=self._apiHeaders(svcRecord))
        if streamdata.status_code == 401:
            raise APIException("No authorization to download activity", block=True, user_exception=UserException(UserExceptionType.Authorization, intervention_required=True))

        streamdata = streamdata.json()

        if "message" in streamdata and streamdata["message"] == "Record Not Found":
            raise APIException("Could not find activity")

        ridedata = {}
        for stream in streamdata:
            ridedata[stream["type"]] = stream["data"]

        activity.Waypoints = []

        hasHR = "heartrate" in ridedata and len(ridedata["heartrate"]) > 0
        hasCadence = "cadence" in ridedata and len(ridedata["cadence"]) > 0
        hasTemp = "temp" in ridedata and len(ridedata["temp"]) > 0
        hasPower = ("watts" in ridedata and len(ridedata["watts"]) > 0) or ("watts_calc" in ridedata and len(ridedata["watts_calc"]) > 0)
        hasAltitude = "altitude" in ridedata and len(ridedata["altitude"]) > 0
        hasRestingData = "resting" in ridedata and len(ridedata["resting"]) > 0
        moving = True

        if "error" in ridedata:
            raise APIException("Strava error " + ridedata["error"])

        hasLocation = False
        waypointCt = len(ridedata["time"])
        for idx in range(0, waypointCt - 1):
            latlng = ridedata["latlng"][idx]

            waypoint = Waypoint(activity.StartTime + timedelta(0, ridedata["time"][idx]))
            latlng = ridedata["latlng"][idx]
            waypoint.Location = Location(latlng[0], latlng[1], None)
            if waypoint.Location.Longitude == 0 and waypoint.Location.Latitude == 0:
                waypoint.Location.Longitude = None
                waypoint.Location.Latitude = None
            else:  # strava only returns 0 as invalid coords, so no need to check for null (update: ??)
                hasLocation = True
            if hasAltitude:
                waypoint.Location.Altitude = float(ridedata["altitude"][idx])

            if idx == 0:
                waypoint.Type = WaypointType.Start
            elif idx == waypointCt - 2:
                waypoint.Type = WaypointType.End
            elif hasRestingData and not moving and ridedata["resting"][idx] is False:
                waypoint.Type = WaypointType.Resume
                moving = True
            elif hasRestingData and ridedata["resting"][idx] is True:
                waypoint.Type = WaypointType.Pause
                moving = False

            if hasHR:
                waypoint.HR = ridedata["heartrate"][idx]
            if hasCadence:
                waypoint.Cadence = ridedata["cadence"][idx]
            if hasTemp:
                waypoint.Temp = ridedata["temp"][idx]
            if hasPower:
                waypoint.Power = ridedata["watts"][idx] if "watts" in ridedata else ridedata["watts_calc"][idx]
            activity.Waypoints.append(waypoint)
        if not hasLocation:
            raise APIExcludeActivity("No waypoints with location", activityId=activityID)
        return activity
Ejemplo n.º 9
0
    def DownloadActivity(self, svcRecord, activity):
        if activity.ServiceData[
                "Manual"]:  # I should really add a param to DownloadActivity for this value as opposed to constantly doing this
            # We've got as much information as we're going to get - we need to copy it into a Lap though.
            activity.Laps = [
                Lap(startTime=activity.StartTime,
                    endTime=activity.EndTime,
                    stats=activity.Stats)
            ]
            return activity
        activityID = activity.ServiceData["ActivityID"]

        streamdata = requests.get(
            "https://www.strava.com/api/v3/activities/" + str(activityID) +
            "/streams/time,altitude,heartrate,cadence,watts,temp,moving,latlng",
            headers=self._apiHeaders(svcRecord))
        if streamdata.status_code == 401:
            self._logAPICall("download",
                             (svcRecord.ExternalID, str(activity.StartTime)),
                             "auth")
            raise APIException("No authorization to download activity",
                               block=True,
                               user_exception=UserException(
                                   UserExceptionType.Authorization,
                                   intervention_required=True))

        try:
            streamdata = streamdata.json()
        except:
            raise APIException("Stream data returned is not JSON")

        if "message" in streamdata and streamdata[
                "message"] == "Record Not Found":
            self._logAPICall("download",
                             (svcRecord.ExternalID, str(activity.StartTime)),
                             "missing")
            raise APIException("Could not find activity")

        ridedata = {}
        for stream in streamdata:
            ridedata[stream["type"]] = stream["data"]

        lap = Lap(
            stats=activity.Stats,
            startTime=activity.StartTime,
            endTime=activity.EndTime
        )  # Strava doesn't support laps, but we need somewhere to put the waypoints.
        activity.Laps = [lap]
        lap.Waypoints = []

        hasHR = "heartrate" in ridedata and len(ridedata["heartrate"]) > 0
        hasCadence = "cadence" in ridedata and len(ridedata["cadence"]) > 0
        hasTemp = "temp" in ridedata and len(ridedata["temp"]) > 0
        hasPower = ("watts" in ridedata and len(ridedata["watts"]) > 0)
        hasAltitude = "altitude" in ridedata and len(ridedata["altitude"]) > 0
        hasMovingData = "moving" in ridedata and len(ridedata["moving"]) > 0
        moving = True

        if "error" in ridedata:
            self._logAPICall("download",
                             (svcRecord.ExternalID, str(activity.StartTime)),
                             "data")
            raise APIException("Strava error " + ridedata["error"])

        hasLocation = False
        waypointCt = len(ridedata["time"])
        for idx in range(0, waypointCt - 1):
            latlng = ridedata["latlng"][idx]

            waypoint = Waypoint(activity.StartTime +
                                timedelta(0, ridedata["time"][idx]))
            latlng = ridedata["latlng"][idx]
            waypoint.Location = Location(latlng[0], latlng[1], None)
            if waypoint.Location.Longitude == 0 and waypoint.Location.Latitude == 0:
                waypoint.Location.Longitude = None
                waypoint.Location.Latitude = None
            else:  # strava only returns 0 as invalid coords, so no need to check for null (update: ??)
                hasLocation = True
            if hasAltitude:
                waypoint.Location.Altitude = float(ridedata["altitude"][idx])

            if idx == 0:
                waypoint.Type = WaypointType.Start
            elif idx == waypointCt - 2:
                waypoint.Type = WaypointType.End
            elif hasMovingData and not moving and ridedata["moving"][
                    idx] is True:
                waypoint.Type = WaypointType.Resume
                moving = True
            elif hasMovingData and ridedata["moving"][idx] is False:
                waypoint.Type = WaypointType.Pause
                moving = False

            if hasHR:
                waypoint.HR = ridedata["heartrate"][idx]
            if hasCadence:
                waypoint.Cadence = ridedata["cadence"][idx]
            if hasTemp:
                waypoint.Temp = ridedata["temp"][idx]
            if hasPower:
                waypoint.Power = ridedata["watts"][idx]
            lap.Waypoints.append(waypoint)
        if not hasLocation:
            self._logAPICall("download",
                             (svcRecord.ExternalID, str(activity.StartTime)),
                             "faulty")
            raise APIExcludeActivity("No waypoints with location",
                                     activityId=activityID,
                                     userException=UserException(
                                         UserExceptionType.Corrupt))
        self._logAPICall("download",
                         (svcRecord.ExternalID, str(activity.StartTime)), None)
        return activity
Ejemplo n.º 10
0
    def create_random_activity(svc=None,
                               actType=ActivityType.Other,
                               tz=False,
                               record=None):
        ''' creates completely random activity with valid waypoints and data '''
        act = TestTools.create_blank_activity(svc, actType, record=record)

        if tz is True:
            tz = pytz.timezone(pytz.all_timezones[random.randint(
                0,
                len(pytz.all_timezones) - 1)])
            act.TZ = tz
        elif tz is not False:
            act.TZ = tz

        if len(act.Waypoints) > 0:
            raise ValueError("Waypoint list already populated")
        # this is entirely random in case the testing account already has events in it (API doesn't support delete, etc)
        act.StartTime = datetime(random.randint(2000, 2020),
                                 random.randint(1, 12), random.randint(1, 28),
                                 random.randint(0, 23), random.randint(0, 59),
                                 random.randint(0, 59))
        if tz is not False:
            if hasattr(tz, "localize"):
                act.StartTime = tz.localize(act.StartTime)
            else:
                act.StartTime = act.StartTime.replace(tzinfo=tz)
        act.EndTime = act.StartTime + timedelta(
            0, random.randint(60 * 5, 60 * 60)
        )  # don't really need to upload 1000s of pts to test this...
        act.Distance = random.random() * 10000
        act.Name = str(random.random())
        paused = False
        waypointTime = act.StartTime
        backToBackPauses = False
        while waypointTime < act.EndTime:
            wp = Waypoint()
            if waypointTime == act.StartTime:
                wp.Type = WaypointType.Start
            wp.Timestamp = waypointTime
            wp.Location = Location(
                random.random() * 180 - 90,
                random.random() * 180 - 90,
                random.random() *
                1000)  # this is gonna be one intense activity

            if not (wp.HR == wp.Cadence == wp.Calories == wp.Power == wp.Temp
                    == None):
                raise ValueError("Waypoint did not initialize cleanly")
            if svc.SupportsHR:
                wp.HR = float(random.randint(90, 180))
            if svc.SupportsPower:
                wp.Power = float(random.randint(0, 1000))
            if svc.SupportsCalories:
                wp.Calories = float(random.randint(0, 500))
            if svc.SupportsCadence:
                wp.Cadence = float(random.randint(0, 100))
            if svc.SupportsTemp:
                wp.Temp = float(random.randint(0, 100))

            if (random.randint(40, 50) == 42
                    or backToBackPauses) and not paused:  # pause quite often
                wp.Type = WaypointType.Pause
                paused = True

            elif paused:
                paused = False
                wp.Type = WaypointType.Resume
                backToBackPauses = not backToBackPauses

            waypointTime += timedelta(0, int(random.random() +
                                             9.5))  # 10ish seconds

            if waypointTime > act.EndTime:
                wp.Timestamp = act.EndTime
                wp.Type = WaypointType.End
            act.Waypoints.append(wp)
        if len(act.Waypoints) == 0:
            raise ValueError("No waypoints populated")
        return act
Ejemplo n.º 11
0
    def create_random_activity(svc=None, actType=ActivityType.Other, tz=False, record=None, withPauses=True, withLaps=True):
        ''' creates completely random activity with valid waypoints and data '''
        act = TestTools.create_blank_activity(svc, actType, record=record)

        if tz is True:
            tz = pytz.timezone("America/Atikokan")
            act.TZ = tz
        elif tz is not False:
            act.TZ = tz

        if act.CountTotalWaypoints() > 0:
            raise ValueError("Waypoint list already populated")
        # this is entirely random in case the testing account already has events in it (API doesn't support delete, etc)
        act.StartTime = datetime(2011, 12, 13, 14, 15, 16)
        if tz is not False:
            if hasattr(tz, "localize"):
                act.StartTime = tz.localize(act.StartTime)
            else:
                act.StartTime = act.StartTime.replace(tzinfo=tz)
        act.EndTime = act.StartTime + timedelta(0, random.randint(60 * 5, 60 * 60))  # don't really need to upload 1000s of pts to test this...
        act.Stats.Distance = ActivityStatistic(ActivityStatisticUnit.Meters, value=random.random() * 10000)
        act.Name = str(random.random())
        paused = False
        waypointTime = act.StartTime
        backToBackPauses = False
        act.Laps = []
        lap = Lap(startTime=act.StartTime)
        while waypointTime < act.EndTime:
            wp = Waypoint()
            if waypointTime == act.StartTime:
                wp.Type = WaypointType.Start
            wp.Timestamp = waypointTime
            wp.Location = Location(random.random() * 180 - 90, random.random() * 180 - 90, random.random() * 1000)  # this is gonna be one intense activity

            if not (wp.HR == wp.Cadence == wp.Calories == wp.Power == wp.Temp == None):
                raise ValueError("Waypoint did not initialize cleanly")
            if svc.SupportsHR:
                wp.HR = float(random.randint(90, 180))
            if svc.SupportsPower:
                wp.Power = float(random.randint(0, 1000))
            if svc.SupportsCalories:
                wp.Calories = float(random.randint(0, 500))
            if svc.SupportsCadence:
                wp.Cadence = float(random.randint(0, 100))
            if svc.SupportsTemp:
                wp.Temp = float(random.randint(0, 100))

            if withPauses and (random.randint(40, 50) == 42 or backToBackPauses) and not paused:  # pause quite often
                wp.Type = WaypointType.Pause
                paused = True

            elif paused:
                paused = False
                wp.Type = WaypointType.Resume
                backToBackPauses = not backToBackPauses

            waypointTime += timedelta(0, int(random.random() + 9.5))  # 10ish seconds

            lap.Waypoints.append(wp)
            if waypointTime > act.EndTime:
                wp.Timestamp = act.EndTime
                wp.Type = WaypointType.End
            elif withLaps and wp.Timestamp < act.EndTime and random.randint(40, 60) == 42:
                # occasionally start new laps
                lap.EndTime = wp.Timestamp
                act.Laps.append(lap)
                lap = Lap(startTime=waypointTime)

        # Final lap
        lap.EndTime = act.EndTime
        act.Laps.append(lap)
        if act.CountTotalWaypoints() == 0:
            raise ValueError("No waypoints populated")

        act.CalculateUID()
        act.EnsureTZ()

        return act
Ejemplo n.º 12
0
    def DownloadActivity(self, svcRecord, activity):
        if activity.ServiceData["Manual"]:  # I should really add a param to DownloadActivity for this value as opposed to constantly doing this
            # We've got as much information as we're going to get - we need to copy it into a Lap though.
            activity.Laps = [Lap(startTime=activity.StartTime, endTime=activity.EndTime, stats=activity.Stats)]
            return activity
        activityID = activity.ServiceData["ActivityID"]

        streamdata = self._requestWithAuth(lambda session: session.get("https://www.strava.com/api/v3/activities/" + str(activityID) + "/streams/time,altitude,heartrate,cadence,watts,temp,moving,latlng,distance,velocity_smooth"), svcRecord)
        if streamdata.status_code == 401:
            raise APIException("No authorization to download activity", block=True, user_exception=UserException(UserExceptionType.Authorization, intervention_required=True))

        try:
            streamdata = streamdata.json()
        except:
            raise APIException("Stream data returned is not JSON")

        if "message" in streamdata and streamdata["message"] == "Record Not Found":
            raise APIException("Could not find activity")

        ridedata = {}
        for stream in streamdata:
            ridedata[stream["type"]] = stream["data"]

        lap = Lap(stats=activity.Stats, startTime=activity.StartTime, endTime=activity.EndTime) # Strava doesn't support laps, but we need somewhere to put the waypoints.
        activity.Laps = [lap]
        lap.Waypoints = []

        hasHR = "heartrate" in ridedata and len(ridedata["heartrate"]) > 0
        hasCadence = "cadence" in ridedata and len(ridedata["cadence"]) > 0
        hasTemp = "temp" in ridedata and len(ridedata["temp"]) > 0
        hasPower = ("watts" in ridedata and len(ridedata["watts"]) > 0)
        hasAltitude = "altitude" in ridedata and len(ridedata["altitude"]) > 0
        hasDistance = "distance" in ridedata and len(ridedata["distance"]) > 0
        hasVelocity = "velocity_smooth" in ridedata and len(ridedata["velocity_smooth"]) > 0

        if "error" in ridedata:
            raise APIException("Strava error " + ridedata["error"])

        inPause = False

        waypointCt = len(ridedata["time"])
        for idx in range(0, waypointCt - 1):

            waypoint = Waypoint(activity.StartTime + timedelta(0, ridedata["time"][idx]))
            if "latlng" in ridedata:
                latlng = ridedata["latlng"][idx]
                waypoint.Location = Location(latlng[0], latlng[1], None)
                if waypoint.Location.Longitude == 0 and waypoint.Location.Latitude == 0:
                    waypoint.Location.Longitude = None
                    waypoint.Location.Latitude = None

            if hasAltitude:
                if not waypoint.Location:
                    waypoint.Location = Location(None, None, None)
                waypoint.Location.Altitude = float(ridedata["altitude"][idx])

            # When pausing, Strava sends this format:
            # idx = 100 ; time = 1000; moving = true
            # idx = 101 ; time = 1001; moving = true  => convert to Pause
            # idx = 102 ; time = 2001; moving = false => convert to Resume: (2001-1001) seconds pause
            # idx = 103 ; time = 2002; moving = true

            if idx == 0:
                waypoint.Type = WaypointType.Start
            elif idx == waypointCt - 2:
                waypoint.Type = WaypointType.End
            elif idx < waypointCt - 2 and ridedata["moving"][idx+1] and inPause:
                waypoint.Type = WaypointType.Resume
                inPause = False
            elif idx < waypointCt - 2 and not ridedata["moving"][idx+1] and not inPause:
                waypoint.Type = WaypointType.Pause
                inPause = True

            if hasHR:
                waypoint.HR = ridedata["heartrate"][idx]
            if hasCadence:
                waypoint.Cadence = ridedata["cadence"][idx]
            if hasTemp:
                waypoint.Temp = ridedata["temp"][idx]
            if hasPower:
                waypoint.Power = ridedata["watts"][idx]
            if hasVelocity:
                waypoint.Speed = ridedata["velocity_smooth"][idx]
            if hasDistance:
                waypoint.Distance = ridedata["distance"][idx]
            lap.Waypoints.append(waypoint)

        return activity