@blueharford/scrypted-spatial-awareness 0.4.6 → 0.4.7

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.
package/dist/plugin.zip CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blueharford/scrypted-spatial-awareness",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
4
4
  "description": "Cross-camera object tracking for Scrypted NVR with spatial awareness",
5
5
  "author": "Joshua Seidel <blueharford>",
6
6
  "license": "Apache-2.0",
@@ -159,25 +159,32 @@ export class AlertManager {
159
159
  const prefix = alert.severity === 'critical' ? '🚨 ' :
160
160
  alert.severity === 'warning' ? '⚠️ ' : '';
161
161
 
162
+ // Use object class in title
163
+ const objectType = alert.details.objectClass
164
+ ? alert.details.objectClass.charAt(0).toUpperCase() + alert.details.objectClass.slice(1)
165
+ : 'Object';
166
+
162
167
  switch (alert.type) {
163
168
  case 'property_entry':
164
- return `${prefix}🚶 Entry Detected`;
169
+ return `${prefix}${objectType} Arrived`;
165
170
  case 'property_exit':
166
- return `${prefix}🚶 Exit Detected`;
171
+ return `${prefix}${objectType} Left`;
167
172
  case 'movement':
168
- return `${prefix}🚶 Movement Detected`;
173
+ // Include destination in title
174
+ const dest = alert.details.toCameraName || 'area';
175
+ return `${prefix}${objectType} → ${dest}`;
169
176
  case 'unusual_path':
170
- return `${prefix}Unusual Path`;
177
+ return `${prefix}Unusual Route`;
171
178
  case 'dwell_time':
172
- return `${prefix}⏱️ Extended Presence`;
179
+ return `${prefix}${objectType} Lingering`;
173
180
  case 'restricted_zone':
174
- return `${prefix}Restricted Zone Alert`;
181
+ return `${prefix}Restricted Zone!`;
175
182
  case 'lost_tracking':
176
- return `${prefix}Lost Tracking`;
183
+ return `${prefix}${objectType} Lost`;
177
184
  case 'reappearance':
178
- return `${prefix}Object Reappeared`;
185
+ return `${prefix}${objectType} Reappeared`;
179
186
  default:
180
- return `${prefix}Spatial Awareness Alert`;
187
+ return `${prefix}Spatial Alert`;
181
188
  }
182
189
  }
183
190
 
@@ -125,6 +125,9 @@ export class ObjectCorrelator {
125
125
  return 1.0;
126
126
  }
127
127
 
128
+ // Calculate transit time first
129
+ const transitTime = sighting.timestamp - lastSighting.timestamp;
130
+
128
131
  // Find connection between cameras
129
132
  const connection = findConnection(
130
133
  this.topology,
@@ -133,12 +136,17 @@ export class ObjectCorrelator {
133
136
  );
134
137
 
135
138
  if (!connection) {
136
- // No defined connection - low score but not zero
137
- // (allows for uncharted paths)
139
+ // No defined connection - still allow correlation based on reasonable timing
140
+ // Allow up to 2 minutes transit between any cameras
141
+ const MAX_UNCHARTED_TRANSIT = 120000; // 2 minutes
142
+ if (transitTime > 0 && transitTime < MAX_UNCHARTED_TRANSIT) {
143
+ // Score based on how reasonable the timing is
144
+ // Shorter transits are more likely to be the same object
145
+ const timingScore = Math.max(0.3, 1 - (transitTime / MAX_UNCHARTED_TRANSIT));
146
+ return timingScore;
147
+ }
138
148
  return 0.2;
139
149
  }
140
-
141
- const transitTime = sighting.timestamp - lastSighting.timestamp;
142
150
  const { min, typical, max } = connection.transitTime;
143
151
 
144
152
  // Way outside range
@@ -217,7 +225,8 @@ export class ObjectCorrelator {
217
225
  );
218
226
 
219
227
  if (!connection) {
220
- return 0.3; // No connection defined
228
+ // No connection defined - give neutral score (don't penalize)
229
+ return 0.5;
221
230
  }
222
231
 
223
232
  let score = 0;
package/src/main.ts CHANGED
@@ -78,8 +78,8 @@ export class SpatialAwarenessPlugin extends ScryptedDeviceBase
78
78
  correlationThreshold: {
79
79
  title: 'Correlation Confidence Threshold',
80
80
  type: 'number',
81
- defaultValue: 0.6,
82
- description: 'Minimum confidence (0-1) for automatic object correlation',
81
+ defaultValue: 0.35,
82
+ description: 'Minimum confidence (0-1) for automatic object correlation. Lower values allow more matches.',
83
83
  group: 'Tracking',
84
84
  },
85
85
  lostTimeout: {
@@ -324,7 +324,7 @@ export class SpatialAwarenessPlugin extends ScryptedDeviceBase
324
324
 
325
325
  const config: TrackingEngineConfig = {
326
326
  correlationWindow: (this.storageSettings.values.correlationWindow as number || 30) * 1000,
327
- correlationThreshold: this.storageSettings.values.correlationThreshold as number || 0.6,
327
+ correlationThreshold: this.storageSettings.values.correlationThreshold as number || 0.35,
328
328
  lostTimeout: (this.storageSettings.values.lostTimeout as number || 300) * 1000,
329
329
  useVisualMatching: this.storageSettings.values.useVisualMatching as boolean ?? true,
330
330
  loiteringThreshold: (this.storageSettings.values.loiteringThreshold as number || 3) * 1000,
@@ -214,9 +214,9 @@ export function generateAlertMessage(
214
214
 
215
215
  switch (type) {
216
216
  case 'property_entry':
217
- return `${objectDesc} entered property via ${details.cameraName || 'unknown camera'}`;
217
+ return `${objectDesc} arrived at ${details.cameraName || 'property'}`;
218
218
  case 'property_exit':
219
- return `${objectDesc} exited property via ${details.cameraName || 'unknown camera'}`;
219
+ return `${objectDesc} left from ${details.cameraName || 'property'}`;
220
220
  case 'movement':
221
221
  // If we have a rich description from LLM/RAG, use it
222
222
  if (details.objectLabel && details.usedLlm) {