@blueharford/scrypted-spatial-awareness 0.6.22 → 0.6.24
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/main.nodejs.js +1 -1
- package/dist/main.nodejs.js.map +1 -1
- package/dist/plugin.zip +0 -0
- package/out/main.nodejs.js +49 -39
- package/out/main.nodejs.js.map +1 -1
- package/out/plugin.zip +0 -0
- package/package.json +1 -1
- package/src/alerts/alert-manager.ts +17 -1
- package/src/core/topology-discovery.ts +8 -4
- package/src/core/tracking-engine.ts +17 -27
- package/src/main.ts +3 -0
- package/src/models/alert.ts +5 -5
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/out/main.nodejs.js
CHANGED
|
@@ -34496,6 +34496,7 @@ class AlertManager {
|
|
|
34496
34496
|
}
|
|
34497
34497
|
/**
|
|
34498
34498
|
* Get notification title based on alert type
|
|
34499
|
+
* For movement alerts with LLM descriptions, use the smart description as title
|
|
34499
34500
|
*/
|
|
34500
34501
|
getNotificationTitle(alert) {
|
|
34501
34502
|
const prefix = alert.severity === 'critical' ? '🚨 ' :
|
|
@@ -34506,11 +34507,27 @@ class AlertManager {
|
|
|
34506
34507
|
: 'Object';
|
|
34507
34508
|
switch (alert.type) {
|
|
34508
34509
|
case 'property_entry':
|
|
34510
|
+
// Legacy - use simple title
|
|
34509
34511
|
return `${prefix}${objectType} Arrived`;
|
|
34510
34512
|
case 'property_exit':
|
|
34513
|
+
// Legacy - use simple title
|
|
34511
34514
|
return `${prefix}${objectType} Left`;
|
|
34512
34515
|
case 'movement':
|
|
34513
|
-
//
|
|
34516
|
+
// For smart activity alerts, use the LLM description as title if available
|
|
34517
|
+
// This gives us rich context like "Person walking toward front door"
|
|
34518
|
+
if (alert.details.objectLabel && alert.details.usedLlm) {
|
|
34519
|
+
// Truncate to reasonable title length (first sentence or 60 chars)
|
|
34520
|
+
let smartTitle = alert.details.objectLabel;
|
|
34521
|
+
const firstPeriod = smartTitle.indexOf('.');
|
|
34522
|
+
if (firstPeriod > 0 && firstPeriod < 60) {
|
|
34523
|
+
smartTitle = smartTitle.substring(0, firstPeriod);
|
|
34524
|
+
}
|
|
34525
|
+
else if (smartTitle.length > 60) {
|
|
34526
|
+
smartTitle = smartTitle.substring(0, 57) + '...';
|
|
34527
|
+
}
|
|
34528
|
+
return `${prefix}${smartTitle}`;
|
|
34529
|
+
}
|
|
34530
|
+
// Fallback: include destination in title
|
|
34514
34531
|
const dest = alert.details.toCameraName || 'area';
|
|
34515
34532
|
return `${prefix}${objectType} → ${dest}`;
|
|
34516
34533
|
case 'unusual_path':
|
|
@@ -36828,7 +36845,13 @@ Use the mount height to help estimate distances - objects at ground level will a
|
|
|
36828
36845
|
this.status.lastScanTime = Date.now();
|
|
36829
36846
|
return null;
|
|
36830
36847
|
}
|
|
36831
|
-
//
|
|
36848
|
+
// ALWAYS generate suggestions from each camera's analysis first
|
|
36849
|
+
// This ensures landmarks and zones from individual cameras are captured
|
|
36850
|
+
for (const analysis of analyses) {
|
|
36851
|
+
this.generateSuggestionsFromAnalysis(analysis);
|
|
36852
|
+
}
|
|
36853
|
+
this.console.log(`[Discovery] Generated suggestions from ${analyses.length} camera analyses`);
|
|
36854
|
+
// Then correlate if we have multiple cameras (adds shared landmarks and connections)
|
|
36832
36855
|
let correlation = null;
|
|
36833
36856
|
if (analyses.length >= 2) {
|
|
36834
36857
|
correlation = await this.correlateScenes(analyses);
|
|
@@ -36836,10 +36859,6 @@ Use the mount height to help estimate distances - objects at ground level will a
|
|
|
36836
36859
|
this.generateSuggestionsFromCorrelation(correlation);
|
|
36837
36860
|
}
|
|
36838
36861
|
}
|
|
36839
|
-
else if (analyses.length === 1) {
|
|
36840
|
-
// Single camera - generate suggestions from its analysis
|
|
36841
|
-
this.generateSuggestionsFromAnalysis(analyses[0]);
|
|
36842
|
-
}
|
|
36843
36862
|
this.status.lastScanTime = Date.now();
|
|
36844
36863
|
this.status.pendingSuggestions = this.getPendingSuggestions().length;
|
|
36845
36864
|
return correlation;
|
|
@@ -37517,33 +37536,19 @@ class TrackingEngine {
|
|
|
37517
37536
|
spatialResult = await this.spatialReasoning.generateEntryDescription(tracked, sighting.cameraId, mediaObject);
|
|
37518
37537
|
this.console.log(`[Entry Alert] Got description: "${spatialResult.description.substring(0, 60)}...", usedLlm=${spatialResult.usedLlm}`);
|
|
37519
37538
|
}
|
|
37520
|
-
|
|
37521
|
-
|
|
37522
|
-
|
|
37523
|
-
|
|
37524
|
-
|
|
37525
|
-
|
|
37526
|
-
|
|
37527
|
-
|
|
37528
|
-
|
|
37529
|
-
|
|
37530
|
-
|
|
37531
|
-
|
|
37532
|
-
|
|
37533
|
-
// Non-entry point - still alert about activity using movement alert type
|
|
37534
|
-
// This notifies about any activity around the property using topology context
|
|
37535
|
-
await this.alertManager.checkAndAlert('movement', tracked, {
|
|
37536
|
-
cameraId: sighting.cameraId,
|
|
37537
|
-
cameraName: sighting.cameraName,
|
|
37538
|
-
toCameraId: sighting.cameraId,
|
|
37539
|
-
toCameraName: sighting.cameraName,
|
|
37540
|
-
objectClass: sighting.detection.className,
|
|
37541
|
-
objectLabel: spatialResult.description, // Use spatial reasoning description (topology-based)
|
|
37542
|
-
detectionId: sighting.detectionId,
|
|
37543
|
-
involvedLandmarks: spatialResult.involvedLandmarks?.map(l => l.name),
|
|
37544
|
-
usedLlm: spatialResult.usedLlm,
|
|
37545
|
-
});
|
|
37546
|
-
}
|
|
37539
|
+
// Always use movement alert type for smart notifications with LLM descriptions
|
|
37540
|
+
// The property_entry/property_exit types are legacy and disabled by default
|
|
37541
|
+
await this.alertManager.checkAndAlert('movement', tracked, {
|
|
37542
|
+
cameraId: sighting.cameraId,
|
|
37543
|
+
cameraName: sighting.cameraName,
|
|
37544
|
+
toCameraId: sighting.cameraId,
|
|
37545
|
+
toCameraName: sighting.cameraName,
|
|
37546
|
+
objectClass: sighting.detection.className,
|
|
37547
|
+
objectLabel: spatialResult.description, // Smart LLM-generated description
|
|
37548
|
+
detectionId: sighting.detectionId,
|
|
37549
|
+
involvedLandmarks: spatialResult.involvedLandmarks?.map(l => l.name),
|
|
37550
|
+
usedLlm: spatialResult.usedLlm,
|
|
37551
|
+
});
|
|
37547
37552
|
this.recordAlertTime(globalId);
|
|
37548
37553
|
}, this.config.loiteringThreshold);
|
|
37549
37554
|
}
|
|
@@ -37651,9 +37656,12 @@ class TrackingEngine {
|
|
|
37651
37656
|
spatialResult = await this.spatialReasoning.generateExitDescription(current, sighting.cameraId, mediaObject);
|
|
37652
37657
|
this.console.log(`[Exit Alert] Got description: "${spatialResult.description.substring(0, 60)}...", usedLlm=${spatialResult.usedLlm}`);
|
|
37653
37658
|
}
|
|
37654
|
-
|
|
37659
|
+
// Use movement alert for exit too - smart notifications with LLM descriptions
|
|
37660
|
+
await this.alertManager.checkAndAlert('movement', current, {
|
|
37655
37661
|
cameraId: sighting.cameraId,
|
|
37656
37662
|
cameraName: sighting.cameraName,
|
|
37663
|
+
toCameraId: sighting.cameraId,
|
|
37664
|
+
toCameraName: sighting.cameraName,
|
|
37657
37665
|
objectClass: current.className,
|
|
37658
37666
|
objectLabel: spatialResult.description,
|
|
37659
37667
|
involvedLandmarks: spatialResult.involvedLandmarks?.map(l => l.name),
|
|
@@ -40829,6 +40837,8 @@ class SpatialAwarenessPlugin extends sdk_1.ScryptedDeviceBase {
|
|
|
40829
40837
|
const landmarkData = suggestion.landmark;
|
|
40830
40838
|
const distanceFeet = landmarkData.distanceFeet || 50; // Default 50ft if not set
|
|
40831
40839
|
const distanceInPixels = distanceFeet * floorPlanScale;
|
|
40840
|
+
// Debug: log the distance data to verify it's being used correctly
|
|
40841
|
+
this.console.log(`[Discovery] Landmark "${suggestion.landmark.name}" distance data: distanceFeet=${distanceFeet}, distance="${landmarkData.distance || 'not set'}", floorPlanScale=${floorPlanScale}, distanceInPixels=${distanceInPixels}`);
|
|
40832
40842
|
// Use bounding box for horizontal positioning within the FOV
|
|
40833
40843
|
const bbox = landmarkData.boundingBox;
|
|
40834
40844
|
let angleOffset;
|
|
@@ -41203,8 +41213,8 @@ function createDefaultRules() {
|
|
|
41203
41213
|
return [
|
|
41204
41214
|
{
|
|
41205
41215
|
id: 'property-entry',
|
|
41206
|
-
name: 'Property Entry',
|
|
41207
|
-
enabled:
|
|
41216
|
+
name: 'Property Entry (Legacy)',
|
|
41217
|
+
enabled: false, // Disabled - use movement alerts with LLM descriptions instead
|
|
41208
41218
|
type: 'property_entry',
|
|
41209
41219
|
conditions: [],
|
|
41210
41220
|
severity: 'info',
|
|
@@ -41213,8 +41223,8 @@ function createDefaultRules() {
|
|
|
41213
41223
|
},
|
|
41214
41224
|
{
|
|
41215
41225
|
id: 'property-exit',
|
|
41216
|
-
name: 'Property Exit',
|
|
41217
|
-
enabled:
|
|
41226
|
+
name: 'Property Exit (Legacy)',
|
|
41227
|
+
enabled: false, // Disabled - use movement alerts with LLM descriptions instead
|
|
41218
41228
|
type: 'property_exit',
|
|
41219
41229
|
conditions: [],
|
|
41220
41230
|
severity: 'info',
|
|
@@ -41223,7 +41233,7 @@ function createDefaultRules() {
|
|
|
41223
41233
|
},
|
|
41224
41234
|
{
|
|
41225
41235
|
id: 'movement',
|
|
41226
|
-
name: '
|
|
41236
|
+
name: 'Smart Activity Alerts',
|
|
41227
41237
|
enabled: true,
|
|
41228
41238
|
type: 'movement',
|
|
41229
41239
|
conditions: [],
|