@camstack/addon-post-analysis 1.2.630 → 1.2.631

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.
@@ -9412,7 +9412,7 @@ function errMsg(err) {
9412
9412
  return String(err);
9413
9413
  }
9414
9414
  //#endregion
9415
- //#region ../types/dist/composition-xz-ud5EQ.mjs
9415
+ //#region ../types/dist/composition-BJ8iAZb3.mjs
9416
9416
  /**
9417
9417
  * Deterministic SHA-256 hash of an arbitrary serialisable value. The
9418
9418
  * canonical form sorts object keys alphabetically at every depth so two
@@ -9503,7 +9503,7 @@ portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac
9503
9503
  * ONE table for everyone who asks "is this device HIGH?": the
9504
9504
  * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
9505
9505
  * sensor markers, the orchestrator's camera-sensors bridge and
9506
- * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
9506
+ * the sources of a pulse (`compilePulseOverride`, D936).
9507
9507
  * A second copy would diverge at the first cap added, and the symptom — "the
9508
9508
  * sensor rings the doorbell but does not record" — is exactly D62.
9509
9509
  *
@@ -57853,20 +57853,68 @@ var BatteryStatusSchema = object({
57853
57853
  */
57854
57854
  binary: boolean().optional()
57855
57855
  });
57856
+ var BATTERY_DEVICE_TYPES = [
57857
+ DeviceType.Camera,
57858
+ DeviceType.Sensor,
57859
+ DeviceType.Button,
57860
+ DeviceType.Switch,
57861
+ DeviceType.PetFeeder,
57862
+ DeviceType.Container,
57863
+ DeviceType.Thermostat
57864
+ ];
57865
+ /** Generic Customize target for the percentage reading (D936). */
57866
+ var batteryCustomize = {
57867
+ version: 1,
57868
+ targets: [{
57869
+ id: "percentage",
57870
+ cardinality: "scalar",
57871
+ vocabulary: {
57872
+ cap: "battery",
57873
+ stateField: "percentage"
57874
+ },
57875
+ deviceTypes: BATTERY_DEVICE_TYPES,
57876
+ apply: "add-or-replace",
57877
+ path: "percentage",
57878
+ sources: [{
57879
+ kind: "field",
57880
+ valueKinds: ["number", "string"],
57881
+ transforms: [{ kind: "identity" }, {
57882
+ kind: "linear",
57883
+ defaultScale: 1,
57884
+ defaultOffset: 0,
57885
+ clampMin: 0,
57886
+ clampMax: 100
57887
+ }]
57888
+ }],
57889
+ companions: [
57890
+ {
57891
+ kind: "constant",
57892
+ path: "charging",
57893
+ value: "unknown",
57894
+ when: "add"
57895
+ },
57896
+ {
57897
+ kind: "constant",
57898
+ path: "sleeping",
57899
+ value: false,
57900
+ when: "add"
57901
+ },
57902
+ {
57903
+ kind: "clock",
57904
+ path: "lastUpdated",
57905
+ when: "add"
57906
+ }
57907
+ ],
57908
+ sourceReport: { status: "assignment-status" },
57909
+ advancedExpression: true
57910
+ }]
57911
+ };
57856
57912
  var batteryCapability = {
57857
57913
  name: "battery",
57858
57914
  scope: "device",
57859
57915
  deviceNative: true,
57860
57916
  mode: "singleton",
57861
- deviceTypes: [
57862
- DeviceType.Camera,
57863
- DeviceType.Sensor,
57864
- DeviceType.Button,
57865
- DeviceType.Switch,
57866
- DeviceType.PetFeeder,
57867
- DeviceType.Container,
57868
- DeviceType.Thermostat
57869
- ],
57917
+ deviceTypes: BATTERY_DEVICE_TYPES,
57870
57918
  methods: {
57871
57919
  /**
57872
57920
  * Explicitly wake the camera from low-power sleep ahead of a
@@ -57950,6 +57998,7 @@ onStatusChanged: { data: object({
57950
57998
  kind: "gauge",
57951
57999
  unit: "%"
57952
58000
  } } },
58001
+ customize: batteryCustomize,
57953
58002
  /** Clock fields: written, but excluded from the compare that decides
57954
58003
  * whether persisting is worth a SQLite commit. */
57955
58004
  volatileStateFields: ["lastUpdated"]
@@ -58951,6 +59000,106 @@ var ConsumablesStatusSchema = object({
58951
59000
  items: array(ConsumableItemSchema),
58952
59001
  lastChangedAt: number()
58953
59002
  });
59003
+ /** Synthesize seed for a link-built status (no native provider).
59004
+ *
59005
+ * ⚠ NO LIVE CALLER since 2026-08-08 (device-links deleted; see
59006
+ * `CapabilityStatusSchema.empty`). The wiring guidance below was written for
59007
+ * exactly the case the operator is asking about again — a Dreame's HA
59008
+ * consumable-life sensors — so it is kept for that conversation, not because
59009
+ * anything reads it today. */
59010
+ var EMPTY_STATUS = {
59011
+ items: [],
59012
+ lastChangedAt: 0
59013
+ };
59014
+ /** Seed for a NEW link-built consumable item. `key`/`label` are overwritten
59015
+ * with the link's `itemKey` (see `status.itemArray`), so the placeholder
59016
+ * empty strings never survive into a validated item. Link-built items are
59017
+ * not resettable — there is no native provider to receive `reset()`.
59018
+ *
59019
+ * Wiring guidance (HA vacuum consumable-life sensors):
59020
+ * - a percent-remaining source (`numeric-sensor`, unit '%') → `level` via
59021
+ * `identity` (or `linear` scale 1 offset 0 clamp [0,100] to be safe);
59022
+ * - an hours-remaining source (e.g. Dreame 'Main Brush Time Left', unit 'h')
59023
+ * → `level` via `linear` with scale = 100 / max-hours for that item
59024
+ * (e.g. main brush 300 h → scale 0.3333) + clamp [0,100];
59025
+ * - a discrete source (`enum-sensor`, e.g. mop pad 'installed') → `status`
59026
+ * via `enum-map` (e.g. { installed: 'ok', missing: 'replace' }).
59027
+ * A numeric→'replace' THRESHOLD (level < 10 → 'replace') is NOT expressible
59028
+ * with the current transform kinds — leave `status` null (valid) until the
59029
+ * expression transform lands. */
59030
+ /** Generic Customize target for one consumable item (D936). Native rows stay read-only. */
59031
+ var consumablesCustomize = {
59032
+ version: 1,
59033
+ targets: [{
59034
+ id: "items",
59035
+ cardinality: "keyedArray",
59036
+ vocabulary: { cap: "consumables" },
59037
+ deviceTypes: Object.values(DeviceType),
59038
+ apply: "add",
59039
+ path: "items",
59040
+ keyField: "key",
59041
+ labelField: "label",
59042
+ itemSchema: ConsumableItemSchema,
59043
+ nativeItems: "read-only",
59044
+ sourceReport: { status: "assignment-status" },
59045
+ fields: [
59046
+ {
59047
+ path: "level",
59048
+ sources: [{
59049
+ kind: "numeric",
59050
+ transforms: [{ kind: "identity" }, {
59051
+ kind: "linear",
59052
+ defaultScale: 1,
59053
+ defaultOffset: 0,
59054
+ clampMin: 0,
59055
+ clampMax: 100
59056
+ }]
59057
+ }]
59058
+ },
59059
+ {
59060
+ path: "remaining.value",
59061
+ sources: [{
59062
+ kind: "numeric",
59063
+ transforms: [{ kind: "identity" }]
59064
+ }],
59065
+ literals: [{
59066
+ path: "remaining.unit",
59067
+ values: [...ConsumableRemainingUnitSchema.options]
59068
+ }]
59069
+ },
59070
+ {
59071
+ path: "status",
59072
+ sources: [{
59073
+ kind: "enum",
59074
+ transforms: [{
59075
+ kind: "enum-map",
59076
+ outputValues: [...ConsumableStatusSchema.options],
59077
+ unmapped: null
59078
+ }]
59079
+ }]
59080
+ }
59081
+ ],
59082
+ traits: [{
59083
+ path: "kind",
59084
+ values: [...ConsumableKindSchema.options],
59085
+ defaultValue: "wear"
59086
+ }, {
59087
+ path: "form",
59088
+ values: [...ConsumableFormSchema.options],
59089
+ defaultValue: "part"
59090
+ }],
59091
+ companions: [{
59092
+ kind: "clock",
59093
+ path: "lastChangedAt",
59094
+ when: "add"
59095
+ }, {
59096
+ kind: "clock",
59097
+ path: "lastFetchedAt",
59098
+ when: "add"
59099
+ }],
59100
+ advancedExpression: true
59101
+ }]
59102
+ };
58954
59103
  var consumablesCapability = {
58955
59104
  name: "consumables",
58956
59105
  scope: "device",
@@ -58988,10 +59137,7 @@ reset: method(object({
58988
59137
  status: {
58989
59138
  schema: ConsumablesStatusSchema,
58990
59139
  kind: "push",
58991
- empty: {
58992
- items: [],
58993
- lastChangedAt: 0
58994
- },
59140
+ empty: EMPTY_STATUS,
58995
59141
  itemArray: {
58996
59142
  path: "items",
58997
59143
  keyField: "key",
@@ -59027,6 +59173,7 @@ reset: method(object({
59027
59173
  * brush's remaining life and a dishwasher's salt are each recorded the moment
59028
59174
  * their provider reports them; an item that appears later gets its series.
59029
59175
  */
59176
+ customize: consumablesCustomize,
59030
59177
  history: {
59031
59178
  fields: {},
59032
59179
  items: {
@@ -59791,6 +59938,36 @@ var dishwasherCapability = {
59791
59938
  powerOn: { kind: "boolean" }
59792
59939
  } }
59793
59940
  };
59941
+ /** Pulse override: a rising edge advances `lastPressedAt` and the press count. */
59942
+ var doorbellCustomize = {
59943
+ version: 1,
59944
+ targets: [{
59945
+ id: "pressed",
59946
+ cardinality: "event",
59947
+ shape: "pulse",
59948
+ vocabulary: {
59949
+ cap: "doorbell",
59950
+ eventName: "onPressed"
59951
+ },
59952
+ deviceTypes: [DeviceType.Camera],
59953
+ apply: "add",
59954
+ applyAuthority: { kind: "composition-claim" },
59955
+ eventName: "onPressed",
59956
+ edges: ["rising"],
59957
+ timestampPath: "lastPressedAt",
59958
+ counterPath: "pressCountSinceStart",
59959
+ highWater: "composer-advance",
59960
+ combine: "any",
59961
+ debounce: {
59962
+ kind: "rising-edge",
59963
+ defaultDebounceMs: 2e3,
59964
+ changedAtRequired: true
59965
+ },
59966
+ sources: [{ kind: "binary" }, { kind: "switch" }],
59967
+ sourceReport: { status: "assignment-status" },
59968
+ advancedExpression: true
59969
+ }]
59970
+ };
59794
59971
  var DoorbellStatusSchema = object({
59795
59972
  /** Ms epoch of the last press. null = never observed since this provider started. */
59796
59973
  lastPressedAt: number().nullable(),
@@ -59857,7 +60034,8 @@ onPressed: {
59857
60034
  /**
59858
60035
  * History (D850): none — `pressCountSinceStart` resets with the addon, so it is not a monotonic meter; presses live in the events ledger.
59859
60036
  */
59860
- history: "none"
60037
+ history: "none",
60038
+ customize: doorbellCustomize
59861
60039
  };
59862
60040
  /**
59863
60041
  * Enum-state sensor — a string value picked from a finite option set.
@@ -62314,6 +62492,38 @@ authKey: string().optional() }), object({
62314
62492
  /** Human-readable error when `ok: false`. */
62315
62493
  error: string().optional()
62316
62494
  }), { kind: "mutation" });
62495
+ /** Span override: start on a rising edge, end on a fall or this timeout. */
62496
+ var motionCustomize = {
62497
+ version: 1,
62498
+ targets: [{
62499
+ id: "detected",
62500
+ cardinality: "event",
62501
+ shape: "span",
62502
+ vocabulary: {
62503
+ cap: "motion",
62504
+ eventName: "onMotionChanged"
62505
+ },
62506
+ deviceTypes: [DeviceType.Camera],
62507
+ apply: "replace",
62508
+ applyAuthority: {
62509
+ kind: "camera-sensors",
62510
+ timeoutField: "motionCooldownMs"
62511
+ },
62512
+ eventName: "onMotionChanged",
62513
+ start: "rising-edge",
62514
+ end: "falling-edge-or-timeout",
62515
+ timeoutMs: 3e4,
62516
+ combine: "any",
62517
+ sourceModes: [
62518
+ "in-addition",
62519
+ "confirm",
62520
+ "replace"
62521
+ ],
62522
+ sources: [{ kind: "binary" }, { kind: "switch" }],
62523
+ sourceReport: { status: "assignment-status" },
62524
+ advancedExpression: false
62525
+ }]
62526
+ };
62317
62527
  /**
62318
62528
  * Hardware / firmware motion sensor cap — binary detected state plus
62319
62529
  * a timestamp of the last observation. Distinct from
@@ -62478,7 +62688,8 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
62478
62688
  history: { fields: { detected: {
62479
62689
  kind: "boolean",
62480
62690
  excludeDeviceTypes: [DeviceType.Camera]
62481
- } } }
62691
+ } } },
62692
+ customize: motionCustomize
62482
62693
  };
62483
62694
  /**
62484
62695
  * Motion-trigger toggle for accessory devices.
@@ -65239,6 +65450,8 @@ var ptzAutotrackCapability = {
65239
65450
  */
65240
65451
  history: "none"
65241
65452
  };
65453
+ var RUNNING_POWER_START_DELAY_MS = 3e4;
65454
+ var RUNNING_POWER_STOP_DELAY_MS = 18e4;
65242
65455
  var RunningStateSourceSchema = _enum(["native", "assigned"]);
65243
65456
  var RunningStateStatusSchema = object({
65244
65457
  /** null = unknown — never coerced to false (D393). */
@@ -65247,19 +65460,100 @@ var RunningStateStatusSchema = object({
65247
65460
  since: number().nullable(),
65248
65461
  source: RunningStateSourceSchema,
65249
65462
  phase: string().nullable(),
65250
- lastFetchedAt: number()
65463
+ /** null until a reading has been published (D393). */
65464
+ lastFetchedAt: number().nullable()
65251
65465
  });
65252
65466
  var RunningFlipEventDataSchema = object({
65253
65467
  deviceId: number(),
65254
65468
  since: number().nullable(),
65255
65469
  phase: string().nullable()
65256
65470
  });
65471
+ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
65472
+ /** Generic Customize target for the running boolean (D936). */
65473
+ var runningCustomize = {
65474
+ version: 1,
65475
+ targets: [{
65476
+ id: "running",
65477
+ cardinality: "scalar",
65478
+ vocabulary: {
65479
+ cap: "running-state",
65480
+ stateField: "running"
65481
+ },
65482
+ deviceTypes: [
65483
+ DeviceType.Dishwasher,
65484
+ DeviceType.Vacuum,
65485
+ DeviceType.LawnMower,
65486
+ DeviceType.MediaPlayer,
65487
+ DeviceType.WaterHeater,
65488
+ DeviceType.Humidifier,
65489
+ DeviceType.Fan,
65490
+ DeviceType.Climate,
65491
+ DeviceType.Thermostat,
65492
+ DeviceType.PetFeeder
65493
+ ],
65494
+ apply: "add-or-replace",
65495
+ path: "running",
65496
+ sources: [
65497
+ {
65498
+ kind: "switch",
65499
+ transforms: [{ kind: "identity" }]
65500
+ },
65501
+ {
65502
+ kind: "binary",
65503
+ transforms: [{ kind: "identity" }, { kind: "invert" }]
65504
+ },
65505
+ {
65506
+ kind: "numeric",
65507
+ requiredUnit: "W",
65508
+ transforms: [{
65509
+ kind: "threshold",
65510
+ comparison: "gte",
65511
+ defaultThreshold: 5,
65512
+ defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
65513
+ defaultStopDwellMs: RUNNING_POWER_STOP_DELAY_MS,
65514
+ thresholdUnit: "W"
65515
+ }]
65516
+ }
65517
+ ],
65518
+ companions: [
65519
+ {
65520
+ kind: "constant",
65521
+ path: "source",
65522
+ value: "assigned",
65523
+ when: "always"
65524
+ },
65525
+ {
65526
+ kind: "constant",
65527
+ path: "phase",
65528
+ value: null,
65529
+ when: "always"
65530
+ },
65531
+ {
65532
+ kind: "clock",
65533
+ path: "lastFetchedAt",
65534
+ when: "always"
65535
+ },
65536
+ {
65537
+ kind: "transition-time",
65538
+ path: "since",
65539
+ sourceChangedAt: "prefer"
65540
+ }
65541
+ ],
65542
+ sourceReport: {
65543
+ status: "assignment-status",
65544
+ runtimeField: "source",
65545
+ nativeValue: "native",
65546
+ assignedValue: "assigned"
65547
+ },
65548
+ advancedExpression: true
65549
+ }]
65550
+ };
65257
65551
  var runningStateCapability = {
65258
65552
  name: "running-state",
65259
65553
  scope: "device",
65260
65554
  deviceNative: true,
65261
65555
  mode: "singleton",
65262
- deviceTypes: Object.values(DeviceType),
65556
+ deviceTypes: RUNNING_DEVICE_TYPES,
65263
65557
  methods: {},
65264
65558
  events: {
65265
65559
  onStarted: { data: RunningFlipEventDataSchema },
@@ -65272,7 +65566,8 @@ var runningStateCapability = {
65272
65566
  runtimeState: RunningStateStatusSchema,
65273
65567
  durability: "restored",
65274
65568
  history: { fields: { running: { kind: "boolean" } } },
65275
- volatileStateFields: ["lastFetchedAt"]
65569
+ volatileStateFields: ["lastFetchedAt"],
65570
+ customize: runningCustomize
65276
65571
  };
65277
65572
  DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
65278
65573
  kind: "mutation",
@@ -87505,6 +87800,96 @@ var BucketAccumulator = class {
87505
87800
  }
87506
87801
  };
87507
87802
  DeviceType.Camera;
87803
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Camera, DeviceType.Camera, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
87804
+ /**
87805
+ * A saved Customize assignment (D936). The schema is the type: callers use
87806
+ * `z.infer`, they do not restate the shape.
87807
+ */
87808
+ var OverrideSourceSchema = object({
87809
+ addonId: string().min(1),
87810
+ stableId: string().min(1),
87811
+ cap: string().min(1),
87812
+ fieldPath: string().min(1)
87813
+ });
87814
+ var CustomizeTransformDraftSchema = discriminatedUnion("kind", [
87815
+ object({ kind: literal("identity") }),
87816
+ object({ kind: literal("invert") }),
87817
+ object({
87818
+ kind: literal("threshold"),
87819
+ comparison: _enum(["gte", "lte"]),
87820
+ threshold: number(),
87821
+ startDwellMs: number().nonnegative(),
87822
+ stopDwellMs: number().nonnegative()
87823
+ }),
87824
+ object({
87825
+ kind: literal("linear"),
87826
+ scale: number(),
87827
+ offset: number(),
87828
+ clampMin: number().optional(),
87829
+ clampMax: number().optional()
87830
+ }),
87831
+ object({
87832
+ kind: literal("enum-map"),
87833
+ mapping: record(string(), string().nullable())
87834
+ }),
87835
+ object({ kind: literal("number") })
87836
+ ]);
87837
+ var ScalarOverrideDraftSchema = object({
87838
+ kind: literal("scalar"),
87839
+ cap: string().min(1),
87840
+ targetId: string().min(1),
87841
+ source: OverrideSourceSchema,
87842
+ transform: CustomizeTransformDraftSchema
87843
+ });
87844
+ var KeyedArrayOverrideDraftSchema = object({
87845
+ kind: literal("keyedArray"),
87846
+ cap: string().min(1),
87847
+ targetId: string().min(1),
87848
+ key: string().min(1),
87849
+ label: string().min(1),
87850
+ fieldPath: string().min(1),
87851
+ source: OverrideSourceSchema,
87852
+ transform: CustomizeTransformDraftSchema
87853
+ });
87854
+ var PulseOverrideDraftSchema = object({
87855
+ kind: literal("pulse"),
87856
+ cap: string().min(1),
87857
+ targetId: string().min(1),
87858
+ enabled: boolean(),
87859
+ debounceMs: number().nonnegative(),
87860
+ sources: array(OverrideSourceSchema).min(1)
87861
+ });
87862
+ var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: _enum([
87863
+ "in-addition",
87864
+ "confirm",
87865
+ "replace"
87866
+ ]).optional() });
87867
+ discriminatedUnion("kind", [
87868
+ ScalarOverrideDraftSchema,
87869
+ KeyedArrayOverrideDraftSchema,
87870
+ PulseOverrideDraftSchema,
87871
+ object({
87872
+ kind: literal("span"),
87873
+ cap: string().min(1),
87874
+ targetId: string().min(1),
87875
+ timeoutMs: number().nonnegative(),
87876
+ cooldownMs: number().nonnegative().optional(),
87877
+ sources: array(SpanSourceDraftSchema)
87878
+ })
87879
+ ]);
87880
+ object({
87881
+ targetId: string().min(1),
87882
+ configured: boolean(),
87883
+ source: _enum(["native", "assigned"]),
87884
+ state: _enum([
87885
+ "active",
87886
+ "stale",
87887
+ "released",
87888
+ "unavailable"
87889
+ ]),
87890
+ reason: string().nullable()
87891
+ });
87892
+ String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
87508
87893
  var G711_SCALE_CORRECTION_DB = {
87509
87894
  PCMU: 20 * Math.log10(4),
87510
87895
  PCMA: 20 * Math.log10(8)