@camstack/addon-provider-bosch 0.1.20 → 0.1.22

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.
@@ -1,5 +1,5 @@
1
1
  import "node:crypto";
2
- //#region ../types/dist/event-category-fDPduoeC.mjs
2
+ //#region ../types/dist/event-category-Ceif8n-v.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -471,6 +471,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
471
471
  * on the device detail page.
472
472
  */
473
473
  EventCategory["DoorbellOnPressed"] = "doorbell.onPressed";
474
+ /** Mirrors `runningStateCapability.events.onStarted`. */
475
+ EventCategory["RunningStarted"] = "running.started";
476
+ /** Mirrors `runningStateCapability.events.onFinished`. */
477
+ EventCategory["RunningFinished"] = "running.finished";
474
478
  /**
475
479
  * Cap event fired by every device that registers the `event-emitter`
476
480
  * capability. Mirrors `eventEmitterCapability.events.onEvent`. Carries
@@ -5430,7 +5434,7 @@ var ZodIssueCode = {
5430
5434
  var ZodFirstPartyTypeKind;
5431
5435
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5432
5436
  //#endregion
5433
- //#region ../types/dist/sleep-CHIEEJkY.mjs
5437
+ //#region ../types/dist/sleep-CYfIZzGv.mjs
5434
5438
  /**
5435
5439
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5436
5440
  * window to float samples (D455).
@@ -5773,7 +5777,7 @@ Object.fromEntries([
5773
5777
  * `hydrateSchema` to skip the `value` injection for structural-only fields.
5774
5778
  */
5775
5779
  function isValuelessField(field) {
5776
- return field.type === "separator" || field.type === "info" || field.type === "qr-code" || field.type === "button" || field.type === "object-array" || field.type === "widget" || field.type === "addon-action-button" || field.type === "device-action-button";
5780
+ return field.type === "separator" || field.type === "info" || field.type === "qr-code" || field.type === "button" || field.type === "object-array" || field.type === "widget" || field.type === "addon-action-button" || field.type === "device-action-button" || field.type === "account-sign-in" || field.type === "secret-presence";
5777
5781
  }
5778
5782
  function hydrateSchema(schema, values, options = {}) {
5779
5783
  return {
@@ -8837,7 +8841,7 @@ function errMsg(err) {
8837
8841
  return String(err);
8838
8842
  }
8839
8843
  //#endregion
8840
- //#region ../types/dist/composition-CB6PMT9p.mjs
8844
+ //#region ../types/dist/composition-BJ8iAZb3.mjs
8841
8845
  /**
8842
8846
  * The ffmpeg build every CamStack node downloads, per platform and arch.
8843
8847
  *
@@ -8897,7 +8901,7 @@ portable("linux64"), portable("linuxarm64"), portable("macarm64"), portable("mac
8897
8901
  * ONE table for everyone who asks "is this device HIGH?": the
8898
8902
  * recorder's `RecordingTriggers.sensorDeviceIds` trigger, the post-analysis
8899
8903
  * sensor markers, the orchestrator's camera-sensors bridge and
8900
- * the sources of a composite doorbell (`doorbellFeatureSources`, D671).
8904
+ * the sources of a pulse (`compilePulseOverride`, D936).
8901
8905
  * A second copy would diverge at the first cap added, and the symptom — "the
8902
8906
  * sensor rings the doorbell but does not record" — is exactly D62.
8903
8907
  *
@@ -9138,6 +9142,20 @@ var table = {
9138
9142
  apply: () => {
9139
9143
  throw new ExpressionEvalError("count: stateful evaluation context is required");
9140
9144
  }
9145
+ },
9146
+ dwell: {
9147
+ minArgs: 3,
9148
+ maxArgs: 3,
9149
+ apply: () => {
9150
+ throw new ExpressionEvalError("dwell: stateful evaluation context is required");
9151
+ }
9152
+ },
9153
+ latchedAt: {
9154
+ minArgs: 1,
9155
+ maxArgs: 1,
9156
+ apply: () => {
9157
+ throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
9158
+ }
9141
9159
  }
9142
9160
  };
9143
9161
  Object.freeze(Object.assign(Object.create(null), table));
@@ -16087,7 +16105,15 @@ Object.freeze({
16087
16105
  kind: "fixed",
16088
16106
  result: ["number", "null"]
16089
16107
  },
16090
- count: NUMBER
16108
+ count: NUMBER,
16109
+ dwell: {
16110
+ kind: "fixed",
16111
+ result: ["boolean", "null"]
16112
+ },
16113
+ latchedAt: {
16114
+ kind: "fixed",
16115
+ result: ["number", "null"]
16116
+ }
16091
16117
  });
16092
16118
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
16093
16119
  /**
@@ -42534,9 +42560,6 @@ var NcSystemEventKindSchema = _enum([
42534
42560
  "device-battery-normal",
42535
42561
  "device-consumable-low",
42536
42562
  "device-consumable-normal",
42537
- "device-tank-low",
42538
- "device-tank-full",
42539
- "device-tank-normal",
42540
42563
  "stream-online",
42541
42564
  "stream-offline",
42542
42565
  "node-online",
@@ -42583,13 +42606,14 @@ var NcSystemEventKindSchema = _enum([
42583
42606
  "camera-enabled"
42584
42607
  ]);
42585
42608
  /** The legacy tail of {@link NcSystemEventKindSchema} — see its docblock. */
42586
- var NC_LEGACY_SYSTEM_EVENT_KINDS = new Set([
42609
+ var NC_LEGACY_SYSTEM_EVENT_KINDS = [
42587
42610
  "camera-online",
42588
42611
  "camera-offline",
42589
42612
  "camera-disabled",
42590
42613
  "camera-enabled"
42591
- ]);
42592
- NcSystemEventKindSchema.options.filter((kind) => !NC_LEGACY_SYSTEM_EVENT_KINDS.has(kind));
42614
+ ];
42615
+ var NC_LEGACY_SYSTEM_EVENT_KIND_SET = new Set(NC_LEGACY_SYSTEM_EVENT_KINDS);
42616
+ NcSystemEventKindSchema.options.filter((kind) => !NC_LEGACY_SYSTEM_EVENT_KIND_SET.has(kind));
42593
42617
  /**
42594
42618
  * The panel's transitions, as ONE list.
42595
42619
  *
@@ -43708,18 +43732,11 @@ var NcRuleSchema = NcRuleInputSchema.extend({
43708
43732
  */
43709
43733
  disabledTargetIds: array(string()).default([])
43710
43734
  });
43711
- /**
43712
- * The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
43713
- * report a still-true state. `addons` is the crash-looped addons only and
43714
- * `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
43715
- * job is not an open state, and the alarm stays instant.
43716
- */
43717
43735
  var NcStateSummarySectionIdSchema = _enum([
43718
43736
  "device-state",
43719
43737
  "streams",
43720
43738
  "battery",
43721
43739
  "consumables",
43722
- "tanks",
43723
43740
  "detection-blind",
43724
43741
  "nodes",
43725
43742
  "addons",
@@ -54339,20 +54356,68 @@ var BatteryStatusSchema = object({
54339
54356
  */
54340
54357
  binary: boolean().optional()
54341
54358
  });
54359
+ var BATTERY_DEVICE_TYPES = [
54360
+ DeviceType.Camera,
54361
+ DeviceType.Sensor,
54362
+ DeviceType.Button,
54363
+ DeviceType.Switch,
54364
+ DeviceType.PetFeeder,
54365
+ DeviceType.Container,
54366
+ DeviceType.Thermostat
54367
+ ];
54368
+ /** Generic Customize target for the percentage reading (D936). */
54369
+ var batteryCustomize = {
54370
+ version: 1,
54371
+ targets: [{
54372
+ id: "percentage",
54373
+ cardinality: "scalar",
54374
+ vocabulary: {
54375
+ cap: "battery",
54376
+ stateField: "percentage"
54377
+ },
54378
+ deviceTypes: BATTERY_DEVICE_TYPES,
54379
+ apply: "add-or-replace",
54380
+ path: "percentage",
54381
+ sources: [{
54382
+ kind: "field",
54383
+ valueKinds: ["number", "string"],
54384
+ transforms: [{ kind: "identity" }, {
54385
+ kind: "linear",
54386
+ defaultScale: 1,
54387
+ defaultOffset: 0,
54388
+ clampMin: 0,
54389
+ clampMax: 100
54390
+ }]
54391
+ }],
54392
+ companions: [
54393
+ {
54394
+ kind: "constant",
54395
+ path: "charging",
54396
+ value: "unknown",
54397
+ when: "add"
54398
+ },
54399
+ {
54400
+ kind: "constant",
54401
+ path: "sleeping",
54402
+ value: false,
54403
+ when: "add"
54404
+ },
54405
+ {
54406
+ kind: "clock",
54407
+ path: "lastUpdated",
54408
+ when: "add"
54409
+ }
54410
+ ],
54411
+ sourceReport: { status: "assignment-status" },
54412
+ advancedExpression: true
54413
+ }]
54414
+ };
54342
54415
  var batteryCapability = {
54343
54416
  name: "battery",
54344
54417
  scope: "device",
54345
54418
  deviceNative: true,
54346
54419
  mode: "singleton",
54347
- deviceTypes: [
54348
- DeviceType.Camera,
54349
- DeviceType.Sensor,
54350
- DeviceType.Button,
54351
- DeviceType.Switch,
54352
- DeviceType.PetFeeder,
54353
- DeviceType.Container,
54354
- DeviceType.Thermostat
54355
- ],
54420
+ deviceTypes: BATTERY_DEVICE_TYPES,
54356
54421
  methods: {
54357
54422
  /**
54358
54423
  * Explicitly wake the camera from low-power sleep ahead of a
@@ -54436,6 +54501,7 @@ onStatusChanged: { data: object({
54436
54501
  kind: "gauge",
54437
54502
  unit: "%"
54438
54503
  } } },
54504
+ customize: batteryCustomize,
54439
54505
  /** Clock fields: written, but excluded from the compare that decides
54440
54506
  * whether persisting is worth a SQLite commit. */
54441
54507
  volatileStateFields: ["lastUpdated"]
@@ -55404,6 +55470,106 @@ var ConsumablesStatusSchema = object({
55404
55470
  items: array(ConsumableItemSchema),
55405
55471
  lastChangedAt: number()
55406
55472
  });
55473
+ /** Synthesize seed for a link-built status (no native provider).
55474
+ *
55475
+ * ⚠ NO LIVE CALLER since 2026-08-08 (device-links deleted; see
55476
+ * `CapabilityStatusSchema.empty`). The wiring guidance below was written for
55477
+ * exactly the case the operator is asking about again — a Dreame's HA
55478
+ * consumable-life sensors — so it is kept for that conversation, not because
55479
+ * anything reads it today. */
55480
+ var EMPTY_STATUS = {
55481
+ items: [],
55482
+ lastChangedAt: 0
55483
+ };
55484
+ /** Seed for a NEW link-built consumable item. `key`/`label` are overwritten
55485
+ * with the link's `itemKey` (see `status.itemArray`), so the placeholder
55486
+ * empty strings never survive into a validated item. Link-built items are
55487
+ * not resettable — there is no native provider to receive `reset()`.
55488
+ *
55489
+ * Wiring guidance (HA vacuum consumable-life sensors):
55490
+ * - a percent-remaining source (`numeric-sensor`, unit '%') → `level` via
55491
+ * `identity` (or `linear` scale 1 offset 0 clamp [0,100] to be safe);
55492
+ * - an hours-remaining source (e.g. Dreame 'Main Brush Time Left', unit 'h')
55493
+ * → `level` via `linear` with scale = 100 / max-hours for that item
55494
+ * (e.g. main brush 300 h → scale 0.3333) + clamp [0,100];
55495
+ * - a discrete source (`enum-sensor`, e.g. mop pad 'installed') → `status`
55496
+ * via `enum-map` (e.g. { installed: 'ok', missing: 'replace' }).
55497
+ * A numeric→'replace' THRESHOLD (level < 10 → 'replace') is NOT expressible
55498
+ * with the current transform kinds — leave `status` null (valid) until the
55499
+ * expression transform lands. */
55500
+ /** Generic Customize target for one consumable item (D936). Native rows stay read-only. */
55501
+ var consumablesCustomize = {
55502
+ version: 1,
55503
+ targets: [{
55504
+ id: "items",
55505
+ cardinality: "keyedArray",
55506
+ vocabulary: { cap: "consumables" },
55507
+ deviceTypes: Object.values(DeviceType),
55508
+ apply: "add",
55509
+ path: "items",
55510
+ keyField: "key",
55511
+ labelField: "label",
55512
+ itemSchema: ConsumableItemSchema,
55513
+ nativeItems: "read-only",
55514
+ sourceReport: { status: "assignment-status" },
55515
+ fields: [
55516
+ {
55517
+ path: "level",
55518
+ sources: [{
55519
+ kind: "numeric",
55520
+ transforms: [{ kind: "identity" }, {
55521
+ kind: "linear",
55522
+ defaultScale: 1,
55523
+ defaultOffset: 0,
55524
+ clampMin: 0,
55525
+ clampMax: 100
55526
+ }]
55527
+ }]
55528
+ },
55529
+ {
55530
+ path: "remaining.value",
55531
+ sources: [{
55532
+ kind: "numeric",
55533
+ transforms: [{ kind: "identity" }]
55534
+ }],
55535
+ literals: [{
55536
+ path: "remaining.unit",
55537
+ values: [...ConsumableRemainingUnitSchema.options]
55538
+ }]
55539
+ },
55540
+ {
55541
+ path: "status",
55542
+ sources: [{
55543
+ kind: "enum",
55544
+ transforms: [{
55545
+ kind: "enum-map",
55546
+ outputValues: [...ConsumableStatusSchema.options],
55547
+ unmapped: null
55548
+ }]
55549
+ }]
55550
+ }
55551
+ ],
55552
+ traits: [{
55553
+ path: "kind",
55554
+ values: [...ConsumableKindSchema.options],
55555
+ defaultValue: "wear"
55556
+ }, {
55557
+ path: "form",
55558
+ values: [...ConsumableFormSchema.options],
55559
+ defaultValue: "part"
55560
+ }],
55561
+ companions: [{
55562
+ kind: "clock",
55563
+ path: "lastChangedAt",
55564
+ when: "add"
55565
+ }, {
55566
+ kind: "clock",
55567
+ path: "lastFetchedAt",
55568
+ when: "add"
55569
+ }],
55570
+ advancedExpression: true
55571
+ }]
55572
+ };
55407
55573
  var consumablesCapability = {
55408
55574
  name: "consumables",
55409
55575
  scope: "device",
@@ -55441,10 +55607,7 @@ reset: method(object({
55441
55607
  status: {
55442
55608
  schema: ConsumablesStatusSchema,
55443
55609
  kind: "push",
55444
- empty: {
55445
- items: [],
55446
- lastChangedAt: 0
55447
- },
55610
+ empty: EMPTY_STATUS,
55448
55611
  itemArray: {
55449
55612
  path: "items",
55450
55613
  keyField: "key",
@@ -55480,6 +55643,7 @@ reset: method(object({
55480
55643
  * brush's remaining life and a dishwasher's salt are each recorded the moment
55481
55644
  * their provider reports them; an item that appears later gets its series.
55482
55645
  */
55646
+ customize: consumablesCustomize,
55483
55647
  history: {
55484
55648
  fields: {},
55485
55649
  items: {
@@ -56222,6 +56386,36 @@ var dishwasherCapability = {
56222
56386
  powerOn: { kind: "boolean" }
56223
56387
  } }
56224
56388
  };
56389
+ /** Pulse override: a rising edge advances `lastPressedAt` and the press count. */
56390
+ var doorbellCustomize = {
56391
+ version: 1,
56392
+ targets: [{
56393
+ id: "pressed",
56394
+ cardinality: "event",
56395
+ shape: "pulse",
56396
+ vocabulary: {
56397
+ cap: "doorbell",
56398
+ eventName: "onPressed"
56399
+ },
56400
+ deviceTypes: [DeviceType.Camera],
56401
+ apply: "add",
56402
+ applyAuthority: { kind: "composition-claim" },
56403
+ eventName: "onPressed",
56404
+ edges: ["rising"],
56405
+ timestampPath: "lastPressedAt",
56406
+ counterPath: "pressCountSinceStart",
56407
+ highWater: "composer-advance",
56408
+ combine: "any",
56409
+ debounce: {
56410
+ kind: "rising-edge",
56411
+ defaultDebounceMs: 2e3,
56412
+ changedAtRequired: true
56413
+ },
56414
+ sources: [{ kind: "binary" }, { kind: "switch" }],
56415
+ sourceReport: { status: "assignment-status" },
56416
+ advancedExpression: true
56417
+ }]
56418
+ };
56225
56419
  var DoorbellStatusSchema = object({
56226
56420
  /** Ms epoch of the last press. null = never observed since this provider started. */
56227
56421
  lastPressedAt: number().nullable(),
@@ -56288,7 +56482,8 @@ onPressed: {
56288
56482
  /**
56289
56483
  * History (D850): none — `pressCountSinceStart` resets with the addon, so it is not a monotonic meter; presses live in the events ledger.
56290
56484
  */
56291
- history: "none"
56485
+ history: "none",
56486
+ customize: doorbellCustomize
56292
56487
  };
56293
56488
  /**
56294
56489
  * Enum-state sensor — a string value picked from a finite option set.
@@ -58684,6 +58879,38 @@ authKey: string().optional() }), object({
58684
58879
  /** Human-readable error when `ok: false`. */
58685
58880
  error: string().optional()
58686
58881
  }), { kind: "mutation" });
58882
+ /** Span override: start on a rising edge, end on a fall or this timeout. */
58883
+ var motionCustomize = {
58884
+ version: 1,
58885
+ targets: [{
58886
+ id: "detected",
58887
+ cardinality: "event",
58888
+ shape: "span",
58889
+ vocabulary: {
58890
+ cap: "motion",
58891
+ eventName: "onMotionChanged"
58892
+ },
58893
+ deviceTypes: [DeviceType.Camera],
58894
+ apply: "replace",
58895
+ applyAuthority: {
58896
+ kind: "camera-sensors",
58897
+ timeoutField: "motionCooldownMs"
58898
+ },
58899
+ eventName: "onMotionChanged",
58900
+ start: "rising-edge",
58901
+ end: "falling-edge-or-timeout",
58902
+ timeoutMs: 3e4,
58903
+ combine: "any",
58904
+ sourceModes: [
58905
+ "in-addition",
58906
+ "confirm",
58907
+ "replace"
58908
+ ],
58909
+ sources: [{ kind: "binary" }, { kind: "switch" }],
58910
+ sourceReport: { status: "assignment-status" },
58911
+ advancedExpression: false
58912
+ }]
58913
+ };
58687
58914
  var MotionStatusSchema = object({
58688
58915
  detected: boolean(),
58689
58916
  /** Ms epoch of the last detected-true observation. Null if never detected. */
@@ -58823,7 +59050,8 @@ onMotionChanged: { data: MotionOnMotionChangedDataSchema } },
58823
59050
  history: { fields: { detected: {
58824
59051
  kind: "boolean",
58825
59052
  excludeDeviceTypes: [DeviceType.Camera]
58826
- } } }
59053
+ } } },
59054
+ customize: motionCustomize
58827
59055
  };
58828
59056
  /**
58829
59057
  * Motion-trigger toggle for accessory devices.
@@ -61549,6 +61777,133 @@ var ptzAutotrackCapability = {
61549
61777
  */
61550
61778
  history: "none"
61551
61779
  };
61780
+ var RUNNING_POWER_START_DELAY_MS = 3e4;
61781
+ var RUNNING_POWER_STOP_DELAY_MS = 18e4;
61782
+ /** Before any provider reading — all fields unknown (D933). */
61783
+ var RUNNING_STATE_COLD = {
61784
+ running: null,
61785
+ since: null,
61786
+ source: "native",
61787
+ phase: null,
61788
+ lastFetchedAt: null
61789
+ };
61790
+ var RunningStateSourceSchema = _enum(["native", "assigned"]);
61791
+ var RunningStateStatusSchema = object({
61792
+ /** null = unknown — never coerced to false (D393). */
61793
+ running: boolean().nullable(),
61794
+ /** Epoch ms the current boolean began; null while `running` is null. */
61795
+ since: number().nullable(),
61796
+ source: RunningStateSourceSchema,
61797
+ phase: string().nullable(),
61798
+ /** null until a reading has been published (D393). */
61799
+ lastFetchedAt: number().nullable()
61800
+ });
61801
+ var RunningFlipEventDataSchema = object({
61802
+ deviceId: number(),
61803
+ since: number().nullable(),
61804
+ phase: string().nullable()
61805
+ });
61806
+ var RUNNING_DEVICE_TYPES = Object.values(DeviceType);
61807
+ /** Generic Customize target for the running boolean (D936). */
61808
+ var runningCustomize = {
61809
+ version: 1,
61810
+ targets: [{
61811
+ id: "running",
61812
+ cardinality: "scalar",
61813
+ vocabulary: {
61814
+ cap: "running-state",
61815
+ stateField: "running"
61816
+ },
61817
+ deviceTypes: [
61818
+ DeviceType.Dishwasher,
61819
+ DeviceType.Vacuum,
61820
+ DeviceType.LawnMower,
61821
+ DeviceType.MediaPlayer,
61822
+ DeviceType.WaterHeater,
61823
+ DeviceType.Humidifier,
61824
+ DeviceType.Fan,
61825
+ DeviceType.Climate,
61826
+ DeviceType.Thermostat,
61827
+ DeviceType.PetFeeder
61828
+ ],
61829
+ apply: "add-or-replace",
61830
+ path: "running",
61831
+ sources: [
61832
+ {
61833
+ kind: "switch",
61834
+ transforms: [{ kind: "identity" }]
61835
+ },
61836
+ {
61837
+ kind: "binary",
61838
+ transforms: [{ kind: "identity" }, { kind: "invert" }]
61839
+ },
61840
+ {
61841
+ kind: "numeric",
61842
+ requiredUnit: "W",
61843
+ transforms: [{
61844
+ kind: "threshold",
61845
+ comparison: "gte",
61846
+ defaultThreshold: 5,
61847
+ defaultStartDwellMs: RUNNING_POWER_START_DELAY_MS,
61848
+ defaultStopDwellMs: RUNNING_POWER_STOP_DELAY_MS,
61849
+ thresholdUnit: "W"
61850
+ }]
61851
+ }
61852
+ ],
61853
+ companions: [
61854
+ {
61855
+ kind: "constant",
61856
+ path: "source",
61857
+ value: "assigned",
61858
+ when: "always"
61859
+ },
61860
+ {
61861
+ kind: "constant",
61862
+ path: "phase",
61863
+ value: null,
61864
+ when: "always"
61865
+ },
61866
+ {
61867
+ kind: "clock",
61868
+ path: "lastFetchedAt",
61869
+ when: "always"
61870
+ },
61871
+ {
61872
+ kind: "transition-time",
61873
+ path: "since",
61874
+ sourceChangedAt: "prefer"
61875
+ }
61876
+ ],
61877
+ sourceReport: {
61878
+ status: "assignment-status",
61879
+ runtimeField: "source",
61880
+ nativeValue: "native",
61881
+ assignedValue: "assigned"
61882
+ },
61883
+ advancedExpression: true
61884
+ }]
61885
+ };
61886
+ var runningStateCapability = {
61887
+ name: "running-state",
61888
+ scope: "device",
61889
+ deviceNative: true,
61890
+ mode: "singleton",
61891
+ deviceTypes: RUNNING_DEVICE_TYPES,
61892
+ methods: {},
61893
+ events: {
61894
+ onStarted: { data: RunningFlipEventDataSchema },
61895
+ onFinished: { data: RunningFlipEventDataSchema }
61896
+ },
61897
+ status: {
61898
+ schema: RunningStateStatusSchema,
61899
+ kind: "push"
61900
+ },
61901
+ runtimeState: RunningStateStatusSchema,
61902
+ durability: "restored",
61903
+ history: { fields: { running: { kind: "boolean" } } },
61904
+ volatileStateFields: ["lastFetchedAt"],
61905
+ customize: runningCustomize
61906
+ };
61552
61907
  DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
61553
61908
  kind: "mutation",
61554
61909
  auth: "admin"
@@ -66179,6 +66534,37 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
66179
66534
  kind: "mutation",
66180
66535
  auth: "admin"
66181
66536
  });
66537
+ function programStartFromRemaining(running, remainingSeconds, fetchedAt) {
66538
+ if (!running || remainingSeconds === null || remainingSeconds === void 0) return null;
66539
+ if (remainingSeconds <= 0) return null;
66540
+ return fetchedAt - remainingSeconds * 1e3;
66541
+ }
66542
+ function resolveSince(running, previous, transitionAtMs, bootstrapSinceMs) {
66543
+ if (running === null) return null;
66544
+ const prevRunning = previous?.running ?? null;
66545
+ if (prevRunning === null) return bootstrapSinceMs;
66546
+ if (prevRunning !== running) return transitionAtMs;
66547
+ return previous?.since ?? null;
66548
+ }
66549
+ function nativeSlice(running, phase, previous, transitionAtMs, fetchedAt, bootstrapSinceMs) {
66550
+ return {
66551
+ running,
66552
+ since: resolveSince(running, previous, transitionAtMs, bootstrapSinceMs),
66553
+ source: "native",
66554
+ phase: running === null ? null : phase,
66555
+ lastFetchedAt: fetchedAt
66556
+ };
66557
+ }
66558
+ function runningFromDishwasherOperation(operation, program, previous, fetchedAt, remainingSeconds, transitionAt) {
66559
+ const transitionAtMs = transitionAt ?? fetchedAt;
66560
+ if (operation === null) return nativeSlice(null, null, previous, transitionAtMs, fetchedAt, null);
66561
+ if (operation === "Run" || operation === "Aborting") {
66562
+ const bootstrap = programStartFromRemaining(true, remainingSeconds, fetchedAt);
66563
+ return nativeSlice(true, program ?? operation, previous, transitionAtMs, fetchedAt, bootstrap);
66564
+ }
66565
+ if (operation === "Pause") return nativeSlice(false, "Pause", previous, transitionAtMs, fetchedAt, null);
66566
+ return nativeSlice(false, operation, previous, transitionAtMs, fetchedAt, null);
66567
+ }
66182
66568
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
66183
66569
  Object.freeze({
66184
66570
  person: .5,
@@ -66530,6 +66916,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
66530
66916
  ptzAutotrack: ptzAutotrackCapability,
66531
66917
  recordingOnboard: recordingOnboardCapability,
66532
66918
  recordingSignal: recordingSignalCapability,
66919
+ runningState: runningStateCapability,
66533
66920
  sceneMonitor: sceneMonitorCapability,
66534
66921
  scriptRunner: scriptRunnerCapability,
66535
66922
  smoke: smokeCapability,
@@ -75272,6 +75659,13 @@ Object.freeze({
75272
75659
  access: "create",
75273
75660
  role: "admin"
75274
75661
  },
75662
+ "runningState.getStatus": {
75663
+ capName: "running-state",
75664
+ capScope: "device",
75665
+ addonId: null,
75666
+ access: "view",
75667
+ role: "viewer"
75668
+ },
75275
75669
  "sceneMonitor.captureReference": {
75276
75670
  capName: "scene-monitor",
75277
75671
  capScope: "device",
@@ -79986,6 +80380,32 @@ var APPLIANCE_CAP_VOCABULARY = {
79986
80380
  }],
79987
80381
  events: { onSent: { notOperatorFacing: "a delivery receipt of a send this system made — not a fact about the world" } }
79988
80382
  },
80383
+ "running-state": {
80384
+ scope: "device",
80385
+ noun: t("Running", "In funzione"),
80386
+ state: [{
80387
+ kind: "boolean",
80388
+ field: "running",
80389
+ label: t("Running", "In funzione"),
80390
+ whenTrue: t("When {device} starts", "Quando {device} inizia"),
80391
+ whenFalse: t("When {device} finishes", "Quando {device} finisce"),
80392
+ icon: "play"
80393
+ }],
80394
+ events: {
80395
+ onStarted: {
80396
+ category: EventCategory.RunningStarted,
80397
+ label: t("Started running", "Ha iniziato a funzionare"),
80398
+ phrase: t("When {device} starts running", "Quando {device} inizia a funzionare"),
80399
+ icon: "play"
80400
+ },
80401
+ onFinished: {
80402
+ category: EventCategory.RunningFinished,
80403
+ label: t("Finished", "Ha finito"),
80404
+ phrase: t("When {device} finishes", "Quando {device} finisce"),
80405
+ icon: "square"
80406
+ }
80407
+ }
80408
+ },
79989
80409
  update: {
79990
80410
  scope: "device",
79991
80411
  noun: t("Firmware update", "Aggiornamento firmware"),
@@ -83526,6 +83946,11 @@ Object.freeze({
83526
83946
  form: "single",
83527
83947
  optional: true
83528
83948
  }],
83949
+ "runningState.getStatus": [{
83950
+ name: "deviceId",
83951
+ form: "single",
83952
+ optional: false
83953
+ }],
83529
83954
  "sceneMonitor.captureReference": [{
83530
83955
  name: "deviceId",
83531
83956
  form: "single",
@@ -84024,6 +84449,96 @@ Object.freeze({
84024
84449
  "smtp-provider": "email"
84025
84450
  });
84026
84451
  DeviceType.Camera;
84452
+ 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;
84453
+ /**
84454
+ * A saved Customize assignment (D936). The schema is the type: callers use
84455
+ * `z.infer`, they do not restate the shape.
84456
+ */
84457
+ var OverrideSourceSchema = object({
84458
+ addonId: string().min(1),
84459
+ stableId: string().min(1),
84460
+ cap: string().min(1),
84461
+ fieldPath: string().min(1)
84462
+ });
84463
+ var CustomizeTransformDraftSchema = discriminatedUnion("kind", [
84464
+ object({ kind: literal("identity") }),
84465
+ object({ kind: literal("invert") }),
84466
+ object({
84467
+ kind: literal("threshold"),
84468
+ comparison: _enum(["gte", "lte"]),
84469
+ threshold: number(),
84470
+ startDwellMs: number().nonnegative(),
84471
+ stopDwellMs: number().nonnegative()
84472
+ }),
84473
+ object({
84474
+ kind: literal("linear"),
84475
+ scale: number(),
84476
+ offset: number(),
84477
+ clampMin: number().optional(),
84478
+ clampMax: number().optional()
84479
+ }),
84480
+ object({
84481
+ kind: literal("enum-map"),
84482
+ mapping: record(string(), string().nullable())
84483
+ }),
84484
+ object({ kind: literal("number") })
84485
+ ]);
84486
+ var ScalarOverrideDraftSchema = object({
84487
+ kind: literal("scalar"),
84488
+ cap: string().min(1),
84489
+ targetId: string().min(1),
84490
+ source: OverrideSourceSchema,
84491
+ transform: CustomizeTransformDraftSchema
84492
+ });
84493
+ var KeyedArrayOverrideDraftSchema = object({
84494
+ kind: literal("keyedArray"),
84495
+ cap: string().min(1),
84496
+ targetId: string().min(1),
84497
+ key: string().min(1),
84498
+ label: string().min(1),
84499
+ fieldPath: string().min(1),
84500
+ source: OverrideSourceSchema,
84501
+ transform: CustomizeTransformDraftSchema
84502
+ });
84503
+ var PulseOverrideDraftSchema = object({
84504
+ kind: literal("pulse"),
84505
+ cap: string().min(1),
84506
+ targetId: string().min(1),
84507
+ enabled: boolean(),
84508
+ debounceMs: number().nonnegative(),
84509
+ sources: array(OverrideSourceSchema).min(1)
84510
+ });
84511
+ var SpanSourceDraftSchema = OverrideSourceSchema.extend({ mode: _enum([
84512
+ "in-addition",
84513
+ "confirm",
84514
+ "replace"
84515
+ ]).optional() });
84516
+ discriminatedUnion("kind", [
84517
+ ScalarOverrideDraftSchema,
84518
+ KeyedArrayOverrideDraftSchema,
84519
+ PulseOverrideDraftSchema,
84520
+ object({
84521
+ kind: literal("span"),
84522
+ cap: string().min(1),
84523
+ targetId: string().min(1),
84524
+ timeoutMs: number().nonnegative(),
84525
+ cooldownMs: number().nonnegative().optional(),
84526
+ sources: array(SpanSourceDraftSchema)
84527
+ })
84528
+ ]);
84529
+ object({
84530
+ targetId: string().min(1),
84531
+ configured: boolean(),
84532
+ source: _enum(["native", "assigned"]),
84533
+ state: _enum([
84534
+ "active",
84535
+ "stale",
84536
+ "released",
84537
+ "unavailable"
84538
+ ]),
84539
+ reason: string().nullable()
84540
+ });
84541
+ String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
84027
84542
  var G711_SCALE_CORRECTION_DB = {
84028
84543
  PCMU: 20 * Math.log10(4),
84029
84544
  PCMA: 20 * Math.log10(8)
@@ -84076,40 +84591,7 @@ var NC_AUDIO_DEFAULTS = {
84076
84591
  samplingSeconds: 10
84077
84592
  };
84078
84593
  new Set(["devices", "classes"]);
84079
- /**
84080
- * WHICH narrowing filter speaks about WHICH system-event kind — one predicate,
84081
- * consumed by the rule ENGINE and by every rule EDITOR.
84082
- *
84083
- * ── The failure this file exists for ───────────────────────────────────────
84084
- * `NcSystemEventConditionSchema` carries four optional narrowing lists
84085
- * (`deviceIds`, `deviceTypes`, `nodeIds`, `packageNames`) beside a required
84086
- * `kinds` gate. They are not four filters over one vocabulary: each belongs to
84087
- * a FAMILY of kinds and is meaningless outside it. A node going away has no
84088
- * device type; a completed export has no package; `stream-offline` deliberately
84089
- * carries no device type at all (a stream belongs to a camera by construction).
84090
- *
84091
- * The engine applied all four to every kind, so a filter from one family failed
84092
- * a kind from another family CLOSED. The operator's live rule "Eventi di
84093
- * sistema" selected eleven kinds and set `deviceTypes: ['camera']` — the only
84094
- * way to say "only my cameras" about the two liveness kinds — and NINE of the
84095
- * eleven silently stopped being deliverable. Four days of history contained
84096
- * `device-online` and `device-offline` and nothing else, across a window in
84097
- * which agents were restarted and addons were updated.
84098
- *
84099
- * Both editors already computed this scoping, to decide which filter boxes to
84100
- * render; the cap's own docblock already promised it ("Narrow a `device-*` kind
84101
- * to these device TYPES"). Only the engine disagreed, and it disagreed in the
84102
- * destructive direction. So the rule is stated ONCE, here, and the engine and
84103
- * the editors are readers of it rather than three independent authors.
84104
- *
84105
- * ── The direction ─────────────────────────────────────────────────────────
84106
- * Out of family ⇒ the filter is IGNORED, never fail-closed. An editor that
84107
- * hides a box has already told the operator this filter does not speak about
84108
- * these kinds, so honouring it as an exclusion contradicts the only
84109
- * explanation the operator was ever given. Inside its family the filter still
84110
- * narrows, and still fails CLOSED on a subject that cannot produce the identity
84111
- * it tests (a device the mirror cannot name is not evidence of a camera).
84112
- */
84594
+ new Set(NC_LEGACY_SYSTEM_EVENT_KINDS);
84113
84595
  /**
84114
84596
  * Every filter, for the callers that must cover all of them (guards, tests).
84115
84597
  *
@@ -84135,9 +84617,6 @@ new Map(Object.entries({
84135
84617
  "device-battery-normal": "device-events",
84136
84618
  "device-consumable-low": "device-events",
84137
84619
  "device-consumable-normal": "device-events",
84138
- "device-tank-low": "device-events",
84139
- "device-tank-full": "device-events",
84140
- "device-tank-normal": "device-events",
84141
84620
  "stream-online": "device-events",
84142
84621
  "stream-offline": "device-events",
84143
84622
  "detection-blind": "device-events",
@@ -84214,16 +84693,6 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
84214
84693
  label: "Consumables",
84215
84694
  kinds: ["device-consumable-low", "device-consumable-normal"]
84216
84695
  },
84217
- {
84218
- id: "tanks",
84219
- family: "device-events",
84220
- label: "Tanks",
84221
- kinds: [
84222
- "device-tank-low",
84223
- "device-tank-full",
84224
- "device-tank-normal"
84225
- ]
84226
- },
84227
84696
  {
84228
84697
  id: "detection-blind",
84229
84698
  family: "device-events",
@@ -84381,11 +84850,6 @@ var RULE_BODY_ONLY = ["body"];
84381
84850
  var RULE_TEXT = ["title", "body"];
84382
84851
  var BATTERY = ["device-battery-low", "device-battery-normal"];
84383
84852
  var CONSUMABLE = ["device-consumable-low", "device-consumable-normal"];
84384
- var TANK = [
84385
- "device-tank-low",
84386
- "device-tank-full",
84387
- "device-tank-normal"
84388
- ];
84389
84853
  var ALERT_EPISODE = [
84390
84854
  "alert-critical",
84391
84855
  "alert-error",
@@ -84417,7 +84881,6 @@ var DEVICE_EVENTS = [
84417
84881
  "device-enabled",
84418
84882
  ...BATTERY,
84419
84883
  ...CONSUMABLE,
84420
- ...TANK,
84421
84884
  "stream-online",
84422
84885
  "stream-offline",
84423
84886
  "detection-blind",
@@ -84463,12 +84926,6 @@ var STATE_SUMMARY_SECTION_VARS = [
84463
84926
  example: "Robot — filter 10 %",
84464
84927
  kinds: CONSUMABLE
84465
84928
  },
84466
- {
84467
- name: "summaryTanks",
84468
- label: "Summary: tanks",
84469
- example: "Robot — clean water low",
84470
- kinds: TANK
84471
- },
84472
84929
  {
84473
84930
  name: "summaryDetection",
84474
84931
  label: "Summary: cameras detecting nothing",
@@ -84584,8 +85041,7 @@ var STATE_SUMMARY_VARS = [
84584
85041
  ([...RULE_TEXT], [...COMBINED_ALARM]),
84585
85042
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
84586
85043
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
84587
- ([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
84588
- ([...RULE_TEXT], [...TANK]),
85044
+ ([...RULE_TEXT], [...CONSUMABLE]),
84589
85045
  [...RULE_TEXT],
84590
85046
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
84591
85047
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
@@ -84689,15 +85145,6 @@ new Map([
84689
85145
  snapshotLabel: "Consumables low now",
84690
85146
  snapshotSection: "consumables"
84691
85147
  },
84692
- {
84693
- id: "tanks",
84694
- family: "device-events",
84695
- label: "Tanks (low or full / back to normal)",
84696
- bad: ["device-tank-low", "device-tank-full"],
84697
- recovery: ["device-tank-normal"],
84698
- snapshotLabel: "Tanks low or full now",
84699
- snapshotSection: "tanks"
84700
- },
84701
85148
  {
84702
85149
  id: "motion-noise",
84703
85150
  family: "device-events",
@@ -85286,4 +85733,4 @@ DEFAULT_NATIVE_LEASE_SETTINGS.admission;
85286
85733
  var MB = 1024 * 1024;
85287
85734
  1024 * MB, 3072 * MB;
85288
85735
  //#endregion
85289
- export { number as A, customAction as C, _enum as D, isSecretMarkerLike as E, unknown as F, EventCategory as I, record as M, string as N, array as O, union as P, createEvent as S, isSecretMarker as T, temperatureSensorCapability as _, binaryCapability as a, DeviceType as b, consumablesCapability as c, enumSensorCapability as d, eventEmitterCapability as f, switchCapability as g, powerMeterCapability as h, batteryCapability as i, object as j, literal as k, deviceAdoptionCapability as l, numericSensorCapability as m, BaseDeviceProvider as n, climateControlCapability as o, heatingValveCapability as p, DishwasherOperationStateSchema as r, connectionTestCapability as s, BaseDevice as t, dishwasherCapability as u, waterHeaterCapability as v, defineCustomActions as w, errMsg as x, DeviceRole as y };
85736
+ export { _enum as A, DeviceType as C, defineCustomActions as D, customAction as E, record as F, string as I, union as L, literal as M, number as N, isSecretMarker as O, object as P, unknown as R, DeviceRole as S, createEvent as T, runningFromDishwasherOperation as _, batteryCapability as a, temperatureSensorCapability as b, connectionTestCapability as c, dishwasherCapability as d, enumSensorCapability as f, powerMeterCapability as g, numericSensorCapability as h, RUNNING_STATE_COLD as i, array as j, isSecretMarkerLike as k, consumablesCapability as l, heatingValveCapability as m, BaseDeviceProvider as n, binaryCapability as o, eventEmitterCapability as p, DishwasherOperationStateSchema as r, climateControlCapability as s, BaseDevice as t, deviceAdoptionCapability as u, runningStateCapability as v, errMsg as w, waterHeaterCapability as x, switchCapability as y, EventCategory as z };