@camstack/addon-provider-tuya 0.2.147 → 0.2.148

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.mjs CHANGED
@@ -818,7 +818,7 @@ async function discoverDevices(options = {}, binder = createDgramBinder()) {
818
818
  return [...byId.values()];
819
819
  }
820
820
  //#endregion
821
- //#region ../types/dist/event-category-CT-hz5Rb.mjs
821
+ //#region ../types/dist/event-category-DmZDPDf_.mjs
822
822
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
823
823
  EventCategory["SystemBoot"] = "system.boot";
824
824
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -1445,7 +1445,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
1445
1445
  * (a track was promoted to a stationary-registry entry) or departs (the
1446
1446
  * object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
1447
1447
  * the dedicated "Stationary" section — never the live event feed. Payload:
1448
- * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp }`.
1448
+ * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp, observedAt, zones }`.
1449
1449
  */
1450
1450
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
1451
1451
  /**
@@ -1583,6 +1583,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
1583
1583
  */
1584
1584
  EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
1585
1585
  /**
1586
+ * An action run started or ended. Emitted by the `actions` surface.
1587
+ * Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
1588
+ */
1589
+ EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
1590
+ /**
1586
1591
  * Progress update from a running model conversion job.
1587
1592
  * Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
1588
1593
  * Emitted by `addon-model-studio` on the converting node.
@@ -6261,7 +6266,7 @@ var ZodIssueCode = {
6261
6266
  var ZodFirstPartyTypeKind;
6262
6267
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
6263
6268
  //#endregion
6264
- //#region ../types/dist/sleep--jXS9hWo.mjs
6269
+ //#region ../types/dist/sleep-Crlmu_tO.mjs
6265
6270
  /**
6266
6271
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6267
6272
  * window to float samples (D455).
@@ -9381,6 +9386,8 @@ Object.freeze({ "doorbell": "lastPressedAt" });
9381
9386
  /** Every capability name, so addon code can check a name without the schema graph. */
9382
9387
  var CAP_NAMES = Object.freeze([
9383
9388
  "accessories",
9389
+ "action-source",
9390
+ "actions",
9384
9391
  "addon-pages",
9385
9392
  "addon-pages-source",
9386
9393
  "addon-routes",
@@ -9569,11 +9576,11 @@ var CAP_NAMES = Object.freeze([
9569
9576
  Object.freeze({
9570
9577
  "air-quality-sensor": [
9571
9578
  {
9572
- "path": "co2Ppm",
9579
+ "path": "co2",
9573
9580
  "valueType": "number"
9574
9581
  },
9575
9582
  {
9576
- "path": "vocPpb",
9583
+ "path": "voc",
9577
9584
  "valueType": "number"
9578
9585
  },
9579
9586
  {
@@ -9623,7 +9630,7 @@ Object.freeze({
9623
9630
  }
9624
9631
  ],
9625
9632
  "ambient-light-sensor": [{
9626
- "path": "lux",
9633
+ "path": "illuminance",
9627
9634
  "valueType": "number"
9628
9635
  }],
9629
9636
  "audio-metrics": [
@@ -9684,7 +9691,7 @@ Object.freeze({
9684
9691
  ],
9685
9692
  "battery": [
9686
9693
  {
9687
- "path": "percentage",
9694
+ "path": "level",
9688
9695
  "valueType": "number"
9689
9696
  },
9690
9697
  {
@@ -9706,7 +9713,7 @@ Object.freeze({
9706
9713
  "valueType": "number"
9707
9714
  },
9708
9715
  {
9709
- "path": "volts",
9716
+ "path": "voltage",
9710
9717
  "valueType": "number"
9711
9718
  },
9712
9719
  {
@@ -9727,7 +9734,7 @@ Object.freeze({
9727
9734
  "valueType": "boolean"
9728
9735
  }],
9729
9736
  "brightness": [{
9730
- "path": "percentage",
9737
+ "path": "level",
9731
9738
  "valueType": "number"
9732
9739
  }],
9733
9740
  "broker": [{
@@ -9928,7 +9935,7 @@ Object.freeze({
9928
9935
  "valueType": "number"
9929
9936
  },
9930
9937
  {
9931
- "path": "mireds",
9938
+ "path": "colorTemperature",
9932
9939
  "valueType": "number"
9933
9940
  }
9934
9941
  ],
@@ -10107,15 +10114,15 @@ Object.freeze({
10107
10114
  "valueType": "string"
10108
10115
  },
10109
10116
  {
10110
- "path": "remainingSeconds",
10117
+ "path": "remaining",
10111
10118
  "valueType": "number"
10112
10119
  },
10113
10120
  {
10114
- "path": "delayedStartSeconds",
10121
+ "path": "delayedStart",
10115
10122
  "valueType": "number"
10116
10123
  },
10117
10124
  {
10118
- "path": "progressPercent",
10125
+ "path": "progress",
10119
10126
  "valueType": "number"
10120
10127
  },
10121
10128
  {
@@ -10229,7 +10236,7 @@ Object.freeze({
10229
10236
  ],
10230
10237
  "fan-control": [
10231
10238
  {
10232
- "path": "percentage",
10239
+ "path": "speed",
10233
10240
  "valueType": "number"
10234
10241
  },
10235
10242
  {
@@ -10329,7 +10336,7 @@ Object.freeze({
10329
10336
  }
10330
10337
  ],
10331
10338
  "humidity-sensor": [{
10332
- "path": "percent",
10339
+ "path": "humidity",
10333
10340
  "valueType": "number"
10334
10341
  }],
10335
10342
  "image": [{
@@ -10439,7 +10446,7 @@ Object.freeze({
10439
10446
  "valueType": "number"
10440
10447
  },
10441
10448
  {
10442
- "path": "progressPercent",
10449
+ "path": "progress",
10443
10450
  "valueType": "number"
10444
10451
  },
10445
10452
  {
@@ -10518,11 +10525,11 @@ Object.freeze({
10518
10525
  "valueType": "string"
10519
10526
  },
10520
10527
  {
10521
- "path": "positionMs",
10528
+ "path": "position",
10522
10529
  "valueType": "number"
10523
10530
  },
10524
10531
  {
10525
- "path": "durationMs",
10532
+ "path": "duration",
10526
10533
  "valueType": "number"
10527
10534
  },
10528
10535
  {
@@ -10624,11 +10631,11 @@ Object.freeze({
10624
10631
  ]
10625
10632
  },
10626
10633
  {
10627
- "path": "signalPercent",
10634
+ "path": "signal",
10628
10635
  "valueType": "number"
10629
10636
  },
10630
10637
  {
10631
- "path": "rssiDbm",
10638
+ "path": "rssi",
10632
10639
  "valueType": "number"
10633
10640
  },
10634
10641
  {
@@ -10683,6 +10690,18 @@ Object.freeze({
10683
10690
  "path": "foodLevel",
10684
10691
  "valueType": "number"
10685
10692
  },
10693
+ {
10694
+ "path": "bowlFood",
10695
+ "valueType": "number"
10696
+ },
10697
+ {
10698
+ "path": "eating",
10699
+ "valueType": "boolean"
10700
+ },
10701
+ {
10702
+ "path": "supportsMarkRefilled",
10703
+ "valueType": "boolean"
10704
+ },
10686
10705
  {
10687
10706
  "path": "food1",
10688
10707
  "valueType": "number"
@@ -10747,23 +10766,23 @@ Object.freeze({
10747
10766
  ],
10748
10767
  "power-meter": [
10749
10768
  {
10750
- "path": "watts",
10769
+ "path": "power",
10751
10770
  "valueType": "number"
10752
10771
  },
10753
10772
  {
10754
- "path": "kwhTotal",
10773
+ "path": "energy",
10755
10774
  "valueType": "number"
10756
10775
  },
10757
10776
  {
10758
- "path": "volts",
10777
+ "path": "voltage",
10759
10778
  "valueType": "number"
10760
10779
  },
10761
10780
  {
10762
- "path": "amps",
10781
+ "path": "current",
10763
10782
  "valueType": "number"
10764
10783
  },
10765
10784
  {
10766
- "path": "va",
10785
+ "path": "apparentPower",
10767
10786
  "valueType": "number"
10768
10787
  },
10769
10788
  {
@@ -10791,14 +10810,10 @@ Object.freeze({
10791
10810
  {
10792
10811
  "path": "gps.accuracyMeters",
10793
10812
  "valueType": "number"
10794
- },
10795
- {
10796
- "path": "batteryPercent",
10797
- "valueType": "number"
10798
10813
  }
10799
10814
  ],
10800
10815
  "pressure-sensor": [{
10801
- "path": "hpa",
10816
+ "path": "pressure",
10802
10817
  "valueType": "number"
10803
10818
  }],
10804
10819
  "privacy-mask": [{
@@ -11112,7 +11127,7 @@ Object.freeze({
11112
11127
  "valueType": "boolean"
11113
11128
  }],
11114
11129
  "temperature-sensor": [{
11115
- "path": "celsius",
11130
+ "path": "temperature",
11116
11131
  "valueType": "number"
11117
11132
  }],
11118
11133
  "update": [
@@ -11160,7 +11175,7 @@ Object.freeze({
11160
11175
  "valueType": "string"
11161
11176
  },
11162
11177
  {
11163
- "path": "progressPercent",
11178
+ "path": "progress",
11164
11179
  "valueType": "number"
11165
11180
  },
11166
11181
  {
@@ -11645,7 +11660,7 @@ function errMsg(err) {
11645
11660
  return String(err);
11646
11661
  }
11647
11662
  //#endregion
11648
- //#region ../types/dist/composition-Bb8iwHEJ.mjs
11663
+ //#region ../types/dist/composition-CZImLpOI.mjs
11649
11664
  /**
11650
11665
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11651
11666
  *
@@ -16165,6 +16180,14 @@ var AutomationConditionLeafSchema = object({
16165
16180
  array(union([string(), number()]))
16166
16181
  ])
16167
16182
  });
16183
+ var AutomationConditionStationaryPresentSchema = object({
16184
+ kind: literal("stationary-present"),
16185
+ deviceId: number().int().nonnegative(),
16186
+ /** Class names; a macro class matches every raw class that maps to it. */
16187
+ classes: array(string().min(1)).min(1).optional(),
16188
+ /** The parked object must be in at least one of these zones. */
16189
+ zones: array(string().min(1)).min(1).optional()
16190
+ });
16168
16191
  /**
16169
16192
  * The expression leaf, declared as a plain object rather than an intersection
16170
16193
  * with {@link ExpressionSourceSchema}: a discriminated union has to be able to
@@ -16198,7 +16221,8 @@ var AutomationConditionSchema = lazy(() => discriminatedUnion("kind", [
16198
16221
  child: AutomationConditionSchema
16199
16222
  }),
16200
16223
  AutomationConditionLeafSchema,
16201
- AutomationConditionExpressionSchema
16224
+ AutomationConditionExpressionSchema,
16225
+ AutomationConditionStationaryPresentSchema
16202
16226
  ]));
16203
16227
  /**
16204
16228
  * What starts a run.
@@ -16239,7 +16263,34 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
16239
16263
  kind: literal("schedule"),
16240
16264
  cron: string().min(1).max(120)
16241
16265
  }),
16242
- object({ kind: literal("manual") })
16266
+ object({ kind: literal("manual") }),
16267
+ object({
16268
+ kind: literal("detection"),
16269
+ /** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
16270
+ * matches every raw class that maps to it; any other name matches
16271
+ * exactly. */
16272
+ classes: array(string().min(1)).min(1),
16273
+ deviceIds: array(number().int().nonnegative()).min(1),
16274
+ /** The track must have visited at least one of these zones. */
16275
+ zones: array(string().min(1)).min(1).optional(),
16276
+ /** Best-so-far confidence the track must reach. */
16277
+ minScore: number().min(0).max(1).optional()
16278
+ }),
16279
+ object({
16280
+ kind: literal("stationary"),
16281
+ deviceIds: array(number().int().nonnegative()).min(1),
16282
+ /** Class names; a macro class matches like the detection trigger. */
16283
+ classes: array(string().min(1)).min(1).optional(),
16284
+ /** The parked object must be in at least one of these zones. */
16285
+ zones: array(string().min(1)).min(1).optional(),
16286
+ /** `appeared`: it became parked. `departed`: the registry retired it.
16287
+ * The vocabulary of `PipelineAnalyticsStationaryChanged`. */
16288
+ phase: _enum(["appeared", "departed"])
16289
+ }),
16290
+ object({
16291
+ kind: literal("interval"),
16292
+ minutes: number().int().min(1).max(1440)
16293
+ })
16243
16294
  ]);
16244
16295
  /**
16245
16296
  * One action step.
@@ -16259,28 +16310,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
16259
16310
  * is called. The runner still receives a number and is untouched; the
16260
16311
  * resolution is the recipe's job, not the runner's.
16261
16312
  */
16313
+ var AutomationWaitStepSchema = object({
16314
+ kind: literal("wait"),
16315
+ seconds: number().min(0).max(300)
16316
+ });
16317
+ var AutomationCapStepSchema = object({
16318
+ kind: literal("cap"),
16319
+ /**
16320
+ * One device, several same-family devices (locks / climate family / …),
16321
+ * or `{ $var }` for the device that triggered the run. An array is
16322
+ * fan-out at codegen — each id gets the same cap.method call.
16323
+ */
16324
+ deviceId: union([
16325
+ number().int(),
16326
+ array(number().int()).min(1),
16327
+ object({ $var: string().min(1) })
16328
+ ]),
16329
+ cap: string().min(1),
16330
+ method: string().min(1),
16331
+ /** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
16332
+ * SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
16333
+ * the expression leaf. */
16334
+ args: record(string(), unknown()).optional()
16335
+ });
16336
+ /**
16337
+ * The steps an internal Action may contain: cap and wait, and nothing that can
16338
+ * call back into an Action — so an Action can never reach itself (no cycles).
16339
+ */
16340
+ var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
16262
16341
  var AutomationActionSchema = discriminatedUnion("kind", [
16342
+ AutomationWaitStepSchema,
16343
+ AutomationCapStepSchema,
16263
16344
  object({
16264
- kind: literal("wait"),
16265
- seconds: number().min(0).max(300)
16266
- }),
16267
- object({
16268
- kind: literal("cap"),
16269
- /**
16270
- * One device, several same-family devices (locks / climate family / …),
16271
- * or `{ $var }` for the device that triggered the run. An array is
16272
- * fan-out at codegen — each id gets the same cap.method call.
16273
- */
16274
- deviceId: union([
16275
- number().int(),
16276
- array(number().int()).min(1),
16277
- object({ $var: string().min(1) })
16278
- ]),
16279
- cap: string().min(1),
16280
- method: string().min(1),
16281
- /** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
16282
- * evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
16283
- args: record(string(), unknown()).optional()
16345
+ kind: literal("action"),
16346
+ /** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
16347
+ actionId: string().min(1),
16348
+ /** Values for the action's declared variables; the others take their default. */
16349
+ variables: record(string(), union([
16350
+ string(),
16351
+ number(),
16352
+ boolean()
16353
+ ])).optional()
16284
16354
  }),
16285
16355
  object({
16286
16356
  kind: literal("code"),
@@ -16289,10 +16359,357 @@ var AutomationActionSchema = discriminatedUnion("kind", [
16289
16359
  code: string().min(1).max(2e4)
16290
16360
  })
16291
16361
  ]);
16362
+ /**
16363
+ * How a trigger that arrives while the automation is busy (or cooling down) is
16364
+ * handled. One of the automation's execution modes, never a property of its
16365
+ * actions. Absent means `single`.
16366
+ *
16367
+ * - `single` — drop the trigger while a run is in progress (traced + logged).
16368
+ * - `restart` — abort the run in progress (at its next step boundary), start fresh.
16369
+ * - `queued` — queue up to `max` triggers, drop the rest (traced).
16370
+ * - `parallel` — up to `max` runs at once, drop the rest (traced).
16371
+ * - `cooldown` — `single`, and no new run until `minutes` after the last run
16372
+ * STARTED; persisted across a restart. A manual trigger bypasses only this
16373
+ * wait, never the single/queued limits.
16374
+ */
16375
+ var AutomationRunModeSchema = discriminatedUnion("mode", [
16376
+ object({ mode: literal("single") }),
16377
+ object({ mode: literal("restart") }),
16378
+ object({
16379
+ mode: literal("queued"),
16380
+ max: number().int().min(1).max(10)
16381
+ }),
16382
+ object({
16383
+ mode: literal("parallel"),
16384
+ max: number().int().min(1).max(10)
16385
+ }),
16386
+ object({
16387
+ mode: literal("cooldown"),
16388
+ minutes: number().int().min(1).max(1440)
16389
+ })
16390
+ ]);
16292
16391
  var AutomationRecipeSchema = object({
16293
16392
  triggers: array(AutomationTriggerSchema),
16294
16393
  conditions: AutomationConditionSchema.optional(),
16295
- actions: array(AutomationActionSchema)
16394
+ actions: array(AutomationActionSchema),
16395
+ runMode: AutomationRunModeSchema.optional(),
16396
+ /** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
16397
+ keepTraces: number().int().min(1).max(100).optional()
16398
+ });
16399
+ new Set([
16400
+ {
16401
+ id: "person",
16402
+ name: "Person"
16403
+ },
16404
+ {
16405
+ id: "vehicle",
16406
+ name: "Vehicle"
16407
+ },
16408
+ {
16409
+ id: "animal",
16410
+ name: "Animal"
16411
+ },
16412
+ {
16413
+ id: "package",
16414
+ name: "Package"
16415
+ }
16416
+ ].map((l) => l.id));
16417
+ var COCO_TO_MACRO = {
16418
+ mapping: {
16419
+ person: "person",
16420
+ bicycle: "vehicle",
16421
+ car: "vehicle",
16422
+ motorcycle: "vehicle",
16423
+ airplane: "vehicle",
16424
+ bus: "vehicle",
16425
+ train: "vehicle",
16426
+ truck: "vehicle",
16427
+ boat: "vehicle",
16428
+ bird: "animal",
16429
+ cat: "animal",
16430
+ dog: "animal",
16431
+ horse: "animal",
16432
+ sheep: "animal",
16433
+ cow: "animal",
16434
+ elephant: "animal",
16435
+ bear: "animal",
16436
+ zebra: "animal",
16437
+ giraffe: "animal",
16438
+ suitcase: "package",
16439
+ backpack: "package",
16440
+ handbag: "package"
16441
+ },
16442
+ preserveOriginal: false
16443
+ };
16444
+ new Set(Object.values(COCO_TO_MACRO.mapping));
16445
+ /**
16446
+ * Run traces — what an automation (or, later, an Action run) DID, node by node,
16447
+ * so the editor can paint every block green or red with its reason.
16448
+ *
16449
+ * A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
16450
+ * every condition node (containers and leaves, including the ones a
16451
+ * short-circuit never reached), the run-mode verdict and every action step —
16452
+ * each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
16453
+ * for an Action run). Skipped
16454
+ * evaluations are traced too, and identical consecutive skips collapse into a
16455
+ * repeat count so a trigger that fails every 5 minutes cannot flush real runs.
16456
+ *
16457
+ * {@link AutomationStepTraceSchema} is deliberately free of automation
16458
+ * vocabulary so an Action run records the same step shape.
16459
+ */
16460
+ /** A value a trace may show: JSON primitives and short lists, nothing deeper. */
16461
+ var TraceValueSchema = union([
16462
+ string(),
16463
+ number(),
16464
+ boolean(),
16465
+ _null(),
16466
+ array(union([string(), number()]))
16467
+ ]);
16468
+ var AutomationRunOutcomeSchema = _enum([
16469
+ "ran",
16470
+ "skipped-trigger",
16471
+ "skipped-conditions",
16472
+ "skipped-cooldown",
16473
+ "skipped-overlap",
16474
+ "failed",
16475
+ "aborted"
16476
+ ]);
16477
+ /** `not-evaluated` = a short-circuit never reached the node. */
16478
+ var TraceNodeOutcomeSchema = _enum([
16479
+ "pass",
16480
+ "fail",
16481
+ "not-evaluated"
16482
+ ]);
16483
+ var AutomationTriggerTraceSchema = object({
16484
+ kind: string().min(1),
16485
+ outcome: _enum(["pass", "fail"]),
16486
+ /** Why an event was rejected ("class person not in [dog]") or what fired. */
16487
+ reason: string(),
16488
+ /** deviceId, className, trackId, score … — only what the trigger exposes. */
16489
+ vars: record(string(), TraceValueSchema)
16490
+ });
16491
+ var AutomationConditionTraceNodeSchema = object({
16492
+ /** `conditions` for the root, `conditions.<i>` for its i-th child, … */
16493
+ path: string().min(1),
16494
+ kind: _enum([
16495
+ "all",
16496
+ "any",
16497
+ "not",
16498
+ "condition",
16499
+ "expression",
16500
+ "stationary-present"
16501
+ ]),
16502
+ outcome: TraceNodeOutcomeSchema,
16503
+ reason: string(),
16504
+ deviceId: number().int().optional(),
16505
+ cap: string().optional(),
16506
+ fieldPath: string().optional(),
16507
+ operator: string().optional(),
16508
+ expected: TraceValueSchema.optional(),
16509
+ /** What the mirror held; `null` when it held nothing (unknown). */
16510
+ observed: TraceValueSchema.optional()
16511
+ });
16512
+ var AutomationRunVerdictSchema = object({
16513
+ mode: AutomationRunModeSchema,
16514
+ decision: _enum([
16515
+ "run",
16516
+ "queued",
16517
+ "restart",
16518
+ "drop",
16519
+ "cooldown",
16520
+ "bypass"
16521
+ ]),
16522
+ reason: string()
16523
+ });
16524
+ /** One executed (or not-run) step — shared by automations and Action runs. */
16525
+ var AutomationStepTraceSchema = object({
16526
+ /** `actions.<i>` */
16527
+ path: string().min(1),
16528
+ kind: string().min(1),
16529
+ cap: string().optional(),
16530
+ method: string().optional(),
16531
+ deviceId: number().int().optional(),
16532
+ startedAt: number().optional(),
16533
+ endedAt: number().optional(),
16534
+ outcome: _enum([
16535
+ "ok",
16536
+ "error",
16537
+ "not-run"
16538
+ ]),
16539
+ message: string().optional()
16540
+ });
16541
+ var AutomationRunTraceSchema = object({
16542
+ runId: string().min(1),
16543
+ startedAt: number(),
16544
+ endedAt: number(),
16545
+ trigger: AutomationTriggerTraceSchema,
16546
+ conditions: array(AutomationConditionTraceNodeSchema),
16547
+ verdict: AutomationRunVerdictSchema.optional(),
16548
+ steps: array(AutomationStepTraceSchema),
16549
+ outcome: AutomationRunOutcomeSchema,
16550
+ /** How many identical consecutive skips this trace stands for (>= 1). */
16551
+ repeat: number().int().min(1),
16552
+ /** When the latest of those repeats happened. */
16553
+ lastAt: number()
16554
+ });
16555
+ /**
16556
+ * What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
16557
+ * `action:<actionId>`): the cooldown stamp and the trace ring.
16558
+ */
16559
+ var AutomationStateDocSchema = object({
16560
+ version: literal(1),
16561
+ lastRunStartedAt: number().nullable(),
16562
+ traces: array(AutomationRunTraceSchema)
16563
+ });
16564
+ /**
16565
+ * Actions — named, runnable things an operator (or an automation) can start,
16566
+ * declared as LIST ENTRIES, never as devices.
16567
+ *
16568
+ * An entry is either **internal** (a short list of cap/wait steps kept in the
16569
+ * hub's `actions` record kind) or declared by an addon through the
16570
+ * `action-source` collection (a Home Assistant script, a scene …). The one
16571
+ * surface the UI and automations talk to is the `actions` cap; it keeps no
16572
+ * catalog of its own (D3) — every `list` asks the providers live.
16573
+ *
16574
+ * This file is the data half: the entry schema, the variables an entry may
16575
+ * declare, and the pure resolution of the values a run was given. It holds no
16576
+ * runtime.
16577
+ */
16578
+ /** What a variable's value is. `select` takes one of `options`. */
16579
+ var ActionVariableTypeSchema = _enum([
16580
+ "string",
16581
+ "number",
16582
+ "boolean",
16583
+ "select"
16584
+ ]);
16585
+ var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
16586
+ var ActionVariableValueSchema = union([
16587
+ string(),
16588
+ number(),
16589
+ boolean()
16590
+ ]);
16591
+ /**
16592
+ * One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
16593
+ * value) or `{{vars.name}}` (inside a string) in their args.
16594
+ */
16595
+ var ActionVariableSchema = object({
16596
+ name: string().regex(ACTION_VARIABLE_NAME_RE),
16597
+ label: string().min(1).max(120).optional(),
16598
+ type: ActionVariableTypeSchema,
16599
+ required: boolean().optional(),
16600
+ default: ActionVariableValueSchema.optional(),
16601
+ /** The allowed values of a `select`. */
16602
+ options: array(string().min(1)).min(1).optional()
16603
+ }).superRefine((v, ctx) => {
16604
+ if (v.type === "select" && v.options === void 0) ctx.addIssue({
16605
+ code: "custom",
16606
+ message: "a select variable needs options",
16607
+ path: ["options"]
16608
+ });
16609
+ if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
16610
+ code: "custom",
16611
+ message: variableValueError(v, v.default) ?? "invalid default",
16612
+ path: ["default"]
16613
+ });
16614
+ });
16615
+ /** Why `value` is not a legal value for the variable, or null when it is. */
16616
+ function variableValueError(variable, value) {
16617
+ switch (variable.type) {
16618
+ case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
16619
+ case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
16620
+ case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
16621
+ case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
16622
+ }
16623
+ }
16624
+ var ActionSourceKindSchema = _enum(["internal", "addon"]);
16625
+ function isInternalActionId(actionId) {
16626
+ return actionId.startsWith("internal:") && actionId.length > 9;
16627
+ }
16628
+ /** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
16629
+ function addonIdOfActionId(actionId) {
16630
+ if (isInternalActionId(actionId)) return null;
16631
+ const at = actionId.indexOf(":");
16632
+ return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
16633
+ }
16634
+ var ActionStatusSchema = object({
16635
+ isRunning: boolean(),
16636
+ /** Ms epoch the latest run STARTED; null when it never ran. */
16637
+ lastRunAt: number().nullable(),
16638
+ /** The latest run's failure; null on success or when it never ran. */
16639
+ lastError: string().nullable()
16640
+ });
16641
+ var ActionEntrySchema = object({
16642
+ /** `internal:<uuid>` or `<addonId>:<localId>`. */
16643
+ id: string().min(3),
16644
+ name: string().min(1).max(120),
16645
+ /** The addon that declared it; `core-blocks` for an internal one. */
16646
+ addonId: string().min(1),
16647
+ source: ActionSourceKindSchema,
16648
+ /** An addon-declared entry is edited where it was declared. */
16649
+ readOnly: boolean(),
16650
+ /** Internal only: cap and wait steps. No action-in-action, so no cycles. */
16651
+ steps: array(ActionStepSchema).min(1).max(50).optional(),
16652
+ variables: array(ActionVariableSchema).max(20).optional(),
16653
+ status: ActionStatusSchema
16654
+ }).superRefine((entry, ctx) => {
16655
+ if (entry.source === "internal") {
16656
+ if (!isInternalActionId(entry.id)) ctx.addIssue({
16657
+ code: "custom",
16658
+ message: "an internal action id is internal:<uuid>",
16659
+ path: ["id"]
16660
+ });
16661
+ return;
16662
+ }
16663
+ if (entry.steps !== void 0) ctx.addIssue({
16664
+ code: "custom",
16665
+ message: "only an internal action carries steps",
16666
+ path: ["steps"]
16667
+ });
16668
+ if (!entry.readOnly) ctx.addIssue({
16669
+ code: "custom",
16670
+ message: "an addon action is read-only here",
16671
+ path: ["readOnly"]
16672
+ });
16673
+ if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
16674
+ code: "custom",
16675
+ message: "an addon action id is <addonId>:<localId>",
16676
+ path: ["id"]
16677
+ });
16678
+ });
16679
+ /** What an operator writes for an internal action. */
16680
+ var ActionInputSchema = object({
16681
+ name: string().min(1).max(120),
16682
+ steps: array(ActionStepSchema).min(1).max(50),
16683
+ variables: array(ActionVariableSchema).max(20).optional()
16684
+ });
16685
+ /** Who started a run. Absent = the operator pressed it. */
16686
+ var ActionRunOriginSchema = object({
16687
+ /** The automation block whose step started it. */
16688
+ blockId: string().min(1).optional() });
16689
+ /** `started` = the caller did not ask to wait. */
16690
+ var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
16691
+ var ActionRunResultSchema = object({
16692
+ runId: string().min(1),
16693
+ outcome: ActionRunOutcomeSchema,
16694
+ /** Why it did not run, or what failed. */
16695
+ message: string().optional()
16696
+ });
16697
+ _enum([
16698
+ "not-found",
16699
+ "read-only",
16700
+ "invalid-variables",
16701
+ "invalid-steps",
16702
+ "not-linked",
16703
+ "busy"
16704
+ ]);
16705
+ object({
16706
+ actionId: string(),
16707
+ runId: string(),
16708
+ isRunning: boolean(),
16709
+ /** Set when the run ended. */
16710
+ outcome: AutomationRunOutcomeSchema.optional(),
16711
+ lastRunAt: number().nullable(),
16712
+ lastError: string().nullable()
16296
16713
  });
16297
16714
  /**
16298
16715
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
@@ -18979,7 +19396,7 @@ var CompositionEventPlanSchema = object({
18979
19396
  stateField: string(),
18980
19397
  fieldKey: string()
18981
19398
  });
18982
- /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
19399
+ /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.temperature`. */
18983
19400
  var CompositionProblemSchema = object({
18984
19401
  code: _enum([
18985
19402
  "reserved-variant",
@@ -19298,7 +19715,7 @@ var GROUP_TEMPLATES = [
19298
19715
  summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
19299
19716
  role: DeviceRole.TemperatureSensor,
19300
19717
  outputCap: "temperature-sensor",
19301
- outputField: "celsius",
19718
+ outputField: "temperature",
19302
19719
  quantity: "temperature",
19303
19720
  defaultAggregate: "mean",
19304
19721
  empty: "null",
@@ -19309,7 +19726,7 @@ var GROUP_TEMPLATES = [
19309
19726
  summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
19310
19727
  role: DeviceRole.HumiditySensor,
19311
19728
  outputCap: "humidity-sensor",
19312
- outputField: "percent",
19729
+ outputField: "humidity",
19313
19730
  quantity: "humidity",
19314
19731
  defaultAggregate: "mean",
19315
19732
  empty: "null",
@@ -19320,7 +19737,7 @@ var GROUP_TEMPLATES = [
19320
19737
  summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
19321
19738
  role: DeviceRole.PressureSensor,
19322
19739
  outputCap: "pressure-sensor",
19323
- outputField: "hpa",
19740
+ outputField: "pressure",
19324
19741
  quantity: "pressure",
19325
19742
  defaultAggregate: "mean",
19326
19743
  empty: "null",
@@ -19331,7 +19748,7 @@ var GROUP_TEMPLATES = [
19331
19748
  summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
19332
19749
  role: DeviceRole.AmbientLightSensor,
19333
19750
  outputCap: "ambient-light-sensor",
19334
- outputField: "lux",
19751
+ outputField: "illuminance",
19335
19752
  quantity: "illuminance",
19336
19753
  defaultAggregate: "mean",
19337
19754
  empty: "null",
@@ -19342,7 +19759,7 @@ var GROUP_TEMPLATES = [
19342
19759
  summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
19343
19760
  role: DeviceRole.PowerSensor,
19344
19761
  outputCap: "power-meter",
19345
- outputField: "watts",
19762
+ outputField: "power",
19346
19763
  quantity: "power",
19347
19764
  defaultAggregate: "sum",
19348
19765
  empty: "omit",
@@ -19353,7 +19770,7 @@ var GROUP_TEMPLATES = [
19353
19770
  summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
19354
19771
  role: DeviceRole.EnergySensor,
19355
19772
  outputCap: "power-meter",
19356
- outputField: "kwhTotal",
19773
+ outputField: "energy",
19357
19774
  quantity: "energy",
19358
19775
  defaultAggregate: "sum",
19359
19776
  empty: "omit",
@@ -19364,7 +19781,7 @@ var GROUP_TEMPLATES = [
19364
19781
  summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
19365
19782
  role: DeviceRole.BatterySensor,
19366
19783
  outputCap: "battery",
19367
- outputField: "percentage",
19784
+ outputField: "level",
19368
19785
  quantity: "percentage",
19369
19786
  defaultAggregate: "mean",
19370
19787
  empty: "null",
@@ -19942,7 +20359,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
19942
20359
  kind: "mutation",
19943
20360
  auth: "admin",
19944
20361
  access: "view"
19945
- });
20362
+ }), method(object({
20363
+ blockId: string().min(1),
20364
+ trace: AutomationRunTraceSchema.optional(),
20365
+ runStartedAt: number().optional(),
20366
+ keepTraces: number().int().min(1).max(100).optional()
20367
+ }), _void(), {
20368
+ kind: "mutation",
20369
+ auth: "admin"
20370
+ }), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
20371
+ traces: array(AutomationRunTraceSchema),
20372
+ lastError: string().nullable()
20373
+ }), { auth: "admin" });
19946
20374
  /**
19947
20375
  * `custom-model-registry` — collection cap exposing operator-registered
19948
20376
  * custom detection models. Each provider (today: `addon-model-studio`)
@@ -45244,51 +45672,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
45244
45672
  kind: "mutation",
45245
45673
  auth: "admin"
45246
45674
  });
45247
- new Set([
45248
- {
45249
- id: "person",
45250
- name: "Person"
45251
- },
45252
- {
45253
- id: "vehicle",
45254
- name: "Vehicle"
45255
- },
45256
- {
45257
- id: "animal",
45258
- name: "Animal"
45259
- },
45260
- {
45261
- id: "package",
45262
- name: "Package"
45263
- }
45264
- ].map((l) => l.id));
45265
- var COCO_TO_MACRO = {
45266
- mapping: {
45267
- person: "person",
45268
- bicycle: "vehicle",
45269
- car: "vehicle",
45270
- motorcycle: "vehicle",
45271
- airplane: "vehicle",
45272
- bus: "vehicle",
45273
- train: "vehicle",
45274
- truck: "vehicle",
45275
- boat: "vehicle",
45276
- bird: "animal",
45277
- cat: "animal",
45278
- dog: "animal",
45279
- horse: "animal",
45280
- sheep: "animal",
45281
- cow: "animal",
45282
- elephant: "animal",
45283
- bear: "animal",
45284
- zebra: "animal",
45285
- giraffe: "animal",
45286
- suitcase: "package",
45287
- backpack: "package",
45288
- handbag: "package"
45289
- },
45290
- preserveOriginal: false
45291
- };
45292
45675
  var AUDIO_MACRO_LABELS = [
45293
45676
  {
45294
45677
  id: "speech",
@@ -57855,9 +58238,9 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
57855
58238
  */
57856
58239
  var AirQualitySensorStatusSchema = object({
57857
58240
  /** Carbon dioxide concentration in ppm. */
57858
- co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
58241
+ co2: number().min(0).optional().meta(readingMeta("concentration-volume")),
57859
58242
  /** Total volatile organic compounds in ppb. */
57860
- vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
58243
+ voc: number().min(0).optional().meta(readingMeta("concentration-ppb")),
57861
58244
  /** Particulate matter ≤ 2.5 μm in µg/m³. */
57862
58245
  pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
57863
58246
  /** Particulate matter ≤ 10 μm in µg/m³. */
@@ -57890,12 +58273,12 @@ var airQualitySensorCapability = {
57890
58273
  * History (D850): recorded series.
57891
58274
  */
57892
58275
  history: { fields: {
57893
- co2Ppm: {
58276
+ co2: {
57894
58277
  kind: "gauge",
57895
58278
  unit: "ppm",
57896
58279
  deadband: 5
57897
58280
  },
57898
- vocPpb: {
58281
+ voc: {
57899
58282
  kind: "gauge",
57900
58283
  unit: "ppb",
57901
58284
  deadband: 5
@@ -57926,7 +58309,7 @@ var airQualitySensorCapability = {
57926
58309
  */
57927
58310
  var AmbientLightSensorStatusSchema = object({
57928
58311
  /** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
57929
- lux: number().min(0).nullable().meta(readingMeta("illuminance", {
58312
+ illuminance: number().min(0).nullable().meta(readingMeta("illuminance", {
57930
58313
  precision: 0,
57931
58314
  label: "Illuminance"
57932
58315
  })),
@@ -57955,7 +58338,7 @@ var ambientLightSensorCapability = {
57955
58338
  /**
57956
58339
  * History (D850): recorded series. Wide range, so a RELATIVE deadband (10 %).
57957
58340
  */
57958
- history: { fields: { lux: {
58341
+ history: { fields: { illuminance: {
57959
58342
  kind: "gauge",
57960
58343
  unit: "lx",
57961
58344
  deadbandPct: 10,
@@ -58094,6 +58477,84 @@ var audioMetricsCapability = {
58094
58477
  */
58095
58478
  history: "none"
58096
58479
  };
58480
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
58481
+ actionId: string().min(1),
58482
+ variables: record(string(), ActionVariableValueSchema).optional()
58483
+ }), _void(), {
58484
+ kind: "mutation",
58485
+ auth: "admin"
58486
+ }), method(object({ actionId: string().min(1) }), _void(), {
58487
+ kind: "mutation",
58488
+ auth: "admin"
58489
+ });
58490
+ /**
58491
+ * actions — the ONE surface for runnable actions, for the UI and for
58492
+ * automations. Provided by the core-blocks builtin on the hub.
58493
+ *
58494
+ * An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
58495
+ * steps, kept in the hub's `actions` record kind) or declared by an addon over
58496
+ * `action-source`. `list` asks every `action-source` provider LIVE and overlays
58497
+ * the run status from the hub's `runs` ledger; there is no catalog here to
58498
+ * drift (D3).
58499
+ *
58500
+ * **Permissions follow the camera, as linked devices do.** An action is linked
58501
+ * to cameras by the operator (`setLinks`, D356: nothing links itself). A
58502
+ * non-admin may `get` / `run` an action only through a camera they may see that
58503
+ * links it: they name the camera (`deviceId`, a top-level field so the scope
58504
+ * gate sees it) and the provider refuses an action that camera does not link.
58505
+ * An admin, and an in-process caller (an automation block), may run any action.
58506
+ * Every refusal is typed (`[not-linked] …`) and logged.
58507
+ *
58508
+ * A second `run` of an action that is already running is REFUSED — traced and
58509
+ * logged — never queued.
58510
+ */
58511
+ var ActionIdInput = object({ actionId: string().min(1) });
58512
+ var ActionLinksSchema = object({
58513
+ deviceId: number().int().nonnegative(),
58514
+ actionIds: array(string().min(1)).max(100)
58515
+ });
58516
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
58517
+ actionId: string().min(1),
58518
+ deviceId: number().int().nonnegative().optional()
58519
+ }), object({ action: ActionEntrySchema.nullable() }), {
58520
+ role: "viewer",
58521
+ auth: "protected",
58522
+ kind: "query",
58523
+ caller: "required"
58524
+ }), method(object({
58525
+ actionId: string().min(1),
58526
+ variables: record(string(), ActionVariableValueSchema).optional(),
58527
+ wait: boolean().optional(),
58528
+ origin: ActionRunOriginSchema.optional(),
58529
+ deviceId: number().int().nonnegative().optional()
58530
+ }), ActionRunResultSchema, {
58531
+ role: "viewer",
58532
+ auth: "protected",
58533
+ kind: "mutation",
58534
+ caller: "required"
58535
+ }), method(ActionIdInput, _void(), {
58536
+ kind: "mutation",
58537
+ auth: "admin"
58538
+ }), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
58539
+ kind: "mutation",
58540
+ auth: "admin"
58541
+ }), method(object({
58542
+ actionId: string().min(1),
58543
+ action: ActionInputSchema.partial()
58544
+ }), object({ action: ActionEntrySchema }), {
58545
+ kind: "mutation",
58546
+ auth: "admin"
58547
+ }), method(ActionIdInput, _void(), {
58548
+ kind: "mutation",
58549
+ auth: "admin"
58550
+ }), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
58551
+ role: "viewer",
58552
+ auth: "protected",
58553
+ kind: "query"
58554
+ }), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
58555
+ kind: "mutation",
58556
+ auth: "admin"
58557
+ });
58097
58558
  /**
58098
58559
  * Automation-control cap. Models HA `automation.*` entities on
58099
58560
  * `DeviceType.Automation`. An automation is a trigger+condition+
@@ -58190,7 +58651,7 @@ var BatteryStatusSchema = object({
58190
58651
  * Consumers must SKIP a null rather than coerce it — `battery-band` already
58191
58652
  * declines to band a non-finite reading, which is the correct shape.
58192
58653
  */
58193
- percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
58654
+ level: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
58194
58655
  /**
58195
58656
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
58196
58657
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -58200,7 +58661,7 @@ var BatteryStatusSchema = object({
58200
58661
  * `'unknown'` is the absence of an answer: the provider has not read the
58201
58662
  * power fields yet, or the firmware reported neither. Before it existed,
58202
58663
  * two unreadable fields produced `'none'`, and a camera nobody had reached
58203
- * was drawn "on battery alone" — the same D315 defect `percentage` closed
58664
+ * was drawn "on battery alone" — the same D315 defect `level` closed
58204
58665
  * by going nullable. Consumers SKIP it (no charger state published, no
58205
58666
  * glyph, no HomeKit ChargingState) rather than coerce it either way.
58206
58667
  */
@@ -58224,7 +58685,7 @@ var BatteryStatusSchema = object({
58224
58685
  * that only report charge. A second reading on this cap, not a second
58225
58686
  * `numeric-sensor` on the same device.
58226
58687
  */
58227
- volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
58688
+ voltage: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
58228
58689
  /**
58229
58690
  * Ms epoch of the last time the device PROVED it was reachable — a
58230
58691
  * completed firmware round-trip, an observed wake, or an inbound push
@@ -58258,7 +58719,7 @@ var BatteryStatusSchema = object({
58258
58719
  /**
58259
58720
  * True when the source is a BINARY low-battery indicator (HA
58260
58721
  * `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
58261
- * charge level — `percentage` is then a coarse stand-in (100 = normal,
58722
+ * charge level — `level` is then a coarse stand-in (100 = normal,
58262
58723
  * sub-threshold = low). UI MUST render "Normal"/"Low" instead of a
58263
58724
  * misleading exact percentage. Absent/false → genuine 0–100 % reading.
58264
58725
  */
@@ -58278,15 +58739,15 @@ var BATTERY_DEVICE_TYPES = [
58278
58739
  var batteryCustomize = {
58279
58740
  version: 1,
58280
58741
  targets: [{
58281
- id: "percentage",
58742
+ id: "level",
58282
58743
  cardinality: "scalar",
58283
58744
  vocabulary: {
58284
58745
  cap: "battery",
58285
- stateField: "percentage"
58746
+ stateField: "level"
58286
58747
  },
58287
58748
  deviceTypes: BATTERY_DEVICE_TYPES,
58288
58749
  apply: "add",
58289
- path: "percentage",
58750
+ path: "level",
58290
58751
  sources: [{
58291
58752
  kind: "field",
58292
58753
  valueKinds: ["number", "string"],
@@ -58380,7 +58841,7 @@ onStatusChanged: { data: object({
58380
58841
  schema: BatteryStatusSchema,
58381
58842
  kind: "push",
58382
58843
  empty: {
58383
- percentage: null,
58844
+ level: null,
58384
58845
  charging: "unknown",
58385
58846
  sleeping: false,
58386
58847
  lastUpdated: 0
@@ -58407,11 +58868,11 @@ onStatusChanged: { data: object({
58407
58868
  * History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
58408
58869
  */
58409
58870
  history: { fields: {
58410
- percentage: {
58871
+ level: {
58411
58872
  kind: "gauge",
58412
58873
  unit: "%"
58413
58874
  },
58414
- volts: {
58875
+ voltage: {
58415
58876
  kind: "gauge",
58416
58877
  unit: "V"
58417
58878
  }
@@ -58471,14 +58932,14 @@ var binaryCapability = {
58471
58932
  * controls to this single-method surface.
58472
58933
  *
58473
58934
  * The cap is intentionally minimal: a single `setBrightness({deviceId,
58474
- * percentage})` mutation plus the auto-injected `getStatus`. Drivers
58935
+ * level})` mutation plus the auto-injected `getStatus`. Drivers
58475
58936
  * that expose richer controls (color temperature, scenes, schedules)
58476
58937
  * should surface those via the device's `getSettingsUISchema()`
58477
58938
  * instead of bloating this cap.
58478
58939
  */
58479
58940
  var BrightnessStatusSchema = object({
58480
58941
  /** Current level as 0..100 inclusive. Firmware-reported. */
58481
- percentage: number().min(0).max(100).meta(readingMeta("percentage")),
58942
+ level: number().min(0).max(100).meta(readingMeta("percentage")),
58482
58943
  /** Ms epoch of the last operator-driven change. Useful for UI freshness. */
58483
58944
  lastChangedAt: number()
58484
58945
  });
@@ -58490,7 +58951,7 @@ var brightnessCapability = {
58490
58951
  deviceTypes: [DeviceType.Light],
58491
58952
  methods: { setBrightness: method(object({
58492
58953
  deviceId: number().int().nonnegative(),
58493
- percentage: number().min(0).max(100)
58954
+ level: number().min(0).max(100)
58494
58955
  }), _void(), {
58495
58956
  kind: "mutation",
58496
58957
  auth: "protected"
@@ -58503,7 +58964,7 @@ var brightnessCapability = {
58503
58964
  */
58504
58965
  onBrightnessChanged: { data: object({
58505
58966
  deviceId: number(),
58506
- percentage: number().min(0).max(100),
58967
+ level: number().min(0).max(100),
58507
58968
  lastChangedAt: number()
58508
58969
  }) } },
58509
58970
  status: {
@@ -58526,7 +58987,7 @@ onBrightnessChanged: { data: object({
58526
58987
  /**
58527
58988
  * History (D850): recorded series. Actuator tier: level keeps every change.
58528
58989
  */
58529
- history: { fields: { percentage: {
58990
+ history: { fields: { level: {
58530
58991
  kind: "gauge",
58531
58992
  unit: "%",
58532
58993
  minIntervalMs: 0
@@ -59123,11 +59584,11 @@ var ColorInputSchema = discriminatedUnion("mode", [
59123
59584
  }),
59124
59585
  object({
59125
59586
  mode: literal("mired"),
59126
- mireds: number().int().min(50).max(1e3)
59587
+ colorTemperature: number().int().min(50).max(1e3)
59127
59588
  })
59128
59589
  ]);
59129
59590
  var ColorStatusSchema = object({
59130
- /** Active color mode — which of `rgb` / `hsv` / `mireds` reflects
59591
+ /** Active color mode — which of `rgb` / `hsv` / `colorTemperature` reflects
59131
59592
  * the bulb's current state. */
59132
59593
  mode: _enum([
59133
59594
  "rgb",
@@ -59139,7 +59600,7 @@ var ColorStatusSchema = object({
59139
59600
  /** Populated when `mode === 'hsv'`. */
59140
59601
  hsv: HsvTripletSchema.optional(),
59141
59602
  /** Populated when `mode === 'mired'`. */
59142
- mireds: number().int().optional().meta(readingMeta("colour-temperature")),
59603
+ colorTemperature: number().int().optional().meta(readingMeta("colour-temperature")),
59143
59604
  /** Ms epoch of the last operator-driven change. */
59144
59605
  lastChangedAt: number()
59145
59606
  });
@@ -59171,7 +59632,7 @@ onColorChanged: { data: object({
59171
59632
  ]),
59172
59633
  rgb: RgbTripletSchema.optional(),
59173
59634
  hsv: HsvTripletSchema.optional(),
59174
- mireds: number().int().optional(),
59635
+ colorTemperature: number().int().optional(),
59175
59636
  lastChangedAt: number()
59176
59637
  }) } },
59177
59638
  status: {
@@ -60056,11 +60517,11 @@ var DishwasherStatusSchema = object({
60056
60517
  /** Feature keys of the programs the appliance currently offers — drives the UI selector. */
60057
60518
  availablePrograms: array(string()),
60058
60519
  /** Seconds remaining on the active cycle, or null when not running / not known. */
60059
- remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
60520
+ remaining: number().int().nonnegative().nullable().meta(readingMeta("duration")),
60060
60521
  /** Seconds the delayed start is set to (time until the cycle starts), or null. */
60061
- delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
60522
+ delayedStart: number().int().nonnegative().nullable().meta(readingMeta("duration")),
60062
60523
  /** Cycle completion 0..100, or null when not applicable. */
60063
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
60524
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
60064
60525
  /** True when the door is reported open; null when the door state is not known. */
60065
60526
  doorOpen: boolean().nullable(),
60066
60527
  /** True when the door is latched (locked) during a cycle; null when not reported. */
@@ -60279,14 +60740,14 @@ var dishwasherCapability = {
60279
60740
  runtimeState: DishwasherStatusSchema,
60280
60741
  durability: "session",
60281
60742
  history: { fields: {
60282
- progressPercent: {
60743
+ progress: {
60283
60744
  kind: "gauge",
60284
60745
  unit: "%",
60285
60746
  deadband: 2
60286
60747
  },
60287
60748
  state: { kind: "enum" },
60288
60749
  operationState: { kind: "enum" },
60289
- remainingSeconds: {
60750
+ remaining: {
60290
60751
  kind: "gauge",
60291
60752
  unit: "s",
60292
60753
  minIntervalMs: 6e4
@@ -60877,7 +61338,7 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
60877
61338
  var FanControlStatusSchema = object({
60878
61339
  /** Active speed as 0..100 inclusive. Null when the device has no
60879
61340
  * speed surface (single-speed fan). */
60880
- percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61341
+ speed: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
60881
61342
  /** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
60882
61343
  * a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
60883
61344
  percentageStep: number().positive().optional().meta(readingMeta("percentage")),
@@ -60904,7 +61365,7 @@ var fanControlCapability = {
60904
61365
  methods: {
60905
61366
  setPercentage: method(object({
60906
61367
  deviceId: number().int().nonnegative(),
60907
- percentage: number().min(0).max(100)
61368
+ speed: number().min(0).max(100)
60908
61369
  }), _void(), {
60909
61370
  kind: "mutation",
60910
61371
  auth: "protected"
@@ -60937,7 +61398,7 @@ var fanControlCapability = {
60937
61398
  },
60938
61399
  /**
60939
61400
  * Runtime-state slice — mirrored by the kernel. UI fan speed
60940
- * sliders read `percentage` for live updates.
61401
+ * sliders read `speed` for live updates.
60941
61402
  */
60942
61403
  runtimeState: FanControlStatusSchema,
60943
61404
  /**
@@ -60951,7 +61412,7 @@ var fanControlCapability = {
60951
61412
  * History (D850): recorded series. Actuator tier: speed keeps every change.
60952
61413
  */
60953
61414
  history: { fields: {
60954
- percentage: {
61415
+ speed: {
60955
61416
  kind: "gauge",
60956
61417
  unit: "%",
60957
61418
  minIntervalMs: 0
@@ -61396,7 +61857,7 @@ var humidifierCapability = {
61396
61857
  */
61397
61858
  var HumiditySensorStatusSchema = object({
61398
61859
  /** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
61399
- percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
61860
+ humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
61400
61861
  precision: 0,
61401
61862
  label: "Humidity"
61402
61863
  })),
@@ -61425,7 +61886,7 @@ var humiditySensorCapability = {
61425
61886
  /**
61426
61887
  * History (D850): recorded series.
61427
61888
  */
61428
- history: { fields: { percent: {
61889
+ history: { fields: { humidity: {
61429
61890
  kind: "gauge",
61430
61891
  unit: "%",
61431
61892
  deadband: .5
@@ -62065,7 +62526,7 @@ var LawnMowerControlStatusSchema = object({
62065
62526
  batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
62066
62527
  /** 0..100 mowing-completion percentage of the current task, or null when no
62067
62528
  * task is active / progress is unavailable. */
62068
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
62529
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
62069
62530
  /** Current device/event code (dynamic — mostly status, sometimes an error),
62070
62531
  * or null when unknown. */
62071
62532
  currentCode: number().nullable().meta(readingMeta("none")),
@@ -62565,7 +63026,7 @@ var lockControlCapability = {
62565
63026
  volatileStateFields: ["lastChangedAt"]
62566
63027
  };
62567
63028
  /**
62568
- * A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
63029
+ * A monotonic total between resets (D944). Energy uses `power-meter.energy`
62569
63030
  * so dashboards keep one series; every other instantaneous reading lands here.
62570
63031
  * `value` is the time integral in the source quantity's accumulated base
62571
63032
  * (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
@@ -62659,10 +63120,10 @@ var MediaPlayerStatusSchema = object({
62659
63120
  currentMedia: MediaInfoSchema.nullable(),
62660
63121
  /** Current playback position in ms. Null when not seekable or
62661
63122
  * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
62662
- positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
63123
+ position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
62663
63124
  /** Total duration of the current media in ms. Null when unknown
62664
63125
  * (live stream) or nothing is playing. */
62665
- durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
63126
+ duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
62666
63127
  /** Shuffle toggle. Null when no shuffle surface.
62667
63128
  * Pair with `DeviceFeature.MediaPlayerShuffle`. */
62668
63129
  shuffle: boolean().nullable(),
@@ -62701,7 +63162,7 @@ var mediaPlayerCapability = {
62701
63162
  }),
62702
63163
  seek: method(object({
62703
63164
  deviceId: number().int().nonnegative(),
62704
- positionMs: number().int().nonnegative()
63165
+ position: number().int().nonnegative()
62705
63166
  }), _void(), {
62706
63167
  kind: "mutation",
62707
63168
  auth: "protected"
@@ -62773,7 +63234,7 @@ var mediaPlayerCapability = {
62773
63234
  /**
62774
63235
  * History (D850): volume (a level an operator or an automation sets; the
62775
63236
  * default 10 s floor folds a slider drag into its end value) and mute.
62776
- * `positionMs` is not recorded: it moves continuously while playing.
63237
+ * `position` is not recorded: it moves continuously while playing.
62777
63238
  */
62778
63239
  history: { fields: {
62779
63240
  volumeLevel: {
@@ -63735,9 +64196,9 @@ var NetworkLinkStatusSchema = object({
63735
64196
  * one whose reading has not landed must not be drawn at 0 %. Consumers
63736
64197
  * SKIP a null rather than coerce it.
63737
64198
  */
63738
- signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64199
+ signal: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
63739
64200
  /** Raw received signal strength in dBm, when the firmware reports one. */
63740
- rssiDbm: number().optional().meta(readingMeta("signal-level")),
64201
+ rssi: number().optional().meta(readingMeta("signal-level")),
63741
64202
  /** Network name of a wireless link, when the firmware reports it. */
63742
64203
  ssid: string().optional(),
63743
64204
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
@@ -63773,7 +64234,7 @@ onStatusChanged: { data: object({
63773
64234
  kind: "push",
63774
64235
  empty: {
63775
64236
  type: "unknown",
63776
- signalPercent: null,
64237
+ signal: null,
63777
64238
  lastUpdated: 0
63778
64239
  }
63779
64240
  },
@@ -63796,13 +64257,13 @@ onStatusChanged: { data: object({
63796
64257
  * History (D850): recorded series.
63797
64258
  */
63798
64259
  history: { fields: {
63799
- signalPercent: {
64260
+ signal: {
63800
64261
  kind: "gauge",
63801
64262
  unit: "%",
63802
64263
  deadband: 3,
63803
64264
  minIntervalMs: 6e4
63804
64265
  },
63805
- rssiDbm: {
64266
+ rssi: {
63806
64267
  kind: "gauge",
63807
64268
  unit: "dBm",
63808
64269
  deadband: 2,
@@ -64547,10 +65008,20 @@ var PetFeederDeviceStatusSchema = _enum([
64547
65008
  ]);
64548
65009
  var gramsPortion = number().int().min(4).max(200);
64549
65010
  var PetFeederStatusSchema = object({
64550
- /** Food currently in the bowl (grams). Null when the device has not
64551
- * reported a reading yet. On dual-hopper models this is the combined
64552
- * bowl reading; per-hopper levels live in `food1`/`food2`. */
65011
+ /** Food in the TANK (hopper), as the feeder's own sensor reports it
65012
+ * (`state.food`). A coarse level code, not grams — `0` is empty. The
65013
+ * amount in the bowl is `bowlFood`. On dual-hopper models this is the
65014
+ * combined reading; per-hopper levels live in `food1`/`food2`. Null when
65015
+ * the device has not reported yet. */
64553
65016
  foodLevel: number().nullable().meta(readingMeta("none")),
65017
+ /** Food in the BOWL as the feeder reports it (`state.bowl`), in the
65018
+ * feeder's own units. Null when the model reports none. */
65019
+ bowlFood: number().nullable().meta(readingMeta("none")),
65020
+ /** True while the pet is eating (`state.eating`). */
65021
+ eating: boolean(),
65022
+ /** Whether `markFoodReplenished` does anything on this model. When false
65023
+ * the client must not offer it. */
65024
+ supportsMarkRefilled: boolean(),
64554
65025
  /** Hopper-1 food level (grams) on dual-hopper feeders; null on
64555
65026
  * single-hopper models. */
64556
65027
  food1: number().nullable().meta(readingMeta("none")),
@@ -64558,8 +65029,8 @@ var PetFeederStatusSchema = object({
64558
65029
  * single-hopper models. */
64559
65030
  food2: number().nullable().meta(readingMeta("none")),
64560
65031
  /** Derived low-food flag — mirrors the HA `food_level` binary_sensor
64561
- * (`device_class: problem`, on = low). True when the bowl is empty /
64562
- * below the feeder's low threshold. */
65032
+ * (`device_class: problem`, on = low). True when the tank reports empty,
65033
+ * or, on a dual-hopper model, when EITHER hopper is empty. */
64563
65034
  lowFood: boolean(),
64564
65035
  /** Battery charge 0..100 (%). Null on mains-powered models or when the
64565
65036
  * device has no battery reading. */
@@ -64627,7 +65098,9 @@ var petFeederCapability = {
64627
65098
  kind: "mutation",
64628
65099
  auth: "protected"
64629
65100
  }),
64630
- /** Mark a hopper as refilled (D4H/D4S/D4SH). */
65101
+ /** Tell the PetKit cloud a hopper was refilled so it stops its low-food
65102
+ * reminders (D4H/D4S/D4SH only — see `supportsMarkRefilled`). It does not
65103
+ * change any sensor reading. */
64631
65104
  markFoodReplenished: method(object({ deviceId: number().int().nonnegative() }), _void(), {
64632
65105
  kind: "mutation",
64633
65106
  auth: "protected"
@@ -64700,6 +65173,7 @@ var petFeederCapability = {
64700
65173
  */
64701
65174
  history: { fields: {
64702
65175
  foodLevel: { kind: "gauge" },
65176
+ bowlFood: { kind: "gauge" },
64703
65177
  food1: { kind: "gauge" },
64704
65178
  food2: { kind: "gauge" },
64705
65179
  batteryPower: {
@@ -65109,16 +65583,16 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
65109
65583
  * in real-world devices.
65110
65584
  */
65111
65585
  var PowerMeterStatusSchema = object({
65112
- /** Instantaneous power draw in watts. */
65113
- watts: number().optional().meta(readingMeta("power", { label: "Power" })),
65586
+ /** Instantaneous power draw (watts). */
65587
+ power: number().optional().meta(readingMeta("power", { label: "Power" })),
65114
65588
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
65115
- kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
65116
- /** Voltage in volts. */
65117
- volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
65589
+ energy: number().optional().meta(readingMeta("energy", { label: "Energy" })),
65590
+ /** Voltage (volts). */
65591
+ voltage: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
65118
65592
  /** Current in amperes. */
65119
- amps: number().optional().meta(readingMeta("current", { label: "Current" })),
65593
+ current: number().optional().meta(readingMeta("current", { label: "Current" })),
65120
65594
  /** Apparent power in volt-amperes. */
65121
- va: number().optional().meta(readingMeta("apparent-power")),
65595
+ apparentPower: number().optional().meta(readingMeta("apparent-power")),
65122
65596
  /** Power factor (0..1) if reported. */
65123
65597
  powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
65124
65598
  /** Ms epoch when the slice was last updated. */
@@ -65176,14 +65650,14 @@ function powerTarget(id, unit) {
65176
65650
  advancedExpression: true
65177
65651
  };
65178
65652
  }
65179
- /** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
65653
+ /** "Power and energy" extension: power, energy, voltage and current from other devices (D951). */
65180
65654
  var powerMeterCustomize = {
65181
65655
  version: 1,
65182
65656
  targets: [
65183
- powerTarget("watts", "W"),
65184
- powerTarget("kwhTotal", "kWh"),
65185
- powerTarget("volts", "V"),
65186
- powerTarget("amps", "A")
65657
+ powerTarget("power", "W"),
65658
+ powerTarget("energy", "kWh"),
65659
+ powerTarget("voltage", "V"),
65660
+ powerTarget("current", "A")
65187
65661
  ]
65188
65662
  };
65189
65663
  var powerMeterCapability = {
@@ -65199,41 +65673,41 @@ var powerMeterCapability = {
65199
65673
  },
65200
65674
  runtimeState: PowerMeterStatusSchema,
65201
65675
  /**
65202
- * Runtime-state durability: **restored** — as `numeric-sensor`; `kwhTotal` is an accumulator whose restored value is the baseline.
65676
+ * Runtime-state durability: **restored** — as `numeric-sensor`; `energy` is an accumulator whose restored value is the baseline.
65203
65677
  *
65204
65678
  * See `RuntimeStateDurability`. Enforced by
65205
65679
  * `scripts/check-runtime-state-durability.ts`.
65206
65680
  */
65207
65681
  durability: "restored",
65208
65682
  /**
65209
- * History (D850): recorded series. Gauges are floored at 30 s; `kwhTotal` is the one monotonic meter (counter).
65683
+ * History (D850): recorded series. Gauges are floored at 30 s; `energy` is the one monotonic meter (counter).
65210
65684
  */
65211
65685
  history: { fields: {
65212
- watts: {
65686
+ power: {
65213
65687
  kind: "gauge",
65214
65688
  unit: "W",
65215
65689
  deadband: 1,
65216
65690
  minIntervalMs: 3e4
65217
65691
  },
65218
- kwhTotal: {
65692
+ energy: {
65219
65693
  kind: "counter",
65220
65694
  unit: "kWh",
65221
65695
  deadband: .01,
65222
65696
  minIntervalMs: 6e4
65223
65697
  },
65224
- volts: {
65698
+ voltage: {
65225
65699
  kind: "gauge",
65226
65700
  unit: "V",
65227
65701
  deadband: 1,
65228
65702
  minIntervalMs: 3e4
65229
65703
  },
65230
- amps: {
65704
+ current: {
65231
65705
  kind: "gauge",
65232
65706
  unit: "A",
65233
65707
  deadband: .05,
65234
65708
  minIntervalMs: 3e4
65235
65709
  },
65236
- va: {
65710
+ apparentPower: {
65237
65711
  kind: "gauge",
65238
65712
  unit: "VA",
65239
65713
  deadband: 1,
@@ -65283,9 +65757,6 @@ var PresenceStatusSchema = object({
65283
65757
  location: string().nullable(),
65284
65758
  /** GPS coordinates when available. Null otherwise. */
65285
65759
  gps: GpsLocationSchema.nullable(),
65286
- /** Optional battery level of the tracking device (0..100). Null
65287
- * when not reported. */
65288
- batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
65289
65760
  /** Ms epoch when the slice was last updated. */
65290
65761
  lastChangedAt: number()
65291
65762
  });
@@ -65314,14 +65785,7 @@ var presenceCapability = {
65314
65785
  * `scripts/check-runtime-state-durability.ts`.
65315
65786
  */
65316
65787
  durability: "restored",
65317
- /**
65318
- * History (D850): recorded series.
65319
- */
65320
- history: { fields: { batteryPercent: {
65321
- kind: "gauge",
65322
- unit: "%",
65323
- deadband: 1
65324
- } } },
65788
+ history: "none",
65325
65789
  /** Clock fields: written, but excluded from the compare that decides
65326
65790
  * whether persisting is worth a SQLite commit. */
65327
65791
  volatileStateFields: ["lastChangedAt"]
@@ -65336,7 +65800,7 @@ var presenceCapability = {
65336
65800
  */
65337
65801
  var PressureSensorStatusSchema = object({
65338
65802
  /** Current pressure in hPa. `null` when the sample was refused (D393). */
65339
- hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
65803
+ pressure: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
65340
65804
  /** Ms epoch when the slice was last updated. */
65341
65805
  lastFetchedAt: number()
65342
65806
  });
@@ -65362,7 +65826,7 @@ var pressureSensorCapability = {
65362
65826
  /**
65363
65827
  * History (D850): recorded series.
65364
65828
  */
65365
- history: { fields: { hpa: {
65829
+ history: { fields: { pressure: {
65366
65830
  kind: "gauge",
65367
65831
  unit: "hPa",
65368
65832
  deadband: .1
@@ -69061,7 +69525,7 @@ var tamperCapability = {
69061
69525
  */
69062
69526
  var TemperatureSensorStatusSchema = object({
69063
69527
  /** Current temperature in Celsius. `null` when the sample was refused (D393). */
69064
- celsius: number().nullable().meta(readingMeta("temperature", {
69528
+ temperature: number().nullable().meta(readingMeta("temperature", {
69065
69529
  precision: 1,
69066
69530
  label: "Temperature"
69067
69531
  })),
@@ -69090,7 +69554,7 @@ var temperatureSensorCapability = {
69090
69554
  /**
69091
69555
  * History (D850): recorded series.
69092
69556
  */
69093
- history: { fields: { celsius: {
69557
+ history: { fields: { temperature: {
69094
69558
  kind: "gauge",
69095
69559
  unit: "°C",
69096
69560
  deadband: .1
@@ -69387,7 +69851,7 @@ var VacuumControlStatusSchema = object({
69387
69851
  /** Speed tokens the hardware accepts — drives the UI selector. */
69388
69852
  availableFanSpeeds: array(string()),
69389
69853
  /** 0..100 cleaning-completion percentage of the current task, or null. */
69390
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
69854
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
69391
69855
  /** Current error code (0 / null = no error). */
69392
69856
  errorCode: number().nullable().meta(readingMeta("none")),
69393
69857
  /** Human label for {@link errorCode}, or null when none / undecodable. */
@@ -71041,7 +71505,7 @@ var BaseDevice = class {
71041
71505
  * `device-local-state.ts`. Drivers access via:
71042
71506
  *
71043
71507
  * `this.state.battery.sleeping = true` // patches the battery slice
71044
- * `const pct = this.state.battery.percentage` // reads the battery slice
71508
+ * `const pct = this.state.battery.level` // reads the battery slice
71045
71509
  * `this.state.deviceStatus.online = true` // mirrors `markOnline(true)`
71046
71510
  *
71047
71511
  * Adding a new cap with `runtimeState:` automatically extends this
@@ -71081,7 +71545,7 @@ var BaseDevice = class {
71081
71545
  * shape; drivers don't redeclare it, they just write through.
71082
71546
  *
71083
71547
  * Read: `this.runtimeState.getCapState('battery')` →
71084
- * `{percentage, charging, sleeping, lastUpdated}` for any
71548
+ * `{level, charging, sleeping, lastUpdated}` for any
71085
71549
  * provider that registers `batteryCapability`.
71086
71550
  * Write: `this.runtimeState.setCapState('battery', { … })`.
71087
71551
  *
@@ -72255,6 +72719,104 @@ Object.freeze({
72255
72719
  access: "create",
72256
72720
  role: "admin"
72257
72721
  },
72722
+ "actions.create": {
72723
+ capName: "actions",
72724
+ capScope: "system",
72725
+ addonId: null,
72726
+ access: "create",
72727
+ role: "admin"
72728
+ },
72729
+ "actions.delete": {
72730
+ capName: "actions",
72731
+ capScope: "system",
72732
+ addonId: null,
72733
+ access: "delete",
72734
+ role: "admin"
72735
+ },
72736
+ "actions.get": {
72737
+ capName: "actions",
72738
+ capScope: "system",
72739
+ addonId: null,
72740
+ access: "view",
72741
+ role: "viewer"
72742
+ },
72743
+ "actions.getLinks": {
72744
+ capName: "actions",
72745
+ capScope: "system",
72746
+ addonId: null,
72747
+ access: "view",
72748
+ role: "admin"
72749
+ },
72750
+ "actions.getTraces": {
72751
+ capName: "actions",
72752
+ capScope: "system",
72753
+ addonId: null,
72754
+ access: "view",
72755
+ role: "admin"
72756
+ },
72757
+ "actions.list": {
72758
+ capName: "actions",
72759
+ capScope: "system",
72760
+ addonId: null,
72761
+ access: "view",
72762
+ role: "admin"
72763
+ },
72764
+ "actions.listForCamera": {
72765
+ capName: "actions",
72766
+ capScope: "system",
72767
+ addonId: null,
72768
+ access: "view",
72769
+ role: "viewer"
72770
+ },
72771
+ "actions.run": {
72772
+ capName: "actions",
72773
+ capScope: "system",
72774
+ addonId: null,
72775
+ access: "create",
72776
+ role: "viewer"
72777
+ },
72778
+ "actions.setLinks": {
72779
+ capName: "actions",
72780
+ capScope: "system",
72781
+ addonId: null,
72782
+ access: "create",
72783
+ role: "admin"
72784
+ },
72785
+ "actions.stop": {
72786
+ capName: "actions",
72787
+ capScope: "system",
72788
+ addonId: null,
72789
+ access: "create",
72790
+ role: "admin"
72791
+ },
72792
+ "actions.update": {
72793
+ capName: "actions",
72794
+ capScope: "system",
72795
+ addonId: null,
72796
+ access: "create",
72797
+ role: "admin"
72798
+ },
72799
+ "actionSource.listActions": {
72800
+ capName: "action-source",
72801
+ capScope: "system",
72802
+ addonId: null,
72803
+ access: "view",
72804
+ role: "admin"
72805
+ },
72806
+ "actionSource.runAction": {
72807
+ capName: "action-source",
72808
+ capScope: "system",
72809
+ addonId: null,
72810
+ access: "create",
72811
+ role: "admin"
72812
+ },
72813
+ "actionSource.stopAction": {
72814
+ capName: "action-source",
72815
+ capScope: "system",
72816
+ addonId: null,
72817
+ access: "create",
72818
+ role: "admin"
72819
+ },
72258
72820
  "addonPages.listPages": {
72259
72821
  capName: "addon-pages",
72260
72822
  capScope: "system",
@@ -73536,6 +74098,13 @@ Object.freeze({
73536
74098
  access: "view",
73537
74099
  role: "admin"
73538
74100
  },
74101
+ "coreBlocks.getAutomationRunState": {
74102
+ capName: "core-blocks",
74103
+ capScope: "system",
74104
+ addonId: null,
74105
+ access: "view",
74106
+ role: "admin"
74107
+ },
73539
74108
  "coreBlocks.getBlockSettings": {
73540
74109
  capName: "core-blocks",
73541
74110
  capScope: "system",
@@ -73557,6 +74126,13 @@ Object.freeze({
73557
74126
  access: "view",
73558
74127
  role: "admin"
73559
74128
  },
74129
+ "coreBlocks.getTraces": {
74130
+ capName: "core-blocks",
74131
+ capScope: "system",
74132
+ addonId: null,
74133
+ access: "view",
74134
+ role: "admin"
74135
+ },
73560
74136
  "coreBlocks.getTypeDefs": {
73561
74137
  capName: "core-blocks",
73562
74138
  capScope: "system",
@@ -73592,6 +74168,13 @@ Object.freeze({
73592
74168
  access: "create",
73593
74169
  role: "admin"
73594
74170
  },
74171
+ "coreBlocks.reportAutomationRun": {
74172
+ capName: "core-blocks",
74173
+ capScope: "system",
74174
+ addonId: null,
74175
+ access: "create",
74176
+ role: "admin"
74177
+ },
73595
74178
  "coreBlocks.restart": {
73596
74179
  capName: "core-blocks",
73597
74180
  capScope: "system",
@@ -82165,7 +82748,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82165
82748
  label: t("Full brightness", "Luminosità massima"),
82166
82749
  phrase: t("Set {device} to full brightness", "Porta {device} alla massima luminosità"),
82167
82750
  icon: "sun",
82168
- args: { percentage: 100 }
82751
+ args: { level: 100 }
82169
82752
  },
82170
82753
  {
82171
82754
  id: "brightness.half",
@@ -82173,7 +82756,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82173
82756
  label: t("Half brightness", "Luminosità a metà"),
82174
82757
  phrase: t("Dim {device} to half", "Abbassa {device} a metà luminosità"),
82175
82758
  icon: "sun-dim",
82176
- args: { percentage: 50 }
82759
+ args: { level: 50 }
82177
82760
  },
82178
82761
  {
82179
82762
  id: "brightness.off",
@@ -82181,16 +82764,16 @@ var ACTUATOR_CAP_VOCABULARY = {
82181
82764
  label: t("Brightness off", "Luminosità a zero"),
82182
82765
  phrase: t("Dim {device} to zero", "Abbassa {device} a zero"),
82183
82766
  icon: "lightbulb-off",
82184
- args: { percentage: 0 }
82767
+ args: { level: 0 }
82185
82768
  },
82186
82769
  {
82187
82770
  id: "brightness.set",
82188
82771
  method: "setBrightness",
82189
82772
  label: t("Set brightness", "Imposta la luminosità"),
82190
- phrase: t("Set the brightness of {device} to {percentage}", "Imposta la luminosità di {device} a {percentage}"),
82773
+ phrase: t("Set the brightness of {device} to {level}", "Imposta la luminosità di {device} a {level}"),
82191
82774
  icon: "sun-medium",
82192
82775
  openArgs: [{
82193
- key: "percentage",
82776
+ key: "level",
82194
82777
  label: PERCENT,
82195
82778
  offer: {
82196
82779
  kind: "number",
@@ -82204,13 +82787,13 @@ var ACTUATOR_CAP_VOCABULARY = {
82204
82787
  ],
82205
82788
  state: [{
82206
82789
  kind: "numeric",
82207
- field: "percentage",
82790
+ field: "level",
82208
82791
  quantity: t("the brightness", "la luminosità"),
82209
82792
  label: t("Brightness", "Luminosità"),
82210
82793
  unit: "%",
82211
82794
  icon: "sun"
82212
82795
  }],
82213
- events: { onBrightnessChanged: { notOperatorFacing: "the `percentage` state trigger reads the same change" } }
82796
+ events: { onBrightnessChanged: { notOperatorFacing: "the `level` state trigger reads the same change" } }
82214
82797
  },
82215
82798
  color: {
82216
82799
  scope: "device",
@@ -82224,7 +82807,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82224
82807
  icon: "sun",
82225
82808
  args: { color: {
82226
82809
  mode: "mired",
82227
- mireds: 370
82810
+ colorTemperature: 370
82228
82811
  } }
82229
82812
  },
82230
82813
  {
@@ -82235,7 +82818,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82235
82818
  icon: "snowflake",
82236
82819
  args: { color: {
82237
82820
  mode: "mired",
82238
- mireds: 200
82821
+ colorTemperature: 200
82239
82822
  } }
82240
82823
  },
82241
82824
  {
@@ -82849,7 +83432,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82849
83432
  label: t("Fan off", "Ventilatore spento"),
82850
83433
  phrase: t("Stop {device}", "Ferma {device}"),
82851
83434
  icon: "power-off",
82852
- args: { percentage: 0 }
83435
+ args: { speed: 0 }
82853
83436
  },
82854
83437
  {
82855
83438
  id: "fan.full",
@@ -82857,16 +83440,16 @@ var ACTUATOR_CAP_VOCABULARY = {
82857
83440
  label: t("Fan full", "Ventilatore al massimo"),
82858
83441
  phrase: t("Run {device} at full speed", "Porta {device} alla massima velocità"),
82859
83442
  icon: "fan",
82860
- args: { percentage: 100 }
83443
+ args: { speed: 100 }
82861
83444
  },
82862
83445
  {
82863
83446
  id: "fan.speed",
82864
83447
  method: "setPercentage",
82865
83448
  label: t("Set speed", "Imposta la velocità"),
82866
- phrase: t("Set the speed of {device} to {percentage}", "Imposta la velocità di {device} al {percentage}"),
83449
+ phrase: t("Set the speed of {device} to {speed}", "Imposta la velocità di {device} al {speed}"),
82867
83450
  icon: "fan",
82868
83451
  openArgs: [{
82869
- key: "percentage",
83452
+ key: "speed",
82870
83453
  label: t("Speed", "Velocità"),
82871
83454
  offer: {
82872
83455
  kind: "number",
@@ -82928,7 +83511,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82928
83511
  ],
82929
83512
  state: [{
82930
83513
  kind: "numeric",
82931
- field: "percentage",
83514
+ field: "speed",
82932
83515
  quantity: t("the speed", "la velocità"),
82933
83516
  label: t("Speed", "Velocità"),
82934
83517
  unit: "%",
@@ -83726,7 +84309,7 @@ var APPLIANCE_CAP_VOCABULARY = {
83726
84309
  },
83727
84310
  {
83728
84311
  kind: "numeric",
83729
- field: "progressPercent",
84312
+ field: "progress",
83730
84313
  quantity: t("the cycle progress", "l’avanzamento del lavaggio"),
83731
84314
  label: t("Progress", "Avanzamento"),
83732
84315
  unit: "%",
@@ -84084,10 +84667,10 @@ var APPLIANCE_CAP_VOCABULARY = {
84084
84667
  id: "media.seek",
84085
84668
  method: "seek",
84086
84669
  label: t("Seek", "Vai al punto"),
84087
- phrase: t("Move {device} to {positionMs}", "Porta {device} al punto {positionMs}"),
84670
+ phrase: t("Move {device} to {position}", "Porta {device} al punto {position}"),
84088
84671
  icon: "fast-forward",
84089
84672
  openArgs: [{
84090
- key: "positionMs",
84673
+ key: "position",
84091
84674
  label: t("Position", "Posizione"),
84092
84675
  offer: {
84093
84676
  kind: "number",
@@ -85136,7 +85719,7 @@ var SENSOR_CAP_VOCABULARY = {
85136
85719
  state: [
85137
85720
  {
85138
85721
  kind: "numeric",
85139
- field: "co2Ppm",
85722
+ field: "co2",
85140
85723
  quantity: t("the CO₂", "la CO₂"),
85141
85724
  label: t("CO₂", "CO₂"),
85142
85725
  unit: "ppm",
@@ -85144,7 +85727,7 @@ var SENSOR_CAP_VOCABULARY = {
85144
85727
  },
85145
85728
  {
85146
85729
  kind: "numeric",
85147
- field: "vocPpb",
85730
+ field: "voc",
85148
85731
  quantity: t("the VOC level", "il livello di COV"),
85149
85732
  label: t("VOC", "COV"),
85150
85733
  unit: "ppb",
@@ -85180,7 +85763,7 @@ var SENSOR_CAP_VOCABULARY = {
85180
85763
  noun: t("Light level", "Luminosità ambiente"),
85181
85764
  state: [{
85182
85765
  kind: "numeric",
85183
- field: "lux",
85766
+ field: "illuminance",
85184
85767
  quantity: t("the light level", "la luminosità"),
85185
85768
  label: t("Illuminance", "Illuminamento"),
85186
85769
  unit: "lx",
@@ -85383,7 +85966,7 @@ var SENSOR_CAP_VOCABULARY = {
85383
85966
  noun: t("Humidity", "Umidità"),
85384
85967
  state: [{
85385
85968
  kind: "numeric",
85386
- field: "percent",
85969
+ field: "humidity",
85387
85970
  quantity: t("the humidity", "l’umidità"),
85388
85971
  label: t("Humidity", "Umidità"),
85389
85972
  unit: "%",
@@ -85431,7 +86014,7 @@ var SENSOR_CAP_VOCABULARY = {
85431
86014
  state: [
85432
86015
  {
85433
86016
  kind: "numeric",
85434
- field: "watts",
86017
+ field: "power",
85435
86018
  quantity: t("the power draw", "il consumo"),
85436
86019
  label: t("Power", "Potenza"),
85437
86020
  unit: "W",
@@ -85439,7 +86022,7 @@ var SENSOR_CAP_VOCABULARY = {
85439
86022
  },
85440
86023
  {
85441
86024
  kind: "numeric",
85442
- field: "kwhTotal",
86025
+ field: "energy",
85443
86026
  quantity: t("the energy used", "l’energia consumata"),
85444
86027
  label: t("Energy", "Energia"),
85445
86028
  unit: "kWh",
@@ -85447,7 +86030,7 @@ var SENSOR_CAP_VOCABULARY = {
85447
86030
  },
85448
86031
  {
85449
86032
  kind: "numeric",
85450
- field: "volts",
86033
+ field: "voltage",
85451
86034
  quantity: t("the voltage", "la tensione"),
85452
86035
  label: t("Voltage", "Tensione"),
85453
86036
  unit: "V",
@@ -85455,7 +86038,7 @@ var SENSOR_CAP_VOCABULARY = {
85455
86038
  },
85456
86039
  {
85457
86040
  kind: "numeric",
85458
- field: "amps",
86041
+ field: "current",
85459
86042
  quantity: t("the current", "la corrente"),
85460
86043
  label: t("Current", "Corrente"),
85461
86044
  unit: "A",
@@ -85472,13 +86055,6 @@ var SENSOR_CAP_VOCABULARY = {
85472
86055
  label: t("Where", "Posizione"),
85473
86056
  phrase: t("When {device} is at {value}", "Quando {device} è in {value}"),
85474
86057
  icon: "map-pin"
85475
- }, {
85476
- kind: "numeric",
85477
- field: "batteryPercent",
85478
- quantity: t("the phone battery", "la batteria del telefono"),
85479
- label: t("Battery", "Batteria"),
85480
- unit: "%",
85481
- icon: "battery"
85482
86058
  }]
85483
86059
  },
85484
86060
  "pressure-sensor": {
@@ -85486,7 +86062,7 @@ var SENSOR_CAP_VOCABULARY = {
85486
86062
  noun: t("Pressure", "Pressione"),
85487
86063
  state: [{
85488
86064
  kind: "numeric",
85489
- field: "hpa",
86065
+ field: "pressure",
85490
86066
  quantity: t("the pressure", "la pressione"),
85491
86067
  label: t("Pressure", "Pressione"),
85492
86068
  unit: "hPa",
@@ -85522,7 +86098,7 @@ var SENSOR_CAP_VOCABULARY = {
85522
86098
  noun: t("Temperature", "Temperatura"),
85523
86099
  state: [{
85524
86100
  kind: "numeric",
85525
- field: "celsius",
86101
+ field: "temperature",
85526
86102
  quantity: t("the temperature", "la temperatura"),
85527
86103
  label: t("Temperature", "Temperatura"),
85528
86104
  unit: "°C",
@@ -85593,7 +86169,7 @@ var SENSOR_CAP_VOCABULARY = {
85593
86169
  state: [
85594
86170
  {
85595
86171
  kind: "numeric",
85596
- field: "percentage",
86172
+ field: "level",
85597
86173
  quantity: t("the battery level", "il livello della batteria"),
85598
86174
  label: t("Battery", "Batteria"),
85599
86175
  unit: "%",
@@ -85635,7 +86211,7 @@ var SENSOR_CAP_VOCABULARY = {
85635
86211
  icon: "battery-charging"
85636
86212
  }
85637
86213
  ],
85638
- events: { onStatusChanged: { notOperatorFacing: "the percentage / sleeping / charging state triggers each read one field of this change" } },
86214
+ events: { onStatusChanged: { notOperatorFacing: "the level / sleeping / charging state triggers each read one field of this change" } },
85639
86215
  extraEvents: [{
85640
86216
  category: EventCategory.DeviceAwake,
85641
86217
  label: t("Woke up", "Risvegliato"),
@@ -85653,7 +86229,7 @@ var SENSOR_CAP_VOCABULARY = {
85653
86229
  noun: t("Network link", "Collegamento di rete"),
85654
86230
  state: [{
85655
86231
  kind: "numeric",
85656
- field: "signalPercent",
86232
+ field: "signal",
85657
86233
  quantity: t("the signal strength", "l’intensità del segnale"),
85658
86234
  label: t("Signal", "Segnale"),
85659
86235
  unit: "%",
@@ -85746,6 +86322,8 @@ var ML = "model and training machinery — no device action";
85746
86322
  var INTERNAL = "internal plumbing between addons — never operator-facing";
85747
86323
  /** Every system-scoped cap, with why it is not a device's vocabulary. */
85748
86324
  var SYSTEM_CAP_VOCABULARY = {
86325
+ "action-source": system(INTERNAL),
86326
+ actions: system("declared actions — run from the Actions page and from the cameras that link them"),
85749
86327
  "addon-pages": system(UI_PLUMBING),
85750
86328
  "addon-pages-source": system(UI_PLUMBING),
85751
86329
  "addon-routes": system(UI_PLUMBING),
@@ -85942,6 +86520,31 @@ Object.freeze({
85942
86520
  form: "single",
85943
86521
  optional: false
85944
86522
  }],
86523
+ "actions.get": [{
86524
+ name: "deviceId",
86525
+ form: "single",
86526
+ optional: true
86527
+ }],
86528
+ "actions.getLinks": [{
86529
+ name: "deviceId",
86530
+ form: "single",
86531
+ optional: false
86532
+ }],
86533
+ "actions.listForCamera": [{
86534
+ name: "deviceId",
86535
+ form: "single",
86536
+ optional: false
86537
+ }],
86538
+ "actions.run": [{
86539
+ name: "deviceId",
86540
+ form: "single",
86541
+ optional: true
86542
+ }],
86543
+ "actions.setLinks": [{
86544
+ name: "deviceId",
86545
+ form: "single",
86546
+ optional: false
86547
+ }],
85945
86548
  "addonSettings.getDeviceSettings": [{
85946
86549
  name: "deviceId",
85947
86550
  form: "single",
@@ -90023,6 +90626,7 @@ DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
90023
90626
  DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
90024
90627
  DEFAULT_NATIVE_LEASE_SETTINGS.sceneBudgetMb;
90025
90628
  DEFAULT_NATIVE_LEASE_SETTINGS.admission;
90629
+ String.raw`(?<=^|["'(\s>,\[{])`;
90026
90630
  var MB = 1024 * 1024;
90027
90631
  1024 * MB, 3072 * MB;
90028
90632
  //#endregion
@@ -90734,7 +91338,7 @@ var TuyaTemperatureSensorDevice = class extends TuyaChildDevice {
90734
91338
  }
90735
91339
  #slice(celsius) {
90736
91340
  return {
90737
- celsius,
91341
+ temperature: celsius,
90738
91342
  lastFetchedAt: Date.now()
90739
91343
  };
90740
91344
  }
@@ -90746,7 +91350,7 @@ var TuyaTemperatureSensorDevice = class extends TuyaChildDevice {
90746
91350
  recomputeSlice() {
90747
91351
  const celsius = this.#read();
90748
91352
  if (celsius === null) return;
90749
- if (this.runtimeState.getCapState(CAP_NAME$1)?.celsius === celsius) return;
91353
+ if (this.runtimeState.getCapState(CAP_NAME$1)?.temperature === celsius) return;
90750
91354
  this.runtimeState.setCapState(CAP_NAME$1, this.#slice(celsius));
90751
91355
  }
90752
91356
  };