@blueharford/scrypted-spatial-awareness 0.1.0
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/.vscode/settings.json +3 -0
- package/CLAUDE.md +168 -0
- package/README.md +152 -0
- package/dist/main.nodejs.js +3 -0
- package/dist/main.nodejs.js.LICENSE.txt +1 -0
- package/dist/main.nodejs.js.map +1 -0
- package/dist/plugin.zip +0 -0
- package/out/main.nodejs.js +37376 -0
- package/out/main.nodejs.js.map +1 -0
- package/out/plugin.zip +0 -0
- package/package.json +59 -0
- package/src/alerts/alert-manager.ts +347 -0
- package/src/core/object-correlator.ts +376 -0
- package/src/core/tracking-engine.ts +367 -0
- package/src/devices/global-tracker-sensor.ts +191 -0
- package/src/devices/tracking-zone.ts +245 -0
- package/src/integrations/mqtt-publisher.ts +320 -0
- package/src/main.ts +690 -0
- package/src/models/alert.ts +229 -0
- package/src/models/topology.ts +168 -0
- package/src/models/tracked-object.ts +226 -0
- package/src/state/tracking-state.ts +285 -0
- package/src/ui/editor.html +1051 -0
- package/src/utils/id-generator.ts +36 -0
- package/tsconfig.json +21 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
This is a Scrypted plugin for cross-camera object tracking ("Spatial Awareness"). It correlates detected objects as they move between cameras, maintains global tracking state, and provides alerts for property entry/exit and movement patterns.
|
|
8
|
+
|
|
9
|
+
## Build & Development Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Install dependencies
|
|
13
|
+
npm install
|
|
14
|
+
|
|
15
|
+
# Build the plugin
|
|
16
|
+
npm run build
|
|
17
|
+
|
|
18
|
+
# Deploy to local Scrypted server (127.0.0.1)
|
|
19
|
+
npm run scrypted-deploy
|
|
20
|
+
|
|
21
|
+
# Deploy to remote Scrypted server
|
|
22
|
+
npm run scrypted-deploy <ip-address>
|
|
23
|
+
|
|
24
|
+
# Debug in VS Code
|
|
25
|
+
# 1. Edit .vscode/settings.json with Scrypted server IP
|
|
26
|
+
# 2. Press F5 or use Run > Start Debugging
|
|
27
|
+
|
|
28
|
+
# Login to Scrypted (required once)
|
|
29
|
+
npx scrypted login
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Architecture
|
|
33
|
+
|
|
34
|
+
### Plugin Entry Point
|
|
35
|
+
- `src/main.ts` - Exports `SpatialAwarenessPlugin` class implementing `DeviceProvider`, `Settings`, `HttpRequestHandler`
|
|
36
|
+
|
|
37
|
+
### Core Tracking Engine
|
|
38
|
+
- `src/core/tracking-engine.ts` - Orchestrates detection events, correlation, and state updates
|
|
39
|
+
- `src/core/object-correlator.ts` - Multi-factor correlation algorithm (timing, visual, spatial, class)
|
|
40
|
+
- `src/core/transit-predictor.ts` - Predicts expected cameras and transit times
|
|
41
|
+
|
|
42
|
+
### Data Models
|
|
43
|
+
- `src/models/topology.ts` - Camera nodes, connections, zones
|
|
44
|
+
- `src/models/tracked-object.ts` - Global tracked object with journey history
|
|
45
|
+
- `src/models/alert.ts` - Alert types and rules
|
|
46
|
+
|
|
47
|
+
### State Management
|
|
48
|
+
- `src/state/tracking-state.ts` - In-memory store with persistence and change notifications
|
|
49
|
+
|
|
50
|
+
### Virtual Devices
|
|
51
|
+
- `src/devices/global-tracker-sensor.ts` - OccupancySensor for property-wide tracking
|
|
52
|
+
- `src/devices/tracking-zone.ts` - Zone-specific motion/occupancy sensors
|
|
53
|
+
|
|
54
|
+
## Key Scrypted Patterns
|
|
55
|
+
|
|
56
|
+
### Listening to Object Detection Events
|
|
57
|
+
```typescript
|
|
58
|
+
import sdk, { ScryptedInterface, ObjectsDetected } from '@scrypted/sdk';
|
|
59
|
+
|
|
60
|
+
const camera = sdk.systemManager.getDeviceById(cameraId);
|
|
61
|
+
camera.listen(ScryptedInterface.ObjectDetector, async (source, details, data) => {
|
|
62
|
+
const results = data as ObjectsDetected;
|
|
63
|
+
// results.detections[] contains ObjectDetectionResult items
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### ObjectDetectionResult Structure
|
|
68
|
+
```typescript
|
|
69
|
+
{
|
|
70
|
+
boundingBox: [x, y, width, height], // normalized coordinates
|
|
71
|
+
className: 'person' | 'car' | 'animal' | 'package',
|
|
72
|
+
score: 0.95, // confidence
|
|
73
|
+
id: 'abc123', // tracking ID (single camera)
|
|
74
|
+
history: { firstSeen: number, lastSeen: number },
|
|
75
|
+
movement: { moving: boolean },
|
|
76
|
+
zones: string[],
|
|
77
|
+
embedding?: string // visual feature embedding (base64)
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### StorageSettings Pattern
|
|
82
|
+
```typescript
|
|
83
|
+
import { StorageSettings } from '@scrypted/sdk/storage-settings';
|
|
84
|
+
|
|
85
|
+
storageSettings = new StorageSettings(this, {
|
|
86
|
+
settingKey: {
|
|
87
|
+
title: 'Setting Title',
|
|
88
|
+
type: 'number',
|
|
89
|
+
defaultValue: 30,
|
|
90
|
+
group: 'GroupName',
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### DeviceProvider Pattern
|
|
96
|
+
```typescript
|
|
97
|
+
async getDevice(nativeId: string): Promise<any> {
|
|
98
|
+
// Return or create device instance by nativeId
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async releaseDevice(id: string, nativeId: string): Promise<void> {
|
|
102
|
+
// Cleanup device
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Correlation Algorithm
|
|
107
|
+
|
|
108
|
+
Objects are correlated across cameras using weighted factors:
|
|
109
|
+
- **Timing (30%)**: Transit time within expected min/max range
|
|
110
|
+
- **Visual (35%)**: Embedding similarity (cosine distance)
|
|
111
|
+
- **Spatial (25%)**: Exit zone → Entry zone coherence
|
|
112
|
+
- **Class (10%)**: Object class must match
|
|
113
|
+
|
|
114
|
+
Threshold for automatic correlation: 0.6 (configurable)
|
|
115
|
+
|
|
116
|
+
## Camera Topology Configuration
|
|
117
|
+
|
|
118
|
+
Topology is stored as JSON with:
|
|
119
|
+
- `cameras[]` - Camera nodes with entry/exit point flags
|
|
120
|
+
- `connections[]` - Links between cameras with exit/entry zones and transit times
|
|
121
|
+
- `globalZones[]` - Named zones spanning multiple cameras
|
|
122
|
+
|
|
123
|
+
## API Endpoints
|
|
124
|
+
|
|
125
|
+
- `GET /api/tracked-objects` - All tracked objects
|
|
126
|
+
- `GET /api/journey/{globalId}` - Journey for specific object
|
|
127
|
+
- `GET|PUT /api/topology` - Camera topology config
|
|
128
|
+
- `GET /api/alerts` - Recent alerts
|
|
129
|
+
- `GET|POST /api/floor-plan` - Floor plan image (base64)
|
|
130
|
+
- `GET /ui/editor` - Visual topology editor
|
|
131
|
+
|
|
132
|
+
## MQTT Integration
|
|
133
|
+
|
|
134
|
+
When enabled, publishes to Home Assistant via MQTT:
|
|
135
|
+
- `{baseTopic}/occupancy/state` - ON/OFF occupancy
|
|
136
|
+
- `{baseTopic}/count/state` - Active object count
|
|
137
|
+
- `{baseTopic}/person_count/state` - People on property
|
|
138
|
+
- `{baseTopic}/vehicle_count/state` - Vehicles on property
|
|
139
|
+
- `{baseTopic}/state` - Full JSON state
|
|
140
|
+
- `{baseTopic}/alerts` - Alert events
|
|
141
|
+
- `{baseTopic}/events/entry|exit|transition` - Movement events
|
|
142
|
+
|
|
143
|
+
## Project Structure
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
src/
|
|
147
|
+
├── main.ts # Plugin entry point
|
|
148
|
+
├── core/
|
|
149
|
+
│ ├── tracking-engine.ts # Central orchestrator
|
|
150
|
+
│ └── object-correlator.ts # Cross-camera matching
|
|
151
|
+
├── models/
|
|
152
|
+
│ ├── topology.ts # Camera topology types
|
|
153
|
+
│ ├── tracked-object.ts # Tracked object types
|
|
154
|
+
│ └── alert.ts # Alert types
|
|
155
|
+
├── devices/
|
|
156
|
+
│ ├── global-tracker-sensor.ts
|
|
157
|
+
│ └── tracking-zone.ts
|
|
158
|
+
├── state/
|
|
159
|
+
│ └── tracking-state.ts # State management
|
|
160
|
+
├── alerts/
|
|
161
|
+
│ └── alert-manager.ts # Alert generation
|
|
162
|
+
├── integrations/
|
|
163
|
+
│ └── mqtt-publisher.ts # MQTT for Home Assistant
|
|
164
|
+
├── ui/
|
|
165
|
+
│ └── editor.html # Visual topology editor
|
|
166
|
+
└── utils/
|
|
167
|
+
└── id-generator.ts
|
|
168
|
+
```
|
package/README.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Spatial Awareness - Scrypted Plugin
|
|
2
|
+
|
|
3
|
+
Cross-camera object tracking for Scrypted NVR with spatial awareness capabilities.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Cross-Camera Tracking**: Correlate objects (people, vehicles, animals) as they move between cameras
|
|
8
|
+
- **Journey History**: Complete path history for each tracked object across your property
|
|
9
|
+
- **Entry/Exit Detection**: Know when objects enter or leave your property
|
|
10
|
+
- **Visual Floor Plan Editor**: Configure camera topology with an intuitive visual editor
|
|
11
|
+
- **MQTT Integration**: Export tracking data to Home Assistant for automations
|
|
12
|
+
- **REST API**: Query tracked objects and journeys programmatically
|
|
13
|
+
- **Smart Alerts**: Get notified about property entry/exit, unusual paths, dwell time, and restricted zones
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### From Scrypted Plugin Repository
|
|
18
|
+
1. Open Scrypted Management Console
|
|
19
|
+
2. Go to Plugins
|
|
20
|
+
3. Search for "Spatial Awareness"
|
|
21
|
+
4. Click Install
|
|
22
|
+
|
|
23
|
+
### From NPM
|
|
24
|
+
```bash
|
|
25
|
+
npm install @blueharford/scrypted-spatial-awareness
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Setup
|
|
29
|
+
|
|
30
|
+
1. **Add Cameras**: In plugin settings, select cameras with object detection enabled
|
|
31
|
+
2. **Configure Topology**:
|
|
32
|
+
- Access the visual editor at `/ui/editor` (via plugin's HTTP endpoint)
|
|
33
|
+
- Upload a floor plan image
|
|
34
|
+
- Place cameras on the floor plan
|
|
35
|
+
- Draw connections between cameras with expected transit times
|
|
36
|
+
3. **Enable Integrations**: Optionally enable MQTT for Home Assistant
|
|
37
|
+
4. **Create Zones**: Add tracking zones for specific area monitoring
|
|
38
|
+
|
|
39
|
+
## How It Works
|
|
40
|
+
|
|
41
|
+
The plugin listens to object detection events from all configured cameras. When an object (person, car, animal, package) is detected:
|
|
42
|
+
|
|
43
|
+
1. **Same Camera**: If the object is already being tracked on this camera, the sighting is added to its history
|
|
44
|
+
2. **Cross-Camera Correlation**: If the object disappeared from another camera recently, the plugin attempts to correlate using:
|
|
45
|
+
- **Timing (30%)**: Does the transit time match the expected range?
|
|
46
|
+
- **Visual (35%)**: Do the visual embeddings match (if available)?
|
|
47
|
+
- **Spatial (25%)**: Was the object in the exit zone of the previous camera and entry zone of the new camera?
|
|
48
|
+
- **Class (10%)**: Is it the same type of object?
|
|
49
|
+
3. **New Object**: If no correlation is found, a new tracked object is created
|
|
50
|
+
|
|
51
|
+
## API Endpoints
|
|
52
|
+
|
|
53
|
+
The plugin exposes a REST API via Scrypted's HTTP handler:
|
|
54
|
+
|
|
55
|
+
| Endpoint | Method | Description |
|
|
56
|
+
|----------|--------|-------------|
|
|
57
|
+
| `/api/tracked-objects` | GET | List all tracked objects |
|
|
58
|
+
| `/api/journey/{id}` | GET | Get journey for specific object |
|
|
59
|
+
| `/api/topology` | GET | Get camera topology configuration |
|
|
60
|
+
| `/api/topology` | PUT | Update camera topology |
|
|
61
|
+
| `/api/alerts` | GET | Get recent alerts |
|
|
62
|
+
| `/api/floor-plan` | GET/POST | Get or upload floor plan image |
|
|
63
|
+
| `/ui/editor` | GET | Visual topology editor |
|
|
64
|
+
|
|
65
|
+
## MQTT Topics
|
|
66
|
+
|
|
67
|
+
When MQTT is enabled, the plugin publishes to:
|
|
68
|
+
|
|
69
|
+
| Topic | Description |
|
|
70
|
+
|-------|-------------|
|
|
71
|
+
| `{baseTopic}/occupancy/state` | ON/OFF property occupancy |
|
|
72
|
+
| `{baseTopic}/count/state` | Number of active tracked objects |
|
|
73
|
+
| `{baseTopic}/person_count/state` | Number of people on property |
|
|
74
|
+
| `{baseTopic}/vehicle_count/state` | Number of vehicles on property |
|
|
75
|
+
| `{baseTopic}/state` | Full JSON state with all objects |
|
|
76
|
+
| `{baseTopic}/alerts` | Alert events |
|
|
77
|
+
| `{baseTopic}/events/entry` | Entry events |
|
|
78
|
+
| `{baseTopic}/events/exit` | Exit events |
|
|
79
|
+
| `{baseTopic}/events/transition` | Camera transition events |
|
|
80
|
+
|
|
81
|
+
Default base topic: `scrypted/spatial-awareness`
|
|
82
|
+
|
|
83
|
+
## Virtual Devices
|
|
84
|
+
|
|
85
|
+
The plugin creates these virtual devices in Scrypted:
|
|
86
|
+
|
|
87
|
+
### Global Object Tracker
|
|
88
|
+
- **Type**: Occupancy Sensor
|
|
89
|
+
- **Purpose**: Shows whether any objects are currently tracked on the property
|
|
90
|
+
- **Use**: Trigger automations when property becomes occupied/unoccupied
|
|
91
|
+
|
|
92
|
+
### Tracking Zones (User-Created)
|
|
93
|
+
- **Type**: Motion + Occupancy Sensor
|
|
94
|
+
- **Purpose**: Monitor specific areas across one or more cameras
|
|
95
|
+
- **Types**: Entry, Exit, Dwell, Restricted
|
|
96
|
+
- **Use**: Create zone-specific automations and alerts
|
|
97
|
+
|
|
98
|
+
## Alert Types
|
|
99
|
+
|
|
100
|
+
| Alert | Description |
|
|
101
|
+
|-------|-------------|
|
|
102
|
+
| Property Entry | Object entered the property via an entry point |
|
|
103
|
+
| Property Exit | Object exited the property via an exit point |
|
|
104
|
+
| Unusual Path | Object took an unexpected route between cameras |
|
|
105
|
+
| Dwell Time | Object lingered too long in an area |
|
|
106
|
+
| Restricted Zone | Object entered a restricted zone |
|
|
107
|
+
| Lost Tracking | Object disappeared without exiting |
|
|
108
|
+
|
|
109
|
+
## Configuration Options
|
|
110
|
+
|
|
111
|
+
### Tracking Settings
|
|
112
|
+
- **Correlation Window**: Maximum time (seconds) to wait for cross-camera correlation
|
|
113
|
+
- **Correlation Threshold**: Minimum confidence (0-1) for automatic correlation
|
|
114
|
+
- **Lost Timeout**: Time before marking an object as lost
|
|
115
|
+
- **Visual Matching**: Enable/disable visual embedding matching
|
|
116
|
+
|
|
117
|
+
### MQTT Settings
|
|
118
|
+
- **Enable MQTT**: Toggle MQTT publishing
|
|
119
|
+
- **Broker URL**: MQTT broker address (e.g., `mqtt://localhost:1883`)
|
|
120
|
+
- **Username/Password**: MQTT authentication
|
|
121
|
+
- **Base Topic**: Topic prefix for all messages
|
|
122
|
+
|
|
123
|
+
## Requirements
|
|
124
|
+
|
|
125
|
+
- Scrypted with NVR plugin
|
|
126
|
+
- Cameras with object detection enabled (via Scrypted NVR, OpenVINO, CoreML, ONNX, or TensorFlow Lite)
|
|
127
|
+
- Optional: MQTT broker for Home Assistant integration
|
|
128
|
+
|
|
129
|
+
## Development
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Install dependencies
|
|
133
|
+
npm install
|
|
134
|
+
|
|
135
|
+
# Build
|
|
136
|
+
npm run build
|
|
137
|
+
|
|
138
|
+
# Deploy to local Scrypted
|
|
139
|
+
npm run scrypted-deploy
|
|
140
|
+
|
|
141
|
+
# Debug in VS Code
|
|
142
|
+
# Edit .vscode/settings.json with your Scrypted server IP
|
|
143
|
+
# Press F5 to start debugging
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
Apache-2.0
|
|
149
|
+
|
|
150
|
+
## Author
|
|
151
|
+
|
|
152
|
+
Joshua Seidel ([@blueharford](https://github.com/blueharford))
|