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