@camstack/addon-provider-ecowitt 0.1.22 → 0.1.23
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/addon.js +194 -14
- package/dist/addon.mjs +194 -14
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
let http = require("http");
|
|
3
3
|
let events = require("events");
|
|
4
4
|
let dgram = require("dgram");
|
|
5
|
-
//#region ../types/dist/event-category-
|
|
5
|
+
//#region ../types/dist/event-category-H4AVePnn.mjs
|
|
6
6
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
7
7
|
EventCategory["SystemBoot"] = "system.boot";
|
|
8
8
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -152,6 +152,9 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
152
152
|
EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
|
|
153
153
|
EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
|
|
154
154
|
EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
|
|
155
|
+
/** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
|
|
156
|
+
* thumb is a scrub gap the recorder's keyframe backfill covers. */
|
|
157
|
+
EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
|
|
155
158
|
EventCategory["DetectionEvent"] = "detection.event";
|
|
156
159
|
EventCategory["SessionTrackNew"] = "session.track.new";
|
|
157
160
|
EventCategory["SessionTrackExpired"] = "session.track.expired";
|
|
@@ -10799,10 +10802,23 @@ var deviceDiscoveryCapability = {
|
|
|
10799
10802
|
}
|
|
10800
10803
|
};
|
|
10801
10804
|
/**
|
|
10802
|
-
* Doorbell button cap.
|
|
10803
|
-
*
|
|
10804
|
-
*
|
|
10805
|
-
*
|
|
10805
|
+
* Doorbell button cap. Two kinds of providers coexist behind this cap
|
|
10806
|
+
* name (same pattern as `snapshot`):
|
|
10807
|
+
*
|
|
10808
|
+
* - **Native** providers: registered per-device by device-driver
|
|
10809
|
+
* addons via `ctx.registerNativeCap` — either on a
|
|
10810
|
+
* `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
|
|
10811
|
+
* or directly on the camera (Reolink registers at camera level).
|
|
10812
|
+
* Emits an `onPressed` event every time the firmware pushes a
|
|
10813
|
+
* ring; status tracks the last press and a pressCount since start
|
|
10814
|
+
* (diagnostic).
|
|
10815
|
+
*
|
|
10816
|
+
* - **Wrapper** provider: the `virtual-doorbell` system builtin
|
|
10817
|
+
* (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
|
|
10818
|
+
* device (contact / switch / event-emitter …) into a doorbell for
|
|
10819
|
+
* a camera. `defaultActive: false` — the operator explicitly binds
|
|
10820
|
+
* it per camera in the device-bindings UI, then picks the source
|
|
10821
|
+
* device + trigger in the per-device settings.
|
|
10806
10822
|
*
|
|
10807
10823
|
* The DeviceEventPropagator re-emits `onPressed` on the camera parent
|
|
10808
10824
|
* — subscribers listening at the camera level receive ring events
|
|
@@ -10823,7 +10839,10 @@ var doorbellCapability = {
|
|
|
10823
10839
|
scope: "device",
|
|
10824
10840
|
deviceNative: true,
|
|
10825
10841
|
mode: "singleton",
|
|
10826
|
-
|
|
10842
|
+
kind: "wrapper",
|
|
10843
|
+
defaultActive: false,
|
|
10844
|
+
deviceTypes: [DeviceType.Button, DeviceType.Camera],
|
|
10845
|
+
exposesDeviceSettings: true,
|
|
10827
10846
|
methods: {},
|
|
10828
10847
|
events: {
|
|
10829
10848
|
/**
|
|
@@ -17175,6 +17194,14 @@ var ConfigEntrySchema = object({
|
|
|
17175
17194
|
value: unknown(),
|
|
17176
17195
|
description: string().optional()
|
|
17177
17196
|
});
|
|
17197
|
+
var DeviceLinkModeSchema = _enum(["auto", "manual"]);
|
|
17198
|
+
/** One resolved linked device — the compact projection consumers need. */
|
|
17199
|
+
var LinkedDeviceSchema = object({
|
|
17200
|
+
deviceId: number(),
|
|
17201
|
+
name: string(),
|
|
17202
|
+
location: string().nullable(),
|
|
17203
|
+
features: array(string())
|
|
17204
|
+
});
|
|
17178
17205
|
var SavedDeviceRowSchema = object({
|
|
17179
17206
|
/** Numeric id reserved at allocateDeviceId time. */
|
|
17180
17207
|
id: number(),
|
|
@@ -17396,7 +17423,10 @@ method(object({
|
|
|
17396
17423
|
}), _void(), {
|
|
17397
17424
|
kind: "mutation",
|
|
17398
17425
|
auth: "admin"
|
|
17399
|
-
}), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }),
|
|
17426
|
+
}), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
|
|
17427
|
+
mode: DeviceLinkModeSchema,
|
|
17428
|
+
devices: array(LinkedDeviceSchema)
|
|
17429
|
+
})), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
|
|
17400
17430
|
deviceId: number(),
|
|
17401
17431
|
values: record(string(), unknown())
|
|
17402
17432
|
}), object({ success: literal(true) }), {
|
|
@@ -18665,6 +18695,61 @@ var EventKindSchema = _enum([
|
|
|
18665
18695
|
"object",
|
|
18666
18696
|
"audio"
|
|
18667
18697
|
]);
|
|
18698
|
+
/**
|
|
18699
|
+
* Spatial filter for `listTracks` — the rect + polygon variants of the shared
|
|
18700
|
+
* MaskShape vocabulary (see `mask-shape.ts`). Coordinates are NORMALIZED 0..1
|
|
18701
|
+
* of the camera frame (top-left origin), matching the drawing-plane editor.
|
|
18702
|
+
*/
|
|
18703
|
+
var TrackZoneFilterSchema = discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
|
|
18704
|
+
/** Closed icon vocabulary so clients render a known glyph per kind. */
|
|
18705
|
+
var EventKindIconSchema = _enum([
|
|
18706
|
+
"motion",
|
|
18707
|
+
"audio",
|
|
18708
|
+
"person",
|
|
18709
|
+
"vehicle",
|
|
18710
|
+
"animal",
|
|
18711
|
+
"door",
|
|
18712
|
+
"pir",
|
|
18713
|
+
"smoke",
|
|
18714
|
+
"water",
|
|
18715
|
+
"button",
|
|
18716
|
+
"generic"
|
|
18717
|
+
]);
|
|
18718
|
+
var EventKindCategorySchema = _enum([
|
|
18719
|
+
"motion",
|
|
18720
|
+
"audio",
|
|
18721
|
+
"detection",
|
|
18722
|
+
"sensor",
|
|
18723
|
+
"custom"
|
|
18724
|
+
]);
|
|
18725
|
+
var EventKindDescriptorSchema = object({
|
|
18726
|
+
/** Stable kind id (e.g. 'motion', 'person', 'contact'). */
|
|
18727
|
+
kind: string(),
|
|
18728
|
+
label: string(),
|
|
18729
|
+
/** Hex color for timeline/legend rendering. */
|
|
18730
|
+
color: string(),
|
|
18731
|
+
icon: EventKindIconSchema,
|
|
18732
|
+
category: EventKindCategorySchema,
|
|
18733
|
+
/** Which cap + device contributes this kind. For built-ins the camera
|
|
18734
|
+
* itself; for sensor kinds the LINKED source device. */
|
|
18735
|
+
source: object({
|
|
18736
|
+
capName: string(),
|
|
18737
|
+
deviceId: number()
|
|
18738
|
+
})
|
|
18739
|
+
});
|
|
18740
|
+
var SensorEventSchema = object({
|
|
18741
|
+
id: string(),
|
|
18742
|
+
/** The CAMERA the event is attributed to (a sensor linked to N cameras
|
|
18743
|
+
* yields N rows, one per camera). */
|
|
18744
|
+
deviceId: number(),
|
|
18745
|
+
/** The linked sensor device whose state changed. */
|
|
18746
|
+
sourceDeviceId: number(),
|
|
18747
|
+
/** Event kind id — matches an `EventKindDescriptor.kind`. */
|
|
18748
|
+
kind: string(),
|
|
18749
|
+
/** Snapshot of the sensor cap's runtime-state slice at the change. */
|
|
18750
|
+
value: record(string(), unknown()).nullable(),
|
|
18751
|
+
timestamp: number()
|
|
18752
|
+
});
|
|
18668
18753
|
var TrackPositionSchema = object({
|
|
18669
18754
|
x: number(),
|
|
18670
18755
|
y: number(),
|
|
@@ -18678,6 +18763,30 @@ var TrackSnapshotSchema = object({
|
|
|
18678
18763
|
mediaKey: string()
|
|
18679
18764
|
});
|
|
18680
18765
|
/**
|
|
18766
|
+
* Normalized 0..1 trajectory envelope (min/max over every position bbox,
|
|
18767
|
+
* divided by the track's detection-frame dims), computed at persist time.
|
|
18768
|
+
* Absent when the frame dims were unknown when the track was persisted
|
|
18769
|
+
* (legacy rows / dims-less sources) and on active (in-RAM) tracks.
|
|
18770
|
+
*/
|
|
18771
|
+
var TrackEnvelopeSchema = object({
|
|
18772
|
+
minX: number(),
|
|
18773
|
+
minY: number(),
|
|
18774
|
+
maxX: number(),
|
|
18775
|
+
maxY: number()
|
|
18776
|
+
});
|
|
18777
|
+
/**
|
|
18778
|
+
* Row projection for track list queries. `full` (default) returns the
|
|
18779
|
+
* complete Track including the frame-rate `positions[]` history and the
|
|
18780
|
+
* `snapshots[]` references — megabytes across a page of tracks. `slim`
|
|
18781
|
+
* keeps every scalar the list surfaces actually render (ids, class(es),
|
|
18782
|
+
* label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
|
|
18783
|
+
* zonesVisited, bestEventId, envelope) and returns `positions` /
|
|
18784
|
+
* `snapshots` as EMPTY arrays — detail views re-fetch the full row via
|
|
18785
|
+
* `getTrack`. Mirrors the event-store `projection` convention
|
|
18786
|
+
* (`getObjectEvents` et al.).
|
|
18787
|
+
*/
|
|
18788
|
+
var TrackProjectionSchema = _enum(["full", "slim"]);
|
|
18789
|
+
/**
|
|
18681
18790
|
* One audio-classification label heard on the track's camera while the
|
|
18682
18791
|
* track was alive, aggregated per label. An "episode" is one persisted
|
|
18683
18792
|
* audio event (the confident-classification path: score ≥ the device's
|
|
@@ -18728,7 +18837,11 @@ var TrackSchema = object({
|
|
|
18728
18837
|
/** Audio-classification labels heard on the camera during the track's
|
|
18729
18838
|
* life (score ≥ device `classificationMinScore`), aggregated per label.
|
|
18730
18839
|
* Absent on legacy rows / tracks with no confident audio. */
|
|
18731
|
-
audioLabels: array(TrackAudioLabelSchema).readonly().optional()
|
|
18840
|
+
audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
|
|
18841
|
+
/** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
|
|
18842
|
+
* Populated from the persisted envelope columns on historical reads;
|
|
18843
|
+
* absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
|
|
18844
|
+
envelope: TrackEnvelopeSchema.optional()
|
|
18732
18845
|
});
|
|
18733
18846
|
var BaseEventFields = {
|
|
18734
18847
|
id: string(),
|
|
@@ -18838,11 +18951,13 @@ var MediaFileSchema = object({
|
|
|
18838
18951
|
sizeBytes: number(),
|
|
18839
18952
|
timestamp: number()
|
|
18840
18953
|
});
|
|
18954
|
+
var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
|
|
18955
|
+
var MAX_EVENT_QUERY_LIMIT = 5e3;
|
|
18841
18956
|
var DeviceEventQueryInput = object({
|
|
18842
18957
|
deviceId: number(),
|
|
18843
18958
|
since: number().optional(),
|
|
18844
18959
|
until: number().optional(),
|
|
18845
|
-
limit: number().int().min(1).max(
|
|
18960
|
+
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
|
|
18846
18961
|
/** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
|
|
18847
18962
|
* optional `mediaUrl` (populated by B5). `full` (default) keeps today's
|
|
18848
18963
|
* exact behaviour. Callers may omit this field — the store defaults to
|
|
@@ -18850,6 +18965,27 @@ var DeviceEventQueryInput = object({
|
|
|
18850
18965
|
projection: _enum(["full", "slim"]).optional()
|
|
18851
18966
|
});
|
|
18852
18967
|
var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
|
|
18968
|
+
var RecentTracksQueryInput = object({
|
|
18969
|
+
/** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
|
|
18970
|
+
deviceIds: array(number()),
|
|
18971
|
+
/** Window lower bound on `lastSeen` (inclusive). */
|
|
18972
|
+
since: number().optional(),
|
|
18973
|
+
/** Window upper bound on `lastSeen` (inclusive). */
|
|
18974
|
+
until: number().optional(),
|
|
18975
|
+
/** Page size. Default 200, max 1000. */
|
|
18976
|
+
limit: number().int().min(1).max(1e3).default(200),
|
|
18977
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`.
|
|
18978
|
+
* Encodes the (lastSeen, trackId) sort position — treat as opaque. */
|
|
18979
|
+
cursor: string().optional(),
|
|
18980
|
+
/** See {@link TrackProjectionSchema}. Default `full`. */
|
|
18981
|
+
projection: TrackProjectionSchema.optional()
|
|
18982
|
+
});
|
|
18983
|
+
var RecentTracksPageSchema = object({
|
|
18984
|
+
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
18985
|
+
tracks: array(TrackSchema).readonly(),
|
|
18986
|
+
/** Cursor for the next page, or null when this page is the last. */
|
|
18987
|
+
nextCursor: string().nullable()
|
|
18988
|
+
});
|
|
18853
18989
|
var KeyEventQueryInput = object({
|
|
18854
18990
|
deviceId: number(),
|
|
18855
18991
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
@@ -18932,11 +19068,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
18932
19068
|
deviceId: number(),
|
|
18933
19069
|
since: number().optional(),
|
|
18934
19070
|
until: number().optional(),
|
|
18935
|
-
limit: number().optional()
|
|
18936
|
-
|
|
19071
|
+
limit: number().optional(),
|
|
19072
|
+
/** Spatial filter — only tracks whose trajectory intersects the zone
|
|
19073
|
+
* (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
|
|
19074
|
+
* envelope columns, then precisely tested per position. Tracks with
|
|
19075
|
+
* an unknown envelope (no frame dims at persist time) always match. */
|
|
19076
|
+
zone: TrackZoneFilterSchema.optional(),
|
|
19077
|
+
/** See {@link TrackProjectionSchema}. Default `full` (backward
|
|
19078
|
+
* compatible — omitting the field keeps today's exact behaviour). */
|
|
19079
|
+
projection: TrackProjectionSchema.optional()
|
|
19080
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
|
|
18937
19081
|
kind: "mutation",
|
|
18938
19082
|
auth: "admin"
|
|
18939
|
-
}), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(
|
|
19083
|
+
}), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
|
|
19084
|
+
deviceId: number(),
|
|
19085
|
+
since: number().optional(),
|
|
19086
|
+
until: number().optional(),
|
|
19087
|
+
kinds: array(string()).optional(),
|
|
19088
|
+
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19089
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
18940
19090
|
deviceId: number(),
|
|
18941
19091
|
since: number(),
|
|
18942
19092
|
until: number(),
|
|
@@ -22137,7 +22287,12 @@ var RecordingStorageUsageSchema = object({
|
|
|
22137
22287
|
/**
|
|
22138
22288
|
* Result of locating footage at a wall-clock instant for one device/profile.
|
|
22139
22289
|
* `segment` carries the covering segment's window; `gap` reports the forward
|
|
22140
|
-
* nearest covered edge (`null` past the end of footage / when none exists)
|
|
22290
|
+
* nearest covered edge (`null` past the end of footage / when none exists)
|
|
22291
|
+
* and the backward covered edge `prevEndMs` (exclusive end of the nearest
|
|
22292
|
+
* footage behind the epoch; `null` when none — optional so older providers
|
|
22293
|
+
* that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
|
|
22294
|
+
* small inter-segment cracks (durMs under-covers the span to the next
|
|
22295
|
+
* startMs by ~11-17 ms) instead of no-opping at a segment head.
|
|
22141
22296
|
*/
|
|
22142
22297
|
var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
|
|
22143
22298
|
kind: literal("segment"),
|
|
@@ -22146,7 +22301,8 @@ var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
|
|
|
22146
22301
|
bytes: number()
|
|
22147
22302
|
}), object({
|
|
22148
22303
|
kind: literal("gap"),
|
|
22149
|
-
nearestEdgeMs: number().nullable()
|
|
22304
|
+
nearestEdgeMs: number().nullable(),
|
|
22305
|
+
prevEndMs: number().nullable().optional()
|
|
22150
22306
|
})]);
|
|
22151
22307
|
/** Raw bytes of one finalized footage segment (read off disk on the recording node). */
|
|
22152
22308
|
var ReadSegmentBytesResultSchema = object({ data: _instanceof(Uint8Array) });
|
|
@@ -23715,6 +23871,12 @@ Object.freeze({
|
|
|
23715
23871
|
addonId: null,
|
|
23716
23872
|
access: "view"
|
|
23717
23873
|
},
|
|
23874
|
+
"deviceManager.getLinkedDevices": {
|
|
23875
|
+
capName: "device-manager",
|
|
23876
|
+
capScope: "system",
|
|
23877
|
+
addonId: null,
|
|
23878
|
+
access: "view"
|
|
23879
|
+
},
|
|
23718
23880
|
"deviceManager.getRoleDisplayDefaults": {
|
|
23719
23881
|
capName: "device-manager",
|
|
23720
23882
|
capScope: "system",
|
|
@@ -25269,6 +25431,12 @@ Object.freeze({
|
|
|
25269
25431
|
addonId: null,
|
|
25270
25432
|
access: "view"
|
|
25271
25433
|
},
|
|
25434
|
+
"pipelineAnalytics.getSensorEvents": {
|
|
25435
|
+
capName: "pipeline-analytics",
|
|
25436
|
+
capScope: "device",
|
|
25437
|
+
addonId: null,
|
|
25438
|
+
access: "view"
|
|
25439
|
+
},
|
|
25272
25440
|
"pipelineAnalytics.getTrack": {
|
|
25273
25441
|
capName: "pipeline-analytics",
|
|
25274
25442
|
capScope: "device",
|
|
@@ -25281,6 +25449,18 @@ Object.freeze({
|
|
|
25281
25449
|
addonId: null,
|
|
25282
25450
|
access: "view"
|
|
25283
25451
|
},
|
|
25452
|
+
"pipelineAnalytics.listEventKinds": {
|
|
25453
|
+
capName: "pipeline-analytics",
|
|
25454
|
+
capScope: "device",
|
|
25455
|
+
addonId: null,
|
|
25456
|
+
access: "view"
|
|
25457
|
+
},
|
|
25458
|
+
"pipelineAnalytics.listRecentTracks": {
|
|
25459
|
+
capName: "pipeline-analytics",
|
|
25460
|
+
capScope: "device",
|
|
25461
|
+
addonId: null,
|
|
25462
|
+
access: "view"
|
|
25463
|
+
},
|
|
25284
25464
|
"pipelineAnalytics.listTracks": {
|
|
25285
25465
|
capName: "pipeline-analytics",
|
|
25286
25466
|
capScope: "device",
|
package/dist/addon.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createServer } from "http";
|
|
2
2
|
import { EventEmitter } from "events";
|
|
3
3
|
import { createSocket } from "dgram";
|
|
4
|
-
//#region ../types/dist/event-category-
|
|
4
|
+
//#region ../types/dist/event-category-H4AVePnn.mjs
|
|
5
5
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
6
6
|
EventCategory["SystemBoot"] = "system.boot";
|
|
7
7
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -151,6 +151,9 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
151
151
|
EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
|
|
152
152
|
EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
|
|
153
153
|
EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
|
|
154
|
+
/** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
|
|
155
|
+
* thumb is a scrub gap the recorder's keyframe backfill covers. */
|
|
156
|
+
EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
|
|
154
157
|
EventCategory["DetectionEvent"] = "detection.event";
|
|
155
158
|
EventCategory["SessionTrackNew"] = "session.track.new";
|
|
156
159
|
EventCategory["SessionTrackExpired"] = "session.track.expired";
|
|
@@ -10798,10 +10801,23 @@ var deviceDiscoveryCapability = {
|
|
|
10798
10801
|
}
|
|
10799
10802
|
};
|
|
10800
10803
|
/**
|
|
10801
|
-
* Doorbell button cap.
|
|
10802
|
-
*
|
|
10803
|
-
*
|
|
10804
|
-
*
|
|
10804
|
+
* Doorbell button cap. Two kinds of providers coexist behind this cap
|
|
10805
|
+
* name (same pattern as `snapshot`):
|
|
10806
|
+
*
|
|
10807
|
+
* - **Native** providers: registered per-device by device-driver
|
|
10808
|
+
* addons via `ctx.registerNativeCap` — either on a
|
|
10809
|
+
* `DeviceType.Button` accessory with `role: DeviceRole.Doorbell`,
|
|
10810
|
+
* or directly on the camera (Reolink registers at camera level).
|
|
10811
|
+
* Emits an `onPressed` event every time the firmware pushes a
|
|
10812
|
+
* ring; status tracks the last press and a pressCount since start
|
|
10813
|
+
* (diagnostic).
|
|
10814
|
+
*
|
|
10815
|
+
* - **Wrapper** provider: the `virtual-doorbell` system builtin
|
|
10816
|
+
* (`@camstack/system/builtins/doorbell`). Turns ANY binary-ish
|
|
10817
|
+
* device (contact / switch / event-emitter …) into a doorbell for
|
|
10818
|
+
* a camera. `defaultActive: false` — the operator explicitly binds
|
|
10819
|
+
* it per camera in the device-bindings UI, then picks the source
|
|
10820
|
+
* device + trigger in the per-device settings.
|
|
10805
10821
|
*
|
|
10806
10822
|
* The DeviceEventPropagator re-emits `onPressed` on the camera parent
|
|
10807
10823
|
* — subscribers listening at the camera level receive ring events
|
|
@@ -10822,7 +10838,10 @@ var doorbellCapability = {
|
|
|
10822
10838
|
scope: "device",
|
|
10823
10839
|
deviceNative: true,
|
|
10824
10840
|
mode: "singleton",
|
|
10825
|
-
|
|
10841
|
+
kind: "wrapper",
|
|
10842
|
+
defaultActive: false,
|
|
10843
|
+
deviceTypes: [DeviceType.Button, DeviceType.Camera],
|
|
10844
|
+
exposesDeviceSettings: true,
|
|
10826
10845
|
methods: {},
|
|
10827
10846
|
events: {
|
|
10828
10847
|
/**
|
|
@@ -17174,6 +17193,14 @@ var ConfigEntrySchema = object({
|
|
|
17174
17193
|
value: unknown(),
|
|
17175
17194
|
description: string().optional()
|
|
17176
17195
|
});
|
|
17196
|
+
var DeviceLinkModeSchema = _enum(["auto", "manual"]);
|
|
17197
|
+
/** One resolved linked device — the compact projection consumers need. */
|
|
17198
|
+
var LinkedDeviceSchema = object({
|
|
17199
|
+
deviceId: number(),
|
|
17200
|
+
name: string(),
|
|
17201
|
+
location: string().nullable(),
|
|
17202
|
+
features: array(string())
|
|
17203
|
+
});
|
|
17177
17204
|
var SavedDeviceRowSchema = object({
|
|
17178
17205
|
/** Numeric id reserved at allocateDeviceId time. */
|
|
17179
17206
|
id: number(),
|
|
@@ -17395,7 +17422,10 @@ method(object({
|
|
|
17395
17422
|
}), _void(), {
|
|
17396
17423
|
kind: "mutation",
|
|
17397
17424
|
auth: "admin"
|
|
17398
|
-
}), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }),
|
|
17425
|
+
}), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
|
|
17426
|
+
mode: DeviceLinkModeSchema,
|
|
17427
|
+
devices: array(LinkedDeviceSchema)
|
|
17428
|
+
})), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
|
|
17399
17429
|
deviceId: number(),
|
|
17400
17430
|
values: record(string(), unknown())
|
|
17401
17431
|
}), object({ success: literal(true) }), {
|
|
@@ -18664,6 +18694,61 @@ var EventKindSchema = _enum([
|
|
|
18664
18694
|
"object",
|
|
18665
18695
|
"audio"
|
|
18666
18696
|
]);
|
|
18697
|
+
/**
|
|
18698
|
+
* Spatial filter for `listTracks` — the rect + polygon variants of the shared
|
|
18699
|
+
* MaskShape vocabulary (see `mask-shape.ts`). Coordinates are NORMALIZED 0..1
|
|
18700
|
+
* of the camera frame (top-left origin), matching the drawing-plane editor.
|
|
18701
|
+
*/
|
|
18702
|
+
var TrackZoneFilterSchema = discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
|
|
18703
|
+
/** Closed icon vocabulary so clients render a known glyph per kind. */
|
|
18704
|
+
var EventKindIconSchema = _enum([
|
|
18705
|
+
"motion",
|
|
18706
|
+
"audio",
|
|
18707
|
+
"person",
|
|
18708
|
+
"vehicle",
|
|
18709
|
+
"animal",
|
|
18710
|
+
"door",
|
|
18711
|
+
"pir",
|
|
18712
|
+
"smoke",
|
|
18713
|
+
"water",
|
|
18714
|
+
"button",
|
|
18715
|
+
"generic"
|
|
18716
|
+
]);
|
|
18717
|
+
var EventKindCategorySchema = _enum([
|
|
18718
|
+
"motion",
|
|
18719
|
+
"audio",
|
|
18720
|
+
"detection",
|
|
18721
|
+
"sensor",
|
|
18722
|
+
"custom"
|
|
18723
|
+
]);
|
|
18724
|
+
var EventKindDescriptorSchema = object({
|
|
18725
|
+
/** Stable kind id (e.g. 'motion', 'person', 'contact'). */
|
|
18726
|
+
kind: string(),
|
|
18727
|
+
label: string(),
|
|
18728
|
+
/** Hex color for timeline/legend rendering. */
|
|
18729
|
+
color: string(),
|
|
18730
|
+
icon: EventKindIconSchema,
|
|
18731
|
+
category: EventKindCategorySchema,
|
|
18732
|
+
/** Which cap + device contributes this kind. For built-ins the camera
|
|
18733
|
+
* itself; for sensor kinds the LINKED source device. */
|
|
18734
|
+
source: object({
|
|
18735
|
+
capName: string(),
|
|
18736
|
+
deviceId: number()
|
|
18737
|
+
})
|
|
18738
|
+
});
|
|
18739
|
+
var SensorEventSchema = object({
|
|
18740
|
+
id: string(),
|
|
18741
|
+
/** The CAMERA the event is attributed to (a sensor linked to N cameras
|
|
18742
|
+
* yields N rows, one per camera). */
|
|
18743
|
+
deviceId: number(),
|
|
18744
|
+
/** The linked sensor device whose state changed. */
|
|
18745
|
+
sourceDeviceId: number(),
|
|
18746
|
+
/** Event kind id — matches an `EventKindDescriptor.kind`. */
|
|
18747
|
+
kind: string(),
|
|
18748
|
+
/** Snapshot of the sensor cap's runtime-state slice at the change. */
|
|
18749
|
+
value: record(string(), unknown()).nullable(),
|
|
18750
|
+
timestamp: number()
|
|
18751
|
+
});
|
|
18667
18752
|
var TrackPositionSchema = object({
|
|
18668
18753
|
x: number(),
|
|
18669
18754
|
y: number(),
|
|
@@ -18677,6 +18762,30 @@ var TrackSnapshotSchema = object({
|
|
|
18677
18762
|
mediaKey: string()
|
|
18678
18763
|
});
|
|
18679
18764
|
/**
|
|
18765
|
+
* Normalized 0..1 trajectory envelope (min/max over every position bbox,
|
|
18766
|
+
* divided by the track's detection-frame dims), computed at persist time.
|
|
18767
|
+
* Absent when the frame dims were unknown when the track was persisted
|
|
18768
|
+
* (legacy rows / dims-less sources) and on active (in-RAM) tracks.
|
|
18769
|
+
*/
|
|
18770
|
+
var TrackEnvelopeSchema = object({
|
|
18771
|
+
minX: number(),
|
|
18772
|
+
minY: number(),
|
|
18773
|
+
maxX: number(),
|
|
18774
|
+
maxY: number()
|
|
18775
|
+
});
|
|
18776
|
+
/**
|
|
18777
|
+
* Row projection for track list queries. `full` (default) returns the
|
|
18778
|
+
* complete Track including the frame-rate `positions[]` history and the
|
|
18779
|
+
* `snapshots[]` references — megabytes across a page of tracks. `slim`
|
|
18780
|
+
* keeps every scalar the list surfaces actually render (ids, class(es),
|
|
18781
|
+
* label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
|
|
18782
|
+
* zonesVisited, bestEventId, envelope) and returns `positions` /
|
|
18783
|
+
* `snapshots` as EMPTY arrays — detail views re-fetch the full row via
|
|
18784
|
+
* `getTrack`. Mirrors the event-store `projection` convention
|
|
18785
|
+
* (`getObjectEvents` et al.).
|
|
18786
|
+
*/
|
|
18787
|
+
var TrackProjectionSchema = _enum(["full", "slim"]);
|
|
18788
|
+
/**
|
|
18680
18789
|
* One audio-classification label heard on the track's camera while the
|
|
18681
18790
|
* track was alive, aggregated per label. An "episode" is one persisted
|
|
18682
18791
|
* audio event (the confident-classification path: score ≥ the device's
|
|
@@ -18727,7 +18836,11 @@ var TrackSchema = object({
|
|
|
18727
18836
|
/** Audio-classification labels heard on the camera during the track's
|
|
18728
18837
|
* life (score ≥ device `classificationMinScore`), aggregated per label.
|
|
18729
18838
|
* Absent on legacy rows / tracks with no confident audio. */
|
|
18730
|
-
audioLabels: array(TrackAudioLabelSchema).readonly().optional()
|
|
18839
|
+
audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
|
|
18840
|
+
/** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
|
|
18841
|
+
* Populated from the persisted envelope columns on historical reads;
|
|
18842
|
+
* absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
|
|
18843
|
+
envelope: TrackEnvelopeSchema.optional()
|
|
18731
18844
|
});
|
|
18732
18845
|
var BaseEventFields = {
|
|
18733
18846
|
id: string(),
|
|
@@ -18837,11 +18950,13 @@ var MediaFileSchema = object({
|
|
|
18837
18950
|
sizeBytes: number(),
|
|
18838
18951
|
timestamp: number()
|
|
18839
18952
|
});
|
|
18953
|
+
var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
|
|
18954
|
+
var MAX_EVENT_QUERY_LIMIT = 5e3;
|
|
18840
18955
|
var DeviceEventQueryInput = object({
|
|
18841
18956
|
deviceId: number(),
|
|
18842
18957
|
since: number().optional(),
|
|
18843
18958
|
until: number().optional(),
|
|
18844
|
-
limit: number().int().min(1).max(
|
|
18959
|
+
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
|
|
18845
18960
|
/** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
|
|
18846
18961
|
* optional `mediaUrl` (populated by B5). `full` (default) keeps today's
|
|
18847
18962
|
* exact behaviour. Callers may omit this field — the store defaults to
|
|
@@ -18849,6 +18964,27 @@ var DeviceEventQueryInput = object({
|
|
|
18849
18964
|
projection: _enum(["full", "slim"]).optional()
|
|
18850
18965
|
});
|
|
18851
18966
|
var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
|
|
18967
|
+
var RecentTracksQueryInput = object({
|
|
18968
|
+
/** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
|
|
18969
|
+
deviceIds: array(number()),
|
|
18970
|
+
/** Window lower bound on `lastSeen` (inclusive). */
|
|
18971
|
+
since: number().optional(),
|
|
18972
|
+
/** Window upper bound on `lastSeen` (inclusive). */
|
|
18973
|
+
until: number().optional(),
|
|
18974
|
+
/** Page size. Default 200, max 1000. */
|
|
18975
|
+
limit: number().int().min(1).max(1e3).default(200),
|
|
18976
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`.
|
|
18977
|
+
* Encodes the (lastSeen, trackId) sort position — treat as opaque. */
|
|
18978
|
+
cursor: string().optional(),
|
|
18979
|
+
/** See {@link TrackProjectionSchema}. Default `full`. */
|
|
18980
|
+
projection: TrackProjectionSchema.optional()
|
|
18981
|
+
});
|
|
18982
|
+
var RecentTracksPageSchema = object({
|
|
18983
|
+
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
18984
|
+
tracks: array(TrackSchema).readonly(),
|
|
18985
|
+
/** Cursor for the next page, or null when this page is the last. */
|
|
18986
|
+
nextCursor: string().nullable()
|
|
18987
|
+
});
|
|
18852
18988
|
var KeyEventQueryInput = object({
|
|
18853
18989
|
deviceId: number(),
|
|
18854
18990
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
@@ -18931,11 +19067,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
18931
19067
|
deviceId: number(),
|
|
18932
19068
|
since: number().optional(),
|
|
18933
19069
|
until: number().optional(),
|
|
18934
|
-
limit: number().optional()
|
|
18935
|
-
|
|
19070
|
+
limit: number().optional(),
|
|
19071
|
+
/** Spatial filter — only tracks whose trajectory intersects the zone
|
|
19072
|
+
* (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
|
|
19073
|
+
* envelope columns, then precisely tested per position. Tracks with
|
|
19074
|
+
* an unknown envelope (no frame dims at persist time) always match. */
|
|
19075
|
+
zone: TrackZoneFilterSchema.optional(),
|
|
19076
|
+
/** See {@link TrackProjectionSchema}. Default `full` (backward
|
|
19077
|
+
* compatible — omitting the field keeps today's exact behaviour). */
|
|
19078
|
+
projection: TrackProjectionSchema.optional()
|
|
19079
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
|
|
18936
19080
|
kind: "mutation",
|
|
18937
19081
|
auth: "admin"
|
|
18938
|
-
}), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(
|
|
19082
|
+
}), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
|
|
19083
|
+
deviceId: number(),
|
|
19084
|
+
since: number().optional(),
|
|
19085
|
+
until: number().optional(),
|
|
19086
|
+
kinds: array(string()).optional(),
|
|
19087
|
+
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19088
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
18939
19089
|
deviceId: number(),
|
|
18940
19090
|
since: number(),
|
|
18941
19091
|
until: number(),
|
|
@@ -22136,7 +22286,12 @@ var RecordingStorageUsageSchema = object({
|
|
|
22136
22286
|
/**
|
|
22137
22287
|
* Result of locating footage at a wall-clock instant for one device/profile.
|
|
22138
22288
|
* `segment` carries the covering segment's window; `gap` reports the forward
|
|
22139
|
-
* nearest covered edge (`null` past the end of footage / when none exists)
|
|
22289
|
+
* nearest covered edge (`null` past the end of footage / when none exists)
|
|
22290
|
+
* and the backward covered edge `prevEndMs` (exclusive end of the nearest
|
|
22291
|
+
* footage behind the epoch; `null` when none — optional so older providers
|
|
22292
|
+
* that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
|
|
22293
|
+
* small inter-segment cracks (durMs under-covers the span to the next
|
|
22294
|
+
* startMs by ~11-17 ms) instead of no-opping at a segment head.
|
|
22140
22295
|
*/
|
|
22141
22296
|
var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
|
|
22142
22297
|
kind: literal("segment"),
|
|
@@ -22145,7 +22300,8 @@ var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
|
|
|
22145
22300
|
bytes: number()
|
|
22146
22301
|
}), object({
|
|
22147
22302
|
kind: literal("gap"),
|
|
22148
|
-
nearestEdgeMs: number().nullable()
|
|
22303
|
+
nearestEdgeMs: number().nullable(),
|
|
22304
|
+
prevEndMs: number().nullable().optional()
|
|
22149
22305
|
})]);
|
|
22150
22306
|
/** Raw bytes of one finalized footage segment (read off disk on the recording node). */
|
|
22151
22307
|
var ReadSegmentBytesResultSchema = object({ data: _instanceof(Uint8Array) });
|
|
@@ -23714,6 +23870,12 @@ Object.freeze({
|
|
|
23714
23870
|
addonId: null,
|
|
23715
23871
|
access: "view"
|
|
23716
23872
|
},
|
|
23873
|
+
"deviceManager.getLinkedDevices": {
|
|
23874
|
+
capName: "device-manager",
|
|
23875
|
+
capScope: "system",
|
|
23876
|
+
addonId: null,
|
|
23877
|
+
access: "view"
|
|
23878
|
+
},
|
|
23717
23879
|
"deviceManager.getRoleDisplayDefaults": {
|
|
23718
23880
|
capName: "device-manager",
|
|
23719
23881
|
capScope: "system",
|
|
@@ -25268,6 +25430,12 @@ Object.freeze({
|
|
|
25268
25430
|
addonId: null,
|
|
25269
25431
|
access: "view"
|
|
25270
25432
|
},
|
|
25433
|
+
"pipelineAnalytics.getSensorEvents": {
|
|
25434
|
+
capName: "pipeline-analytics",
|
|
25435
|
+
capScope: "device",
|
|
25436
|
+
addonId: null,
|
|
25437
|
+
access: "view"
|
|
25438
|
+
},
|
|
25271
25439
|
"pipelineAnalytics.getTrack": {
|
|
25272
25440
|
capName: "pipeline-analytics",
|
|
25273
25441
|
capScope: "device",
|
|
@@ -25280,6 +25448,18 @@ Object.freeze({
|
|
|
25280
25448
|
addonId: null,
|
|
25281
25449
|
access: "view"
|
|
25282
25450
|
},
|
|
25451
|
+
"pipelineAnalytics.listEventKinds": {
|
|
25452
|
+
capName: "pipeline-analytics",
|
|
25453
|
+
capScope: "device",
|
|
25454
|
+
addonId: null,
|
|
25455
|
+
access: "view"
|
|
25456
|
+
},
|
|
25457
|
+
"pipelineAnalytics.listRecentTracks": {
|
|
25458
|
+
capName: "pipeline-analytics",
|
|
25459
|
+
capScope: "device",
|
|
25460
|
+
addonId: null,
|
|
25461
|
+
access: "view"
|
|
25462
|
+
},
|
|
25283
25463
|
"pipelineAnalytics.listTracks": {
|
|
25284
25464
|
capName: "pipeline-analytics",
|
|
25285
25465
|
capScope: "device",
|
package/package.json
CHANGED