@camstack/addon-provider-gree 0.1.25 → 0.1.26

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 CHANGED
@@ -7660,6 +7660,160 @@ var EncodeProfileSchema = object({
7660
7660
  */
7661
7661
  outputArgs: array(string()).optional()
7662
7662
  });
7663
+ var COCO_TO_MACRO = {
7664
+ mapping: {
7665
+ person: "person",
7666
+ bicycle: "vehicle",
7667
+ car: "vehicle",
7668
+ motorcycle: "vehicle",
7669
+ airplane: "vehicle",
7670
+ bus: "vehicle",
7671
+ train: "vehicle",
7672
+ truck: "vehicle",
7673
+ boat: "vehicle",
7674
+ bird: "animal",
7675
+ cat: "animal",
7676
+ dog: "animal",
7677
+ horse: "animal",
7678
+ sheep: "animal",
7679
+ cow: "animal",
7680
+ elephant: "animal",
7681
+ bear: "animal",
7682
+ zebra: "animal",
7683
+ giraffe: "animal",
7684
+ suitcase: "package",
7685
+ backpack: "package",
7686
+ handbag: "package"
7687
+ },
7688
+ preserveOriginal: false
7689
+ };
7690
+ var AUDIO_MACRO_LABELS = [
7691
+ {
7692
+ id: "speech",
7693
+ name: "Speech",
7694
+ icon: "🗣️"
7695
+ },
7696
+ {
7697
+ id: "scream",
7698
+ name: "Scream / Shout",
7699
+ icon: "😱"
7700
+ },
7701
+ {
7702
+ id: "crying",
7703
+ name: "Crying / Baby",
7704
+ icon: "😢"
7705
+ },
7706
+ {
7707
+ id: "laughter",
7708
+ name: "Laughter",
7709
+ icon: "😂"
7710
+ },
7711
+ {
7712
+ id: "music",
7713
+ name: "Music",
7714
+ icon: "🎵"
7715
+ },
7716
+ {
7717
+ id: "dog",
7718
+ name: "Dog",
7719
+ icon: "🐕"
7720
+ },
7721
+ {
7722
+ id: "cat",
7723
+ name: "Cat",
7724
+ icon: "🐈"
7725
+ },
7726
+ {
7727
+ id: "bird",
7728
+ name: "Bird",
7729
+ icon: "🐦"
7730
+ },
7731
+ {
7732
+ id: "animal",
7733
+ name: "Animal (other)",
7734
+ icon: "🐾"
7735
+ },
7736
+ {
7737
+ id: "alarm",
7738
+ name: "Alarm / Siren",
7739
+ icon: "🚨"
7740
+ },
7741
+ {
7742
+ id: "doorbell",
7743
+ name: "Doorbell / Knock",
7744
+ icon: "🔔"
7745
+ },
7746
+ {
7747
+ id: "glass_breaking",
7748
+ name: "Glass Breaking",
7749
+ icon: "💥"
7750
+ },
7751
+ {
7752
+ id: "gunshot",
7753
+ name: "Gunshot / Explosion",
7754
+ icon: "💣"
7755
+ },
7756
+ {
7757
+ id: "vehicle",
7758
+ name: "Vehicle",
7759
+ icon: "🚗"
7760
+ },
7761
+ {
7762
+ id: "siren",
7763
+ name: "Emergency Siren",
7764
+ icon: "🚑"
7765
+ },
7766
+ {
7767
+ id: "fire",
7768
+ name: "Fire / Smoke",
7769
+ icon: "🔥"
7770
+ },
7771
+ {
7772
+ id: "water",
7773
+ name: "Water",
7774
+ icon: "💧"
7775
+ },
7776
+ {
7777
+ id: "wind",
7778
+ name: "Wind / Weather",
7779
+ icon: "🌬️"
7780
+ },
7781
+ {
7782
+ id: "door",
7783
+ name: "Door",
7784
+ icon: "🚪"
7785
+ },
7786
+ {
7787
+ id: "footsteps",
7788
+ name: "Footsteps",
7789
+ icon: "👣"
7790
+ },
7791
+ {
7792
+ id: "crowd",
7793
+ name: "Crowd / Chatter",
7794
+ icon: "👥"
7795
+ },
7796
+ {
7797
+ id: "telephone",
7798
+ name: "Telephone",
7799
+ icon: "📞"
7800
+ },
7801
+ {
7802
+ id: "engine",
7803
+ name: "Engine / Motor",
7804
+ icon: "⚙️"
7805
+ },
7806
+ {
7807
+ id: "tools",
7808
+ name: "Tools / Construction",
7809
+ icon: "🔨"
7810
+ },
7811
+ {
7812
+ id: "silence",
7813
+ name: "Silence",
7814
+ icon: "🤫"
7815
+ }
7816
+ ];
7663
7817
  var YAMNET_TO_MACRO = {
7664
7818
  mapping: {
7665
7819
  Speech: "speech",
@@ -7926,6 +8080,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
7926
8080
  for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
7927
8081
  for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
7928
8082
  /**
8083
+ * Unified event-kind taxonomy — THE single source of truth for
8084
+ * `kind → { parentKind, category, level, color, iconId, labelKey, label,
8085
+ * icon }`.
8086
+ *
8087
+ * This dictionary folds together what used to be scattered across four
8088
+ * copies:
8089
+ * - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
8090
+ * - `addon-post-analysis/.../services/event-kinds.ts`
8091
+ * (MOTION/PERSON/VEHICLE… _COLOR constants)
8092
+ * - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
8093
+ * - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
8094
+ * - the COCO / audio class maps (macro ↔ sub relationships)
8095
+ *
8096
+ * The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
8097
+ * `@camstack/types`. The UI-side mapping `iconId → lucide component` and
8098
+ * `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
8099
+ * color or an icon: they read this dictionary (server descriptors carry the
8100
+ * fields inline; the client resolves color/icon/label from `iconId`/`kind`).
8101
+ *
8102
+ * Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
8103
+ */
8104
+ var TAXONOMY_COLORS = {
8105
+ motion: "#f59e0b",
8106
+ audio: "#06b6d4",
8107
+ person: "#22c55e",
8108
+ vehicle: "#3b82f6",
8109
+ animal: "#f97316",
8110
+ package: "#a855f7",
8111
+ sensor: "#8b5cf6",
8112
+ control: "#10b981",
8113
+ genericDetection: "#64748b"
8114
+ };
8115
+ var DETECTION_SUB_COLORS = {
8116
+ car: "#f59e0b",
8117
+ truck: "#d97706",
8118
+ bus: "#b45309",
8119
+ motorcycle: "#eab308",
8120
+ bicycle: "#ca8a04",
8121
+ airplane: "#60a5fa",
8122
+ boat: "#2563eb",
8123
+ train: "#1d4ed8",
8124
+ bird: "#14b8a6",
8125
+ dog: "#84cc16",
8126
+ cat: "#f97316",
8127
+ horse: "#a16207",
8128
+ sheep: "#a3a3a3",
8129
+ cow: "#78716c",
8130
+ elephant: "#6b7280",
8131
+ bear: "#7c2d12",
8132
+ zebra: "#404040",
8133
+ giraffe: "#d4a373"
8134
+ };
8135
+ function titleCase$1(id) {
8136
+ return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
8137
+ }
8138
+ var entries = /* @__PURE__ */ new Map();
8139
+ function macro(kind, category, color, iconId, label) {
8140
+ entries.set(kind, {
8141
+ kind,
8142
+ parentKind: null,
8143
+ level: "macro",
8144
+ category,
8145
+ color,
8146
+ iconId,
8147
+ labelKey: `eventKind.${kind}`,
8148
+ label
8149
+ });
8150
+ }
8151
+ function sub(kind, parentKind, category, color, iconId, label) {
8152
+ entries.set(kind, {
8153
+ kind,
8154
+ parentKind,
8155
+ level: "sub",
8156
+ category,
8157
+ color,
8158
+ iconId,
8159
+ labelKey: `eventKind.${kind}`,
8160
+ label
8161
+ });
8162
+ }
8163
+ macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
8164
+ macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
8165
+ macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
8166
+ macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
8167
+ macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
8168
+ macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
8169
+ macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
8170
+ macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
8171
+ for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
8172
+ if (macroClass !== "vehicle" && macroClass !== "animal") continue;
8173
+ if (entries.has(cocoClass)) continue;
8174
+ sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase$1(cocoClass));
8175
+ }
8176
+ sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
8177
+ sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
8178
+ sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
8179
+ sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
8180
+ sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
8181
+ sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
8182
+ sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
8183
+ sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
8184
+ sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
8185
+ sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
8186
+ sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
8187
+ sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
8188
+ sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
8189
+ sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
8190
+ sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
8191
+ sub("siren", "control", "control", "#dc2626", "siren", "Siren");
8192
+ sub("button", "control", "control", "#10b981", "button", "Button");
8193
+ sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
8194
+ for (const l of AUDIO_MACRO_LABELS) {
8195
+ const kind = `audio-${l.id}`;
8196
+ if (entries.has(kind)) continue;
8197
+ sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
8198
+ }
8199
+ /** The complete taxonomy dictionary, keyed by kind. */
8200
+ var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
8201
+ /**
7929
8202
  * Error types for the safe expression engine. Two distinct classes so callers
7930
8203
  * can tell a compile-time (grammar) failure from a runtime (evaluation)
7931
8204
  * failure — both are non-fatal to the host: read paths degrade to "skip link".
@@ -18858,17 +19131,30 @@ var EventKindCategorySchema = _enum([
18858
19131
  "audio",
18859
19132
  "detection",
18860
19133
  "sensor",
19134
+ "control",
18861
19135
  "custom",
18862
19136
  "package"
18863
19137
  ]);
19138
+ /** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
19139
+ var EventKindLevelSchema = _enum(["macro", "sub"]);
18864
19140
  var EventKindDescriptorSchema = object({
18865
- /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
19141
+ /** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
18866
19142
  kind: string(),
19143
+ /** i18n key resolved on the UI side; `label` is the English fallback. */
19144
+ labelKey: string(),
19145
+ /** English fallback label (kept for clients that don't translate). */
18867
19146
  label: string(),
18868
19147
  /** Hex color for timeline/legend rendering. */
18869
19148
  color: string(),
19149
+ /** Dictionary id → lucide component on the UI side. */
19150
+ iconId: string(),
19151
+ /** Legacy closed-vocab glyph — fallback for `iconId`. */
18870
19152
  icon: EventKindIconSchema,
18871
19153
  category: EventKindCategorySchema,
19154
+ /** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
19155
+ parentKind: string().nullable(),
19156
+ /** Derived from `parentKind`, explicit for the client tree. */
19157
+ level: EventKindLevelSchema,
18872
19158
  /** Which cap + device contributes this kind. For built-ins the camera
18873
19159
  * itself; for sensor kinds the LINKED source device. */
18874
19160
  source: object({
@@ -18941,11 +19227,21 @@ var TrackAudioLabelSchema = object({
18941
19227
  firstAt: number(),
18942
19228
  lastAt: number()
18943
19229
  });
19230
+ /**
19231
+ * How a track was produced. `pipeline` (default / absent) = the spatial
19232
+ * detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
19233
+ * linked sensor/control state change (no positions; carries a snapshot). The
19234
+ * spatial subsystems (tracker association, occupancy count, re-id/embedding,
19235
+ * resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
19236
+ */
19237
+ var TrackSourceSchema = _enum(["pipeline", "sensor"]);
18944
19238
  var TrackSchema = object({
18945
19239
  trackId: string(),
18946
19240
  deviceId: number(),
18947
19241
  className: string(),
18948
19242
  label: string().optional(),
19243
+ /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
19244
+ source: TrackSourceSchema.optional(),
18949
19245
  firstSeen: number(),
18950
19246
  lastSeen: number(),
18951
19247
  /** Frame-rate position history (subject to maxPositionHistory cap). */
@@ -19322,6 +19618,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19322
19618
  eventId: string(),
19323
19619
  timestamp: number()
19324
19620
  });
19621
+ /**
19622
+ * Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
19623
+ * `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
19624
+ * caps into per-camera event-kind descriptors.
19625
+ *
19626
+ * The descriptor DATA (color / iconId / labelKey / parentKind / category)
19627
+ * is NOT duplicated here — every entry is derived from the single
19628
+ * `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
19629
+ * ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
19630
+ * control cap means adding one line here (and a taxonomy entry); the anti-
19631
+ * drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
19632
+ * eventful cap is missing.
19633
+ */
19634
+ /** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
19635
+ var LEGACY_ICON = {
19636
+ motion: "motion",
19637
+ audio: "audio",
19638
+ person: "person",
19639
+ vehicle: "vehicle",
19640
+ animal: "animal",
19641
+ package: "package",
19642
+ door: "door",
19643
+ pir: "pir",
19644
+ smoke: "smoke",
19645
+ water: "water",
19646
+ button: "button",
19647
+ generic: "generic",
19648
+ gas: "smoke",
19649
+ vibration: "generic",
19650
+ tamper: "generic",
19651
+ presence: "person",
19652
+ lock: "generic",
19653
+ siren: "generic",
19654
+ switch: "generic",
19655
+ doorbell: "button"
19656
+ };
19657
+ function legacyIcon(iconId) {
19658
+ return LEGACY_ICON[iconId] ?? "generic";
19659
+ }
19660
+ /**
19661
+ * Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
19662
+ * The anti-drift guard cross-checks this against the eventful caps declared
19663
+ * in `packages/types/src/capabilities/*.cap.ts`.
19664
+ */
19665
+ var CAP_TO_KIND = {
19666
+ contact: "contact",
19667
+ motion: "motion-sensor",
19668
+ smoke: "smoke",
19669
+ flood: "flood",
19670
+ gas: "gas",
19671
+ "carbon-monoxide": "carbon-monoxide",
19672
+ vibration: "vibration",
19673
+ tamper: "tamper",
19674
+ presence: "presence",
19675
+ "enum-sensor": "enum-sensor",
19676
+ "event-emitter": "device-event",
19677
+ "lock-control": "lock",
19678
+ switch: "switch",
19679
+ button: "button",
19680
+ doorbell: "doorbell"
19681
+ };
19682
+ function buildDescriptor(capName, kind) {
19683
+ const t = EVENT_TAXONOMY[kind];
19684
+ if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
19685
+ return {
19686
+ ...t,
19687
+ icon: legacyIcon(t.iconId)
19688
+ };
19689
+ }
19690
+ Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
19325
19691
  var CameraPipelineConfigSchema = object({
19326
19692
  engine: PipelineEngineChoiceSchema.optional(),
19327
19693
  steps: array(PipelineStepInputSchema).readonly(),
package/dist/addon.mjs CHANGED
@@ -7659,6 +7659,160 @@ var EncodeProfileSchema = object({
7659
7659
  */
7660
7660
  outputArgs: array(string()).optional()
7661
7661
  });
7662
+ var COCO_TO_MACRO = {
7663
+ mapping: {
7664
+ person: "person",
7665
+ bicycle: "vehicle",
7666
+ car: "vehicle",
7667
+ motorcycle: "vehicle",
7668
+ airplane: "vehicle",
7669
+ bus: "vehicle",
7670
+ train: "vehicle",
7671
+ truck: "vehicle",
7672
+ boat: "vehicle",
7673
+ bird: "animal",
7674
+ cat: "animal",
7675
+ dog: "animal",
7676
+ horse: "animal",
7677
+ sheep: "animal",
7678
+ cow: "animal",
7679
+ elephant: "animal",
7680
+ bear: "animal",
7681
+ zebra: "animal",
7682
+ giraffe: "animal",
7683
+ suitcase: "package",
7684
+ backpack: "package",
7685
+ handbag: "package"
7686
+ },
7687
+ preserveOriginal: false
7688
+ };
7689
+ var AUDIO_MACRO_LABELS = [
7690
+ {
7691
+ id: "speech",
7692
+ name: "Speech",
7693
+ icon: "🗣️"
7694
+ },
7695
+ {
7696
+ id: "scream",
7697
+ name: "Scream / Shout",
7698
+ icon: "😱"
7699
+ },
7700
+ {
7701
+ id: "crying",
7702
+ name: "Crying / Baby",
7703
+ icon: "😢"
7704
+ },
7705
+ {
7706
+ id: "laughter",
7707
+ name: "Laughter",
7708
+ icon: "😂"
7709
+ },
7710
+ {
7711
+ id: "music",
7712
+ name: "Music",
7713
+ icon: "🎵"
7714
+ },
7715
+ {
7716
+ id: "dog",
7717
+ name: "Dog",
7718
+ icon: "🐕"
7719
+ },
7720
+ {
7721
+ id: "cat",
7722
+ name: "Cat",
7723
+ icon: "🐈"
7724
+ },
7725
+ {
7726
+ id: "bird",
7727
+ name: "Bird",
7728
+ icon: "🐦"
7729
+ },
7730
+ {
7731
+ id: "animal",
7732
+ name: "Animal (other)",
7733
+ icon: "🐾"
7734
+ },
7735
+ {
7736
+ id: "alarm",
7737
+ name: "Alarm / Siren",
7738
+ icon: "🚨"
7739
+ },
7740
+ {
7741
+ id: "doorbell",
7742
+ name: "Doorbell / Knock",
7743
+ icon: "🔔"
7744
+ },
7745
+ {
7746
+ id: "glass_breaking",
7747
+ name: "Glass Breaking",
7748
+ icon: "💥"
7749
+ },
7750
+ {
7751
+ id: "gunshot",
7752
+ name: "Gunshot / Explosion",
7753
+ icon: "💣"
7754
+ },
7755
+ {
7756
+ id: "vehicle",
7757
+ name: "Vehicle",
7758
+ icon: "🚗"
7759
+ },
7760
+ {
7761
+ id: "siren",
7762
+ name: "Emergency Siren",
7763
+ icon: "🚑"
7764
+ },
7765
+ {
7766
+ id: "fire",
7767
+ name: "Fire / Smoke",
7768
+ icon: "🔥"
7769
+ },
7770
+ {
7771
+ id: "water",
7772
+ name: "Water",
7773
+ icon: "💧"
7774
+ },
7775
+ {
7776
+ id: "wind",
7777
+ name: "Wind / Weather",
7778
+ icon: "🌬️"
7779
+ },
7780
+ {
7781
+ id: "door",
7782
+ name: "Door",
7783
+ icon: "🚪"
7784
+ },
7785
+ {
7786
+ id: "footsteps",
7787
+ name: "Footsteps",
7788
+ icon: "👣"
7789
+ },
7790
+ {
7791
+ id: "crowd",
7792
+ name: "Crowd / Chatter",
7793
+ icon: "👥"
7794
+ },
7795
+ {
7796
+ id: "telephone",
7797
+ name: "Telephone",
7798
+ icon: "📞"
7799
+ },
7800
+ {
7801
+ id: "engine",
7802
+ name: "Engine / Motor",
7803
+ icon: "⚙️"
7804
+ },
7805
+ {
7806
+ id: "tools",
7807
+ name: "Tools / Construction",
7808
+ icon: "🔨"
7809
+ },
7810
+ {
7811
+ id: "silence",
7812
+ name: "Silence",
7813
+ icon: "🤫"
7814
+ }
7815
+ ];
7662
7816
  var YAMNET_TO_MACRO = {
7663
7817
  mapping: {
7664
7818
  Speech: "speech",
@@ -7925,6 +8079,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
7925
8079
  for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
7926
8080
  for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
7927
8081
  /**
8082
+ * Unified event-kind taxonomy — THE single source of truth for
8083
+ * `kind → { parentKind, category, level, color, iconId, labelKey, label,
8084
+ * icon }`.
8085
+ *
8086
+ * This dictionary folds together what used to be scattered across four
8087
+ * copies:
8088
+ * - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
8089
+ * - `addon-post-analysis/.../services/event-kinds.ts`
8090
+ * (MOTION/PERSON/VEHICLE… _COLOR constants)
8091
+ * - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
8092
+ * - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
8093
+ * - the COCO / audio class maps (macro ↔ sub relationships)
8094
+ *
8095
+ * The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
8096
+ * `@camstack/types`. The UI-side mapping `iconId → lucide component` and
8097
+ * `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
8098
+ * color or an icon: they read this dictionary (server descriptors carry the
8099
+ * fields inline; the client resolves color/icon/label from `iconId`/`kind`).
8100
+ *
8101
+ * Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
8102
+ */
8103
+ var TAXONOMY_COLORS = {
8104
+ motion: "#f59e0b",
8105
+ audio: "#06b6d4",
8106
+ person: "#22c55e",
8107
+ vehicle: "#3b82f6",
8108
+ animal: "#f97316",
8109
+ package: "#a855f7",
8110
+ sensor: "#8b5cf6",
8111
+ control: "#10b981",
8112
+ genericDetection: "#64748b"
8113
+ };
8114
+ var DETECTION_SUB_COLORS = {
8115
+ car: "#f59e0b",
8116
+ truck: "#d97706",
8117
+ bus: "#b45309",
8118
+ motorcycle: "#eab308",
8119
+ bicycle: "#ca8a04",
8120
+ airplane: "#60a5fa",
8121
+ boat: "#2563eb",
8122
+ train: "#1d4ed8",
8123
+ bird: "#14b8a6",
8124
+ dog: "#84cc16",
8125
+ cat: "#f97316",
8126
+ horse: "#a16207",
8127
+ sheep: "#a3a3a3",
8128
+ cow: "#78716c",
8129
+ elephant: "#6b7280",
8130
+ bear: "#7c2d12",
8131
+ zebra: "#404040",
8132
+ giraffe: "#d4a373"
8133
+ };
8134
+ function titleCase$1(id) {
8135
+ return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
8136
+ }
8137
+ var entries = /* @__PURE__ */ new Map();
8138
+ function macro(kind, category, color, iconId, label) {
8139
+ entries.set(kind, {
8140
+ kind,
8141
+ parentKind: null,
8142
+ level: "macro",
8143
+ category,
8144
+ color,
8145
+ iconId,
8146
+ labelKey: `eventKind.${kind}`,
8147
+ label
8148
+ });
8149
+ }
8150
+ function sub(kind, parentKind, category, color, iconId, label) {
8151
+ entries.set(kind, {
8152
+ kind,
8153
+ parentKind,
8154
+ level: "sub",
8155
+ category,
8156
+ color,
8157
+ iconId,
8158
+ labelKey: `eventKind.${kind}`,
8159
+ label
8160
+ });
8161
+ }
8162
+ macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
8163
+ macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
8164
+ macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
8165
+ macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
8166
+ macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
8167
+ macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
8168
+ macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
8169
+ macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
8170
+ for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
8171
+ if (macroClass !== "vehicle" && macroClass !== "animal") continue;
8172
+ if (entries.has(cocoClass)) continue;
8173
+ sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase$1(cocoClass));
8174
+ }
8175
+ sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
8176
+ sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
8177
+ sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
8178
+ sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
8179
+ sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
8180
+ sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
8181
+ sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
8182
+ sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
8183
+ sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
8184
+ sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
8185
+ sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
8186
+ sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
8187
+ sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
8188
+ sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
8189
+ sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
8190
+ sub("siren", "control", "control", "#dc2626", "siren", "Siren");
8191
+ sub("button", "control", "control", "#10b981", "button", "Button");
8192
+ sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
8193
+ for (const l of AUDIO_MACRO_LABELS) {
8194
+ const kind = `audio-${l.id}`;
8195
+ if (entries.has(kind)) continue;
8196
+ sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
8197
+ }
8198
+ /** The complete taxonomy dictionary, keyed by kind. */
8199
+ var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
8200
+ /**
7928
8201
  * Error types for the safe expression engine. Two distinct classes so callers
7929
8202
  * can tell a compile-time (grammar) failure from a runtime (evaluation)
7930
8203
  * failure — both are non-fatal to the host: read paths degrade to "skip link".
@@ -18857,17 +19130,30 @@ var EventKindCategorySchema = _enum([
18857
19130
  "audio",
18858
19131
  "detection",
18859
19132
  "sensor",
19133
+ "control",
18860
19134
  "custom",
18861
19135
  "package"
18862
19136
  ]);
19137
+ /** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
19138
+ var EventKindLevelSchema = _enum(["macro", "sub"]);
18863
19139
  var EventKindDescriptorSchema = object({
18864
- /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
19140
+ /** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
18865
19141
  kind: string(),
19142
+ /** i18n key resolved on the UI side; `label` is the English fallback. */
19143
+ labelKey: string(),
19144
+ /** English fallback label (kept for clients that don't translate). */
18866
19145
  label: string(),
18867
19146
  /** Hex color for timeline/legend rendering. */
18868
19147
  color: string(),
19148
+ /** Dictionary id → lucide component on the UI side. */
19149
+ iconId: string(),
19150
+ /** Legacy closed-vocab glyph — fallback for `iconId`. */
18869
19151
  icon: EventKindIconSchema,
18870
19152
  category: EventKindCategorySchema,
19153
+ /** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
19154
+ parentKind: string().nullable(),
19155
+ /** Derived from `parentKind`, explicit for the client tree. */
19156
+ level: EventKindLevelSchema,
18871
19157
  /** Which cap + device contributes this kind. For built-ins the camera
18872
19158
  * itself; for sensor kinds the LINKED source device. */
18873
19159
  source: object({
@@ -18940,11 +19226,21 @@ var TrackAudioLabelSchema = object({
18940
19226
  firstAt: number(),
18941
19227
  lastAt: number()
18942
19228
  });
19229
+ /**
19230
+ * How a track was produced. `pipeline` (default / absent) = the spatial
19231
+ * detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
19232
+ * linked sensor/control state change (no positions; carries a snapshot). The
19233
+ * spatial subsystems (tracker association, occupancy count, re-id/embedding,
19234
+ * resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
19235
+ */
19236
+ var TrackSourceSchema = _enum(["pipeline", "sensor"]);
18943
19237
  var TrackSchema = object({
18944
19238
  trackId: string(),
18945
19239
  deviceId: number(),
18946
19240
  className: string(),
18947
19241
  label: string().optional(),
19242
+ /** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
19243
+ source: TrackSourceSchema.optional(),
18948
19244
  firstSeen: number(),
18949
19245
  lastSeen: number(),
18950
19246
  /** Frame-rate position history (subject to maxPositionHistory cap). */
@@ -19321,6 +19617,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19321
19617
  eventId: string(),
19322
19618
  timestamp: number()
19323
19619
  });
19620
+ /**
19621
+ * Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
19622
+ * `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
19623
+ * caps into per-camera event-kind descriptors.
19624
+ *
19625
+ * The descriptor DATA (color / iconId / labelKey / parentKind / category)
19626
+ * is NOT duplicated here — every entry is derived from the single
19627
+ * `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
19628
+ * ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
19629
+ * control cap means adding one line here (and a taxonomy entry); the anti-
19630
+ * drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
19631
+ * eventful cap is missing.
19632
+ */
19633
+ /** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
19634
+ var LEGACY_ICON = {
19635
+ motion: "motion",
19636
+ audio: "audio",
19637
+ person: "person",
19638
+ vehicle: "vehicle",
19639
+ animal: "animal",
19640
+ package: "package",
19641
+ door: "door",
19642
+ pir: "pir",
19643
+ smoke: "smoke",
19644
+ water: "water",
19645
+ button: "button",
19646
+ generic: "generic",
19647
+ gas: "smoke",
19648
+ vibration: "generic",
19649
+ tamper: "generic",
19650
+ presence: "person",
19651
+ lock: "generic",
19652
+ siren: "generic",
19653
+ switch: "generic",
19654
+ doorbell: "button"
19655
+ };
19656
+ function legacyIcon(iconId) {
19657
+ return LEGACY_ICON[iconId] ?? "generic";
19658
+ }
19659
+ /**
19660
+ * Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
19661
+ * The anti-drift guard cross-checks this against the eventful caps declared
19662
+ * in `packages/types/src/capabilities/*.cap.ts`.
19663
+ */
19664
+ var CAP_TO_KIND = {
19665
+ contact: "contact",
19666
+ motion: "motion-sensor",
19667
+ smoke: "smoke",
19668
+ flood: "flood",
19669
+ gas: "gas",
19670
+ "carbon-monoxide": "carbon-monoxide",
19671
+ vibration: "vibration",
19672
+ tamper: "tamper",
19673
+ presence: "presence",
19674
+ "enum-sensor": "enum-sensor",
19675
+ "event-emitter": "device-event",
19676
+ "lock-control": "lock",
19677
+ switch: "switch",
19678
+ button: "button",
19679
+ doorbell: "doorbell"
19680
+ };
19681
+ function buildDescriptor(capName, kind) {
19682
+ const t = EVENT_TAXONOMY[kind];
19683
+ if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
19684
+ return {
19685
+ ...t,
19686
+ icon: legacyIcon(t.iconId)
19687
+ };
19688
+ }
19689
+ Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
19324
19690
  var CameraPipelineConfigSchema = object({
19325
19691
  engine: PipelineEngineChoiceSchema.optional(),
19326
19692
  steps: array(PipelineStepInputSchema).readonly(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-gree",
3
- "version": "0.1.25",
3
+ "version": "0.1.26",
4
4
  "description": "Gree air-conditioner device-provider addon for CamStack — wraps the @apocaliss92/nodegree local-UDP client (LAN discovery + AES control), exposing climate-control and fan-control",
5
5
  "keywords": [
6
6
  "camstack",