@camstack/addon-provider-ecowitt 0.2.149 → 0.2.150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/addon.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createServer } from "http";
2
2
  import { EventEmitter } from "events";
3
3
  import { createSocket } from "dgram";
4
- //#region ../types/dist/event-category-CT-hz5Rb.mjs
4
+ //#region ../types/dist/event-category-DmZDPDf_.mjs
5
5
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
6
6
  EventCategory["SystemBoot"] = "system.boot";
7
7
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -628,7 +628,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
628
628
  * (a track was promoted to a stationary-registry entry) or departs (the
629
629
  * object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
630
630
  * the dedicated "Stationary" section — never the live event feed. Payload:
631
- * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp }`.
631
+ * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp, observedAt, zones }`.
632
632
  */
633
633
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
634
634
  /**
@@ -766,6 +766,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
766
766
  */
767
767
  EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
768
768
  /**
769
+ * An action run started or ended. Emitted by the `actions` surface.
770
+ * Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
771
+ */
772
+ EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
773
+ /**
769
774
  * Progress update from a running model conversion job.
770
775
  * Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
771
776
  * Emitted by `addon-model-studio` on the converting node.
@@ -5444,7 +5449,7 @@ var ZodIssueCode$1 = {
5444
5449
  var ZodFirstPartyTypeKind$1;
5445
5450
  ZodFirstPartyTypeKind$1 || (ZodFirstPartyTypeKind$1 = {});
5446
5451
  //#endregion
5447
- //#region ../types/dist/sleep--jXS9hWo.mjs
5452
+ //#region ../types/dist/sleep-Crlmu_tO.mjs
5448
5453
  /**
5449
5454
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5450
5455
  * window to float samples (D455).
@@ -8564,6 +8569,8 @@ Object.freeze({ "doorbell": "lastPressedAt" });
8564
8569
  /** Every capability name, so addon code can check a name without the schema graph. */
8565
8570
  var CAP_NAMES = Object.freeze([
8566
8571
  "accessories",
8572
+ "action-source",
8573
+ "actions",
8567
8574
  "addon-pages",
8568
8575
  "addon-pages-source",
8569
8576
  "addon-routes",
@@ -8752,11 +8759,11 @@ var CAP_NAMES = Object.freeze([
8752
8759
  Object.freeze({
8753
8760
  "air-quality-sensor": [
8754
8761
  {
8755
- "path": "co2Ppm",
8762
+ "path": "co2",
8756
8763
  "valueType": "number"
8757
8764
  },
8758
8765
  {
8759
- "path": "vocPpb",
8766
+ "path": "voc",
8760
8767
  "valueType": "number"
8761
8768
  },
8762
8769
  {
@@ -8806,7 +8813,7 @@ Object.freeze({
8806
8813
  }
8807
8814
  ],
8808
8815
  "ambient-light-sensor": [{
8809
- "path": "lux",
8816
+ "path": "illuminance",
8810
8817
  "valueType": "number"
8811
8818
  }],
8812
8819
  "audio-metrics": [
@@ -8867,7 +8874,7 @@ Object.freeze({
8867
8874
  ],
8868
8875
  "battery": [
8869
8876
  {
8870
- "path": "percentage",
8877
+ "path": "level",
8871
8878
  "valueType": "number"
8872
8879
  },
8873
8880
  {
@@ -8889,7 +8896,7 @@ Object.freeze({
8889
8896
  "valueType": "number"
8890
8897
  },
8891
8898
  {
8892
- "path": "volts",
8899
+ "path": "voltage",
8893
8900
  "valueType": "number"
8894
8901
  },
8895
8902
  {
@@ -8910,7 +8917,7 @@ Object.freeze({
8910
8917
  "valueType": "boolean"
8911
8918
  }],
8912
8919
  "brightness": [{
8913
- "path": "percentage",
8920
+ "path": "level",
8914
8921
  "valueType": "number"
8915
8922
  }],
8916
8923
  "broker": [{
@@ -9111,7 +9118,7 @@ Object.freeze({
9111
9118
  "valueType": "number"
9112
9119
  },
9113
9120
  {
9114
- "path": "mireds",
9121
+ "path": "colorTemperature",
9115
9122
  "valueType": "number"
9116
9123
  }
9117
9124
  ],
@@ -9290,15 +9297,15 @@ Object.freeze({
9290
9297
  "valueType": "string"
9291
9298
  },
9292
9299
  {
9293
- "path": "remainingSeconds",
9300
+ "path": "remaining",
9294
9301
  "valueType": "number"
9295
9302
  },
9296
9303
  {
9297
- "path": "delayedStartSeconds",
9304
+ "path": "delayedStart",
9298
9305
  "valueType": "number"
9299
9306
  },
9300
9307
  {
9301
- "path": "progressPercent",
9308
+ "path": "progress",
9302
9309
  "valueType": "number"
9303
9310
  },
9304
9311
  {
@@ -9412,7 +9419,7 @@ Object.freeze({
9412
9419
  ],
9413
9420
  "fan-control": [
9414
9421
  {
9415
- "path": "percentage",
9422
+ "path": "speed",
9416
9423
  "valueType": "number"
9417
9424
  },
9418
9425
  {
@@ -9512,7 +9519,7 @@ Object.freeze({
9512
9519
  }
9513
9520
  ],
9514
9521
  "humidity-sensor": [{
9515
- "path": "percent",
9522
+ "path": "humidity",
9516
9523
  "valueType": "number"
9517
9524
  }],
9518
9525
  "image": [{
@@ -9622,7 +9629,7 @@ Object.freeze({
9622
9629
  "valueType": "number"
9623
9630
  },
9624
9631
  {
9625
- "path": "progressPercent",
9632
+ "path": "progress",
9626
9633
  "valueType": "number"
9627
9634
  },
9628
9635
  {
@@ -9701,11 +9708,11 @@ Object.freeze({
9701
9708
  "valueType": "string"
9702
9709
  },
9703
9710
  {
9704
- "path": "positionMs",
9711
+ "path": "position",
9705
9712
  "valueType": "number"
9706
9713
  },
9707
9714
  {
9708
- "path": "durationMs",
9715
+ "path": "duration",
9709
9716
  "valueType": "number"
9710
9717
  },
9711
9718
  {
@@ -9807,11 +9814,11 @@ Object.freeze({
9807
9814
  ]
9808
9815
  },
9809
9816
  {
9810
- "path": "signalPercent",
9817
+ "path": "signal",
9811
9818
  "valueType": "number"
9812
9819
  },
9813
9820
  {
9814
- "path": "rssiDbm",
9821
+ "path": "rssi",
9815
9822
  "valueType": "number"
9816
9823
  },
9817
9824
  {
@@ -9866,6 +9873,18 @@ Object.freeze({
9866
9873
  "path": "foodLevel",
9867
9874
  "valueType": "number"
9868
9875
  },
9876
+ {
9877
+ "path": "bowlFood",
9878
+ "valueType": "number"
9879
+ },
9880
+ {
9881
+ "path": "eating",
9882
+ "valueType": "boolean"
9883
+ },
9884
+ {
9885
+ "path": "supportsMarkRefilled",
9886
+ "valueType": "boolean"
9887
+ },
9869
9888
  {
9870
9889
  "path": "food1",
9871
9890
  "valueType": "number"
@@ -9930,23 +9949,23 @@ Object.freeze({
9930
9949
  ],
9931
9950
  "power-meter": [
9932
9951
  {
9933
- "path": "watts",
9952
+ "path": "power",
9934
9953
  "valueType": "number"
9935
9954
  },
9936
9955
  {
9937
- "path": "kwhTotal",
9956
+ "path": "energy",
9938
9957
  "valueType": "number"
9939
9958
  },
9940
9959
  {
9941
- "path": "volts",
9960
+ "path": "voltage",
9942
9961
  "valueType": "number"
9943
9962
  },
9944
9963
  {
9945
- "path": "amps",
9964
+ "path": "current",
9946
9965
  "valueType": "number"
9947
9966
  },
9948
9967
  {
9949
- "path": "va",
9968
+ "path": "apparentPower",
9950
9969
  "valueType": "number"
9951
9970
  },
9952
9971
  {
@@ -9974,14 +9993,10 @@ Object.freeze({
9974
9993
  {
9975
9994
  "path": "gps.accuracyMeters",
9976
9995
  "valueType": "number"
9977
- },
9978
- {
9979
- "path": "batteryPercent",
9980
- "valueType": "number"
9981
9996
  }
9982
9997
  ],
9983
9998
  "pressure-sensor": [{
9984
- "path": "hpa",
9999
+ "path": "pressure",
9985
10000
  "valueType": "number"
9986
10001
  }],
9987
10002
  "privacy-mask": [{
@@ -10295,7 +10310,7 @@ Object.freeze({
10295
10310
  "valueType": "boolean"
10296
10311
  }],
10297
10312
  "temperature-sensor": [{
10298
- "path": "celsius",
10313
+ "path": "temperature",
10299
10314
  "valueType": "number"
10300
10315
  }],
10301
10316
  "update": [
@@ -10343,7 +10358,7 @@ Object.freeze({
10343
10358
  "valueType": "string"
10344
10359
  },
10345
10360
  {
10346
- "path": "progressPercent",
10361
+ "path": "progress",
10347
10362
  "valueType": "number"
10348
10363
  },
10349
10364
  {
@@ -10842,7 +10857,7 @@ function errMsg(err) {
10842
10857
  return String(err);
10843
10858
  }
10844
10859
  //#endregion
10845
- //#region ../types/dist/composition-Bb8iwHEJ.mjs
10860
+ //#region ../types/dist/composition-CZImLpOI.mjs
10846
10861
  /**
10847
10862
  * The ffmpeg build every CamStack node downloads, per platform and arch.
10848
10863
  *
@@ -15362,6 +15377,14 @@ var AutomationConditionLeafSchema = object({
15362
15377
  array(union([string(), number()]))
15363
15378
  ])
15364
15379
  });
15380
+ var AutomationConditionStationaryPresentSchema = object({
15381
+ kind: literal("stationary-present"),
15382
+ deviceId: number().int().nonnegative(),
15383
+ /** Class names; a macro class matches every raw class that maps to it. */
15384
+ classes: array(string().min(1)).min(1).optional(),
15385
+ /** The parked object must be in at least one of these zones. */
15386
+ zones: array(string().min(1)).min(1).optional()
15387
+ });
15365
15388
  /**
15366
15389
  * The expression leaf, declared as a plain object rather than an intersection
15367
15390
  * with {@link ExpressionSourceSchema}: a discriminated union has to be able to
@@ -15395,7 +15418,8 @@ var AutomationConditionSchema = lazy(() => discriminatedUnion("kind", [
15395
15418
  child: AutomationConditionSchema
15396
15419
  }),
15397
15420
  AutomationConditionLeafSchema,
15398
- AutomationConditionExpressionSchema
15421
+ AutomationConditionExpressionSchema,
15422
+ AutomationConditionStationaryPresentSchema
15399
15423
  ]));
15400
15424
  /**
15401
15425
  * What starts a run.
@@ -15436,7 +15460,34 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
15436
15460
  kind: literal("schedule"),
15437
15461
  cron: string().min(1).max(120)
15438
15462
  }),
15439
- object({ kind: literal("manual") })
15463
+ object({ kind: literal("manual") }),
15464
+ object({
15465
+ kind: literal("detection"),
15466
+ /** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
15467
+ * matches every raw class that maps to it; any other name matches
15468
+ * exactly. */
15469
+ classes: array(string().min(1)).min(1),
15470
+ deviceIds: array(number().int().nonnegative()).min(1),
15471
+ /** The track must have visited at least one of these zones. */
15472
+ zones: array(string().min(1)).min(1).optional(),
15473
+ /** Best-so-far confidence the track must reach. */
15474
+ minScore: number().min(0).max(1).optional()
15475
+ }),
15476
+ object({
15477
+ kind: literal("stationary"),
15478
+ deviceIds: array(number().int().nonnegative()).min(1),
15479
+ /** Class names; a macro class matches like the detection trigger. */
15480
+ classes: array(string().min(1)).min(1).optional(),
15481
+ /** The parked object must be in at least one of these zones. */
15482
+ zones: array(string().min(1)).min(1).optional(),
15483
+ /** `appeared`: it became parked. `departed`: the registry retired it.
15484
+ * The vocabulary of `PipelineAnalyticsStationaryChanged`. */
15485
+ phase: _enum(["appeared", "departed"])
15486
+ }),
15487
+ object({
15488
+ kind: literal("interval"),
15489
+ minutes: number().int().min(1).max(1440)
15490
+ })
15440
15491
  ]);
15441
15492
  /**
15442
15493
  * One action step.
@@ -15456,28 +15507,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
15456
15507
  * is called. The runner still receives a number and is untouched; the
15457
15508
  * resolution is the recipe's job, not the runner's.
15458
15509
  */
15510
+ var AutomationWaitStepSchema = object({
15511
+ kind: literal("wait"),
15512
+ seconds: number().min(0).max(300)
15513
+ });
15514
+ var AutomationCapStepSchema = object({
15515
+ kind: literal("cap"),
15516
+ /**
15517
+ * One device, several same-family devices (locks / climate family / …),
15518
+ * or `{ $var }` for the device that triggered the run. An array is
15519
+ * fan-out at codegen — each id gets the same cap.method call.
15520
+ */
15521
+ deviceId: union([
15522
+ number().int(),
15523
+ array(number().int()).min(1),
15524
+ object({ $var: string().min(1) })
15525
+ ]),
15526
+ cap: string().min(1),
15527
+ method: string().min(1),
15528
+ /** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
15529
+ * SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
15530
+ * the expression leaf. */
15531
+ args: record(string(), unknown()).optional()
15532
+ });
15533
+ /**
15534
+ * The steps an internal Action may contain: cap and wait, and nothing that can
15535
+ * call back into an Action — so an Action can never reach itself (no cycles).
15536
+ */
15537
+ var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
15459
15538
  var AutomationActionSchema = discriminatedUnion("kind", [
15539
+ AutomationWaitStepSchema,
15540
+ AutomationCapStepSchema,
15460
15541
  object({
15461
- kind: literal("wait"),
15462
- seconds: number().min(0).max(300)
15463
- }),
15464
- object({
15465
- kind: literal("cap"),
15466
- /**
15467
- * One device, several same-family devices (locks / climate family / …),
15468
- * or `{ $var }` for the device that triggered the run. An array is
15469
- * fan-out at codegen — each id gets the same cap.method call.
15470
- */
15471
- deviceId: union([
15472
- number().int(),
15473
- array(number().int()).min(1),
15474
- object({ $var: string().min(1) })
15475
- ]),
15476
- cap: string().min(1),
15477
- method: string().min(1),
15478
- /** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
15479
- * evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
15480
- args: record(string(), unknown()).optional()
15542
+ kind: literal("action"),
15543
+ /** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
15544
+ actionId: string().min(1),
15545
+ /** Values for the action's declared variables; the others take their default. */
15546
+ variables: record(string(), union([
15547
+ string(),
15548
+ number(),
15549
+ boolean()
15550
+ ])).optional()
15481
15551
  }),
15482
15552
  object({
15483
15553
  kind: literal("code"),
@@ -15486,10 +15556,357 @@ var AutomationActionSchema = discriminatedUnion("kind", [
15486
15556
  code: string().min(1).max(2e4)
15487
15557
  })
15488
15558
  ]);
15559
+ /**
15560
+ * How a trigger that arrives while the automation is busy (or cooling down) is
15561
+ * handled. One of the automation's execution modes, never a property of its
15562
+ * actions. Absent means `single`.
15563
+ *
15564
+ * - `single` — drop the trigger while a run is in progress (traced + logged).
15565
+ * - `restart` — abort the run in progress (at its next step boundary), start fresh.
15566
+ * - `queued` — queue up to `max` triggers, drop the rest (traced).
15567
+ * - `parallel` — up to `max` runs at once, drop the rest (traced).
15568
+ * - `cooldown` — `single`, and no new run until `minutes` after the last run
15569
+ * STARTED; persisted across a restart. A manual trigger bypasses only this
15570
+ * wait, never the single/queued limits.
15571
+ */
15572
+ var AutomationRunModeSchema = discriminatedUnion("mode", [
15573
+ object({ mode: literal("single") }),
15574
+ object({ mode: literal("restart") }),
15575
+ object({
15576
+ mode: literal("queued"),
15577
+ max: number().int().min(1).max(10)
15578
+ }),
15579
+ object({
15580
+ mode: literal("parallel"),
15581
+ max: number().int().min(1).max(10)
15582
+ }),
15583
+ object({
15584
+ mode: literal("cooldown"),
15585
+ minutes: number().int().min(1).max(1440)
15586
+ })
15587
+ ]);
15489
15588
  var AutomationRecipeSchema = object({
15490
15589
  triggers: array(AutomationTriggerSchema),
15491
15590
  conditions: AutomationConditionSchema.optional(),
15492
- actions: array(AutomationActionSchema)
15591
+ actions: array(AutomationActionSchema),
15592
+ runMode: AutomationRunModeSchema.optional(),
15593
+ /** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
15594
+ keepTraces: number().int().min(1).max(100).optional()
15595
+ });
15596
+ new Set([
15597
+ {
15598
+ id: "person",
15599
+ name: "Person"
15600
+ },
15601
+ {
15602
+ id: "vehicle",
15603
+ name: "Vehicle"
15604
+ },
15605
+ {
15606
+ id: "animal",
15607
+ name: "Animal"
15608
+ },
15609
+ {
15610
+ id: "package",
15611
+ name: "Package"
15612
+ }
15613
+ ].map((l) => l.id));
15614
+ var COCO_TO_MACRO = {
15615
+ mapping: {
15616
+ person: "person",
15617
+ bicycle: "vehicle",
15618
+ car: "vehicle",
15619
+ motorcycle: "vehicle",
15620
+ airplane: "vehicle",
15621
+ bus: "vehicle",
15622
+ train: "vehicle",
15623
+ truck: "vehicle",
15624
+ boat: "vehicle",
15625
+ bird: "animal",
15626
+ cat: "animal",
15627
+ dog: "animal",
15628
+ horse: "animal",
15629
+ sheep: "animal",
15630
+ cow: "animal",
15631
+ elephant: "animal",
15632
+ bear: "animal",
15633
+ zebra: "animal",
15634
+ giraffe: "animal",
15635
+ suitcase: "package",
15636
+ backpack: "package",
15637
+ handbag: "package"
15638
+ },
15639
+ preserveOriginal: false
15640
+ };
15641
+ new Set(Object.values(COCO_TO_MACRO.mapping));
15642
+ /**
15643
+ * Run traces — what an automation (or, later, an Action run) DID, node by node,
15644
+ * so the editor can paint every block green or red with its reason.
15645
+ *
15646
+ * A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
15647
+ * every condition node (containers and leaves, including the ones a
15648
+ * short-circuit never reached), the run-mode verdict and every action step —
15649
+ * each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
15650
+ * for an Action run). Skipped
15651
+ * evaluations are traced too, and identical consecutive skips collapse into a
15652
+ * repeat count so a trigger that fails every 5 minutes cannot flush real runs.
15653
+ *
15654
+ * {@link AutomationStepTraceSchema} is deliberately free of automation
15655
+ * vocabulary so an Action run records the same step shape.
15656
+ */
15657
+ /** A value a trace may show: JSON primitives and short lists, nothing deeper. */
15658
+ var TraceValueSchema = union([
15659
+ string(),
15660
+ number(),
15661
+ boolean(),
15662
+ _null(),
15663
+ array(union([string(), number()]))
15664
+ ]);
15665
+ var AutomationRunOutcomeSchema = _enum([
15666
+ "ran",
15667
+ "skipped-trigger",
15668
+ "skipped-conditions",
15669
+ "skipped-cooldown",
15670
+ "skipped-overlap",
15671
+ "failed",
15672
+ "aborted"
15673
+ ]);
15674
+ /** `not-evaluated` = a short-circuit never reached the node. */
15675
+ var TraceNodeOutcomeSchema = _enum([
15676
+ "pass",
15677
+ "fail",
15678
+ "not-evaluated"
15679
+ ]);
15680
+ var AutomationTriggerTraceSchema = object({
15681
+ kind: string().min(1),
15682
+ outcome: _enum(["pass", "fail"]),
15683
+ /** Why an event was rejected ("class person not in [dog]") or what fired. */
15684
+ reason: string(),
15685
+ /** deviceId, className, trackId, score … — only what the trigger exposes. */
15686
+ vars: record(string(), TraceValueSchema)
15687
+ });
15688
+ var AutomationConditionTraceNodeSchema = object({
15689
+ /** `conditions` for the root, `conditions.<i>` for its i-th child, … */
15690
+ path: string().min(1),
15691
+ kind: _enum([
15692
+ "all",
15693
+ "any",
15694
+ "not",
15695
+ "condition",
15696
+ "expression",
15697
+ "stationary-present"
15698
+ ]),
15699
+ outcome: TraceNodeOutcomeSchema,
15700
+ reason: string(),
15701
+ deviceId: number().int().optional(),
15702
+ cap: string().optional(),
15703
+ fieldPath: string().optional(),
15704
+ operator: string().optional(),
15705
+ expected: TraceValueSchema.optional(),
15706
+ /** What the mirror held; `null` when it held nothing (unknown). */
15707
+ observed: TraceValueSchema.optional()
15708
+ });
15709
+ var AutomationRunVerdictSchema = object({
15710
+ mode: AutomationRunModeSchema,
15711
+ decision: _enum([
15712
+ "run",
15713
+ "queued",
15714
+ "restart",
15715
+ "drop",
15716
+ "cooldown",
15717
+ "bypass"
15718
+ ]),
15719
+ reason: string()
15720
+ });
15721
+ /** One executed (or not-run) step — shared by automations and Action runs. */
15722
+ var AutomationStepTraceSchema = object({
15723
+ /** `actions.<i>` */
15724
+ path: string().min(1),
15725
+ kind: string().min(1),
15726
+ cap: string().optional(),
15727
+ method: string().optional(),
15728
+ deviceId: number().int().optional(),
15729
+ startedAt: number().optional(),
15730
+ endedAt: number().optional(),
15731
+ outcome: _enum([
15732
+ "ok",
15733
+ "error",
15734
+ "not-run"
15735
+ ]),
15736
+ message: string().optional()
15737
+ });
15738
+ var AutomationRunTraceSchema = object({
15739
+ runId: string().min(1),
15740
+ startedAt: number(),
15741
+ endedAt: number(),
15742
+ trigger: AutomationTriggerTraceSchema,
15743
+ conditions: array(AutomationConditionTraceNodeSchema),
15744
+ verdict: AutomationRunVerdictSchema.optional(),
15745
+ steps: array(AutomationStepTraceSchema),
15746
+ outcome: AutomationRunOutcomeSchema,
15747
+ /** How many identical consecutive skips this trace stands for (>= 1). */
15748
+ repeat: number().int().min(1),
15749
+ /** When the latest of those repeats happened. */
15750
+ lastAt: number()
15751
+ });
15752
+ /**
15753
+ * What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
15754
+ * `action:<actionId>`): the cooldown stamp and the trace ring.
15755
+ */
15756
+ var AutomationStateDocSchema = object({
15757
+ version: literal(1),
15758
+ lastRunStartedAt: number().nullable(),
15759
+ traces: array(AutomationRunTraceSchema)
15760
+ });
15761
+ /**
15762
+ * Actions — named, runnable things an operator (or an automation) can start,
15763
+ * declared as LIST ENTRIES, never as devices.
15764
+ *
15765
+ * An entry is either **internal** (a short list of cap/wait steps kept in the
15766
+ * hub's `actions` record kind) or declared by an addon through the
15767
+ * `action-source` collection (a Home Assistant script, a scene …). The one
15768
+ * surface the UI and automations talk to is the `actions` cap; it keeps no
15769
+ * catalog of its own (D3) — every `list` asks the providers live.
15770
+ *
15771
+ * This file is the data half: the entry schema, the variables an entry may
15772
+ * declare, and the pure resolution of the values a run was given. It holds no
15773
+ * runtime.
15774
+ */
15775
+ /** What a variable's value is. `select` takes one of `options`. */
15776
+ var ActionVariableTypeSchema = _enum([
15777
+ "string",
15778
+ "number",
15779
+ "boolean",
15780
+ "select"
15781
+ ]);
15782
+ var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
15783
+ var ActionVariableValueSchema = union([
15784
+ string(),
15785
+ number(),
15786
+ boolean()
15787
+ ]);
15788
+ /**
15789
+ * One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
15790
+ * value) or `{{vars.name}}` (inside a string) in their args.
15791
+ */
15792
+ var ActionVariableSchema = object({
15793
+ name: string().regex(ACTION_VARIABLE_NAME_RE),
15794
+ label: string().min(1).max(120).optional(),
15795
+ type: ActionVariableTypeSchema,
15796
+ required: boolean().optional(),
15797
+ default: ActionVariableValueSchema.optional(),
15798
+ /** The allowed values of a `select`. */
15799
+ options: array(string().min(1)).min(1).optional()
15800
+ }).superRefine((v, ctx) => {
15801
+ if (v.type === "select" && v.options === void 0) ctx.addIssue({
15802
+ code: "custom",
15803
+ message: "a select variable needs options",
15804
+ path: ["options"]
15805
+ });
15806
+ if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
15807
+ code: "custom",
15808
+ message: variableValueError(v, v.default) ?? "invalid default",
15809
+ path: ["default"]
15810
+ });
15811
+ });
15812
+ /** Why `value` is not a legal value for the variable, or null when it is. */
15813
+ function variableValueError(variable, value) {
15814
+ switch (variable.type) {
15815
+ case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
15816
+ case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
15817
+ case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
15818
+ case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
15819
+ }
15820
+ }
15821
+ var ActionSourceKindSchema = _enum(["internal", "addon"]);
15822
+ function isInternalActionId(actionId) {
15823
+ return actionId.startsWith("internal:") && actionId.length > 9;
15824
+ }
15825
+ /** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
15826
+ function addonIdOfActionId(actionId) {
15827
+ if (isInternalActionId(actionId)) return null;
15828
+ const at = actionId.indexOf(":");
15829
+ return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
15830
+ }
15831
+ var ActionStatusSchema = object({
15832
+ isRunning: boolean(),
15833
+ /** Ms epoch the latest run STARTED; null when it never ran. */
15834
+ lastRunAt: number().nullable(),
15835
+ /** The latest run's failure; null on success or when it never ran. */
15836
+ lastError: string().nullable()
15837
+ });
15838
+ var ActionEntrySchema = object({
15839
+ /** `internal:<uuid>` or `<addonId>:<localId>`. */
15840
+ id: string().min(3),
15841
+ name: string().min(1).max(120),
15842
+ /** The addon that declared it; `core-blocks` for an internal one. */
15843
+ addonId: string().min(1),
15844
+ source: ActionSourceKindSchema,
15845
+ /** An addon-declared entry is edited where it was declared. */
15846
+ readOnly: boolean(),
15847
+ /** Internal only: cap and wait steps. No action-in-action, so no cycles. */
15848
+ steps: array(ActionStepSchema).min(1).max(50).optional(),
15849
+ variables: array(ActionVariableSchema).max(20).optional(),
15850
+ status: ActionStatusSchema
15851
+ }).superRefine((entry, ctx) => {
15852
+ if (entry.source === "internal") {
15853
+ if (!isInternalActionId(entry.id)) ctx.addIssue({
15854
+ code: "custom",
15855
+ message: "an internal action id is internal:<uuid>",
15856
+ path: ["id"]
15857
+ });
15858
+ return;
15859
+ }
15860
+ if (entry.steps !== void 0) ctx.addIssue({
15861
+ code: "custom",
15862
+ message: "only an internal action carries steps",
15863
+ path: ["steps"]
15864
+ });
15865
+ if (!entry.readOnly) ctx.addIssue({
15866
+ code: "custom",
15867
+ message: "an addon action is read-only here",
15868
+ path: ["readOnly"]
15869
+ });
15870
+ if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
15871
+ code: "custom",
15872
+ message: "an addon action id is <addonId>:<localId>",
15873
+ path: ["id"]
15874
+ });
15875
+ });
15876
+ /** What an operator writes for an internal action. */
15877
+ var ActionInputSchema = object({
15878
+ name: string().min(1).max(120),
15879
+ steps: array(ActionStepSchema).min(1).max(50),
15880
+ variables: array(ActionVariableSchema).max(20).optional()
15881
+ });
15882
+ /** Who started a run. Absent = the operator pressed it. */
15883
+ var ActionRunOriginSchema = object({
15884
+ /** The automation block whose step started it. */
15885
+ blockId: string().min(1).optional() });
15886
+ /** `started` = the caller did not ask to wait. */
15887
+ var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
15888
+ var ActionRunResultSchema = object({
15889
+ runId: string().min(1),
15890
+ outcome: ActionRunOutcomeSchema,
15891
+ /** Why it did not run, or what failed. */
15892
+ message: string().optional()
15893
+ });
15894
+ _enum([
15895
+ "not-found",
15896
+ "read-only",
15897
+ "invalid-variables",
15898
+ "invalid-steps",
15899
+ "not-linked",
15900
+ "busy"
15901
+ ]);
15902
+ object({
15903
+ actionId: string(),
15904
+ runId: string(),
15905
+ isRunning: boolean(),
15906
+ /** Set when the run ended. */
15907
+ outcome: AutomationRunOutcomeSchema.optional(),
15908
+ lastRunAt: number().nullable(),
15909
+ lastError: string().nullable()
15493
15910
  });
15494
15911
  /**
15495
15912
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
@@ -18176,7 +18593,7 @@ var CompositionEventPlanSchema = object({
18176
18593
  stateField: string(),
18177
18594
  fieldKey: string()
18178
18595
  });
18179
- /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
18596
+ /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.temperature`. */
18180
18597
  var CompositionProblemSchema = object({
18181
18598
  code: _enum([
18182
18599
  "reserved-variant",
@@ -18495,7 +18912,7 @@ var GROUP_TEMPLATES = [
18495
18912
  summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
18496
18913
  role: DeviceRole.TemperatureSensor,
18497
18914
  outputCap: "temperature-sensor",
18498
- outputField: "celsius",
18915
+ outputField: "temperature",
18499
18916
  quantity: "temperature",
18500
18917
  defaultAggregate: "mean",
18501
18918
  empty: "null",
@@ -18506,7 +18923,7 @@ var GROUP_TEMPLATES = [
18506
18923
  summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
18507
18924
  role: DeviceRole.HumiditySensor,
18508
18925
  outputCap: "humidity-sensor",
18509
- outputField: "percent",
18926
+ outputField: "humidity",
18510
18927
  quantity: "humidity",
18511
18928
  defaultAggregate: "mean",
18512
18929
  empty: "null",
@@ -18517,7 +18934,7 @@ var GROUP_TEMPLATES = [
18517
18934
  summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
18518
18935
  role: DeviceRole.PressureSensor,
18519
18936
  outputCap: "pressure-sensor",
18520
- outputField: "hpa",
18937
+ outputField: "pressure",
18521
18938
  quantity: "pressure",
18522
18939
  defaultAggregate: "mean",
18523
18940
  empty: "null",
@@ -18528,7 +18945,7 @@ var GROUP_TEMPLATES = [
18528
18945
  summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
18529
18946
  role: DeviceRole.AmbientLightSensor,
18530
18947
  outputCap: "ambient-light-sensor",
18531
- outputField: "lux",
18948
+ outputField: "illuminance",
18532
18949
  quantity: "illuminance",
18533
18950
  defaultAggregate: "mean",
18534
18951
  empty: "null",
@@ -18539,7 +18956,7 @@ var GROUP_TEMPLATES = [
18539
18956
  summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
18540
18957
  role: DeviceRole.PowerSensor,
18541
18958
  outputCap: "power-meter",
18542
- outputField: "watts",
18959
+ outputField: "power",
18543
18960
  quantity: "power",
18544
18961
  defaultAggregate: "sum",
18545
18962
  empty: "omit",
@@ -18550,7 +18967,7 @@ var GROUP_TEMPLATES = [
18550
18967
  summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
18551
18968
  role: DeviceRole.EnergySensor,
18552
18969
  outputCap: "power-meter",
18553
- outputField: "kwhTotal",
18970
+ outputField: "energy",
18554
18971
  quantity: "energy",
18555
18972
  defaultAggregate: "sum",
18556
18973
  empty: "omit",
@@ -18561,7 +18978,7 @@ var GROUP_TEMPLATES = [
18561
18978
  summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
18562
18979
  role: DeviceRole.BatterySensor,
18563
18980
  outputCap: "battery",
18564
- outputField: "percentage",
18981
+ outputField: "level",
18565
18982
  quantity: "percentage",
18566
18983
  defaultAggregate: "mean",
18567
18984
  empty: "null",
@@ -19139,7 +19556,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
19139
19556
  kind: "mutation",
19140
19557
  auth: "admin",
19141
19558
  access: "view"
19142
- });
19559
+ }), method(object({
19560
+ blockId: string().min(1),
19561
+ trace: AutomationRunTraceSchema.optional(),
19562
+ runStartedAt: number().optional(),
19563
+ keepTraces: number().int().min(1).max(100).optional()
19564
+ }), _void(), {
19565
+ kind: "mutation",
19566
+ auth: "admin"
19567
+ }), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
19568
+ traces: array(AutomationRunTraceSchema),
19569
+ lastError: string().nullable()
19570
+ }), { auth: "admin" });
19143
19571
  /**
19144
19572
  * `custom-model-registry` — collection cap exposing operator-registered
19145
19573
  * custom detection models. Each provider (today: `addon-model-studio`)
@@ -44611,51 +45039,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
44611
45039
  kind: "mutation",
44612
45040
  auth: "admin"
44613
45041
  });
44614
- new Set([
44615
- {
44616
- id: "person",
44617
- name: "Person"
44618
- },
44619
- {
44620
- id: "vehicle",
44621
- name: "Vehicle"
44622
- },
44623
- {
44624
- id: "animal",
44625
- name: "Animal"
44626
- },
44627
- {
44628
- id: "package",
44629
- name: "Package"
44630
- }
44631
- ].map((l) => l.id));
44632
- var COCO_TO_MACRO = {
44633
- mapping: {
44634
- person: "person",
44635
- bicycle: "vehicle",
44636
- car: "vehicle",
44637
- motorcycle: "vehicle",
44638
- airplane: "vehicle",
44639
- bus: "vehicle",
44640
- train: "vehicle",
44641
- truck: "vehicle",
44642
- boat: "vehicle",
44643
- bird: "animal",
44644
- cat: "animal",
44645
- dog: "animal",
44646
- horse: "animal",
44647
- sheep: "animal",
44648
- cow: "animal",
44649
- elephant: "animal",
44650
- bear: "animal",
44651
- zebra: "animal",
44652
- giraffe: "animal",
44653
- suitcase: "package",
44654
- backpack: "package",
44655
- handbag: "package"
44656
- },
44657
- preserveOriginal: false
44658
- };
44659
45042
  var AUDIO_MACRO_LABELS = [
44660
45043
  {
44661
45044
  id: "speech",
@@ -57222,9 +57605,9 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
57222
57605
  */
57223
57606
  var AirQualitySensorStatusSchema = object({
57224
57607
  /** Carbon dioxide concentration in ppm. */
57225
- co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
57608
+ co2: number().min(0).optional().meta(readingMeta("concentration-volume")),
57226
57609
  /** Total volatile organic compounds in ppb. */
57227
- vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
57610
+ voc: number().min(0).optional().meta(readingMeta("concentration-ppb")),
57228
57611
  /** Particulate matter ≤ 2.5 μm in µg/m³. */
57229
57612
  pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
57230
57613
  /** Particulate matter ≤ 10 μm in µg/m³. */
@@ -57257,12 +57640,12 @@ var airQualitySensorCapability = {
57257
57640
  * History (D850): recorded series.
57258
57641
  */
57259
57642
  history: { fields: {
57260
- co2Ppm: {
57643
+ co2: {
57261
57644
  kind: "gauge",
57262
57645
  unit: "ppm",
57263
57646
  deadband: 5
57264
57647
  },
57265
- vocPpb: {
57648
+ voc: {
57266
57649
  kind: "gauge",
57267
57650
  unit: "ppb",
57268
57651
  deadband: 5
@@ -57293,7 +57676,7 @@ var airQualitySensorCapability = {
57293
57676
  */
57294
57677
  var AmbientLightSensorStatusSchema = object({
57295
57678
  /** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
57296
- lux: number().min(0).nullable().meta(readingMeta("illuminance", {
57679
+ illuminance: number().min(0).nullable().meta(readingMeta("illuminance", {
57297
57680
  precision: 0,
57298
57681
  label: "Illuminance"
57299
57682
  })),
@@ -57322,7 +57705,7 @@ var ambientLightSensorCapability = {
57322
57705
  /**
57323
57706
  * History (D850): recorded series. Wide range, so a RELATIVE deadband (10 %).
57324
57707
  */
57325
- history: { fields: { lux: {
57708
+ history: { fields: { illuminance: {
57326
57709
  kind: "gauge",
57327
57710
  unit: "lx",
57328
57711
  deadbandPct: 10,
@@ -57461,6 +57844,84 @@ var audioMetricsCapability = {
57461
57844
  */
57462
57845
  history: "none"
57463
57846
  };
57847
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
57848
+ actionId: string().min(1),
57849
+ variables: record(string(), ActionVariableValueSchema).optional()
57850
+ }), _void(), {
57851
+ kind: "mutation",
57852
+ auth: "admin"
57853
+ }), method(object({ actionId: string().min(1) }), _void(), {
57854
+ kind: "mutation",
57855
+ auth: "admin"
57856
+ });
57857
+ /**
57858
+ * actions — the ONE surface for runnable actions, for the UI and for
57859
+ * automations. Provided by the core-blocks builtin on the hub.
57860
+ *
57861
+ * An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
57862
+ * steps, kept in the hub's `actions` record kind) or declared by an addon over
57863
+ * `action-source`. `list` asks every `action-source` provider LIVE and overlays
57864
+ * the run status from the hub's `runs` ledger; there is no catalog here to
57865
+ * drift (D3).
57866
+ *
57867
+ * **Permissions follow the camera, as linked devices do.** An action is linked
57868
+ * to cameras by the operator (`setLinks`, D356: nothing links itself). A
57869
+ * non-admin may `get` / `run` an action only through a camera they may see that
57870
+ * links it: they name the camera (`deviceId`, a top-level field so the scope
57871
+ * gate sees it) and the provider refuses an action that camera does not link.
57872
+ * An admin, and an in-process caller (an automation block), may run any action.
57873
+ * Every refusal is typed (`[not-linked] …`) and logged.
57874
+ *
57875
+ * A second `run` of an action that is already running is REFUSED — traced and
57876
+ * logged — never queued.
57877
+ */
57878
+ var ActionIdInput = object({ actionId: string().min(1) });
57879
+ var ActionLinksSchema = object({
57880
+ deviceId: number().int().nonnegative(),
57881
+ actionIds: array(string().min(1)).max(100)
57882
+ });
57883
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
57884
+ actionId: string().min(1),
57885
+ deviceId: number().int().nonnegative().optional()
57886
+ }), object({ action: ActionEntrySchema.nullable() }), {
57887
+ role: "viewer",
57888
+ auth: "protected",
57889
+ kind: "query",
57890
+ caller: "required"
57891
+ }), method(object({
57892
+ actionId: string().min(1),
57893
+ variables: record(string(), ActionVariableValueSchema).optional(),
57894
+ wait: boolean().optional(),
57895
+ origin: ActionRunOriginSchema.optional(),
57896
+ deviceId: number().int().nonnegative().optional()
57897
+ }), ActionRunResultSchema, {
57898
+ role: "viewer",
57899
+ auth: "protected",
57900
+ kind: "mutation",
57901
+ caller: "required"
57902
+ }), method(ActionIdInput, _void(), {
57903
+ kind: "mutation",
57904
+ auth: "admin"
57905
+ }), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
57906
+ kind: "mutation",
57907
+ auth: "admin"
57908
+ }), method(object({
57909
+ actionId: string().min(1),
57910
+ action: ActionInputSchema.partial()
57911
+ }), object({ action: ActionEntrySchema }), {
57912
+ kind: "mutation",
57913
+ auth: "admin"
57914
+ }), method(ActionIdInput, _void(), {
57915
+ kind: "mutation",
57916
+ auth: "admin"
57917
+ }), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
57918
+ role: "viewer",
57919
+ auth: "protected",
57920
+ kind: "query"
57921
+ }), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
57922
+ kind: "mutation",
57923
+ auth: "admin"
57924
+ });
57464
57925
  /**
57465
57926
  * Automation-control cap. Models HA `automation.*` entities on
57466
57927
  * `DeviceType.Automation`. An automation is a trigger+condition+
@@ -57557,7 +58018,7 @@ var BatteryStatusSchema = object({
57557
58018
  * Consumers must SKIP a null rather than coerce it — `battery-band` already
57558
58019
  * declines to band a non-finite reading, which is the correct shape.
57559
58020
  */
57560
- percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
58021
+ level: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
57561
58022
  /**
57562
58023
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
57563
58024
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -57567,7 +58028,7 @@ var BatteryStatusSchema = object({
57567
58028
  * `'unknown'` is the absence of an answer: the provider has not read the
57568
58029
  * power fields yet, or the firmware reported neither. Before it existed,
57569
58030
  * two unreadable fields produced `'none'`, and a camera nobody had reached
57570
- * was drawn "on battery alone" — the same D315 defect `percentage` closed
58031
+ * was drawn "on battery alone" — the same D315 defect `level` closed
57571
58032
  * by going nullable. Consumers SKIP it (no charger state published, no
57572
58033
  * glyph, no HomeKit ChargingState) rather than coerce it either way.
57573
58034
  */
@@ -57591,7 +58052,7 @@ var BatteryStatusSchema = object({
57591
58052
  * that only report charge. A second reading on this cap, not a second
57592
58053
  * `numeric-sensor` on the same device.
57593
58054
  */
57594
- volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
58055
+ voltage: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
57595
58056
  /**
57596
58057
  * Ms epoch of the last time the device PROVED it was reachable — a
57597
58058
  * completed firmware round-trip, an observed wake, or an inbound push
@@ -57625,7 +58086,7 @@ var BatteryStatusSchema = object({
57625
58086
  /**
57626
58087
  * True when the source is a BINARY low-battery indicator (HA
57627
58088
  * `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
57628
- * charge level — `percentage` is then a coarse stand-in (100 = normal,
58089
+ * charge level — `level` is then a coarse stand-in (100 = normal,
57629
58090
  * sub-threshold = low). UI MUST render "Normal"/"Low" instead of a
57630
58091
  * misleading exact percentage. Absent/false → genuine 0–100 % reading.
57631
58092
  */
@@ -57645,15 +58106,15 @@ var BATTERY_DEVICE_TYPES = [
57645
58106
  var batteryCustomize = {
57646
58107
  version: 1,
57647
58108
  targets: [{
57648
- id: "percentage",
58109
+ id: "level",
57649
58110
  cardinality: "scalar",
57650
58111
  vocabulary: {
57651
58112
  cap: "battery",
57652
- stateField: "percentage"
58113
+ stateField: "level"
57653
58114
  },
57654
58115
  deviceTypes: BATTERY_DEVICE_TYPES,
57655
58116
  apply: "add",
57656
- path: "percentage",
58117
+ path: "level",
57657
58118
  sources: [{
57658
58119
  kind: "field",
57659
58120
  valueKinds: ["number", "string"],
@@ -57747,7 +58208,7 @@ onStatusChanged: { data: object({
57747
58208
  schema: BatteryStatusSchema,
57748
58209
  kind: "push",
57749
58210
  empty: {
57750
- percentage: null,
58211
+ level: null,
57751
58212
  charging: "unknown",
57752
58213
  sleeping: false,
57753
58214
  lastUpdated: 0
@@ -57774,11 +58235,11 @@ onStatusChanged: { data: object({
57774
58235
  * History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
57775
58236
  */
57776
58237
  history: { fields: {
57777
- percentage: {
58238
+ level: {
57778
58239
  kind: "gauge",
57779
58240
  unit: "%"
57780
58241
  },
57781
- volts: {
58242
+ voltage: {
57782
58243
  kind: "gauge",
57783
58244
  unit: "V"
57784
58245
  }
@@ -57838,14 +58299,14 @@ var binaryCapability = {
57838
58299
  * controls to this single-method surface.
57839
58300
  *
57840
58301
  * The cap is intentionally minimal: a single `setBrightness({deviceId,
57841
- * percentage})` mutation plus the auto-injected `getStatus`. Drivers
58302
+ * level})` mutation plus the auto-injected `getStatus`. Drivers
57842
58303
  * that expose richer controls (color temperature, scenes, schedules)
57843
58304
  * should surface those via the device's `getSettingsUISchema()`
57844
58305
  * instead of bloating this cap.
57845
58306
  */
57846
58307
  var BrightnessStatusSchema = object({
57847
58308
  /** Current level as 0..100 inclusive. Firmware-reported. */
57848
- percentage: number().min(0).max(100).meta(readingMeta("percentage")),
58309
+ level: number().min(0).max(100).meta(readingMeta("percentage")),
57849
58310
  /** Ms epoch of the last operator-driven change. Useful for UI freshness. */
57850
58311
  lastChangedAt: number()
57851
58312
  });
@@ -57857,7 +58318,7 @@ var brightnessCapability = {
57857
58318
  deviceTypes: [DeviceType.Light],
57858
58319
  methods: { setBrightness: method(object({
57859
58320
  deviceId: number().int().nonnegative(),
57860
- percentage: number().min(0).max(100)
58321
+ level: number().min(0).max(100)
57861
58322
  }), _void(), {
57862
58323
  kind: "mutation",
57863
58324
  auth: "protected"
@@ -57870,7 +58331,7 @@ var brightnessCapability = {
57870
58331
  */
57871
58332
  onBrightnessChanged: { data: object({
57872
58333
  deviceId: number(),
57873
- percentage: number().min(0).max(100),
58334
+ level: number().min(0).max(100),
57874
58335
  lastChangedAt: number()
57875
58336
  }) } },
57876
58337
  status: {
@@ -57893,7 +58354,7 @@ onBrightnessChanged: { data: object({
57893
58354
  /**
57894
58355
  * History (D850): recorded series. Actuator tier: level keeps every change.
57895
58356
  */
57896
- history: { fields: { percentage: {
58357
+ history: { fields: { level: {
57897
58358
  kind: "gauge",
57898
58359
  unit: "%",
57899
58360
  minIntervalMs: 0
@@ -58490,11 +58951,11 @@ var ColorInputSchema = discriminatedUnion("mode", [
58490
58951
  }),
58491
58952
  object({
58492
58953
  mode: literal("mired"),
58493
- mireds: number().int().min(50).max(1e3)
58954
+ colorTemperature: number().int().min(50).max(1e3)
58494
58955
  })
58495
58956
  ]);
58496
58957
  var ColorStatusSchema = object({
58497
- /** Active color mode — which of `rgb` / `hsv` / `mireds` reflects
58958
+ /** Active color mode — which of `rgb` / `hsv` / `colorTemperature` reflects
58498
58959
  * the bulb's current state. */
58499
58960
  mode: _enum([
58500
58961
  "rgb",
@@ -58506,7 +58967,7 @@ var ColorStatusSchema = object({
58506
58967
  /** Populated when `mode === 'hsv'`. */
58507
58968
  hsv: HsvTripletSchema.optional(),
58508
58969
  /** Populated when `mode === 'mired'`. */
58509
- mireds: number().int().optional().meta(readingMeta("colour-temperature")),
58970
+ colorTemperature: number().int().optional().meta(readingMeta("colour-temperature")),
58510
58971
  /** Ms epoch of the last operator-driven change. */
58511
58972
  lastChangedAt: number()
58512
58973
  });
@@ -58538,7 +58999,7 @@ onColorChanged: { data: object({
58538
58999
  ]),
58539
59000
  rgb: RgbTripletSchema.optional(),
58540
59001
  hsv: HsvTripletSchema.optional(),
58541
- mireds: number().int().optional(),
59002
+ colorTemperature: number().int().optional(),
58542
59003
  lastChangedAt: number()
58543
59004
  }) } },
58544
59005
  status: {
@@ -59415,11 +59876,11 @@ var DishwasherStatusSchema = object({
59415
59876
  /** Feature keys of the programs the appliance currently offers — drives the UI selector. */
59416
59877
  availablePrograms: array(string()),
59417
59878
  /** Seconds remaining on the active cycle, or null when not running / not known. */
59418
- remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
59879
+ remaining: number().int().nonnegative().nullable().meta(readingMeta("duration")),
59419
59880
  /** Seconds the delayed start is set to (time until the cycle starts), or null. */
59420
- delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
59881
+ delayedStart: number().int().nonnegative().nullable().meta(readingMeta("duration")),
59421
59882
  /** Cycle completion 0..100, or null when not applicable. */
59422
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
59883
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
59423
59884
  /** True when the door is reported open; null when the door state is not known. */
59424
59885
  doorOpen: boolean().nullable(),
59425
59886
  /** True when the door is latched (locked) during a cycle; null when not reported. */
@@ -59638,14 +60099,14 @@ var dishwasherCapability = {
59638
60099
  runtimeState: DishwasherStatusSchema,
59639
60100
  durability: "session",
59640
60101
  history: { fields: {
59641
- progressPercent: {
60102
+ progress: {
59642
60103
  kind: "gauge",
59643
60104
  unit: "%",
59644
60105
  deadband: 2
59645
60106
  },
59646
60107
  state: { kind: "enum" },
59647
60108
  operationState: { kind: "enum" },
59648
- remainingSeconds: {
60109
+ remaining: {
59649
60110
  kind: "gauge",
59650
60111
  unit: "s",
59651
60112
  minIntervalMs: 6e4
@@ -60236,7 +60697,7 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
60236
60697
  var FanControlStatusSchema = object({
60237
60698
  /** Active speed as 0..100 inclusive. Null when the device has no
60238
60699
  * speed surface (single-speed fan). */
60239
- percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
60700
+ speed: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
60240
60701
  /** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
60241
60702
  * a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
60242
60703
  percentageStep: number().positive().optional().meta(readingMeta("percentage")),
@@ -60263,7 +60724,7 @@ var fanControlCapability = {
60263
60724
  methods: {
60264
60725
  setPercentage: method(object({
60265
60726
  deviceId: number().int().nonnegative(),
60266
- percentage: number().min(0).max(100)
60727
+ speed: number().min(0).max(100)
60267
60728
  }), _void(), {
60268
60729
  kind: "mutation",
60269
60730
  auth: "protected"
@@ -60296,7 +60757,7 @@ var fanControlCapability = {
60296
60757
  },
60297
60758
  /**
60298
60759
  * Runtime-state slice — mirrored by the kernel. UI fan speed
60299
- * sliders read `percentage` for live updates.
60760
+ * sliders read `speed` for live updates.
60300
60761
  */
60301
60762
  runtimeState: FanControlStatusSchema,
60302
60763
  /**
@@ -60310,7 +60771,7 @@ var fanControlCapability = {
60310
60771
  * History (D850): recorded series. Actuator tier: speed keeps every change.
60311
60772
  */
60312
60773
  history: { fields: {
60313
- percentage: {
60774
+ speed: {
60314
60775
  kind: "gauge",
60315
60776
  unit: "%",
60316
60777
  minIntervalMs: 0
@@ -60755,7 +61216,7 @@ var humidifierCapability = {
60755
61216
  */
60756
61217
  var HumiditySensorStatusSchema = object({
60757
61218
  /** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
60758
- percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
61219
+ humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
60759
61220
  precision: 0,
60760
61221
  label: "Humidity"
60761
61222
  })),
@@ -60784,7 +61245,7 @@ var humiditySensorCapability = {
60784
61245
  /**
60785
61246
  * History (D850): recorded series.
60786
61247
  */
60787
- history: { fields: { percent: {
61248
+ history: { fields: { humidity: {
60788
61249
  kind: "gauge",
60789
61250
  unit: "%",
60790
61251
  deadband: .5
@@ -61424,7 +61885,7 @@ var LawnMowerControlStatusSchema = object({
61424
61885
  batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61425
61886
  /** 0..100 mowing-completion percentage of the current task, or null when no
61426
61887
  * task is active / progress is unavailable. */
61427
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61888
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61428
61889
  /** Current device/event code (dynamic — mostly status, sometimes an error),
61429
61890
  * or null when unknown. */
61430
61891
  currentCode: number().nullable().meta(readingMeta("none")),
@@ -61924,7 +62385,7 @@ var lockControlCapability = {
61924
62385
  volatileStateFields: ["lastChangedAt"]
61925
62386
  };
61926
62387
  /**
61927
- * A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
62388
+ * A monotonic total between resets (D944). Energy uses `power-meter.energy`
61928
62389
  * so dashboards keep one series; every other instantaneous reading lands here.
61929
62390
  * `value` is the time integral in the source quantity's accumulated base
61930
62391
  * (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
@@ -62018,10 +62479,10 @@ var MediaPlayerStatusSchema = object({
62018
62479
  currentMedia: MediaInfoSchema.nullable(),
62019
62480
  /** Current playback position in ms. Null when not seekable or
62020
62481
  * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
62021
- positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
62482
+ position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
62022
62483
  /** Total duration of the current media in ms. Null when unknown
62023
62484
  * (live stream) or nothing is playing. */
62024
- durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
62485
+ duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
62025
62486
  /** Shuffle toggle. Null when no shuffle surface.
62026
62487
  * Pair with `DeviceFeature.MediaPlayerShuffle`. */
62027
62488
  shuffle: boolean().nullable(),
@@ -62060,7 +62521,7 @@ var mediaPlayerCapability = {
62060
62521
  }),
62061
62522
  seek: method(object({
62062
62523
  deviceId: number().int().nonnegative(),
62063
- positionMs: number().int().nonnegative()
62524
+ position: number().int().nonnegative()
62064
62525
  }), _void(), {
62065
62526
  kind: "mutation",
62066
62527
  auth: "protected"
@@ -62132,7 +62593,7 @@ var mediaPlayerCapability = {
62132
62593
  /**
62133
62594
  * History (D850): volume (a level an operator or an automation sets; the
62134
62595
  * default 10 s floor folds a slider drag into its end value) and mute.
62135
- * `positionMs` is not recorded: it moves continuously while playing.
62596
+ * `position` is not recorded: it moves continuously while playing.
62136
62597
  */
62137
62598
  history: { fields: {
62138
62599
  volumeLevel: {
@@ -63094,9 +63555,9 @@ var NetworkLinkStatusSchema = object({
63094
63555
  * one whose reading has not landed must not be drawn at 0 %. Consumers
63095
63556
  * SKIP a null rather than coerce it.
63096
63557
  */
63097
- signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
63558
+ signal: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
63098
63559
  /** Raw received signal strength in dBm, when the firmware reports one. */
63099
- rssiDbm: number().optional().meta(readingMeta("signal-level")),
63560
+ rssi: number().optional().meta(readingMeta("signal-level")),
63100
63561
  /** Network name of a wireless link, when the firmware reports it. */
63101
63562
  ssid: string().optional(),
63102
63563
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
@@ -63132,7 +63593,7 @@ onStatusChanged: { data: object({
63132
63593
  kind: "push",
63133
63594
  empty: {
63134
63595
  type: "unknown",
63135
- signalPercent: null,
63596
+ signal: null,
63136
63597
  lastUpdated: 0
63137
63598
  }
63138
63599
  },
@@ -63155,13 +63616,13 @@ onStatusChanged: { data: object({
63155
63616
  * History (D850): recorded series.
63156
63617
  */
63157
63618
  history: { fields: {
63158
- signalPercent: {
63619
+ signal: {
63159
63620
  kind: "gauge",
63160
63621
  unit: "%",
63161
63622
  deadband: 3,
63162
63623
  minIntervalMs: 6e4
63163
63624
  },
63164
- rssiDbm: {
63625
+ rssi: {
63165
63626
  kind: "gauge",
63166
63627
  unit: "dBm",
63167
63628
  deadband: 2,
@@ -63906,10 +64367,20 @@ var PetFeederDeviceStatusSchema = _enum([
63906
64367
  ]);
63907
64368
  var gramsPortion = number().int().min(4).max(200);
63908
64369
  var PetFeederStatusSchema = object({
63909
- /** Food currently in the bowl (grams). Null when the device has not
63910
- * reported a reading yet. On dual-hopper models this is the combined
63911
- * bowl reading; per-hopper levels live in `food1`/`food2`. */
64370
+ /** Food in the TANK (hopper), as the feeder's own sensor reports it
64371
+ * (`state.food`). A coarse level code, not grams — `0` is empty. The
64372
+ * amount in the bowl is `bowlFood`. On dual-hopper models this is the
64373
+ * combined reading; per-hopper levels live in `food1`/`food2`. Null when
64374
+ * the device has not reported yet. */
63912
64375
  foodLevel: number().nullable().meta(readingMeta("none")),
64376
+ /** Food in the BOWL as the feeder reports it (`state.bowl`), in the
64377
+ * feeder's own units. Null when the model reports none. */
64378
+ bowlFood: number().nullable().meta(readingMeta("none")),
64379
+ /** True while the pet is eating (`state.eating`). */
64380
+ eating: boolean(),
64381
+ /** Whether `markFoodReplenished` does anything on this model. When false
64382
+ * the client must not offer it. */
64383
+ supportsMarkRefilled: boolean(),
63913
64384
  /** Hopper-1 food level (grams) on dual-hopper feeders; null on
63914
64385
  * single-hopper models. */
63915
64386
  food1: number().nullable().meta(readingMeta("none")),
@@ -63917,8 +64388,8 @@ var PetFeederStatusSchema = object({
63917
64388
  * single-hopper models. */
63918
64389
  food2: number().nullable().meta(readingMeta("none")),
63919
64390
  /** Derived low-food flag — mirrors the HA `food_level` binary_sensor
63920
- * (`device_class: problem`, on = low). True when the bowl is empty /
63921
- * below the feeder's low threshold. */
64391
+ * (`device_class: problem`, on = low). True when the tank reports empty,
64392
+ * or, on a dual-hopper model, when EITHER hopper is empty. */
63922
64393
  lowFood: boolean(),
63923
64394
  /** Battery charge 0..100 (%). Null on mains-powered models or when the
63924
64395
  * device has no battery reading. */
@@ -63986,7 +64457,9 @@ var petFeederCapability = {
63986
64457
  kind: "mutation",
63987
64458
  auth: "protected"
63988
64459
  }),
63989
- /** Mark a hopper as refilled (D4H/D4S/D4SH). */
64460
+ /** Tell the PetKit cloud a hopper was refilled so it stops its low-food
64461
+ * reminders (D4H/D4S/D4SH only — see `supportsMarkRefilled`). It does not
64462
+ * change any sensor reading. */
63990
64463
  markFoodReplenished: method(object({ deviceId: number().int().nonnegative() }), _void(), {
63991
64464
  kind: "mutation",
63992
64465
  auth: "protected"
@@ -64059,6 +64532,7 @@ var petFeederCapability = {
64059
64532
  */
64060
64533
  history: { fields: {
64061
64534
  foodLevel: { kind: "gauge" },
64535
+ bowlFood: { kind: "gauge" },
64062
64536
  food1: { kind: "gauge" },
64063
64537
  food2: { kind: "gauge" },
64064
64538
  batteryPower: {
@@ -64468,16 +64942,16 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
64468
64942
  * in real-world devices.
64469
64943
  */
64470
64944
  var PowerMeterStatusSchema = object({
64471
- /** Instantaneous power draw in watts. */
64472
- watts: number().optional().meta(readingMeta("power", { label: "Power" })),
64945
+ /** Instantaneous power draw (watts). */
64946
+ power: number().optional().meta(readingMeta("power", { label: "Power" })),
64473
64947
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
64474
- kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
64475
- /** Voltage in volts. */
64476
- volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
64948
+ energy: number().optional().meta(readingMeta("energy", { label: "Energy" })),
64949
+ /** Voltage (volts). */
64950
+ voltage: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
64477
64951
  /** Current in amperes. */
64478
- amps: number().optional().meta(readingMeta("current", { label: "Current" })),
64952
+ current: number().optional().meta(readingMeta("current", { label: "Current" })),
64479
64953
  /** Apparent power in volt-amperes. */
64480
- va: number().optional().meta(readingMeta("apparent-power")),
64954
+ apparentPower: number().optional().meta(readingMeta("apparent-power")),
64481
64955
  /** Power factor (0..1) if reported. */
64482
64956
  powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
64483
64957
  /** Ms epoch when the slice was last updated. */
@@ -64535,14 +65009,14 @@ function powerTarget(id, unit) {
64535
65009
  advancedExpression: true
64536
65010
  };
64537
65011
  }
64538
- /** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
65012
+ /** "Power and energy" extension: power, energy, voltage and current from other devices (D951). */
64539
65013
  var powerMeterCustomize = {
64540
65014
  version: 1,
64541
65015
  targets: [
64542
- powerTarget("watts", "W"),
64543
- powerTarget("kwhTotal", "kWh"),
64544
- powerTarget("volts", "V"),
64545
- powerTarget("amps", "A")
65016
+ powerTarget("power", "W"),
65017
+ powerTarget("energy", "kWh"),
65018
+ powerTarget("voltage", "V"),
65019
+ powerTarget("current", "A")
64546
65020
  ]
64547
65021
  };
64548
65022
  var powerMeterCapability = {
@@ -64558,41 +65032,41 @@ var powerMeterCapability = {
64558
65032
  },
64559
65033
  runtimeState: PowerMeterStatusSchema,
64560
65034
  /**
64561
- * Runtime-state durability: **restored** — as `numeric-sensor`; `kwhTotal` is an accumulator whose restored value is the baseline.
65035
+ * Runtime-state durability: **restored** — as `numeric-sensor`; `energy` is an accumulator whose restored value is the baseline.
64562
65036
  *
64563
65037
  * See `RuntimeStateDurability`. Enforced by
64564
65038
  * `scripts/check-runtime-state-durability.ts`.
64565
65039
  */
64566
65040
  durability: "restored",
64567
65041
  /**
64568
- * History (D850): recorded series. Gauges are floored at 30 s; `kwhTotal` is the one monotonic meter (counter).
65042
+ * History (D850): recorded series. Gauges are floored at 30 s; `energy` is the one monotonic meter (counter).
64569
65043
  */
64570
65044
  history: { fields: {
64571
- watts: {
65045
+ power: {
64572
65046
  kind: "gauge",
64573
65047
  unit: "W",
64574
65048
  deadband: 1,
64575
65049
  minIntervalMs: 3e4
64576
65050
  },
64577
- kwhTotal: {
65051
+ energy: {
64578
65052
  kind: "counter",
64579
65053
  unit: "kWh",
64580
65054
  deadband: .01,
64581
65055
  minIntervalMs: 6e4
64582
65056
  },
64583
- volts: {
65057
+ voltage: {
64584
65058
  kind: "gauge",
64585
65059
  unit: "V",
64586
65060
  deadband: 1,
64587
65061
  minIntervalMs: 3e4
64588
65062
  },
64589
- amps: {
65063
+ current: {
64590
65064
  kind: "gauge",
64591
65065
  unit: "A",
64592
65066
  deadband: .05,
64593
65067
  minIntervalMs: 3e4
64594
65068
  },
64595
- va: {
65069
+ apparentPower: {
64596
65070
  kind: "gauge",
64597
65071
  unit: "VA",
64598
65072
  deadband: 1,
@@ -64642,9 +65116,6 @@ var PresenceStatusSchema = object({
64642
65116
  location: string().nullable(),
64643
65117
  /** GPS coordinates when available. Null otherwise. */
64644
65118
  gps: GpsLocationSchema.nullable(),
64645
- /** Optional battery level of the tracking device (0..100). Null
64646
- * when not reported. */
64647
- batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64648
65119
  /** Ms epoch when the slice was last updated. */
64649
65120
  lastChangedAt: number()
64650
65121
  });
@@ -64673,14 +65144,7 @@ var presenceCapability = {
64673
65144
  * `scripts/check-runtime-state-durability.ts`.
64674
65145
  */
64675
65146
  durability: "restored",
64676
- /**
64677
- * History (D850): recorded series.
64678
- */
64679
- history: { fields: { batteryPercent: {
64680
- kind: "gauge",
64681
- unit: "%",
64682
- deadband: 1
64683
- } } },
65147
+ history: "none",
64684
65148
  /** Clock fields: written, but excluded from the compare that decides
64685
65149
  * whether persisting is worth a SQLite commit. */
64686
65150
  volatileStateFields: ["lastChangedAt"]
@@ -64695,7 +65159,7 @@ var presenceCapability = {
64695
65159
  */
64696
65160
  var PressureSensorStatusSchema = object({
64697
65161
  /** Current pressure in hPa. `null` when the sample was refused (D393). */
64698
- hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
65162
+ pressure: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
64699
65163
  /** Ms epoch when the slice was last updated. */
64700
65164
  lastFetchedAt: number()
64701
65165
  });
@@ -64721,7 +65185,7 @@ var pressureSensorCapability = {
64721
65185
  /**
64722
65186
  * History (D850): recorded series.
64723
65187
  */
64724
- history: { fields: { hpa: {
65188
+ history: { fields: { pressure: {
64725
65189
  kind: "gauge",
64726
65190
  unit: "hPa",
64727
65191
  deadband: .1
@@ -68420,7 +68884,7 @@ var tamperCapability = {
68420
68884
  */
68421
68885
  var TemperatureSensorStatusSchema = object({
68422
68886
  /** Current temperature in Celsius. `null` when the sample was refused (D393). */
68423
- celsius: number().nullable().meta(readingMeta("temperature", {
68887
+ temperature: number().nullable().meta(readingMeta("temperature", {
68424
68888
  precision: 1,
68425
68889
  label: "Temperature"
68426
68890
  })),
@@ -68449,7 +68913,7 @@ var temperatureSensorCapability = {
68449
68913
  /**
68450
68914
  * History (D850): recorded series.
68451
68915
  */
68452
- history: { fields: { celsius: {
68916
+ history: { fields: { temperature: {
68453
68917
  kind: "gauge",
68454
68918
  unit: "°C",
68455
68919
  deadband: .1
@@ -68746,7 +69210,7 @@ var VacuumControlStatusSchema = object({
68746
69210
  /** Speed tokens the hardware accepts — drives the UI selector. */
68747
69211
  availableFanSpeeds: array(string()),
68748
69212
  /** 0..100 cleaning-completion percentage of the current task, or null. */
68749
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
69213
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
68750
69214
  /** Current error code (0 / null = no error). */
68751
69215
  errorCode: number().nullable().meta(readingMeta("none")),
68752
69216
  /** Human label for {@link errorCode}, or null when none / undecodable. */
@@ -70783,7 +71247,7 @@ var BaseDevice = class {
70783
71247
  * `device-local-state.ts`. Drivers access via:
70784
71248
  *
70785
71249
  * `this.state.battery.sleeping = true` // patches the battery slice
70786
- * `const pct = this.state.battery.percentage` // reads the battery slice
71250
+ * `const pct = this.state.battery.level` // reads the battery slice
70787
71251
  * `this.state.deviceStatus.online = true` // mirrors `markOnline(true)`
70788
71252
  *
70789
71253
  * Adding a new cap with `runtimeState:` automatically extends this
@@ -70823,7 +71287,7 @@ var BaseDevice = class {
70823
71287
  * shape; drivers don't redeclare it, they just write through.
70824
71288
  *
70825
71289
  * Read: `this.runtimeState.getCapState('battery')` →
70826
- * `{percentage, charging, sleeping, lastUpdated}` for any
71290
+ * `{level, charging, sleeping, lastUpdated}` for any
70827
71291
  * provider that registers `batteryCapability`.
70828
71292
  * Write: `this.runtimeState.setCapState('battery', { … })`.
70829
71293
  *
@@ -71997,6 +72461,104 @@ Object.freeze({
71997
72461
  access: "create",
71998
72462
  role: "admin"
71999
72463
  },
72464
+ "actions.create": {
72465
+ capName: "actions",
72466
+ capScope: "system",
72467
+ addonId: null,
72468
+ access: "create",
72469
+ role: "admin"
72470
+ },
72471
+ "actions.delete": {
72472
+ capName: "actions",
72473
+ capScope: "system",
72474
+ addonId: null,
72475
+ access: "delete",
72476
+ role: "admin"
72477
+ },
72478
+ "actions.get": {
72479
+ capName: "actions",
72480
+ capScope: "system",
72481
+ addonId: null,
72482
+ access: "view",
72483
+ role: "viewer"
72484
+ },
72485
+ "actions.getLinks": {
72486
+ capName: "actions",
72487
+ capScope: "system",
72488
+ addonId: null,
72489
+ access: "view",
72490
+ role: "admin"
72491
+ },
72492
+ "actions.getTraces": {
72493
+ capName: "actions",
72494
+ capScope: "system",
72495
+ addonId: null,
72496
+ access: "view",
72497
+ role: "admin"
72498
+ },
72499
+ "actions.list": {
72500
+ capName: "actions",
72501
+ capScope: "system",
72502
+ addonId: null,
72503
+ access: "view",
72504
+ role: "admin"
72505
+ },
72506
+ "actions.listForCamera": {
72507
+ capName: "actions",
72508
+ capScope: "system",
72509
+ addonId: null,
72510
+ access: "view",
72511
+ role: "viewer"
72512
+ },
72513
+ "actions.run": {
72514
+ capName: "actions",
72515
+ capScope: "system",
72516
+ addonId: null,
72517
+ access: "create",
72518
+ role: "viewer"
72519
+ },
72520
+ "actions.setLinks": {
72521
+ capName: "actions",
72522
+ capScope: "system",
72523
+ addonId: null,
72524
+ access: "create",
72525
+ role: "admin"
72526
+ },
72527
+ "actions.stop": {
72528
+ capName: "actions",
72529
+ capScope: "system",
72530
+ addonId: null,
72531
+ access: "create",
72532
+ role: "admin"
72533
+ },
72534
+ "actions.update": {
72535
+ capName: "actions",
72536
+ capScope: "system",
72537
+ addonId: null,
72538
+ access: "create",
72539
+ role: "admin"
72540
+ },
72541
+ "actionSource.listActions": {
72542
+ capName: "action-source",
72543
+ capScope: "system",
72544
+ addonId: null,
72545
+ access: "view",
72546
+ role: "admin"
72547
+ },
72548
+ "actionSource.runAction": {
72549
+ capName: "action-source",
72550
+ capScope: "system",
72551
+ addonId: null,
72552
+ access: "create",
72553
+ role: "admin"
72554
+ },
72555
+ "actionSource.stopAction": {
72556
+ capName: "action-source",
72557
+ capScope: "system",
72558
+ addonId: null,
72559
+ access: "create",
72560
+ role: "admin"
72561
+ },
72000
72562
  "addonPages.listPages": {
72001
72563
  capName: "addon-pages",
72002
72564
  capScope: "system",
@@ -73278,6 +73840,13 @@ Object.freeze({
73278
73840
  access: "view",
73279
73841
  role: "admin"
73280
73842
  },
73843
+ "coreBlocks.getAutomationRunState": {
73844
+ capName: "core-blocks",
73845
+ capScope: "system",
73846
+ addonId: null,
73847
+ access: "view",
73848
+ role: "admin"
73849
+ },
73281
73850
  "coreBlocks.getBlockSettings": {
73282
73851
  capName: "core-blocks",
73283
73852
  capScope: "system",
@@ -73299,6 +73868,13 @@ Object.freeze({
73299
73868
  access: "view",
73300
73869
  role: "admin"
73301
73870
  },
73871
+ "coreBlocks.getTraces": {
73872
+ capName: "core-blocks",
73873
+ capScope: "system",
73874
+ addonId: null,
73875
+ access: "view",
73876
+ role: "admin"
73877
+ },
73302
73878
  "coreBlocks.getTypeDefs": {
73303
73879
  capName: "core-blocks",
73304
73880
  capScope: "system",
@@ -73334,6 +73910,13 @@ Object.freeze({
73334
73910
  access: "create",
73335
73911
  role: "admin"
73336
73912
  },
73913
+ "coreBlocks.reportAutomationRun": {
73914
+ capName: "core-blocks",
73915
+ capScope: "system",
73916
+ addonId: null,
73917
+ access: "create",
73918
+ role: "admin"
73919
+ },
73337
73920
  "coreBlocks.restart": {
73338
73921
  capName: "core-blocks",
73339
73922
  capScope: "system",
@@ -81907,7 +82490,7 @@ var ACTUATOR_CAP_VOCABULARY = {
81907
82490
  label: t("Full brightness", "Luminosità massima"),
81908
82491
  phrase: t("Set {device} to full brightness", "Porta {device} alla massima luminosità"),
81909
82492
  icon: "sun",
81910
- args: { percentage: 100 }
82493
+ args: { level: 100 }
81911
82494
  },
81912
82495
  {
81913
82496
  id: "brightness.half",
@@ -81915,7 +82498,7 @@ var ACTUATOR_CAP_VOCABULARY = {
81915
82498
  label: t("Half brightness", "Luminosità a metà"),
81916
82499
  phrase: t("Dim {device} to half", "Abbassa {device} a metà luminosità"),
81917
82500
  icon: "sun-dim",
81918
- args: { percentage: 50 }
82501
+ args: { level: 50 }
81919
82502
  },
81920
82503
  {
81921
82504
  id: "brightness.off",
@@ -81923,16 +82506,16 @@ var ACTUATOR_CAP_VOCABULARY = {
81923
82506
  label: t("Brightness off", "Luminosità a zero"),
81924
82507
  phrase: t("Dim {device} to zero", "Abbassa {device} a zero"),
81925
82508
  icon: "lightbulb-off",
81926
- args: { percentage: 0 }
82509
+ args: { level: 0 }
81927
82510
  },
81928
82511
  {
81929
82512
  id: "brightness.set",
81930
82513
  method: "setBrightness",
81931
82514
  label: t("Set brightness", "Imposta la luminosità"),
81932
- phrase: t("Set the brightness of {device} to {percentage}", "Imposta la luminosità di {device} a {percentage}"),
82515
+ phrase: t("Set the brightness of {device} to {level}", "Imposta la luminosità di {device} a {level}"),
81933
82516
  icon: "sun-medium",
81934
82517
  openArgs: [{
81935
- key: "percentage",
82518
+ key: "level",
81936
82519
  label: PERCENT,
81937
82520
  offer: {
81938
82521
  kind: "number",
@@ -81946,13 +82529,13 @@ var ACTUATOR_CAP_VOCABULARY = {
81946
82529
  ],
81947
82530
  state: [{
81948
82531
  kind: "numeric",
81949
- field: "percentage",
82532
+ field: "level",
81950
82533
  quantity: t("the brightness", "la luminosità"),
81951
82534
  label: t("Brightness", "Luminosità"),
81952
82535
  unit: "%",
81953
82536
  icon: "sun"
81954
82537
  }],
81955
- events: { onBrightnessChanged: { notOperatorFacing: "the `percentage` state trigger reads the same change" } }
82538
+ events: { onBrightnessChanged: { notOperatorFacing: "the `level` state trigger reads the same change" } }
81956
82539
  },
81957
82540
  color: {
81958
82541
  scope: "device",
@@ -81966,7 +82549,7 @@ var ACTUATOR_CAP_VOCABULARY = {
81966
82549
  icon: "sun",
81967
82550
  args: { color: {
81968
82551
  mode: "mired",
81969
- mireds: 370
82552
+ colorTemperature: 370
81970
82553
  } }
81971
82554
  },
81972
82555
  {
@@ -81977,7 +82560,7 @@ var ACTUATOR_CAP_VOCABULARY = {
81977
82560
  icon: "snowflake",
81978
82561
  args: { color: {
81979
82562
  mode: "mired",
81980
- mireds: 200
82563
+ colorTemperature: 200
81981
82564
  } }
81982
82565
  },
81983
82566
  {
@@ -82591,7 +83174,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82591
83174
  label: t("Fan off", "Ventilatore spento"),
82592
83175
  phrase: t("Stop {device}", "Ferma {device}"),
82593
83176
  icon: "power-off",
82594
- args: { percentage: 0 }
83177
+ args: { speed: 0 }
82595
83178
  },
82596
83179
  {
82597
83180
  id: "fan.full",
@@ -82599,16 +83182,16 @@ var ACTUATOR_CAP_VOCABULARY = {
82599
83182
  label: t("Fan full", "Ventilatore al massimo"),
82600
83183
  phrase: t("Run {device} at full speed", "Porta {device} alla massima velocità"),
82601
83184
  icon: "fan",
82602
- args: { percentage: 100 }
83185
+ args: { speed: 100 }
82603
83186
  },
82604
83187
  {
82605
83188
  id: "fan.speed",
82606
83189
  method: "setPercentage",
82607
83190
  label: t("Set speed", "Imposta la velocità"),
82608
- phrase: t("Set the speed of {device} to {percentage}", "Imposta la velocità di {device} al {percentage}"),
83191
+ phrase: t("Set the speed of {device} to {speed}", "Imposta la velocità di {device} al {speed}"),
82609
83192
  icon: "fan",
82610
83193
  openArgs: [{
82611
- key: "percentage",
83194
+ key: "speed",
82612
83195
  label: t("Speed", "Velocità"),
82613
83196
  offer: {
82614
83197
  kind: "number",
@@ -82670,7 +83253,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82670
83253
  ],
82671
83254
  state: [{
82672
83255
  kind: "numeric",
82673
- field: "percentage",
83256
+ field: "speed",
82674
83257
  quantity: t("the speed", "la velocità"),
82675
83258
  label: t("Speed", "Velocità"),
82676
83259
  unit: "%",
@@ -83468,7 +84051,7 @@ var APPLIANCE_CAP_VOCABULARY = {
83468
84051
  },
83469
84052
  {
83470
84053
  kind: "numeric",
83471
- field: "progressPercent",
84054
+ field: "progress",
83472
84055
  quantity: t("the cycle progress", "l’avanzamento del lavaggio"),
83473
84056
  label: t("Progress", "Avanzamento"),
83474
84057
  unit: "%",
@@ -83826,10 +84409,10 @@ var APPLIANCE_CAP_VOCABULARY = {
83826
84409
  id: "media.seek",
83827
84410
  method: "seek",
83828
84411
  label: t("Seek", "Vai al punto"),
83829
- phrase: t("Move {device} to {positionMs}", "Porta {device} al punto {positionMs}"),
84412
+ phrase: t("Move {device} to {position}", "Porta {device} al punto {position}"),
83830
84413
  icon: "fast-forward",
83831
84414
  openArgs: [{
83832
- key: "positionMs",
84415
+ key: "position",
83833
84416
  label: t("Position", "Posizione"),
83834
84417
  offer: {
83835
84418
  kind: "number",
@@ -84878,7 +85461,7 @@ var SENSOR_CAP_VOCABULARY = {
84878
85461
  state: [
84879
85462
  {
84880
85463
  kind: "numeric",
84881
- field: "co2Ppm",
85464
+ field: "co2",
84882
85465
  quantity: t("the CO₂", "la CO₂"),
84883
85466
  label: t("CO₂", "CO₂"),
84884
85467
  unit: "ppm",
@@ -84886,7 +85469,7 @@ var SENSOR_CAP_VOCABULARY = {
84886
85469
  },
84887
85470
  {
84888
85471
  kind: "numeric",
84889
- field: "vocPpb",
85472
+ field: "voc",
84890
85473
  quantity: t("the VOC level", "il livello di COV"),
84891
85474
  label: t("VOC", "COV"),
84892
85475
  unit: "ppb",
@@ -84922,7 +85505,7 @@ var SENSOR_CAP_VOCABULARY = {
84922
85505
  noun: t("Light level", "Luminosità ambiente"),
84923
85506
  state: [{
84924
85507
  kind: "numeric",
84925
- field: "lux",
85508
+ field: "illuminance",
84926
85509
  quantity: t("the light level", "la luminosità"),
84927
85510
  label: t("Illuminance", "Illuminamento"),
84928
85511
  unit: "lx",
@@ -85125,7 +85708,7 @@ var SENSOR_CAP_VOCABULARY = {
85125
85708
  noun: t("Humidity", "Umidità"),
85126
85709
  state: [{
85127
85710
  kind: "numeric",
85128
- field: "percent",
85711
+ field: "humidity",
85129
85712
  quantity: t("the humidity", "l’umidità"),
85130
85713
  label: t("Humidity", "Umidità"),
85131
85714
  unit: "%",
@@ -85173,7 +85756,7 @@ var SENSOR_CAP_VOCABULARY = {
85173
85756
  state: [
85174
85757
  {
85175
85758
  kind: "numeric",
85176
- field: "watts",
85759
+ field: "power",
85177
85760
  quantity: t("the power draw", "il consumo"),
85178
85761
  label: t("Power", "Potenza"),
85179
85762
  unit: "W",
@@ -85181,7 +85764,7 @@ var SENSOR_CAP_VOCABULARY = {
85181
85764
  },
85182
85765
  {
85183
85766
  kind: "numeric",
85184
- field: "kwhTotal",
85767
+ field: "energy",
85185
85768
  quantity: t("the energy used", "l’energia consumata"),
85186
85769
  label: t("Energy", "Energia"),
85187
85770
  unit: "kWh",
@@ -85189,7 +85772,7 @@ var SENSOR_CAP_VOCABULARY = {
85189
85772
  },
85190
85773
  {
85191
85774
  kind: "numeric",
85192
- field: "volts",
85775
+ field: "voltage",
85193
85776
  quantity: t("the voltage", "la tensione"),
85194
85777
  label: t("Voltage", "Tensione"),
85195
85778
  unit: "V",
@@ -85197,7 +85780,7 @@ var SENSOR_CAP_VOCABULARY = {
85197
85780
  },
85198
85781
  {
85199
85782
  kind: "numeric",
85200
- field: "amps",
85783
+ field: "current",
85201
85784
  quantity: t("the current", "la corrente"),
85202
85785
  label: t("Current", "Corrente"),
85203
85786
  unit: "A",
@@ -85214,13 +85797,6 @@ var SENSOR_CAP_VOCABULARY = {
85214
85797
  label: t("Where", "Posizione"),
85215
85798
  phrase: t("When {device} is at {value}", "Quando {device} è in {value}"),
85216
85799
  icon: "map-pin"
85217
- }, {
85218
- kind: "numeric",
85219
- field: "batteryPercent",
85220
- quantity: t("the phone battery", "la batteria del telefono"),
85221
- label: t("Battery", "Batteria"),
85222
- unit: "%",
85223
- icon: "battery"
85224
85800
  }]
85225
85801
  },
85226
85802
  "pressure-sensor": {
@@ -85228,7 +85804,7 @@ var SENSOR_CAP_VOCABULARY = {
85228
85804
  noun: t("Pressure", "Pressione"),
85229
85805
  state: [{
85230
85806
  kind: "numeric",
85231
- field: "hpa",
85807
+ field: "pressure",
85232
85808
  quantity: t("the pressure", "la pressione"),
85233
85809
  label: t("Pressure", "Pressione"),
85234
85810
  unit: "hPa",
@@ -85264,7 +85840,7 @@ var SENSOR_CAP_VOCABULARY = {
85264
85840
  noun: t("Temperature", "Temperatura"),
85265
85841
  state: [{
85266
85842
  kind: "numeric",
85267
- field: "celsius",
85843
+ field: "temperature",
85268
85844
  quantity: t("the temperature", "la temperatura"),
85269
85845
  label: t("Temperature", "Temperatura"),
85270
85846
  unit: "°C",
@@ -85335,7 +85911,7 @@ var SENSOR_CAP_VOCABULARY = {
85335
85911
  state: [
85336
85912
  {
85337
85913
  kind: "numeric",
85338
- field: "percentage",
85914
+ field: "level",
85339
85915
  quantity: t("the battery level", "il livello della batteria"),
85340
85916
  label: t("Battery", "Batteria"),
85341
85917
  unit: "%",
@@ -85377,7 +85953,7 @@ var SENSOR_CAP_VOCABULARY = {
85377
85953
  icon: "battery-charging"
85378
85954
  }
85379
85955
  ],
85380
- events: { onStatusChanged: { notOperatorFacing: "the percentage / sleeping / charging state triggers each read one field of this change" } },
85956
+ events: { onStatusChanged: { notOperatorFacing: "the level / sleeping / charging state triggers each read one field of this change" } },
85381
85957
  extraEvents: [{
85382
85958
  category: EventCategory.DeviceAwake,
85383
85959
  label: t("Woke up", "Risvegliato"),
@@ -85395,7 +85971,7 @@ var SENSOR_CAP_VOCABULARY = {
85395
85971
  noun: t("Network link", "Collegamento di rete"),
85396
85972
  state: [{
85397
85973
  kind: "numeric",
85398
- field: "signalPercent",
85974
+ field: "signal",
85399
85975
  quantity: t("the signal strength", "l’intensità del segnale"),
85400
85976
  label: t("Signal", "Segnale"),
85401
85977
  unit: "%",
@@ -85488,6 +86064,8 @@ var ML = "model and training machinery — no device action";
85488
86064
  var INTERNAL = "internal plumbing between addons — never operator-facing";
85489
86065
  /** Every system-scoped cap, with why it is not a device's vocabulary. */
85490
86066
  var SYSTEM_CAP_VOCABULARY = {
86067
+ "action-source": system(INTERNAL),
86068
+ actions: system("declared actions — run from the Actions page and from the cameras that link them"),
85491
86069
  "addon-pages": system(UI_PLUMBING),
85492
86070
  "addon-pages-source": system(UI_PLUMBING),
85493
86071
  "addon-routes": system(UI_PLUMBING),
@@ -85684,6 +86262,31 @@ Object.freeze({
85684
86262
  form: "single",
85685
86263
  optional: false
85686
86264
  }],
86265
+ "actions.get": [{
86266
+ name: "deviceId",
86267
+ form: "single",
86268
+ optional: true
86269
+ }],
86270
+ "actions.getLinks": [{
86271
+ name: "deviceId",
86272
+ form: "single",
86273
+ optional: false
86274
+ }],
86275
+ "actions.listForCamera": [{
86276
+ name: "deviceId",
86277
+ form: "single",
86278
+ optional: false
86279
+ }],
86280
+ "actions.run": [{
86281
+ name: "deviceId",
86282
+ form: "single",
86283
+ optional: true
86284
+ }],
86285
+ "actions.setLinks": [{
86286
+ name: "deviceId",
86287
+ form: "single",
86288
+ optional: false
86289
+ }],
85687
86290
  "addonSettings.getDeviceSettings": [{
85688
86291
  name: "deviceId",
85689
86292
  form: "single",
@@ -89855,6 +90458,7 @@ function ingestReading(input) {
89855
90458
  value: converted
89856
90459
  };
89857
90460
  }
90461
+ String.raw`(?<=^|["'(\s>,\[{])`;
89858
90462
  var MB = 1024 * 1024;
89859
90463
  1024 * MB, 3072 * MB;
89860
90464
  //#endregion
@@ -96287,10 +96891,10 @@ function batteryModeForUnit(unit) {
96287
96891
  /** The canonical "value" field name for a typed sensor cap's slice. */
96288
96892
  function valueFieldForCap(cap) {
96289
96893
  switch (cap) {
96290
- case "temperature-sensor": return "celsius";
96291
- case "humidity-sensor": return "percent";
96292
- case "pressure-sensor": return "hpa";
96293
- case "ambient-light-sensor": return "lux";
96894
+ case "temperature-sensor": return "temperature";
96895
+ case "humidity-sensor": return "humidity";
96896
+ case "pressure-sensor": return "pressure";
96897
+ case "ambient-light-sensor": return "illuminance";
96294
96898
  case "numeric-sensor": return "value";
96295
96899
  }
96296
96900
  }
@@ -96535,7 +97139,7 @@ var SUPPORTED_CAPS = new Set([
96535
97139
  * - `'%'` (binary/bar batteries, already decoded to a percent) → the typed
96536
97140
  * `battery` cap (which models a 0..100 percentage).
96537
97141
  * - `'V'` (raw voltage, e.g. WS90/WH90/WS85 capacitor + soil/leaf push) →
96538
- * `battery.volts`. A voltage has no honest percentage, so `percentage`
97142
+ * `battery.voltage`. A voltage has no honest percentage, so `level`
96539
97143
  * stays null. The field lives on `battery`, so a numeric primary sensor
96540
97144
  * and a voltage battery do not share a slice.
96541
97145
  */
@@ -96549,7 +97153,7 @@ var EcowittSensorDevice = class extends BaseDevice {
96549
97153
  /**
96550
97154
  * Which battery cap (if any) was registered for this sensor:
96551
97155
  * - `'percent'` → the typed `battery` cap (percentage),
96552
- * - `'voltage'` → `battery.volts` (percentage stays null),
97156
+ * - `'voltage'` → `battery.voltage` (level stays null),
96553
97157
  * - `'none'` → no battery cap.
96554
97158
  */
96555
97159
  batteryMode = "none";
@@ -96620,7 +97224,7 @@ var EcowittSensorDevice = class extends BaseDevice {
96620
97224
  this.runtimeState.setCapState(this.capName, slice);
96621
97225
  if (this.batteryMode === "percent" && sensor.batteryUnit === "%" && typeof sensor.battery === "number") {
96622
97226
  const next = {
96623
- percentage: Math.max(0, Math.min(100, sensor.battery)),
97227
+ level: Math.max(0, Math.min(100, sensor.battery)),
96624
97228
  charging: "none",
96625
97229
  sleeping: false,
96626
97230
  lastUpdated: lastFetchedAt
@@ -96629,8 +97233,8 @@ var EcowittSensorDevice = class extends BaseDevice {
96629
97233
  }
96630
97234
  if (this.batteryMode === "voltage" && sensor.batteryUnit === "V" && typeof sensor.battery === "number" && Number.isFinite(sensor.battery)) {
96631
97235
  const next = {
96632
- percentage: null,
96633
- volts: sensor.battery,
97236
+ level: null,
97237
+ voltage: sensor.battery,
96634
97238
  charging: "none",
96635
97239
  sleeping: false,
96636
97240
  lastUpdated: lastFetchedAt
@@ -96642,7 +97246,7 @@ var EcowittSensorDevice = class extends BaseDevice {
96642
97246
  switch (this.capName) {
96643
97247
  case "temperature-sensor": {
96644
97248
  const COLD = {
96645
- celsius: 0,
97249
+ temperature: 0,
96646
97250
  lastFetchedAt: 0
96647
97251
  };
96648
97252
  this.ctx.registerNativeCap(temperatureSensorCapability, { getStatus: async () => this.readSlice(COLD) });
@@ -96651,7 +97255,7 @@ var EcowittSensorDevice = class extends BaseDevice {
96651
97255
  }
96652
97256
  case "humidity-sensor": {
96653
97257
  const COLD = {
96654
- percent: 0,
97258
+ humidity: 0,
96655
97259
  lastFetchedAt: 0
96656
97260
  };
96657
97261
  this.ctx.registerNativeCap(humiditySensorCapability, { getStatus: async () => this.readSlice(COLD) });
@@ -96660,7 +97264,7 @@ var EcowittSensorDevice = class extends BaseDevice {
96660
97264
  }
96661
97265
  case "pressure-sensor": {
96662
97266
  const COLD = {
96663
- hpa: 0,
97267
+ pressure: 0,
96664
97268
  lastFetchedAt: 0
96665
97269
  };
96666
97270
  this.ctx.registerNativeCap(pressureSensorCapability, { getStatus: async () => this.readSlice(COLD) });
@@ -96669,7 +97273,7 @@ var EcowittSensorDevice = class extends BaseDevice {
96669
97273
  }
96670
97274
  case "ambient-light-sensor": {
96671
97275
  const COLD = {
96672
- lux: 0,
97276
+ illuminance: 0,
96673
97277
  lastFetchedAt: 0
96674
97278
  };
96675
97279
  this.ctx.registerNativeCap(ambientLightSensorCapability, { getStatus: async () => this.readSlice(COLD) });
@@ -96688,8 +97292,8 @@ var EcowittSensorDevice = class extends BaseDevice {
96688
97292
  }
96689
97293
  }
96690
97294
  /**
96691
- * Register the `battery` cap. Percent batteries fill `percentage`. Voltage
96692
- * batteries fill `volts` and leave `percentage` null.
97295
+ * Register the `battery` cap. Percent batteries fill `level`. Voltage
97296
+ * batteries fill `voltage` and leave `level` null.
96693
97297
  */
96694
97298
  maybeRegisterBatteryCap() {
96695
97299
  const sensor = this.resolveSensor();
@@ -96701,7 +97305,7 @@ var EcowittSensorDevice = class extends BaseDevice {
96701
97305
  /** Register the typed `battery` (percentage) cap for a `%`-unit battery. */
96702
97306
  registerPercentBatteryCap() {
96703
97307
  const COLD = {
96704
- percentage: 0,
97308
+ level: 0,
96705
97309
  charging: "none",
96706
97310
  sleeping: false,
96707
97311
  lastUpdated: 0
@@ -96716,11 +97320,11 @@ var EcowittSensorDevice = class extends BaseDevice {
96716
97320
  this.runtimeState.setCapState("battery", COLD);
96717
97321
  this.batteryMode = "percent";
96718
97322
  }
96719
- /** Voltage batteries share the `battery` cap. `percentage` stays unknown. */
97323
+ /** Voltage batteries share the `battery` cap. `level` stays unknown. */
96720
97324
  registerVoltageBatteryCap() {
96721
97325
  const COLD = {
96722
- percentage: null,
96723
- volts: null,
97326
+ level: null,
97327
+ voltage: null,
96724
97328
  charging: "unknown",
96725
97329
  sleeping: false,
96726
97330
  lastUpdated: 0