@apocaliss92/scrypted-advanced-notifier 4.8.36 → 4.8.38

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/CHANGELOG.md CHANGED
@@ -1,6 +1,10 @@
1
1
  <details>
2
2
  <summary>Changelog</summary>
3
3
 
4
+ ### 4.8.37
5
+
6
+ - **On-generated sequences**: new sequence hook for Detection, Occupancy and Timelapse rules. Runs when all rule artifacts (video, gif, image) have been generated. Configurable per rule under "On-generated sequences". Script actions in the sequence receive a `payload` object (e.g. `variables.payload` in Scrypted scripts) with `rule`, `videoUrl`, `gifUrl`, `imageUrl` (and for timelapse also `videoPath`, `imagePath`). Any sequence can now receive an optional payload and forward it to linked scripts.
7
+
4
8
  ### 4.8.36
5
9
 
6
10
  - Setting added on every rule to allow the selection of an additional path to save artifacts, with filename {deviceId}_{ruleName}_{triggerTime}.{ext}
package/README.md CHANGED
@@ -190,8 +190,35 @@ Audio rules will monitor the audio received by the camera
190
190
 
191
191
  ## Sequences
192
192
 
193
- In the sequences section, on the plugin page, you will be able to define a custom sequence with various steps. Sequences can be used on detection rules when it gets trigger or reset.
194
- (Initially only a few will be available, ask for more if you wish something more specific)
193
+ In the sequences section, on the plugin page, you will be able to define a custom sequence with various steps. Each sequence can contain actions such as: Wait, Script, PTZ preset, Switch on/off, Lock, Entry open/close.
194
+
195
+ Sequences can be attached to rules at different moments:
196
+
197
+ - **On-activation sequences** (rules with activation type other than Always): run when the rule becomes active.
198
+ - **On-deactivation sequences**: run when the rule becomes inactive.
199
+ - **On-trigger sequences**: run when the rule is triggered (e.g. detection matched, occupancy change).
200
+ - **On-reset sequences**: run when the rule is reset (e.g. after the trigger window ends).
201
+ - **On-generated sequences**: run when all artifacts for that rule have been generated (video clip, gif, image). Available for Detection, Occupancy and Timelapse rules.
202
+
203
+ When a sequence is run with a **payload** (e.g. On-generated), Script actions receive it as run variables. In Scrypted scripts, access it via `variables.payload`.
204
+
205
+ ### Payload for On-generated sequences
206
+
207
+ For **On-generated sequences**, the payload passed to scripts has the following shape:
208
+
209
+ - **Detection and Occupancy rules**: `{ rule, videoUrl?, gifUrl?, imageUrl }`
210
+ - `rule`: the rule object (name, notifiers, settings, etc.).
211
+ - `videoUrl`: URL of the generated video clip (if clip type is MP4).
212
+ - `gifUrl`: URL of the generated GIF (if clip type is GIF).
213
+ - `imageUrl`: URL of the stored snapshot used for the notification.
214
+
215
+ - **Timelapse rules**: `{ rule, videoUrl, imageUrl, videoPath?, imagePath? }`
216
+ - `rule`: the timelapse rule object.
217
+ - `videoUrl`: URL to the generated timelapse video.
218
+ - `imageUrl`: URL to the generated thumbnail image.
219
+ - `videoPath`, `imagePath`: filesystem paths where the video and image were saved (when available).
220
+
221
+ (Initially only a few action types will be available, ask for more if you wish something more specific)
195
222
 
196
223
  ## Stored images
197
224
 
package/dist/plugin.zip CHANGED
Binary file
@@ -0,0 +1,184 @@
1
+ # Migrazione da Webhook HTTP a Socket SDK con interfaceDescriptors
2
+
3
+ Piano per esporre i metodi Events App via **interfaceDescriptors** (come [@scrypted/llm](https://github.com/scryptedapp/llm)), eliminando le chiamate REST e usando solo la socket SDK.
4
+
5
+ ---
6
+
7
+ ## 1. Come funziona interfaceDescriptors (LLM plugin)
8
+
9
+ Dal [package.json dell'LLM](https://github.com/scryptedapp/llm/blob/main/package.json):
10
+
11
+ ```json
12
+ {
13
+ "scrypted": {
14
+ "interfaces": ["DeviceProvider", "UserDatabase", ...],
15
+ "interfaceDescriptors": {
16
+ "UserDatabase": {
17
+ "name": "UserDatabase",
18
+ "methods": ["openDatabase"],
19
+ "properties": []
20
+ }
21
+ }
22
+ }
23
+ }
24
+ ```
25
+
26
+ - **interfaceDescriptors** dichiara interfacce custom con metodi e proprietà
27
+ - Il server Scrypted usa questi descrittori per esporre i metodi via RPC sulla socket
28
+ - Il client può chiamare `device.openDatabase()` invece di fare HTTP
29
+
30
+ ---
31
+
32
+ ## 2. Metodi Events App da esporre (handleEventsAppRequest)
33
+
34
+ | apimethod | payload | Note |
35
+ |-----------|---------|------|
36
+ | GetConfigs | — | |
37
+ | GetCamerasStatus | — | |
38
+ | GetEvents | fromDate, tillDate, limit, offset, sources, cameras, detectionClasses, eventSource, filter, groupingRange | |
39
+ | GetVideoclips | fromDate, tillDate, limit, offset, cameras, detectionClasses | |
40
+ | GetCameraDayData | deviceId, day | |
41
+ | GetClusteredDayData | deviceId, days, bucketMs, enabledClasses, classFilter | |
42
+ | GetClusterEvents | clusterId, deviceId, startMs, endMs | |
43
+ | GetArtifacts | deviceId, day | |
44
+ | GetLatestRuleArtifacts | deviceId, limit | |
45
+ | RemoteLog | level, message | |
46
+
47
+ ---
48
+
49
+ ## 3. Modifiche al plugin advanced-notifier
50
+
51
+ ### 3.1 package.json — aggiungere interfaceDescriptors
52
+
53
+ ```json
54
+ {
55
+ "scrypted": {
56
+ "interfaces": ["Settings", "DeviceProvider", "MixinProvider", "HttpRequestHandler", "Videoclips", "LauncherApplication", "PushHandler"],
57
+ "interfaceDescriptors": {
58
+ "EventsAppApi": {
59
+ "name": "EventsAppApi",
60
+ "methods": [
61
+ "getConfigs",
62
+ "getCamerasStatus",
63
+ "getEvents",
64
+ "getVideoclips",
65
+ "getCameraDayData",
66
+ "getClusteredDayData",
67
+ "getClusterEvents",
68
+ "getArtifacts",
69
+ "getLatestRuleArtifacts",
70
+ "remoteLog"
71
+ ],
72
+ "properties": []
73
+ }
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ ### 3.2 utils.ts — costante interfaccia
80
+
81
+ ```ts
82
+ export const EVENTS_APP_API_INTERFACE = "EventsAppApi";
83
+ ```
84
+
85
+ ### 3.3 main.ts — aggiungere interfaccia al data fetcher
86
+
87
+ In `onDeviceDiscovered` per DATA_FETCHER_NATIVE_ID:
88
+
89
+ ```ts
90
+ interfaces: [
91
+ ScryptedInterface.VideoClips,
92
+ ScryptedInterface.EventRecorder,
93
+ ScryptedInterface.Settings,
94
+ EVENTS_APP_API_INTERFACE, // <-- aggiungere
95
+ ],
96
+ ```
97
+
98
+ ### 3.4 dataFetcher.ts — implementare EventsAppApi
99
+
100
+ La classe `AdvancedNotifierDataFetcher` deve implementare i metodi pubblici che mappano 1:1 con gli apimethod. Esempio:
101
+
102
+ ```ts
103
+ // EventsAppApi interface
104
+ async getConfigs(): Promise<{ cameras: ...; enabledDetectionSources: string[] }> {
105
+ const { statusCode, body } = await this.handleEventsAppRequest('GetConfigs', {});
106
+ if (statusCode !== 200) throw new Error(JSON.stringify(body));
107
+ return body as any;
108
+ }
109
+ async getCamerasStatus(): Promise<CamerasStatusResponse> { ... }
110
+ async getEvents(payload: GetEventsPayload): Promise<GetEventsResponse> { ... }
111
+ // ... etc
112
+ ```
113
+
114
+ Oppure, più pulito: estrarre la logica da `handleEventsAppRequest` in metodi dedicati e far sì che `handleEventsAppRequest` li chiami, così si evita duplicazione.
115
+
116
+ ---
117
+
118
+ ## 4. Come il server Scrypted gestisce interfaceDescriptors
119
+
120
+ Il server Scrypted (koush/scrypted) legge `interfaceDescriptors` dal `package.json` del plugin. Quando un device dichiara un'interfaccia in `interfaces`, il server:
121
+
122
+ 1. Verifica che l'interfaccia sia in `interfaceDescriptors` (per interfacce custom)
123
+ 2. Espone i metodi via RPC sulla socket Engine.IO
124
+ 3. Il client `@scrypted/client` può chiamare `device.getConfigs()` e la chiamata viene serializzata e inviata via socket
125
+
126
+ Non serve modificare il server: il supporto è già presente. Il client deve solo usare `client.systemManager.getDeviceById(deviceId)` e chiamare i metodi sull'oggetto restituito.
127
+
128
+ ---
129
+
130
+ ## 5. Modifiche al client (camstack / scrypted-an-frontend)
131
+
132
+ ### 5.1 Trovare il device Events App
133
+
134
+ Il device "Advanced notifier data fetcher" ha tipo `API` e implementa `EventsAppApi`. Per ottenere il suo ID:
135
+
136
+ ```ts
137
+ const state = client.systemManager.getSystemState();
138
+ const eventsAppDeviceId = Object.entries(state).find(
139
+ ([_, d]) => (d as any)?.interfaces?.includes?.('EventsAppApi')
140
+ )?.[0];
141
+ ```
142
+
143
+ Oppure cercare per nome/tipo se lo stato lo espone.
144
+
145
+ ### 5.2 Sostituire fetch con chiamate SDK
146
+
147
+ **Prima (HTTP):**
148
+ ```ts
149
+ const res = await fetch(`${baseUrl}/eventsApp`, {
150
+ method: 'POST',
151
+ body: JSON.stringify({ apimethod: 'GetClusteredDayData', payload: { deviceId, days, bucketMs } }),
152
+ headers: { 'Content-Type': 'application/json', Authorization: getAuthHeader(auth) },
153
+ });
154
+ const data = await res.json();
155
+ ```
156
+
157
+ **Dopo (Socket):**
158
+ ```ts
159
+ const client = await getScryptedClient(auth);
160
+ const device = client.systemManager.getDeviceById(eventsAppDeviceId) as EventsAppApi;
161
+ const data = await device.getClusteredDayData({ deviceId, days, bucketMs });
162
+ ```
163
+
164
+ ### 5.3 Cosa resta su HTTP
165
+
166
+ - **URL di immagini/thumbnail/video**: usati in `<Image src={url} />` e `<Video source={{ uri }} />` — devono restare URL HTTP. Il plugin continua a servire `/eventThumbnail/...`, `/eventImage/...`, `/eventVideoclip/...` via HttpRequestHandler.
167
+ - **Autenticazione**: la socket SDK usa già le credenziali del client (login con username/password). Non serve più Basic auth per le chiamate dati.
168
+
169
+ ---
170
+
171
+ ## 6. Ordine di implementazione
172
+
173
+ 1. **Plugin**: aggiungere `interfaceDescriptors` e `EVENTS_APP_API_INTERFACE`, implementare i metodi su `AdvancedNotifierDataFetcher`
174
+ 2. **Mantenere HttpRequestHandler**: per `apimethod` POST a `/eventsApp` — opzionale durante la transizione (fallback)
175
+ 3. **Client**: creare `eventsAppSdk.ts` che usa la socket; `eventsAppApi.ts` può passare a usare l'SDK quando il client è connesso
176
+ 4. **Rimuovere** le chiamate fetch a `/eventsApp` dal client una volta validato l'SDK
177
+
178
+ ---
179
+
180
+ ## 7. Riferimenti
181
+
182
+ - [LLM plugin package.json](https://github.com/scryptedapp/llm/blob/main/package.json) — esempio interfaceDescriptors
183
+ - [Scrypted Developer Docs](https://developer.scrypted.app/) — interfacce e plugin
184
+ - [@scrypted/client](https://www.npmjs.com/package/@scrypted/client) — SDK client con socket
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "type": "git",
6
6
  "url": "https://github.com/apocaliss92/scrypted-advanced-notifier"
7
7
  },
8
- "version": "4.8.36",
8
+ "version": "4.8.38",
9
9
  "scripts": {
10
10
  "scrypted-setup-project": "scrypted-setup-project",
11
11
  "prescrypted-setup-project": "scrypted-package-json",
@@ -49,9 +49,31 @@
49
49
  "HttpRequestHandler",
50
50
  "Videoclips",
51
51
  "LauncherApplication",
52
- "PushHandler"
52
+ "PushHandler",
53
+ "EventsAppApi"
53
54
  ],
54
- "pluginDependencies": []
55
+ "pluginDependencies": [],
56
+ "interfaceDescriptors": {
57
+ "EventsAppApi": {
58
+ "name": "EventsAppApi",
59
+ "methods": [
60
+ "getConfigs",
61
+ "getCamerasStatus",
62
+ "getEvents",
63
+ "getVideoclips",
64
+ "getCameraDayData",
65
+ "getClusteredDayData",
66
+ "getClusterEvents",
67
+ "getArtifacts",
68
+ "getLatestRuleArtifacts",
69
+ "remoteLog",
70
+ "getAsset",
71
+ "getVideoClipThumbnailData",
72
+ "getVideoClipData"
73
+ ],
74
+ "properties": []
75
+ }
76
+ }
55
77
  },
56
78
  "dependencies": {
57
79
  "@scrypted/common": "file:../scrypted/common",
@@ -69,4 +91,4 @@
69
91
  "@types/lodash": "^4.17.12",
70
92
  "@types/node": "^20.11.0"
71
93
  }
72
- }
94
+ }