@camstack/addon-provider-enpal 0.1.2 → 0.1.4

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
@@ -1,4 +1,4 @@
1
- //#region ../types/dist/event-category-CT-hz5Rb.mjs
1
+ //#region ../types/dist/event-category-DmZDPDf_.mjs
2
2
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
3
3
  EventCategory["SystemBoot"] = "system.boot";
4
4
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -625,7 +625,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
625
625
  * (a track was promoted to a stationary-registry entry) or departs (the
626
626
  * object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
627
627
  * the dedicated "Stationary" section — never the live event feed. Payload:
628
- * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp }`.
628
+ * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp, observedAt, zones }`.
629
629
  */
630
630
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
631
631
  /**
@@ -763,6 +763,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
763
763
  */
764
764
  EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
765
765
  /**
766
+ * An action run started or ended. Emitted by the `actions` surface.
767
+ * Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
768
+ */
769
+ EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
770
+ /**
766
771
  * Progress update from a running model conversion job.
767
772
  * Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
768
773
  * Emitted by `addon-model-studio` on the converting node.
@@ -5441,7 +5446,7 @@ var ZodIssueCode = {
5441
5446
  var ZodFirstPartyTypeKind;
5442
5447
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5443
5448
  //#endregion
5444
- //#region ../types/dist/sleep--jXS9hWo.mjs
5449
+ //#region ../types/dist/sleep-Crlmu_tO.mjs
5445
5450
  /**
5446
5451
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5447
5452
  * window to float samples (D455).
@@ -8565,6 +8570,8 @@ Object.freeze({ "doorbell": "lastPressedAt" });
8565
8570
  /** Every capability name, so addon code can check a name without the schema graph. */
8566
8571
  var CAP_NAMES = Object.freeze([
8567
8572
  "accessories",
8573
+ "action-source",
8574
+ "actions",
8568
8575
  "addon-pages",
8569
8576
  "addon-pages-source",
8570
8577
  "addon-routes",
@@ -8753,11 +8760,11 @@ var CAP_NAMES = Object.freeze([
8753
8760
  Object.freeze({
8754
8761
  "air-quality-sensor": [
8755
8762
  {
8756
- "path": "co2Ppm",
8763
+ "path": "co2",
8757
8764
  "valueType": "number"
8758
8765
  },
8759
8766
  {
8760
- "path": "vocPpb",
8767
+ "path": "voc",
8761
8768
  "valueType": "number"
8762
8769
  },
8763
8770
  {
@@ -8807,7 +8814,7 @@ Object.freeze({
8807
8814
  }
8808
8815
  ],
8809
8816
  "ambient-light-sensor": [{
8810
- "path": "lux",
8817
+ "path": "illuminance",
8811
8818
  "valueType": "number"
8812
8819
  }],
8813
8820
  "audio-metrics": [
@@ -8868,7 +8875,7 @@ Object.freeze({
8868
8875
  ],
8869
8876
  "battery": [
8870
8877
  {
8871
- "path": "percentage",
8878
+ "path": "level",
8872
8879
  "valueType": "number"
8873
8880
  },
8874
8881
  {
@@ -8890,7 +8897,7 @@ Object.freeze({
8890
8897
  "valueType": "number"
8891
8898
  },
8892
8899
  {
8893
- "path": "volts",
8900
+ "path": "voltage",
8894
8901
  "valueType": "number"
8895
8902
  },
8896
8903
  {
@@ -8911,7 +8918,7 @@ Object.freeze({
8911
8918
  "valueType": "boolean"
8912
8919
  }],
8913
8920
  "brightness": [{
8914
- "path": "percentage",
8921
+ "path": "level",
8915
8922
  "valueType": "number"
8916
8923
  }],
8917
8924
  "broker": [{
@@ -9112,7 +9119,7 @@ Object.freeze({
9112
9119
  "valueType": "number"
9113
9120
  },
9114
9121
  {
9115
- "path": "mireds",
9122
+ "path": "colorTemperature",
9116
9123
  "valueType": "number"
9117
9124
  }
9118
9125
  ],
@@ -9291,15 +9298,15 @@ Object.freeze({
9291
9298
  "valueType": "string"
9292
9299
  },
9293
9300
  {
9294
- "path": "remainingSeconds",
9301
+ "path": "remaining",
9295
9302
  "valueType": "number"
9296
9303
  },
9297
9304
  {
9298
- "path": "delayedStartSeconds",
9305
+ "path": "delayedStart",
9299
9306
  "valueType": "number"
9300
9307
  },
9301
9308
  {
9302
- "path": "progressPercent",
9309
+ "path": "progress",
9303
9310
  "valueType": "number"
9304
9311
  },
9305
9312
  {
@@ -9413,7 +9420,7 @@ Object.freeze({
9413
9420
  ],
9414
9421
  "fan-control": [
9415
9422
  {
9416
- "path": "percentage",
9423
+ "path": "speed",
9417
9424
  "valueType": "number"
9418
9425
  },
9419
9426
  {
@@ -9513,7 +9520,7 @@ Object.freeze({
9513
9520
  }
9514
9521
  ],
9515
9522
  "humidity-sensor": [{
9516
- "path": "percent",
9523
+ "path": "humidity",
9517
9524
  "valueType": "number"
9518
9525
  }],
9519
9526
  "image": [{
@@ -9623,7 +9630,7 @@ Object.freeze({
9623
9630
  "valueType": "number"
9624
9631
  },
9625
9632
  {
9626
- "path": "progressPercent",
9633
+ "path": "progress",
9627
9634
  "valueType": "number"
9628
9635
  },
9629
9636
  {
@@ -9702,11 +9709,11 @@ Object.freeze({
9702
9709
  "valueType": "string"
9703
9710
  },
9704
9711
  {
9705
- "path": "positionMs",
9712
+ "path": "position",
9706
9713
  "valueType": "number"
9707
9714
  },
9708
9715
  {
9709
- "path": "durationMs",
9716
+ "path": "duration",
9710
9717
  "valueType": "number"
9711
9718
  },
9712
9719
  {
@@ -9808,11 +9815,11 @@ Object.freeze({
9808
9815
  ]
9809
9816
  },
9810
9817
  {
9811
- "path": "signalPercent",
9818
+ "path": "signal",
9812
9819
  "valueType": "number"
9813
9820
  },
9814
9821
  {
9815
- "path": "rssiDbm",
9822
+ "path": "rssi",
9816
9823
  "valueType": "number"
9817
9824
  },
9818
9825
  {
@@ -9867,6 +9874,18 @@ Object.freeze({
9867
9874
  "path": "foodLevel",
9868
9875
  "valueType": "number"
9869
9876
  },
9877
+ {
9878
+ "path": "bowlFood",
9879
+ "valueType": "number"
9880
+ },
9881
+ {
9882
+ "path": "eating",
9883
+ "valueType": "boolean"
9884
+ },
9885
+ {
9886
+ "path": "supportsMarkRefilled",
9887
+ "valueType": "boolean"
9888
+ },
9870
9889
  {
9871
9890
  "path": "food1",
9872
9891
  "valueType": "number"
@@ -9931,23 +9950,23 @@ Object.freeze({
9931
9950
  ],
9932
9951
  "power-meter": [
9933
9952
  {
9934
- "path": "watts",
9953
+ "path": "power",
9935
9954
  "valueType": "number"
9936
9955
  },
9937
9956
  {
9938
- "path": "kwhTotal",
9957
+ "path": "energy",
9939
9958
  "valueType": "number"
9940
9959
  },
9941
9960
  {
9942
- "path": "volts",
9961
+ "path": "voltage",
9943
9962
  "valueType": "number"
9944
9963
  },
9945
9964
  {
9946
- "path": "amps",
9965
+ "path": "current",
9947
9966
  "valueType": "number"
9948
9967
  },
9949
9968
  {
9950
- "path": "va",
9969
+ "path": "apparentPower",
9951
9970
  "valueType": "number"
9952
9971
  },
9953
9972
  {
@@ -9975,14 +9994,10 @@ Object.freeze({
9975
9994
  {
9976
9995
  "path": "gps.accuracyMeters",
9977
9996
  "valueType": "number"
9978
- },
9979
- {
9980
- "path": "batteryPercent",
9981
- "valueType": "number"
9982
9997
  }
9983
9998
  ],
9984
9999
  "pressure-sensor": [{
9985
- "path": "hpa",
10000
+ "path": "pressure",
9986
10001
  "valueType": "number"
9987
10002
  }],
9988
10003
  "privacy-mask": [{
@@ -10296,7 +10311,7 @@ Object.freeze({
10296
10311
  "valueType": "boolean"
10297
10312
  }],
10298
10313
  "temperature-sensor": [{
10299
- "path": "celsius",
10314
+ "path": "temperature",
10300
10315
  "valueType": "number"
10301
10316
  }],
10302
10317
  "update": [
@@ -10344,7 +10359,7 @@ Object.freeze({
10344
10359
  "valueType": "string"
10345
10360
  },
10346
10361
  {
10347
- "path": "progressPercent",
10362
+ "path": "progress",
10348
10363
  "valueType": "number"
10349
10364
  },
10350
10365
  {
@@ -10829,7 +10844,7 @@ function errMsg(err) {
10829
10844
  return String(err);
10830
10845
  }
10831
10846
  //#endregion
10832
- //#region ../types/dist/composition-Bb8iwHEJ.mjs
10847
+ //#region ../types/dist/composition-CZImLpOI.mjs
10833
10848
  /**
10834
10849
  * The ffmpeg build every CamStack node downloads, per platform and arch.
10835
10850
  *
@@ -15349,6 +15364,14 @@ var AutomationConditionLeafSchema = object({
15349
15364
  array(union([string(), number()]))
15350
15365
  ])
15351
15366
  });
15367
+ var AutomationConditionStationaryPresentSchema = object({
15368
+ kind: literal("stationary-present"),
15369
+ deviceId: number().int().nonnegative(),
15370
+ /** Class names; a macro class matches every raw class that maps to it. */
15371
+ classes: array(string().min(1)).min(1).optional(),
15372
+ /** The parked object must be in at least one of these zones. */
15373
+ zones: array(string().min(1)).min(1).optional()
15374
+ });
15352
15375
  /**
15353
15376
  * The expression leaf, declared as a plain object rather than an intersection
15354
15377
  * with {@link ExpressionSourceSchema}: a discriminated union has to be able to
@@ -15382,7 +15405,8 @@ var AutomationConditionSchema = lazy(() => discriminatedUnion("kind", [
15382
15405
  child: AutomationConditionSchema
15383
15406
  }),
15384
15407
  AutomationConditionLeafSchema,
15385
- AutomationConditionExpressionSchema
15408
+ AutomationConditionExpressionSchema,
15409
+ AutomationConditionStationaryPresentSchema
15386
15410
  ]));
15387
15411
  /**
15388
15412
  * What starts a run.
@@ -15423,7 +15447,34 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
15423
15447
  kind: literal("schedule"),
15424
15448
  cron: string().min(1).max(120)
15425
15449
  }),
15426
- object({ kind: literal("manual") })
15450
+ object({ kind: literal("manual") }),
15451
+ object({
15452
+ kind: literal("detection"),
15453
+ /** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
15454
+ * matches every raw class that maps to it; any other name matches
15455
+ * exactly. */
15456
+ classes: array(string().min(1)).min(1),
15457
+ deviceIds: array(number().int().nonnegative()).min(1),
15458
+ /** The track must have visited at least one of these zones. */
15459
+ zones: array(string().min(1)).min(1).optional(),
15460
+ /** Best-so-far confidence the track must reach. */
15461
+ minScore: number().min(0).max(1).optional()
15462
+ }),
15463
+ object({
15464
+ kind: literal("stationary"),
15465
+ deviceIds: array(number().int().nonnegative()).min(1),
15466
+ /** Class names; a macro class matches like the detection trigger. */
15467
+ classes: array(string().min(1)).min(1).optional(),
15468
+ /** The parked object must be in at least one of these zones. */
15469
+ zones: array(string().min(1)).min(1).optional(),
15470
+ /** `appeared`: it became parked. `departed`: the registry retired it.
15471
+ * The vocabulary of `PipelineAnalyticsStationaryChanged`. */
15472
+ phase: _enum(["appeared", "departed"])
15473
+ }),
15474
+ object({
15475
+ kind: literal("interval"),
15476
+ minutes: number().int().min(1).max(1440)
15477
+ })
15427
15478
  ]);
15428
15479
  /**
15429
15480
  * One action step.
@@ -15443,28 +15494,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
15443
15494
  * is called. The runner still receives a number and is untouched; the
15444
15495
  * resolution is the recipe's job, not the runner's.
15445
15496
  */
15497
+ var AutomationWaitStepSchema = object({
15498
+ kind: literal("wait"),
15499
+ seconds: number().min(0).max(300)
15500
+ });
15501
+ var AutomationCapStepSchema = object({
15502
+ kind: literal("cap"),
15503
+ /**
15504
+ * One device, several same-family devices (locks / climate family / …),
15505
+ * or `{ $var }` for the device that triggered the run. An array is
15506
+ * fan-out at codegen — each id gets the same cap.method call.
15507
+ */
15508
+ deviceId: union([
15509
+ number().int(),
15510
+ array(number().int()).min(1),
15511
+ object({ $var: string().min(1) })
15512
+ ]),
15513
+ cap: string().min(1),
15514
+ method: string().min(1),
15515
+ /** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
15516
+ * SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
15517
+ * the expression leaf. */
15518
+ args: record(string(), unknown()).optional()
15519
+ });
15520
+ /**
15521
+ * The steps an internal Action may contain: cap and wait, and nothing that can
15522
+ * call back into an Action — so an Action can never reach itself (no cycles).
15523
+ */
15524
+ var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
15446
15525
  var AutomationActionSchema = discriminatedUnion("kind", [
15526
+ AutomationWaitStepSchema,
15527
+ AutomationCapStepSchema,
15447
15528
  object({
15448
- kind: literal("wait"),
15449
- seconds: number().min(0).max(300)
15450
- }),
15451
- object({
15452
- kind: literal("cap"),
15453
- /**
15454
- * One device, several same-family devices (locks / climate family / …),
15455
- * or `{ $var }` for the device that triggered the run. An array is
15456
- * fan-out at codegen — each id gets the same cap.method call.
15457
- */
15458
- deviceId: union([
15459
- number().int(),
15460
- array(number().int()).min(1),
15461
- object({ $var: string().min(1) })
15462
- ]),
15463
- cap: string().min(1),
15464
- method: string().min(1),
15465
- /** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
15466
- * evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
15467
- args: record(string(), unknown()).optional()
15529
+ kind: literal("action"),
15530
+ /** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
15531
+ actionId: string().min(1),
15532
+ /** Values for the action's declared variables; the others take their default. */
15533
+ variables: record(string(), union([
15534
+ string(),
15535
+ number(),
15536
+ boolean()
15537
+ ])).optional()
15468
15538
  }),
15469
15539
  object({
15470
15540
  kind: literal("code"),
@@ -15473,10 +15543,357 @@ var AutomationActionSchema = discriminatedUnion("kind", [
15473
15543
  code: string().min(1).max(2e4)
15474
15544
  })
15475
15545
  ]);
15546
+ /**
15547
+ * How a trigger that arrives while the automation is busy (or cooling down) is
15548
+ * handled. One of the automation's execution modes, never a property of its
15549
+ * actions. Absent means `single`.
15550
+ *
15551
+ * - `single` — drop the trigger while a run is in progress (traced + logged).
15552
+ * - `restart` — abort the run in progress (at its next step boundary), start fresh.
15553
+ * - `queued` — queue up to `max` triggers, drop the rest (traced).
15554
+ * - `parallel` — up to `max` runs at once, drop the rest (traced).
15555
+ * - `cooldown` — `single`, and no new run until `minutes` after the last run
15556
+ * STARTED; persisted across a restart. A manual trigger bypasses only this
15557
+ * wait, never the single/queued limits.
15558
+ */
15559
+ var AutomationRunModeSchema = discriminatedUnion("mode", [
15560
+ object({ mode: literal("single") }),
15561
+ object({ mode: literal("restart") }),
15562
+ object({
15563
+ mode: literal("queued"),
15564
+ max: number().int().min(1).max(10)
15565
+ }),
15566
+ object({
15567
+ mode: literal("parallel"),
15568
+ max: number().int().min(1).max(10)
15569
+ }),
15570
+ object({
15571
+ mode: literal("cooldown"),
15572
+ minutes: number().int().min(1).max(1440)
15573
+ })
15574
+ ]);
15476
15575
  var AutomationRecipeSchema = object({
15477
15576
  triggers: array(AutomationTriggerSchema),
15478
15577
  conditions: AutomationConditionSchema.optional(),
15479
- actions: array(AutomationActionSchema)
15578
+ actions: array(AutomationActionSchema),
15579
+ runMode: AutomationRunModeSchema.optional(),
15580
+ /** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
15581
+ keepTraces: number().int().min(1).max(100).optional()
15582
+ });
15583
+ new Set([
15584
+ {
15585
+ id: "person",
15586
+ name: "Person"
15587
+ },
15588
+ {
15589
+ id: "vehicle",
15590
+ name: "Vehicle"
15591
+ },
15592
+ {
15593
+ id: "animal",
15594
+ name: "Animal"
15595
+ },
15596
+ {
15597
+ id: "package",
15598
+ name: "Package"
15599
+ }
15600
+ ].map((l) => l.id));
15601
+ var COCO_TO_MACRO = {
15602
+ mapping: {
15603
+ person: "person",
15604
+ bicycle: "vehicle",
15605
+ car: "vehicle",
15606
+ motorcycle: "vehicle",
15607
+ airplane: "vehicle",
15608
+ bus: "vehicle",
15609
+ train: "vehicle",
15610
+ truck: "vehicle",
15611
+ boat: "vehicle",
15612
+ bird: "animal",
15613
+ cat: "animal",
15614
+ dog: "animal",
15615
+ horse: "animal",
15616
+ sheep: "animal",
15617
+ cow: "animal",
15618
+ elephant: "animal",
15619
+ bear: "animal",
15620
+ zebra: "animal",
15621
+ giraffe: "animal",
15622
+ suitcase: "package",
15623
+ backpack: "package",
15624
+ handbag: "package"
15625
+ },
15626
+ preserveOriginal: false
15627
+ };
15628
+ new Set(Object.values(COCO_TO_MACRO.mapping));
15629
+ /**
15630
+ * Run traces — what an automation (or, later, an Action run) DID, node by node,
15631
+ * so the editor can paint every block green or red with its reason.
15632
+ *
15633
+ * A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
15634
+ * every condition node (containers and leaves, including the ones a
15635
+ * short-circuit never reached), the run-mode verdict and every action step —
15636
+ * each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
15637
+ * for an Action run). Skipped
15638
+ * evaluations are traced too, and identical consecutive skips collapse into a
15639
+ * repeat count so a trigger that fails every 5 minutes cannot flush real runs.
15640
+ *
15641
+ * {@link AutomationStepTraceSchema} is deliberately free of automation
15642
+ * vocabulary so an Action run records the same step shape.
15643
+ */
15644
+ /** A value a trace may show: JSON primitives and short lists, nothing deeper. */
15645
+ var TraceValueSchema = union([
15646
+ string(),
15647
+ number(),
15648
+ boolean(),
15649
+ _null(),
15650
+ array(union([string(), number()]))
15651
+ ]);
15652
+ var AutomationRunOutcomeSchema = _enum([
15653
+ "ran",
15654
+ "skipped-trigger",
15655
+ "skipped-conditions",
15656
+ "skipped-cooldown",
15657
+ "skipped-overlap",
15658
+ "failed",
15659
+ "aborted"
15660
+ ]);
15661
+ /** `not-evaluated` = a short-circuit never reached the node. */
15662
+ var TraceNodeOutcomeSchema = _enum([
15663
+ "pass",
15664
+ "fail",
15665
+ "not-evaluated"
15666
+ ]);
15667
+ var AutomationTriggerTraceSchema = object({
15668
+ kind: string().min(1),
15669
+ outcome: _enum(["pass", "fail"]),
15670
+ /** Why an event was rejected ("class person not in [dog]") or what fired. */
15671
+ reason: string(),
15672
+ /** deviceId, className, trackId, score … — only what the trigger exposes. */
15673
+ vars: record(string(), TraceValueSchema)
15674
+ });
15675
+ var AutomationConditionTraceNodeSchema = object({
15676
+ /** `conditions` for the root, `conditions.<i>` for its i-th child, … */
15677
+ path: string().min(1),
15678
+ kind: _enum([
15679
+ "all",
15680
+ "any",
15681
+ "not",
15682
+ "condition",
15683
+ "expression",
15684
+ "stationary-present"
15685
+ ]),
15686
+ outcome: TraceNodeOutcomeSchema,
15687
+ reason: string(),
15688
+ deviceId: number().int().optional(),
15689
+ cap: string().optional(),
15690
+ fieldPath: string().optional(),
15691
+ operator: string().optional(),
15692
+ expected: TraceValueSchema.optional(),
15693
+ /** What the mirror held; `null` when it held nothing (unknown). */
15694
+ observed: TraceValueSchema.optional()
15695
+ });
15696
+ var AutomationRunVerdictSchema = object({
15697
+ mode: AutomationRunModeSchema,
15698
+ decision: _enum([
15699
+ "run",
15700
+ "queued",
15701
+ "restart",
15702
+ "drop",
15703
+ "cooldown",
15704
+ "bypass"
15705
+ ]),
15706
+ reason: string()
15707
+ });
15708
+ /** One executed (or not-run) step — shared by automations and Action runs. */
15709
+ var AutomationStepTraceSchema = object({
15710
+ /** `actions.<i>` */
15711
+ path: string().min(1),
15712
+ kind: string().min(1),
15713
+ cap: string().optional(),
15714
+ method: string().optional(),
15715
+ deviceId: number().int().optional(),
15716
+ startedAt: number().optional(),
15717
+ endedAt: number().optional(),
15718
+ outcome: _enum([
15719
+ "ok",
15720
+ "error",
15721
+ "not-run"
15722
+ ]),
15723
+ message: string().optional()
15724
+ });
15725
+ var AutomationRunTraceSchema = object({
15726
+ runId: string().min(1),
15727
+ startedAt: number(),
15728
+ endedAt: number(),
15729
+ trigger: AutomationTriggerTraceSchema,
15730
+ conditions: array(AutomationConditionTraceNodeSchema),
15731
+ verdict: AutomationRunVerdictSchema.optional(),
15732
+ steps: array(AutomationStepTraceSchema),
15733
+ outcome: AutomationRunOutcomeSchema,
15734
+ /** How many identical consecutive skips this trace stands for (>= 1). */
15735
+ repeat: number().int().min(1),
15736
+ /** When the latest of those repeats happened. */
15737
+ lastAt: number()
15738
+ });
15739
+ /**
15740
+ * What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
15741
+ * `action:<actionId>`): the cooldown stamp and the trace ring.
15742
+ */
15743
+ var AutomationStateDocSchema = object({
15744
+ version: literal(1),
15745
+ lastRunStartedAt: number().nullable(),
15746
+ traces: array(AutomationRunTraceSchema)
15747
+ });
15748
+ /**
15749
+ * Actions — named, runnable things an operator (or an automation) can start,
15750
+ * declared as LIST ENTRIES, never as devices.
15751
+ *
15752
+ * An entry is either **internal** (a short list of cap/wait steps kept in the
15753
+ * hub's `actions` record kind) or declared by an addon through the
15754
+ * `action-source` collection (a Home Assistant script, a scene …). The one
15755
+ * surface the UI and automations talk to is the `actions` cap; it keeps no
15756
+ * catalog of its own (D3) — every `list` asks the providers live.
15757
+ *
15758
+ * This file is the data half: the entry schema, the variables an entry may
15759
+ * declare, and the pure resolution of the values a run was given. It holds no
15760
+ * runtime.
15761
+ */
15762
+ /** What a variable's value is. `select` takes one of `options`. */
15763
+ var ActionVariableTypeSchema = _enum([
15764
+ "string",
15765
+ "number",
15766
+ "boolean",
15767
+ "select"
15768
+ ]);
15769
+ var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
15770
+ var ActionVariableValueSchema = union([
15771
+ string(),
15772
+ number(),
15773
+ boolean()
15774
+ ]);
15775
+ /**
15776
+ * One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
15777
+ * value) or `{{vars.name}}` (inside a string) in their args.
15778
+ */
15779
+ var ActionVariableSchema = object({
15780
+ name: string().regex(ACTION_VARIABLE_NAME_RE),
15781
+ label: string().min(1).max(120).optional(),
15782
+ type: ActionVariableTypeSchema,
15783
+ required: boolean().optional(),
15784
+ default: ActionVariableValueSchema.optional(),
15785
+ /** The allowed values of a `select`. */
15786
+ options: array(string().min(1)).min(1).optional()
15787
+ }).superRefine((v, ctx) => {
15788
+ if (v.type === "select" && v.options === void 0) ctx.addIssue({
15789
+ code: "custom",
15790
+ message: "a select variable needs options",
15791
+ path: ["options"]
15792
+ });
15793
+ if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
15794
+ code: "custom",
15795
+ message: variableValueError(v, v.default) ?? "invalid default",
15796
+ path: ["default"]
15797
+ });
15798
+ });
15799
+ /** Why `value` is not a legal value for the variable, or null when it is. */
15800
+ function variableValueError(variable, value) {
15801
+ switch (variable.type) {
15802
+ case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
15803
+ case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
15804
+ case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
15805
+ case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
15806
+ }
15807
+ }
15808
+ var ActionSourceKindSchema = _enum(["internal", "addon"]);
15809
+ function isInternalActionId(actionId) {
15810
+ return actionId.startsWith("internal:") && actionId.length > 9;
15811
+ }
15812
+ /** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
15813
+ function addonIdOfActionId(actionId) {
15814
+ if (isInternalActionId(actionId)) return null;
15815
+ const at = actionId.indexOf(":");
15816
+ return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
15817
+ }
15818
+ var ActionStatusSchema = object({
15819
+ isRunning: boolean(),
15820
+ /** Ms epoch the latest run STARTED; null when it never ran. */
15821
+ lastRunAt: number().nullable(),
15822
+ /** The latest run's failure; null on success or when it never ran. */
15823
+ lastError: string().nullable()
15824
+ });
15825
+ var ActionEntrySchema = object({
15826
+ /** `internal:<uuid>` or `<addonId>:<localId>`. */
15827
+ id: string().min(3),
15828
+ name: string().min(1).max(120),
15829
+ /** The addon that declared it; `core-blocks` for an internal one. */
15830
+ addonId: string().min(1),
15831
+ source: ActionSourceKindSchema,
15832
+ /** An addon-declared entry is edited where it was declared. */
15833
+ readOnly: boolean(),
15834
+ /** Internal only: cap and wait steps. No action-in-action, so no cycles. */
15835
+ steps: array(ActionStepSchema).min(1).max(50).optional(),
15836
+ variables: array(ActionVariableSchema).max(20).optional(),
15837
+ status: ActionStatusSchema
15838
+ }).superRefine((entry, ctx) => {
15839
+ if (entry.source === "internal") {
15840
+ if (!isInternalActionId(entry.id)) ctx.addIssue({
15841
+ code: "custom",
15842
+ message: "an internal action id is internal:<uuid>",
15843
+ path: ["id"]
15844
+ });
15845
+ return;
15846
+ }
15847
+ if (entry.steps !== void 0) ctx.addIssue({
15848
+ code: "custom",
15849
+ message: "only an internal action carries steps",
15850
+ path: ["steps"]
15851
+ });
15852
+ if (!entry.readOnly) ctx.addIssue({
15853
+ code: "custom",
15854
+ message: "an addon action is read-only here",
15855
+ path: ["readOnly"]
15856
+ });
15857
+ if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
15858
+ code: "custom",
15859
+ message: "an addon action id is <addonId>:<localId>",
15860
+ path: ["id"]
15861
+ });
15862
+ });
15863
+ /** What an operator writes for an internal action. */
15864
+ var ActionInputSchema = object({
15865
+ name: string().min(1).max(120),
15866
+ steps: array(ActionStepSchema).min(1).max(50),
15867
+ variables: array(ActionVariableSchema).max(20).optional()
15868
+ });
15869
+ /** Who started a run. Absent = the operator pressed it. */
15870
+ var ActionRunOriginSchema = object({
15871
+ /** The automation block whose step started it. */
15872
+ blockId: string().min(1).optional() });
15873
+ /** `started` = the caller did not ask to wait. */
15874
+ var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
15875
+ var ActionRunResultSchema = object({
15876
+ runId: string().min(1),
15877
+ outcome: ActionRunOutcomeSchema,
15878
+ /** Why it did not run, or what failed. */
15879
+ message: string().optional()
15880
+ });
15881
+ _enum([
15882
+ "not-found",
15883
+ "read-only",
15884
+ "invalid-variables",
15885
+ "invalid-steps",
15886
+ "not-linked",
15887
+ "busy"
15888
+ ]);
15889
+ object({
15890
+ actionId: string(),
15891
+ runId: string(),
15892
+ isRunning: boolean(),
15893
+ /** Set when the run ended. */
15894
+ outcome: AutomationRunOutcomeSchema.optional(),
15895
+ lastRunAt: number().nullable(),
15896
+ lastError: string().nullable()
15480
15897
  });
15481
15898
  /**
15482
15899
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
@@ -18163,7 +18580,7 @@ var CompositionEventPlanSchema = object({
18163
18580
  stateField: string(),
18164
18581
  fieldKey: string()
18165
18582
  });
18166
- /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
18583
+ /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.temperature`. */
18167
18584
  var CompositionProblemSchema = object({
18168
18585
  code: _enum([
18169
18586
  "reserved-variant",
@@ -18482,7 +18899,7 @@ var GROUP_TEMPLATES = [
18482
18899
  summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
18483
18900
  role: DeviceRole.TemperatureSensor,
18484
18901
  outputCap: "temperature-sensor",
18485
- outputField: "celsius",
18902
+ outputField: "temperature",
18486
18903
  quantity: "temperature",
18487
18904
  defaultAggregate: "mean",
18488
18905
  empty: "null",
@@ -18493,7 +18910,7 @@ var GROUP_TEMPLATES = [
18493
18910
  summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
18494
18911
  role: DeviceRole.HumiditySensor,
18495
18912
  outputCap: "humidity-sensor",
18496
- outputField: "percent",
18913
+ outputField: "humidity",
18497
18914
  quantity: "humidity",
18498
18915
  defaultAggregate: "mean",
18499
18916
  empty: "null",
@@ -18504,7 +18921,7 @@ var GROUP_TEMPLATES = [
18504
18921
  summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
18505
18922
  role: DeviceRole.PressureSensor,
18506
18923
  outputCap: "pressure-sensor",
18507
- outputField: "hpa",
18924
+ outputField: "pressure",
18508
18925
  quantity: "pressure",
18509
18926
  defaultAggregate: "mean",
18510
18927
  empty: "null",
@@ -18515,7 +18932,7 @@ var GROUP_TEMPLATES = [
18515
18932
  summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
18516
18933
  role: DeviceRole.AmbientLightSensor,
18517
18934
  outputCap: "ambient-light-sensor",
18518
- outputField: "lux",
18935
+ outputField: "illuminance",
18519
18936
  quantity: "illuminance",
18520
18937
  defaultAggregate: "mean",
18521
18938
  empty: "null",
@@ -18526,7 +18943,7 @@ var GROUP_TEMPLATES = [
18526
18943
  summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
18527
18944
  role: DeviceRole.PowerSensor,
18528
18945
  outputCap: "power-meter",
18529
- outputField: "watts",
18946
+ outputField: "power",
18530
18947
  quantity: "power",
18531
18948
  defaultAggregate: "sum",
18532
18949
  empty: "omit",
@@ -18537,7 +18954,7 @@ var GROUP_TEMPLATES = [
18537
18954
  summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
18538
18955
  role: DeviceRole.EnergySensor,
18539
18956
  outputCap: "power-meter",
18540
- outputField: "kwhTotal",
18957
+ outputField: "energy",
18541
18958
  quantity: "energy",
18542
18959
  defaultAggregate: "sum",
18543
18960
  empty: "omit",
@@ -18548,7 +18965,7 @@ var GROUP_TEMPLATES = [
18548
18965
  summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
18549
18966
  role: DeviceRole.BatterySensor,
18550
18967
  outputCap: "battery",
18551
- outputField: "percentage",
18968
+ outputField: "level",
18552
18969
  quantity: "percentage",
18553
18970
  defaultAggregate: "mean",
18554
18971
  empty: "null",
@@ -19126,7 +19543,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
19126
19543
  kind: "mutation",
19127
19544
  auth: "admin",
19128
19545
  access: "view"
19129
- });
19546
+ }), method(object({
19547
+ blockId: string().min(1),
19548
+ trace: AutomationRunTraceSchema.optional(),
19549
+ runStartedAt: number().optional(),
19550
+ keepTraces: number().int().min(1).max(100).optional()
19551
+ }), _void(), {
19552
+ kind: "mutation",
19553
+ auth: "admin"
19554
+ }), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
19555
+ traces: array(AutomationRunTraceSchema),
19556
+ lastError: string().nullable()
19557
+ }), { auth: "admin" });
19130
19558
  /**
19131
19559
  * `custom-model-registry` — collection cap exposing operator-registered
19132
19560
  * custom detection models. Each provider (today: `addon-model-studio`)
@@ -44109,7 +44537,7 @@ var NetworkAccessStatusSchema = object({
44109
44537
  });
44110
44538
  /**
44111
44539
  * Optional, richer endpoint shape returned by providers that expose
44112
- * MORE than one ingress concurrently (Tailscale Ingress with mixed
44540
+ * MORE than one ingress concurrently (Tailscale Funnel with mixed
44113
44541
  * serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
44114
44542
  * the originating provider config (mode + sourcePort) so the
44115
44543
  * orchestrator UI can label rows distinctly. Providers that expose only
@@ -44502,51 +44930,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
44502
44930
  kind: "mutation",
44503
44931
  auth: "admin"
44504
44932
  });
44505
- new Set([
44506
- {
44507
- id: "person",
44508
- name: "Person"
44509
- },
44510
- {
44511
- id: "vehicle",
44512
- name: "Vehicle"
44513
- },
44514
- {
44515
- id: "animal",
44516
- name: "Animal"
44517
- },
44518
- {
44519
- id: "package",
44520
- name: "Package"
44521
- }
44522
- ].map((l) => l.id));
44523
- var COCO_TO_MACRO = {
44524
- mapping: {
44525
- person: "person",
44526
- bicycle: "vehicle",
44527
- car: "vehicle",
44528
- motorcycle: "vehicle",
44529
- airplane: "vehicle",
44530
- bus: "vehicle",
44531
- train: "vehicle",
44532
- truck: "vehicle",
44533
- boat: "vehicle",
44534
- bird: "animal",
44535
- cat: "animal",
44536
- dog: "animal",
44537
- horse: "animal",
44538
- sheep: "animal",
44539
- cow: "animal",
44540
- elephant: "animal",
44541
- bear: "animal",
44542
- zebra: "animal",
44543
- giraffe: "animal",
44544
- suitcase: "package",
44545
- backpack: "package",
44546
- handbag: "package"
44547
- },
44548
- preserveOriginal: false
44549
- };
44550
44933
  var AUDIO_MACRO_LABELS = [
44551
44934
  {
44552
44935
  id: "speech",
@@ -57113,9 +57496,9 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
57113
57496
  */
57114
57497
  var AirQualitySensorStatusSchema = object({
57115
57498
  /** Carbon dioxide concentration in ppm. */
57116
- co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
57499
+ co2: number().min(0).optional().meta(readingMeta("concentration-volume")),
57117
57500
  /** Total volatile organic compounds in ppb. */
57118
- vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
57501
+ voc: number().min(0).optional().meta(readingMeta("concentration-ppb")),
57119
57502
  /** Particulate matter ≤ 2.5 μm in µg/m³. */
57120
57503
  pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
57121
57504
  /** Particulate matter ≤ 10 μm in µg/m³. */
@@ -57148,12 +57531,12 @@ var airQualitySensorCapability = {
57148
57531
  * History (D850): recorded series.
57149
57532
  */
57150
57533
  history: { fields: {
57151
- co2Ppm: {
57534
+ co2: {
57152
57535
  kind: "gauge",
57153
57536
  unit: "ppm",
57154
57537
  deadband: 5
57155
57538
  },
57156
- vocPpb: {
57539
+ voc: {
57157
57540
  kind: "gauge",
57158
57541
  unit: "ppb",
57159
57542
  deadband: 5
@@ -57184,7 +57567,7 @@ var airQualitySensorCapability = {
57184
57567
  */
57185
57568
  var AmbientLightSensorStatusSchema = object({
57186
57569
  /** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
57187
- lux: number().min(0).nullable().meta(readingMeta("illuminance", {
57570
+ illuminance: number().min(0).nullable().meta(readingMeta("illuminance", {
57188
57571
  precision: 0,
57189
57572
  label: "Illuminance"
57190
57573
  })),
@@ -57213,7 +57596,7 @@ var ambientLightSensorCapability = {
57213
57596
  /**
57214
57597
  * History (D850): recorded series. Wide range, so a RELATIVE deadband (10 %).
57215
57598
  */
57216
- history: { fields: { lux: {
57599
+ history: { fields: { illuminance: {
57217
57600
  kind: "gauge",
57218
57601
  unit: "lx",
57219
57602
  deadbandPct: 10,
@@ -57352,6 +57735,84 @@ var audioMetricsCapability = {
57352
57735
  */
57353
57736
  history: "none"
57354
57737
  };
57738
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
57739
+ actionId: string().min(1),
57740
+ variables: record(string(), ActionVariableValueSchema).optional()
57741
+ }), _void(), {
57742
+ kind: "mutation",
57743
+ auth: "admin"
57744
+ }), method(object({ actionId: string().min(1) }), _void(), {
57745
+ kind: "mutation",
57746
+ auth: "admin"
57747
+ });
57748
+ /**
57749
+ * actions — the ONE surface for runnable actions, for the UI and for
57750
+ * automations. Provided by the core-blocks builtin on the hub.
57751
+ *
57752
+ * An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
57753
+ * steps, kept in the hub's `actions` record kind) or declared by an addon over
57754
+ * `action-source`. `list` asks every `action-source` provider LIVE and overlays
57755
+ * the run status from the hub's `runs` ledger; there is no catalog here to
57756
+ * drift (D3).
57757
+ *
57758
+ * **Permissions follow the camera, as linked devices do.** An action is linked
57759
+ * to cameras by the operator (`setLinks`, D356: nothing links itself). A
57760
+ * non-admin may `get` / `run` an action only through a camera they may see that
57761
+ * links it: they name the camera (`deviceId`, a top-level field so the scope
57762
+ * gate sees it) and the provider refuses an action that camera does not link.
57763
+ * An admin, and an in-process caller (an automation block), may run any action.
57764
+ * Every refusal is typed (`[not-linked] …`) and logged.
57765
+ *
57766
+ * A second `run` of an action that is already running is REFUSED — traced and
57767
+ * logged — never queued.
57768
+ */
57769
+ var ActionIdInput = object({ actionId: string().min(1) });
57770
+ var ActionLinksSchema = object({
57771
+ deviceId: number().int().nonnegative(),
57772
+ actionIds: array(string().min(1)).max(100)
57773
+ });
57774
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
57775
+ actionId: string().min(1),
57776
+ deviceId: number().int().nonnegative().optional()
57777
+ }), object({ action: ActionEntrySchema.nullable() }), {
57778
+ role: "viewer",
57779
+ auth: "protected",
57780
+ kind: "query",
57781
+ caller: "required"
57782
+ }), method(object({
57783
+ actionId: string().min(1),
57784
+ variables: record(string(), ActionVariableValueSchema).optional(),
57785
+ wait: boolean().optional(),
57786
+ origin: ActionRunOriginSchema.optional(),
57787
+ deviceId: number().int().nonnegative().optional()
57788
+ }), ActionRunResultSchema, {
57789
+ role: "viewer",
57790
+ auth: "protected",
57791
+ kind: "mutation",
57792
+ caller: "required"
57793
+ }), method(ActionIdInput, _void(), {
57794
+ kind: "mutation",
57795
+ auth: "admin"
57796
+ }), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
57797
+ kind: "mutation",
57798
+ auth: "admin"
57799
+ }), method(object({
57800
+ actionId: string().min(1),
57801
+ action: ActionInputSchema.partial()
57802
+ }), object({ action: ActionEntrySchema }), {
57803
+ kind: "mutation",
57804
+ auth: "admin"
57805
+ }), method(ActionIdInput, _void(), {
57806
+ kind: "mutation",
57807
+ auth: "admin"
57808
+ }), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
57809
+ role: "viewer",
57810
+ auth: "protected",
57811
+ kind: "query"
57812
+ }), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
57813
+ kind: "mutation",
57814
+ auth: "admin"
57815
+ });
57355
57816
  /**
57356
57817
  * Automation-control cap. Models HA `automation.*` entities on
57357
57818
  * `DeviceType.Automation`. An automation is a trigger+condition+
@@ -57448,7 +57909,7 @@ var BatteryStatusSchema = object({
57448
57909
  * Consumers must SKIP a null rather than coerce it — `battery-band` already
57449
57910
  * declines to band a non-finite reading, which is the correct shape.
57450
57911
  */
57451
- percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
57912
+ level: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
57452
57913
  /**
57453
57914
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
57454
57915
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -57458,7 +57919,7 @@ var BatteryStatusSchema = object({
57458
57919
  * `'unknown'` is the absence of an answer: the provider has not read the
57459
57920
  * power fields yet, or the firmware reported neither. Before it existed,
57460
57921
  * two unreadable fields produced `'none'`, and a camera nobody had reached
57461
- * was drawn "on battery alone" — the same D315 defect `percentage` closed
57922
+ * was drawn "on battery alone" — the same D315 defect `level` closed
57462
57923
  * by going nullable. Consumers SKIP it (no charger state published, no
57463
57924
  * glyph, no HomeKit ChargingState) rather than coerce it either way.
57464
57925
  */
@@ -57482,7 +57943,7 @@ var BatteryStatusSchema = object({
57482
57943
  * that only report charge. A second reading on this cap, not a second
57483
57944
  * `numeric-sensor` on the same device.
57484
57945
  */
57485
- volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
57946
+ voltage: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
57486
57947
  /**
57487
57948
  * Ms epoch of the last time the device PROVED it was reachable — a
57488
57949
  * completed firmware round-trip, an observed wake, or an inbound push
@@ -57516,7 +57977,7 @@ var BatteryStatusSchema = object({
57516
57977
  /**
57517
57978
  * True when the source is a BINARY low-battery indicator (HA
57518
57979
  * `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
57519
- * charge level — `percentage` is then a coarse stand-in (100 = normal,
57980
+ * charge level — `level` is then a coarse stand-in (100 = normal,
57520
57981
  * sub-threshold = low). UI MUST render "Normal"/"Low" instead of a
57521
57982
  * misleading exact percentage. Absent/false → genuine 0–100 % reading.
57522
57983
  */
@@ -57529,21 +57990,22 @@ var BATTERY_DEVICE_TYPES = [
57529
57990
  DeviceType.Switch,
57530
57991
  DeviceType.PetFeeder,
57531
57992
  DeviceType.Container,
57532
- DeviceType.Thermostat
57993
+ DeviceType.Thermostat,
57994
+ DeviceType.EventEmitter
57533
57995
  ];
57534
57996
  /** Generic Customize target for the percentage reading (D936). */
57535
57997
  var batteryCustomize = {
57536
57998
  version: 1,
57537
57999
  targets: [{
57538
- id: "percentage",
58000
+ id: "level",
57539
58001
  cardinality: "scalar",
57540
58002
  vocabulary: {
57541
58003
  cap: "battery",
57542
- stateField: "percentage"
58004
+ stateField: "level"
57543
58005
  },
57544
58006
  deviceTypes: BATTERY_DEVICE_TYPES,
57545
58007
  apply: "add",
57546
- path: "percentage",
58008
+ path: "level",
57547
58009
  sources: [{
57548
58010
  kind: "field",
57549
58011
  valueKinds: ["number", "string"],
@@ -57637,7 +58099,7 @@ onStatusChanged: { data: object({
57637
58099
  schema: BatteryStatusSchema,
57638
58100
  kind: "push",
57639
58101
  empty: {
57640
- percentage: null,
58102
+ level: null,
57641
58103
  charging: "unknown",
57642
58104
  sleeping: false,
57643
58105
  lastUpdated: 0
@@ -57664,11 +58126,11 @@ onStatusChanged: { data: object({
57664
58126
  * History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
57665
58127
  */
57666
58128
  history: { fields: {
57667
- percentage: {
58129
+ level: {
57668
58130
  kind: "gauge",
57669
58131
  unit: "%"
57670
58132
  },
57671
- volts: {
58133
+ voltage: {
57672
58134
  kind: "gauge",
57673
58135
  unit: "V"
57674
58136
  }
@@ -57728,14 +58190,14 @@ var binaryCapability = {
57728
58190
  * controls to this single-method surface.
57729
58191
  *
57730
58192
  * The cap is intentionally minimal: a single `setBrightness({deviceId,
57731
- * percentage})` mutation plus the auto-injected `getStatus`. Drivers
58193
+ * level})` mutation plus the auto-injected `getStatus`. Drivers
57732
58194
  * that expose richer controls (color temperature, scenes, schedules)
57733
58195
  * should surface those via the device's `getSettingsUISchema()`
57734
58196
  * instead of bloating this cap.
57735
58197
  */
57736
58198
  var BrightnessStatusSchema = object({
57737
58199
  /** Current level as 0..100 inclusive. Firmware-reported. */
57738
- percentage: number().min(0).max(100).meta(readingMeta("percentage")),
58200
+ level: number().min(0).max(100).meta(readingMeta("percentage")),
57739
58201
  /** Ms epoch of the last operator-driven change. Useful for UI freshness. */
57740
58202
  lastChangedAt: number()
57741
58203
  });
@@ -57747,7 +58209,7 @@ var brightnessCapability = {
57747
58209
  deviceTypes: [DeviceType.Light],
57748
58210
  methods: { setBrightness: method(object({
57749
58211
  deviceId: number().int().nonnegative(),
57750
- percentage: number().min(0).max(100)
58212
+ level: number().min(0).max(100)
57751
58213
  }), _void(), {
57752
58214
  kind: "mutation",
57753
58215
  auth: "protected"
@@ -57760,7 +58222,7 @@ var brightnessCapability = {
57760
58222
  */
57761
58223
  onBrightnessChanged: { data: object({
57762
58224
  deviceId: number(),
57763
- percentage: number().min(0).max(100),
58225
+ level: number().min(0).max(100),
57764
58226
  lastChangedAt: number()
57765
58227
  }) } },
57766
58228
  status: {
@@ -57783,7 +58245,7 @@ onBrightnessChanged: { data: object({
57783
58245
  /**
57784
58246
  * History (D850): recorded series. Actuator tier: level keeps every change.
57785
58247
  */
57786
- history: { fields: { percentage: {
58248
+ history: { fields: { level: {
57787
58249
  kind: "gauge",
57788
58250
  unit: "%",
57789
58251
  minIntervalMs: 0
@@ -58380,11 +58842,11 @@ var ColorInputSchema = discriminatedUnion("mode", [
58380
58842
  }),
58381
58843
  object({
58382
58844
  mode: literal("mired"),
58383
- mireds: number().int().min(50).max(1e3)
58845
+ colorTemperature: number().int().min(50).max(1e3)
58384
58846
  })
58385
58847
  ]);
58386
58848
  var ColorStatusSchema = object({
58387
- /** Active color mode — which of `rgb` / `hsv` / `mireds` reflects
58849
+ /** Active color mode — which of `rgb` / `hsv` / `colorTemperature` reflects
58388
58850
  * the bulb's current state. */
58389
58851
  mode: _enum([
58390
58852
  "rgb",
@@ -58396,7 +58858,7 @@ var ColorStatusSchema = object({
58396
58858
  /** Populated when `mode === 'hsv'`. */
58397
58859
  hsv: HsvTripletSchema.optional(),
58398
58860
  /** Populated when `mode === 'mired'`. */
58399
- mireds: number().int().optional().meta(readingMeta("colour-temperature")),
58861
+ colorTemperature: number().int().optional().meta(readingMeta("colour-temperature")),
58400
58862
  /** Ms epoch of the last operator-driven change. */
58401
58863
  lastChangedAt: number()
58402
58864
  });
@@ -58428,7 +58890,7 @@ onColorChanged: { data: object({
58428
58890
  ]),
58429
58891
  rgb: RgbTripletSchema.optional(),
58430
58892
  hsv: HsvTripletSchema.optional(),
58431
- mireds: number().int().optional(),
58893
+ colorTemperature: number().int().optional(),
58432
58894
  lastChangedAt: number()
58433
58895
  }) } },
58434
58896
  status: {
@@ -59305,11 +59767,11 @@ var DishwasherStatusSchema = object({
59305
59767
  /** Feature keys of the programs the appliance currently offers — drives the UI selector. */
59306
59768
  availablePrograms: array(string()),
59307
59769
  /** Seconds remaining on the active cycle, or null when not running / not known. */
59308
- remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
59770
+ remaining: number().int().nonnegative().nullable().meta(readingMeta("duration")),
59309
59771
  /** Seconds the delayed start is set to (time until the cycle starts), or null. */
59310
- delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
59772
+ delayedStart: number().int().nonnegative().nullable().meta(readingMeta("duration")),
59311
59773
  /** Cycle completion 0..100, or null when not applicable. */
59312
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
59774
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
59313
59775
  /** True when the door is reported open; null when the door state is not known. */
59314
59776
  doorOpen: boolean().nullable(),
59315
59777
  /** True when the door is latched (locked) during a cycle; null when not reported. */
@@ -59528,14 +59990,14 @@ var dishwasherCapability = {
59528
59990
  runtimeState: DishwasherStatusSchema,
59529
59991
  durability: "session",
59530
59992
  history: { fields: {
59531
- progressPercent: {
59993
+ progress: {
59532
59994
  kind: "gauge",
59533
59995
  unit: "%",
59534
59996
  deadband: 2
59535
59997
  },
59536
59998
  state: { kind: "enum" },
59537
59999
  operationState: { kind: "enum" },
59538
- remainingSeconds: {
60000
+ remaining: {
59539
60001
  kind: "gauge",
59540
60002
  unit: "s",
59541
60003
  minIntervalMs: 6e4
@@ -60126,7 +60588,7 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
60126
60588
  var FanControlStatusSchema = object({
60127
60589
  /** Active speed as 0..100 inclusive. Null when the device has no
60128
60590
  * speed surface (single-speed fan). */
60129
- percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
60591
+ speed: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
60130
60592
  /** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
60131
60593
  * a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
60132
60594
  percentageStep: number().positive().optional().meta(readingMeta("percentage")),
@@ -60153,7 +60615,7 @@ var fanControlCapability = {
60153
60615
  methods: {
60154
60616
  setPercentage: method(object({
60155
60617
  deviceId: number().int().nonnegative(),
60156
- percentage: number().min(0).max(100)
60618
+ speed: number().min(0).max(100)
60157
60619
  }), _void(), {
60158
60620
  kind: "mutation",
60159
60621
  auth: "protected"
@@ -60186,7 +60648,7 @@ var fanControlCapability = {
60186
60648
  },
60187
60649
  /**
60188
60650
  * Runtime-state slice — mirrored by the kernel. UI fan speed
60189
- * sliders read `percentage` for live updates.
60651
+ * sliders read `speed` for live updates.
60190
60652
  */
60191
60653
  runtimeState: FanControlStatusSchema,
60192
60654
  /**
@@ -60200,7 +60662,7 @@ var fanControlCapability = {
60200
60662
  * History (D850): recorded series. Actuator tier: speed keeps every change.
60201
60663
  */
60202
60664
  history: { fields: {
60203
- percentage: {
60665
+ speed: {
60204
60666
  kind: "gauge",
60205
60667
  unit: "%",
60206
60668
  minIntervalMs: 0
@@ -60645,7 +61107,7 @@ var humidifierCapability = {
60645
61107
  */
60646
61108
  var HumiditySensorStatusSchema = object({
60647
61109
  /** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
60648
- percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
61110
+ humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
60649
61111
  precision: 0,
60650
61112
  label: "Humidity"
60651
61113
  })),
@@ -60674,7 +61136,7 @@ var humiditySensorCapability = {
60674
61136
  /**
60675
61137
  * History (D850): recorded series.
60676
61138
  */
60677
- history: { fields: { percent: {
61139
+ history: { fields: { humidity: {
60678
61140
  kind: "gauge",
60679
61141
  unit: "%",
60680
61142
  deadband: .5
@@ -61314,7 +61776,7 @@ var LawnMowerControlStatusSchema = object({
61314
61776
  batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61315
61777
  /** 0..100 mowing-completion percentage of the current task, or null when no
61316
61778
  * task is active / progress is unavailable. */
61317
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61779
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61318
61780
  /** Current device/event code (dynamic — mostly status, sometimes an error),
61319
61781
  * or null when unknown. */
61320
61782
  currentCode: number().nullable().meta(readingMeta("none")),
@@ -61814,7 +62276,7 @@ var lockControlCapability = {
61814
62276
  volatileStateFields: ["lastChangedAt"]
61815
62277
  };
61816
62278
  /**
61817
- * A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
62279
+ * A monotonic total between resets (D944). Energy uses `power-meter.energy`
61818
62280
  * so dashboards keep one series; every other instantaneous reading lands here.
61819
62281
  * `value` is the time integral in the source quantity's accumulated base
61820
62282
  * (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
@@ -61908,10 +62370,10 @@ var MediaPlayerStatusSchema = object({
61908
62370
  currentMedia: MediaInfoSchema.nullable(),
61909
62371
  /** Current playback position in ms. Null when not seekable or
61910
62372
  * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
61911
- positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
62373
+ position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
61912
62374
  /** Total duration of the current media in ms. Null when unknown
61913
62375
  * (live stream) or nothing is playing. */
61914
- durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
62376
+ duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
61915
62377
  /** Shuffle toggle. Null when no shuffle surface.
61916
62378
  * Pair with `DeviceFeature.MediaPlayerShuffle`. */
61917
62379
  shuffle: boolean().nullable(),
@@ -61950,7 +62412,7 @@ var mediaPlayerCapability = {
61950
62412
  }),
61951
62413
  seek: method(object({
61952
62414
  deviceId: number().int().nonnegative(),
61953
- positionMs: number().int().nonnegative()
62415
+ position: number().int().nonnegative()
61954
62416
  }), _void(), {
61955
62417
  kind: "mutation",
61956
62418
  auth: "protected"
@@ -62022,7 +62484,7 @@ var mediaPlayerCapability = {
62022
62484
  /**
62023
62485
  * History (D850): volume (a level an operator or an automation sets; the
62024
62486
  * default 10 s floor folds a slider drag into its end value) and mute.
62025
- * `positionMs` is not recorded: it moves continuously while playing.
62487
+ * `position` is not recorded: it moves continuously while playing.
62026
62488
  */
62027
62489
  history: { fields: {
62028
62490
  volumeLevel: {
@@ -62984,9 +63446,9 @@ var NetworkLinkStatusSchema = object({
62984
63446
  * one whose reading has not landed must not be drawn at 0 %. Consumers
62985
63447
  * SKIP a null rather than coerce it.
62986
63448
  */
62987
- signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
63449
+ signal: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
62988
63450
  /** Raw received signal strength in dBm, when the firmware reports one. */
62989
- rssiDbm: number().optional().meta(readingMeta("signal-level")),
63451
+ rssi: number().optional().meta(readingMeta("signal-level")),
62990
63452
  /** Network name of a wireless link, when the firmware reports it. */
62991
63453
  ssid: string().optional(),
62992
63454
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
@@ -63022,7 +63484,7 @@ onStatusChanged: { data: object({
63022
63484
  kind: "push",
63023
63485
  empty: {
63024
63486
  type: "unknown",
63025
- signalPercent: null,
63487
+ signal: null,
63026
63488
  lastUpdated: 0
63027
63489
  }
63028
63490
  },
@@ -63045,13 +63507,13 @@ onStatusChanged: { data: object({
63045
63507
  * History (D850): recorded series.
63046
63508
  */
63047
63509
  history: { fields: {
63048
- signalPercent: {
63510
+ signal: {
63049
63511
  kind: "gauge",
63050
63512
  unit: "%",
63051
63513
  deadband: 3,
63052
63514
  minIntervalMs: 6e4
63053
63515
  },
63054
- rssiDbm: {
63516
+ rssi: {
63055
63517
  kind: "gauge",
63056
63518
  unit: "dBm",
63057
63519
  deadband: 2,
@@ -63796,10 +64258,20 @@ var PetFeederDeviceStatusSchema = _enum([
63796
64258
  ]);
63797
64259
  var gramsPortion = number().int().min(4).max(200);
63798
64260
  var PetFeederStatusSchema = object({
63799
- /** Food currently in the bowl (grams). Null when the device has not
63800
- * reported a reading yet. On dual-hopper models this is the combined
63801
- * bowl reading; per-hopper levels live in `food1`/`food2`. */
64261
+ /** Food in the TANK (hopper), as the feeder's own sensor reports it
64262
+ * (`state.food`). A coarse level code, not grams — `0` is empty. The
64263
+ * amount in the bowl is `bowlFood`. On dual-hopper models this is the
64264
+ * combined reading; per-hopper levels live in `food1`/`food2`. Null when
64265
+ * the device has not reported yet. */
63802
64266
  foodLevel: number().nullable().meta(readingMeta("none")),
64267
+ /** Food in the BOWL as the feeder reports it (`state.bowl`), in the
64268
+ * feeder's own units. Null when the model reports none. */
64269
+ bowlFood: number().nullable().meta(readingMeta("none")),
64270
+ /** True while the pet is eating (`state.eating`). */
64271
+ eating: boolean(),
64272
+ /** Whether `markFoodReplenished` does anything on this model. When false
64273
+ * the client must not offer it. */
64274
+ supportsMarkRefilled: boolean(),
63803
64275
  /** Hopper-1 food level (grams) on dual-hopper feeders; null on
63804
64276
  * single-hopper models. */
63805
64277
  food1: number().nullable().meta(readingMeta("none")),
@@ -63807,8 +64279,8 @@ var PetFeederStatusSchema = object({
63807
64279
  * single-hopper models. */
63808
64280
  food2: number().nullable().meta(readingMeta("none")),
63809
64281
  /** Derived low-food flag — mirrors the HA `food_level` binary_sensor
63810
- * (`device_class: problem`, on = low). True when the bowl is empty /
63811
- * below the feeder's low threshold. */
64282
+ * (`device_class: problem`, on = low). True when the tank reports empty,
64283
+ * or, on a dual-hopper model, when EITHER hopper is empty. */
63812
64284
  lowFood: boolean(),
63813
64285
  /** Battery charge 0..100 (%). Null on mains-powered models or when the
63814
64286
  * device has no battery reading. */
@@ -63876,7 +64348,9 @@ var petFeederCapability = {
63876
64348
  kind: "mutation",
63877
64349
  auth: "protected"
63878
64350
  }),
63879
- /** Mark a hopper as refilled (D4H/D4S/D4SH). */
64351
+ /** Tell the PetKit cloud a hopper was refilled so it stops its low-food
64352
+ * reminders (D4H/D4S/D4SH only — see `supportsMarkRefilled`). It does not
64353
+ * change any sensor reading. */
63880
64354
  markFoodReplenished: method(object({ deviceId: number().int().nonnegative() }), _void(), {
63881
64355
  kind: "mutation",
63882
64356
  auth: "protected"
@@ -63949,6 +64423,7 @@ var petFeederCapability = {
63949
64423
  */
63950
64424
  history: { fields: {
63951
64425
  foodLevel: { kind: "gauge" },
64426
+ bowlFood: { kind: "gauge" },
63952
64427
  food1: { kind: "gauge" },
63953
64428
  food2: { kind: "gauge" },
63954
64429
  batteryPower: {
@@ -64358,16 +64833,16 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
64358
64833
  * in real-world devices.
64359
64834
  */
64360
64835
  var PowerMeterStatusSchema = object({
64361
- /** Instantaneous power draw in watts. */
64362
- watts: number().optional().meta(readingMeta("power", { label: "Power" })),
64836
+ /** Instantaneous power draw (watts). */
64837
+ power: number().optional().meta(readingMeta("power", { label: "Power" })),
64363
64838
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
64364
- kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
64365
- /** Voltage in volts. */
64366
- volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
64839
+ energy: number().optional().meta(readingMeta("energy", { label: "Energy" })),
64840
+ /** Voltage (volts). */
64841
+ voltage: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
64367
64842
  /** Current in amperes. */
64368
- amps: number().optional().meta(readingMeta("current", { label: "Current" })),
64843
+ current: number().optional().meta(readingMeta("current", { label: "Current" })),
64369
64844
  /** Apparent power in volt-amperes. */
64370
- va: number().optional().meta(readingMeta("apparent-power")),
64845
+ apparentPower: number().optional().meta(readingMeta("apparent-power")),
64371
64846
  /** Power factor (0..1) if reported. */
64372
64847
  powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
64373
64848
  /** Ms epoch when the slice was last updated. */
@@ -64425,14 +64900,14 @@ function powerTarget(id, unit) {
64425
64900
  advancedExpression: true
64426
64901
  };
64427
64902
  }
64428
- /** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
64903
+ /** "Power and energy" extension: power, energy, voltage and current from other devices (D951). */
64429
64904
  var powerMeterCustomize = {
64430
64905
  version: 1,
64431
64906
  targets: [
64432
- powerTarget("watts", "W"),
64433
- powerTarget("kwhTotal", "kWh"),
64434
- powerTarget("volts", "V"),
64435
- powerTarget("amps", "A")
64907
+ powerTarget("power", "W"),
64908
+ powerTarget("energy", "kWh"),
64909
+ powerTarget("voltage", "V"),
64910
+ powerTarget("current", "A")
64436
64911
  ]
64437
64912
  };
64438
64913
  var powerMeterCapability = {
@@ -64448,41 +64923,41 @@ var powerMeterCapability = {
64448
64923
  },
64449
64924
  runtimeState: PowerMeterStatusSchema,
64450
64925
  /**
64451
- * Runtime-state durability: **restored** — as `numeric-sensor`; `kwhTotal` is an accumulator whose restored value is the baseline.
64926
+ * Runtime-state durability: **restored** — as `numeric-sensor`; `energy` is an accumulator whose restored value is the baseline.
64452
64927
  *
64453
64928
  * See `RuntimeStateDurability`. Enforced by
64454
64929
  * `scripts/check-runtime-state-durability.ts`.
64455
64930
  */
64456
64931
  durability: "restored",
64457
64932
  /**
64458
- * History (D850): recorded series. Gauges are floored at 30 s; `kwhTotal` is the one monotonic meter (counter).
64933
+ * History (D850): recorded series. Gauges are floored at 30 s; `energy` is the one monotonic meter (counter).
64459
64934
  */
64460
64935
  history: { fields: {
64461
- watts: {
64936
+ power: {
64462
64937
  kind: "gauge",
64463
64938
  unit: "W",
64464
64939
  deadband: 1,
64465
64940
  minIntervalMs: 3e4
64466
64941
  },
64467
- kwhTotal: {
64942
+ energy: {
64468
64943
  kind: "counter",
64469
64944
  unit: "kWh",
64470
64945
  deadband: .01,
64471
64946
  minIntervalMs: 6e4
64472
64947
  },
64473
- volts: {
64948
+ voltage: {
64474
64949
  kind: "gauge",
64475
64950
  unit: "V",
64476
64951
  deadband: 1,
64477
64952
  minIntervalMs: 3e4
64478
64953
  },
64479
- amps: {
64954
+ current: {
64480
64955
  kind: "gauge",
64481
64956
  unit: "A",
64482
64957
  deadband: .05,
64483
64958
  minIntervalMs: 3e4
64484
64959
  },
64485
- va: {
64960
+ apparentPower: {
64486
64961
  kind: "gauge",
64487
64962
  unit: "VA",
64488
64963
  deadband: 1,
@@ -64532,9 +65007,6 @@ var PresenceStatusSchema = object({
64532
65007
  location: string().nullable(),
64533
65008
  /** GPS coordinates when available. Null otherwise. */
64534
65009
  gps: GpsLocationSchema.nullable(),
64535
- /** Optional battery level of the tracking device (0..100). Null
64536
- * when not reported. */
64537
- batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64538
65010
  /** Ms epoch when the slice was last updated. */
64539
65011
  lastChangedAt: number()
64540
65012
  });
@@ -64563,14 +65035,7 @@ var presenceCapability = {
64563
65035
  * `scripts/check-runtime-state-durability.ts`.
64564
65036
  */
64565
65037
  durability: "restored",
64566
- /**
64567
- * History (D850): recorded series.
64568
- */
64569
- history: { fields: { batteryPercent: {
64570
- kind: "gauge",
64571
- unit: "%",
64572
- deadband: 1
64573
- } } },
65038
+ history: "none",
64574
65039
  /** Clock fields: written, but excluded from the compare that decides
64575
65040
  * whether persisting is worth a SQLite commit. */
64576
65041
  volatileStateFields: ["lastChangedAt"]
@@ -64585,7 +65050,7 @@ var presenceCapability = {
64585
65050
  */
64586
65051
  var PressureSensorStatusSchema = object({
64587
65052
  /** Current pressure in hPa. `null` when the sample was refused (D393). */
64588
- hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
65053
+ pressure: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
64589
65054
  /** Ms epoch when the slice was last updated. */
64590
65055
  lastFetchedAt: number()
64591
65056
  });
@@ -64611,7 +65076,7 @@ var pressureSensorCapability = {
64611
65076
  /**
64612
65077
  * History (D850): recorded series.
64613
65078
  */
64614
- history: { fields: { hpa: {
65079
+ history: { fields: { pressure: {
64615
65080
  kind: "gauge",
64616
65081
  unit: "hPa",
64617
65082
  deadband: .1
@@ -68310,7 +68775,7 @@ var tamperCapability = {
68310
68775
  */
68311
68776
  var TemperatureSensorStatusSchema = object({
68312
68777
  /** Current temperature in Celsius. `null` when the sample was refused (D393). */
68313
- celsius: number().nullable().meta(readingMeta("temperature", {
68778
+ temperature: number().nullable().meta(readingMeta("temperature", {
68314
68779
  precision: 1,
68315
68780
  label: "Temperature"
68316
68781
  })),
@@ -68339,7 +68804,7 @@ var temperatureSensorCapability = {
68339
68804
  /**
68340
68805
  * History (D850): recorded series.
68341
68806
  */
68342
- history: { fields: { celsius: {
68807
+ history: { fields: { temperature: {
68343
68808
  kind: "gauge",
68344
68809
  unit: "°C",
68345
68810
  deadband: .1
@@ -68636,7 +69101,7 @@ var VacuumControlStatusSchema = object({
68636
69101
  /** Speed tokens the hardware accepts — drives the UI selector. */
68637
69102
  availableFanSpeeds: array(string()),
68638
69103
  /** 0..100 cleaning-completion percentage of the current task, or null. */
68639
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
69104
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
68640
69105
  /** Current error code (0 / null = no error). */
68641
69106
  errorCode: number().nullable().meta(readingMeta("none")),
68642
69107
  /** Human label for {@link errorCode}, or null when none / undecodable. */
@@ -70269,7 +70734,7 @@ function tryConvertUnit(value, from, to) {
70269
70734
  return fromCanonical(toCanonical(value, fromSpec), toSpec);
70270
70735
  }
70271
70736
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
70272
- DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
70737
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
70273
70738
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
70274
70739
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
70275
70740
  new Set(CAP_NAMES);
@@ -70673,7 +71138,7 @@ var BaseDevice = class {
70673
71138
  * `device-local-state.ts`. Drivers access via:
70674
71139
  *
70675
71140
  * `this.state.battery.sleeping = true` // patches the battery slice
70676
- * `const pct = this.state.battery.percentage` // reads the battery slice
71141
+ * `const pct = this.state.battery.level` // reads the battery slice
70677
71142
  * `this.state.deviceStatus.online = true` // mirrors `markOnline(true)`
70678
71143
  *
70679
71144
  * Adding a new cap with `runtimeState:` automatically extends this
@@ -70713,7 +71178,7 @@ var BaseDevice = class {
70713
71178
  * shape; drivers don't redeclare it, they just write through.
70714
71179
  *
70715
71180
  * Read: `this.runtimeState.getCapState('battery')` →
70716
- * `{percentage, charging, sleeping, lastUpdated}` for any
71181
+ * `{level, charging, sleeping, lastUpdated}` for any
70717
71182
  * provider that registers `batteryCapability`.
70718
71183
  * Write: `this.runtimeState.setCapState('battery', { … })`.
70719
71184
  *
@@ -71887,6 +72352,104 @@ Object.freeze({
71887
72352
  access: "create",
71888
72353
  role: "admin"
71889
72354
  },
72355
+ "actions.create": {
72356
+ capName: "actions",
72357
+ capScope: "system",
72358
+ addonId: null,
72359
+ access: "create",
72360
+ role: "admin"
72361
+ },
72362
+ "actions.delete": {
72363
+ capName: "actions",
72364
+ capScope: "system",
72365
+ addonId: null,
72366
+ access: "delete",
72367
+ role: "admin"
72368
+ },
72369
+ "actions.get": {
72370
+ capName: "actions",
72371
+ capScope: "system",
72372
+ addonId: null,
72373
+ access: "view",
72374
+ role: "viewer"
72375
+ },
72376
+ "actions.getLinks": {
72377
+ capName: "actions",
72378
+ capScope: "system",
72379
+ addonId: null,
72380
+ access: "view",
72381
+ role: "admin"
72382
+ },
72383
+ "actions.getTraces": {
72384
+ capName: "actions",
72385
+ capScope: "system",
72386
+ addonId: null,
72387
+ access: "view",
72388
+ role: "admin"
72389
+ },
72390
+ "actions.list": {
72391
+ capName: "actions",
72392
+ capScope: "system",
72393
+ addonId: null,
72394
+ access: "view",
72395
+ role: "admin"
72396
+ },
72397
+ "actions.listForCamera": {
72398
+ capName: "actions",
72399
+ capScope: "system",
72400
+ addonId: null,
72401
+ access: "view",
72402
+ role: "viewer"
72403
+ },
72404
+ "actions.run": {
72405
+ capName: "actions",
72406
+ capScope: "system",
72407
+ addonId: null,
72408
+ access: "create",
72409
+ role: "viewer"
72410
+ },
72411
+ "actions.setLinks": {
72412
+ capName: "actions",
72413
+ capScope: "system",
72414
+ addonId: null,
72415
+ access: "create",
72416
+ role: "admin"
72417
+ },
72418
+ "actions.stop": {
72419
+ capName: "actions",
72420
+ capScope: "system",
72421
+ addonId: null,
72422
+ access: "create",
72423
+ role: "admin"
72424
+ },
72425
+ "actions.update": {
72426
+ capName: "actions",
72427
+ capScope: "system",
72428
+ addonId: null,
72429
+ access: "create",
72430
+ role: "admin"
72431
+ },
72432
+ "actionSource.listActions": {
72433
+ capName: "action-source",
72434
+ capScope: "system",
72435
+ addonId: null,
72436
+ access: "view",
72437
+ role: "admin"
72438
+ },
72439
+ "actionSource.runAction": {
72440
+ capName: "action-source",
72441
+ capScope: "system",
72442
+ addonId: null,
72443
+ access: "create",
72444
+ role: "admin"
72445
+ },
72446
+ "actionSource.stopAction": {
72447
+ capName: "action-source",
72448
+ capScope: "system",
72449
+ addonId: null,
72450
+ access: "create",
72451
+ role: "admin"
72452
+ },
71890
72453
  "addonPages.listPages": {
71891
72454
  capName: "addon-pages",
71892
72455
  capScope: "system",
@@ -73168,6 +73731,13 @@ Object.freeze({
73168
73731
  access: "view",
73169
73732
  role: "admin"
73170
73733
  },
73734
+ "coreBlocks.getAutomationRunState": {
73735
+ capName: "core-blocks",
73736
+ capScope: "system",
73737
+ addonId: null,
73738
+ access: "view",
73739
+ role: "admin"
73740
+ },
73171
73741
  "coreBlocks.getBlockSettings": {
73172
73742
  capName: "core-blocks",
73173
73743
  capScope: "system",
@@ -73189,6 +73759,13 @@ Object.freeze({
73189
73759
  access: "view",
73190
73760
  role: "admin"
73191
73761
  },
73762
+ "coreBlocks.getTraces": {
73763
+ capName: "core-blocks",
73764
+ capScope: "system",
73765
+ addonId: null,
73766
+ access: "view",
73767
+ role: "admin"
73768
+ },
73192
73769
  "coreBlocks.getTypeDefs": {
73193
73770
  capName: "core-blocks",
73194
73771
  capScope: "system",
@@ -73224,6 +73801,13 @@ Object.freeze({
73224
73801
  access: "create",
73225
73802
  role: "admin"
73226
73803
  },
73804
+ "coreBlocks.reportAutomationRun": {
73805
+ capName: "core-blocks",
73806
+ capScope: "system",
73807
+ addonId: null,
73808
+ access: "create",
73809
+ role: "admin"
73810
+ },
73227
73811
  "coreBlocks.restart": {
73228
73812
  capName: "core-blocks",
73229
73813
  capScope: "system",
@@ -81797,7 +82381,7 @@ var ACTUATOR_CAP_VOCABULARY = {
81797
82381
  label: t("Full brightness", "Luminosità massima"),
81798
82382
  phrase: t("Set {device} to full brightness", "Porta {device} alla massima luminosità"),
81799
82383
  icon: "sun",
81800
- args: { percentage: 100 }
82384
+ args: { level: 100 }
81801
82385
  },
81802
82386
  {
81803
82387
  id: "brightness.half",
@@ -81805,7 +82389,7 @@ var ACTUATOR_CAP_VOCABULARY = {
81805
82389
  label: t("Half brightness", "Luminosità a metà"),
81806
82390
  phrase: t("Dim {device} to half", "Abbassa {device} a metà luminosità"),
81807
82391
  icon: "sun-dim",
81808
- args: { percentage: 50 }
82392
+ args: { level: 50 }
81809
82393
  },
81810
82394
  {
81811
82395
  id: "brightness.off",
@@ -81813,16 +82397,16 @@ var ACTUATOR_CAP_VOCABULARY = {
81813
82397
  label: t("Brightness off", "Luminosità a zero"),
81814
82398
  phrase: t("Dim {device} to zero", "Abbassa {device} a zero"),
81815
82399
  icon: "lightbulb-off",
81816
- args: { percentage: 0 }
82400
+ args: { level: 0 }
81817
82401
  },
81818
82402
  {
81819
82403
  id: "brightness.set",
81820
82404
  method: "setBrightness",
81821
82405
  label: t("Set brightness", "Imposta la luminosità"),
81822
- phrase: t("Set the brightness of {device} to {percentage}", "Imposta la luminosità di {device} a {percentage}"),
82406
+ phrase: t("Set the brightness of {device} to {level}", "Imposta la luminosità di {device} a {level}"),
81823
82407
  icon: "sun-medium",
81824
82408
  openArgs: [{
81825
- key: "percentage",
82409
+ key: "level",
81826
82410
  label: PERCENT,
81827
82411
  offer: {
81828
82412
  kind: "number",
@@ -81836,13 +82420,13 @@ var ACTUATOR_CAP_VOCABULARY = {
81836
82420
  ],
81837
82421
  state: [{
81838
82422
  kind: "numeric",
81839
- field: "percentage",
82423
+ field: "level",
81840
82424
  quantity: t("the brightness", "la luminosità"),
81841
82425
  label: t("Brightness", "Luminosità"),
81842
82426
  unit: "%",
81843
82427
  icon: "sun"
81844
82428
  }],
81845
- events: { onBrightnessChanged: { notOperatorFacing: "the `percentage` state trigger reads the same change" } }
82429
+ events: { onBrightnessChanged: { notOperatorFacing: "the `level` state trigger reads the same change" } }
81846
82430
  },
81847
82431
  color: {
81848
82432
  scope: "device",
@@ -81856,7 +82440,7 @@ var ACTUATOR_CAP_VOCABULARY = {
81856
82440
  icon: "sun",
81857
82441
  args: { color: {
81858
82442
  mode: "mired",
81859
- mireds: 370
82443
+ colorTemperature: 370
81860
82444
  } }
81861
82445
  },
81862
82446
  {
@@ -81867,7 +82451,7 @@ var ACTUATOR_CAP_VOCABULARY = {
81867
82451
  icon: "snowflake",
81868
82452
  args: { color: {
81869
82453
  mode: "mired",
81870
- mireds: 200
82454
+ colorTemperature: 200
81871
82455
  } }
81872
82456
  },
81873
82457
  {
@@ -82481,7 +83065,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82481
83065
  label: t("Fan off", "Ventilatore spento"),
82482
83066
  phrase: t("Stop {device}", "Ferma {device}"),
82483
83067
  icon: "power-off",
82484
- args: { percentage: 0 }
83068
+ args: { speed: 0 }
82485
83069
  },
82486
83070
  {
82487
83071
  id: "fan.full",
@@ -82489,16 +83073,16 @@ var ACTUATOR_CAP_VOCABULARY = {
82489
83073
  label: t("Fan full", "Ventilatore al massimo"),
82490
83074
  phrase: t("Run {device} at full speed", "Porta {device} alla massima velocità"),
82491
83075
  icon: "fan",
82492
- args: { percentage: 100 }
83076
+ args: { speed: 100 }
82493
83077
  },
82494
83078
  {
82495
83079
  id: "fan.speed",
82496
83080
  method: "setPercentage",
82497
83081
  label: t("Set speed", "Imposta la velocità"),
82498
- phrase: t("Set the speed of {device} to {percentage}", "Imposta la velocità di {device} al {percentage}"),
83082
+ phrase: t("Set the speed of {device} to {speed}", "Imposta la velocità di {device} al {speed}"),
82499
83083
  icon: "fan",
82500
83084
  openArgs: [{
82501
- key: "percentage",
83085
+ key: "speed",
82502
83086
  label: t("Speed", "Velocità"),
82503
83087
  offer: {
82504
83088
  kind: "number",
@@ -82560,7 +83144,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82560
83144
  ],
82561
83145
  state: [{
82562
83146
  kind: "numeric",
82563
- field: "percentage",
83147
+ field: "speed",
82564
83148
  quantity: t("the speed", "la velocità"),
82565
83149
  label: t("Speed", "Velocità"),
82566
83150
  unit: "%",
@@ -83358,7 +83942,7 @@ var APPLIANCE_CAP_VOCABULARY = {
83358
83942
  },
83359
83943
  {
83360
83944
  kind: "numeric",
83361
- field: "progressPercent",
83945
+ field: "progress",
83362
83946
  quantity: t("the cycle progress", "l’avanzamento del lavaggio"),
83363
83947
  label: t("Progress", "Avanzamento"),
83364
83948
  unit: "%",
@@ -83716,10 +84300,10 @@ var APPLIANCE_CAP_VOCABULARY = {
83716
84300
  id: "media.seek",
83717
84301
  method: "seek",
83718
84302
  label: t("Seek", "Vai al punto"),
83719
- phrase: t("Move {device} to {positionMs}", "Porta {device} al punto {positionMs}"),
84303
+ phrase: t("Move {device} to {position}", "Porta {device} al punto {position}"),
83720
84304
  icon: "fast-forward",
83721
84305
  openArgs: [{
83722
- key: "positionMs",
84306
+ key: "position",
83723
84307
  label: t("Position", "Posizione"),
83724
84308
  offer: {
83725
84309
  kind: "number",
@@ -84768,7 +85352,7 @@ var SENSOR_CAP_VOCABULARY = {
84768
85352
  state: [
84769
85353
  {
84770
85354
  kind: "numeric",
84771
- field: "co2Ppm",
85355
+ field: "co2",
84772
85356
  quantity: t("the CO₂", "la CO₂"),
84773
85357
  label: t("CO₂", "CO₂"),
84774
85358
  unit: "ppm",
@@ -84776,7 +85360,7 @@ var SENSOR_CAP_VOCABULARY = {
84776
85360
  },
84777
85361
  {
84778
85362
  kind: "numeric",
84779
- field: "vocPpb",
85363
+ field: "voc",
84780
85364
  quantity: t("the VOC level", "il livello di COV"),
84781
85365
  label: t("VOC", "COV"),
84782
85366
  unit: "ppb",
@@ -84812,7 +85396,7 @@ var SENSOR_CAP_VOCABULARY = {
84812
85396
  noun: t("Light level", "Luminosità ambiente"),
84813
85397
  state: [{
84814
85398
  kind: "numeric",
84815
- field: "lux",
85399
+ field: "illuminance",
84816
85400
  quantity: t("the light level", "la luminosità"),
84817
85401
  label: t("Illuminance", "Illuminamento"),
84818
85402
  unit: "lx",
@@ -85015,7 +85599,7 @@ var SENSOR_CAP_VOCABULARY = {
85015
85599
  noun: t("Humidity", "Umidità"),
85016
85600
  state: [{
85017
85601
  kind: "numeric",
85018
- field: "percent",
85602
+ field: "humidity",
85019
85603
  quantity: t("the humidity", "l’umidità"),
85020
85604
  label: t("Humidity", "Umidità"),
85021
85605
  unit: "%",
@@ -85063,7 +85647,7 @@ var SENSOR_CAP_VOCABULARY = {
85063
85647
  state: [
85064
85648
  {
85065
85649
  kind: "numeric",
85066
- field: "watts",
85650
+ field: "power",
85067
85651
  quantity: t("the power draw", "il consumo"),
85068
85652
  label: t("Power", "Potenza"),
85069
85653
  unit: "W",
@@ -85071,7 +85655,7 @@ var SENSOR_CAP_VOCABULARY = {
85071
85655
  },
85072
85656
  {
85073
85657
  kind: "numeric",
85074
- field: "kwhTotal",
85658
+ field: "energy",
85075
85659
  quantity: t("the energy used", "l’energia consumata"),
85076
85660
  label: t("Energy", "Energia"),
85077
85661
  unit: "kWh",
@@ -85079,7 +85663,7 @@ var SENSOR_CAP_VOCABULARY = {
85079
85663
  },
85080
85664
  {
85081
85665
  kind: "numeric",
85082
- field: "volts",
85666
+ field: "voltage",
85083
85667
  quantity: t("the voltage", "la tensione"),
85084
85668
  label: t("Voltage", "Tensione"),
85085
85669
  unit: "V",
@@ -85087,7 +85671,7 @@ var SENSOR_CAP_VOCABULARY = {
85087
85671
  },
85088
85672
  {
85089
85673
  kind: "numeric",
85090
- field: "amps",
85674
+ field: "current",
85091
85675
  quantity: t("the current", "la corrente"),
85092
85676
  label: t("Current", "Corrente"),
85093
85677
  unit: "A",
@@ -85104,13 +85688,6 @@ var SENSOR_CAP_VOCABULARY = {
85104
85688
  label: t("Where", "Posizione"),
85105
85689
  phrase: t("When {device} is at {value}", "Quando {device} è in {value}"),
85106
85690
  icon: "map-pin"
85107
- }, {
85108
- kind: "numeric",
85109
- field: "batteryPercent",
85110
- quantity: t("the phone battery", "la batteria del telefono"),
85111
- label: t("Battery", "Batteria"),
85112
- unit: "%",
85113
- icon: "battery"
85114
85691
  }]
85115
85692
  },
85116
85693
  "pressure-sensor": {
@@ -85118,7 +85695,7 @@ var SENSOR_CAP_VOCABULARY = {
85118
85695
  noun: t("Pressure", "Pressione"),
85119
85696
  state: [{
85120
85697
  kind: "numeric",
85121
- field: "hpa",
85698
+ field: "pressure",
85122
85699
  quantity: t("the pressure", "la pressione"),
85123
85700
  label: t("Pressure", "Pressione"),
85124
85701
  unit: "hPa",
@@ -85154,7 +85731,7 @@ var SENSOR_CAP_VOCABULARY = {
85154
85731
  noun: t("Temperature", "Temperatura"),
85155
85732
  state: [{
85156
85733
  kind: "numeric",
85157
- field: "celsius",
85734
+ field: "temperature",
85158
85735
  quantity: t("the temperature", "la temperatura"),
85159
85736
  label: t("Temperature", "Temperatura"),
85160
85737
  unit: "°C",
@@ -85225,7 +85802,7 @@ var SENSOR_CAP_VOCABULARY = {
85225
85802
  state: [
85226
85803
  {
85227
85804
  kind: "numeric",
85228
- field: "percentage",
85805
+ field: "level",
85229
85806
  quantity: t("the battery level", "il livello della batteria"),
85230
85807
  label: t("Battery", "Batteria"),
85231
85808
  unit: "%",
@@ -85267,7 +85844,7 @@ var SENSOR_CAP_VOCABULARY = {
85267
85844
  icon: "battery-charging"
85268
85845
  }
85269
85846
  ],
85270
- events: { onStatusChanged: { notOperatorFacing: "the percentage / sleeping / charging state triggers each read one field of this change" } },
85847
+ events: { onStatusChanged: { notOperatorFacing: "the level / sleeping / charging state triggers each read one field of this change" } },
85271
85848
  extraEvents: [{
85272
85849
  category: EventCategory.DeviceAwake,
85273
85850
  label: t("Woke up", "Risvegliato"),
@@ -85285,7 +85862,7 @@ var SENSOR_CAP_VOCABULARY = {
85285
85862
  noun: t("Network link", "Collegamento di rete"),
85286
85863
  state: [{
85287
85864
  kind: "numeric",
85288
- field: "signalPercent",
85865
+ field: "signal",
85289
85866
  quantity: t("the signal strength", "l’intensità del segnale"),
85290
85867
  label: t("Signal", "Segnale"),
85291
85868
  unit: "%",
@@ -85378,6 +85955,8 @@ var ML = "model and training machinery — no device action";
85378
85955
  var INTERNAL = "internal plumbing between addons — never operator-facing";
85379
85956
  /** Every system-scoped cap, with why it is not a device's vocabulary. */
85380
85957
  var SYSTEM_CAP_VOCABULARY = {
85958
+ "action-source": system(INTERNAL),
85959
+ actions: system("declared actions — run from the Actions page and from the cameras that link them"),
85381
85960
  "addon-pages": system(UI_PLUMBING),
85382
85961
  "addon-pages-source": system(UI_PLUMBING),
85383
85962
  "addon-routes": system(UI_PLUMBING),
@@ -85574,6 +86153,31 @@ Object.freeze({
85574
86153
  form: "single",
85575
86154
  optional: false
85576
86155
  }],
86156
+ "actions.get": [{
86157
+ name: "deviceId",
86158
+ form: "single",
86159
+ optional: true
86160
+ }],
86161
+ "actions.getLinks": [{
86162
+ name: "deviceId",
86163
+ form: "single",
86164
+ optional: false
86165
+ }],
86166
+ "actions.listForCamera": [{
86167
+ name: "deviceId",
86168
+ form: "single",
86169
+ optional: false
86170
+ }],
86171
+ "actions.run": [{
86172
+ name: "deviceId",
86173
+ form: "single",
86174
+ optional: true
86175
+ }],
86176
+ "actions.setLinks": [{
86177
+ name: "deviceId",
86178
+ form: "single",
86179
+ optional: false
86180
+ }],
85577
86181
  "addonSettings.getDeviceSettings": [{
85578
86182
  name: "deviceId",
85579
86183
  form: "single",
@@ -89698,6 +90302,7 @@ function ingestReading(input) {
89698
90302
  value: converted
89699
90303
  };
89700
90304
  }
90305
+ String.raw`(?<=^|["'(\s>,\[{])`;
89701
90306
  var MB = 1024 * 1024;
89702
90307
  1024 * MB, 3072 * MB;
89703
90308
  //#endregion
@@ -89932,7 +90537,7 @@ var point = (quantity, ...sources) => ({
89932
90537
  * What an Enpal box can show, by the dotted keys its InfluxDB and device page use (the
89933
90538
  * names follow the Home Assistant component's key table). A device is offered only when the
89934
90539
  * box reported at least one of its points, so a box without a heat pump has no heat-pump
89935
- * devices. Lifetime energy rides `power-meter.kwhTotal` where a power reading sits beside it
90540
+ * devices. Lifetime energy rides `power-meter.energy` where a power reading sits beside it
89936
90541
  * and the `meter` cap where it does not (D944).
89937
90542
  */
89938
90543
  var ENPAL_SPECS = [
@@ -89941,7 +90546,7 @@ var ENPAL_SPECS = [
89941
90546
  id: "pv",
89942
90547
  name: "Production",
89943
90548
  role: DeviceRole.PowerSensor,
89944
- watts: point("power", "Power.DC.Total", "Power.DC.Total.Calculated", "Power.DC.Total.Huawei", "Power.Production.Total"),
90549
+ power: point("power", "Power.DC.Total", "Power.DC.Total.Calculated", "Power.DC.Total.Huawei", "Power.Production.Total"),
89945
90550
  kwh: point("energy", "Energy.Production.Total.Lifetime")
89946
90551
  },
89947
90552
  {
@@ -89951,9 +90556,9 @@ var ENPAL_SPECS = [
89951
90556
  role: DeviceRole.BatterySensor,
89952
90557
  level: point("percentage", "Energy.Battery.Charge.Level"),
89953
90558
  capacity: point("energy", "Energy.Battery.Capacity"),
89954
- watts: point("power", "Power.Battery.Charge.Discharge"),
89955
- volts: point("voltage", "Voltage.Battery"),
89956
- amps: point("current", "Current.Battery")
90559
+ power: point("power", "Power.Battery.Charge.Discharge"),
90560
+ voltage: point("voltage", "Voltage.Battery"),
90561
+ current: point("current", "Current.Battery")
89957
90562
  },
89958
90563
  {
89959
90564
  kind: "meter",
@@ -89976,7 +90581,7 @@ var ENPAL_SPECS = [
89976
90581
  id: "grid-import",
89977
90582
  name: "Import",
89978
90583
  role: DeviceRole.PowerSensor,
89979
- watts: point("power", "Grid.Import.Power.Total.Calculated", {
90584
+ power: point("power", "Grid.Import.Power.Total.Calculated", {
89980
90585
  key: "Power.Grid.Export",
89981
90586
  part: "negative"
89982
90587
  }, {
@@ -89993,7 +90598,7 @@ var ENPAL_SPECS = [
89993
90598
  id: "grid-export",
89994
90599
  name: "Export",
89995
90600
  role: DeviceRole.PowerSensor,
89996
- watts: point("power", {
90601
+ power: point("power", {
89997
90602
  key: "Power.Grid.Export",
89998
90603
  part: "positive"
89999
90604
  }, {
@@ -90010,7 +90615,7 @@ var ENPAL_SPECS = [
90010
90615
  id: "house",
90011
90616
  name: "Consumption",
90012
90617
  role: DeviceRole.PowerSensor,
90013
- watts: point("power", "Power.Consumption.Total", "Power.Consumption.AC"),
90618
+ power: point("power", "Power.Consumption.Total", "Power.Consumption.AC"),
90014
90619
  kwh: point("energy", "Energy.Consumption.Total.Lifetime")
90015
90620
  },
90016
90621
  {
@@ -90018,7 +90623,7 @@ var ENPAL_SPECS = [
90018
90623
  id: "heatpump",
90019
90624
  name: "Consumption",
90020
90625
  role: DeviceRole.PowerSensor,
90021
- watts: point("power", "Heatpump.Power.Consumption.Total"),
90626
+ power: point("power", "Heatpump.Power.Consumption.Total"),
90022
90627
  kwh: point("energy", "Heatpump.Energy.Consumption.Total.Lifetime")
90023
90628
  },
90024
90629
  {
@@ -90076,12 +90681,12 @@ function capsOfSpec(spec) {
90076
90681
  }
90077
90682
  function pointsOf(spec) {
90078
90683
  switch (spec.kind) {
90079
- case "power-meter": return spec.kwh !== void 0 ? [spec.watts, spec.kwh] : [spec.watts];
90684
+ case "power-meter": return spec.kwh !== void 0 ? [spec.power, spec.kwh] : [spec.power];
90080
90685
  case "battery": return [
90081
90686
  spec.level,
90082
- spec.watts,
90083
- spec.volts,
90084
- spec.amps
90687
+ spec.power,
90688
+ spec.voltage,
90689
+ spec.current
90085
90690
  ];
90086
90691
  case "meter":
90087
90692
  case "numeric": return [spec.value];
@@ -90147,46 +90752,46 @@ function stateOfCharge(spec, snapshot) {
90147
90752
  function computeSlices(spec, snapshot, options, now) {
90148
90753
  switch (spec.kind) {
90149
90754
  case "power-meter": {
90150
- const watts = resolve(spec.watts, snapshot);
90755
+ const power = resolve(spec.power, snapshot);
90151
90756
  const kwh = spec.kwh !== void 0 ? resolve(spec.kwh, snapshot) : { state: "absent" };
90152
- const w = numberOf(watts);
90757
+ const w = numberOf(power);
90153
90758
  const e = numberOf(kwh);
90154
90759
  return {
90155
90760
  ...w !== void 0 || e !== void 0 ? { powerMeter: {
90156
- ...w !== void 0 ? { watts: w } : {},
90157
- ...e !== void 0 ? { kwhTotal: e } : {},
90761
+ ...w !== void 0 ? { power: w } : {},
90762
+ ...e !== void 0 ? { energy: e } : {},
90158
90763
  lastFetchedAt: now
90159
90764
  } } : {},
90160
- refusals: [...refusalOf(watts), ...refusalOf(kwh)]
90765
+ refusals: [...refusalOf(power), ...refusalOf(kwh)]
90161
90766
  };
90162
90767
  }
90163
90768
  case "battery": {
90164
90769
  const soc = stateOfCharge(spec, snapshot);
90165
- const watts = resolve(spec.watts, snapshot);
90166
- const volts = resolve(spec.volts, snapshot);
90167
- const amps = resolve(spec.amps, snapshot);
90770
+ const power = resolve(spec.power, snapshot);
90771
+ const voltage = resolve(spec.voltage, snapshot);
90772
+ const current = resolve(spec.current, snapshot);
90168
90773
  const sign = options.invertBatteryPower ? -1 : 1;
90169
- const w = numberOf(watts);
90170
- const v = numberOf(volts);
90171
- const a = numberOf(amps);
90774
+ const w = numberOf(power);
90775
+ const v = numberOf(voltage);
90776
+ const a = numberOf(current);
90172
90777
  return {
90173
90778
  battery: {
90174
- percentage: nullableOf(soc),
90779
+ level: nullableOf(soc),
90175
90780
  charging: "unknown",
90176
90781
  sleeping: false,
90177
90782
  lastUpdated: now
90178
90783
  },
90179
90784
  ...w !== void 0 || v !== void 0 || a !== void 0 ? { powerMeter: {
90180
- ...w !== void 0 ? { watts: w * sign || 0 } : {},
90181
- ...v !== void 0 ? { volts: v } : {},
90182
- ...a !== void 0 ? { amps: a * sign || 0 } : {},
90785
+ ...w !== void 0 ? { power: w * sign || 0 } : {},
90786
+ ...v !== void 0 ? { voltage: v } : {},
90787
+ ...a !== void 0 ? { current: a * sign || 0 } : {},
90183
90788
  lastFetchedAt: now
90184
90789
  } } : {},
90185
90790
  refusals: [
90186
90791
  ...refusalOf(soc),
90187
- ...refusalOf(watts),
90188
- ...refusalOf(volts),
90189
- ...refusalOf(amps)
90792
+ ...refusalOf(power),
90793
+ ...refusalOf(voltage),
90794
+ ...refusalOf(current)
90190
90795
  ]
90191
90796
  };
90192
90797
  }
@@ -90309,7 +90914,7 @@ var METER_CAP = meterCapability.name;
90309
90914
  var NUMERIC_CAP = numericSensorCapability.name;
90310
90915
  var POWER_COLD = { lastFetchedAt: 0 };
90311
90916
  var BATTERY_COLD = {
90312
- percentage: null,
90917
+ level: null,
90313
90918
  charging: "unknown",
90314
90919
  sleeping: false,
90315
90920
  lastUpdated: 0
@@ -90398,10 +91003,10 @@ var EnpalSensorDevice = class extends BaseDevice {
90398
91003
  }
90399
91004
  publish(slices) {
90400
91005
  if (slices.powerMeter !== void 0) {
90401
- const kwh = slices.powerMeter.kwhTotal;
91006
+ const kwh = slices.powerMeter.energy;
90402
91007
  this.runtimeState.setCapState(POWER_CAP, kwh === void 0 ? slices.powerMeter : {
90403
91008
  ...slices.powerMeter,
90404
- kwhTotal: this.energyGuard.accept(kwh)
91009
+ energy: this.energyGuard.accept(kwh)
90405
91010
  });
90406
91011
  }
90407
91012
  if (slices.battery !== void 0) this.runtimeState.setCapState(BATTERY_CAP, slices.battery);