@camstack/addon-provider-reolink 1.2.212 → 1.2.213

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
@@ -28,7 +28,7 @@ import { URL as URL$1 } from "url";
28
28
  import { spawn as spawn$1 } from "node:child_process";
29
29
  import os, { tmpdir } from "node:os";
30
30
  import { createReadStream } from "node:fs";
31
- //#region ../types/dist/event-category-CT-hz5Rb.mjs
31
+ //#region ../types/dist/event-category-DmZDPDf_.mjs
32
32
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
33
33
  EventCategory["SystemBoot"] = "system.boot";
34
34
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -655,7 +655,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
655
655
  * (a track was promoted to a stationary-registry entry) or departs (the
656
656
  * object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
657
657
  * the dedicated "Stationary" section — never the live event feed. Payload:
658
- * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp }`.
658
+ * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp, observedAt, zones }`.
659
659
  */
660
660
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
661
661
  /**
@@ -793,6 +793,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
793
793
  */
794
794
  EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
795
795
  /**
796
+ * An action run started or ended. Emitted by the `actions` surface.
797
+ * Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
798
+ */
799
+ EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
800
+ /**
796
801
  * Progress update from a running model conversion job.
797
802
  * Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
798
803
  * Emitted by `addon-model-studio` on the converting node.
@@ -5471,7 +5476,7 @@ var ZodIssueCode = {
5471
5476
  var ZodFirstPartyTypeKind;
5472
5477
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5473
5478
  //#endregion
5474
- //#region ../types/dist/sleep--jXS9hWo.mjs
5479
+ //#region ../types/dist/sleep-Crlmu_tO.mjs
5475
5480
  /**
5476
5481
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5477
5482
  * window to float samples (D455).
@@ -8629,6 +8634,8 @@ Object.freeze({ "doorbell": "lastPressedAt" });
8629
8634
  /** Every capability name, so addon code can check a name without the schema graph. */
8630
8635
  var CAP_NAMES = Object.freeze([
8631
8636
  "accessories",
8637
+ "action-source",
8638
+ "actions",
8632
8639
  "addon-pages",
8633
8640
  "addon-pages-source",
8634
8641
  "addon-routes",
@@ -8817,11 +8824,11 @@ var CAP_NAMES = Object.freeze([
8817
8824
  Object.freeze({
8818
8825
  "air-quality-sensor": [
8819
8826
  {
8820
- "path": "co2Ppm",
8827
+ "path": "co2",
8821
8828
  "valueType": "number"
8822
8829
  },
8823
8830
  {
8824
- "path": "vocPpb",
8831
+ "path": "voc",
8825
8832
  "valueType": "number"
8826
8833
  },
8827
8834
  {
@@ -8871,7 +8878,7 @@ Object.freeze({
8871
8878
  }
8872
8879
  ],
8873
8880
  "ambient-light-sensor": [{
8874
- "path": "lux",
8881
+ "path": "illuminance",
8875
8882
  "valueType": "number"
8876
8883
  }],
8877
8884
  "audio-metrics": [
@@ -8932,7 +8939,7 @@ Object.freeze({
8932
8939
  ],
8933
8940
  "battery": [
8934
8941
  {
8935
- "path": "percentage",
8942
+ "path": "level",
8936
8943
  "valueType": "number"
8937
8944
  },
8938
8945
  {
@@ -8954,7 +8961,7 @@ Object.freeze({
8954
8961
  "valueType": "number"
8955
8962
  },
8956
8963
  {
8957
- "path": "volts",
8964
+ "path": "voltage",
8958
8965
  "valueType": "number"
8959
8966
  },
8960
8967
  {
@@ -8975,7 +8982,7 @@ Object.freeze({
8975
8982
  "valueType": "boolean"
8976
8983
  }],
8977
8984
  "brightness": [{
8978
- "path": "percentage",
8985
+ "path": "level",
8979
8986
  "valueType": "number"
8980
8987
  }],
8981
8988
  "broker": [{
@@ -9176,7 +9183,7 @@ Object.freeze({
9176
9183
  "valueType": "number"
9177
9184
  },
9178
9185
  {
9179
- "path": "mireds",
9186
+ "path": "colorTemperature",
9180
9187
  "valueType": "number"
9181
9188
  }
9182
9189
  ],
@@ -9355,15 +9362,15 @@ Object.freeze({
9355
9362
  "valueType": "string"
9356
9363
  },
9357
9364
  {
9358
- "path": "remainingSeconds",
9365
+ "path": "remaining",
9359
9366
  "valueType": "number"
9360
9367
  },
9361
9368
  {
9362
- "path": "delayedStartSeconds",
9369
+ "path": "delayedStart",
9363
9370
  "valueType": "number"
9364
9371
  },
9365
9372
  {
9366
- "path": "progressPercent",
9373
+ "path": "progress",
9367
9374
  "valueType": "number"
9368
9375
  },
9369
9376
  {
@@ -9477,7 +9484,7 @@ Object.freeze({
9477
9484
  ],
9478
9485
  "fan-control": [
9479
9486
  {
9480
- "path": "percentage",
9487
+ "path": "speed",
9481
9488
  "valueType": "number"
9482
9489
  },
9483
9490
  {
@@ -9577,7 +9584,7 @@ Object.freeze({
9577
9584
  }
9578
9585
  ],
9579
9586
  "humidity-sensor": [{
9580
- "path": "percent",
9587
+ "path": "humidity",
9581
9588
  "valueType": "number"
9582
9589
  }],
9583
9590
  "image": [{
@@ -9687,7 +9694,7 @@ Object.freeze({
9687
9694
  "valueType": "number"
9688
9695
  },
9689
9696
  {
9690
- "path": "progressPercent",
9697
+ "path": "progress",
9691
9698
  "valueType": "number"
9692
9699
  },
9693
9700
  {
@@ -9766,11 +9773,11 @@ Object.freeze({
9766
9773
  "valueType": "string"
9767
9774
  },
9768
9775
  {
9769
- "path": "positionMs",
9776
+ "path": "position",
9770
9777
  "valueType": "number"
9771
9778
  },
9772
9779
  {
9773
- "path": "durationMs",
9780
+ "path": "duration",
9774
9781
  "valueType": "number"
9775
9782
  },
9776
9783
  {
@@ -9872,11 +9879,11 @@ Object.freeze({
9872
9879
  ]
9873
9880
  },
9874
9881
  {
9875
- "path": "signalPercent",
9882
+ "path": "signal",
9876
9883
  "valueType": "number"
9877
9884
  },
9878
9885
  {
9879
- "path": "rssiDbm",
9886
+ "path": "rssi",
9880
9887
  "valueType": "number"
9881
9888
  },
9882
9889
  {
@@ -9931,6 +9938,18 @@ Object.freeze({
9931
9938
  "path": "foodLevel",
9932
9939
  "valueType": "number"
9933
9940
  },
9941
+ {
9942
+ "path": "bowlFood",
9943
+ "valueType": "number"
9944
+ },
9945
+ {
9946
+ "path": "eating",
9947
+ "valueType": "boolean"
9948
+ },
9949
+ {
9950
+ "path": "supportsMarkRefilled",
9951
+ "valueType": "boolean"
9952
+ },
9934
9953
  {
9935
9954
  "path": "food1",
9936
9955
  "valueType": "number"
@@ -9995,23 +10014,23 @@ Object.freeze({
9995
10014
  ],
9996
10015
  "power-meter": [
9997
10016
  {
9998
- "path": "watts",
10017
+ "path": "power",
9999
10018
  "valueType": "number"
10000
10019
  },
10001
10020
  {
10002
- "path": "kwhTotal",
10021
+ "path": "energy",
10003
10022
  "valueType": "number"
10004
10023
  },
10005
10024
  {
10006
- "path": "volts",
10025
+ "path": "voltage",
10007
10026
  "valueType": "number"
10008
10027
  },
10009
10028
  {
10010
- "path": "amps",
10029
+ "path": "current",
10011
10030
  "valueType": "number"
10012
10031
  },
10013
10032
  {
10014
- "path": "va",
10033
+ "path": "apparentPower",
10015
10034
  "valueType": "number"
10016
10035
  },
10017
10036
  {
@@ -10039,14 +10058,10 @@ Object.freeze({
10039
10058
  {
10040
10059
  "path": "gps.accuracyMeters",
10041
10060
  "valueType": "number"
10042
- },
10043
- {
10044
- "path": "batteryPercent",
10045
- "valueType": "number"
10046
10061
  }
10047
10062
  ],
10048
10063
  "pressure-sensor": [{
10049
- "path": "hpa",
10064
+ "path": "pressure",
10050
10065
  "valueType": "number"
10051
10066
  }],
10052
10067
  "privacy-mask": [{
@@ -10360,7 +10375,7 @@ Object.freeze({
10360
10375
  "valueType": "boolean"
10361
10376
  }],
10362
10377
  "temperature-sensor": [{
10363
- "path": "celsius",
10378
+ "path": "temperature",
10364
10379
  "valueType": "number"
10365
10380
  }],
10366
10381
  "update": [
@@ -10408,7 +10423,7 @@ Object.freeze({
10408
10423
  "valueType": "string"
10409
10424
  },
10410
10425
  {
10411
- "path": "progressPercent",
10426
+ "path": "progress",
10412
10427
  "valueType": "number"
10413
10428
  },
10414
10429
  {
@@ -10921,7 +10936,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
10921
10936
  return DeviceRole;
10922
10937
  }({});
10923
10938
  //#endregion
10924
- //#region ../types/dist/composition-Bb8iwHEJ.mjs
10939
+ //#region ../types/dist/composition-CZImLpOI.mjs
10925
10940
  /**
10926
10941
  * The ffmpeg build every CamStack node downloads, per platform and arch.
10927
10942
  *
@@ -16011,6 +16026,14 @@ var AutomationConditionLeafSchema = object({
16011
16026
  array(union([string(), number()]))
16012
16027
  ])
16013
16028
  });
16029
+ var AutomationConditionStationaryPresentSchema = object({
16030
+ kind: literal("stationary-present"),
16031
+ deviceId: number().int().nonnegative(),
16032
+ /** Class names; a macro class matches every raw class that maps to it. */
16033
+ classes: array(string().min(1)).min(1).optional(),
16034
+ /** The parked object must be in at least one of these zones. */
16035
+ zones: array(string().min(1)).min(1).optional()
16036
+ });
16014
16037
  /**
16015
16038
  * The expression leaf, declared as a plain object rather than an intersection
16016
16039
  * with {@link ExpressionSourceSchema}: a discriminated union has to be able to
@@ -16044,7 +16067,8 @@ var AutomationConditionSchema = lazy(() => discriminatedUnion("kind", [
16044
16067
  child: AutomationConditionSchema
16045
16068
  }),
16046
16069
  AutomationConditionLeafSchema,
16047
- AutomationConditionExpressionSchema
16070
+ AutomationConditionExpressionSchema,
16071
+ AutomationConditionStationaryPresentSchema
16048
16072
  ]));
16049
16073
  /**
16050
16074
  * What starts a run.
@@ -16085,7 +16109,34 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
16085
16109
  kind: literal("schedule"),
16086
16110
  cron: string().min(1).max(120)
16087
16111
  }),
16088
- object({ kind: literal("manual") })
16112
+ object({ kind: literal("manual") }),
16113
+ object({
16114
+ kind: literal("detection"),
16115
+ /** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
16116
+ * matches every raw class that maps to it; any other name matches
16117
+ * exactly. */
16118
+ classes: array(string().min(1)).min(1),
16119
+ deviceIds: array(number().int().nonnegative()).min(1),
16120
+ /** The track must have visited at least one of these zones. */
16121
+ zones: array(string().min(1)).min(1).optional(),
16122
+ /** Best-so-far confidence the track must reach. */
16123
+ minScore: number().min(0).max(1).optional()
16124
+ }),
16125
+ object({
16126
+ kind: literal("stationary"),
16127
+ deviceIds: array(number().int().nonnegative()).min(1),
16128
+ /** Class names; a macro class matches like the detection trigger. */
16129
+ classes: array(string().min(1)).min(1).optional(),
16130
+ /** The parked object must be in at least one of these zones. */
16131
+ zones: array(string().min(1)).min(1).optional(),
16132
+ /** `appeared`: it became parked. `departed`: the registry retired it.
16133
+ * The vocabulary of `PipelineAnalyticsStationaryChanged`. */
16134
+ phase: _enum(["appeared", "departed"])
16135
+ }),
16136
+ object({
16137
+ kind: literal("interval"),
16138
+ minutes: number().int().min(1).max(1440)
16139
+ })
16089
16140
  ]);
16090
16141
  /**
16091
16142
  * One action step.
@@ -16105,28 +16156,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
16105
16156
  * is called. The runner still receives a number and is untouched; the
16106
16157
  * resolution is the recipe's job, not the runner's.
16107
16158
  */
16159
+ var AutomationWaitStepSchema = object({
16160
+ kind: literal("wait"),
16161
+ seconds: number().min(0).max(300)
16162
+ });
16163
+ var AutomationCapStepSchema = object({
16164
+ kind: literal("cap"),
16165
+ /**
16166
+ * One device, several same-family devices (locks / climate family / …),
16167
+ * or `{ $var }` for the device that triggered the run. An array is
16168
+ * fan-out at codegen — each id gets the same cap.method call.
16169
+ */
16170
+ deviceId: union([
16171
+ number().int(),
16172
+ array(number().int()).min(1),
16173
+ object({ $var: string().min(1) })
16174
+ ]),
16175
+ cap: string().min(1),
16176
+ method: string().min(1),
16177
+ /** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
16178
+ * SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
16179
+ * the expression leaf. */
16180
+ args: record(string(), unknown()).optional()
16181
+ });
16182
+ /**
16183
+ * The steps an internal Action may contain: cap and wait, and nothing that can
16184
+ * call back into an Action — so an Action can never reach itself (no cycles).
16185
+ */
16186
+ var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
16108
16187
  var AutomationActionSchema = discriminatedUnion("kind", [
16188
+ AutomationWaitStepSchema,
16189
+ AutomationCapStepSchema,
16109
16190
  object({
16110
- kind: literal("wait"),
16111
- seconds: number().min(0).max(300)
16112
- }),
16113
- object({
16114
- kind: literal("cap"),
16115
- /**
16116
- * One device, several same-family devices (locks / climate family / …),
16117
- * or `{ $var }` for the device that triggered the run. An array is
16118
- * fan-out at codegen — each id gets the same cap.method call.
16119
- */
16120
- deviceId: union([
16121
- number().int(),
16122
- array(number().int()).min(1),
16123
- object({ $var: string().min(1) })
16124
- ]),
16125
- cap: string().min(1),
16126
- method: string().min(1),
16127
- /** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
16128
- * evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
16129
- args: record(string(), unknown()).optional()
16191
+ kind: literal("action"),
16192
+ /** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
16193
+ actionId: string().min(1),
16194
+ /** Values for the action's declared variables; the others take their default. */
16195
+ variables: record(string(), union([
16196
+ string(),
16197
+ number(),
16198
+ boolean()
16199
+ ])).optional()
16130
16200
  }),
16131
16201
  object({
16132
16202
  kind: literal("code"),
@@ -16135,10 +16205,357 @@ var AutomationActionSchema = discriminatedUnion("kind", [
16135
16205
  code: string().min(1).max(2e4)
16136
16206
  })
16137
16207
  ]);
16208
+ /**
16209
+ * How a trigger that arrives while the automation is busy (or cooling down) is
16210
+ * handled. One of the automation's execution modes, never a property of its
16211
+ * actions. Absent means `single`.
16212
+ *
16213
+ * - `single` — drop the trigger while a run is in progress (traced + logged).
16214
+ * - `restart` — abort the run in progress (at its next step boundary), start fresh.
16215
+ * - `queued` — queue up to `max` triggers, drop the rest (traced).
16216
+ * - `parallel` — up to `max` runs at once, drop the rest (traced).
16217
+ * - `cooldown` — `single`, and no new run until `minutes` after the last run
16218
+ * STARTED; persisted across a restart. A manual trigger bypasses only this
16219
+ * wait, never the single/queued limits.
16220
+ */
16221
+ var AutomationRunModeSchema = discriminatedUnion("mode", [
16222
+ object({ mode: literal("single") }),
16223
+ object({ mode: literal("restart") }),
16224
+ object({
16225
+ mode: literal("queued"),
16226
+ max: number().int().min(1).max(10)
16227
+ }),
16228
+ object({
16229
+ mode: literal("parallel"),
16230
+ max: number().int().min(1).max(10)
16231
+ }),
16232
+ object({
16233
+ mode: literal("cooldown"),
16234
+ minutes: number().int().min(1).max(1440)
16235
+ })
16236
+ ]);
16138
16237
  var AutomationRecipeSchema = object({
16139
16238
  triggers: array(AutomationTriggerSchema),
16140
16239
  conditions: AutomationConditionSchema.optional(),
16141
- actions: array(AutomationActionSchema)
16240
+ actions: array(AutomationActionSchema),
16241
+ runMode: AutomationRunModeSchema.optional(),
16242
+ /** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
16243
+ keepTraces: number().int().min(1).max(100).optional()
16244
+ });
16245
+ new Set([
16246
+ {
16247
+ id: "person",
16248
+ name: "Person"
16249
+ },
16250
+ {
16251
+ id: "vehicle",
16252
+ name: "Vehicle"
16253
+ },
16254
+ {
16255
+ id: "animal",
16256
+ name: "Animal"
16257
+ },
16258
+ {
16259
+ id: "package",
16260
+ name: "Package"
16261
+ }
16262
+ ].map((l) => l.id));
16263
+ var COCO_TO_MACRO = {
16264
+ mapping: {
16265
+ person: "person",
16266
+ bicycle: "vehicle",
16267
+ car: "vehicle",
16268
+ motorcycle: "vehicle",
16269
+ airplane: "vehicle",
16270
+ bus: "vehicle",
16271
+ train: "vehicle",
16272
+ truck: "vehicle",
16273
+ boat: "vehicle",
16274
+ bird: "animal",
16275
+ cat: "animal",
16276
+ dog: "animal",
16277
+ horse: "animal",
16278
+ sheep: "animal",
16279
+ cow: "animal",
16280
+ elephant: "animal",
16281
+ bear: "animal",
16282
+ zebra: "animal",
16283
+ giraffe: "animal",
16284
+ suitcase: "package",
16285
+ backpack: "package",
16286
+ handbag: "package"
16287
+ },
16288
+ preserveOriginal: false
16289
+ };
16290
+ new Set(Object.values(COCO_TO_MACRO.mapping));
16291
+ /**
16292
+ * Run traces — what an automation (or, later, an Action run) DID, node by node,
16293
+ * so the editor can paint every block green or red with its reason.
16294
+ *
16295
+ * A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
16296
+ * every condition node (containers and leaves, including the ones a
16297
+ * short-circuit never reached), the run-mode verdict and every action step —
16298
+ * each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
16299
+ * for an Action run). Skipped
16300
+ * evaluations are traced too, and identical consecutive skips collapse into a
16301
+ * repeat count so a trigger that fails every 5 minutes cannot flush real runs.
16302
+ *
16303
+ * {@link AutomationStepTraceSchema} is deliberately free of automation
16304
+ * vocabulary so an Action run records the same step shape.
16305
+ */
16306
+ /** A value a trace may show: JSON primitives and short lists, nothing deeper. */
16307
+ var TraceValueSchema = union([
16308
+ string(),
16309
+ number(),
16310
+ boolean(),
16311
+ _null(),
16312
+ array(union([string(), number()]))
16313
+ ]);
16314
+ var AutomationRunOutcomeSchema = _enum([
16315
+ "ran",
16316
+ "skipped-trigger",
16317
+ "skipped-conditions",
16318
+ "skipped-cooldown",
16319
+ "skipped-overlap",
16320
+ "failed",
16321
+ "aborted"
16322
+ ]);
16323
+ /** `not-evaluated` = a short-circuit never reached the node. */
16324
+ var TraceNodeOutcomeSchema = _enum([
16325
+ "pass",
16326
+ "fail",
16327
+ "not-evaluated"
16328
+ ]);
16329
+ var AutomationTriggerTraceSchema = object({
16330
+ kind: string().min(1),
16331
+ outcome: _enum(["pass", "fail"]),
16332
+ /** Why an event was rejected ("class person not in [dog]") or what fired. */
16333
+ reason: string(),
16334
+ /** deviceId, className, trackId, score … — only what the trigger exposes. */
16335
+ vars: record(string(), TraceValueSchema)
16336
+ });
16337
+ var AutomationConditionTraceNodeSchema = object({
16338
+ /** `conditions` for the root, `conditions.<i>` for its i-th child, … */
16339
+ path: string().min(1),
16340
+ kind: _enum([
16341
+ "all",
16342
+ "any",
16343
+ "not",
16344
+ "condition",
16345
+ "expression",
16346
+ "stationary-present"
16347
+ ]),
16348
+ outcome: TraceNodeOutcomeSchema,
16349
+ reason: string(),
16350
+ deviceId: number().int().optional(),
16351
+ cap: string().optional(),
16352
+ fieldPath: string().optional(),
16353
+ operator: string().optional(),
16354
+ expected: TraceValueSchema.optional(),
16355
+ /** What the mirror held; `null` when it held nothing (unknown). */
16356
+ observed: TraceValueSchema.optional()
16357
+ });
16358
+ var AutomationRunVerdictSchema = object({
16359
+ mode: AutomationRunModeSchema,
16360
+ decision: _enum([
16361
+ "run",
16362
+ "queued",
16363
+ "restart",
16364
+ "drop",
16365
+ "cooldown",
16366
+ "bypass"
16367
+ ]),
16368
+ reason: string()
16369
+ });
16370
+ /** One executed (or not-run) step — shared by automations and Action runs. */
16371
+ var AutomationStepTraceSchema = object({
16372
+ /** `actions.<i>` */
16373
+ path: string().min(1),
16374
+ kind: string().min(1),
16375
+ cap: string().optional(),
16376
+ method: string().optional(),
16377
+ deviceId: number().int().optional(),
16378
+ startedAt: number().optional(),
16379
+ endedAt: number().optional(),
16380
+ outcome: _enum([
16381
+ "ok",
16382
+ "error",
16383
+ "not-run"
16384
+ ]),
16385
+ message: string().optional()
16386
+ });
16387
+ var AutomationRunTraceSchema = object({
16388
+ runId: string().min(1),
16389
+ startedAt: number(),
16390
+ endedAt: number(),
16391
+ trigger: AutomationTriggerTraceSchema,
16392
+ conditions: array(AutomationConditionTraceNodeSchema),
16393
+ verdict: AutomationRunVerdictSchema.optional(),
16394
+ steps: array(AutomationStepTraceSchema),
16395
+ outcome: AutomationRunOutcomeSchema,
16396
+ /** How many identical consecutive skips this trace stands for (>= 1). */
16397
+ repeat: number().int().min(1),
16398
+ /** When the latest of those repeats happened. */
16399
+ lastAt: number()
16400
+ });
16401
+ /**
16402
+ * What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
16403
+ * `action:<actionId>`): the cooldown stamp and the trace ring.
16404
+ */
16405
+ var AutomationStateDocSchema = object({
16406
+ version: literal(1),
16407
+ lastRunStartedAt: number().nullable(),
16408
+ traces: array(AutomationRunTraceSchema)
16409
+ });
16410
+ /**
16411
+ * Actions — named, runnable things an operator (or an automation) can start,
16412
+ * declared as LIST ENTRIES, never as devices.
16413
+ *
16414
+ * An entry is either **internal** (a short list of cap/wait steps kept in the
16415
+ * hub's `actions` record kind) or declared by an addon through the
16416
+ * `action-source` collection (a Home Assistant script, a scene …). The one
16417
+ * surface the UI and automations talk to is the `actions` cap; it keeps no
16418
+ * catalog of its own (D3) — every `list` asks the providers live.
16419
+ *
16420
+ * This file is the data half: the entry schema, the variables an entry may
16421
+ * declare, and the pure resolution of the values a run was given. It holds no
16422
+ * runtime.
16423
+ */
16424
+ /** What a variable's value is. `select` takes one of `options`. */
16425
+ var ActionVariableTypeSchema = _enum([
16426
+ "string",
16427
+ "number",
16428
+ "boolean",
16429
+ "select"
16430
+ ]);
16431
+ var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
16432
+ var ActionVariableValueSchema = union([
16433
+ string(),
16434
+ number(),
16435
+ boolean()
16436
+ ]);
16437
+ /**
16438
+ * One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
16439
+ * value) or `{{vars.name}}` (inside a string) in their args.
16440
+ */
16441
+ var ActionVariableSchema = object({
16442
+ name: string().regex(ACTION_VARIABLE_NAME_RE),
16443
+ label: string().min(1).max(120).optional(),
16444
+ type: ActionVariableTypeSchema,
16445
+ required: boolean().optional(),
16446
+ default: ActionVariableValueSchema.optional(),
16447
+ /** The allowed values of a `select`. */
16448
+ options: array(string().min(1)).min(1).optional()
16449
+ }).superRefine((v, ctx) => {
16450
+ if (v.type === "select" && v.options === void 0) ctx.addIssue({
16451
+ code: "custom",
16452
+ message: "a select variable needs options",
16453
+ path: ["options"]
16454
+ });
16455
+ if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
16456
+ code: "custom",
16457
+ message: variableValueError(v, v.default) ?? "invalid default",
16458
+ path: ["default"]
16459
+ });
16460
+ });
16461
+ /** Why `value` is not a legal value for the variable, or null when it is. */
16462
+ function variableValueError(variable, value) {
16463
+ switch (variable.type) {
16464
+ case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
16465
+ case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
16466
+ case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
16467
+ case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
16468
+ }
16469
+ }
16470
+ var ActionSourceKindSchema = _enum(["internal", "addon"]);
16471
+ function isInternalActionId(actionId) {
16472
+ return actionId.startsWith("internal:") && actionId.length > 9;
16473
+ }
16474
+ /** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
16475
+ function addonIdOfActionId(actionId) {
16476
+ if (isInternalActionId(actionId)) return null;
16477
+ const at = actionId.indexOf(":");
16478
+ return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
16479
+ }
16480
+ var ActionStatusSchema = object({
16481
+ isRunning: boolean(),
16482
+ /** Ms epoch the latest run STARTED; null when it never ran. */
16483
+ lastRunAt: number().nullable(),
16484
+ /** The latest run's failure; null on success or when it never ran. */
16485
+ lastError: string().nullable()
16486
+ });
16487
+ var ActionEntrySchema = object({
16488
+ /** `internal:<uuid>` or `<addonId>:<localId>`. */
16489
+ id: string().min(3),
16490
+ name: string().min(1).max(120),
16491
+ /** The addon that declared it; `core-blocks` for an internal one. */
16492
+ addonId: string().min(1),
16493
+ source: ActionSourceKindSchema,
16494
+ /** An addon-declared entry is edited where it was declared. */
16495
+ readOnly: boolean(),
16496
+ /** Internal only: cap and wait steps. No action-in-action, so no cycles. */
16497
+ steps: array(ActionStepSchema).min(1).max(50).optional(),
16498
+ variables: array(ActionVariableSchema).max(20).optional(),
16499
+ status: ActionStatusSchema
16500
+ }).superRefine((entry, ctx) => {
16501
+ if (entry.source === "internal") {
16502
+ if (!isInternalActionId(entry.id)) ctx.addIssue({
16503
+ code: "custom",
16504
+ message: "an internal action id is internal:<uuid>",
16505
+ path: ["id"]
16506
+ });
16507
+ return;
16508
+ }
16509
+ if (entry.steps !== void 0) ctx.addIssue({
16510
+ code: "custom",
16511
+ message: "only an internal action carries steps",
16512
+ path: ["steps"]
16513
+ });
16514
+ if (!entry.readOnly) ctx.addIssue({
16515
+ code: "custom",
16516
+ message: "an addon action is read-only here",
16517
+ path: ["readOnly"]
16518
+ });
16519
+ if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
16520
+ code: "custom",
16521
+ message: "an addon action id is <addonId>:<localId>",
16522
+ path: ["id"]
16523
+ });
16524
+ });
16525
+ /** What an operator writes for an internal action. */
16526
+ var ActionInputSchema = object({
16527
+ name: string().min(1).max(120),
16528
+ steps: array(ActionStepSchema).min(1).max(50),
16529
+ variables: array(ActionVariableSchema).max(20).optional()
16530
+ });
16531
+ /** Who started a run. Absent = the operator pressed it. */
16532
+ var ActionRunOriginSchema = object({
16533
+ /** The automation block whose step started it. */
16534
+ blockId: string().min(1).optional() });
16535
+ /** `started` = the caller did not ask to wait. */
16536
+ var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
16537
+ var ActionRunResultSchema = object({
16538
+ runId: string().min(1),
16539
+ outcome: ActionRunOutcomeSchema,
16540
+ /** Why it did not run, or what failed. */
16541
+ message: string().optional()
16542
+ });
16543
+ _enum([
16544
+ "not-found",
16545
+ "read-only",
16546
+ "invalid-variables",
16547
+ "invalid-steps",
16548
+ "not-linked",
16549
+ "busy"
16550
+ ]);
16551
+ object({
16552
+ actionId: string(),
16553
+ runId: string(),
16554
+ isRunning: boolean(),
16555
+ /** Set when the run ended. */
16556
+ outcome: AutomationRunOutcomeSchema.optional(),
16557
+ lastRunAt: number().nullable(),
16558
+ lastError: string().nullable()
16142
16559
  });
16143
16560
  /**
16144
16561
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
@@ -18825,7 +19242,7 @@ var CompositionEventPlanSchema = object({
18825
19242
  stateField: string(),
18826
19243
  fieldKey: string()
18827
19244
  });
18828
- /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
19245
+ /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.temperature`. */
18829
19246
  var CompositionProblemSchema = object({
18830
19247
  code: _enum([
18831
19248
  "reserved-variant",
@@ -19144,7 +19561,7 @@ var GROUP_TEMPLATES = [
19144
19561
  summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
19145
19562
  role: DeviceRole.TemperatureSensor,
19146
19563
  outputCap: "temperature-sensor",
19147
- outputField: "celsius",
19564
+ outputField: "temperature",
19148
19565
  quantity: "temperature",
19149
19566
  defaultAggregate: "mean",
19150
19567
  empty: "null",
@@ -19155,7 +19572,7 @@ var GROUP_TEMPLATES = [
19155
19572
  summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
19156
19573
  role: DeviceRole.HumiditySensor,
19157
19574
  outputCap: "humidity-sensor",
19158
- outputField: "percent",
19575
+ outputField: "humidity",
19159
19576
  quantity: "humidity",
19160
19577
  defaultAggregate: "mean",
19161
19578
  empty: "null",
@@ -19166,7 +19583,7 @@ var GROUP_TEMPLATES = [
19166
19583
  summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
19167
19584
  role: DeviceRole.PressureSensor,
19168
19585
  outputCap: "pressure-sensor",
19169
- outputField: "hpa",
19586
+ outputField: "pressure",
19170
19587
  quantity: "pressure",
19171
19588
  defaultAggregate: "mean",
19172
19589
  empty: "null",
@@ -19177,7 +19594,7 @@ var GROUP_TEMPLATES = [
19177
19594
  summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
19178
19595
  role: DeviceRole.AmbientLightSensor,
19179
19596
  outputCap: "ambient-light-sensor",
19180
- outputField: "lux",
19597
+ outputField: "illuminance",
19181
19598
  quantity: "illuminance",
19182
19599
  defaultAggregate: "mean",
19183
19600
  empty: "null",
@@ -19188,7 +19605,7 @@ var GROUP_TEMPLATES = [
19188
19605
  summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
19189
19606
  role: DeviceRole.PowerSensor,
19190
19607
  outputCap: "power-meter",
19191
- outputField: "watts",
19608
+ outputField: "power",
19192
19609
  quantity: "power",
19193
19610
  defaultAggregate: "sum",
19194
19611
  empty: "omit",
@@ -19199,7 +19616,7 @@ var GROUP_TEMPLATES = [
19199
19616
  summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
19200
19617
  role: DeviceRole.EnergySensor,
19201
19618
  outputCap: "power-meter",
19202
- outputField: "kwhTotal",
19619
+ outputField: "energy",
19203
19620
  quantity: "energy",
19204
19621
  defaultAggregate: "sum",
19205
19622
  empty: "omit",
@@ -19210,7 +19627,7 @@ var GROUP_TEMPLATES = [
19210
19627
  summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
19211
19628
  role: DeviceRole.BatterySensor,
19212
19629
  outputCap: "battery",
19213
- outputField: "percentage",
19630
+ outputField: "level",
19214
19631
  quantity: "percentage",
19215
19632
  defaultAggregate: "mean",
19216
19633
  empty: "null",
@@ -19788,7 +20205,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
19788
20205
  kind: "mutation",
19789
20206
  auth: "admin",
19790
20207
  access: "view"
19791
- });
20208
+ }), method(object({
20209
+ blockId: string().min(1),
20210
+ trace: AutomationRunTraceSchema.optional(),
20211
+ runStartedAt: number().optional(),
20212
+ keepTraces: number().int().min(1).max(100).optional()
20213
+ }), _void(), {
20214
+ kind: "mutation",
20215
+ auth: "admin"
20216
+ }), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
20217
+ traces: array(AutomationRunTraceSchema),
20218
+ lastError: string().nullable()
20219
+ }), { auth: "admin" });
19792
20220
  /**
19793
20221
  * `custom-model-registry` — collection cap exposing operator-registered
19794
20222
  * custom detection models. Each provider (today: `addon-model-studio`)
@@ -45226,51 +45654,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
45226
45654
  kind: "mutation",
45227
45655
  auth: "admin"
45228
45656
  });
45229
- new Set([
45230
- {
45231
- id: "person",
45232
- name: "Person"
45233
- },
45234
- {
45235
- id: "vehicle",
45236
- name: "Vehicle"
45237
- },
45238
- {
45239
- id: "animal",
45240
- name: "Animal"
45241
- },
45242
- {
45243
- id: "package",
45244
- name: "Package"
45245
- }
45246
- ].map((l) => l.id));
45247
- var COCO_TO_MACRO = {
45248
- mapping: {
45249
- person: "person",
45250
- bicycle: "vehicle",
45251
- car: "vehicle",
45252
- motorcycle: "vehicle",
45253
- airplane: "vehicle",
45254
- bus: "vehicle",
45255
- train: "vehicle",
45256
- truck: "vehicle",
45257
- boat: "vehicle",
45258
- bird: "animal",
45259
- cat: "animal",
45260
- dog: "animal",
45261
- horse: "animal",
45262
- sheep: "animal",
45263
- cow: "animal",
45264
- elephant: "animal",
45265
- bear: "animal",
45266
- zebra: "animal",
45267
- giraffe: "animal",
45268
- suitcase: "package",
45269
- backpack: "package",
45270
- handbag: "package"
45271
- },
45272
- preserveOriginal: false
45273
- };
45274
45657
  var AUDIO_MACRO_LABELS = [
45275
45658
  {
45276
45659
  id: "speech",
@@ -58359,9 +58742,9 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
58359
58742
  */
58360
58743
  var AirQualitySensorStatusSchema = object({
58361
58744
  /** Carbon dioxide concentration in ppm. */
58362
- co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
58745
+ co2: number().min(0).optional().meta(readingMeta("concentration-volume")),
58363
58746
  /** Total volatile organic compounds in ppb. */
58364
- vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
58747
+ voc: number().min(0).optional().meta(readingMeta("concentration-ppb")),
58365
58748
  /** Particulate matter ≤ 2.5 μm in µg/m³. */
58366
58749
  pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
58367
58750
  /** Particulate matter ≤ 10 μm in µg/m³. */
@@ -58394,12 +58777,12 @@ var airQualitySensorCapability = {
58394
58777
  * History (D850): recorded series.
58395
58778
  */
58396
58779
  history: { fields: {
58397
- co2Ppm: {
58780
+ co2: {
58398
58781
  kind: "gauge",
58399
58782
  unit: "ppm",
58400
58783
  deadband: 5
58401
58784
  },
58402
- vocPpb: {
58785
+ voc: {
58403
58786
  kind: "gauge",
58404
58787
  unit: "ppb",
58405
58788
  deadband: 5
@@ -58430,7 +58813,7 @@ var airQualitySensorCapability = {
58430
58813
  */
58431
58814
  var AmbientLightSensorStatusSchema = object({
58432
58815
  /** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
58433
- lux: number().min(0).nullable().meta(readingMeta("illuminance", {
58816
+ illuminance: number().min(0).nullable().meta(readingMeta("illuminance", {
58434
58817
  precision: 0,
58435
58818
  label: "Illuminance"
58436
58819
  })),
@@ -58459,7 +58842,7 @@ var ambientLightSensorCapability = {
58459
58842
  /**
58460
58843
  * History (D850): recorded series. Wide range, so a RELATIVE deadband (10 %).
58461
58844
  */
58462
- history: { fields: { lux: {
58845
+ history: { fields: { illuminance: {
58463
58846
  kind: "gauge",
58464
58847
  unit: "lx",
58465
58848
  deadbandPct: 10,
@@ -58598,6 +58981,84 @@ var audioMetricsCapability = {
58598
58981
  */
58599
58982
  history: "none"
58600
58983
  };
58984
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
58985
+ actionId: string().min(1),
58986
+ variables: record(string(), ActionVariableValueSchema).optional()
58987
+ }), _void(), {
58988
+ kind: "mutation",
58989
+ auth: "admin"
58990
+ }), method(object({ actionId: string().min(1) }), _void(), {
58991
+ kind: "mutation",
58992
+ auth: "admin"
58993
+ });
58994
+ /**
58995
+ * actions — the ONE surface for runnable actions, for the UI and for
58996
+ * automations. Provided by the core-blocks builtin on the hub.
58997
+ *
58998
+ * An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
58999
+ * steps, kept in the hub's `actions` record kind) or declared by an addon over
59000
+ * `action-source`. `list` asks every `action-source` provider LIVE and overlays
59001
+ * the run status from the hub's `runs` ledger; there is no catalog here to
59002
+ * drift (D3).
59003
+ *
59004
+ * **Permissions follow the camera, as linked devices do.** An action is linked
59005
+ * to cameras by the operator (`setLinks`, D356: nothing links itself). A
59006
+ * non-admin may `get` / `run` an action only through a camera they may see that
59007
+ * links it: they name the camera (`deviceId`, a top-level field so the scope
59008
+ * gate sees it) and the provider refuses an action that camera does not link.
59009
+ * An admin, and an in-process caller (an automation block), may run any action.
59010
+ * Every refusal is typed (`[not-linked] …`) and logged.
59011
+ *
59012
+ * A second `run` of an action that is already running is REFUSED — traced and
59013
+ * logged — never queued.
59014
+ */
59015
+ var ActionIdInput = object({ actionId: string().min(1) });
59016
+ var ActionLinksSchema = object({
59017
+ deviceId: number().int().nonnegative(),
59018
+ actionIds: array(string().min(1)).max(100)
59019
+ });
59020
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
59021
+ actionId: string().min(1),
59022
+ deviceId: number().int().nonnegative().optional()
59023
+ }), object({ action: ActionEntrySchema.nullable() }), {
59024
+ role: "viewer",
59025
+ auth: "protected",
59026
+ kind: "query",
59027
+ caller: "required"
59028
+ }), method(object({
59029
+ actionId: string().min(1),
59030
+ variables: record(string(), ActionVariableValueSchema).optional(),
59031
+ wait: boolean().optional(),
59032
+ origin: ActionRunOriginSchema.optional(),
59033
+ deviceId: number().int().nonnegative().optional()
59034
+ }), ActionRunResultSchema, {
59035
+ role: "viewer",
59036
+ auth: "protected",
59037
+ kind: "mutation",
59038
+ caller: "required"
59039
+ }), method(ActionIdInput, _void(), {
59040
+ kind: "mutation",
59041
+ auth: "admin"
59042
+ }), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
59043
+ kind: "mutation",
59044
+ auth: "admin"
59045
+ }), method(object({
59046
+ actionId: string().min(1),
59047
+ action: ActionInputSchema.partial()
59048
+ }), object({ action: ActionEntrySchema }), {
59049
+ kind: "mutation",
59050
+ auth: "admin"
59051
+ }), method(ActionIdInput, _void(), {
59052
+ kind: "mutation",
59053
+ auth: "admin"
59054
+ }), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
59055
+ role: "viewer",
59056
+ auth: "protected",
59057
+ kind: "query"
59058
+ }), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
59059
+ kind: "mutation",
59060
+ auth: "admin"
59061
+ });
58601
59062
  /**
58602
59063
  * Automation-control cap. Models HA `automation.*` entities on
58603
59064
  * `DeviceType.Automation`. An automation is a trigger+condition+
@@ -58694,7 +59155,7 @@ var BatteryStatusSchema = object({
58694
59155
  * Consumers must SKIP a null rather than coerce it — `battery-band` already
58695
59156
  * declines to band a non-finite reading, which is the correct shape.
58696
59157
  */
58697
- percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
59158
+ level: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
58698
59159
  /**
58699
59160
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
58700
59161
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -58704,7 +59165,7 @@ var BatteryStatusSchema = object({
58704
59165
  * `'unknown'` is the absence of an answer: the provider has not read the
58705
59166
  * power fields yet, or the firmware reported neither. Before it existed,
58706
59167
  * two unreadable fields produced `'none'`, and a camera nobody had reached
58707
- * was drawn "on battery alone" — the same D315 defect `percentage` closed
59168
+ * was drawn "on battery alone" — the same D315 defect `level` closed
58708
59169
  * by going nullable. Consumers SKIP it (no charger state published, no
58709
59170
  * glyph, no HomeKit ChargingState) rather than coerce it either way.
58710
59171
  */
@@ -58728,7 +59189,7 @@ var BatteryStatusSchema = object({
58728
59189
  * that only report charge. A second reading on this cap, not a second
58729
59190
  * `numeric-sensor` on the same device.
58730
59191
  */
58731
- volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
59192
+ voltage: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
58732
59193
  /**
58733
59194
  * Ms epoch of the last time the device PROVED it was reachable — a
58734
59195
  * completed firmware round-trip, an observed wake, or an inbound push
@@ -58762,7 +59223,7 @@ var BatteryStatusSchema = object({
58762
59223
  /**
58763
59224
  * True when the source is a BINARY low-battery indicator (HA
58764
59225
  * `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
58765
- * charge level — `percentage` is then a coarse stand-in (100 = normal,
59226
+ * charge level — `level` is then a coarse stand-in (100 = normal,
58766
59227
  * sub-threshold = low). UI MUST render "Normal"/"Low" instead of a
58767
59228
  * misleading exact percentage. Absent/false → genuine 0–100 % reading.
58768
59229
  */
@@ -58782,15 +59243,15 @@ var BATTERY_DEVICE_TYPES = [
58782
59243
  var batteryCustomize = {
58783
59244
  version: 1,
58784
59245
  targets: [{
58785
- id: "percentage",
59246
+ id: "level",
58786
59247
  cardinality: "scalar",
58787
59248
  vocabulary: {
58788
59249
  cap: "battery",
58789
- stateField: "percentage"
59250
+ stateField: "level"
58790
59251
  },
58791
59252
  deviceTypes: BATTERY_DEVICE_TYPES,
58792
59253
  apply: "add",
58793
- path: "percentage",
59254
+ path: "level",
58794
59255
  sources: [{
58795
59256
  kind: "field",
58796
59257
  valueKinds: ["number", "string"],
@@ -58884,7 +59345,7 @@ onStatusChanged: { data: object({
58884
59345
  schema: BatteryStatusSchema,
58885
59346
  kind: "push",
58886
59347
  empty: {
58887
- percentage: null,
59348
+ level: null,
58888
59349
  charging: "unknown",
58889
59350
  sleeping: false,
58890
59351
  lastUpdated: 0
@@ -58911,11 +59372,11 @@ onStatusChanged: { data: object({
58911
59372
  * History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
58912
59373
  */
58913
59374
  history: { fields: {
58914
- percentage: {
59375
+ level: {
58915
59376
  kind: "gauge",
58916
59377
  unit: "%"
58917
59378
  },
58918
- volts: {
59379
+ voltage: {
58919
59380
  kind: "gauge",
58920
59381
  unit: "V"
58921
59382
  }
@@ -58975,14 +59436,14 @@ var binaryCapability = {
58975
59436
  * controls to this single-method surface.
58976
59437
  *
58977
59438
  * The cap is intentionally minimal: a single `setBrightness({deviceId,
58978
- * percentage})` mutation plus the auto-injected `getStatus`. Drivers
59439
+ * level})` mutation plus the auto-injected `getStatus`. Drivers
58979
59440
  * that expose richer controls (color temperature, scenes, schedules)
58980
59441
  * should surface those via the device's `getSettingsUISchema()`
58981
59442
  * instead of bloating this cap.
58982
59443
  */
58983
59444
  var BrightnessStatusSchema = object({
58984
59445
  /** Current level as 0..100 inclusive. Firmware-reported. */
58985
- percentage: number().min(0).max(100).meta(readingMeta("percentage")),
59446
+ level: number().min(0).max(100).meta(readingMeta("percentage")),
58986
59447
  /** Ms epoch of the last operator-driven change. Useful for UI freshness. */
58987
59448
  lastChangedAt: number()
58988
59449
  });
@@ -58994,7 +59455,7 @@ var brightnessCapability = {
58994
59455
  deviceTypes: [DeviceType.Light],
58995
59456
  methods: { setBrightness: method(object({
58996
59457
  deviceId: number().int().nonnegative(),
58997
- percentage: number().min(0).max(100)
59458
+ level: number().min(0).max(100)
58998
59459
  }), _void(), {
58999
59460
  kind: "mutation",
59000
59461
  auth: "protected"
@@ -59007,7 +59468,7 @@ var brightnessCapability = {
59007
59468
  */
59008
59469
  onBrightnessChanged: { data: object({
59009
59470
  deviceId: number(),
59010
- percentage: number().min(0).max(100),
59471
+ level: number().min(0).max(100),
59011
59472
  lastChangedAt: number()
59012
59473
  }) } },
59013
59474
  status: {
@@ -59030,7 +59491,7 @@ onBrightnessChanged: { data: object({
59030
59491
  /**
59031
59492
  * History (D850): recorded series. Actuator tier: level keeps every change.
59032
59493
  */
59033
- history: { fields: { percentage: {
59494
+ history: { fields: { level: {
59034
59495
  kind: "gauge",
59035
59496
  unit: "%",
59036
59497
  minIntervalMs: 0
@@ -59627,11 +60088,11 @@ var ColorInputSchema = discriminatedUnion("mode", [
59627
60088
  }),
59628
60089
  object({
59629
60090
  mode: literal("mired"),
59630
- mireds: number().int().min(50).max(1e3)
60091
+ colorTemperature: number().int().min(50).max(1e3)
59631
60092
  })
59632
60093
  ]);
59633
60094
  var ColorStatusSchema = object({
59634
- /** Active color mode — which of `rgb` / `hsv` / `mireds` reflects
60095
+ /** Active color mode — which of `rgb` / `hsv` / `colorTemperature` reflects
59635
60096
  * the bulb's current state. */
59636
60097
  mode: _enum([
59637
60098
  "rgb",
@@ -59643,7 +60104,7 @@ var ColorStatusSchema = object({
59643
60104
  /** Populated when `mode === 'hsv'`. */
59644
60105
  hsv: HsvTripletSchema.optional(),
59645
60106
  /** Populated when `mode === 'mired'`. */
59646
- mireds: number().int().optional().meta(readingMeta("colour-temperature")),
60107
+ colorTemperature: number().int().optional().meta(readingMeta("colour-temperature")),
59647
60108
  /** Ms epoch of the last operator-driven change. */
59648
60109
  lastChangedAt: number()
59649
60110
  });
@@ -59675,7 +60136,7 @@ onColorChanged: { data: object({
59675
60136
  ]),
59676
60137
  rgb: RgbTripletSchema.optional(),
59677
60138
  hsv: HsvTripletSchema.optional(),
59678
- mireds: number().int().optional(),
60139
+ colorTemperature: number().int().optional(),
59679
60140
  lastChangedAt: number()
59680
60141
  }) } },
59681
60142
  status: {
@@ -60552,11 +61013,11 @@ var DishwasherStatusSchema = object({
60552
61013
  /** Feature keys of the programs the appliance currently offers — drives the UI selector. */
60553
61014
  availablePrograms: array(string()),
60554
61015
  /** Seconds remaining on the active cycle, or null when not running / not known. */
60555
- remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
61016
+ remaining: number().int().nonnegative().nullable().meta(readingMeta("duration")),
60556
61017
  /** Seconds the delayed start is set to (time until the cycle starts), or null. */
60557
- delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
61018
+ delayedStart: number().int().nonnegative().nullable().meta(readingMeta("duration")),
60558
61019
  /** Cycle completion 0..100, or null when not applicable. */
60559
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61020
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
60560
61021
  /** True when the door is reported open; null when the door state is not known. */
60561
61022
  doorOpen: boolean().nullable(),
60562
61023
  /** True when the door is latched (locked) during a cycle; null when not reported. */
@@ -60775,14 +61236,14 @@ var dishwasherCapability = {
60775
61236
  runtimeState: DishwasherStatusSchema,
60776
61237
  durability: "session",
60777
61238
  history: { fields: {
60778
- progressPercent: {
61239
+ progress: {
60779
61240
  kind: "gauge",
60780
61241
  unit: "%",
60781
61242
  deadband: 2
60782
61243
  },
60783
61244
  state: { kind: "enum" },
60784
61245
  operationState: { kind: "enum" },
60785
- remainingSeconds: {
61246
+ remaining: {
60786
61247
  kind: "gauge",
60787
61248
  unit: "s",
60788
61249
  minIntervalMs: 6e4
@@ -61373,7 +61834,7 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
61373
61834
  var FanControlStatusSchema = object({
61374
61835
  /** Active speed as 0..100 inclusive. Null when the device has no
61375
61836
  * speed surface (single-speed fan). */
61376
- percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61837
+ speed: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61377
61838
  /** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
61378
61839
  * a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
61379
61840
  percentageStep: number().positive().optional().meta(readingMeta("percentage")),
@@ -61400,7 +61861,7 @@ var fanControlCapability = {
61400
61861
  methods: {
61401
61862
  setPercentage: method(object({
61402
61863
  deviceId: number().int().nonnegative(),
61403
- percentage: number().min(0).max(100)
61864
+ speed: number().min(0).max(100)
61404
61865
  }), _void(), {
61405
61866
  kind: "mutation",
61406
61867
  auth: "protected"
@@ -61433,7 +61894,7 @@ var fanControlCapability = {
61433
61894
  },
61434
61895
  /**
61435
61896
  * Runtime-state slice — mirrored by the kernel. UI fan speed
61436
- * sliders read `percentage` for live updates.
61897
+ * sliders read `speed` for live updates.
61437
61898
  */
61438
61899
  runtimeState: FanControlStatusSchema,
61439
61900
  /**
@@ -61447,7 +61908,7 @@ var fanControlCapability = {
61447
61908
  * History (D850): recorded series. Actuator tier: speed keeps every change.
61448
61909
  */
61449
61910
  history: { fields: {
61450
- percentage: {
61911
+ speed: {
61451
61912
  kind: "gauge",
61452
61913
  unit: "%",
61453
61914
  minIntervalMs: 0
@@ -61892,7 +62353,7 @@ var humidifierCapability = {
61892
62353
  */
61893
62354
  var HumiditySensorStatusSchema = object({
61894
62355
  /** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
61895
- percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
62356
+ humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
61896
62357
  precision: 0,
61897
62358
  label: "Humidity"
61898
62359
  })),
@@ -61921,7 +62382,7 @@ var humiditySensorCapability = {
61921
62382
  /**
61922
62383
  * History (D850): recorded series.
61923
62384
  */
61924
- history: { fields: { percent: {
62385
+ history: { fields: { humidity: {
61925
62386
  kind: "gauge",
61926
62387
  unit: "%",
61927
62388
  deadband: .5
@@ -62561,7 +63022,7 @@ var LawnMowerControlStatusSchema = object({
62561
63022
  batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
62562
63023
  /** 0..100 mowing-completion percentage of the current task, or null when no
62563
63024
  * task is active / progress is unavailable. */
62564
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
63025
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
62565
63026
  /** Current device/event code (dynamic — mostly status, sometimes an error),
62566
63027
  * or null when unknown. */
62567
63028
  currentCode: number().nullable().meta(readingMeta("none")),
@@ -63061,7 +63522,7 @@ var lockControlCapability = {
63061
63522
  volatileStateFields: ["lastChangedAt"]
63062
63523
  };
63063
63524
  /**
63064
- * A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
63525
+ * A monotonic total between resets (D944). Energy uses `power-meter.energy`
63065
63526
  * so dashboards keep one series; every other instantaneous reading lands here.
63066
63527
  * `value` is the time integral in the source quantity's accumulated base
63067
63528
  * (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
@@ -63155,10 +63616,10 @@ var MediaPlayerStatusSchema = object({
63155
63616
  currentMedia: MediaInfoSchema.nullable(),
63156
63617
  /** Current playback position in ms. Null when not seekable or
63157
63618
  * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
63158
- positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
63619
+ position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
63159
63620
  /** Total duration of the current media in ms. Null when unknown
63160
63621
  * (live stream) or nothing is playing. */
63161
- durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
63622
+ duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
63162
63623
  /** Shuffle toggle. Null when no shuffle surface.
63163
63624
  * Pair with `DeviceFeature.MediaPlayerShuffle`. */
63164
63625
  shuffle: boolean().nullable(),
@@ -63197,7 +63658,7 @@ var mediaPlayerCapability = {
63197
63658
  }),
63198
63659
  seek: method(object({
63199
63660
  deviceId: number().int().nonnegative(),
63200
- positionMs: number().int().nonnegative()
63661
+ position: number().int().nonnegative()
63201
63662
  }), _void(), {
63202
63663
  kind: "mutation",
63203
63664
  auth: "protected"
@@ -63269,7 +63730,7 @@ var mediaPlayerCapability = {
63269
63730
  /**
63270
63731
  * History (D850): volume (a level an operator or an automation sets; the
63271
63732
  * default 10 s floor folds a slider drag into its end value) and mute.
63272
- * `positionMs` is not recorded: it moves continuously while playing.
63733
+ * `position` is not recorded: it moves continuously while playing.
63273
63734
  */
63274
63735
  history: { fields: {
63275
63736
  volumeLevel: {
@@ -64231,9 +64692,9 @@ var NetworkLinkStatusSchema = object({
64231
64692
  * one whose reading has not landed must not be drawn at 0 %. Consumers
64232
64693
  * SKIP a null rather than coerce it.
64233
64694
  */
64234
- signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64695
+ signal: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64235
64696
  /** Raw received signal strength in dBm, when the firmware reports one. */
64236
- rssiDbm: number().optional().meta(readingMeta("signal-level")),
64697
+ rssi: number().optional().meta(readingMeta("signal-level")),
64237
64698
  /** Network name of a wireless link, when the firmware reports it. */
64238
64699
  ssid: string().optional(),
64239
64700
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
@@ -64242,7 +64703,7 @@ var NetworkLinkStatusSchema = object({
64242
64703
  /** The slice a provider seeds before its first read: nothing is known yet. */
64243
64704
  var NETWORK_LINK_UNKNOWN = {
64244
64705
  type: "unknown",
64245
- signalPercent: null,
64706
+ signal: null,
64246
64707
  lastUpdated: 0
64247
64708
  };
64248
64709
  /**
@@ -64259,9 +64720,9 @@ function signalPercentFromBars(bars, maxBars) {
64259
64720
  * below is 0 %, -50 dBm and above is 100 %, linear between. Non-finite or
64260
64721
  * positive input is not an RSSI: `null`.
64261
64722
  */
64262
- function signalPercentFromRssi(rssiDbm) {
64263
- if (rssiDbm === void 0 || !Number.isFinite(rssiDbm) || rssiDbm > 0) return null;
64264
- return Math.round((Math.min(-50, Math.max(-100, rssiDbm)) + 100) * 2);
64723
+ function signalPercentFromRssi(rssi) {
64724
+ if (rssi === void 0 || !Number.isFinite(rssi) || rssi > 0) return null;
64725
+ return Math.round((Math.min(-50, Math.max(-100, rssi)) + 100) * 2);
64265
64726
  }
64266
64727
  var networkLinkCapability = {
64267
64728
  name: "network-link",
@@ -64312,13 +64773,13 @@ onStatusChanged: { data: object({
64312
64773
  * History (D850): recorded series.
64313
64774
  */
64314
64775
  history: { fields: {
64315
- signalPercent: {
64776
+ signal: {
64316
64777
  kind: "gauge",
64317
64778
  unit: "%",
64318
64779
  deadband: 3,
64319
64780
  minIntervalMs: 6e4
64320
64781
  },
64321
- rssiDbm: {
64782
+ rssi: {
64322
64783
  kind: "gauge",
64323
64784
  unit: "dBm",
64324
64785
  deadband: 2,
@@ -65109,10 +65570,20 @@ var PetFeederDeviceStatusSchema = _enum([
65109
65570
  ]);
65110
65571
  var gramsPortion = number().int().min(4).max(200);
65111
65572
  var PetFeederStatusSchema = object({
65112
- /** Food currently in the bowl (grams). Null when the device has not
65113
- * reported a reading yet. On dual-hopper models this is the combined
65114
- * bowl reading; per-hopper levels live in `food1`/`food2`. */
65573
+ /** Food in the TANK (hopper), as the feeder's own sensor reports it
65574
+ * (`state.food`). A coarse level code, not grams — `0` is empty. The
65575
+ * amount in the bowl is `bowlFood`. On dual-hopper models this is the
65576
+ * combined reading; per-hopper levels live in `food1`/`food2`. Null when
65577
+ * the device has not reported yet. */
65115
65578
  foodLevel: number().nullable().meta(readingMeta("none")),
65579
+ /** Food in the BOWL as the feeder reports it (`state.bowl`), in the
65580
+ * feeder's own units. Null when the model reports none. */
65581
+ bowlFood: number().nullable().meta(readingMeta("none")),
65582
+ /** True while the pet is eating (`state.eating`). */
65583
+ eating: boolean(),
65584
+ /** Whether `markFoodReplenished` does anything on this model. When false
65585
+ * the client must not offer it. */
65586
+ supportsMarkRefilled: boolean(),
65116
65587
  /** Hopper-1 food level (grams) on dual-hopper feeders; null on
65117
65588
  * single-hopper models. */
65118
65589
  food1: number().nullable().meta(readingMeta("none")),
@@ -65120,8 +65591,8 @@ var PetFeederStatusSchema = object({
65120
65591
  * single-hopper models. */
65121
65592
  food2: number().nullable().meta(readingMeta("none")),
65122
65593
  /** Derived low-food flag — mirrors the HA `food_level` binary_sensor
65123
- * (`device_class: problem`, on = low). True when the bowl is empty /
65124
- * below the feeder's low threshold. */
65594
+ * (`device_class: problem`, on = low). True when the tank reports empty,
65595
+ * or, on a dual-hopper model, when EITHER hopper is empty. */
65125
65596
  lowFood: boolean(),
65126
65597
  /** Battery charge 0..100 (%). Null on mains-powered models or when the
65127
65598
  * device has no battery reading. */
@@ -65189,7 +65660,9 @@ var petFeederCapability = {
65189
65660
  kind: "mutation",
65190
65661
  auth: "protected"
65191
65662
  }),
65192
- /** Mark a hopper as refilled (D4H/D4S/D4SH). */
65663
+ /** Tell the PetKit cloud a hopper was refilled so it stops its low-food
65664
+ * reminders (D4H/D4S/D4SH only — see `supportsMarkRefilled`). It does not
65665
+ * change any sensor reading. */
65193
65666
  markFoodReplenished: method(object({ deviceId: number().int().nonnegative() }), _void(), {
65194
65667
  kind: "mutation",
65195
65668
  auth: "protected"
@@ -65262,6 +65735,7 @@ var petFeederCapability = {
65262
65735
  */
65263
65736
  history: { fields: {
65264
65737
  foodLevel: { kind: "gauge" },
65738
+ bowlFood: { kind: "gauge" },
65265
65739
  food1: { kind: "gauge" },
65266
65740
  food2: { kind: "gauge" },
65267
65741
  batteryPower: {
@@ -65671,16 +66145,16 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
65671
66145
  * in real-world devices.
65672
66146
  */
65673
66147
  var PowerMeterStatusSchema = object({
65674
- /** Instantaneous power draw in watts. */
65675
- watts: number().optional().meta(readingMeta("power", { label: "Power" })),
66148
+ /** Instantaneous power draw (watts). */
66149
+ power: number().optional().meta(readingMeta("power", { label: "Power" })),
65676
66150
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
65677
- kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
65678
- /** Voltage in volts. */
65679
- volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
66151
+ energy: number().optional().meta(readingMeta("energy", { label: "Energy" })),
66152
+ /** Voltage (volts). */
66153
+ voltage: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
65680
66154
  /** Current in amperes. */
65681
- amps: number().optional().meta(readingMeta("current", { label: "Current" })),
66155
+ current: number().optional().meta(readingMeta("current", { label: "Current" })),
65682
66156
  /** Apparent power in volt-amperes. */
65683
- va: number().optional().meta(readingMeta("apparent-power")),
66157
+ apparentPower: number().optional().meta(readingMeta("apparent-power")),
65684
66158
  /** Power factor (0..1) if reported. */
65685
66159
  powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
65686
66160
  /** Ms epoch when the slice was last updated. */
@@ -65738,14 +66212,14 @@ function powerTarget(id, unit) {
65738
66212
  advancedExpression: true
65739
66213
  };
65740
66214
  }
65741
- /** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
66215
+ /** "Power and energy" extension: power, energy, voltage and current from other devices (D951). */
65742
66216
  var powerMeterCustomize = {
65743
66217
  version: 1,
65744
66218
  targets: [
65745
- powerTarget("watts", "W"),
65746
- powerTarget("kwhTotal", "kWh"),
65747
- powerTarget("volts", "V"),
65748
- powerTarget("amps", "A")
66219
+ powerTarget("power", "W"),
66220
+ powerTarget("energy", "kWh"),
66221
+ powerTarget("voltage", "V"),
66222
+ powerTarget("current", "A")
65749
66223
  ]
65750
66224
  };
65751
66225
  var powerMeterCapability = {
@@ -65761,41 +66235,41 @@ var powerMeterCapability = {
65761
66235
  },
65762
66236
  runtimeState: PowerMeterStatusSchema,
65763
66237
  /**
65764
- * Runtime-state durability: **restored** — as `numeric-sensor`; `kwhTotal` is an accumulator whose restored value is the baseline.
66238
+ * Runtime-state durability: **restored** — as `numeric-sensor`; `energy` is an accumulator whose restored value is the baseline.
65765
66239
  *
65766
66240
  * See `RuntimeStateDurability`. Enforced by
65767
66241
  * `scripts/check-runtime-state-durability.ts`.
65768
66242
  */
65769
66243
  durability: "restored",
65770
66244
  /**
65771
- * History (D850): recorded series. Gauges are floored at 30 s; `kwhTotal` is the one monotonic meter (counter).
66245
+ * History (D850): recorded series. Gauges are floored at 30 s; `energy` is the one monotonic meter (counter).
65772
66246
  */
65773
66247
  history: { fields: {
65774
- watts: {
66248
+ power: {
65775
66249
  kind: "gauge",
65776
66250
  unit: "W",
65777
66251
  deadband: 1,
65778
66252
  minIntervalMs: 3e4
65779
66253
  },
65780
- kwhTotal: {
66254
+ energy: {
65781
66255
  kind: "counter",
65782
66256
  unit: "kWh",
65783
66257
  deadband: .01,
65784
66258
  minIntervalMs: 6e4
65785
66259
  },
65786
- volts: {
66260
+ voltage: {
65787
66261
  kind: "gauge",
65788
66262
  unit: "V",
65789
66263
  deadband: 1,
65790
66264
  minIntervalMs: 3e4
65791
66265
  },
65792
- amps: {
66266
+ current: {
65793
66267
  kind: "gauge",
65794
66268
  unit: "A",
65795
66269
  deadband: .05,
65796
66270
  minIntervalMs: 3e4
65797
66271
  },
65798
- va: {
66272
+ apparentPower: {
65799
66273
  kind: "gauge",
65800
66274
  unit: "VA",
65801
66275
  deadband: 1,
@@ -65845,9 +66319,6 @@ var PresenceStatusSchema = object({
65845
66319
  location: string().nullable(),
65846
66320
  /** GPS coordinates when available. Null otherwise. */
65847
66321
  gps: GpsLocationSchema.nullable(),
65848
- /** Optional battery level of the tracking device (0..100). Null
65849
- * when not reported. */
65850
- batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
65851
66322
  /** Ms epoch when the slice was last updated. */
65852
66323
  lastChangedAt: number()
65853
66324
  });
@@ -65876,14 +66347,7 @@ var presenceCapability = {
65876
66347
  * `scripts/check-runtime-state-durability.ts`.
65877
66348
  */
65878
66349
  durability: "restored",
65879
- /**
65880
- * History (D850): recorded series.
65881
- */
65882
- history: { fields: { batteryPercent: {
65883
- kind: "gauge",
65884
- unit: "%",
65885
- deadband: 1
65886
- } } },
66350
+ history: "none",
65887
66351
  /** Clock fields: written, but excluded from the compare that decides
65888
66352
  * whether persisting is worth a SQLite commit. */
65889
66353
  volatileStateFields: ["lastChangedAt"]
@@ -65898,7 +66362,7 @@ var presenceCapability = {
65898
66362
  */
65899
66363
  var PressureSensorStatusSchema = object({
65900
66364
  /** Current pressure in hPa. `null` when the sample was refused (D393). */
65901
- hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
66365
+ pressure: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
65902
66366
  /** Ms epoch when the slice was last updated. */
65903
66367
  lastFetchedAt: number()
65904
66368
  });
@@ -65924,7 +66388,7 @@ var pressureSensorCapability = {
65924
66388
  /**
65925
66389
  * History (D850): recorded series.
65926
66390
  */
65927
- history: { fields: { hpa: {
66391
+ history: { fields: { pressure: {
65928
66392
  kind: "gauge",
65929
66393
  unit: "hPa",
65930
66394
  deadband: .1
@@ -70127,7 +70591,7 @@ var tamperCapability = {
70127
70591
  */
70128
70592
  var TemperatureSensorStatusSchema = object({
70129
70593
  /** Current temperature in Celsius. `null` when the sample was refused (D393). */
70130
- celsius: number().nullable().meta(readingMeta("temperature", {
70594
+ temperature: number().nullable().meta(readingMeta("temperature", {
70131
70595
  precision: 1,
70132
70596
  label: "Temperature"
70133
70597
  })),
@@ -70156,7 +70620,7 @@ var temperatureSensorCapability = {
70156
70620
  /**
70157
70621
  * History (D850): recorded series.
70158
70622
  */
70159
- history: { fields: { celsius: {
70623
+ history: { fields: { temperature: {
70160
70624
  kind: "gauge",
70161
70625
  unit: "°C",
70162
70626
  deadband: .1
@@ -70453,7 +70917,7 @@ var VacuumControlStatusSchema = object({
70453
70917
  /** Speed tokens the hardware accepts — drives the UI selector. */
70454
70918
  availableFanSpeeds: array(string()),
70455
70919
  /** 0..100 cleaning-completion percentage of the current task, or null. */
70456
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
70920
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
70457
70921
  /** Current error code (0 / null = no error). */
70458
70922
  errorCode: number().nullable().meta(readingMeta("none")),
70459
70923
  /** Human label for {@link errorCode}, or null when none / undecodable. */
@@ -72255,7 +72719,7 @@ var BaseDevice = class {
72255
72719
  * `device-local-state.ts`. Drivers access via:
72256
72720
  *
72257
72721
  * `this.state.battery.sleeping = true` // patches the battery slice
72258
- * `const pct = this.state.battery.percentage` // reads the battery slice
72722
+ * `const pct = this.state.battery.level` // reads the battery slice
72259
72723
  * `this.state.deviceStatus.online = true` // mirrors `markOnline(true)`
72260
72724
  *
72261
72725
  * Adding a new cap with `runtimeState:` automatically extends this
@@ -72295,7 +72759,7 @@ var BaseDevice = class {
72295
72759
  * shape; drivers don't redeclare it, they just write through.
72296
72760
  *
72297
72761
  * Read: `this.runtimeState.getCapState('battery')` →
72298
- * `{percentage, charging, sleeping, lastUpdated}` for any
72762
+ * `{level, charging, sleeping, lastUpdated}` for any
72299
72763
  * provider that registers `batteryCapability`.
72300
72764
  * Write: `this.runtimeState.setCapState('battery', { … })`.
72301
72765
  *
@@ -73469,6 +73933,104 @@ Object.freeze({
73469
73933
  access: "create",
73470
73934
  role: "admin"
73471
73935
  },
73936
+ "actions.create": {
73937
+ capName: "actions",
73938
+ capScope: "system",
73939
+ addonId: null,
73940
+ access: "create",
73941
+ role: "admin"
73942
+ },
73943
+ "actions.delete": {
73944
+ capName: "actions",
73945
+ capScope: "system",
73946
+ addonId: null,
73947
+ access: "delete",
73948
+ role: "admin"
73949
+ },
73950
+ "actions.get": {
73951
+ capName: "actions",
73952
+ capScope: "system",
73953
+ addonId: null,
73954
+ access: "view",
73955
+ role: "viewer"
73956
+ },
73957
+ "actions.getLinks": {
73958
+ capName: "actions",
73959
+ capScope: "system",
73960
+ addonId: null,
73961
+ access: "view",
73962
+ role: "admin"
73963
+ },
73964
+ "actions.getTraces": {
73965
+ capName: "actions",
73966
+ capScope: "system",
73967
+ addonId: null,
73968
+ access: "view",
73969
+ role: "admin"
73970
+ },
73971
+ "actions.list": {
73972
+ capName: "actions",
73973
+ capScope: "system",
73974
+ addonId: null,
73975
+ access: "view",
73976
+ role: "admin"
73977
+ },
73978
+ "actions.listForCamera": {
73979
+ capName: "actions",
73980
+ capScope: "system",
73981
+ addonId: null,
73982
+ access: "view",
73983
+ role: "viewer"
73984
+ },
73985
+ "actions.run": {
73986
+ capName: "actions",
73987
+ capScope: "system",
73988
+ addonId: null,
73989
+ access: "create",
73990
+ role: "viewer"
73991
+ },
73992
+ "actions.setLinks": {
73993
+ capName: "actions",
73994
+ capScope: "system",
73995
+ addonId: null,
73996
+ access: "create",
73997
+ role: "admin"
73998
+ },
73999
+ "actions.stop": {
74000
+ capName: "actions",
74001
+ capScope: "system",
74002
+ addonId: null,
74003
+ access: "create",
74004
+ role: "admin"
74005
+ },
74006
+ "actions.update": {
74007
+ capName: "actions",
74008
+ capScope: "system",
74009
+ addonId: null,
74010
+ access: "create",
74011
+ role: "admin"
74012
+ },
74013
+ "actionSource.listActions": {
74014
+ capName: "action-source",
74015
+ capScope: "system",
74016
+ addonId: null,
74017
+ access: "view",
74018
+ role: "admin"
74019
+ },
74020
+ "actionSource.runAction": {
74021
+ capName: "action-source",
74022
+ capScope: "system",
74023
+ addonId: null,
74024
+ access: "create",
74025
+ role: "admin"
74026
+ },
74027
+ "actionSource.stopAction": {
74028
+ capName: "action-source",
74029
+ capScope: "system",
74030
+ addonId: null,
74031
+ access: "create",
74032
+ role: "admin"
74033
+ },
73472
74034
  "addonPages.listPages": {
73473
74035
  capName: "addon-pages",
73474
74036
  capScope: "system",
@@ -74750,6 +75312,13 @@ Object.freeze({
74750
75312
  access: "view",
74751
75313
  role: "admin"
74752
75314
  },
75315
+ "coreBlocks.getAutomationRunState": {
75316
+ capName: "core-blocks",
75317
+ capScope: "system",
75318
+ addonId: null,
75319
+ access: "view",
75320
+ role: "admin"
75321
+ },
74753
75322
  "coreBlocks.getBlockSettings": {
74754
75323
  capName: "core-blocks",
74755
75324
  capScope: "system",
@@ -74771,6 +75340,13 @@ Object.freeze({
74771
75340
  access: "view",
74772
75341
  role: "admin"
74773
75342
  },
75343
+ "coreBlocks.getTraces": {
75344
+ capName: "core-blocks",
75345
+ capScope: "system",
75346
+ addonId: null,
75347
+ access: "view",
75348
+ role: "admin"
75349
+ },
74774
75350
  "coreBlocks.getTypeDefs": {
74775
75351
  capName: "core-blocks",
74776
75352
  capScope: "system",
@@ -74806,6 +75382,13 @@ Object.freeze({
74806
75382
  access: "create",
74807
75383
  role: "admin"
74808
75384
  },
75385
+ "coreBlocks.reportAutomationRun": {
75386
+ capName: "core-blocks",
75387
+ capScope: "system",
75388
+ addonId: null,
75389
+ access: "create",
75390
+ role: "admin"
75391
+ },
74809
75392
  "coreBlocks.restart": {
74810
75393
  capName: "core-blocks",
74811
75394
  capScope: "system",
@@ -83379,7 +83962,7 @@ var ACTUATOR_CAP_VOCABULARY = {
83379
83962
  label: t("Full brightness", "Luminosità massima"),
83380
83963
  phrase: t("Set {device} to full brightness", "Porta {device} alla massima luminosità"),
83381
83964
  icon: "sun",
83382
- args: { percentage: 100 }
83965
+ args: { level: 100 }
83383
83966
  },
83384
83967
  {
83385
83968
  id: "brightness.half",
@@ -83387,7 +83970,7 @@ var ACTUATOR_CAP_VOCABULARY = {
83387
83970
  label: t("Half brightness", "Luminosità a metà"),
83388
83971
  phrase: t("Dim {device} to half", "Abbassa {device} a metà luminosità"),
83389
83972
  icon: "sun-dim",
83390
- args: { percentage: 50 }
83973
+ args: { level: 50 }
83391
83974
  },
83392
83975
  {
83393
83976
  id: "brightness.off",
@@ -83395,16 +83978,16 @@ var ACTUATOR_CAP_VOCABULARY = {
83395
83978
  label: t("Brightness off", "Luminosità a zero"),
83396
83979
  phrase: t("Dim {device} to zero", "Abbassa {device} a zero"),
83397
83980
  icon: "lightbulb-off",
83398
- args: { percentage: 0 }
83981
+ args: { level: 0 }
83399
83982
  },
83400
83983
  {
83401
83984
  id: "brightness.set",
83402
83985
  method: "setBrightness",
83403
83986
  label: t("Set brightness", "Imposta la luminosità"),
83404
- phrase: t("Set the brightness of {device} to {percentage}", "Imposta la luminosità di {device} a {percentage}"),
83987
+ phrase: t("Set the brightness of {device} to {level}", "Imposta la luminosità di {device} a {level}"),
83405
83988
  icon: "sun-medium",
83406
83989
  openArgs: [{
83407
- key: "percentage",
83990
+ key: "level",
83408
83991
  label: PERCENT,
83409
83992
  offer: {
83410
83993
  kind: "number",
@@ -83418,13 +84001,13 @@ var ACTUATOR_CAP_VOCABULARY = {
83418
84001
  ],
83419
84002
  state: [{
83420
84003
  kind: "numeric",
83421
- field: "percentage",
84004
+ field: "level",
83422
84005
  quantity: t("the brightness", "la luminosità"),
83423
84006
  label: t("Brightness", "Luminosità"),
83424
84007
  unit: "%",
83425
84008
  icon: "sun"
83426
84009
  }],
83427
- events: { onBrightnessChanged: { notOperatorFacing: "the `percentage` state trigger reads the same change" } }
84010
+ events: { onBrightnessChanged: { notOperatorFacing: "the `level` state trigger reads the same change" } }
83428
84011
  },
83429
84012
  color: {
83430
84013
  scope: "device",
@@ -83438,7 +84021,7 @@ var ACTUATOR_CAP_VOCABULARY = {
83438
84021
  icon: "sun",
83439
84022
  args: { color: {
83440
84023
  mode: "mired",
83441
- mireds: 370
84024
+ colorTemperature: 370
83442
84025
  } }
83443
84026
  },
83444
84027
  {
@@ -83449,7 +84032,7 @@ var ACTUATOR_CAP_VOCABULARY = {
83449
84032
  icon: "snowflake",
83450
84033
  args: { color: {
83451
84034
  mode: "mired",
83452
- mireds: 200
84035
+ colorTemperature: 200
83453
84036
  } }
83454
84037
  },
83455
84038
  {
@@ -84063,7 +84646,7 @@ var ACTUATOR_CAP_VOCABULARY = {
84063
84646
  label: t("Fan off", "Ventilatore spento"),
84064
84647
  phrase: t("Stop {device}", "Ferma {device}"),
84065
84648
  icon: "power-off",
84066
- args: { percentage: 0 }
84649
+ args: { speed: 0 }
84067
84650
  },
84068
84651
  {
84069
84652
  id: "fan.full",
@@ -84071,16 +84654,16 @@ var ACTUATOR_CAP_VOCABULARY = {
84071
84654
  label: t("Fan full", "Ventilatore al massimo"),
84072
84655
  phrase: t("Run {device} at full speed", "Porta {device} alla massima velocità"),
84073
84656
  icon: "fan",
84074
- args: { percentage: 100 }
84657
+ args: { speed: 100 }
84075
84658
  },
84076
84659
  {
84077
84660
  id: "fan.speed",
84078
84661
  method: "setPercentage",
84079
84662
  label: t("Set speed", "Imposta la velocità"),
84080
- phrase: t("Set the speed of {device} to {percentage}", "Imposta la velocità di {device} al {percentage}"),
84663
+ phrase: t("Set the speed of {device} to {speed}", "Imposta la velocità di {device} al {speed}"),
84081
84664
  icon: "fan",
84082
84665
  openArgs: [{
84083
- key: "percentage",
84666
+ key: "speed",
84084
84667
  label: t("Speed", "Velocità"),
84085
84668
  offer: {
84086
84669
  kind: "number",
@@ -84142,7 +84725,7 @@ var ACTUATOR_CAP_VOCABULARY = {
84142
84725
  ],
84143
84726
  state: [{
84144
84727
  kind: "numeric",
84145
- field: "percentage",
84728
+ field: "speed",
84146
84729
  quantity: t("the speed", "la velocità"),
84147
84730
  label: t("Speed", "Velocità"),
84148
84731
  unit: "%",
@@ -84940,7 +85523,7 @@ var APPLIANCE_CAP_VOCABULARY = {
84940
85523
  },
84941
85524
  {
84942
85525
  kind: "numeric",
84943
- field: "progressPercent",
85526
+ field: "progress",
84944
85527
  quantity: t("the cycle progress", "l’avanzamento del lavaggio"),
84945
85528
  label: t("Progress", "Avanzamento"),
84946
85529
  unit: "%",
@@ -85298,10 +85881,10 @@ var APPLIANCE_CAP_VOCABULARY = {
85298
85881
  id: "media.seek",
85299
85882
  method: "seek",
85300
85883
  label: t("Seek", "Vai al punto"),
85301
- phrase: t("Move {device} to {positionMs}", "Porta {device} al punto {positionMs}"),
85884
+ phrase: t("Move {device} to {position}", "Porta {device} al punto {position}"),
85302
85885
  icon: "fast-forward",
85303
85886
  openArgs: [{
85304
- key: "positionMs",
85887
+ key: "position",
85305
85888
  label: t("Position", "Posizione"),
85306
85889
  offer: {
85307
85890
  kind: "number",
@@ -86350,7 +86933,7 @@ var SENSOR_CAP_VOCABULARY = {
86350
86933
  state: [
86351
86934
  {
86352
86935
  kind: "numeric",
86353
- field: "co2Ppm",
86936
+ field: "co2",
86354
86937
  quantity: t("the CO₂", "la CO₂"),
86355
86938
  label: t("CO₂", "CO₂"),
86356
86939
  unit: "ppm",
@@ -86358,7 +86941,7 @@ var SENSOR_CAP_VOCABULARY = {
86358
86941
  },
86359
86942
  {
86360
86943
  kind: "numeric",
86361
- field: "vocPpb",
86944
+ field: "voc",
86362
86945
  quantity: t("the VOC level", "il livello di COV"),
86363
86946
  label: t("VOC", "COV"),
86364
86947
  unit: "ppb",
@@ -86394,7 +86977,7 @@ var SENSOR_CAP_VOCABULARY = {
86394
86977
  noun: t("Light level", "Luminosità ambiente"),
86395
86978
  state: [{
86396
86979
  kind: "numeric",
86397
- field: "lux",
86980
+ field: "illuminance",
86398
86981
  quantity: t("the light level", "la luminosità"),
86399
86982
  label: t("Illuminance", "Illuminamento"),
86400
86983
  unit: "lx",
@@ -86597,7 +87180,7 @@ var SENSOR_CAP_VOCABULARY = {
86597
87180
  noun: t("Humidity", "Umidità"),
86598
87181
  state: [{
86599
87182
  kind: "numeric",
86600
- field: "percent",
87183
+ field: "humidity",
86601
87184
  quantity: t("the humidity", "l’umidità"),
86602
87185
  label: t("Humidity", "Umidità"),
86603
87186
  unit: "%",
@@ -86645,7 +87228,7 @@ var SENSOR_CAP_VOCABULARY = {
86645
87228
  state: [
86646
87229
  {
86647
87230
  kind: "numeric",
86648
- field: "watts",
87231
+ field: "power",
86649
87232
  quantity: t("the power draw", "il consumo"),
86650
87233
  label: t("Power", "Potenza"),
86651
87234
  unit: "W",
@@ -86653,7 +87236,7 @@ var SENSOR_CAP_VOCABULARY = {
86653
87236
  },
86654
87237
  {
86655
87238
  kind: "numeric",
86656
- field: "kwhTotal",
87239
+ field: "energy",
86657
87240
  quantity: t("the energy used", "l’energia consumata"),
86658
87241
  label: t("Energy", "Energia"),
86659
87242
  unit: "kWh",
@@ -86661,7 +87244,7 @@ var SENSOR_CAP_VOCABULARY = {
86661
87244
  },
86662
87245
  {
86663
87246
  kind: "numeric",
86664
- field: "volts",
87247
+ field: "voltage",
86665
87248
  quantity: t("the voltage", "la tensione"),
86666
87249
  label: t("Voltage", "Tensione"),
86667
87250
  unit: "V",
@@ -86669,7 +87252,7 @@ var SENSOR_CAP_VOCABULARY = {
86669
87252
  },
86670
87253
  {
86671
87254
  kind: "numeric",
86672
- field: "amps",
87255
+ field: "current",
86673
87256
  quantity: t("the current", "la corrente"),
86674
87257
  label: t("Current", "Corrente"),
86675
87258
  unit: "A",
@@ -86686,13 +87269,6 @@ var SENSOR_CAP_VOCABULARY = {
86686
87269
  label: t("Where", "Posizione"),
86687
87270
  phrase: t("When {device} is at {value}", "Quando {device} è in {value}"),
86688
87271
  icon: "map-pin"
86689
- }, {
86690
- kind: "numeric",
86691
- field: "batteryPercent",
86692
- quantity: t("the phone battery", "la batteria del telefono"),
86693
- label: t("Battery", "Batteria"),
86694
- unit: "%",
86695
- icon: "battery"
86696
87272
  }]
86697
87273
  },
86698
87274
  "pressure-sensor": {
@@ -86700,7 +87276,7 @@ var SENSOR_CAP_VOCABULARY = {
86700
87276
  noun: t("Pressure", "Pressione"),
86701
87277
  state: [{
86702
87278
  kind: "numeric",
86703
- field: "hpa",
87279
+ field: "pressure",
86704
87280
  quantity: t("the pressure", "la pressione"),
86705
87281
  label: t("Pressure", "Pressione"),
86706
87282
  unit: "hPa",
@@ -86736,7 +87312,7 @@ var SENSOR_CAP_VOCABULARY = {
86736
87312
  noun: t("Temperature", "Temperatura"),
86737
87313
  state: [{
86738
87314
  kind: "numeric",
86739
- field: "celsius",
87315
+ field: "temperature",
86740
87316
  quantity: t("the temperature", "la temperatura"),
86741
87317
  label: t("Temperature", "Temperatura"),
86742
87318
  unit: "°C",
@@ -86807,7 +87383,7 @@ var SENSOR_CAP_VOCABULARY = {
86807
87383
  state: [
86808
87384
  {
86809
87385
  kind: "numeric",
86810
- field: "percentage",
87386
+ field: "level",
86811
87387
  quantity: t("the battery level", "il livello della batteria"),
86812
87388
  label: t("Battery", "Batteria"),
86813
87389
  unit: "%",
@@ -86849,7 +87425,7 @@ var SENSOR_CAP_VOCABULARY = {
86849
87425
  icon: "battery-charging"
86850
87426
  }
86851
87427
  ],
86852
- events: { onStatusChanged: { notOperatorFacing: "the percentage / sleeping / charging state triggers each read one field of this change" } },
87428
+ events: { onStatusChanged: { notOperatorFacing: "the level / sleeping / charging state triggers each read one field of this change" } },
86853
87429
  extraEvents: [{
86854
87430
  category: EventCategory.DeviceAwake,
86855
87431
  label: t("Woke up", "Risvegliato"),
@@ -86867,7 +87443,7 @@ var SENSOR_CAP_VOCABULARY = {
86867
87443
  noun: t("Network link", "Collegamento di rete"),
86868
87444
  state: [{
86869
87445
  kind: "numeric",
86870
- field: "signalPercent",
87446
+ field: "signal",
86871
87447
  quantity: t("the signal strength", "l’intensità del segnale"),
86872
87448
  label: t("Signal", "Segnale"),
86873
87449
  unit: "%",
@@ -86960,6 +87536,8 @@ var ML = "model and training machinery — no device action";
86960
87536
  var INTERNAL = "internal plumbing between addons — never operator-facing";
86961
87537
  /** Every system-scoped cap, with why it is not a device's vocabulary. */
86962
87538
  var SYSTEM_CAP_VOCABULARY = {
87539
+ "action-source": system(INTERNAL),
87540
+ actions: system("declared actions — run from the Actions page and from the cameras that link them"),
86963
87541
  "addon-pages": system(UI_PLUMBING),
86964
87542
  "addon-pages-source": system(UI_PLUMBING),
86965
87543
  "addon-routes": system(UI_PLUMBING),
@@ -87308,6 +87886,31 @@ Object.freeze({
87308
87886
  form: "single",
87309
87887
  optional: false
87310
87888
  }],
87889
+ "actions.get": [{
87890
+ name: "deviceId",
87891
+ form: "single",
87892
+ optional: true
87893
+ }],
87894
+ "actions.getLinks": [{
87895
+ name: "deviceId",
87896
+ form: "single",
87897
+ optional: false
87898
+ }],
87899
+ "actions.listForCamera": [{
87900
+ name: "deviceId",
87901
+ form: "single",
87902
+ optional: false
87903
+ }],
87904
+ "actions.run": [{
87905
+ name: "deviceId",
87906
+ form: "single",
87907
+ optional: true
87908
+ }],
87909
+ "actions.setLinks": [{
87910
+ name: "deviceId",
87911
+ form: "single",
87912
+ optional: false
87913
+ }],
87311
87914
  "addonSettings.getDeviceSettings": [{
87312
87915
  name: "deviceId",
87313
87916
  form: "single",
@@ -91440,6 +92043,7 @@ DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
91440
92043
  DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
91441
92044
  DEFAULT_NATIVE_LEASE_SETTINGS.sceneBudgetMb;
91442
92045
  DEFAULT_NATIVE_LEASE_SETTINGS.admission;
92046
+ String.raw`(?<=^|["'(\s>,\[{])`;
91443
92047
  var MB = 1024 * 1024;
91444
92048
  1024 * MB, 3072 * MB;
91445
92049
  //#endregion
@@ -200809,7 +201413,7 @@ var FloodlightAccessory = class extends BaseDevice {
200809
201413
  lastChangedAt: ts
200810
201414
  });
200811
201415
  if (brightness !== void 0) this.setCapSlice(brightnessCapability, {
200812
- percentage: brightness,
201416
+ level: brightness,
200813
201417
  lastChangedAt: ts
200814
201418
  });
200815
201419
  this.hasFetchedFromFirmware = true;
@@ -200928,7 +201532,7 @@ var FloodlightAccessory = class extends BaseDevice {
200928
201532
  }
200929
201533
  brightnessView() {
200930
201534
  return this.getCapSlice(brightnessCapability) ?? {
200931
- percentage: 100,
201535
+ level: 100,
200932
201536
  lastChangedAt: 0
200933
201537
  };
200934
201538
  }
@@ -200953,19 +201557,19 @@ var FloodlightAccessory = class extends BaseDevice {
200953
201557
  registerBrightnessCap() {
200954
201558
  this.ctx.registerNativeCap(brightnessCapability, {
200955
201559
  getStatus: async () => this.brightnessView(),
200956
- setBrightness: async ({ deviceId, percentage }) => {
201560
+ setBrightness: async ({ deviceId, level: percentage }) => {
200957
201561
  if (deviceId !== this.id) return;
200958
201562
  const value = Math.max(0, Math.min(100, percentage));
200959
201563
  if (this.switchView().on) await (await this.api).setWhiteLedState(this.channel, void 0, value);
200960
201564
  this.setCapSlice(brightnessCapability, {
200961
- percentage: value,
201565
+ level: value,
200962
201566
  lastChangedAt: Date.now()
200963
201567
  });
200964
201568
  this.lastSetAtMs = Date.now();
200965
201569
  }
200966
201570
  });
200967
201571
  this.setCapSlice(brightnessCapability, {
200968
- percentage: 100,
201572
+ level: 100,
200969
201573
  lastChangedAt: 0
200970
201574
  });
200971
201575
  }
@@ -201641,13 +202245,13 @@ function mapNetworkReadout(readout, now) {
201641
202245
  const type = linkTypeOf(readout);
201642
202246
  const raw = readout.wifiSignal;
201643
202247
  const wireless = type === "wifi" || type === "cellular";
201644
- const signalPercent = wireless ? signalPercentOf(raw) : null;
202248
+ const signal = wireless ? signalPercentOf(raw) : null;
201645
202249
  const rssiDbm = wireless && raw !== void 0 && Number.isFinite(raw) && raw < 0 ? raw : void 0;
201646
202250
  const ssid = wireless && readout.ssid !== void 0 && readout.ssid !== "" ? readout.ssid : void 0;
201647
202251
  return {
201648
202252
  type,
201649
- signalPercent,
201650
- ...rssiDbm !== void 0 ? { rssiDbm } : {},
202253
+ signal,
202254
+ ...rssiDbm !== void 0 ? { rssi: rssiDbm } : {},
201651
202255
  ...ssid !== void 0 ? { ssid } : {},
201652
202256
  lastUpdated: now
201653
202257
  };
@@ -204890,7 +205494,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
204890
205494
  */
204891
205495
  mapBatteryInfo(info) {
204892
205496
  return {
204893
- percentage: typeof info.batteryPercent === "number" ? Math.max(0, Math.min(100, Math.round(info.batteryPercent))) : this.state.battery.percentage ?? null,
205497
+ level: typeof info.batteryPercent === "number" ? Math.max(0, Math.min(100, Math.round(info.batteryPercent))) : this.state.battery.level ?? null,
204894
205498
  charging: reportsPowerSource(info) ? deriveChargingSource(info.adapterStatus, info.chargeStatus) : this.state.battery.charging ?? "unknown",
204895
205499
  sleeping: info.sleeping === true || this.sleeping,
204896
205500
  lastUpdated: Date.now()
@@ -205026,7 +205630,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
205026
205630
  }
205027
205631
  });
205028
205632
  if (this.getCapSlice(batteryCapability) === null) this.setCapSlice(batteryCapability, {
205029
- percentage: null,
205633
+ level: null,
205030
205634
  charging: "none",
205031
205635
  sleeping: false,
205032
205636
  lastUpdated: Date.now()
@@ -205254,7 +205858,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
205254
205858
  });
205255
205859
  this.setCapSlice(batteryCapability, {
205256
205860
  ...this.state.battery,
205257
- percentage: mapped.percentage,
205861
+ level: mapped.level,
205258
205862
  charging: mapped.charging,
205259
205863
  lastUpdated: Date.now()
205260
205864
  });