Beispiel #1
0
    def DownloadActivity(self, serviceRecord, activity):
        resp = self._oauthSession(serviceRecord).get("https://api.endomondo.com/api/1/workouts/%d" % activity.ServiceData["WorkoutID"], params={"fields": "points"})
        try:
            resp = resp.json()
        except ValueError:
            self._rateLimitBailout(resp)
            res_txt = resp.text
            raise APIException("Parse failure in Endomondo activity download: %s" % resp.status_code)
        lap = Lap(stats=activity.Stats, startTime=activity.StartTime, endTime=activity.EndTime)
        activity.Laps = [lap]

        activity.GPS = False

        old_location = None
        in_pause = False
        for pt in resp["points"]:
            wp = Waypoint()
            if "time" not in pt:
                # Manually-entered activities with a course attached to them have date-less waypoints
                # It'd be nice to transfer those courses, but it's a concept few other sites support AFAIK
                # So, ignore the points entirely
                continue
            wp.Timestamp = self._parseDate(pt["time"])

            if ("lat" in pt and "lng" in pt) or "alt" in pt:
                wp.Location = Location()
                if "lat" in pt and "lng" in pt:
                    wp.Location.Latitude = pt["lat"]
                    wp.Location.Longitude = pt["lng"]
                    activity.GPS = True
                if "alt" in pt:
                    wp.Location.Altitude = pt["alt"]

                if wp.Location == old_location:
                    # We have seen the point with the same coordinates
                    # before. This causes other services (e.g Strava) to
                    # interpret this as if we were standing for a while,
                    # which causes us having wrong activity time when
                    # importing. We mark the point as paused in hopes this
                    # fixes the issue.
                    in_pause = True
                    wp.Type = WaypointType.Pause
                elif in_pause:
                    in_pause = False
                    wp.Type = WaypointType.Resume

                old_location = wp.Location

            if "hr" in pt:
                wp.HR = pt["hr"]

            if "cad" in pt:
                wp.Cadence = pt["cad"]

            if "pow" in pt:
                wp.Power = pt["pow"]

            lap.Waypoints.append(wp)
        activity.Stationary = len(lap.Waypoints) == 0
        return activity
Beispiel #2
0
    def DownloadActivity(self, serviceRecord, activity):
        resp = self._oauthSession(serviceRecord).get("https://api.endomondo.com/api/1/workouts/%d" % activity.ServiceData["WorkoutID"], params={"fields": "points"})
        try:
            resp = resp.json()
        except ValueError:
            res_txt = resp.text
            raise APIException("Parse failure in Endomondo activity download: %s" % resp.status_code)
        lap = Lap(stats=activity.Stats, startTime=activity.StartTime, endTime=activity.EndTime)
        activity.Laps = [lap]

        activity.GPS = False

        for pt in resp["points"]:
            wp = Waypoint()
            wp.Timestamp = self._parseDate(pt["time"])

            if ("lat" in pt and "lng" in pt) or "alt" in pt:
                wp.Location = Location()
                if "lat" in pt and "lng" in pt:
                    wp.Location.Latitude = pt["lat"]
                    wp.Location.Longitude = pt["lng"]
                    activity.GPS = True
                if "alt" in pt:
                    wp.Location.Altitude = pt["alt"]

            if "hr" in pt:
                wp.HR = pt["hr"]

            if "cad" in pt:
                wp.Cadence = pt["cad"]

            lap.Waypoints.append(wp)
        activity.Stationary = len(lap.Waypoints) == 0
        return activity
Beispiel #3
0
    def DownloadActivity(self, serviceRecord, activity):
        resp = self._oauthSession(serviceRecord).get("https://api.endomondo.com/api/1/workouts/%d" % activity.ServiceData["WorkoutID"], params={"fields": "points"})
        try:
            resp = resp.json()
        except ValueError:
            self._rateLimitBailout(resp)
            res_txt = resp.text
            raise APIException("Parse failure in Endomondo activity download: %s" % resp.status_code)
        lap = Lap(stats=activity.Stats, startTime=activity.StartTime, endTime=activity.EndTime)
        activity.Laps = [lap]

        activity.GPS = False

        old_location = None
        in_pause = False
        for pt in resp["points"]:
            wp = Waypoint()
            if "time" not in pt:
                # Manually-entered activities with a course attached to them have date-less waypoints
                # It'd be nice to transfer those courses, but it's a concept few other sites support AFAIK
                # So, ignore the points entirely
                continue
            wp.Timestamp = self._parseDate(pt["time"])

            if ("lat" in pt and "lng" in pt) or "alt" in pt:
                wp.Location = Location()
                if "lat" in pt and "lng" in pt:
                    wp.Location.Latitude = pt["lat"]
                    wp.Location.Longitude = pt["lng"]
                    activity.GPS = True
                if "alt" in pt:
                    wp.Location.Altitude = pt["alt"]

                if wp.Location == old_location:
                    # We have seen the point with the same coordinates
                    # before. This causes other services (e.g Strava) to
                    # interpret this as if we were standing for a while,
                    # which causes us having wrong activity time when
                    # importing. We mark the point as paused in hopes this
                    # fixes the issue.
                    in_pause = True
                    wp.Type = WaypointType.Pause
                elif in_pause:
                    in_pause = False
                    wp.Type = WaypointType.Resume

                old_location = wp.Location

            if "hr" in pt:
                wp.HR = pt["hr"]

            if "cad" in pt:
                wp.Cadence = pt["cad"]

            if "pow" in pt:
                wp.Power = pt["pow"]

            lap.Waypoints.append(wp)
        activity.Stationary = len(lap.Waypoints) == 0
        return activity
Beispiel #4
0
    def DownloadActivity(self, serviceRecord, activity):
        resp = self._oauthSession(serviceRecord).get("https://api.endomondo.com/api/1/workouts/%d" % activity.ServiceData["WorkoutID"], params={"fields": "points"})
        try:
            resp = resp.json()
        except ValueError:
            self._rateLimitBailout(resp)
            res_txt = resp.text
            raise APIException("Parse failure in Endomondo activity download: %s" % resp.status_code)
        lap = Lap(stats=activity.Stats, startTime=activity.StartTime, endTime=activity.EndTime)
        activity.Laps = [lap]

        activity.GPS = False

        prevLon = 0.0
        prevLat = 0.0
        for pt in resp["points"]:
            wp = Waypoint()
            if "time" not in pt:
                # Manually-entered activities with a course attached to them have date-less waypoints
                # It'd be nice to transfer those courses, but it's a concept few other sites support AFAIK
                # So, ignore the points entirely
                continue
            wp.Timestamp = self._parseDate(pt["time"])

            if ("lat" in pt and "lng" in pt) or "alt" in pt:
                wp.Location = Location()
                if "lat" in pt and "lng" in pt:
                    wp.Location.Latitude = pt["lat"]
                    wp.Location.Longitude = pt["lng"]
                    if (wp.Location.Latitude == prevLat and wp.Location.Longitude == prevLon):
                        # we have seen the point with the same coordinates
                        # before. This causes other services (e.g Strava) to
                        # interpret this as if we were standing for a while,
                        # which causes us having wrong activity time when
                        # importing. We discard this entry to keep only unique
                        # ones to avoid this. This is still a hack :( However,
                        # I don't know if this will handle the situation when
                        # we are actually standing for some time in one place
                        # well...
                        continue;
                    prevLat = wp.Location.Latitude;
                    prevLon = wp.Location.Longitude;
                    activity.GPS = True
                if "alt" in pt:
                    wp.Location.Altitude = pt["alt"]

            if "hr" in pt:
                wp.HR = pt["hr"]

            if "cad" in pt:
                wp.Cadence = pt["cad"]

            lap.Waypoints.append(wp)
        activity.Stationary = len(lap.Waypoints) == 0
        return activity
Beispiel #5
0
        def stream_waypoint(offset, speed=None, distance=None, heartrate=None, calories=None, steps=None, watts=None, gps=None, **kwargs):
            wp = Waypoint()
            wp.Timestamp = activity.StartTime + timedelta(seconds=offset)
            wp.Speed = float(speed) if speed else None
            wp.Distance = float(distance) / 1000 if distance else None
            wp.HR = float(heartrate) if heartrate else None
            wp.Calories = float(calories) if calories else None
            wp.Power = float(watts) if watts else None

            if gps:
                wp.Location = Location(lat=float(gps["latitude"]), lon=float(gps["longitude"]), alt=float(gps["elevation"]))
            lap.Waypoints.append(wp)
Beispiel #6
0
    def DownloadActivity(self, serviceRecord, activity):
        resp = self._oauthSession(serviceRecord).get(
            "https://api.endomondo.com/api/1/workouts/%d" %
            activity.ServiceData["WorkoutID"],
            params={"fields": "points"})
        try:
            resp = resp.json()
        except ValueError:
            self._rateLimitBailout(resp)
            res_txt = resp.text
            raise APIException(
                "Parse failure in Endomondo activity download: %s" %
                resp.status_code)
        lap = Lap(stats=activity.Stats,
                  startTime=activity.StartTime,
                  endTime=activity.EndTime)
        activity.Laps = [lap]

        activity.GPS = False

        for pt in resp["points"]:
            wp = Waypoint()
            if "time" not in pt:
                # Manually-entered activities with a course attached to them have date-less waypoints
                # It'd be nice to transfer those courses, but it's a concept few other sites support AFAIK
                # So, ignore the points entirely
                continue
            wp.Timestamp = self._parseDate(pt["time"])

            if ("lat" in pt and "lng" in pt) or "alt" in pt:
                wp.Location = Location()
                if "lat" in pt and "lng" in pt:
                    wp.Location.Latitude = pt["lat"]
                    wp.Location.Longitude = pt["lng"]
                    activity.GPS = True
                if "alt" in pt:
                    wp.Location.Altitude = pt["alt"]

            if "hr" in pt:
                wp.HR = pt["hr"]

            if "cad" in pt:
                wp.Cadence = pt["cad"]

            lap.Waypoints.append(wp)
        activity.Stationary = len(lap.Waypoints) == 0
        return activity
Beispiel #7
0
    def DownloadActivity(self, serviceRecord, activity):
        workoutID = activity.ServiceData["WorkoutID"]
        logger.debug("DownloadActivity for %s" % workoutID)

        session = self._get_session(record=serviceRecord)

        resp = session.get(self._urlRoot + "/api/workout/%d" % workoutID)

        try:
            res = resp.json()
        except ValueError:
            raise APIException(
                "Parse failure in Motivato activity (%d) download: %s" %
                (workoutID, res.text))

        lap = Lap(stats=activity.Stats,
                  startTime=activity.StartTime,
                  endTime=activity.EndTime)
        activity.Laps = [lap]
        activity.GPS = False
        if "track" in res and "points" in res["track"]:
            for pt in res["track"]["points"]:
                wp = Waypoint()
                if "moment" not in pt:
                    continue
                wp.Timestamp = self._parseDateTime(pt["moment"])

                if ("lat" in pt and "lon" in pt) or "ele" in pt:
                    wp.Location = Location()
                    if "lat" in pt and "lon" in pt:
                        wp.Location.Latitude = pt["lat"]
                        wp.Location.Longitude = pt["lon"]
                        activity.GPS = True
                    if "ele" in pt:
                        wp.Location.Altitude = float(pt["ele"])

                if "bpm" in pt:
                    wp.HR = pt["bpm"]

                lap.Waypoints.append(wp)

        activity.Stationary = len(lap.Waypoints) == 0

        return activity
Beispiel #8
0
    def DownloadActivity(self, serviceRecord, activity):
        resp = self._oauthSession(serviceRecord).get(
            "https://api.endomondo.com/api/1/workouts/%d" %
            activity.ServiceData["WorkoutID"],
            params={"fields": "points"})
        try:
            resp = resp.json()
        except ValueError:
            res_txt = resp.text
            raise APIException(
                "Parse failure in Endomondo activity download: %s" %
                resp.status_code)
        lap = Lap(stats=activity.Stats,
                  startTime=activity.StartTime,
                  endTime=activity.EndTime)
        activity.Laps = [lap]

        activity.GPS = False

        for pt in resp["points"]:
            wp = Waypoint()
            wp.Timestamp = self._parseDate(pt["time"])

            if ("lat" in pt and "lng" in pt) or "alt" in pt:
                wp.Location = Location()
                if "lat" in pt and "lng" in pt:
                    wp.Location.Latitude = pt["lat"]
                    wp.Location.Longitude = pt["lng"]
                    activity.GPS = True
                if "alt" in pt:
                    wp.Location.Altitude = pt["alt"]

            if "hr" in pt:
                wp.HR = pt["hr"]

            if "cad" in pt:
                wp.Cadence = pt["cad"]

            lap.Waypoints.append(wp)
        activity.Stationary = len(lap.Waypoints) == 0
        return activity
Beispiel #9
0
    def DownloadActivity(self, serviceRecord, activity):
        workoutID = activity.ServiceData["WorkoutID"]
        logger.debug("DownloadActivity for %s" % workoutID);

        session = self._get_session(record=serviceRecord)

        resp = session.get(self._urlRoot + "/api/workout/%d" % workoutID)

        try:
            res = resp.json()
        except ValueError:
            raise APIException("Parse failure in Motivato activity (%d) download: %s" % (workoutID, res.text))

        lap = Lap(stats=activity.Stats, startTime=activity.StartTime, endTime=activity.EndTime)
        activity.Laps = [lap]
        activity.GPS = False
        if "track" in res and "points" in res["track"]:
            for pt in res["track"]["points"]:
                wp = Waypoint()
                if "moment" not in pt:
                    continue
                wp.Timestamp = self._parseDateTime(pt["moment"])

                if ("lat" in pt and "lon" in pt) or "ele" in pt:
                    wp.Location = Location()
                    if "lat" in pt and "lon" in pt:
                        wp.Location.Latitude = pt["lat"]
                        wp.Location.Longitude = pt["lon"]
                        activity.GPS = True
                    if "ele" in pt:
                        wp.Location.Altitude = float(pt["ele"])

                if "bpm" in pt:
                    wp.HR = pt["bpm"]

                lap.Waypoints.append(wp)

        activity.Stationary = len(lap.Waypoints) == 0

        return activity
Beispiel #10
0
    def DownloadActivity(self, serviceRecord, activity):
        resp = self._oauthSession(serviceRecord).get("https://api.endomondo.com/api/1/workouts/%d" % activity.ServiceData["WorkoutID"], params={"fields": "points"})
        try:
            resp = resp.json()
        except ValueError:
            self._rateLimitBailout(resp)
            res_txt = resp.text
            raise APIException("Parse failure in Endomondo activity download: %s" % resp.status_code)
        lap = Lap(stats=activity.Stats, startTime=activity.StartTime, endTime=activity.EndTime)
        activity.Laps = [lap]

        activity.GPS = False

        for pt in resp["points"]:
            wp = Waypoint()
            if "time" not in pt:
                # Manually-entered activities with a course attached to them have date-less waypoints
                # It'd be nice to transfer those courses, but it's a concept few other sites support AFAIK
                # So, ignore the points entirely
                continue
            wp.Timestamp = self._parseDate(pt["time"])

            if ("lat" in pt and "lng" in pt) or "alt" in pt:
                wp.Location = Location()
                if "lat" in pt and "lng" in pt:
                    wp.Location.Latitude = pt["lat"]
                    wp.Location.Longitude = pt["lng"]
                    activity.GPS = True
                if "alt" in pt:
                    wp.Location.Altitude = pt["alt"]

            if "hr" in pt:
                wp.HR = pt["hr"]

            if "cad" in pt:
                wp.Cadence = pt["cad"]

            lap.Waypoints.append(wp)
        activity.Stationary = len(lap.Waypoints) == 0
        return activity
Beispiel #11
0
        def stream_waypoint(offset,
                            speed=None,
                            distance=None,
                            heartrate=None,
                            calories=None,
                            steps=None,
                            watts=None,
                            gps=None,
                            **kwargs):
            wp = Waypoint()
            wp.Timestamp = activity.StartTime + timedelta(seconds=offset)
            wp.Speed = float(speed) if speed else None
            wp.Distance = float(distance) / 1000 if distance else None
            wp.HR = float(heartrate) if heartrate else None
            wp.Calories = float(calories) if calories else None
            wp.Power = float(watts) if watts else None

            if gps:
                wp.Location = Location(lat=float(gps["latitude"]),
                                       lon=float(gps["longitude"]),
                                       alt=float(gps["elevation"]))
            lap.Waypoints.append(wp)
Beispiel #12
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
Beispiel #13
0
    def _populateActivityFromTrackData(self,
                                       activity,
                                       recordText,
                                       minimumWaypoints=False):
        activity.Waypoints = []
        ###       1ST RECORD      ###
        # userID;
        # timestamp - create date?;
        # type? W=1st
        # User name;
        # activity name;
        # activity type;
        # another timestamp - start time of event?;
        # duration.00;
        # distance (km);
        # kcal;
        #;
        # max alt;
        # min alt;
        # max HR;
        # avg HR;

        ###     TRACK RECORDS     ###
        # timestamp;
        # type (2=start, 3=end, 0=pause, 1=resume);
        # latitude;
        # longitude;
        #;
        #;
        # alt;
        # hr;
        wptsWithLocation = False
        wptsWithNonZeroAltitude = False
        rows = recordText.split("\n")
        for row in rows:
            if row == "OK" or len(row) == 0:
                continue
            split = row.split(";")
            if split[2] == "W":
                # init record
                activity.Distance = float(
                    split[8]) * 1000 if split[8] != "" else None

                activity.Name = split[4]
            else:
                wp = Waypoint()
                if split[1] == "2":
                    wp.Type = WaypointType.Start
                elif split[1] == "3":
                    wp.Type = WaypointType.End
                elif split[1] == "0":
                    wp.Type = WaypointType.Pause
                elif split[1] == "1":
                    wp.Type = WaypointType.Resume
                else:
                    wp.Type == WaypointType.Regular

                if split[0] == "":
                    continue  # no timestamp, for whatever reason
                wp.Timestamp = pytz.utc.localize(
                    datetime.strptime(split[0], "%Y-%m-%d %H:%M:%S UTC")
                )  # it's like this as opposed to %z so I know when they change things (it'll break)
                if split[2] != "":
                    wp.Location = Location(float(split[2]), float(split[3]),
                                           None)
                    if wp.Location.Longitude > 180 or wp.Location.Latitude > 90 or wp.Location.Longitude < -180 or wp.Location.Latitude < -90:
                        raise APIExcludeActivity("Out of range lat/lng")
                    if wp.Location.Latitude is not None and wp.Location.Latitude is not None:
                        wptsWithLocation = True
                    if split[6] != "":
                        wp.Location.Altitude = float(
                            split[6])  # why this is missing: who knows?
                        if wp.Location.Altitude != 0:
                            wptsWithNonZeroAltitude = True

                if split[7] != "":
                    wp.HR = float(split[7])
                activity.Waypoints.append(wp)
                if wptsWithLocation and minimumWaypoints:
                    break
        activity.Waypoints = sorted(activity.Waypoints,
                                    key=lambda v: v.Timestamp)
        if wptsWithLocation:
            activity.EnsureTZ()
            if not wptsWithNonZeroAltitude:  # do this here so, should the activity run near sea level, altitude data won't be spotty
                for x in activity.Waypoints:  # clear waypoints of altitude data if all of them were logged at 0m (invalid)
                    if x.Location is not None:
                        x.Location.Altitude = None
        else:
            activity.Waypoints = []  # practically speaking
Beispiel #14
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
Beispiel #15
0
    def DownloadActivity(self, svcRecord, activity):

        service_id = svcRecord._id
        user = db.users.find_one({
            'ConnectedServices': {
                '$elemMatch': {
                    'ID': service_id,
                    'Service': self.ID
                }
            }
        })

        userID = svcRecord.ExternalID
        oauth_token = svcRecord.Authorization.get('OAuthToken')
        user_access_token = svcRecord.Authorization.get('AccessToken')
        user_access_token_secret = svcRecord.Authorization.get(
            'AccessTokenSecret')

        logging.info("\t Building signin for activity detail")

        user_tokens = {
            'access_token': user_access_token,
            'access_token_secret': user_access_token_secret,
            'oauth_token': oauth_token
        }
        payload = ""

        start_date = datetime.now() - timedelta(days=1)
        end_date = start_date + timedelta(seconds=86400)
        start_date_tmstmp = str(int(start_date.timestamp()))
        end_date_tmstmp = str(int(end_date.timestamp()))
        start_date_str = start_date.strftime("%Y-%m-%d")
        end_date_str = end_date.strftime("%Y-%m-%d")

        signin_parameters = {
            'upload_start_time': start_date_tmstmp,
            'upload_end_time': end_date_tmstmp,
        }
        signin_info = self._request_signin('GET',
                                           self.URI_ACTIVITIES_DETAIL,
                                           user_tokens,
                                           parameters=signin_parameters)

        resp = requests.request("GET",
                                signin_info['path'],
                                data=payload,
                                headers=signin_info['header'])

        if resp.status_code != 204 and resp.status_code != 200:
            logging.info(
                "\t An error occured while downloading Garmin Health activities from %s to %s "
                % (start_date_str, end_date_str))

        json_data = resp.json()
        activity_id = activity.ServiceData["ActivityID"]
        activity_detail_id = activity_id + '-detail'
        if json_data:
            for item in json_data:
                if activity_detail_id == item['summaryId']:
                    lapsdata = []

                    if "laps" in item:
                        for lap in item['laps']:
                            lapsdata.append(lap['startTimeInSeconds'])

                    ridedata = {}
                    lapWaypoints = []
                    startTimeLap = activity.StartTime
                    endTimeLap = activity.EndTime

                    if "samples" in item:
                        activity.GPS = True
                        activity.Stationary = False
                        for pt in item['samples']:
                            wp = Waypoint()

                            delta = int(pt.get('clockDurationInSeconds'))
                            dateStartPoint = int(pt.get('startTimeInSeconds'))
                            dateStartPointDt = datetime.utcfromtimestamp(
                                dateStartPoint)

                            wp.Timestamp = dateStartPointDt

                            wp.Location = Location()
                            if "latitudeInDegree" in pt:
                                wp.Location.Latitude = float(
                                    pt.get('latitudeInDegree'))
                            if "longitudeInDegree" in pt:
                                wp.Location.Longitude = float(
                                    pt.get('longitudeInDegree'))
                            if "elevationInMeters" in pt:
                                wp.Location.Altitude = int(
                                    pt.get('elevationInMeters'))

                            if "totalDistanceInMeters" in pt:
                                wp.Distance = int(
                                    pt.get('totalDistanceInMeters'))

                            if "speedMetersPerSecond" in pt:
                                wp.Speed = int(pt.get('speedMetersPerSecond'))

                            if "heartRate" in pt:
                                wp.HR = int(pt.get('heartRate'))

                            # current sample is = to lap occur , so store current nap and build a new one
                            if dateStartPoint in lapsdata:

                                lap = Lap(stats=activity.Stats,
                                          startTime=startTimeLap,
                                          endTime=dateStartPointDt)
                                lap.Waypoints = lapWaypoints
                                activity.Laps.append(lap)
                                # re init a new lap
                                startTimeLap = datetime.utcfromtimestamp(
                                    dateStartPoint)
                                lapWaypoints = []
                            # add occur
                            lapWaypoints.append(wp)

                        # build last lap
                        if len(lapWaypoints) > 0:
                            lap = Lap(stats=activity.Stats,
                                      startTime=startTimeLap,
                                      endTime=endTimeLap)
                            lap.Waypoints = lapWaypoints
                            activity.Laps.append(lap)
                    else:
                        activity.Laps = [
                            Lap(startTime=activity.StartTime,
                                endTime=activity.EndTime,
                                stats=activity.Stats)
                        ]

                    break
        return activity
Beispiel #16
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
Beispiel #17
0
    def _populateActivityFromTrackData(self, activity, recordText, minimumWaypoints=False):
        lap = Lap()
        activity.Laps = [lap]
        ###       1ST RECORD      ###
        # userID;
        # timestamp - create date?;
        # type? W=1st
        # User name;
        # activity name;
        # activity type;
        # another timestamp - start time of event?;
        # duration.00;
        # distance (km);
        # kcal;
        #;
        # max alt;
        # min alt;
        # max HR;
        # avg HR;

        ###     TRACK RECORDS     ###
        # timestamp;
        # type (2=start, 3=end, 0=pause, 1=resume);
        # latitude;
        # longitude;
        #;
        #;
        # alt;
        # hr;
        wptsWithLocation = False
        wptsWithNonZeroAltitude = False
        rows = recordText.split("\n")
        for row in rows:
            if row == "OK" or len(row) == 0:
                continue
            split = row.split(";")
            if split[2] == "W":
                # init record
                lap.Stats.MovingTime = ActivityStatistic(ActivityStatisticUnit.Time, value=timedelta(seconds=float(split[7])) if split[7] != "" else None)
                lap.Stats.Distance = ActivityStatistic(ActivityStatisticUnit.Kilometers, value=float(split[8]) if split[8] != "" else None)
                lap.Stats.HR = ActivityStatistic(ActivityStatisticUnit.BeatsPerMinute, avg=float(split[14]) if split[14] != "" else None, max=float(split[13]) if split[13] != "" else None)
                lap.Stats.Elevation = ActivityStatistic(ActivityStatisticUnit.Meters, min=float(split[12]) if split[12] != "" else None, max=float(split[11]) if split[11] != "" else None)
                lap.Stats.Energy = ActivityStatistic(ActivityStatisticUnit.Kilocalories, value=float(split[12]) if split[12] != "" else None)
                activity.Stats.update(lap.Stats)
                lap.Stats = activity.Stats
                activity.Name = split[4]
            else:
                wp = Waypoint()
                if split[1] == "2":
                    wp.Type = WaypointType.Start
                elif split[1] == "3":
                    wp.Type = WaypointType.End
                elif split[1] == "0":
                    wp.Type = WaypointType.Pause
                elif split[1] == "1":
                    wp.Type = WaypointType.Resume
                else:
                    wp.Type == WaypointType.Regular

                if split[0] == "":
                    continue  # no timestamp, for whatever reason
                wp.Timestamp = pytz.utc.localize(datetime.strptime(split[0], "%Y-%m-%d %H:%M:%S UTC"))  # it's like this as opposed to %z so I know when they change things (it'll break)
                if split[2] != "":
                    wp.Location = Location(float(split[2]), float(split[3]), None)
                    if wp.Location.Longitude > 180 or wp.Location.Latitude > 90 or wp.Location.Longitude < -180 or wp.Location.Latitude < -90:
                        raise APIExcludeActivity("Out of range lat/lng")
                    if wp.Location.Latitude is not None and wp.Location.Latitude is not None:
                        wptsWithLocation = True
                    if split[6] != "":
                        wp.Location.Altitude = float(split[6])  # why this is missing: who knows?
                        if wp.Location.Altitude != 0:
                            wptsWithNonZeroAltitude = True

                if split[7] != "":
                    wp.HR = float(split[7])
                lap.Waypoints.append(wp)
                if wptsWithLocation and minimumWaypoints:
                    break
        lap.Waypoints = sorted(activity.Waypoints, key=lambda v: v.Timestamp)
        if wptsWithLocation:
            activity.EnsureTZ(recalculate=True)
            if not wptsWithNonZeroAltitude:  # do this here so, should the activity run near sea level, altitude data won't be spotty
                for x in lap.Waypoints:  # clear waypoints of altitude data if all of them were logged at 0m (invalid)
                    if x.Location is not None:
                        x.Location.Altitude = None
        else:
            lap.Waypoints = []  # practically speaking
Beispiel #18
0
    def _populateActivityFromTrackRecord(self, activity, recordText, minimumWaypoints=False):
        activity.Waypoints = []
        ###       1ST RECORD      ###
        # userID;
        # timestamp - create date?;
        # type? W=1st
        # User name;
        # activity name;
        # activity type;
        # another timestamp - start time of event?;
        # duration.00;
        # distance (km);
        # kcal;
        #;
        # max alt;
        # min alt;
        # max HR;
        # avg HR;

        ###     TRACK RECORDS     ###
        # timestamp;
        # type (2=start, 3=end, 0=pause, 1=resume);
        # latitude;
        # longitude;
        #;
        #;
        # alt;
        # hr;
        wptsWithLocation = False
        wptsWithNonZeroAltitude = False
        rows = recordText.split("\n")
        for row in rows:
            if row == "OK" or len(row) == 0:
                continue
            split = row.split(";")
            if split[2] == "W":
                # init record
                activity.Distance = float(split[8]) * 1000 if split[8] != "" else None

                activity.Name = split[4]
            else:
                wp = Waypoint()
                if split[1] == "2":
                    wp.Type = WaypointType.Start
                elif split[1] == "3":
                    wp.Type = WaypointType.End
                elif split[1] == "0":
                    wp.Type = WaypointType.Pause
                elif split[1] == "1":
                    wp.Type = WaypointType.Resume
                else:
                    wp.Type == WaypointType.Regular

                if split[0] == "":
                    continue  # no timestamp, for whatever reason
                wp.Timestamp = pytz.utc.localize(datetime.strptime(split[0], "%Y-%m-%d %H:%M:%S UTC"))  # it's like this as opposed to %z so I know when they change things (it'll break)
                if split[2] != "":
                    wp.Location = Location(float(split[2]), float(split[3]), None)
                    if wp.Location.Latitude is not None and wp.Location.Latitude is not None:
                        wptsWithLocation = True
                    if split[6] != "":
                        wp.Location.Altitude = float(split[6])  # why this is missing: who knows?
                        if wp.Location.Altitude != 0:
                            wptsWithNonZeroAltitude = True

                if split[7] != "":
                    wp.HR = float(split[7])
                activity.Waypoints.append(wp)
                if wptsWithLocation and minimumWaypoints:
                    break

        if wptsWithLocation:
            activity.EnsureTZ()
            if not wptsWithNonZeroAltitude:  # do this here so, should the activity run near sea level, altitude data won't be spotty
                for x in activity.Waypoints:  # clear waypoints of altitude data if all of them were logged at 0m (invalid)
                    if x.Location is not None:
                        x.Location.Altitude = None
        else:
            activity.Waypoints = []  # practically speaking
Beispiel #19
0
    def DownloadActivity(self, svcRecord, activity):
        activityID = activity.ServiceData["ActivityID"]

        logging.info("\t\t DC LOADING  : " + str(activityID))

        headers = self._getAuthHeaders(svcRecord)
        self._rate_limit()
        resp = requests.get(DECATHLON_API_BASE_URL + "/activity/" +
                            activityID + "/fullactivity.xml",
                            headers=headers)

        if resp.status_code == 401:
            raise APIException("No authorization to download activity",
                               block=True,
                               user_exception=UserException(
                                   UserExceptionType.Authorization,
                                   intervention_required=True))

        try:
            root = xml.fromstring(resp.content)
        except:
            raise APIException(
                "Stream data returned from Decathlon is not XML")

        activity.GPS = False
        activity.Stationary = True
        #work on date
        startdate = root.find('.//STARTDATE').text
        timezone = root.find('.//TIMEZONE').text
        datebase = parse(startdate + timezone)

        ridedata = {}
        ridedataindex = []

        for pt in root.iter('LOCATION'):
            delta = int(pt.get('elapsed_time'))
            ridedataindex.append(delta)
            ridedata[delta] = {}
            if activityID == 'eu2132ac60d9a40a1d9a':
                logging.info('========time : ' + str(delta))
                logging.info('========lat : ' +
                             str(float(pt.find('LATITUDE').text[:8])))
            ridedata[delta]['LATITUDE'] = float(pt.find('LATITUDE').text[:8])
            ridedata[delta]['LONGITUDE'] = float(pt.find('LONGITUDE').text[:8])
            ridedata[delta]['ELEVATION'] = int(pt.find('ELEVATION').text[:8])

        if len(ridedata) > 0:
            activity.GPS = True
            activity.Stationary = False

        for measure in root.iter('MEASURE'):
            delta = int(measure.get('elapsed_time'))
            if delta not in ridedataindex:
                ridedataindex.append(delta)
                ridedata[delta] = {}

            for measureValue in measure.iter('VALUE'):
                if measureValue.get('id') == "1":
                    ridedata[delta]['HR'] = int(measureValue.text)
                if measureValue.get('id') == "6":
                    ridedata[delta]['SPEED'] = int(measureValue.text)
                if measureValue.get('id') == "5":
                    ridedata[delta]['DISTANCE'] = int(measureValue.text)
                if measureValue.get('id') == "20":
                    ridedata[delta]['LAP'] = int(measureValue.text)

        ridedataindex.sort()

        if len(ridedata) == 0:
            lap = Lap(stats=activity.Stats,
                      startTime=activity.StartTime,
                      endTime=activity.EndTime)
            activity.Laps = [lap]
        else:
            lapWaypoints = []
            startTimeLap = activity.StartTime
            for elapsedTime in ridedataindex:
                rd = ridedata[elapsedTime]
                wp = Waypoint()
                delta = elapsedTime
                formatedDate = datebase + timedelta(seconds=delta)
                wp.Timestamp = formatedDate  #self._parseDate(formatedDate.isoformat())

                if 'LATITUDE' in rd:
                    wp.Location = Location()
                    wp.Location.Latitude = rd['LATITUDE']
                    wp.Location.Longitude = rd['LONGITUDE']
                    wp.Location.Altitude = rd['ELEVATION']

                if 'HR' in rd:
                    wp.HR = rd['HR']

                if 'SPEED' in rd:
                    wp.Speed = rd['SPEED'] / 3600

                if 'DISTANCE' in rd:
                    wp.Distance = rd['DISTANCE']

                lapWaypoints.append(wp)

                if "LAP" in rd:
                    #build the lap
                    lap = Lap(stats=activity.Stats,
                              startTime=startTimeLap,
                              endTime=formatedDate)
                    lap.Waypoints = lapWaypoints
                    activity.Laps.append(lap)
                    # re init a new lap
                    startTimeLap = formatedDate
                    lapWaypoints = []

            #build last lap
            if len(lapWaypoints) > 0:
                lap = Lap(stats=activity.Stats,
                          startTime=startTimeLap,
                          endTime=formatedDate)
                lap.Waypoints = lapWaypoints
                activity.Laps.append(lap)

        return activity
Beispiel #20
0
    def DownloadActivity(self, svcRecord, activity):
        activityID = activity.ServiceData["ActivityID"]

        logger.info("\t\t DC LOADING  : " + str(activityID))

        headers = self._getAuthHeaders(svcRecord)
        resp = requests.get(self.ApiEndpoint + "/activity/" + activityID +
                            "/fullactivity.xml",
                            headers=headers)
        if resp.status_code == 401:
            raise APIException("No authorization to download activity",
                               block=True,
                               user_exception=UserException(
                                   UserExceptionType.Authorization,
                                   intervention_required=True))

        try:
            root = xml.fromstring(resp.content)
        except:
            raise APIException(
                "Stream data returned from DecathlonCoach is not XML")

        lap = Lap(stats=activity.Stats,
                  startTime=activity.StartTime,
                  endTime=activity.EndTime)
        activity.Laps = [lap]
        lap.Waypoints = []

        activity.GPS = False

        #work on date
        startdate = root.find('.//STARTDATE').text
        timezone = root.find('.//TIMEZONE').text
        datebase = parse(startdate + timezone)

        for pt in root.iter('LOCATION'):
            wp = Waypoint()

            delta = int(pt.get('elapsed_time'))
            formatedDate = datebase + timedelta(seconds=delta)

            wp.Timestamp = formatedDate  #self._parseDate(formatedDate.isoformat())

            wp.Location = Location()
            wp.Location.Latitude = float(pt.find('LATITUDE').text[:8])
            wp.Location.Longitude = float(pt.find('LONGITUDE').text[:8])
            activity.GPS = True
            wp.Location.Altitude = int(pt.find('ELEVATION').text[:8])

            #get the HR value in the Datastream node and measures collection
            for hr in root.iter('MEASURE'):
                if pt.get('elapsed_time') == hr.get('elapsed_time'):
                    for measureValue in hr.iter('VALUE'):
                        if measureValue.get('id') == "1":
                            wp.HR = int(measureValue.text)
                            break
                    break

            lap.Waypoints.append(wp)
        activity.Stationary = len(lap.Waypoints) == 0

        return activity
Beispiel #21
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