@blueharford/scrypted-spatial-awareness 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,300 @@
1
+ /**
2
+ * Training Mode Types
3
+ *
4
+ * These types support the guided training system where a user physically
5
+ * walks around their property to train the system on camera positions,
6
+ * transit times, overlaps, landmarks, and structures.
7
+ */
8
+
9
+ /** Unique identifier for a training session */
10
+ export type TrainingSessionId = string;
11
+
12
+ /** Current state of the training session */
13
+ export type TrainingSessionState = 'idle' | 'active' | 'paused' | 'completed';
14
+
15
+ /** Type of training action being performed */
16
+ export type TrainingActionType =
17
+ | 'camera_visit' // User arrived at a camera
18
+ | 'transit_start' // User started walking to another camera
19
+ | 'transit_end' // User arrived at destination camera
20
+ | 'mark_landmark' // User marked a landmark location
21
+ | 'mark_overlap' // User marked camera overlap zone
22
+ | 'mark_structure' // User marked a structure (wall, fence, etc.)
23
+ | 'confirm_position' // User confirmed camera position on floor plan
24
+ | 'adjust_fov'; // User adjusted camera field of view
25
+
26
+ /** A single camera visit during training */
27
+ export interface TrainingCameraVisit {
28
+ /** Camera device ID */
29
+ cameraId: string;
30
+ /** Camera name for display */
31
+ cameraName: string;
32
+ /** When the trainer was first detected on this camera */
33
+ arrivedAt: number;
34
+ /** When the trainer left this camera (null if still there) */
35
+ departedAt: number | null;
36
+ /** Visual embedding captured for the trainer */
37
+ trainerEmbedding?: string;
38
+ /** Confidence of trainer detection (0-1) */
39
+ detectionConfidence: number;
40
+ /** Bounding box of trainer in frame [x, y, width, height] */
41
+ boundingBox?: [number, number, number, number];
42
+ /** Position on floor plan if confirmed */
43
+ floorPlanPosition?: { x: number; y: number };
44
+ /** Entry zone detected (if any) */
45
+ entryZone?: string;
46
+ /** Exit zone detected (if any) */
47
+ exitZone?: string;
48
+ }
49
+
50
+ /** A recorded transit between two cameras */
51
+ export interface TrainingTransit {
52
+ /** Unique ID for this transit */
53
+ id: string;
54
+ /** Source camera ID */
55
+ fromCameraId: string;
56
+ /** Destination camera ID */
57
+ toCameraId: string;
58
+ /** Transit start time */
59
+ startTime: number;
60
+ /** Transit end time */
61
+ endTime: number;
62
+ /** Calculated transit duration in seconds */
63
+ transitSeconds: number;
64
+ /** Whether there was direct overlap (both cameras saw trainer simultaneously) */
65
+ hasOverlap: boolean;
66
+ /** Duration of overlap in seconds (if any) */
67
+ overlapDuration?: number;
68
+ /** Exit zone from source camera */
69
+ exitZone?: string;
70
+ /** Entry zone to destination camera */
71
+ entryZone?: string;
72
+ /** Path description entered by user (optional) */
73
+ pathDescription?: string;
74
+ }
75
+
76
+ /** A landmark marked during training */
77
+ export interface TrainingLandmark {
78
+ /** Unique ID for this landmark */
79
+ id: string;
80
+ /** Name given by user */
81
+ name: string;
82
+ /** Type of landmark */
83
+ type: 'mailbox' | 'garage' | 'shed' | 'tree' | 'gate' | 'door' | 'driveway' | 'pathway' | 'garden' | 'pool' | 'deck' | 'patio' | 'other';
84
+ /** Position on floor plan */
85
+ position: { x: number; y: number };
86
+ /** Which camera(s) can see this landmark */
87
+ visibleFromCameras: string[];
88
+ /** When this was marked */
89
+ markedAt: number;
90
+ /** Optional description */
91
+ description?: string;
92
+ }
93
+
94
+ /** A camera overlap zone marked during training */
95
+ export interface TrainingOverlap {
96
+ /** Unique ID for this overlap */
97
+ id: string;
98
+ /** First camera in overlap */
99
+ camera1Id: string;
100
+ /** Second camera in overlap */
101
+ camera2Id: string;
102
+ /** Position on floor plan where overlap was confirmed */
103
+ position: { x: number; y: number };
104
+ /** Approximate radius of overlap zone */
105
+ radius: number;
106
+ /** When this was marked */
107
+ markedAt: number;
108
+ }
109
+
110
+ /** A structure marked during training (walls, fences, etc.) */
111
+ export interface TrainingStructure {
112
+ /** Unique ID for this structure */
113
+ id: string;
114
+ /** Type of structure */
115
+ type: 'wall' | 'fence' | 'hedge' | 'building' | 'path' | 'road' | 'other';
116
+ /** Name/description */
117
+ name: string;
118
+ /** Points defining the structure (line or polygon) */
119
+ points: Array<{ x: number; y: number }>;
120
+ /** When this was marked */
121
+ markedAt: number;
122
+ }
123
+
124
+ /** Summary statistics for a training session */
125
+ export interface TrainingSessionStats {
126
+ /** Total duration of training in seconds */
127
+ totalDuration: number;
128
+ /** Number of cameras visited */
129
+ camerasVisited: number;
130
+ /** Number of transits recorded */
131
+ transitsRecorded: number;
132
+ /** Number of landmarks marked */
133
+ landmarksMarked: number;
134
+ /** Number of overlaps detected */
135
+ overlapsDetected: number;
136
+ /** Number of structures marked */
137
+ structuresMarked: number;
138
+ /** Average transit time in seconds */
139
+ averageTransitTime: number;
140
+ /** Coverage percentage (cameras visited / total cameras) */
141
+ coveragePercentage: number;
142
+ }
143
+
144
+ /** A training session */
145
+ export interface TrainingSession {
146
+ /** Unique session ID */
147
+ id: TrainingSessionId;
148
+ /** Current state */
149
+ state: TrainingSessionState;
150
+ /** When the session started */
151
+ startedAt: number;
152
+ /** When the session was last updated */
153
+ updatedAt: number;
154
+ /** When the session ended (if completed) */
155
+ completedAt?: number;
156
+ /** Visual embedding of the trainer (captured at start) */
157
+ trainerEmbedding?: string;
158
+ /** Name of the trainer (for display) */
159
+ trainerName?: string;
160
+ /** All camera visits during this session */
161
+ visits: TrainingCameraVisit[];
162
+ /** All transits recorded during this session */
163
+ transits: TrainingTransit[];
164
+ /** All landmarks marked during this session */
165
+ landmarks: TrainingLandmark[];
166
+ /** All overlaps detected during this session */
167
+ overlaps: TrainingOverlap[];
168
+ /** All structures marked during this session */
169
+ structures: TrainingStructure[];
170
+ /** Current camera where trainer is detected (if any) */
171
+ currentCameraId?: string;
172
+ /** Previous camera (for transit tracking) */
173
+ previousCameraId?: string;
174
+ /** Time when trainer left previous camera */
175
+ transitStartTime?: number;
176
+ /** Session statistics */
177
+ stats: TrainingSessionStats;
178
+ }
179
+
180
+ /** Configuration for training mode */
181
+ export interface TrainingConfig {
182
+ /** Minimum confidence for trainer detection */
183
+ minDetectionConfidence: number;
184
+ /** Maximum time (seconds) to wait for trainer at next camera */
185
+ maxTransitWait: number;
186
+ /** Whether to auto-detect overlaps */
187
+ autoDetectOverlaps: boolean;
188
+ /** Whether to auto-suggest landmarks based on AI */
189
+ autoSuggestLandmarks: boolean;
190
+ /** Minimum overlap duration (seconds) to count as overlap */
191
+ minOverlapDuration: number;
192
+ }
193
+
194
+ /** Real-time training status update sent to UI */
195
+ export interface TrainingStatusUpdate {
196
+ /** Session ID */
197
+ sessionId: TrainingSessionId;
198
+ /** Current state */
199
+ state: TrainingSessionState;
200
+ /** Current camera (if detected) */
201
+ currentCamera?: {
202
+ id: string;
203
+ name: string;
204
+ detectedAt: number;
205
+ confidence: number;
206
+ };
207
+ /** Active transit (if in transit) */
208
+ activeTransit?: {
209
+ fromCameraId: string;
210
+ fromCameraName: string;
211
+ startTime: number;
212
+ elapsedSeconds: number;
213
+ };
214
+ /** Recent action */
215
+ lastAction?: {
216
+ type: TrainingActionType;
217
+ description: string;
218
+ timestamp: number;
219
+ };
220
+ /** Session stats */
221
+ stats: TrainingSessionStats;
222
+ /** Suggestions for next actions */
223
+ suggestions: string[];
224
+ }
225
+
226
+ /** Result of applying training to topology */
227
+ export interface TrainingApplicationResult {
228
+ /** Number of cameras added to topology */
229
+ camerasAdded: number;
230
+ /** Number of connections created */
231
+ connectionsCreated: number;
232
+ /** Number of connections updated */
233
+ connectionsUpdated: number;
234
+ /** Number of landmarks added */
235
+ landmarksAdded: number;
236
+ /** Number of zones created */
237
+ zonesCreated: number;
238
+ /** Any warnings or issues */
239
+ warnings: string[];
240
+ /** Whether the application was successful */
241
+ success: boolean;
242
+ }
243
+
244
+ /** Default training configuration */
245
+ export const DEFAULT_TRAINING_CONFIG: TrainingConfig = {
246
+ minDetectionConfidence: 0.7,
247
+ maxTransitWait: 120, // 2 minutes
248
+ autoDetectOverlaps: true,
249
+ autoSuggestLandmarks: true,
250
+ minOverlapDuration: 2, // 2 seconds
251
+ };
252
+
253
+ /** Create a new empty training session */
254
+ export function createTrainingSession(trainerName?: string): TrainingSession {
255
+ const now = Date.now();
256
+ return {
257
+ id: `training-${now}-${Math.random().toString(36).substr(2, 9)}`,
258
+ state: 'idle',
259
+ startedAt: now,
260
+ updatedAt: now,
261
+ trainerName,
262
+ visits: [],
263
+ transits: [],
264
+ landmarks: [],
265
+ overlaps: [],
266
+ structures: [],
267
+ stats: {
268
+ totalDuration: 0,
269
+ camerasVisited: 0,
270
+ transitsRecorded: 0,
271
+ landmarksMarked: 0,
272
+ overlapsDetected: 0,
273
+ structuresMarked: 0,
274
+ averageTransitTime: 0,
275
+ coveragePercentage: 0,
276
+ },
277
+ };
278
+ }
279
+
280
+ /** Calculate session statistics */
281
+ export function calculateTrainingStats(session: TrainingSession, totalCameras: number): TrainingSessionStats {
282
+ const uniqueCameras = new Set(session.visits.map(v => v.cameraId));
283
+ const transitTimes = session.transits.map(t => t.transitSeconds);
284
+ const avgTransit = transitTimes.length > 0
285
+ ? transitTimes.reduce((a, b) => a + b, 0) / transitTimes.length
286
+ : 0;
287
+
288
+ return {
289
+ totalDuration: (session.completedAt || Date.now()) - session.startedAt,
290
+ camerasVisited: uniqueCameras.size,
291
+ transitsRecorded: session.transits.length,
292
+ landmarksMarked: session.landmarks.length,
293
+ overlapsDetected: session.overlaps.length,
294
+ structuresMarked: session.structures.length,
295
+ averageTransitTime: Math.round(avgTransit),
296
+ coveragePercentage: totalCameras > 0
297
+ ? Math.round((uniqueCameras.size / totalCameras) * 100)
298
+ : 0,
299
+ };
300
+ }