@trillboards/edge-sdk 0.2.3 → 0.2.6

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.
Files changed (200) hide show
  1. package/README.md +4 -3
  2. package/deploy/docker/Dockerfile.cloud-sense +117 -0
  3. package/deploy/docker/Dockerfile.cpu +30 -21
  4. package/deploy/docker/Dockerfile.cuda +30 -21
  5. package/deploy/docker/Dockerfile.openvino +30 -20
  6. package/deploy/docker/README.md +9 -4
  7. package/deploy/docker/connector-entrypoint.sh +122 -0
  8. package/deploy/helm/README.md +1 -1
  9. package/deploy/k8s/daemonset.yaml +1 -1
  10. package/deploy/macos/README.md +161 -0
  11. package/deploy/macos/TrillboardsSetupApp.m +603 -0
  12. package/deploy/macos/build-macos-pkg.sh +588 -0
  13. package/deploy/macos/com.trillboards.edge.plist +62 -0
  14. package/deploy/macos/com.trillboards.litertlm.plist +45 -0
  15. package/deploy/macos/pair.command +519 -0
  16. package/deploy/macos/scripts/ensure-litertlm.sh +62 -0
  17. package/deploy/macos/scripts/postinstall +153 -0
  18. package/deploy/macos/scripts/setup-litertlm.sh +272 -0
  19. package/deploy/macos/test-install-pair.sh +383 -0
  20. package/deploy/macos/test-setup-litertlm-reinstall.sh +109 -0
  21. package/deploy/systemd/install.sh +25 -15
  22. package/deploy/systemd/trillboards-edge.service +4 -1
  23. package/deploy/windows/README.md +70 -0
  24. package/deploy/windows/build-windows.ps1 +225 -0
  25. package/deploy/windows/bundle-windows-installer.ps1 +153 -0
  26. package/deploy/windows/check-feeds.js +26 -0
  27. package/deploy/windows/e2e/fixtures/person.jpg +0 -0
  28. package/deploy/windows/e2e/test-local-sense.ps1 +185 -0
  29. package/deploy/windows/install-update.ps1 +101 -0
  30. package/deploy/windows/installer.nsi +138 -0
  31. package/deploy/windows/register-litertlm-task.ps1 +42 -0
  32. package/deploy/windows/register-task.ps1 +44 -0
  33. package/deploy/windows/run-connector.ps1 +69 -0
  34. package/deploy/windows/setup-litertlm.ps1 +361 -0
  35. package/deploy/windows/stop-existing.ps1 +72 -0
  36. package/deploy/windows/trillboards-edge-task.vbs +25 -0
  37. package/deploy/windows/trillboards-edge.cmd +33 -0
  38. package/deploy/windows/trillboards-pair.cmd +276 -0
  39. package/deploy/windows/trillboards-setup.ps1 +456 -0
  40. package/deploy/windows/trillboards-setup.vbs +13 -0
  41. package/dist/AudienceAnalyzeClient.d.ts +136 -0
  42. package/dist/AudienceAnalyzeClient.d.ts.map +1 -0
  43. package/dist/AudienceAnalyzeClient.js +246 -0
  44. package/dist/AudienceAnalyzeClient.js.map +1 -0
  45. package/dist/ChannelProber.d.ts +150 -0
  46. package/dist/ChannelProber.d.ts.map +1 -0
  47. package/dist/ChannelProber.js +887 -0
  48. package/dist/ChannelProber.js.map +1 -0
  49. package/dist/CloudEscalationPolicy.d.ts +143 -0
  50. package/dist/CloudEscalationPolicy.d.ts.map +1 -0
  51. package/dist/CloudEscalationPolicy.js +137 -0
  52. package/dist/CloudEscalationPolicy.js.map +1 -0
  53. package/dist/CloudSensingManager.d.ts +533 -0
  54. package/dist/CloudSensingManager.d.ts.map +1 -0
  55. package/dist/CloudSensingManager.js +1254 -0
  56. package/dist/CloudSensingManager.js.map +1 -0
  57. package/dist/DiscoveryReportClient.d.ts +66 -0
  58. package/dist/DiscoveryReportClient.d.ts.map +1 -0
  59. package/dist/DiscoveryReportClient.js +85 -0
  60. package/dist/DiscoveryReportClient.js.map +1 -0
  61. package/dist/EdgeAgent.d.ts +12 -2
  62. package/dist/EdgeAgent.d.ts.map +1 -1
  63. package/dist/EdgeAgent.js +122 -65
  64. package/dist/EdgeAgent.js.map +1 -1
  65. package/dist/LiteRtVlmProvider.d.ts +193 -0
  66. package/dist/LiteRtVlmProvider.d.ts.map +1 -0
  67. package/dist/LiteRtVlmProvider.js +436 -0
  68. package/dist/LiteRtVlmProvider.js.map +1 -0
  69. package/dist/MosaicSource.d.ts +108 -0
  70. package/dist/MosaicSource.d.ts.map +1 -0
  71. package/dist/MosaicSource.js +274 -0
  72. package/dist/MosaicSource.js.map +1 -0
  73. package/dist/OnvifClient.d.ts +83 -0
  74. package/dist/OnvifClient.d.ts.map +1 -0
  75. package/dist/OnvifClient.js +209 -0
  76. package/dist/OnvifClient.js.map +1 -0
  77. package/dist/PairClient.d.ts +106 -0
  78. package/dist/PairClient.d.ts.map +1 -0
  79. package/dist/PairClient.js +186 -0
  80. package/dist/PairClient.js.map +1 -0
  81. package/dist/RecorderAddressRecovery.d.ts +53 -0
  82. package/dist/RecorderAddressRecovery.d.ts.map +1 -0
  83. package/dist/RecorderAddressRecovery.js +359 -0
  84. package/dist/RecorderAddressRecovery.js.map +1 -0
  85. package/dist/SceneChangeDetector.d.ts +291 -0
  86. package/dist/SceneChangeDetector.d.ts.map +1 -0
  87. package/dist/SceneChangeDetector.js +682 -0
  88. package/dist/SceneChangeDetector.js.map +1 -0
  89. package/dist/SensingProfileClient.d.ts +59 -0
  90. package/dist/SensingProfileClient.d.ts.map +1 -0
  91. package/dist/SensingProfileClient.js +78 -0
  92. package/dist/SensingProfileClient.js.map +1 -0
  93. package/dist/SetupSessionClient.d.ts +114 -0
  94. package/dist/SetupSessionClient.d.ts.map +1 -0
  95. package/dist/SetupSessionClient.js +95 -0
  96. package/dist/SetupSessionClient.js.map +1 -0
  97. package/dist/VlmAdmissionGate.d.ts +126 -0
  98. package/dist/VlmAdmissionGate.d.ts.map +1 -0
  99. package/dist/VlmAdmissionGate.js +166 -0
  100. package/dist/VlmAdmissionGate.js.map +1 -0
  101. package/dist/autoSense.d.ts +216 -0
  102. package/dist/autoSense.d.ts.map +1 -0
  103. package/dist/autoSense.js +521 -0
  104. package/dist/autoSense.js.map +1 -0
  105. package/dist/cli.d.ts +27 -1
  106. package/dist/cli.d.ts.map +1 -1
  107. package/dist/cli.js +511 -21
  108. package/dist/cli.js.map +1 -1
  109. package/dist/combinedSense.d.ts +128 -0
  110. package/dist/combinedSense.d.ts.map +1 -0
  111. package/dist/combinedSense.js +261 -0
  112. package/dist/combinedSense.js.map +1 -0
  113. package/dist/config.d.ts +351 -0
  114. package/dist/config.d.ts.map +1 -1
  115. package/dist/config.js +99 -2
  116. package/dist/config.js.map +1 -1
  117. package/dist/connectorCadence.d.ts +135 -0
  118. package/dist/connectorCadence.d.ts.map +1 -0
  119. package/dist/connectorCadence.js +151 -0
  120. package/dist/connectorCadence.js.map +1 -0
  121. package/dist/dataDir.d.ts +33 -0
  122. package/dist/dataDir.d.ts.map +1 -0
  123. package/dist/dataDir.js +76 -0
  124. package/dist/dataDir.js.map +1 -0
  125. package/dist/deployedCadence.d.ts +167 -0
  126. package/dist/deployedCadence.d.ts.map +1 -0
  127. package/dist/deployedCadence.js +209 -0
  128. package/dist/deployedCadence.js.map +1 -0
  129. package/dist/deployedCadenceSource.d.ts +48 -0
  130. package/dist/deployedCadenceSource.d.ts.map +1 -0
  131. package/dist/deployedCadenceSource.js +74 -0
  132. package/dist/deployedCadenceSource.js.map +1 -0
  133. package/dist/diagnose.d.ts +1 -1
  134. package/dist/diagnose.d.ts.map +1 -1
  135. package/dist/diagnose.js +13 -12
  136. package/dist/diagnose.js.map +1 -1
  137. package/dist/discovery.d.ts +131 -0
  138. package/dist/discovery.d.ts.map +1 -0
  139. package/dist/discovery.js +499 -0
  140. package/dist/discovery.js.map +1 -0
  141. package/dist/gemmaModelOta.d.ts +118 -0
  142. package/dist/gemmaModelOta.d.ts.map +1 -0
  143. package/dist/gemmaModelOta.js +291 -0
  144. package/dist/gemmaModelOta.js.map +1 -0
  145. package/dist/index.d.ts +16 -1
  146. package/dist/index.d.ts.map +1 -1
  147. package/dist/index.js +40 -1
  148. package/dist/index.js.map +1 -1
  149. package/dist/init.d.ts.map +1 -1
  150. package/dist/init.js +41 -18
  151. package/dist/init.js.map +1 -1
  152. package/dist/keepAwake.d.ts +33 -0
  153. package/dist/keepAwake.d.ts.map +1 -0
  154. package/dist/keepAwake.js +54 -0
  155. package/dist/keepAwake.js.map +1 -0
  156. package/dist/legacyRecorderProfile.d.ts +20 -0
  157. package/dist/legacyRecorderProfile.d.ts.map +1 -0
  158. package/dist/legacyRecorderProfile.js +27 -0
  159. package/dist/legacyRecorderProfile.js.map +1 -0
  160. package/dist/localInferenceSchema.d.ts +132 -0
  161. package/dist/localInferenceSchema.d.ts.map +1 -0
  162. package/dist/localInferenceSchema.js +274 -0
  163. package/dist/localInferenceSchema.js.map +1 -0
  164. package/dist/localSenseE2eHarness.d.ts +101 -0
  165. package/dist/localSenseE2eHarness.d.ts.map +1 -0
  166. package/dist/localSenseE2eHarness.js +279 -0
  167. package/dist/localSenseE2eHarness.js.map +1 -0
  168. package/dist/localSensing.d.ts +268 -0
  169. package/dist/localSensing.d.ts.map +1 -0
  170. package/dist/localSensing.js +492 -0
  171. package/dist/localSensing.js.map +1 -0
  172. package/dist/modelIntegrity.d.ts +59 -0
  173. package/dist/modelIntegrity.d.ts.map +1 -0
  174. package/dist/modelIntegrity.js +165 -0
  175. package/dist/modelIntegrity.js.map +1 -0
  176. package/dist/pairVerify.d.ts +100 -0
  177. package/dist/pairVerify.d.ts.map +1 -0
  178. package/dist/pairVerify.js +296 -0
  179. package/dist/pairVerify.js.map +1 -0
  180. package/dist/qrScanner.d.ts +33 -0
  181. package/dist/qrScanner.d.ts.map +1 -0
  182. package/dist/qrScanner.js +103 -0
  183. package/dist/qrScanner.js.map +1 -0
  184. package/dist/runtimePaths.d.ts +10 -0
  185. package/dist/runtimePaths.d.ts.map +1 -0
  186. package/dist/runtimePaths.js +79 -0
  187. package/dist/runtimePaths.js.map +1 -0
  188. package/dist/sensingRunMode.d.ts +68 -0
  189. package/dist/sensingRunMode.d.ts.map +1 -0
  190. package/dist/sensingRunMode.js +346 -0
  191. package/dist/sensingRunMode.js.map +1 -0
  192. package/dist/setupMode.d.ts +98 -0
  193. package/dist/setupMode.d.ts.map +1 -0
  194. package/dist/setupMode.js +828 -0
  195. package/dist/setupMode.js.map +1 -0
  196. package/dist/setupProgress.d.ts +31 -0
  197. package/dist/setupProgress.d.ts.map +1 -0
  198. package/dist/setupProgress.js +173 -0
  199. package/dist/setupProgress.js.map +1 -0
  200. package/package.json +13 -4
@@ -0,0 +1,533 @@
1
+ import { EventEmitter } from 'events';
2
+ import type { CameraProvider } from '@trillboards/edge-core';
3
+ import { AudienceAnalyzeClient, type AudienceAnalyzeResponse, type CameraHealthFailureClass, type CameraHealthReport, type HttpPoster } from './AudienceAnalyzeClient';
4
+ import { SharedFrameSource } from './MosaicSource';
5
+ import type { EdgeAgentConfig, MosaicTile, RecorderIdentity } from './config';
6
+ import { type VlmAdmissionStats } from './VlmAdmissionGate';
7
+ import { type MotionGateOptions } from './SceneChangeDetector';
8
+ import type { DeployedCadence } from './deployedCadence';
9
+ export declare function classifyRtspFailureClass(err: unknown): CameraHealthFailureClass;
10
+ /**
11
+ * The subset of AudienceAnalyzeClient the cadence loop needs. A local-inference
12
+ * client (LocalSensingClient — see localSensing.ts) substitutes here to run the
13
+ * VLM ON-DEVICE and POST the structured result as `preAnalyzed`, so the manager
14
+ * runs UNCHANGED for both the cloud and local paths.
15
+ */
16
+ export interface SensingClient {
17
+ analyze(request: {
18
+ jpeg: Buffer;
19
+ captureMode?: string;
20
+ }): Promise<AudienceAnalyzeResponse>;
21
+ reportCameraHealth?(cameraHealth: CameraHealthReport): Promise<AudienceAnalyzeResponse>;
22
+ getEndpoint(): string;
23
+ /**
24
+ * Cloud escalations this client has made (LocalSensingClient only). Optional
25
+ * so the plain cloud client — which has nothing to escalate TO — implements
26
+ * nothing. Aggregated into `getSensingHealth()` because a frame leaving the
27
+ * premises has to be countable by the operator, not just documented.
28
+ */
29
+ getEscalationStats?(): {
30
+ enabled: boolean;
31
+ escalated: number;
32
+ };
33
+ }
34
+ /** A camera + its dedicated sensing client (one feed = one token). */
35
+ export interface SensingLoopDeps {
36
+ /** Label for logs/stats (defaults to the feed name or screenId). */
37
+ name: string;
38
+ camera: CameraProvider;
39
+ client: SensingClient;
40
+ }
41
+ export interface CloudSensingManagerOptions {
42
+ /** Per-feed capture loops. */
43
+ loops: SensingLoopDeps[];
44
+ /** Capture interval (ms) when NO faces. Default: 300000. */
45
+ periodicIntervalMs?: number;
46
+ /** Capture interval (ms) when faces ARE detected. Default: 30000. */
47
+ faceTriggeredIntervalMs?: number;
48
+ /** JPEG quality for the POSTed frame. Default: 70. */
49
+ jpegQuality?: number;
50
+ /** Skip the POST when no faces (still captures periodically). Default: true. */
51
+ skipPostWhenNoFaces?: boolean;
52
+ /** Frame width (for raw RGB24 → JPEG encoding). */
53
+ width?: number;
54
+ /** Frame height (for raw RGB24 → JPEG encoding). */
55
+ height?: number;
56
+ /**
57
+ * Initial delay (ms) before the first RTSP re-open attempt after a drop.
58
+ * Doubles each consecutive failure up to `reconnectMaxDelayMs`, then holds at
59
+ * the cap and retries FOREVER. Default: 1000. The connector self-recovers when
60
+ * the camera/feed comes back; it never permanently gives up.
61
+ */
62
+ reconnectInitialDelayMs?: number;
63
+ /** Cap (ms) for the exponential reconnect backoff. Default: 30000. */
64
+ reconnectMaxDelayMs?: number;
65
+ /**
66
+ * Additional per-feed phase offset (ms) added by loop index when multiple
67
+ * cameras run in one connector. Default: 1000 for multi-feed, 0 for single.
68
+ */
69
+ feedStaggerMs?: number;
70
+ /** Cap for the computed per-feed phase offset. Default: 15000. */
71
+ maxFeedStaggerMs?: number;
72
+ /**
73
+ * Consecutive non-auth RTSP failures tolerated before reporting failed
74
+ * camera health. Auth failures still report immediately. Default: 3.
75
+ */
76
+ cameraHealthFailureGraceCount?: number;
77
+ /**
78
+ * Decode-only camera probe cadence while every inference slot is busy.
79
+ * This keeps video liveness independent from AI throughput without opening
80
+ * a second persistent RTSP session. Default: 120000.
81
+ */
82
+ cameraHealthProbeIntervalMs?: number;
83
+ /** Maximum gap between connector/sensing status beacons. Default: 60000. */
84
+ cameraHealthHeartbeatIntervalMs?: number;
85
+ /**
86
+ * Concurrent analyze() calls allowed across ALL feeds in this process — the
87
+ * global admission gate. Default: one slot per loop (i.e. today's unbounded
88
+ * fan-out), so the cloud path, whose backend really is concurrent, is
89
+ * unchanged. LOCAL sensing MUST set this to 1: `litert-lm serve` is a
90
+ * single-conversation server and 16 free-running loops oversubscribe it ~17x.
91
+ */
92
+ maxConcurrentAnalyses?: number;
93
+ /**
94
+ * Reclaim an admission slot held longer than this (ms). Default 180000 — the
95
+ * provider's 120 s HTTP timeout plus retry headroom. Guards a 24/7 connector
96
+ * against one lost promise wedging every camera forever.
97
+ */
98
+ maxAnalysisInFlightMs?: number;
99
+ /**
100
+ * Delay (ms) before a tick the admission gate denied tries again. Default:
101
+ * the derived stagger step, clamped to 250…5000. Short on purpose — the loop
102
+ * dropped its frame, so this is a cheap poll for a freed slot, not a queue.
103
+ */
104
+ admissionRetryDelayMs?: number;
105
+ /**
106
+ * Cheap motion cascade in front of the model. Omitted ⇒ disabled and every
107
+ * captured frame is analyzed (today's behavior). `heartbeatIntervalMs`
108
+ * defaults to `periodicIntervalMs` and `minAnalyzeIntervalMs` to
109
+ * `faceTriggeredIntervalMs`, so the analyze rate stays inside the cadence
110
+ * band the config already declares — the gate can only REMOVE calls.
111
+ */
112
+ motionGate?: Partial<MotionGateOptions> & {
113
+ enabled?: boolean;
114
+ /**
115
+ * How often a STILL feed takes a look (ms) once the cascade is on.
116
+ * Defaults to `faceTriggeredIntervalMs`. Looking is the cheap half — an
117
+ * RTSP grab plus a few ms of motion — so it runs at the responsive
118
+ * cadence while `periodicIntervalMs` becomes the gate's heartbeat: the
119
+ * guaranteed reporting floor for a scene where genuinely nothing happens.
120
+ */
121
+ scanIntervalMs?: number;
122
+ };
123
+ /**
124
+ * Let the motion verdict drive the periodic/face-triggered cadence switch —
125
+ * finally supplying the `setFaceDetected` signal this loop was always
126
+ * documented to consume. Default: true whenever `motionGate` is enabled.
127
+ */
128
+ motionDrivesCadence?: boolean;
129
+ /**
130
+ * Where this connector learns the cadence its OPERATOR deployed. Polled every
131
+ * `cadenceRefreshIntervalMs`; a null answer leaves the current cadence alone.
132
+ * Omitted ⇒ the cadence is whatever the config said at construction, which is
133
+ * the behavior every connector had before this existed.
134
+ */
135
+ cadenceSource?: CadenceSource;
136
+ /** How often to ask `cadenceSource`. Default 300000 (the profile TTL). */
137
+ cadenceRefreshIntervalMs?: number;
138
+ /** Clock injection for tests. Default `Date.now`. */
139
+ now?: () => number;
140
+ }
141
+ /**
142
+ * The connector's link to the cadence its operator actually deployed.
143
+ *
144
+ * `resolve()` returns the FULL verdict rather than a number so the clamp — and,
145
+ * on the cloud path, the bill the operator is being protected from — stays
146
+ * legible in `getSensingHealth()` instead of being silently applied.
147
+ */
148
+ export interface CadenceSource {
149
+ resolve(): Promise<DeployedCadence | null>;
150
+ }
151
+ export declare class CloudSensingManager extends EventEmitter {
152
+ private readonly loops;
153
+ /**
154
+ * NOT readonly: the deployed profile's cadence must be able to reach a
155
+ * RUNNING connector. Until this changed, the interval was frozen at
156
+ * construction and the only way to alter a venue's cadence was to edit
157
+ * trillboards.config.json on their machine and restart the process — while
158
+ * the server was already serving the operator's chosen value every 5 minutes
159
+ * to a client that discarded it. See setPeriodicIntervalMs + deployedCadence.
160
+ */
161
+ private periodicIntervalMs;
162
+ /** The last cadence verdict applied, surfaced by getSensingHealth(). */
163
+ private cadence;
164
+ private readonly cadenceSource?;
165
+ private readonly cadenceRefreshIntervalMs;
166
+ private cadenceTimer;
167
+ private readonly faceTriggeredIntervalMs;
168
+ private readonly jpegQuality;
169
+ private readonly skipPostWhenNoFaces;
170
+ private readonly width?;
171
+ private readonly height?;
172
+ private readonly reconnectInitialDelayMs;
173
+ private readonly reconnectMaxDelayMs;
174
+ private readonly feedStaggerMs;
175
+ private readonly maxFeedStaggerMs;
176
+ private readonly cameraHealthFailureGraceCount;
177
+ private readonly cameraHealthProbeIntervalMs;
178
+ private readonly cameraHealthHeartbeatIntervalMs;
179
+ private readonly admissionGate;
180
+ private readonly admissionRetryDelayMs;
181
+ private readonly motionDrivesCadence;
182
+ /** Retained so a cadence change can rebuild each feed's gate heartbeat. */
183
+ private motionGateOptions;
184
+ /** Look-rate for a still feed when the cascade is on. null ⇒ cascade off. */
185
+ private motionScanIntervalMs;
186
+ private readonly now;
187
+ private running;
188
+ private startGeneration;
189
+ private runStartedAtMs;
190
+ /** One decode-only probe at a time protects recorder session limits. */
191
+ private healthCaptureInFlight;
192
+ constructor(options: CloudSensingManagerOptions);
193
+ /**
194
+ * Retune a RUNNING connector's still-scene cadence.
195
+ *
196
+ * Timers are NOT cancelled: each loop re-arms from `nextDelayFor` in its own
197
+ * `.finally`, so the new interval takes effect on the next tick. Cancelling
198
+ * and rescheduling here would collapse every feed's carefully-staggered phase
199
+ * onto the same instant — the multi-camera NVR stampede `staggerStepMs`
200
+ * exists to prevent — for no gain, since the worst-case lag is one old
201
+ * period.
202
+ *
203
+ * The motion gate's HEARTBEAT tracks the cadence, because the heartbeat IS
204
+ * the still-scene reporting floor: leaving it at the old value would let a
205
+ * gate keep reporting on a cadence the operator has replaced.
206
+ *
207
+ * The heartbeat is retuned IN PLACE (`MotionGate.setHeartbeatIntervalMs`) and
208
+ * NOT by rebuilding the gate. A fresh `MotionGate` is a fresh
209
+ * `SceneChangeDetector`: no background model, `calibrating` re-armed, the
210
+ * contrast ring un-seeded, the stationary signature forgotten and — the
211
+ * expensive one — `lastAnalyzedAtMs` back to null, which makes the very next
212
+ * look heartbeat-DUE and forces an inference on a scene the gate had already
213
+ * proven still. Measured: a byte-identical still frame costs 0 analyses over
214
+ * ten looks, then exactly +1 per feed the instant the cadence moves. On a
215
+ * 16-camera store that is 16 forced generations against the connector's single
216
+ * slot for a change that was meant to cost nothing. Rebuilding also swapped
217
+ * the object mid-tick, so a frame's `evaluate()` and its `markAnalyzed()`
218
+ * could land on two different gates.
219
+ *
220
+ * @returns true when the interval actually changed.
221
+ */
222
+ setPeriodicIntervalMs(intervalMs: number): boolean;
223
+ /** The still-scene cadence currently in force. */
224
+ getPeriodicIntervalMs(): number;
225
+ /**
226
+ * Ask the cadence source what the operator deployed and apply it. Best-effort
227
+ * and never throws: a failed lookup leaves the running cadence untouched,
228
+ * because a connector that resets to a default every time the API blips is
229
+ * worse than one that is briefly stale.
230
+ */
231
+ refreshDeployedCadence(): Promise<DeployedCadence | null>;
232
+ /** Number of independent capture loops (== number of feeds/tokens). */
233
+ getLoopCount(): number;
234
+ /** Per-loop stats (capture + POST counts, cadence, cascade drops). */
235
+ getStats(): Array<{
236
+ name: string;
237
+ captureCount: number;
238
+ postCount: number;
239
+ faceDetected: boolean;
240
+ currentIntervalMs: number;
241
+ admissionDeniedCount: number;
242
+ motionSkipCount: number;
243
+ }>;
244
+ /** Live admission-gate counters (admitted / dropped / stale-reclaimed). */
245
+ getAdmissionStats(): VlmAdmissionStats;
246
+ /**
247
+ * The operator-facing answer to "why is my 16-camera store only sampling
248
+ * every N seconds?" — sustained analyses/minute is what the machine can
249
+ * actually do, and `effectiveSampleIntervalMs` is what that buys each camera.
250
+ * Drops are attributed: `admissionDenied` means the backend is the ceiling,
251
+ * `motionSkipped` means the cascade decided the frame was not worth paying
252
+ * for. Both are wins over the old failure mode, where the surplus vanished
253
+ * into 120 s timeouts.
254
+ */
255
+ getSensingHealth(): {
256
+ loops: number;
257
+ maxConcurrentAnalyses: number;
258
+ inFlight: number;
259
+ uptimeMs: number;
260
+ analyses: number;
261
+ analysesPerMinute: number;
262
+ effectiveSampleIntervalMs: number | null;
263
+ /** The still-scene cadence in force right now (a deployed profile can move it). */
264
+ periodicIntervalMs: number;
265
+ /**
266
+ * What the operator's deployed profile asked for, and what actually
267
+ * happened to it. null before the first successful lookup, or when this
268
+ * connector has no cadence source. The clamp is REPORTED rather than
269
+ * silently applied — an operator who set 30 s and is running 303 s has to
270
+ * be able to see both numbers and the reason.
271
+ */
272
+ deployedCadence: DeployedCadence | null;
273
+ admissionDenied: number;
274
+ motionSkipped: number;
275
+ /**
276
+ * Frames sent to the cloud VLM for confirmation (local sensing with
277
+ * escalation enabled). 0 — and `cloudEscalationEnabled:false` — for a
278
+ * fully-local or cloud-sensing deployment.
279
+ */
280
+ cloudEscalated: number;
281
+ cloudEscalationEnabled: boolean;
282
+ perFeed: Array<{
283
+ name: string;
284
+ captures: number;
285
+ analyses: number;
286
+ admissionDenied: number;
287
+ motionSkipped: number;
288
+ cloudEscalated: number;
289
+ faceDetected: boolean;
290
+ currentIntervalMs: number;
291
+ }>;
292
+ };
293
+ isRunning(): boolean;
294
+ /** Open cameras, prove one frame, and start capture loops without one slow feed blocking others. */
295
+ start(): Promise<void>;
296
+ /** Stop all loops and close cameras. */
297
+ stop(): Promise<void>;
298
+ /**
299
+ * Notify a loop (by feed name) that its face-detection state changed —
300
+ * switches that loop between the periodic and face-triggered cadence.
301
+ */
302
+ setFaceDetected(loopName: string, detected: boolean): void;
303
+ /**
304
+ * Same cadence switch, but from INSIDE a running tick: record the new state
305
+ * and announce it WITHOUT rescheduling. The tick's own `finally` already
306
+ * calls scheduleNext and will read the updated interval — rescheduling here
307
+ * as well would leave the feed running two concurrent timers.
308
+ */
309
+ private applyMotionCadence;
310
+ /**
311
+ * Capture + (conditionally) POST one frame for a given loop, immediately.
312
+ *
313
+ * Goes through the SAME cascade as a scheduled tick — an out-of-band capture
314
+ * that jumped the admission gate would break the very invariant the gate
315
+ * exists to hold. Returns `null` (rather than waiting) when the gate is
316
+ * closed or the motion stage judged the frame not worth an inference.
317
+ */
318
+ captureNow(loopName: string): Promise<AudienceAnalyzeResponse | null>;
319
+ private isCurrentStart;
320
+ private startLoop;
321
+ private closeCameraQuietly;
322
+ /**
323
+ * How long until this feed's next LOOK.
324
+ *
325
+ * Without the cascade this is the historical rule: fast while faces are
326
+ * present, slow otherwise. With the cascade on, a still feed keeps looking at
327
+ * the scan cadence — looking is cheap and only analysis is gated — and
328
+ * `periodicIntervalMs` becomes the gate's heartbeat, i.e. the floor on
329
+ * REPORTING rather than the rate of watching.
330
+ */
331
+ private intervalFor;
332
+ /**
333
+ * Per-feed phase step, derived from FEED COUNT and CADENCE instead of a fixed
334
+ * per-feed cap.
335
+ *
336
+ * The spread window is the smaller of the configured `maxFeedStaggerMs` and
337
+ * the fastest capture cadence (a spread longer than one period would just
338
+ * re-alias), and the step is the largest value that fits every feed inside
339
+ * it, never exceeding the configured `feedStaggerMs`. Small installs keep
340
+ * exactly today's offsets (4 feeds x 1000 ms); a 16-camera store gets 16
341
+ * DISTINCT offsets instead of feeds 15+ colliding on the cap.
342
+ */
343
+ private staggerStepMs;
344
+ private staggerFor;
345
+ /**
346
+ * Delay before the next tick.
347
+ *
348
+ * - Camera dropped → the reconnect backoff, PLUS the phase offset so a
349
+ * recorder that rebooted does not get all N feeds re-opening in lock-step.
350
+ * - Admission denied → a short one-shot retry (consumed here) so the loop
351
+ * takes the inference slot as soon as it frees rather than idling a full
352
+ * cadence.
353
+ * - Otherwise → exactly the capture cadence. The phase offset is applied ONCE
354
+ * at startup (and on reconnect); adding it to every tick would make feed i's
355
+ * period `cadence + offset_i`, quietly stretching the last feed's cadence by
356
+ * the whole spread window — a 47 % slower camera 16 at the 30 s cadence.
357
+ * Equal periods preserve the startup phase difference forever.
358
+ */
359
+ private nextDelayFor;
360
+ /**
361
+ * Arm this feed's next tick, for ONE run of the manager.
362
+ *
363
+ * `generation` is not decoration. A tick re-arms from its own `.finally`, and
364
+ * that `.finally` can run AFTER a stop()/start() cycle — the auto-sense
365
+ * supervisor stops and restarts the SAME manager instance every time
366
+ * `litert-lm` appears or disappears, and a cloud analyze can be in flight for
367
+ * up to two minutes. Without the generation the surviving tick re-arms a
368
+ * chain, `startLoop` arms another, and `s.timer` holds only the second one, so
369
+ * `stop()` can never clear the first: the feed now captures twice per cadence,
370
+ * permanently, and every further flap adds another chain. Measured: two
371
+ * pending timers for ONE feed after a single cycle. On the cloud path
372
+ * `maxConcurrentAnalyses` defaults to one slot PER LOOP, so the duplicate
373
+ * chain is duplicate Vertex spend, not just duplicate RTSP load.
374
+ */
375
+ private scheduleNext;
376
+ /**
377
+ * One scheduled loop iteration with built-in RTSP self-recovery.
378
+ *
379
+ * If the camera is dropped (closed), this attempts to RE-OPEN it (the keystone
380
+ * 24/7 fix — a transient feed/network blip used to wedge the loop on "camera
381
+ * is not open" forever). On a successful re-open the backoff resets and the
382
+ * tick falls through to a normal capture so sensing resumes immediately; on a
383
+ * failed re-open the backoff doubles (capped) and we retry FOREVER. The
384
+ * per-attempt connect timeout still lives in the RTSP provider's open() — only
385
+ * the give-up-forever behavior changes to retry-forever.
386
+ */
387
+ private runScheduledTick;
388
+ /**
389
+ * Attempt one camera re-open. Returns true on success (backoff cleared, sensing
390
+ * resumes), false on failure (backoff doubled+capped for the next attempt).
391
+ * Emits `reconnecting` before each attempt and `reconnected` on recovery so
392
+ * operators can observe the self-healing on an unattended connector.
393
+ */
394
+ private tryReopen;
395
+ /**
396
+ * Put a loop into reconnect mode (camera dropped). Idempotent: an already
397
+ * dropped loop keeps its current (climbing) backoff rather than resetting to
398
+ * the initial delay.
399
+ */
400
+ private enterReconnect;
401
+ private emitLoopError;
402
+ private reportCameraFailure;
403
+ private reportCameraHealth;
404
+ private reportCameraOpen;
405
+ private healthProbeDue;
406
+ /**
407
+ * Prove video locally without waiting for the model. The global boolean keeps
408
+ * legacy recorders to one extra short-lived ffmpeg pull at a time.
409
+ */
410
+ private captureHealthFrame;
411
+ /**
412
+ * One cascade pass for a feed: admission → capture → motion → inference,
413
+ * with a bounded decode-only health probe when admission is denied.
414
+ *
415
+ * The admission check comes first so denied inference frames are dropped,
416
+ * never buffered. Video health is independent: at most one feed at a time
417
+ * may take a slow-cadence decode-only proof while the model is occupied.
418
+ */
419
+ private captureAndPost;
420
+ /**
421
+ * Convert a camera frame to JPEG bytes for the POST.
422
+ *
423
+ * RTSP frames arrive as raw RGB24 Buffers, so we encode them with `sharp`
424
+ * when available (the standard sensing dep). If `sharp` is missing AND the
425
+ * frame is already JPEG (some providers emit JPEG directly), we ship it
426
+ * as-is; raw-RGB-without-sharp is rejected loudly so it never silently POSTs
427
+ * an un-decodable frame.
428
+ *
429
+ * Dimensions are needed to decode raw RGB24. Resolution order: the camera's
430
+ * own getResolution() (passed in by the caller — works for multi-channel
431
+ * feeds with no top-level camera.width/height), then the manager's configured
432
+ * width/height, then EdgeImageData's own dims.
433
+ */
434
+ private toJpeg;
435
+ }
436
+ /**
437
+ * Build the per-feed capture loops from an EdgeAgentConfig — the bridge between
438
+ * config (`cameras: [...]` multi-channel, or single `camera`) and the manager.
439
+ *
440
+ * - Multi-channel: one loop per `cameras[]` entry, each with its own token +
441
+ * its own RTSP provider.
442
+ * - Single-camera (back-compat): one loop from the top-level `camera`/token.
443
+ *
444
+ * `rtspProviderFactory` / `clientFactory` are injectable for tests; defaults
445
+ * use the neutral RTSP package + AudienceAnalyzeClient.
446
+ */
447
+ export declare function buildSensingLoops(config: EdgeAgentConfig, deps?: {
448
+ rtspProviderFactory?: (feed: ResolvedFeed) => CameraProvider;
449
+ streamUrlResolver?: (feed: ResolvedFeed, currentUrl: string, error: Error) => Promise<string | null>;
450
+ clientFactory?: (feed: ResolvedFeed) => AudienceAnalyzeClient;
451
+ httpPoster?: HttpPoster;
452
+ /** Freshness window (ms) a mosaic tile reuses the shared pull. Default 5000. */
453
+ sharedFrameMaxAgeMs?: number;
454
+ /** Shared per-mosaic-source pull registry so the VLM attaches to the SAME
455
+ * SharedFrameSource the on-device zoo uses (one RTSP pull for both rails). */
456
+ sharedSources?: Map<string, SharedFrameSource>;
457
+ }): SensingLoopDeps[];
458
+ /**
459
+ * Build one CameraProvider per feed, collapsing mosaic tiles that share a source
460
+ * onto a SINGLE shared RTSP pull. This is the ONE implementation of mosaic
461
+ * tiling, used by BOTH cloud-sense (buildSensingLoops) and local-sense
462
+ * (buildLocalSensingLoops) — no split-brain between run modes. Returns feed↔camera
463
+ * pairs so each caller attaches its own sensing client.
464
+ *
465
+ * Grouping: a feed opts into sharing a pull only via `sourceFeedId` (a tile → its
466
+ * mosaic source) or by being that source (`id`); a feed with neither is solo
467
+ * (keyed uniquely) and gets exactly the historical one-provider-per-feed path.
468
+ *
469
+ * `rtspFactory` builds the underlying RTSP provider and MUST honor `feed.crop`
470
+ * (used by the per-tile-pull fallback when no source feed is configured).
471
+ */
472
+ export declare function buildTiledCameras(feeds: ResolvedFeed[], rtspFactory: (feed: ResolvedFeed) => CameraProvider, opts?: {
473
+ sharedFrameMaxAgeMs?: number;
474
+ /**
475
+ * Memoizes the per-mosaic-source SharedFrameSource so MULTIPLE consumers
476
+ * (the VLM rail AND the on-device ONNX zoo rail) attach to the SAME single
477
+ * RTSP pull instead of each opening its own. Keyed by the mosaic group key
478
+ * (the source feed's `id`). When omitted, each call builds its own sources
479
+ * (unchanged single-consumer behavior).
480
+ */
481
+ sharedSources?: Map<string, SharedFrameSource>;
482
+ /**
483
+ * Pixel format each tile's CropViewProvider emits: 'jpeg' (default, the
484
+ * VLM/cloud POST) or 'rgb24' (raw RGB the on-device ONNX FaceDetector
485
+ * consumes). Both carve from the SAME JPEG mosaic pull; only the per-tile
486
+ * re-encode differs, so two consumers can share one pull at different formats.
487
+ */
488
+ cropOutputFormat?: 'jpeg' | 'rgb24';
489
+ }): Array<{
490
+ feed: ResolvedFeed;
491
+ camera: CameraProvider;
492
+ }>;
493
+ /** A fully-resolved feed (token + rtspUrl guaranteed present). */
494
+ export interface ResolvedFeed {
495
+ name: string;
496
+ /** Config-local feed id (set on a mosaic source feed; tiles point at it). */
497
+ id?: string;
498
+ screenId?: string;
499
+ deviceToken: string;
500
+ rtspUrl: string;
501
+ sourceType?: 'recorder' | 'direct_url';
502
+ channelKey?: string;
503
+ recorder?: RecorderIdentity;
504
+ width?: number;
505
+ height?: number;
506
+ fps?: number;
507
+ transport?: 'tcp' | 'udp';
508
+ ffmpegPath?: string;
509
+ /**
510
+ * Mosaic tiling. `sourceFeedId` groups this tile with its mosaic source (the
511
+ * feed whose `id` matches) so the source RTSP is pulled ONCE; `crop` is the
512
+ * tile's sub-rectangle in source pixels, carved in ffmpeg. Both omitted ⇒ a
513
+ * normal whole-frame feed with its own dedicated pull (unchanged).
514
+ */
515
+ sourceFeedId?: string;
516
+ crop?: MosaicTile;
517
+ /**
518
+ * Frame encoding the RTSP provider should emit. Cloud-sense always wants
519
+ * 'jpeg' so ffmpeg encodes directly and NO image library (sharp) is needed
520
+ * for the POST. Set on every resolved feed by resolveFeeds().
521
+ */
522
+ outputFormat?: 'rgb24' | 'jpeg';
523
+ /** JPEG quality (1-100) when outputFormat='jpeg'. */
524
+ jpegQuality?: number;
525
+ }
526
+ /**
527
+ * Flatten an EdgeAgentConfig into the list of feeds to run. Multi-channel
528
+ * `cameras[]` wins; otherwise the single `camera` (+ top-level token) becomes
529
+ * a one-element list (back-compat). Feeds without both a token and rtspUrl are
530
+ * skipped (the single-camera fallback needs both for cloud sensing).
531
+ */
532
+ export declare function resolveFeeds(config: EdgeAgentConfig): ResolvedFeed[];
533
+ //# sourceMappingURL=CloudSensingManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CloudSensingManager.d.ts","sourceRoot":"","sources":["../src/CloudSensingManager.ts"],"names":[],"mappings":"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"}