From 1260e76523c0de2be505e167aa823d27e4632c93 Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Tue, 7 May 2024 13:40:49 -0400 Subject: [PATCH] fill in new BLE fields & update types `ble_sensed_mode` and `ble_sensed_summary` were added to sections and confirmed trips in https://github.com/e-mission/e-mission-server/pull/965. We are going to need `ble_sensed_mode` to determine vehicle info. The section summaries (`ble_sensed_summary`, `cleaned_section_summary` and `inferred_section_summary`) are not used in unprocessed trips currently, but I am adding them so there is less of a gap between composite trips and unprocessed trips --- package.cordovabuild.json | 1 + package.serve.json | 1 + www/__tests__/timelineHelper.test.ts | 3 ++- www/js/diary/timelineHelper.ts | 40 +++++++++++++++++++++++++--- www/js/types/diaryTypes.ts | 6 +++++ 5 files changed, 46 insertions(+), 5 deletions(-) diff --git a/package.cordovabuild.json b/package.cordovabuild.json index 282e3693d..f5d9b6d58 100644 --- a/package.cordovabuild.json +++ b/package.cordovabuild.json @@ -139,6 +139,7 @@ "cordova-custom-config": "^5.1.1", "cordova-plugin-ibeacon": "git+https://github.com/louisg1337/cordova-plugin-ibeacon.git", "core-js": "^2.5.7", + "e-mission-common": "git+https://github.com/JGreenlee/e-mission-common.git", "enketo-core": "^6.1.7", "enketo-transformer": "^4.0.0", "fast-xml-parser": "^4.2.2", diff --git a/package.serve.json b/package.serve.json index f6f5c2ae3..af33531ae 100644 --- a/package.serve.json +++ b/package.serve.json @@ -65,6 +65,7 @@ "chartjs-adapter-luxon": "^1.3.1", "chartjs-plugin-annotation": "^3.0.1", "core-js": "^2.5.7", + "e-mission-common": "git+https://github.com/JGreenlee/e-mission-common.git", "enketo-core": "^6.1.7", "enketo-transformer": "^4.0.0", "fast-xml-parser": "^4.2.2", diff --git a/www/__tests__/timelineHelper.test.ts b/www/__tests__/timelineHelper.test.ts index aafe13926..c40262aae 100644 --- a/www/__tests__/timelineHelper.test.ts +++ b/www/__tests__/timelineHelper.test.ts @@ -291,7 +291,7 @@ jest.mock('../js/services/unifiedDataLoader', () => ({ })); it('works when there are no unprocessed trips...', async () => { - expect(readUnprocessedTrips(-1, -1, {} as any)).resolves.toEqual([]); + expect(readUnprocessedTrips(-1, -1, {} as any, {} as any)).resolves.toEqual([]); }); it('works when there are one or more unprocessed trips...', async () => { @@ -299,6 +299,7 @@ it('works when there are one or more unprocessed trips...', async () => { mockTLH.fakeStartTsOne, mockTLH.fakeEndTsOne, {} as any, + {} as any, ); expect(testValueOne.length).toEqual(1); expect(testValueOne[0]).toEqual( diff --git a/www/js/diary/timelineHelper.ts b/www/js/diary/timelineHelper.ts index 6e82c0fbf..f850f0074 100644 --- a/www/js/diary/timelineHelper.ts +++ b/www/js/diary/timelineHelper.ts @@ -17,12 +17,14 @@ import { BluetoothBleData, SectionData, CompositeTripLocation, + SectionSummary, } from '../types/diaryTypes'; import { getLabelInputDetails, getLabelInputs } from '../survey/multilabel/confirmHelper'; import { LabelOptions } from '../types/labelTypes'; import { EnketoUserInputEntry, filterByNameAndVersion } from '../survey/enketo/enketoHelper'; import { AppConfig } from '../types/appConfigTypes'; import { Point, Feature } from 'geojson'; +import { ble_matching } from 'e-mission-common'; const cachedGeojsons: Map = new Map(); @@ -306,10 +308,25 @@ const dateTime2localdate = (currtime: DateTime, tz: string) => ({ second: currtime.second, }); +/* Compute a section summary, which is really simple for unprocessed trips because they are + always assumed to be unimodal. +/* maybe unify with eaum.get_section_summary on e-mission-server at some point */ +const getSectionSummaryForUnprocessed = (section: SectionData, modeProp): SectionSummary => { + const baseMode = section[modeProp] || 'UNKNOWN'; + return { + count: { [baseMode]: 1 }, + distance: { [baseMode]: section.distance }, + duration: { [baseMode]: section.duration }, + }; +}; + /** * @description Given an array of location points, creates an UnprocessedTrip object. */ -function points2UnprocessedTrip(locationPoints: Array>): UnprocessedTrip { +function points2UnprocessedTrip( + locationPoints: Array>, + appConfig: AppConfig, +): UnprocessedTrip { const startPoint = locationPoints[0]; const endPoint = locationPoints[locationPoints.length - 1]; const tripAndSectionId = `unprocessed_${startPoint.data.ts}_${endPoint.data.ts}`; @@ -369,6 +386,12 @@ function points2UnprocessedTrip(locationPoints: Array> origin_key: 'UNPROCESSED_section', sensed_mode: 4, // MotionTypes.UNKNOWN (4) sensed_mode_str: 'UNKNOWN', + ble_sensed_mode: ble_matching.get_ble_sensed_vehicle_for_section( + unprocessedBleScans, + baseProps.start_ts, + baseProps.end_ts, + appConfig, + ), trip_id: { $oid: tripAndSectionId }, }; @@ -377,6 +400,9 @@ function points2UnprocessedTrip(locationPoints: Array> ...baseProps, _id: { $oid: tripAndSectionId }, additions: [], + ble_sensed_summary: getSectionSummaryForUnprocessed(singleSection, 'ble_sensed_mode'), + cleaned_section_summary: getSectionSummaryForUnprocessed(singleSection, 'sensed_mode_str'), + inferred_section_summary: getSectionSummaryForUnprocessed(singleSection, 'sensed_mode_str'), confidence_threshold: 0, expectation: { to_label: true }, inferred_labels: [], @@ -395,7 +421,10 @@ const tsEntrySort = (e1: BEMData, e2: BEMData): Promise { +function tripTransitions2UnprocessedTrip( + trip: Array, + appConfig: AppConfig, +): Promise { const tripStartTransition = trip[0]; const tripEndTransition = trip[1]; const tq = { @@ -437,7 +466,7 @@ function tripTransitions2UnprocessedTrip(trip: Array): Promise { logDebug(JSON.stringify(trip, null, 2)); }); - const tripFillPromises = tripsList.map(tripTransitions2UnprocessedTrip); + const tripFillPromises = tripsList.map((t) => + tripTransitions2UnprocessedTrip(t, appConfig), + ); return Promise.all(tripFillPromises).then( (rawTripObjs: (UnprocessedTrip | undefined)[]) => { // Now we need to link up the trips. linking unprocessed trips diff --git a/www/js/types/diaryTypes.ts b/www/js/types/diaryTypes.ts index 9757e95cf..53b618be0 100644 --- a/www/js/types/diaryTypes.ts +++ b/www/js/types/diaryTypes.ts @@ -4,6 +4,7 @@ import { BaseModeKey, MotionTypeKey } from '../diary/diaryHelper'; import useDerivedProperties from '../diary/useDerivedProperties'; +import { VehicleIdentity } from './appConfigTypes'; import { MultilabelKey } from './labelTypes'; import { BEMData, LocalDt } from './serverData'; import { FeatureCollection, Feature, Geometry, Point, Position } from 'geojson'; @@ -58,6 +59,8 @@ export type CompositeTripLocation = { export type UnprocessedTrip = { _id: ObjectId; additions: []; // unprocessed trips won't have any matched processed inputs, so this is always empty + ble_sensed_summary: SectionSummary; + cleaned_section_summary: SectionSummary; confidence_threshold: number; distance: number; duration: number; @@ -67,6 +70,7 @@ export type UnprocessedTrip = { end_ts: number; expectation: { to_label: true }; // unprocessed trips are always expected to be labeled inferred_labels: []; // unprocessed trips won't have inferred labels + inferred_section_summary: SectionSummary; key: 'UNPROCESSED_trip'; locations?: CompositeTripLocation[]; origin_key: 'UNPROCESSED_trip'; @@ -85,6 +89,7 @@ export type UnprocessedTrip = { export type CompositeTrip = { _id: ObjectId; additions: UserInputEntry[]; + ble_sensed_summary: SectionSummary; cleaned_section_summary: SectionSummary; cleaned_trip: ObjectId; confidence_threshold: number; @@ -202,6 +207,7 @@ export type SectionData = { key: string; origin_key: string; trip_id: ObjectId; + ble_sensed_mode: VehicleIdentity; sensed_mode: number; source: string; // e.x., "SmoothedHighConfidenceMotion" start_ts: number; // Unix