def create(self, validated_data): provider_id = self.context["request"].user.provider_id unknown_ids = [ str(id) for id in (set(t["device_id"] for t in validated_data["data"]) - set( models.Device.objects.filter( id__in=[t["device_id"] for t in validated_data["data"]]). filter(provider_id=provider_id).values_list("id", flat=True))) ] if unknown_ids: raise ValidationError( {"data.device_id": "Unknown ids: %s" % " ".join(unknown_ids)}) event_records = (models.EventRecord( timestamp=telemetry["timestamp"], point=gps_to_gis_point(telemetry.get("gps", {})), device_id=telemetry["device_id"], event_type=enums.EVENT_TYPE.telemetry.name, properties={ "telemetry": telemetry, "trip_id": None }, ) for telemetry in validated_data["data"]) db_helpers.upsert_event_records(event_records, enums.EVENT_SOURCE.agency_api.name, on_conflict_update=True) # We don't have the created event records, # but we will return an empty response anyway (cf. DeviceViewSet) return []
def _create_event_record(status_change): properties = {"trip_id": status_change.get("associated_trip")} event_location = status_change["event_location"] if event_location: # GeoJSON Point Feature try: longitude, latitude, altitude = event_location["geometry"][ "coordinates"] except ValueError: longitude, latitude = event_location["geometry"]["coordinates"] altitude = None point = geos.Point(longitude, latitude, altitude, srid=4326) properties["telemetry"] = { "timestamp": event_location["properties"]["timestamp"], "gps": { "lng": longitude, "lat": latitude }, # No coordinates, no battery charge saved "battery_pct": status_change.get("battery_pct"), } if altitude: properties["telemetry"]["gps"]["altitude"] = altitude else: # Spec violation! point = None return models.EventRecord( device_id=status_change["device_id"], timestamp=utils.from_mds_timestamp(status_change["event_time"]), point=point, event_type=status_change["agency_event_type"], properties=properties, )
def _create_event_record(status_change): properties = {"trip_id": status_change.get("associated_trip")} event_location = status_change["event_location"] if event_location: # GeoJSON Point Feature try: longitude, latitude, altitude = event_location["geometry"]["coordinates"] except ValueError: longitude, latitude = event_location["geometry"]["coordinates"] altitude = None point = geos.Point(longitude, latitude, altitude, srid=4326) properties["telemetry"] = { "timestamp": event_location["properties"]["timestamp"], "gps": {"lng": longitude, "lat": latitude}, # No coordinates, no battery charge saved "battery_pct": status_change.get("battery_pct"), } if altitude: properties["telemetry"]["gps"]["altitude"] = altitude else: # Spec violation! point = None publication_time = None if status_change.get("publication_time"): publication_time = utils.from_mds_timestamp(status_change["publication_time"]) # "Aggregation" providers store a recorded field, and we want to keep the same value # until we get the publication_time everywhere # Vendor only, 0.3 only, will disappear recorded = None if status_change.get("recorded"): recorded = utils.from_mds_timestamp(status_change["recorded"]) if publication_time and recorded: difference = abs(publication_time - recorded) if difference > datetime.timedelta(minutes=10): logger.warning("publication_time and recorded differ by %s", difference) return models.EventRecord( device_id=status_change["device_id"], timestamp=utils.from_mds_timestamp(status_change["event_time"]), point=point, event_type=status_change["agency_event_type"], event_type_reason=status_change["agency_event_type_reason"], properties=properties, publication_time=publication_time or recorded, )
def create(self, validated_data): device = self.context["device"] event_record = models.EventRecord( timestamp=validated_data["timestamp"], point=gps_to_gis_point(validated_data["telemetry"].get("gps", {})), device_id=device.id, event_type=validated_data["event_type"], properties={ "telemetry": validated_data["telemetry"], "trip_id": validated_data.get("trip_id"), }, ) db_helpers.upsert_event_records([event_record], enums.EVENT_SOURCE.agency_api.name, on_conflict_update=True) # We don't get the created event record but we need to return it return models.EventRecord.objects.get( device=device, timestamp=validated_data["timestamp"])
def _create_register_event_record(status_change): """ As the goal of the poller is to catch up with the history of a provider, simulate the registration of a device with a fake register event. This fake event is flagged in its properties to tell it apart from real ones. Should the device be unregistered and registered again according to the specs, don't delete the fake events in the past. """ return models.EventRecord( device_id=status_change["device_id"], # Another event for the same device with the same timestamp will be rejected timestamp=utils.from_mds_timestamp(status_change["event_time"]) - datetime.timedelta(milliseconds=1), event_type=enums.EVENT_TYPE.register.name, properties={"created_on_register": True}, source=enums.EVENT_SOURCE.provider_api.name, )