@apocaliss92/scrypted-advanced-notifier 5.0.1 → 5.0.3
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 +8 -0
- package/IMPROVEMENT_PLAN.md +186 -0
- package/README.md +3 -1
- package/dist/plugin.zip +0 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
<details>
|
|
2
2
|
<summary>Changelog</summary>
|
|
3
3
|
|
|
4
|
+
### 5.0.3
|
|
5
|
+
|
|
6
|
+
Use REST interface to update entities instead of websocket, to avoid usage of admin permissions
|
|
7
|
+
|
|
8
|
+
### 5.0.2
|
|
9
|
+
|
|
10
|
+
Native HA component now available. Follow docs on page https://advanced-notifier-docs.zentik.app/docs/advanced-notifier/discovery for how to install and configure it
|
|
11
|
+
|
|
4
12
|
### 5.0.0
|
|
5
13
|
Finally An app is completed. It's called CamStack and it's available on testflight and as pwa on the scrypted local istance. Also available on https://camstack.zentik.app
|
|
6
14
|
New docs is up on https://advanced-notifier-docs.zentik.app/docs/advanced-notifier
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Advanced Notifier — Piano di Miglioramento
|
|
2
|
+
|
|
3
|
+
## Panoramica Codebase
|
|
4
|
+
|
|
5
|
+
| File | LOC | Problema |
|
|
6
|
+
|------|-----|----------|
|
|
7
|
+
| cameraMixin.ts | 6,669 | God class: 43+ metodi, 8 responsabilità, 13 metodi >100 LOC |
|
|
8
|
+
| utils.ts | 6,631 | God file: 120+ export, settings/rules/text/notifier mischiati |
|
|
9
|
+
| main.ts | 5,910 | God class: HTTP/MQTT/FS/DB/media/HA in un unico file |
|
|
10
|
+
| mqtt-utils.ts | 2,719 | 5 subscribe fn e 5 setup fn quasi identiche |
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. Memory Leak — Priorità CRITICA
|
|
15
|
+
|
|
16
|
+
### 1.1 Cache embedding senza limiti (main.ts)
|
|
17
|
+
- `imageEmbeddingCache: Record<string, Buffer>` — mai pulita
|
|
18
|
+
- `textEmbeddingCache: Record<string, Buffer>` — mai pulita
|
|
19
|
+
- **Fix:** Implementare LRU con max ~100 entry, o Map con TTL
|
|
20
|
+
|
|
21
|
+
### 1.2 State maps mai potate (cameraMixin.ts)
|
|
22
|
+
- `detectionIdEventIdMap` — cresce a ogni detection, mai pulita
|
|
23
|
+
- `objectIdLastReport` — per object ID, senza TTL
|
|
24
|
+
- `audioRuleSamples` — array `{timestamp, dBs}[]` per regola, mai trimmati
|
|
25
|
+
- `occupancyState` — contiene `b64Image` per regola, mai rilasciate
|
|
26
|
+
- `snoozeUntilDic` — entry mai rimosse
|
|
27
|
+
- `clipGenerationTimeout` — se la regola viene rimossa, il timeout resta
|
|
28
|
+
- **Fix:** TTL-based cleanup periodico (ogni 5 min), trim audioRuleSamples a max 1000 entry
|
|
29
|
+
|
|
30
|
+
### 1.3 Doppio caching immagine
|
|
31
|
+
- `lastFrame: Buffer` + `lastB64Image: string` — stessa immagine in due formati (~33% overhead)
|
|
32
|
+
- **Fix:** Tenere solo `lastB64Image`, decodificare on-demand se serve Buffer
|
|
33
|
+
|
|
34
|
+
### 1.4 State non pulite su device removal (main.ts)
|
|
35
|
+
- `cameraStates` — entry mai rimosse su releaseMixin
|
|
36
|
+
- `lastCameraAutodiscoveryMap` — entry per camera mai rimosse
|
|
37
|
+
- **Fix:** Pulire in `releaseMixin()`
|
|
38
|
+
|
|
39
|
+
### 1.5 release() incompleto (cameraMixin.ts)
|
|
40
|
+
- `release()` pulisce listener/interval ma NON: occupancyState, audioRuleSamples, detectionIdEventIdMap, maps vari
|
|
41
|
+
- **Fix:** Aggiungere cleanup completo in release()
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 2. Complessità Metodi — Priorità ALTA
|
|
46
|
+
|
|
47
|
+
### 2.1 Metodi >200 LOC da spezzare
|
|
48
|
+
|
|
49
|
+
| Metodo | LOC | Dove | Estrarre in |
|
|
50
|
+
|--------|-----|------|-------------|
|
|
51
|
+
| `onRequest()` | ~1,300 | main.ts | `HttpRouter` class con handler separati per route |
|
|
52
|
+
| `manualCheckOccupancyRule()` | ~853 | cameraMixin.ts | `OccupancyChecker.evaluate()` |
|
|
53
|
+
| `onRestart()` | ~745 | cameraMixin.ts | Separare occupancy check da restart logic |
|
|
54
|
+
| `startCheckInterval()` | ~580 | cameraMixin.ts | `enableRules()`, `setupMqtt()`, `scheduleMaintenance()` |
|
|
55
|
+
| `getDetectionRulesSettings()` | ~500 | utils.ts | `SettingsBuilder` class |
|
|
56
|
+
| `executeDetection()` | ~497 | cameraMixin.ts | `DetectionExecutor.run()` |
|
|
57
|
+
| `processDetections()` | ~460 | cameraMixin.ts | `acquireImage()`, `reportDetections()`, `matchRules()`, `storeData()` |
|
|
58
|
+
|
|
59
|
+
### 2.2 processDetections() — Pipeline
|
|
60
|
+
Attualmente è un metodo monolitico. Dovrebbe diventare una pipeline:
|
|
61
|
+
```
|
|
62
|
+
1. acquireDetectionImage(detect, eventSource) → {b64Image, image, imageSource}
|
|
63
|
+
2. reportBasicDetections(candidates, b64Image) → void (MQTT side-effect)
|
|
64
|
+
3. matchAndTriggerRules(candidates, image) → MatchRule[]
|
|
65
|
+
4. storeDetectionData(candidates, b64Image, eventSource) → void (FS side-effect)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 3. Duplicazione Codice — Priorità ALTA
|
|
71
|
+
|
|
72
|
+
### 3.1 mqtt-utils.ts — 5 subscribe fn identiche
|
|
73
|
+
`subscribeToPluginMqttTopics`, `subscribeToAlarmSystemMqttTopics`, `subscribeToCameraMqttTopics`, `subscribeToNotifierMqttTopics`, `subscribeToSensorMqttTopics` — stesso pattern:
|
|
74
|
+
```
|
|
75
|
+
check mqttClient → getEntities → for each → getMqttTopics → subscribe → check payload → callback → publish
|
|
76
|
+
```
|
|
77
|
+
**Fix:** Creare `MqttSubscriptionBuilder`:
|
|
78
|
+
```typescript
|
|
79
|
+
new MqttSubscriptionBuilder(mqttClient)
|
|
80
|
+
.addSwitch('recording', switchRecordingCb)
|
|
81
|
+
.addSwitch('snapshots', switchSnapshotsCb)
|
|
82
|
+
.subscribe()
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 3.2 mqtt-utils.ts — 5 setup/autodiscovery fn simili
|
|
86
|
+
`setupPluginAutodiscovery`, `setupAlarmSystemAutodiscovery`, `setupCameraAutodiscovery`, `setupNotifierAutodiscovery`, `setupSensorAutodiscovery`
|
|
87
|
+
**Fix:** Estrarre template comune `setupEntityAutodiscovery(type, entities, mqttClient)`
|
|
88
|
+
|
|
89
|
+
### 3.3 utils.ts — 6 pattern rules identici
|
|
90
|
+
`getDetectionRules`, `getDeviceOccupancyRules`, `getDeviceTimelapseRules`, `getDeviceAudioRules`, `getRecordingRules`, `getDevicePatrolRules` — tutti:
|
|
91
|
+
```
|
|
92
|
+
storage.getItem() → safeParseJson() → loop/filter → return {availableRules, allowedRules}
|
|
93
|
+
```
|
|
94
|
+
**Fix:** `createRuleProcessor(ruleType, storageKey, parser)` factory
|
|
95
|
+
|
|
96
|
+
### 3.4 cameraMixin.ts — switch subscribe duplicati (righe 1376-1435)
|
|
97
|
+
5 blocchi `if (switchXyzCb)` identici per rebroadcast, recording, snapshots, privacy, notifications
|
|
98
|
+
**Fix:** Usa il `MqttSubscriptionBuilder` del punto 3.1
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 4. Estrazione Moduli — Priorità MEDIA
|
|
103
|
+
|
|
104
|
+
### 4.1 Da cameraMixin.ts (6,669 LOC → ~5 file)
|
|
105
|
+
|
|
106
|
+
| Modulo | Responsabilità | LOC stimato |
|
|
107
|
+
|--------|----------------|-------------|
|
|
108
|
+
| `DetectionProcessor` | processDetections, executeDetection, checkRuleMatches | ~1,200 |
|
|
109
|
+
| `OccupancyChecker` | checkOccupancyData, manualCheckOccupancyRule | ~1,000 |
|
|
110
|
+
| `RecordingManager` | startRecording, stopRecording, getVideoClips | ~500 |
|
|
111
|
+
| `AudioAnalyzer` | startAudioAnalyzer, audio level, audio classification | ~400 |
|
|
112
|
+
| `DecoderManager` | initDecoderStream, startDecoder, stopDecoder, cleanup | ~300 |
|
|
113
|
+
|
|
114
|
+
### 4.2 Da main.ts (5,910 LOC → ~4 file)
|
|
115
|
+
|
|
116
|
+
| Modulo | Responsabilità | LOC stimato |
|
|
117
|
+
|--------|----------------|-------------|
|
|
118
|
+
| `HttpRouter` | onRequest, route matching, SPA serving | ~1,500 |
|
|
119
|
+
| `FilesystemStorage` | getFsPaths, getRulePaths, store*, clear* | ~800 |
|
|
120
|
+
| `MediaGenerator` | generateTimelapse, generateVideoclip, generateGif | ~400 |
|
|
121
|
+
| `QueueProcessor` | dbWriteQueue, clearVideoclipsQueue, autodiscoveryQueue | ~300 |
|
|
122
|
+
|
|
123
|
+
### 4.3 Da utils.ts (6,631 LOC → ~3 file)
|
|
124
|
+
|
|
125
|
+
| Modulo | Responsabilità | LOC stimato |
|
|
126
|
+
|--------|----------------|-------------|
|
|
127
|
+
| `ruleUtils.ts` | Tutti i rule getter, rule parsing, rule keys | ~2,000 |
|
|
128
|
+
| `settingsUtils.ts` | getTextSettings, getMixinBaseSettings, getRuleSettings | ~2,500 |
|
|
129
|
+
| `textUtils.ts` | Template text, i18n keys, text rendering | ~500 |
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 5. Anti-pattern da Correggere — Priorità BASSA
|
|
134
|
+
|
|
135
|
+
### 5.1 Fire-and-forget promises
|
|
136
|
+
```typescript
|
|
137
|
+
setupPluginAutodiscovery({...}).catch(logger.error); // no retry
|
|
138
|
+
publishPluginValues({...}).catch(logger.error); // silently fails
|
|
139
|
+
```
|
|
140
|
+
**Fix:** Implementare retry con backoff per operazioni critiche
|
|
141
|
+
|
|
142
|
+
### 5.2 Nested callback in notifyDetectionEvent
|
|
143
|
+
```typescript
|
|
144
|
+
const executeNotify = async (props) => { ... }
|
|
145
|
+
checkIfClipRequired({ cb: executeNotify, ... })
|
|
146
|
+
```
|
|
147
|
+
**Fix:** Linearizzare con async/await: `const clipRequired = await checkIfClipRequired(); if (clipRequired) await executeNotify();`
|
|
148
|
+
|
|
149
|
+
### 5.3 getBasicMqttEntities() non memoizzato
|
|
150
|
+
Crea 25+ entity definitions da zero a ogni chiamata.
|
|
151
|
+
**Fix:** Memoizzare a livello modulo (le entity non cambiano a runtime)
|
|
152
|
+
|
|
153
|
+
### 5.4 audioLabels hardcoded (285 righe)
|
|
154
|
+
Array da 285 righe in detectionClasses.ts
|
|
155
|
+
**Fix:** Spostare in file JSON esterno
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Ordine di Esecuzione Consigliato
|
|
160
|
+
|
|
161
|
+
### Fase 1 — Memory (impatto immediato su stabilità)
|
|
162
|
+
- [ ] 1.1 LRU su embedding cache
|
|
163
|
+
- [ ] 1.2 TTL cleanup su state maps cameraMixin
|
|
164
|
+
- [ ] 1.3 Rimuovere lastFrame, tenere solo lastB64Image
|
|
165
|
+
- [ ] 1.4 Cleanup in releaseMixin()
|
|
166
|
+
- [ ] 1.5 Completare release()
|
|
167
|
+
|
|
168
|
+
### Fase 2 — Duplicazione (riduce LOC, facilita manutenzione)
|
|
169
|
+
- [ ] 3.1 MqttSubscriptionBuilder
|
|
170
|
+
- [ ] 3.3 createRuleProcessor factory
|
|
171
|
+
- [ ] 3.2 Template autodiscovery comune
|
|
172
|
+
|
|
173
|
+
### Fase 3 — Estrazione moduli (architettura)
|
|
174
|
+
- [ ] 4.1 DetectionProcessor da cameraMixin
|
|
175
|
+
- [ ] 4.1 OccupancyChecker da cameraMixin
|
|
176
|
+
- [ ] 4.2 HttpRouter da main.ts
|
|
177
|
+
- [ ] 4.3 ruleUtils.ts e settingsUtils.ts da utils.ts
|
|
178
|
+
|
|
179
|
+
### Fase 4 — Complessità metodi
|
|
180
|
+
- [ ] 2.2 Pipeline processDetections
|
|
181
|
+
- [ ] 2.1 Spezzare metodi >200 LOC
|
|
182
|
+
|
|
183
|
+
### Fase 5 — Cleanup
|
|
184
|
+
- [ ] 5.1 Retry su promise critiche
|
|
185
|
+
- [ ] 5.2 Linearizzare callback
|
|
186
|
+
- [ ] 5.3 Memoizzare getBasicMqttEntities
|
package/README.md
CHANGED
|
@@ -3,4 +3,6 @@
|
|
|
3
3
|
☕️ If this extension works well for you, consider buying me a coffee. Thanks!
|
|
4
4
|
[Buy me a coffee!](https://buymeacoffee.com/apocaliss92)
|
|
5
5
|
|
|
6
|
-
**Documentation:** [https://advanced-notifier-docs.zentik.app/](https://advanced-notifier-docs.zentik.app/)
|
|
6
|
+
**Documentation:** [https://advanced-notifier-docs.zentik.app/docs/advanced-notifier](https://advanced-notifier-docs.zentik.app/docs/advanced-notifier)
|
|
7
|
+
|
|
8
|
+
[For requests and bugs](https://github.com/apocaliss92/scrypted-advanced-notifier)
|
package/dist/plugin.zip
CHANGED
|
Binary file
|