@camstack/addon-provider-homeassistant 1.2.7 → 1.2.8

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
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let node_crypto = require("node:crypto");
3
3
  let node_zlib = require("node:zlib");
4
- //#region ../types/dist/event-category-BLcNejAE.mjs
4
+ //#region ../types/dist/event-category-Bz24uP1U.mjs
5
5
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
6
6
  EventCategory["SystemBoot"] = "system.boot";
7
7
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -272,6 +272,19 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
272
272
  */
273
273
  EventCategory["DeviceStateChanged"] = "device.state-changed";
274
274
  /**
275
+ * Frame occupancy for a camera CHANGED — a tracked object was gained or
276
+ * lost. Carries `{ deviceId, totalObjects, byClass, zones }`.
277
+ *
278
+ * Emitted only on a change, so a steady scene is silent. It exists so a
279
+ * client can stop polling `zoneAnalytics.getCurrentSnapshot`: that was the
280
+ * one live badge with no push signal at all, and it cost a request every
281
+ * four seconds per visible camera.
282
+ *
283
+ * Like every event it is telemetry and may be dropped ([D8]) — a consumer
284
+ * keeps a slow reconcile rather than trusting it alone.
285
+ */
286
+ EventCategory["ZoneAnalyticsOccupancyChanged"] = "zone-analytics.occupancy-changed";
287
+ /**
275
288
  * Cap event fired by every device that registers the `battery`
276
289
  * capability. Mirrors the cap definition's `onStatusChanged`. Carries
277
290
  * `{ deviceId, status: BatteryStatus }`. Subscribers (alert center,
@@ -9637,6 +9650,29 @@ var NcOccupancyConditionSchema = object({
9637
9650
  count: number().int().min(0).default(1),
9638
9651
  sustainSeconds: number().int().min(0).max(3600).default(15)
9639
9652
  });
9653
+ /**
9654
+ * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
9655
+ *
9656
+ * The values are not symmetric, and deliberately so — the absent value has to
9657
+ * mean exactly what every rule authored before this condition existed already
9658
+ * does:
9659
+ * - `enter` — entries and every NON-crossing record (movement state,
9660
+ * package, sensor). Exits are rejected. **This is the absent behaviour**:
9661
+ * an operator who never asked for exits must not start receiving them.
9662
+ * - `exit` — ONLY an exit crossing. A record that is not a crossing at all
9663
+ * fails closed, because "the car left the drive" is a question about a
9664
+ * boundary, not about a detection.
9665
+ * - `any` — no direction filter; entries, exits and non-crossings alike.
9666
+ *
9667
+ * A rule asking for a direction should normally also scope `zones`, which the
9668
+ * engine evaluates against the crossed zone as well as the current membership
9669
+ * (an exit's membership no longer contains the zone it just left).
9670
+ */
9671
+ var NcCrossingSchema = _enum([
9672
+ "enter",
9673
+ "exit",
9674
+ "any"
9675
+ ]);
9640
9676
  /** Admin-zone membership condition (zone IDs as stamped by the ZoneEngine). */
9641
9677
  var NcZoneConditionSchema = object({
9642
9678
  ids: array(string().min(1)).min(1),
@@ -9661,6 +9697,13 @@ var NcConditionsSchema = object({
9661
9697
  /** Veto zones — any hit fails the rule. */
9662
9698
  zonesExclude: array(string().min(1)).optional(),
9663
9699
  /**
9700
+ * Zone-crossing direction. IMMEDIATE only — a crossing is a per-event fact
9701
+ * and a closed track carries none, so a `track-end` rule asking for one
9702
+ * fails closed (use `zones`, which tests `zonesVisited`). ABSENT = `enter`,
9703
+ * which is exactly today's behaviour. See {@link NcCrossingSchema}.
9704
+ */
9705
+ crossing: NcCrossingSchema.optional(),
9706
+ /**
9664
9707
  * Exact (case-insensitive) match on the record's collapsed `label`
9665
9708
  * (identity name / plate text / subclass).
9666
9709
  */
@@ -9849,11 +9892,31 @@ var NcMediaPolicySchema = object({
9849
9892
  */
9850
9893
  profile: CamProfileSchema.optional()
9851
9894
  });
9895
+ /**
9896
+ * Cooldown GRANULARITY over the subject's class — how much a fired
9897
+ * notification suppresses.
9898
+ * - `shared` (default, and the absent value) — one window for the whole
9899
+ * rule/scope: a cat silences the next dog for `cooldownSec`.
9900
+ * - `per-class` — an independent window per detected class, so cat→dog fires
9901
+ * at once and cat→cat still waits.
9902
+ *
9903
+ * AUDIO subjects are ALWAYS per-class regardless of this setting: a scream
9904
+ * must not be swallowed by a bark's window (the precedent this generalizes —
9905
+ * see `cooldownKey` in the rule engine).
9906
+ */
9907
+ var NcThrottleGranularitySchema = _enum(["shared", "per-class"]);
9852
9908
  /** Throttle — cooldown survives restarts (rebuilt from the outbox on boot). */
9853
9909
  var NcThrottleSchema = object({
9854
9910
  cooldownSec: number().int().min(0).max(86400).default(60),
9855
9911
  /** `rule` = one shared cooldown; `rule-device` = per-camera cooldown. */
9856
- scope: _enum(["rule", "rule-device"]).default("rule-device")
9912
+ scope: _enum(["rule", "rule-device"]).default("rule-device"),
9913
+ /**
9914
+ * Class granularity of the cooldown key. Optional rather than defaulted:
9915
+ * a Zod default does NOT run on the addon→addon cap path, so a persisted
9916
+ * rule authored before this field simply carries none — and the engine
9917
+ * reads absent as `shared`, the pre-existing behaviour.
9918
+ */
9919
+ granularity: NcThrottleGranularitySchema.optional()
9857
9920
  });
9858
9921
  /** Client-supplied rule fields (server stamps id/createdBy/createdAt/updatedAt). */
9859
9922
  var NcRuleInputSchema = object({
@@ -9961,6 +10024,7 @@ var NcConditionDescriptorSchema = object({
9961
10024
  "schedule",
9962
10025
  "plateMatcher",
9963
10026
  "packagePhase",
10027
+ "crossingSelect",
9964
10028
  "polygonDraw",
9965
10029
  "occupancy"
9966
10030
  ]),
@@ -19313,7 +19377,10 @@ method(object({
19313
19377
  }), method(object({
19314
19378
  deviceId: number(),
19315
19379
  caps: array(string()).readonly().optional()
19316
- }), record(string(), unknown().nullable()));
19380
+ }), record(string(), unknown().nullable())), method(object({
19381
+ deviceIds: array(number()).readonly(),
19382
+ caps: array(string()).readonly().optional()
19383
+ }), record(string(), record(string(), unknown().nullable())));
19317
19384
  method(object({ deviceId: number() }), record(string(), record(string(), unknown()))), method(object({
19318
19385
  deviceId: number(),
19319
19386
  capName: string()
@@ -20735,6 +20802,29 @@ var MotionEventSchema = object({
20735
20802
  * Absent on legacy rows ⇒ treat as `pipeline`.
20736
20803
  */
20737
20804
  var DetectionSourceSchema = _enum(["pipeline", "onboard"]);
20805
+ /**
20806
+ * The confirmed zone crossing that produced an object event. Present ONLY on
20807
+ * an event emitted BY a crossing (`zone.enter` / `zone.exit`); a movement-state
20808
+ * event (`object.entering` / `leaving` / `stationary` / `loitering`) and an
20809
+ * appearance event carry none, so a rule asking for a direction fails closed
20810
+ * on them.
20811
+ *
20812
+ * Exactly ONE crossing per event: the emitter turns each confirmed crossing
20813
+ * into its own event, so a frame in which a track enters A while leaving B
20814
+ * produces two events with two directions — never one ambiguous row.
20815
+ *
20816
+ * `zoneId` is load-bearing for an EXIT: the event's `zones` list is the
20817
+ * membership the box has NOW, and by definition it no longer contains the zone
20818
+ * that was just left. Without the id here, a zone-scoped rule could never match
20819
+ * the exit it asked for.
20820
+ */
20821
+ var ZoneCrossingSchema = object({
20822
+ direction: _enum(["enter", "exit"]),
20823
+ /** Admin zone id crossed. */
20824
+ zoneId: string(),
20825
+ /** Zone display name at crossing time (falls back to the id). */
20826
+ zoneName: string().optional()
20827
+ });
20738
20828
  var ObjectEventSchema = object({
20739
20829
  ...BaseEventFields,
20740
20830
  kind: literal("object"),
@@ -20761,6 +20851,12 @@ var ObjectEventSchema = object({
20761
20851
  zones: array(string()).readonly().optional(),
20762
20852
  /** Omitted in slim projection. */
20763
20853
  state: TrackStateSchema.optional(),
20854
+ /**
20855
+ * The zone crossing this event IS, when it is one. Absent on every other
20856
+ * event kind (movement state, appearance, package) — see
20857
+ * {@link ZoneCrossingSchema}. Omitted in slim projection.
20858
+ */
20859
+ zoneCrossing: ZoneCrossingSchema.optional(),
20764
20860
  /** Detection-frame dimensions in pixels — let consumers normalize the
20765
20861
  * pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
20766
20862
  frameWidth: number().optional(),
@@ -26174,6 +26270,12 @@ Object.freeze({
26174
26270
  addonId: null,
26175
26271
  access: "view"
26176
26272
  },
26273
+ "deviceManager.getDeviceStatusAggregateBatch": {
26274
+ capName: "device-manager",
26275
+ capScope: "system",
26276
+ addonId: null,
26277
+ access: "view"
26278
+ },
26177
26279
  "deviceManager.getLinkedDevices": {
26178
26280
  capName: "device-manager",
26179
26281
  capScope: "system",
package/dist/addon.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
3
- //#region ../types/dist/event-category-BLcNejAE.mjs
3
+ //#region ../types/dist/event-category-Bz24uP1U.mjs
4
4
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
5
5
  EventCategory["SystemBoot"] = "system.boot";
6
6
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -271,6 +271,19 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
271
271
  */
272
272
  EventCategory["DeviceStateChanged"] = "device.state-changed";
273
273
  /**
274
+ * Frame occupancy for a camera CHANGED — a tracked object was gained or
275
+ * lost. Carries `{ deviceId, totalObjects, byClass, zones }`.
276
+ *
277
+ * Emitted only on a change, so a steady scene is silent. It exists so a
278
+ * client can stop polling `zoneAnalytics.getCurrentSnapshot`: that was the
279
+ * one live badge with no push signal at all, and it cost a request every
280
+ * four seconds per visible camera.
281
+ *
282
+ * Like every event it is telemetry and may be dropped ([D8]) — a consumer
283
+ * keeps a slow reconcile rather than trusting it alone.
284
+ */
285
+ EventCategory["ZoneAnalyticsOccupancyChanged"] = "zone-analytics.occupancy-changed";
286
+ /**
274
287
  * Cap event fired by every device that registers the `battery`
275
288
  * capability. Mirrors the cap definition's `onStatusChanged`. Carries
276
289
  * `{ deviceId, status: BatteryStatus }`. Subscribers (alert center,
@@ -9636,6 +9649,29 @@ var NcOccupancyConditionSchema = object({
9636
9649
  count: number().int().min(0).default(1),
9637
9650
  sustainSeconds: number().int().min(0).max(3600).default(15)
9638
9651
  });
9652
+ /**
9653
+ * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
9654
+ *
9655
+ * The values are not symmetric, and deliberately so — the absent value has to
9656
+ * mean exactly what every rule authored before this condition existed already
9657
+ * does:
9658
+ * - `enter` — entries and every NON-crossing record (movement state,
9659
+ * package, sensor). Exits are rejected. **This is the absent behaviour**:
9660
+ * an operator who never asked for exits must not start receiving them.
9661
+ * - `exit` — ONLY an exit crossing. A record that is not a crossing at all
9662
+ * fails closed, because "the car left the drive" is a question about a
9663
+ * boundary, not about a detection.
9664
+ * - `any` — no direction filter; entries, exits and non-crossings alike.
9665
+ *
9666
+ * A rule asking for a direction should normally also scope `zones`, which the
9667
+ * engine evaluates against the crossed zone as well as the current membership
9668
+ * (an exit's membership no longer contains the zone it just left).
9669
+ */
9670
+ var NcCrossingSchema = _enum([
9671
+ "enter",
9672
+ "exit",
9673
+ "any"
9674
+ ]);
9639
9675
  /** Admin-zone membership condition (zone IDs as stamped by the ZoneEngine). */
9640
9676
  var NcZoneConditionSchema = object({
9641
9677
  ids: array(string().min(1)).min(1),
@@ -9660,6 +9696,13 @@ var NcConditionsSchema = object({
9660
9696
  /** Veto zones — any hit fails the rule. */
9661
9697
  zonesExclude: array(string().min(1)).optional(),
9662
9698
  /**
9699
+ * Zone-crossing direction. IMMEDIATE only — a crossing is a per-event fact
9700
+ * and a closed track carries none, so a `track-end` rule asking for one
9701
+ * fails closed (use `zones`, which tests `zonesVisited`). ABSENT = `enter`,
9702
+ * which is exactly today's behaviour. See {@link NcCrossingSchema}.
9703
+ */
9704
+ crossing: NcCrossingSchema.optional(),
9705
+ /**
9663
9706
  * Exact (case-insensitive) match on the record's collapsed `label`
9664
9707
  * (identity name / plate text / subclass).
9665
9708
  */
@@ -9848,11 +9891,31 @@ var NcMediaPolicySchema = object({
9848
9891
  */
9849
9892
  profile: CamProfileSchema.optional()
9850
9893
  });
9894
+ /**
9895
+ * Cooldown GRANULARITY over the subject's class — how much a fired
9896
+ * notification suppresses.
9897
+ * - `shared` (default, and the absent value) — one window for the whole
9898
+ * rule/scope: a cat silences the next dog for `cooldownSec`.
9899
+ * - `per-class` — an independent window per detected class, so cat→dog fires
9900
+ * at once and cat→cat still waits.
9901
+ *
9902
+ * AUDIO subjects are ALWAYS per-class regardless of this setting: a scream
9903
+ * must not be swallowed by a bark's window (the precedent this generalizes —
9904
+ * see `cooldownKey` in the rule engine).
9905
+ */
9906
+ var NcThrottleGranularitySchema = _enum(["shared", "per-class"]);
9851
9907
  /** Throttle — cooldown survives restarts (rebuilt from the outbox on boot). */
9852
9908
  var NcThrottleSchema = object({
9853
9909
  cooldownSec: number().int().min(0).max(86400).default(60),
9854
9910
  /** `rule` = one shared cooldown; `rule-device` = per-camera cooldown. */
9855
- scope: _enum(["rule", "rule-device"]).default("rule-device")
9911
+ scope: _enum(["rule", "rule-device"]).default("rule-device"),
9912
+ /**
9913
+ * Class granularity of the cooldown key. Optional rather than defaulted:
9914
+ * a Zod default does NOT run on the addon→addon cap path, so a persisted
9915
+ * rule authored before this field simply carries none — and the engine
9916
+ * reads absent as `shared`, the pre-existing behaviour.
9917
+ */
9918
+ granularity: NcThrottleGranularitySchema.optional()
9856
9919
  });
9857
9920
  /** Client-supplied rule fields (server stamps id/createdBy/createdAt/updatedAt). */
9858
9921
  var NcRuleInputSchema = object({
@@ -9960,6 +10023,7 @@ var NcConditionDescriptorSchema = object({
9960
10023
  "schedule",
9961
10024
  "plateMatcher",
9962
10025
  "packagePhase",
10026
+ "crossingSelect",
9963
10027
  "polygonDraw",
9964
10028
  "occupancy"
9965
10029
  ]),
@@ -19312,7 +19376,10 @@ method(object({
19312
19376
  }), method(object({
19313
19377
  deviceId: number(),
19314
19378
  caps: array(string()).readonly().optional()
19315
- }), record(string(), unknown().nullable()));
19379
+ }), record(string(), unknown().nullable())), method(object({
19380
+ deviceIds: array(number()).readonly(),
19381
+ caps: array(string()).readonly().optional()
19382
+ }), record(string(), record(string(), unknown().nullable())));
19316
19383
  method(object({ deviceId: number() }), record(string(), record(string(), unknown()))), method(object({
19317
19384
  deviceId: number(),
19318
19385
  capName: string()
@@ -20734,6 +20801,29 @@ var MotionEventSchema = object({
20734
20801
  * Absent on legacy rows ⇒ treat as `pipeline`.
20735
20802
  */
20736
20803
  var DetectionSourceSchema = _enum(["pipeline", "onboard"]);
20804
+ /**
20805
+ * The confirmed zone crossing that produced an object event. Present ONLY on
20806
+ * an event emitted BY a crossing (`zone.enter` / `zone.exit`); a movement-state
20807
+ * event (`object.entering` / `leaving` / `stationary` / `loitering`) and an
20808
+ * appearance event carry none, so a rule asking for a direction fails closed
20809
+ * on them.
20810
+ *
20811
+ * Exactly ONE crossing per event: the emitter turns each confirmed crossing
20812
+ * into its own event, so a frame in which a track enters A while leaving B
20813
+ * produces two events with two directions — never one ambiguous row.
20814
+ *
20815
+ * `zoneId` is load-bearing for an EXIT: the event's `zones` list is the
20816
+ * membership the box has NOW, and by definition it no longer contains the zone
20817
+ * that was just left. Without the id here, a zone-scoped rule could never match
20818
+ * the exit it asked for.
20819
+ */
20820
+ var ZoneCrossingSchema = object({
20821
+ direction: _enum(["enter", "exit"]),
20822
+ /** Admin zone id crossed. */
20823
+ zoneId: string(),
20824
+ /** Zone display name at crossing time (falls back to the id). */
20825
+ zoneName: string().optional()
20826
+ });
20737
20827
  var ObjectEventSchema = object({
20738
20828
  ...BaseEventFields,
20739
20829
  kind: literal("object"),
@@ -20760,6 +20850,12 @@ var ObjectEventSchema = object({
20760
20850
  zones: array(string()).readonly().optional(),
20761
20851
  /** Omitted in slim projection. */
20762
20852
  state: TrackStateSchema.optional(),
20853
+ /**
20854
+ * The zone crossing this event IS, when it is one. Absent on every other
20855
+ * event kind (movement state, appearance, package) — see
20856
+ * {@link ZoneCrossingSchema}. Omitted in slim projection.
20857
+ */
20858
+ zoneCrossing: ZoneCrossingSchema.optional(),
20763
20859
  /** Detection-frame dimensions in pixels — let consumers normalize the
20764
20860
  * pixel-space `bbox` onto a displayed image. Omitted in slim projection. */
20765
20861
  frameWidth: number().optional(),
@@ -26173,6 +26269,12 @@ Object.freeze({
26173
26269
  addonId: null,
26174
26270
  access: "view"
26175
26271
  },
26272
+ "deviceManager.getDeviceStatusAggregateBatch": {
26273
+ capName: "device-manager",
26274
+ capScope: "system",
26275
+ addonId: null,
26276
+ access: "view"
26277
+ },
26176
26278
  "deviceManager.getLinkedDevices": {
26177
26279
  capName: "device-manager",
26178
26280
  capScope: "system",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homeassistant",
3
- "version": "1.2.7",
3
+ "version": "1.2.8",
4
4
  "description": "Home Assistant device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",