diff --git a/vrobbler/apps/locations/models.py b/vrobbler/apps/locations/models.py index c2aec39..6c99a64 100644 --- a/vrobbler/apps/locations/models.py +++ b/vrobbler/apps/locations/models.py @@ -92,18 +92,43 @@ class GeoLocation(ScrobblableMixin): ) def has_moved(self, past_points: list["GeoLocation"]) -> bool: + """GPS jumps from time to time. This function tries to smooth out + when we appear to have flagging our location as having not moved if one of our last + 3""" has_moved = False + has_moved_locs = [] for point in past_points: loc_diff = self.loc_diff((point.lat, point.lon)) - logger.info(f"[locations] {self} is {loc_diff} from {point}") + logger.info( + f"[locations] checking whether location has moved", + extra={"location": self, "loc_diff": loc_diff, "point": point}, + ) if ( - loc_diff[0] < GEOLOC_PROXIMITY - or loc_diff[1] < GEOLOC_PROXIMITY + loc_diff[0] > GEOLOC_PROXIMITY + or loc_diff[1] > GEOLOC_PROXIMITY ): logger.info( - f"[locations] {loc_diff} is less than proximity setting {GEOLOC_PROXIMITY}, we've moved" + f"[locations] difference is less than proximity setting, we may have moved", + extra={ + "loc_diff": loc_diff, + "point": point, + "geoloc_proximity": GEOLOC_PROXIMITY, + }, ) - has_moved = True + has_moved_locs.append(True) + else: + has_moved_locs.append(False) + + # Sum up all True values, if they're more than half of our locations, we've moved + if sum(has_moved_locs) > int(len(past_points) / 2): + logger.info( + f"[locations] more than half of past points have moved, we've moved", + extra={ + "has_moved_locs": has_moved_locs, + "past_points": past_points, + }, + ) + has_moved = True return has_moved diff --git a/vrobbler/apps/locations/tests/test_models.py b/vrobbler/apps/locations/tests/test_models.py index cc65816..983afe6 100644 --- a/vrobbler/apps/locations/tests/test_models.py +++ b/vrobbler/apps/locations/tests/test_models.py @@ -39,3 +39,69 @@ def test_find_or_create_creates_new(): {"lat": 44.2345, "lon": -68.2345, "alt": 60.356} ) assert not loc.id == extant.id + + +@pytest.mark.django_db +def test_found_in_proximity_location(): + lat = 44.234 + lon = -69.234 + loc = GeoLocation.objects.create(lat=lat, lon=lon, altitude=60) + + close = GeoLocation.objects.create( + lat=lat + 0.0001, lon=lon - 0.0001, altitude=60 + ) + assert close not in loc.in_proximity() + assert close in loc.in_proximity(named=False) + + +@pytest.mark.django_db +def test_not_found_in_proximity_location(): + lat = 44.234 + lon = -69.234 + loc = GeoLocation.objects.create(lat=lat, lon=lon, altitude=60) + + far = GeoLocation.objects.create( + lat=lat + 0.0002, lon=lon - 0.0001, altitude=60 + ) + assert far not in loc.in_proximity(named=False) + + +@pytest.mark.django_db +def test_has_moved(caplog): + lat = 44.234 + lon = -69.234 + loc = GeoLocation.objects.create(lat=lat, lon=lon, altitude=60) + + past1 = GeoLocation.objects.get_or_create( + lat=lat + 0.000, lon=lon - 0.000, altitude=60 + )[0] + past2 = GeoLocation.objects.get_or_create( + lat=lat + 0.002, lon=lon - 0.002, altitude=60 + )[0] + past3 = GeoLocation.objects.get_or_create( + lat=lat + 0.0001, lon=lon - 0.000, altitude=60 + )[0] + last_three = [past1, past2, past3] + assert loc.has_moved(last_three) + + +@pytest.mark.django_db +def test_has_not_moved(): + lat = 44.234 + lon = -69.234 + loc = GeoLocation.objects.create(lat=lat, lon=lon, altitude=60) + + past1 = GeoLocation.objects.get_or_create( + lat=lat + 0.00001, lon=lon - 0.0000, altitude=60 + )[0] + past2 = GeoLocation.objects.get_or_create( + lat=lat + 0.000, lon=lon - 0.000, altitude=60 + )[0] + past3 = GeoLocation.objects.get_or_create( + lat=lat + 0.0000, lon=lon - 0.00001, altitude=60 + )[0] + past4 = GeoLocation.objects.get_or_create( + lat=lat + 0.005, lon=lon - 0.0003, altitude=60 + )[0] + last_four = [past1, past2, past3, past4] + assert not loc.has_moved(last_four)