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