@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.js CHANGED
@@ -36,7 +36,7 @@ let node_os = require("node:os");
36
36
  node_os = require_chunk.__toESM(node_os, 1);
37
37
  let node_fs = require("node:fs");
38
38
  node_fs = require_chunk.__toESM(node_fs, 1);
39
- //#region ../types/dist/event-category-CT-hz5Rb.mjs
39
+ //#region ../types/dist/event-category-DmZDPDf_.mjs
40
40
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
41
41
  EventCategory["SystemBoot"] = "system.boot";
42
42
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -663,7 +663,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
663
663
  * (a track was promoted to a stationary-registry entry) or departs (the
664
664
  * object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
665
665
  * the dedicated "Stationary" section — never the live event feed. Payload:
666
- * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp }`.
666
+ * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp, observedAt, zones }`.
667
667
  */
668
668
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
669
669
  /**
@@ -801,6 +801,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
801
801
  */
802
802
  EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
803
803
  /**
804
+ * An action run started or ended. Emitted by the `actions` surface.
805
+ * Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
806
+ */
807
+ EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
808
+ /**
804
809
  * Progress update from a running model conversion job.
805
810
  * Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
806
811
  * Emitted by `addon-model-studio` on the converting node.
@@ -5479,7 +5484,7 @@ var ZodIssueCode = {
5479
5484
  var ZodFirstPartyTypeKind;
5480
5485
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5481
5486
  //#endregion
5482
- //#region ../types/dist/sleep--jXS9hWo.mjs
5487
+ //#region ../types/dist/sleep-Crlmu_tO.mjs
5483
5488
  /**
5484
5489
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5485
5490
  * window to float samples (D455).
@@ -8637,6 +8642,8 @@ Object.freeze({ "doorbell": "lastPressedAt" });
8637
8642
  /** Every capability name, so addon code can check a name without the schema graph. */
8638
8643
  var CAP_NAMES = Object.freeze([
8639
8644
  "accessories",
8645
+ "action-source",
8646
+ "actions",
8640
8647
  "addon-pages",
8641
8648
  "addon-pages-source",
8642
8649
  "addon-routes",
@@ -8825,11 +8832,11 @@ var CAP_NAMES = Object.freeze([
8825
8832
  Object.freeze({
8826
8833
  "air-quality-sensor": [
8827
8834
  {
8828
- "path": "co2Ppm",
8835
+ "path": "co2",
8829
8836
  "valueType": "number"
8830
8837
  },
8831
8838
  {
8832
- "path": "vocPpb",
8839
+ "path": "voc",
8833
8840
  "valueType": "number"
8834
8841
  },
8835
8842
  {
@@ -8879,7 +8886,7 @@ Object.freeze({
8879
8886
  }
8880
8887
  ],
8881
8888
  "ambient-light-sensor": [{
8882
- "path": "lux",
8889
+ "path": "illuminance",
8883
8890
  "valueType": "number"
8884
8891
  }],
8885
8892
  "audio-metrics": [
@@ -8940,7 +8947,7 @@ Object.freeze({
8940
8947
  ],
8941
8948
  "battery": [
8942
8949
  {
8943
- "path": "percentage",
8950
+ "path": "level",
8944
8951
  "valueType": "number"
8945
8952
  },
8946
8953
  {
@@ -8962,7 +8969,7 @@ Object.freeze({
8962
8969
  "valueType": "number"
8963
8970
  },
8964
8971
  {
8965
- "path": "volts",
8972
+ "path": "voltage",
8966
8973
  "valueType": "number"
8967
8974
  },
8968
8975
  {
@@ -8983,7 +8990,7 @@ Object.freeze({
8983
8990
  "valueType": "boolean"
8984
8991
  }],
8985
8992
  "brightness": [{
8986
- "path": "percentage",
8993
+ "path": "level",
8987
8994
  "valueType": "number"
8988
8995
  }],
8989
8996
  "broker": [{
@@ -9184,7 +9191,7 @@ Object.freeze({
9184
9191
  "valueType": "number"
9185
9192
  },
9186
9193
  {
9187
- "path": "mireds",
9194
+ "path": "colorTemperature",
9188
9195
  "valueType": "number"
9189
9196
  }
9190
9197
  ],
@@ -9363,15 +9370,15 @@ Object.freeze({
9363
9370
  "valueType": "string"
9364
9371
  },
9365
9372
  {
9366
- "path": "remainingSeconds",
9373
+ "path": "remaining",
9367
9374
  "valueType": "number"
9368
9375
  },
9369
9376
  {
9370
- "path": "delayedStartSeconds",
9377
+ "path": "delayedStart",
9371
9378
  "valueType": "number"
9372
9379
  },
9373
9380
  {
9374
- "path": "progressPercent",
9381
+ "path": "progress",
9375
9382
  "valueType": "number"
9376
9383
  },
9377
9384
  {
@@ -9485,7 +9492,7 @@ Object.freeze({
9485
9492
  ],
9486
9493
  "fan-control": [
9487
9494
  {
9488
- "path": "percentage",
9495
+ "path": "speed",
9489
9496
  "valueType": "number"
9490
9497
  },
9491
9498
  {
@@ -9585,7 +9592,7 @@ Object.freeze({
9585
9592
  }
9586
9593
  ],
9587
9594
  "humidity-sensor": [{
9588
- "path": "percent",
9595
+ "path": "humidity",
9589
9596
  "valueType": "number"
9590
9597
  }],
9591
9598
  "image": [{
@@ -9695,7 +9702,7 @@ Object.freeze({
9695
9702
  "valueType": "number"
9696
9703
  },
9697
9704
  {
9698
- "path": "progressPercent",
9705
+ "path": "progress",
9699
9706
  "valueType": "number"
9700
9707
  },
9701
9708
  {
@@ -9774,11 +9781,11 @@ Object.freeze({
9774
9781
  "valueType": "string"
9775
9782
  },
9776
9783
  {
9777
- "path": "positionMs",
9784
+ "path": "position",
9778
9785
  "valueType": "number"
9779
9786
  },
9780
9787
  {
9781
- "path": "durationMs",
9788
+ "path": "duration",
9782
9789
  "valueType": "number"
9783
9790
  },
9784
9791
  {
@@ -9880,11 +9887,11 @@ Object.freeze({
9880
9887
  ]
9881
9888
  },
9882
9889
  {
9883
- "path": "signalPercent",
9890
+ "path": "signal",
9884
9891
  "valueType": "number"
9885
9892
  },
9886
9893
  {
9887
- "path": "rssiDbm",
9894
+ "path": "rssi",
9888
9895
  "valueType": "number"
9889
9896
  },
9890
9897
  {
@@ -9939,6 +9946,18 @@ Object.freeze({
9939
9946
  "path": "foodLevel",
9940
9947
  "valueType": "number"
9941
9948
  },
9949
+ {
9950
+ "path": "bowlFood",
9951
+ "valueType": "number"
9952
+ },
9953
+ {
9954
+ "path": "eating",
9955
+ "valueType": "boolean"
9956
+ },
9957
+ {
9958
+ "path": "supportsMarkRefilled",
9959
+ "valueType": "boolean"
9960
+ },
9942
9961
  {
9943
9962
  "path": "food1",
9944
9963
  "valueType": "number"
@@ -10003,23 +10022,23 @@ Object.freeze({
10003
10022
  ],
10004
10023
  "power-meter": [
10005
10024
  {
10006
- "path": "watts",
10025
+ "path": "power",
10007
10026
  "valueType": "number"
10008
10027
  },
10009
10028
  {
10010
- "path": "kwhTotal",
10029
+ "path": "energy",
10011
10030
  "valueType": "number"
10012
10031
  },
10013
10032
  {
10014
- "path": "volts",
10033
+ "path": "voltage",
10015
10034
  "valueType": "number"
10016
10035
  },
10017
10036
  {
10018
- "path": "amps",
10037
+ "path": "current",
10019
10038
  "valueType": "number"
10020
10039
  },
10021
10040
  {
10022
- "path": "va",
10041
+ "path": "apparentPower",
10023
10042
  "valueType": "number"
10024
10043
  },
10025
10044
  {
@@ -10047,14 +10066,10 @@ Object.freeze({
10047
10066
  {
10048
10067
  "path": "gps.accuracyMeters",
10049
10068
  "valueType": "number"
10050
- },
10051
- {
10052
- "path": "batteryPercent",
10053
- "valueType": "number"
10054
10069
  }
10055
10070
  ],
10056
10071
  "pressure-sensor": [{
10057
- "path": "hpa",
10072
+ "path": "pressure",
10058
10073
  "valueType": "number"
10059
10074
  }],
10060
10075
  "privacy-mask": [{
@@ -10368,7 +10383,7 @@ Object.freeze({
10368
10383
  "valueType": "boolean"
10369
10384
  }],
10370
10385
  "temperature-sensor": [{
10371
- "path": "celsius",
10386
+ "path": "temperature",
10372
10387
  "valueType": "number"
10373
10388
  }],
10374
10389
  "update": [
@@ -10416,7 +10431,7 @@ Object.freeze({
10416
10431
  "valueType": "string"
10417
10432
  },
10418
10433
  {
10419
- "path": "progressPercent",
10434
+ "path": "progress",
10420
10435
  "valueType": "number"
10421
10436
  },
10422
10437
  {
@@ -10929,7 +10944,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
10929
10944
  return DeviceRole;
10930
10945
  }({});
10931
10946
  //#endregion
10932
- //#region ../types/dist/composition-Bb8iwHEJ.mjs
10947
+ //#region ../types/dist/composition-CZImLpOI.mjs
10933
10948
  /**
10934
10949
  * The ffmpeg build every CamStack node downloads, per platform and arch.
10935
10950
  *
@@ -16019,6 +16034,14 @@ var AutomationConditionLeafSchema = object({
16019
16034
  array(union([string(), number()]))
16020
16035
  ])
16021
16036
  });
16037
+ var AutomationConditionStationaryPresentSchema = object({
16038
+ kind: literal("stationary-present"),
16039
+ deviceId: number().int().nonnegative(),
16040
+ /** Class names; a macro class matches every raw class that maps to it. */
16041
+ classes: array(string().min(1)).min(1).optional(),
16042
+ /** The parked object must be in at least one of these zones. */
16043
+ zones: array(string().min(1)).min(1).optional()
16044
+ });
16022
16045
  /**
16023
16046
  * The expression leaf, declared as a plain object rather than an intersection
16024
16047
  * with {@link ExpressionSourceSchema}: a discriminated union has to be able to
@@ -16052,7 +16075,8 @@ var AutomationConditionSchema = lazy(() => discriminatedUnion("kind", [
16052
16075
  child: AutomationConditionSchema
16053
16076
  }),
16054
16077
  AutomationConditionLeafSchema,
16055
- AutomationConditionExpressionSchema
16078
+ AutomationConditionExpressionSchema,
16079
+ AutomationConditionStationaryPresentSchema
16056
16080
  ]));
16057
16081
  /**
16058
16082
  * What starts a run.
@@ -16093,7 +16117,34 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
16093
16117
  kind: literal("schedule"),
16094
16118
  cron: string().min(1).max(120)
16095
16119
  }),
16096
- object({ kind: literal("manual") })
16120
+ object({ kind: literal("manual") }),
16121
+ object({
16122
+ kind: literal("detection"),
16123
+ /** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
16124
+ * matches every raw class that maps to it; any other name matches
16125
+ * exactly. */
16126
+ classes: array(string().min(1)).min(1),
16127
+ deviceIds: array(number().int().nonnegative()).min(1),
16128
+ /** The track must have visited at least one of these zones. */
16129
+ zones: array(string().min(1)).min(1).optional(),
16130
+ /** Best-so-far confidence the track must reach. */
16131
+ minScore: number().min(0).max(1).optional()
16132
+ }),
16133
+ object({
16134
+ kind: literal("stationary"),
16135
+ deviceIds: array(number().int().nonnegative()).min(1),
16136
+ /** Class names; a macro class matches like the detection trigger. */
16137
+ classes: array(string().min(1)).min(1).optional(),
16138
+ /** The parked object must be in at least one of these zones. */
16139
+ zones: array(string().min(1)).min(1).optional(),
16140
+ /** `appeared`: it became parked. `departed`: the registry retired it.
16141
+ * The vocabulary of `PipelineAnalyticsStationaryChanged`. */
16142
+ phase: _enum(["appeared", "departed"])
16143
+ }),
16144
+ object({
16145
+ kind: literal("interval"),
16146
+ minutes: number().int().min(1).max(1440)
16147
+ })
16097
16148
  ]);
16098
16149
  /**
16099
16150
  * One action step.
@@ -16113,28 +16164,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
16113
16164
  * is called. The runner still receives a number and is untouched; the
16114
16165
  * resolution is the recipe's job, not the runner's.
16115
16166
  */
16167
+ var AutomationWaitStepSchema = object({
16168
+ kind: literal("wait"),
16169
+ seconds: number().min(0).max(300)
16170
+ });
16171
+ var AutomationCapStepSchema = object({
16172
+ kind: literal("cap"),
16173
+ /**
16174
+ * One device, several same-family devices (locks / climate family / …),
16175
+ * or `{ $var }` for the device that triggered the run. An array is
16176
+ * fan-out at codegen — each id gets the same cap.method call.
16177
+ */
16178
+ deviceId: union([
16179
+ number().int(),
16180
+ array(number().int()).min(1),
16181
+ object({ $var: string().min(1) })
16182
+ ]),
16183
+ cap: string().min(1),
16184
+ method: string().min(1),
16185
+ /** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
16186
+ * SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
16187
+ * the expression leaf. */
16188
+ args: record(string(), unknown()).optional()
16189
+ });
16190
+ /**
16191
+ * The steps an internal Action may contain: cap and wait, and nothing that can
16192
+ * call back into an Action — so an Action can never reach itself (no cycles).
16193
+ */
16194
+ var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
16116
16195
  var AutomationActionSchema = discriminatedUnion("kind", [
16196
+ AutomationWaitStepSchema,
16197
+ AutomationCapStepSchema,
16117
16198
  object({
16118
- kind: literal("wait"),
16119
- seconds: number().min(0).max(300)
16120
- }),
16121
- object({
16122
- kind: literal("cap"),
16123
- /**
16124
- * One device, several same-family devices (locks / climate family / …),
16125
- * or `{ $var }` for the device that triggered the run. An array is
16126
- * fan-out at codegen — each id gets the same cap.method call.
16127
- */
16128
- deviceId: union([
16129
- number().int(),
16130
- array(number().int()).min(1),
16131
- object({ $var: string().min(1) })
16132
- ]),
16133
- cap: string().min(1),
16134
- method: string().min(1),
16135
- /** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
16136
- * evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
16137
- args: record(string(), unknown()).optional()
16199
+ kind: literal("action"),
16200
+ /** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
16201
+ actionId: string().min(1),
16202
+ /** Values for the action's declared variables; the others take their default. */
16203
+ variables: record(string(), union([
16204
+ string(),
16205
+ number(),
16206
+ boolean()
16207
+ ])).optional()
16138
16208
  }),
16139
16209
  object({
16140
16210
  kind: literal("code"),
@@ -16143,10 +16213,357 @@ var AutomationActionSchema = discriminatedUnion("kind", [
16143
16213
  code: string().min(1).max(2e4)
16144
16214
  })
16145
16215
  ]);
16216
+ /**
16217
+ * How a trigger that arrives while the automation is busy (or cooling down) is
16218
+ * handled. One of the automation's execution modes, never a property of its
16219
+ * actions. Absent means `single`.
16220
+ *
16221
+ * - `single` — drop the trigger while a run is in progress (traced + logged).
16222
+ * - `restart` — abort the run in progress (at its next step boundary), start fresh.
16223
+ * - `queued` — queue up to `max` triggers, drop the rest (traced).
16224
+ * - `parallel` — up to `max` runs at once, drop the rest (traced).
16225
+ * - `cooldown` — `single`, and no new run until `minutes` after the last run
16226
+ * STARTED; persisted across a restart. A manual trigger bypasses only this
16227
+ * wait, never the single/queued limits.
16228
+ */
16229
+ var AutomationRunModeSchema = discriminatedUnion("mode", [
16230
+ object({ mode: literal("single") }),
16231
+ object({ mode: literal("restart") }),
16232
+ object({
16233
+ mode: literal("queued"),
16234
+ max: number().int().min(1).max(10)
16235
+ }),
16236
+ object({
16237
+ mode: literal("parallel"),
16238
+ max: number().int().min(1).max(10)
16239
+ }),
16240
+ object({
16241
+ mode: literal("cooldown"),
16242
+ minutes: number().int().min(1).max(1440)
16243
+ })
16244
+ ]);
16146
16245
  var AutomationRecipeSchema = object({
16147
16246
  triggers: array(AutomationTriggerSchema),
16148
16247
  conditions: AutomationConditionSchema.optional(),
16149
- actions: array(AutomationActionSchema)
16248
+ actions: array(AutomationActionSchema),
16249
+ runMode: AutomationRunModeSchema.optional(),
16250
+ /** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
16251
+ keepTraces: number().int().min(1).max(100).optional()
16252
+ });
16253
+ new Set([
16254
+ {
16255
+ id: "person",
16256
+ name: "Person"
16257
+ },
16258
+ {
16259
+ id: "vehicle",
16260
+ name: "Vehicle"
16261
+ },
16262
+ {
16263
+ id: "animal",
16264
+ name: "Animal"
16265
+ },
16266
+ {
16267
+ id: "package",
16268
+ name: "Package"
16269
+ }
16270
+ ].map((l) => l.id));
16271
+ var COCO_TO_MACRO = {
16272
+ mapping: {
16273
+ person: "person",
16274
+ bicycle: "vehicle",
16275
+ car: "vehicle",
16276
+ motorcycle: "vehicle",
16277
+ airplane: "vehicle",
16278
+ bus: "vehicle",
16279
+ train: "vehicle",
16280
+ truck: "vehicle",
16281
+ boat: "vehicle",
16282
+ bird: "animal",
16283
+ cat: "animal",
16284
+ dog: "animal",
16285
+ horse: "animal",
16286
+ sheep: "animal",
16287
+ cow: "animal",
16288
+ elephant: "animal",
16289
+ bear: "animal",
16290
+ zebra: "animal",
16291
+ giraffe: "animal",
16292
+ suitcase: "package",
16293
+ backpack: "package",
16294
+ handbag: "package"
16295
+ },
16296
+ preserveOriginal: false
16297
+ };
16298
+ new Set(Object.values(COCO_TO_MACRO.mapping));
16299
+ /**
16300
+ * Run traces — what an automation (or, later, an Action run) DID, node by node,
16301
+ * so the editor can paint every block green or red with its reason.
16302
+ *
16303
+ * A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
16304
+ * every condition node (containers and leaves, including the ones a
16305
+ * short-circuit never reached), the run-mode verdict and every action step —
16306
+ * each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
16307
+ * for an Action run). Skipped
16308
+ * evaluations are traced too, and identical consecutive skips collapse into a
16309
+ * repeat count so a trigger that fails every 5 minutes cannot flush real runs.
16310
+ *
16311
+ * {@link AutomationStepTraceSchema} is deliberately free of automation
16312
+ * vocabulary so an Action run records the same step shape.
16313
+ */
16314
+ /** A value a trace may show: JSON primitives and short lists, nothing deeper. */
16315
+ var TraceValueSchema = union([
16316
+ string(),
16317
+ number(),
16318
+ boolean(),
16319
+ _null(),
16320
+ array(union([string(), number()]))
16321
+ ]);
16322
+ var AutomationRunOutcomeSchema = _enum([
16323
+ "ran",
16324
+ "skipped-trigger",
16325
+ "skipped-conditions",
16326
+ "skipped-cooldown",
16327
+ "skipped-overlap",
16328
+ "failed",
16329
+ "aborted"
16330
+ ]);
16331
+ /** `not-evaluated` = a short-circuit never reached the node. */
16332
+ var TraceNodeOutcomeSchema = _enum([
16333
+ "pass",
16334
+ "fail",
16335
+ "not-evaluated"
16336
+ ]);
16337
+ var AutomationTriggerTraceSchema = object({
16338
+ kind: string().min(1),
16339
+ outcome: _enum(["pass", "fail"]),
16340
+ /** Why an event was rejected ("class person not in [dog]") or what fired. */
16341
+ reason: string(),
16342
+ /** deviceId, className, trackId, score … — only what the trigger exposes. */
16343
+ vars: record(string(), TraceValueSchema)
16344
+ });
16345
+ var AutomationConditionTraceNodeSchema = object({
16346
+ /** `conditions` for the root, `conditions.<i>` for its i-th child, … */
16347
+ path: string().min(1),
16348
+ kind: _enum([
16349
+ "all",
16350
+ "any",
16351
+ "not",
16352
+ "condition",
16353
+ "expression",
16354
+ "stationary-present"
16355
+ ]),
16356
+ outcome: TraceNodeOutcomeSchema,
16357
+ reason: string(),
16358
+ deviceId: number().int().optional(),
16359
+ cap: string().optional(),
16360
+ fieldPath: string().optional(),
16361
+ operator: string().optional(),
16362
+ expected: TraceValueSchema.optional(),
16363
+ /** What the mirror held; `null` when it held nothing (unknown). */
16364
+ observed: TraceValueSchema.optional()
16365
+ });
16366
+ var AutomationRunVerdictSchema = object({
16367
+ mode: AutomationRunModeSchema,
16368
+ decision: _enum([
16369
+ "run",
16370
+ "queued",
16371
+ "restart",
16372
+ "drop",
16373
+ "cooldown",
16374
+ "bypass"
16375
+ ]),
16376
+ reason: string()
16377
+ });
16378
+ /** One executed (or not-run) step — shared by automations and Action runs. */
16379
+ var AutomationStepTraceSchema = object({
16380
+ /** `actions.<i>` */
16381
+ path: string().min(1),
16382
+ kind: string().min(1),
16383
+ cap: string().optional(),
16384
+ method: string().optional(),
16385
+ deviceId: number().int().optional(),
16386
+ startedAt: number().optional(),
16387
+ endedAt: number().optional(),
16388
+ outcome: _enum([
16389
+ "ok",
16390
+ "error",
16391
+ "not-run"
16392
+ ]),
16393
+ message: string().optional()
16394
+ });
16395
+ var AutomationRunTraceSchema = object({
16396
+ runId: string().min(1),
16397
+ startedAt: number(),
16398
+ endedAt: number(),
16399
+ trigger: AutomationTriggerTraceSchema,
16400
+ conditions: array(AutomationConditionTraceNodeSchema),
16401
+ verdict: AutomationRunVerdictSchema.optional(),
16402
+ steps: array(AutomationStepTraceSchema),
16403
+ outcome: AutomationRunOutcomeSchema,
16404
+ /** How many identical consecutive skips this trace stands for (>= 1). */
16405
+ repeat: number().int().min(1),
16406
+ /** When the latest of those repeats happened. */
16407
+ lastAt: number()
16408
+ });
16409
+ /**
16410
+ * What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
16411
+ * `action:<actionId>`): the cooldown stamp and the trace ring.
16412
+ */
16413
+ var AutomationStateDocSchema = object({
16414
+ version: literal(1),
16415
+ lastRunStartedAt: number().nullable(),
16416
+ traces: array(AutomationRunTraceSchema)
16417
+ });
16418
+ /**
16419
+ * Actions — named, runnable things an operator (or an automation) can start,
16420
+ * declared as LIST ENTRIES, never as devices.
16421
+ *
16422
+ * An entry is either **internal** (a short list of cap/wait steps kept in the
16423
+ * hub's `actions` record kind) or declared by an addon through the
16424
+ * `action-source` collection (a Home Assistant script, a scene …). The one
16425
+ * surface the UI and automations talk to is the `actions` cap; it keeps no
16426
+ * catalog of its own (D3) — every `list` asks the providers live.
16427
+ *
16428
+ * This file is the data half: the entry schema, the variables an entry may
16429
+ * declare, and the pure resolution of the values a run was given. It holds no
16430
+ * runtime.
16431
+ */
16432
+ /** What a variable's value is. `select` takes one of `options`. */
16433
+ var ActionVariableTypeSchema = _enum([
16434
+ "string",
16435
+ "number",
16436
+ "boolean",
16437
+ "select"
16438
+ ]);
16439
+ var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
16440
+ var ActionVariableValueSchema = union([
16441
+ string(),
16442
+ number(),
16443
+ boolean()
16444
+ ]);
16445
+ /**
16446
+ * One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
16447
+ * value) or `{{vars.name}}` (inside a string) in their args.
16448
+ */
16449
+ var ActionVariableSchema = object({
16450
+ name: string().regex(ACTION_VARIABLE_NAME_RE),
16451
+ label: string().min(1).max(120).optional(),
16452
+ type: ActionVariableTypeSchema,
16453
+ required: boolean().optional(),
16454
+ default: ActionVariableValueSchema.optional(),
16455
+ /** The allowed values of a `select`. */
16456
+ options: array(string().min(1)).min(1).optional()
16457
+ }).superRefine((v, ctx) => {
16458
+ if (v.type === "select" && v.options === void 0) ctx.addIssue({
16459
+ code: "custom",
16460
+ message: "a select variable needs options",
16461
+ path: ["options"]
16462
+ });
16463
+ if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
16464
+ code: "custom",
16465
+ message: variableValueError(v, v.default) ?? "invalid default",
16466
+ path: ["default"]
16467
+ });
16468
+ });
16469
+ /** Why `value` is not a legal value for the variable, or null when it is. */
16470
+ function variableValueError(variable, value) {
16471
+ switch (variable.type) {
16472
+ case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
16473
+ case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
16474
+ case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
16475
+ case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
16476
+ }
16477
+ }
16478
+ var ActionSourceKindSchema = _enum(["internal", "addon"]);
16479
+ function isInternalActionId(actionId) {
16480
+ return actionId.startsWith("internal:") && actionId.length > 9;
16481
+ }
16482
+ /** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
16483
+ function addonIdOfActionId(actionId) {
16484
+ if (isInternalActionId(actionId)) return null;
16485
+ const at = actionId.indexOf(":");
16486
+ return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
16487
+ }
16488
+ var ActionStatusSchema = object({
16489
+ isRunning: boolean(),
16490
+ /** Ms epoch the latest run STARTED; null when it never ran. */
16491
+ lastRunAt: number().nullable(),
16492
+ /** The latest run's failure; null on success or when it never ran. */
16493
+ lastError: string().nullable()
16494
+ });
16495
+ var ActionEntrySchema = object({
16496
+ /** `internal:<uuid>` or `<addonId>:<localId>`. */
16497
+ id: string().min(3),
16498
+ name: string().min(1).max(120),
16499
+ /** The addon that declared it; `core-blocks` for an internal one. */
16500
+ addonId: string().min(1),
16501
+ source: ActionSourceKindSchema,
16502
+ /** An addon-declared entry is edited where it was declared. */
16503
+ readOnly: boolean(),
16504
+ /** Internal only: cap and wait steps. No action-in-action, so no cycles. */
16505
+ steps: array(ActionStepSchema).min(1).max(50).optional(),
16506
+ variables: array(ActionVariableSchema).max(20).optional(),
16507
+ status: ActionStatusSchema
16508
+ }).superRefine((entry, ctx) => {
16509
+ if (entry.source === "internal") {
16510
+ if (!isInternalActionId(entry.id)) ctx.addIssue({
16511
+ code: "custom",
16512
+ message: "an internal action id is internal:<uuid>",
16513
+ path: ["id"]
16514
+ });
16515
+ return;
16516
+ }
16517
+ if (entry.steps !== void 0) ctx.addIssue({
16518
+ code: "custom",
16519
+ message: "only an internal action carries steps",
16520
+ path: ["steps"]
16521
+ });
16522
+ if (!entry.readOnly) ctx.addIssue({
16523
+ code: "custom",
16524
+ message: "an addon action is read-only here",
16525
+ path: ["readOnly"]
16526
+ });
16527
+ if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
16528
+ code: "custom",
16529
+ message: "an addon action id is <addonId>:<localId>",
16530
+ path: ["id"]
16531
+ });
16532
+ });
16533
+ /** What an operator writes for an internal action. */
16534
+ var ActionInputSchema = object({
16535
+ name: string().min(1).max(120),
16536
+ steps: array(ActionStepSchema).min(1).max(50),
16537
+ variables: array(ActionVariableSchema).max(20).optional()
16538
+ });
16539
+ /** Who started a run. Absent = the operator pressed it. */
16540
+ var ActionRunOriginSchema = object({
16541
+ /** The automation block whose step started it. */
16542
+ blockId: string().min(1).optional() });
16543
+ /** `started` = the caller did not ask to wait. */
16544
+ var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
16545
+ var ActionRunResultSchema = object({
16546
+ runId: string().min(1),
16547
+ outcome: ActionRunOutcomeSchema,
16548
+ /** Why it did not run, or what failed. */
16549
+ message: string().optional()
16550
+ });
16551
+ _enum([
16552
+ "not-found",
16553
+ "read-only",
16554
+ "invalid-variables",
16555
+ "invalid-steps",
16556
+ "not-linked",
16557
+ "busy"
16558
+ ]);
16559
+ object({
16560
+ actionId: string(),
16561
+ runId: string(),
16562
+ isRunning: boolean(),
16563
+ /** Set when the run ended. */
16564
+ outcome: AutomationRunOutcomeSchema.optional(),
16565
+ lastRunAt: number().nullable(),
16566
+ lastError: string().nullable()
16150
16567
  });
16151
16568
  /**
16152
16569
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
@@ -18833,7 +19250,7 @@ var CompositionEventPlanSchema = object({
18833
19250
  stateField: string(),
18834
19251
  fieldKey: string()
18835
19252
  });
18836
- /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
19253
+ /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.temperature`. */
18837
19254
  var CompositionProblemSchema = object({
18838
19255
  code: _enum([
18839
19256
  "reserved-variant",
@@ -19152,7 +19569,7 @@ var GROUP_TEMPLATES = [
19152
19569
  summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
19153
19570
  role: DeviceRole.TemperatureSensor,
19154
19571
  outputCap: "temperature-sensor",
19155
- outputField: "celsius",
19572
+ outputField: "temperature",
19156
19573
  quantity: "temperature",
19157
19574
  defaultAggregate: "mean",
19158
19575
  empty: "null",
@@ -19163,7 +19580,7 @@ var GROUP_TEMPLATES = [
19163
19580
  summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
19164
19581
  role: DeviceRole.HumiditySensor,
19165
19582
  outputCap: "humidity-sensor",
19166
- outputField: "percent",
19583
+ outputField: "humidity",
19167
19584
  quantity: "humidity",
19168
19585
  defaultAggregate: "mean",
19169
19586
  empty: "null",
@@ -19174,7 +19591,7 @@ var GROUP_TEMPLATES = [
19174
19591
  summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
19175
19592
  role: DeviceRole.PressureSensor,
19176
19593
  outputCap: "pressure-sensor",
19177
- outputField: "hpa",
19594
+ outputField: "pressure",
19178
19595
  quantity: "pressure",
19179
19596
  defaultAggregate: "mean",
19180
19597
  empty: "null",
@@ -19185,7 +19602,7 @@ var GROUP_TEMPLATES = [
19185
19602
  summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
19186
19603
  role: DeviceRole.AmbientLightSensor,
19187
19604
  outputCap: "ambient-light-sensor",
19188
- outputField: "lux",
19605
+ outputField: "illuminance",
19189
19606
  quantity: "illuminance",
19190
19607
  defaultAggregate: "mean",
19191
19608
  empty: "null",
@@ -19196,7 +19613,7 @@ var GROUP_TEMPLATES = [
19196
19613
  summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
19197
19614
  role: DeviceRole.PowerSensor,
19198
19615
  outputCap: "power-meter",
19199
- outputField: "watts",
19616
+ outputField: "power",
19200
19617
  quantity: "power",
19201
19618
  defaultAggregate: "sum",
19202
19619
  empty: "omit",
@@ -19207,7 +19624,7 @@ var GROUP_TEMPLATES = [
19207
19624
  summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
19208
19625
  role: DeviceRole.EnergySensor,
19209
19626
  outputCap: "power-meter",
19210
- outputField: "kwhTotal",
19627
+ outputField: "energy",
19211
19628
  quantity: "energy",
19212
19629
  defaultAggregate: "sum",
19213
19630
  empty: "omit",
@@ -19218,7 +19635,7 @@ var GROUP_TEMPLATES = [
19218
19635
  summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
19219
19636
  role: DeviceRole.BatterySensor,
19220
19637
  outputCap: "battery",
19221
- outputField: "percentage",
19638
+ outputField: "level",
19222
19639
  quantity: "percentage",
19223
19640
  defaultAggregate: "mean",
19224
19641
  empty: "null",
@@ -19796,7 +20213,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
19796
20213
  kind: "mutation",
19797
20214
  auth: "admin",
19798
20215
  access: "view"
19799
- });
20216
+ }), method(object({
20217
+ blockId: string().min(1),
20218
+ trace: AutomationRunTraceSchema.optional(),
20219
+ runStartedAt: number().optional(),
20220
+ keepTraces: number().int().min(1).max(100).optional()
20221
+ }), _void(), {
20222
+ kind: "mutation",
20223
+ auth: "admin"
20224
+ }), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
20225
+ traces: array(AutomationRunTraceSchema),
20226
+ lastError: string().nullable()
20227
+ }), { auth: "admin" });
19800
20228
  /**
19801
20229
  * `custom-model-registry` — collection cap exposing operator-registered
19802
20230
  * custom detection models. Each provider (today: `addon-model-studio`)
@@ -45234,51 +45662,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
45234
45662
  kind: "mutation",
45235
45663
  auth: "admin"
45236
45664
  });
45237
- new Set([
45238
- {
45239
- id: "person",
45240
- name: "Person"
45241
- },
45242
- {
45243
- id: "vehicle",
45244
- name: "Vehicle"
45245
- },
45246
- {
45247
- id: "animal",
45248
- name: "Animal"
45249
- },
45250
- {
45251
- id: "package",
45252
- name: "Package"
45253
- }
45254
- ].map((l) => l.id));
45255
- var COCO_TO_MACRO = {
45256
- mapping: {
45257
- person: "person",
45258
- bicycle: "vehicle",
45259
- car: "vehicle",
45260
- motorcycle: "vehicle",
45261
- airplane: "vehicle",
45262
- bus: "vehicle",
45263
- train: "vehicle",
45264
- truck: "vehicle",
45265
- boat: "vehicle",
45266
- bird: "animal",
45267
- cat: "animal",
45268
- dog: "animal",
45269
- horse: "animal",
45270
- sheep: "animal",
45271
- cow: "animal",
45272
- elephant: "animal",
45273
- bear: "animal",
45274
- zebra: "animal",
45275
- giraffe: "animal",
45276
- suitcase: "package",
45277
- backpack: "package",
45278
- handbag: "package"
45279
- },
45280
- preserveOriginal: false
45281
- };
45282
45665
  var AUDIO_MACRO_LABELS = [
45283
45666
  {
45284
45667
  id: "speech",
@@ -58367,9 +58750,9 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
58367
58750
  */
58368
58751
  var AirQualitySensorStatusSchema = object({
58369
58752
  /** Carbon dioxide concentration in ppm. */
58370
- co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
58753
+ co2: number().min(0).optional().meta(readingMeta("concentration-volume")),
58371
58754
  /** Total volatile organic compounds in ppb. */
58372
- vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
58755
+ voc: number().min(0).optional().meta(readingMeta("concentration-ppb")),
58373
58756
  /** Particulate matter ≤ 2.5 μm in µg/m³. */
58374
58757
  pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
58375
58758
  /** Particulate matter ≤ 10 μm in µg/m³. */
@@ -58402,12 +58785,12 @@ var airQualitySensorCapability = {
58402
58785
  * History (D850): recorded series.
58403
58786
  */
58404
58787
  history: { fields: {
58405
- co2Ppm: {
58788
+ co2: {
58406
58789
  kind: "gauge",
58407
58790
  unit: "ppm",
58408
58791
  deadband: 5
58409
58792
  },
58410
- vocPpb: {
58793
+ voc: {
58411
58794
  kind: "gauge",
58412
58795
  unit: "ppb",
58413
58796
  deadband: 5
@@ -58438,7 +58821,7 @@ var airQualitySensorCapability = {
58438
58821
  */
58439
58822
  var AmbientLightSensorStatusSchema = object({
58440
58823
  /** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
58441
- lux: number().min(0).nullable().meta(readingMeta("illuminance", {
58824
+ illuminance: number().min(0).nullable().meta(readingMeta("illuminance", {
58442
58825
  precision: 0,
58443
58826
  label: "Illuminance"
58444
58827
  })),
@@ -58467,7 +58850,7 @@ var ambientLightSensorCapability = {
58467
58850
  /**
58468
58851
  * History (D850): recorded series. Wide range, so a RELATIVE deadband (10 %).
58469
58852
  */
58470
- history: { fields: { lux: {
58853
+ history: { fields: { illuminance: {
58471
58854
  kind: "gauge",
58472
58855
  unit: "lx",
58473
58856
  deadbandPct: 10,
@@ -58606,6 +58989,84 @@ var audioMetricsCapability = {
58606
58989
  */
58607
58990
  history: "none"
58608
58991
  };
58992
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
58993
+ actionId: string().min(1),
58994
+ variables: record(string(), ActionVariableValueSchema).optional()
58995
+ }), _void(), {
58996
+ kind: "mutation",
58997
+ auth: "admin"
58998
+ }), method(object({ actionId: string().min(1) }), _void(), {
58999
+ kind: "mutation",
59000
+ auth: "admin"
59001
+ });
59002
+ /**
59003
+ * actions — the ONE surface for runnable actions, for the UI and for
59004
+ * automations. Provided by the core-blocks builtin on the hub.
59005
+ *
59006
+ * An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
59007
+ * steps, kept in the hub's `actions` record kind) or declared by an addon over
59008
+ * `action-source`. `list` asks every `action-source` provider LIVE and overlays
59009
+ * the run status from the hub's `runs` ledger; there is no catalog here to
59010
+ * drift (D3).
59011
+ *
59012
+ * **Permissions follow the camera, as linked devices do.** An action is linked
59013
+ * to cameras by the operator (`setLinks`, D356: nothing links itself). A
59014
+ * non-admin may `get` / `run` an action only through a camera they may see that
59015
+ * links it: they name the camera (`deviceId`, a top-level field so the scope
59016
+ * gate sees it) and the provider refuses an action that camera does not link.
59017
+ * An admin, and an in-process caller (an automation block), may run any action.
59018
+ * Every refusal is typed (`[not-linked] …`) and logged.
59019
+ *
59020
+ * A second `run` of an action that is already running is REFUSED — traced and
59021
+ * logged — never queued.
59022
+ */
59023
+ var ActionIdInput = object({ actionId: string().min(1) });
59024
+ var ActionLinksSchema = object({
59025
+ deviceId: number().int().nonnegative(),
59026
+ actionIds: array(string().min(1)).max(100)
59027
+ });
59028
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
59029
+ actionId: string().min(1),
59030
+ deviceId: number().int().nonnegative().optional()
59031
+ }), object({ action: ActionEntrySchema.nullable() }), {
59032
+ role: "viewer",
59033
+ auth: "protected",
59034
+ kind: "query",
59035
+ caller: "required"
59036
+ }), method(object({
59037
+ actionId: string().min(1),
59038
+ variables: record(string(), ActionVariableValueSchema).optional(),
59039
+ wait: boolean().optional(),
59040
+ origin: ActionRunOriginSchema.optional(),
59041
+ deviceId: number().int().nonnegative().optional()
59042
+ }), ActionRunResultSchema, {
59043
+ role: "viewer",
59044
+ auth: "protected",
59045
+ kind: "mutation",
59046
+ caller: "required"
59047
+ }), method(ActionIdInput, _void(), {
59048
+ kind: "mutation",
59049
+ auth: "admin"
59050
+ }), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
59051
+ kind: "mutation",
59052
+ auth: "admin"
59053
+ }), method(object({
59054
+ actionId: string().min(1),
59055
+ action: ActionInputSchema.partial()
59056
+ }), object({ action: ActionEntrySchema }), {
59057
+ kind: "mutation",
59058
+ auth: "admin"
59059
+ }), method(ActionIdInput, _void(), {
59060
+ kind: "mutation",
59061
+ auth: "admin"
59062
+ }), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
59063
+ role: "viewer",
59064
+ auth: "protected",
59065
+ kind: "query"
59066
+ }), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
59067
+ kind: "mutation",
59068
+ auth: "admin"
59069
+ });
58609
59070
  /**
58610
59071
  * Automation-control cap. Models HA `automation.*` entities on
58611
59072
  * `DeviceType.Automation`. An automation is a trigger+condition+
@@ -58702,7 +59163,7 @@ var BatteryStatusSchema = object({
58702
59163
  * Consumers must SKIP a null rather than coerce it — `battery-band` already
58703
59164
  * declines to band a non-finite reading, which is the correct shape.
58704
59165
  */
58705
- percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
59166
+ level: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
58706
59167
  /**
58707
59168
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
58708
59169
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -58712,7 +59173,7 @@ var BatteryStatusSchema = object({
58712
59173
  * `'unknown'` is the absence of an answer: the provider has not read the
58713
59174
  * power fields yet, or the firmware reported neither. Before it existed,
58714
59175
  * two unreadable fields produced `'none'`, and a camera nobody had reached
58715
- * was drawn "on battery alone" — the same D315 defect `percentage` closed
59176
+ * was drawn "on battery alone" — the same D315 defect `level` closed
58716
59177
  * by going nullable. Consumers SKIP it (no charger state published, no
58717
59178
  * glyph, no HomeKit ChargingState) rather than coerce it either way.
58718
59179
  */
@@ -58736,7 +59197,7 @@ var BatteryStatusSchema = object({
58736
59197
  * that only report charge. A second reading on this cap, not a second
58737
59198
  * `numeric-sensor` on the same device.
58738
59199
  */
58739
- volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
59200
+ voltage: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
58740
59201
  /**
58741
59202
  * Ms epoch of the last time the device PROVED it was reachable — a
58742
59203
  * completed firmware round-trip, an observed wake, or an inbound push
@@ -58770,7 +59231,7 @@ var BatteryStatusSchema = object({
58770
59231
  /**
58771
59232
  * True when the source is a BINARY low-battery indicator (HA
58772
59233
  * `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
58773
- * charge level — `percentage` is then a coarse stand-in (100 = normal,
59234
+ * charge level — `level` is then a coarse stand-in (100 = normal,
58774
59235
  * sub-threshold = low). UI MUST render "Normal"/"Low" instead of a
58775
59236
  * misleading exact percentage. Absent/false → genuine 0–100 % reading.
58776
59237
  */
@@ -58790,15 +59251,15 @@ var BATTERY_DEVICE_TYPES = [
58790
59251
  var batteryCustomize = {
58791
59252
  version: 1,
58792
59253
  targets: [{
58793
- id: "percentage",
59254
+ id: "level",
58794
59255
  cardinality: "scalar",
58795
59256
  vocabulary: {
58796
59257
  cap: "battery",
58797
- stateField: "percentage"
59258
+ stateField: "level"
58798
59259
  },
58799
59260
  deviceTypes: BATTERY_DEVICE_TYPES,
58800
59261
  apply: "add",
58801
- path: "percentage",
59262
+ path: "level",
58802
59263
  sources: [{
58803
59264
  kind: "field",
58804
59265
  valueKinds: ["number", "string"],
@@ -58892,7 +59353,7 @@ onStatusChanged: { data: object({
58892
59353
  schema: BatteryStatusSchema,
58893
59354
  kind: "push",
58894
59355
  empty: {
58895
- percentage: null,
59356
+ level: null,
58896
59357
  charging: "unknown",
58897
59358
  sleeping: false,
58898
59359
  lastUpdated: 0
@@ -58919,11 +59380,11 @@ onStatusChanged: { data: object({
58919
59380
  * History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
58920
59381
  */
58921
59382
  history: { fields: {
58922
- percentage: {
59383
+ level: {
58923
59384
  kind: "gauge",
58924
59385
  unit: "%"
58925
59386
  },
58926
- volts: {
59387
+ voltage: {
58927
59388
  kind: "gauge",
58928
59389
  unit: "V"
58929
59390
  }
@@ -58983,14 +59444,14 @@ var binaryCapability = {
58983
59444
  * controls to this single-method surface.
58984
59445
  *
58985
59446
  * The cap is intentionally minimal: a single `setBrightness({deviceId,
58986
- * percentage})` mutation plus the auto-injected `getStatus`. Drivers
59447
+ * level})` mutation plus the auto-injected `getStatus`. Drivers
58987
59448
  * that expose richer controls (color temperature, scenes, schedules)
58988
59449
  * should surface those via the device's `getSettingsUISchema()`
58989
59450
  * instead of bloating this cap.
58990
59451
  */
58991
59452
  var BrightnessStatusSchema = object({
58992
59453
  /** Current level as 0..100 inclusive. Firmware-reported. */
58993
- percentage: number().min(0).max(100).meta(readingMeta("percentage")),
59454
+ level: number().min(0).max(100).meta(readingMeta("percentage")),
58994
59455
  /** Ms epoch of the last operator-driven change. Useful for UI freshness. */
58995
59456
  lastChangedAt: number()
58996
59457
  });
@@ -59002,7 +59463,7 @@ var brightnessCapability = {
59002
59463
  deviceTypes: [DeviceType.Light],
59003
59464
  methods: { setBrightness: method(object({
59004
59465
  deviceId: number().int().nonnegative(),
59005
- percentage: number().min(0).max(100)
59466
+ level: number().min(0).max(100)
59006
59467
  }), _void(), {
59007
59468
  kind: "mutation",
59008
59469
  auth: "protected"
@@ -59015,7 +59476,7 @@ var brightnessCapability = {
59015
59476
  */
59016
59477
  onBrightnessChanged: { data: object({
59017
59478
  deviceId: number(),
59018
- percentage: number().min(0).max(100),
59479
+ level: number().min(0).max(100),
59019
59480
  lastChangedAt: number()
59020
59481
  }) } },
59021
59482
  status: {
@@ -59038,7 +59499,7 @@ onBrightnessChanged: { data: object({
59038
59499
  /**
59039
59500
  * History (D850): recorded series. Actuator tier: level keeps every change.
59040
59501
  */
59041
- history: { fields: { percentage: {
59502
+ history: { fields: { level: {
59042
59503
  kind: "gauge",
59043
59504
  unit: "%",
59044
59505
  minIntervalMs: 0
@@ -59635,11 +60096,11 @@ var ColorInputSchema = discriminatedUnion("mode", [
59635
60096
  }),
59636
60097
  object({
59637
60098
  mode: literal("mired"),
59638
- mireds: number().int().min(50).max(1e3)
60099
+ colorTemperature: number().int().min(50).max(1e3)
59639
60100
  })
59640
60101
  ]);
59641
60102
  var ColorStatusSchema = object({
59642
- /** Active color mode — which of `rgb` / `hsv` / `mireds` reflects
60103
+ /** Active color mode — which of `rgb` / `hsv` / `colorTemperature` reflects
59643
60104
  * the bulb's current state. */
59644
60105
  mode: _enum([
59645
60106
  "rgb",
@@ -59651,7 +60112,7 @@ var ColorStatusSchema = object({
59651
60112
  /** Populated when `mode === 'hsv'`. */
59652
60113
  hsv: HsvTripletSchema.optional(),
59653
60114
  /** Populated when `mode === 'mired'`. */
59654
- mireds: number().int().optional().meta(readingMeta("colour-temperature")),
60115
+ colorTemperature: number().int().optional().meta(readingMeta("colour-temperature")),
59655
60116
  /** Ms epoch of the last operator-driven change. */
59656
60117
  lastChangedAt: number()
59657
60118
  });
@@ -59683,7 +60144,7 @@ onColorChanged: { data: object({
59683
60144
  ]),
59684
60145
  rgb: RgbTripletSchema.optional(),
59685
60146
  hsv: HsvTripletSchema.optional(),
59686
- mireds: number().int().optional(),
60147
+ colorTemperature: number().int().optional(),
59687
60148
  lastChangedAt: number()
59688
60149
  }) } },
59689
60150
  status: {
@@ -60560,11 +61021,11 @@ var DishwasherStatusSchema = object({
60560
61021
  /** Feature keys of the programs the appliance currently offers — drives the UI selector. */
60561
61022
  availablePrograms: array(string()),
60562
61023
  /** Seconds remaining on the active cycle, or null when not running / not known. */
60563
- remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
61024
+ remaining: number().int().nonnegative().nullable().meta(readingMeta("duration")),
60564
61025
  /** Seconds the delayed start is set to (time until the cycle starts), or null. */
60565
- delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
61026
+ delayedStart: number().int().nonnegative().nullable().meta(readingMeta("duration")),
60566
61027
  /** Cycle completion 0..100, or null when not applicable. */
60567
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61028
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
60568
61029
  /** True when the door is reported open; null when the door state is not known. */
60569
61030
  doorOpen: boolean().nullable(),
60570
61031
  /** True when the door is latched (locked) during a cycle; null when not reported. */
@@ -60783,14 +61244,14 @@ var dishwasherCapability = {
60783
61244
  runtimeState: DishwasherStatusSchema,
60784
61245
  durability: "session",
60785
61246
  history: { fields: {
60786
- progressPercent: {
61247
+ progress: {
60787
61248
  kind: "gauge",
60788
61249
  unit: "%",
60789
61250
  deadband: 2
60790
61251
  },
60791
61252
  state: { kind: "enum" },
60792
61253
  operationState: { kind: "enum" },
60793
- remainingSeconds: {
61254
+ remaining: {
60794
61255
  kind: "gauge",
60795
61256
  unit: "s",
60796
61257
  minIntervalMs: 6e4
@@ -61381,7 +61842,7 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
61381
61842
  var FanControlStatusSchema = object({
61382
61843
  /** Active speed as 0..100 inclusive. Null when the device has no
61383
61844
  * speed surface (single-speed fan). */
61384
- percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61845
+ speed: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61385
61846
  /** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
61386
61847
  * a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
61387
61848
  percentageStep: number().positive().optional().meta(readingMeta("percentage")),
@@ -61408,7 +61869,7 @@ var fanControlCapability = {
61408
61869
  methods: {
61409
61870
  setPercentage: method(object({
61410
61871
  deviceId: number().int().nonnegative(),
61411
- percentage: number().min(0).max(100)
61872
+ speed: number().min(0).max(100)
61412
61873
  }), _void(), {
61413
61874
  kind: "mutation",
61414
61875
  auth: "protected"
@@ -61441,7 +61902,7 @@ var fanControlCapability = {
61441
61902
  },
61442
61903
  /**
61443
61904
  * Runtime-state slice — mirrored by the kernel. UI fan speed
61444
- * sliders read `percentage` for live updates.
61905
+ * sliders read `speed` for live updates.
61445
61906
  */
61446
61907
  runtimeState: FanControlStatusSchema,
61447
61908
  /**
@@ -61455,7 +61916,7 @@ var fanControlCapability = {
61455
61916
  * History (D850): recorded series. Actuator tier: speed keeps every change.
61456
61917
  */
61457
61918
  history: { fields: {
61458
- percentage: {
61919
+ speed: {
61459
61920
  kind: "gauge",
61460
61921
  unit: "%",
61461
61922
  minIntervalMs: 0
@@ -61900,7 +62361,7 @@ var humidifierCapability = {
61900
62361
  */
61901
62362
  var HumiditySensorStatusSchema = object({
61902
62363
  /** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
61903
- percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
62364
+ humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
61904
62365
  precision: 0,
61905
62366
  label: "Humidity"
61906
62367
  })),
@@ -61929,7 +62390,7 @@ var humiditySensorCapability = {
61929
62390
  /**
61930
62391
  * History (D850): recorded series.
61931
62392
  */
61932
- history: { fields: { percent: {
62393
+ history: { fields: { humidity: {
61933
62394
  kind: "gauge",
61934
62395
  unit: "%",
61935
62396
  deadband: .5
@@ -62569,7 +63030,7 @@ var LawnMowerControlStatusSchema = object({
62569
63030
  batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
62570
63031
  /** 0..100 mowing-completion percentage of the current task, or null when no
62571
63032
  * task is active / progress is unavailable. */
62572
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
63033
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
62573
63034
  /** Current device/event code (dynamic — mostly status, sometimes an error),
62574
63035
  * or null when unknown. */
62575
63036
  currentCode: number().nullable().meta(readingMeta("none")),
@@ -63069,7 +63530,7 @@ var lockControlCapability = {
63069
63530
  volatileStateFields: ["lastChangedAt"]
63070
63531
  };
63071
63532
  /**
63072
- * A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
63533
+ * A monotonic total between resets (D944). Energy uses `power-meter.energy`
63073
63534
  * so dashboards keep one series; every other instantaneous reading lands here.
63074
63535
  * `value` is the time integral in the source quantity's accumulated base
63075
63536
  * (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
@@ -63163,10 +63624,10 @@ var MediaPlayerStatusSchema = object({
63163
63624
  currentMedia: MediaInfoSchema.nullable(),
63164
63625
  /** Current playback position in ms. Null when not seekable or
63165
63626
  * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
63166
- positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
63627
+ position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
63167
63628
  /** Total duration of the current media in ms. Null when unknown
63168
63629
  * (live stream) or nothing is playing. */
63169
- durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
63630
+ duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
63170
63631
  /** Shuffle toggle. Null when no shuffle surface.
63171
63632
  * Pair with `DeviceFeature.MediaPlayerShuffle`. */
63172
63633
  shuffle: boolean().nullable(),
@@ -63205,7 +63666,7 @@ var mediaPlayerCapability = {
63205
63666
  }),
63206
63667
  seek: method(object({
63207
63668
  deviceId: number().int().nonnegative(),
63208
- positionMs: number().int().nonnegative()
63669
+ position: number().int().nonnegative()
63209
63670
  }), _void(), {
63210
63671
  kind: "mutation",
63211
63672
  auth: "protected"
@@ -63277,7 +63738,7 @@ var mediaPlayerCapability = {
63277
63738
  /**
63278
63739
  * History (D850): volume (a level an operator or an automation sets; the
63279
63740
  * default 10 s floor folds a slider drag into its end value) and mute.
63280
- * `positionMs` is not recorded: it moves continuously while playing.
63741
+ * `position` is not recorded: it moves continuously while playing.
63281
63742
  */
63282
63743
  history: { fields: {
63283
63744
  volumeLevel: {
@@ -64239,9 +64700,9 @@ var NetworkLinkStatusSchema = object({
64239
64700
  * one whose reading has not landed must not be drawn at 0 %. Consumers
64240
64701
  * SKIP a null rather than coerce it.
64241
64702
  */
64242
- signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64703
+ signal: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64243
64704
  /** Raw received signal strength in dBm, when the firmware reports one. */
64244
- rssiDbm: number().optional().meta(readingMeta("signal-level")),
64705
+ rssi: number().optional().meta(readingMeta("signal-level")),
64245
64706
  /** Network name of a wireless link, when the firmware reports it. */
64246
64707
  ssid: string().optional(),
64247
64708
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
@@ -64250,7 +64711,7 @@ var NetworkLinkStatusSchema = object({
64250
64711
  /** The slice a provider seeds before its first read: nothing is known yet. */
64251
64712
  var NETWORK_LINK_UNKNOWN = {
64252
64713
  type: "unknown",
64253
- signalPercent: null,
64714
+ signal: null,
64254
64715
  lastUpdated: 0
64255
64716
  };
64256
64717
  /**
@@ -64267,9 +64728,9 @@ function signalPercentFromBars(bars, maxBars) {
64267
64728
  * below is 0 %, -50 dBm and above is 100 %, linear between. Non-finite or
64268
64729
  * positive input is not an RSSI: `null`.
64269
64730
  */
64270
- function signalPercentFromRssi(rssiDbm) {
64271
- if (rssiDbm === void 0 || !Number.isFinite(rssiDbm) || rssiDbm > 0) return null;
64272
- return Math.round((Math.min(-50, Math.max(-100, rssiDbm)) + 100) * 2);
64731
+ function signalPercentFromRssi(rssi) {
64732
+ if (rssi === void 0 || !Number.isFinite(rssi) || rssi > 0) return null;
64733
+ return Math.round((Math.min(-50, Math.max(-100, rssi)) + 100) * 2);
64273
64734
  }
64274
64735
  var networkLinkCapability = {
64275
64736
  name: "network-link",
@@ -64320,13 +64781,13 @@ onStatusChanged: { data: object({
64320
64781
  * History (D850): recorded series.
64321
64782
  */
64322
64783
  history: { fields: {
64323
- signalPercent: {
64784
+ signal: {
64324
64785
  kind: "gauge",
64325
64786
  unit: "%",
64326
64787
  deadband: 3,
64327
64788
  minIntervalMs: 6e4
64328
64789
  },
64329
- rssiDbm: {
64790
+ rssi: {
64330
64791
  kind: "gauge",
64331
64792
  unit: "dBm",
64332
64793
  deadband: 2,
@@ -65117,10 +65578,20 @@ var PetFeederDeviceStatusSchema = _enum([
65117
65578
  ]);
65118
65579
  var gramsPortion = number().int().min(4).max(200);
65119
65580
  var PetFeederStatusSchema = object({
65120
- /** Food currently in the bowl (grams). Null when the device has not
65121
- * reported a reading yet. On dual-hopper models this is the combined
65122
- * bowl reading; per-hopper levels live in `food1`/`food2`. */
65581
+ /** Food in the TANK (hopper), as the feeder's own sensor reports it
65582
+ * (`state.food`). A coarse level code, not grams — `0` is empty. The
65583
+ * amount in the bowl is `bowlFood`. On dual-hopper models this is the
65584
+ * combined reading; per-hopper levels live in `food1`/`food2`. Null when
65585
+ * the device has not reported yet. */
65123
65586
  foodLevel: number().nullable().meta(readingMeta("none")),
65587
+ /** Food in the BOWL as the feeder reports it (`state.bowl`), in the
65588
+ * feeder's own units. Null when the model reports none. */
65589
+ bowlFood: number().nullable().meta(readingMeta("none")),
65590
+ /** True while the pet is eating (`state.eating`). */
65591
+ eating: boolean(),
65592
+ /** Whether `markFoodReplenished` does anything on this model. When false
65593
+ * the client must not offer it. */
65594
+ supportsMarkRefilled: boolean(),
65124
65595
  /** Hopper-1 food level (grams) on dual-hopper feeders; null on
65125
65596
  * single-hopper models. */
65126
65597
  food1: number().nullable().meta(readingMeta("none")),
@@ -65128,8 +65599,8 @@ var PetFeederStatusSchema = object({
65128
65599
  * single-hopper models. */
65129
65600
  food2: number().nullable().meta(readingMeta("none")),
65130
65601
  /** Derived low-food flag — mirrors the HA `food_level` binary_sensor
65131
- * (`device_class: problem`, on = low). True when the bowl is empty /
65132
- * below the feeder's low threshold. */
65602
+ * (`device_class: problem`, on = low). True when the tank reports empty,
65603
+ * or, on a dual-hopper model, when EITHER hopper is empty. */
65133
65604
  lowFood: boolean(),
65134
65605
  /** Battery charge 0..100 (%). Null on mains-powered models or when the
65135
65606
  * device has no battery reading. */
@@ -65197,7 +65668,9 @@ var petFeederCapability = {
65197
65668
  kind: "mutation",
65198
65669
  auth: "protected"
65199
65670
  }),
65200
- /** Mark a hopper as refilled (D4H/D4S/D4SH). */
65671
+ /** Tell the PetKit cloud a hopper was refilled so it stops its low-food
65672
+ * reminders (D4H/D4S/D4SH only — see `supportsMarkRefilled`). It does not
65673
+ * change any sensor reading. */
65201
65674
  markFoodReplenished: method(object({ deviceId: number().int().nonnegative() }), _void(), {
65202
65675
  kind: "mutation",
65203
65676
  auth: "protected"
@@ -65270,6 +65743,7 @@ var petFeederCapability = {
65270
65743
  */
65271
65744
  history: { fields: {
65272
65745
  foodLevel: { kind: "gauge" },
65746
+ bowlFood: { kind: "gauge" },
65273
65747
  food1: { kind: "gauge" },
65274
65748
  food2: { kind: "gauge" },
65275
65749
  batteryPower: {
@@ -65679,16 +66153,16 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
65679
66153
  * in real-world devices.
65680
66154
  */
65681
66155
  var PowerMeterStatusSchema = object({
65682
- /** Instantaneous power draw in watts. */
65683
- watts: number().optional().meta(readingMeta("power", { label: "Power" })),
66156
+ /** Instantaneous power draw (watts). */
66157
+ power: number().optional().meta(readingMeta("power", { label: "Power" })),
65684
66158
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
65685
- kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
65686
- /** Voltage in volts. */
65687
- volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
66159
+ energy: number().optional().meta(readingMeta("energy", { label: "Energy" })),
66160
+ /** Voltage (volts). */
66161
+ voltage: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
65688
66162
  /** Current in amperes. */
65689
- amps: number().optional().meta(readingMeta("current", { label: "Current" })),
66163
+ current: number().optional().meta(readingMeta("current", { label: "Current" })),
65690
66164
  /** Apparent power in volt-amperes. */
65691
- va: number().optional().meta(readingMeta("apparent-power")),
66165
+ apparentPower: number().optional().meta(readingMeta("apparent-power")),
65692
66166
  /** Power factor (0..1) if reported. */
65693
66167
  powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
65694
66168
  /** Ms epoch when the slice was last updated. */
@@ -65746,14 +66220,14 @@ function powerTarget(id, unit) {
65746
66220
  advancedExpression: true
65747
66221
  };
65748
66222
  }
65749
- /** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
66223
+ /** "Power and energy" extension: power, energy, voltage and current from other devices (D951). */
65750
66224
  var powerMeterCustomize = {
65751
66225
  version: 1,
65752
66226
  targets: [
65753
- powerTarget("watts", "W"),
65754
- powerTarget("kwhTotal", "kWh"),
65755
- powerTarget("volts", "V"),
65756
- powerTarget("amps", "A")
66227
+ powerTarget("power", "W"),
66228
+ powerTarget("energy", "kWh"),
66229
+ powerTarget("voltage", "V"),
66230
+ powerTarget("current", "A")
65757
66231
  ]
65758
66232
  };
65759
66233
  var powerMeterCapability = {
@@ -65769,41 +66243,41 @@ var powerMeterCapability = {
65769
66243
  },
65770
66244
  runtimeState: PowerMeterStatusSchema,
65771
66245
  /**
65772
- * Runtime-state durability: **restored** — as `numeric-sensor`; `kwhTotal` is an accumulator whose restored value is the baseline.
66246
+ * Runtime-state durability: **restored** — as `numeric-sensor`; `energy` is an accumulator whose restored value is the baseline.
65773
66247
  *
65774
66248
  * See `RuntimeStateDurability`. Enforced by
65775
66249
  * `scripts/check-runtime-state-durability.ts`.
65776
66250
  */
65777
66251
  durability: "restored",
65778
66252
  /**
65779
- * History (D850): recorded series. Gauges are floored at 30 s; `kwhTotal` is the one monotonic meter (counter).
66253
+ * History (D850): recorded series. Gauges are floored at 30 s; `energy` is the one monotonic meter (counter).
65780
66254
  */
65781
66255
  history: { fields: {
65782
- watts: {
66256
+ power: {
65783
66257
  kind: "gauge",
65784
66258
  unit: "W",
65785
66259
  deadband: 1,
65786
66260
  minIntervalMs: 3e4
65787
66261
  },
65788
- kwhTotal: {
66262
+ energy: {
65789
66263
  kind: "counter",
65790
66264
  unit: "kWh",
65791
66265
  deadband: .01,
65792
66266
  minIntervalMs: 6e4
65793
66267
  },
65794
- volts: {
66268
+ voltage: {
65795
66269
  kind: "gauge",
65796
66270
  unit: "V",
65797
66271
  deadband: 1,
65798
66272
  minIntervalMs: 3e4
65799
66273
  },
65800
- amps: {
66274
+ current: {
65801
66275
  kind: "gauge",
65802
66276
  unit: "A",
65803
66277
  deadband: .05,
65804
66278
  minIntervalMs: 3e4
65805
66279
  },
65806
- va: {
66280
+ apparentPower: {
65807
66281
  kind: "gauge",
65808
66282
  unit: "VA",
65809
66283
  deadband: 1,
@@ -65853,9 +66327,6 @@ var PresenceStatusSchema = object({
65853
66327
  location: string().nullable(),
65854
66328
  /** GPS coordinates when available. Null otherwise. */
65855
66329
  gps: GpsLocationSchema.nullable(),
65856
- /** Optional battery level of the tracking device (0..100). Null
65857
- * when not reported. */
65858
- batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
65859
66330
  /** Ms epoch when the slice was last updated. */
65860
66331
  lastChangedAt: number()
65861
66332
  });
@@ -65884,14 +66355,7 @@ var presenceCapability = {
65884
66355
  * `scripts/check-runtime-state-durability.ts`.
65885
66356
  */
65886
66357
  durability: "restored",
65887
- /**
65888
- * History (D850): recorded series.
65889
- */
65890
- history: { fields: { batteryPercent: {
65891
- kind: "gauge",
65892
- unit: "%",
65893
- deadband: 1
65894
- } } },
66358
+ history: "none",
65895
66359
  /** Clock fields: written, but excluded from the compare that decides
65896
66360
  * whether persisting is worth a SQLite commit. */
65897
66361
  volatileStateFields: ["lastChangedAt"]
@@ -65906,7 +66370,7 @@ var presenceCapability = {
65906
66370
  */
65907
66371
  var PressureSensorStatusSchema = object({
65908
66372
  /** Current pressure in hPa. `null` when the sample was refused (D393). */
65909
- hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
66373
+ pressure: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
65910
66374
  /** Ms epoch when the slice was last updated. */
65911
66375
  lastFetchedAt: number()
65912
66376
  });
@@ -65932,7 +66396,7 @@ var pressureSensorCapability = {
65932
66396
  /**
65933
66397
  * History (D850): recorded series.
65934
66398
  */
65935
- history: { fields: { hpa: {
66399
+ history: { fields: { pressure: {
65936
66400
  kind: "gauge",
65937
66401
  unit: "hPa",
65938
66402
  deadband: .1
@@ -70135,7 +70599,7 @@ var tamperCapability = {
70135
70599
  */
70136
70600
  var TemperatureSensorStatusSchema = object({
70137
70601
  /** Current temperature in Celsius. `null` when the sample was refused (D393). */
70138
- celsius: number().nullable().meta(readingMeta("temperature", {
70602
+ temperature: number().nullable().meta(readingMeta("temperature", {
70139
70603
  precision: 1,
70140
70604
  label: "Temperature"
70141
70605
  })),
@@ -70164,7 +70628,7 @@ var temperatureSensorCapability = {
70164
70628
  /**
70165
70629
  * History (D850): recorded series.
70166
70630
  */
70167
- history: { fields: { celsius: {
70631
+ history: { fields: { temperature: {
70168
70632
  kind: "gauge",
70169
70633
  unit: "°C",
70170
70634
  deadband: .1
@@ -70461,7 +70925,7 @@ var VacuumControlStatusSchema = object({
70461
70925
  /** Speed tokens the hardware accepts — drives the UI selector. */
70462
70926
  availableFanSpeeds: array(string()),
70463
70927
  /** 0..100 cleaning-completion percentage of the current task, or null. */
70464
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
70928
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
70465
70929
  /** Current error code (0 / null = no error). */
70466
70930
  errorCode: number().nullable().meta(readingMeta("none")),
70467
70931
  /** Human label for {@link errorCode}, or null when none / undecodable. */
@@ -72263,7 +72727,7 @@ var BaseDevice = class {
72263
72727
  * `device-local-state.ts`. Drivers access via:
72264
72728
  *
72265
72729
  * `this.state.battery.sleeping = true` // patches the battery slice
72266
- * `const pct = this.state.battery.percentage` // reads the battery slice
72730
+ * `const pct = this.state.battery.level` // reads the battery slice
72267
72731
  * `this.state.deviceStatus.online = true` // mirrors `markOnline(true)`
72268
72732
  *
72269
72733
  * Adding a new cap with `runtimeState:` automatically extends this
@@ -72303,7 +72767,7 @@ var BaseDevice = class {
72303
72767
  * shape; drivers don't redeclare it, they just write through.
72304
72768
  *
72305
72769
  * Read: `this.runtimeState.getCapState('battery')` →
72306
- * `{percentage, charging, sleeping, lastUpdated}` for any
72770
+ * `{level, charging, sleeping, lastUpdated}` for any
72307
72771
  * provider that registers `batteryCapability`.
72308
72772
  * Write: `this.runtimeState.setCapState('battery', { … })`.
72309
72773
  *
@@ -73477,6 +73941,104 @@ Object.freeze({
73477
73941
  access: "create",
73478
73942
  role: "admin"
73479
73943
  },
73944
+ "actions.create": {
73945
+ capName: "actions",
73946
+ capScope: "system",
73947
+ addonId: null,
73948
+ access: "create",
73949
+ role: "admin"
73950
+ },
73951
+ "actions.delete": {
73952
+ capName: "actions",
73953
+ capScope: "system",
73954
+ addonId: null,
73955
+ access: "delete",
73956
+ role: "admin"
73957
+ },
73958
+ "actions.get": {
73959
+ capName: "actions",
73960
+ capScope: "system",
73961
+ addonId: null,
73962
+ access: "view",
73963
+ role: "viewer"
73964
+ },
73965
+ "actions.getLinks": {
73966
+ capName: "actions",
73967
+ capScope: "system",
73968
+ addonId: null,
73969
+ access: "view",
73970
+ role: "admin"
73971
+ },
73972
+ "actions.getTraces": {
73973
+ capName: "actions",
73974
+ capScope: "system",
73975
+ addonId: null,
73976
+ access: "view",
73977
+ role: "admin"
73978
+ },
73979
+ "actions.list": {
73980
+ capName: "actions",
73981
+ capScope: "system",
73982
+ addonId: null,
73983
+ access: "view",
73984
+ role: "admin"
73985
+ },
73986
+ "actions.listForCamera": {
73987
+ capName: "actions",
73988
+ capScope: "system",
73989
+ addonId: null,
73990
+ access: "view",
73991
+ role: "viewer"
73992
+ },
73993
+ "actions.run": {
73994
+ capName: "actions",
73995
+ capScope: "system",
73996
+ addonId: null,
73997
+ access: "create",
73998
+ role: "viewer"
73999
+ },
74000
+ "actions.setLinks": {
74001
+ capName: "actions",
74002
+ capScope: "system",
74003
+ addonId: null,
74004
+ access: "create",
74005
+ role: "admin"
74006
+ },
74007
+ "actions.stop": {
74008
+ capName: "actions",
74009
+ capScope: "system",
74010
+ addonId: null,
74011
+ access: "create",
74012
+ role: "admin"
74013
+ },
74014
+ "actions.update": {
74015
+ capName: "actions",
74016
+ capScope: "system",
74017
+ addonId: null,
74018
+ access: "create",
74019
+ role: "admin"
74020
+ },
74021
+ "actionSource.listActions": {
74022
+ capName: "action-source",
74023
+ capScope: "system",
74024
+ addonId: null,
74025
+ access: "view",
74026
+ role: "admin"
74027
+ },
74028
+ "actionSource.runAction": {
74029
+ capName: "action-source",
74030
+ capScope: "system",
74031
+ addonId: null,
74032
+ access: "create",
74033
+ role: "admin"
74034
+ },
74035
+ "actionSource.stopAction": {
74036
+ capName: "action-source",
74037
+ capScope: "system",
74038
+ addonId: null,
74039
+ access: "create",
74040
+ role: "admin"
74041
+ },
73480
74042
  "addonPages.listPages": {
73481
74043
  capName: "addon-pages",
73482
74044
  capScope: "system",
@@ -74758,6 +75320,13 @@ Object.freeze({
74758
75320
  access: "view",
74759
75321
  role: "admin"
74760
75322
  },
75323
+ "coreBlocks.getAutomationRunState": {
75324
+ capName: "core-blocks",
75325
+ capScope: "system",
75326
+ addonId: null,
75327
+ access: "view",
75328
+ role: "admin"
75329
+ },
74761
75330
  "coreBlocks.getBlockSettings": {
74762
75331
  capName: "core-blocks",
74763
75332
  capScope: "system",
@@ -74779,6 +75348,13 @@ Object.freeze({
74779
75348
  access: "view",
74780
75349
  role: "admin"
74781
75350
  },
75351
+ "coreBlocks.getTraces": {
75352
+ capName: "core-blocks",
75353
+ capScope: "system",
75354
+ addonId: null,
75355
+ access: "view",
75356
+ role: "admin"
75357
+ },
74782
75358
  "coreBlocks.getTypeDefs": {
74783
75359
  capName: "core-blocks",
74784
75360
  capScope: "system",
@@ -74814,6 +75390,13 @@ Object.freeze({
74814
75390
  access: "create",
74815
75391
  role: "admin"
74816
75392
  },
75393
+ "coreBlocks.reportAutomationRun": {
75394
+ capName: "core-blocks",
75395
+ capScope: "system",
75396
+ addonId: null,
75397
+ access: "create",
75398
+ role: "admin"
75399
+ },
74817
75400
  "coreBlocks.restart": {
74818
75401
  capName: "core-blocks",
74819
75402
  capScope: "system",
@@ -83387,7 +83970,7 @@ var ACTUATOR_CAP_VOCABULARY = {
83387
83970
  label: t("Full brightness", "Luminosità massima"),
83388
83971
  phrase: t("Set {device} to full brightness", "Porta {device} alla massima luminosità"),
83389
83972
  icon: "sun",
83390
- args: { percentage: 100 }
83973
+ args: { level: 100 }
83391
83974
  },
83392
83975
  {
83393
83976
  id: "brightness.half",
@@ -83395,7 +83978,7 @@ var ACTUATOR_CAP_VOCABULARY = {
83395
83978
  label: t("Half brightness", "Luminosità a metà"),
83396
83979
  phrase: t("Dim {device} to half", "Abbassa {device} a metà luminosità"),
83397
83980
  icon: "sun-dim",
83398
- args: { percentage: 50 }
83981
+ args: { level: 50 }
83399
83982
  },
83400
83983
  {
83401
83984
  id: "brightness.off",
@@ -83403,16 +83986,16 @@ var ACTUATOR_CAP_VOCABULARY = {
83403
83986
  label: t("Brightness off", "Luminosità a zero"),
83404
83987
  phrase: t("Dim {device} to zero", "Abbassa {device} a zero"),
83405
83988
  icon: "lightbulb-off",
83406
- args: { percentage: 0 }
83989
+ args: { level: 0 }
83407
83990
  },
83408
83991
  {
83409
83992
  id: "brightness.set",
83410
83993
  method: "setBrightness",
83411
83994
  label: t("Set brightness", "Imposta la luminosità"),
83412
- phrase: t("Set the brightness of {device} to {percentage}", "Imposta la luminosità di {device} a {percentage}"),
83995
+ phrase: t("Set the brightness of {device} to {level}", "Imposta la luminosità di {device} a {level}"),
83413
83996
  icon: "sun-medium",
83414
83997
  openArgs: [{
83415
- key: "percentage",
83998
+ key: "level",
83416
83999
  label: PERCENT,
83417
84000
  offer: {
83418
84001
  kind: "number",
@@ -83426,13 +84009,13 @@ var ACTUATOR_CAP_VOCABULARY = {
83426
84009
  ],
83427
84010
  state: [{
83428
84011
  kind: "numeric",
83429
- field: "percentage",
84012
+ field: "level",
83430
84013
  quantity: t("the brightness", "la luminosità"),
83431
84014
  label: t("Brightness", "Luminosità"),
83432
84015
  unit: "%",
83433
84016
  icon: "sun"
83434
84017
  }],
83435
- events: { onBrightnessChanged: { notOperatorFacing: "the `percentage` state trigger reads the same change" } }
84018
+ events: { onBrightnessChanged: { notOperatorFacing: "the `level` state trigger reads the same change" } }
83436
84019
  },
83437
84020
  color: {
83438
84021
  scope: "device",
@@ -83446,7 +84029,7 @@ var ACTUATOR_CAP_VOCABULARY = {
83446
84029
  icon: "sun",
83447
84030
  args: { color: {
83448
84031
  mode: "mired",
83449
- mireds: 370
84032
+ colorTemperature: 370
83450
84033
  } }
83451
84034
  },
83452
84035
  {
@@ -83457,7 +84040,7 @@ var ACTUATOR_CAP_VOCABULARY = {
83457
84040
  icon: "snowflake",
83458
84041
  args: { color: {
83459
84042
  mode: "mired",
83460
- mireds: 200
84043
+ colorTemperature: 200
83461
84044
  } }
83462
84045
  },
83463
84046
  {
@@ -84071,7 +84654,7 @@ var ACTUATOR_CAP_VOCABULARY = {
84071
84654
  label: t("Fan off", "Ventilatore spento"),
84072
84655
  phrase: t("Stop {device}", "Ferma {device}"),
84073
84656
  icon: "power-off",
84074
- args: { percentage: 0 }
84657
+ args: { speed: 0 }
84075
84658
  },
84076
84659
  {
84077
84660
  id: "fan.full",
@@ -84079,16 +84662,16 @@ var ACTUATOR_CAP_VOCABULARY = {
84079
84662
  label: t("Fan full", "Ventilatore al massimo"),
84080
84663
  phrase: t("Run {device} at full speed", "Porta {device} alla massima velocità"),
84081
84664
  icon: "fan",
84082
- args: { percentage: 100 }
84665
+ args: { speed: 100 }
84083
84666
  },
84084
84667
  {
84085
84668
  id: "fan.speed",
84086
84669
  method: "setPercentage",
84087
84670
  label: t("Set speed", "Imposta la velocità"),
84088
- phrase: t("Set the speed of {device} to {percentage}", "Imposta la velocità di {device} al {percentage}"),
84671
+ phrase: t("Set the speed of {device} to {speed}", "Imposta la velocità di {device} al {speed}"),
84089
84672
  icon: "fan",
84090
84673
  openArgs: [{
84091
- key: "percentage",
84674
+ key: "speed",
84092
84675
  label: t("Speed", "Velocità"),
84093
84676
  offer: {
84094
84677
  kind: "number",
@@ -84150,7 +84733,7 @@ var ACTUATOR_CAP_VOCABULARY = {
84150
84733
  ],
84151
84734
  state: [{
84152
84735
  kind: "numeric",
84153
- field: "percentage",
84736
+ field: "speed",
84154
84737
  quantity: t("the speed", "la velocità"),
84155
84738
  label: t("Speed", "Velocità"),
84156
84739
  unit: "%",
@@ -84948,7 +85531,7 @@ var APPLIANCE_CAP_VOCABULARY = {
84948
85531
  },
84949
85532
  {
84950
85533
  kind: "numeric",
84951
- field: "progressPercent",
85534
+ field: "progress",
84952
85535
  quantity: t("the cycle progress", "l’avanzamento del lavaggio"),
84953
85536
  label: t("Progress", "Avanzamento"),
84954
85537
  unit: "%",
@@ -85306,10 +85889,10 @@ var APPLIANCE_CAP_VOCABULARY = {
85306
85889
  id: "media.seek",
85307
85890
  method: "seek",
85308
85891
  label: t("Seek", "Vai al punto"),
85309
- phrase: t("Move {device} to {positionMs}", "Porta {device} al punto {positionMs}"),
85892
+ phrase: t("Move {device} to {position}", "Porta {device} al punto {position}"),
85310
85893
  icon: "fast-forward",
85311
85894
  openArgs: [{
85312
- key: "positionMs",
85895
+ key: "position",
85313
85896
  label: t("Position", "Posizione"),
85314
85897
  offer: {
85315
85898
  kind: "number",
@@ -86358,7 +86941,7 @@ var SENSOR_CAP_VOCABULARY = {
86358
86941
  state: [
86359
86942
  {
86360
86943
  kind: "numeric",
86361
- field: "co2Ppm",
86944
+ field: "co2",
86362
86945
  quantity: t("the CO₂", "la CO₂"),
86363
86946
  label: t("CO₂", "CO₂"),
86364
86947
  unit: "ppm",
@@ -86366,7 +86949,7 @@ var SENSOR_CAP_VOCABULARY = {
86366
86949
  },
86367
86950
  {
86368
86951
  kind: "numeric",
86369
- field: "vocPpb",
86952
+ field: "voc",
86370
86953
  quantity: t("the VOC level", "il livello di COV"),
86371
86954
  label: t("VOC", "COV"),
86372
86955
  unit: "ppb",
@@ -86402,7 +86985,7 @@ var SENSOR_CAP_VOCABULARY = {
86402
86985
  noun: t("Light level", "Luminosità ambiente"),
86403
86986
  state: [{
86404
86987
  kind: "numeric",
86405
- field: "lux",
86988
+ field: "illuminance",
86406
86989
  quantity: t("the light level", "la luminosità"),
86407
86990
  label: t("Illuminance", "Illuminamento"),
86408
86991
  unit: "lx",
@@ -86605,7 +87188,7 @@ var SENSOR_CAP_VOCABULARY = {
86605
87188
  noun: t("Humidity", "Umidità"),
86606
87189
  state: [{
86607
87190
  kind: "numeric",
86608
- field: "percent",
87191
+ field: "humidity",
86609
87192
  quantity: t("the humidity", "l’umidità"),
86610
87193
  label: t("Humidity", "Umidità"),
86611
87194
  unit: "%",
@@ -86653,7 +87236,7 @@ var SENSOR_CAP_VOCABULARY = {
86653
87236
  state: [
86654
87237
  {
86655
87238
  kind: "numeric",
86656
- field: "watts",
87239
+ field: "power",
86657
87240
  quantity: t("the power draw", "il consumo"),
86658
87241
  label: t("Power", "Potenza"),
86659
87242
  unit: "W",
@@ -86661,7 +87244,7 @@ var SENSOR_CAP_VOCABULARY = {
86661
87244
  },
86662
87245
  {
86663
87246
  kind: "numeric",
86664
- field: "kwhTotal",
87247
+ field: "energy",
86665
87248
  quantity: t("the energy used", "l’energia consumata"),
86666
87249
  label: t("Energy", "Energia"),
86667
87250
  unit: "kWh",
@@ -86669,7 +87252,7 @@ var SENSOR_CAP_VOCABULARY = {
86669
87252
  },
86670
87253
  {
86671
87254
  kind: "numeric",
86672
- field: "volts",
87255
+ field: "voltage",
86673
87256
  quantity: t("the voltage", "la tensione"),
86674
87257
  label: t("Voltage", "Tensione"),
86675
87258
  unit: "V",
@@ -86677,7 +87260,7 @@ var SENSOR_CAP_VOCABULARY = {
86677
87260
  },
86678
87261
  {
86679
87262
  kind: "numeric",
86680
- field: "amps",
87263
+ field: "current",
86681
87264
  quantity: t("the current", "la corrente"),
86682
87265
  label: t("Current", "Corrente"),
86683
87266
  unit: "A",
@@ -86694,13 +87277,6 @@ var SENSOR_CAP_VOCABULARY = {
86694
87277
  label: t("Where", "Posizione"),
86695
87278
  phrase: t("When {device} is at {value}", "Quando {device} è in {value}"),
86696
87279
  icon: "map-pin"
86697
- }, {
86698
- kind: "numeric",
86699
- field: "batteryPercent",
86700
- quantity: t("the phone battery", "la batteria del telefono"),
86701
- label: t("Battery", "Batteria"),
86702
- unit: "%",
86703
- icon: "battery"
86704
87280
  }]
86705
87281
  },
86706
87282
  "pressure-sensor": {
@@ -86708,7 +87284,7 @@ var SENSOR_CAP_VOCABULARY = {
86708
87284
  noun: t("Pressure", "Pressione"),
86709
87285
  state: [{
86710
87286
  kind: "numeric",
86711
- field: "hpa",
87287
+ field: "pressure",
86712
87288
  quantity: t("the pressure", "la pressione"),
86713
87289
  label: t("Pressure", "Pressione"),
86714
87290
  unit: "hPa",
@@ -86744,7 +87320,7 @@ var SENSOR_CAP_VOCABULARY = {
86744
87320
  noun: t("Temperature", "Temperatura"),
86745
87321
  state: [{
86746
87322
  kind: "numeric",
86747
- field: "celsius",
87323
+ field: "temperature",
86748
87324
  quantity: t("the temperature", "la temperatura"),
86749
87325
  label: t("Temperature", "Temperatura"),
86750
87326
  unit: "°C",
@@ -86815,7 +87391,7 @@ var SENSOR_CAP_VOCABULARY = {
86815
87391
  state: [
86816
87392
  {
86817
87393
  kind: "numeric",
86818
- field: "percentage",
87394
+ field: "level",
86819
87395
  quantity: t("the battery level", "il livello della batteria"),
86820
87396
  label: t("Battery", "Batteria"),
86821
87397
  unit: "%",
@@ -86857,7 +87433,7 @@ var SENSOR_CAP_VOCABULARY = {
86857
87433
  icon: "battery-charging"
86858
87434
  }
86859
87435
  ],
86860
- events: { onStatusChanged: { notOperatorFacing: "the percentage / sleeping / charging state triggers each read one field of this change" } },
87436
+ events: { onStatusChanged: { notOperatorFacing: "the level / sleeping / charging state triggers each read one field of this change" } },
86861
87437
  extraEvents: [{
86862
87438
  category: EventCategory.DeviceAwake,
86863
87439
  label: t("Woke up", "Risvegliato"),
@@ -86875,7 +87451,7 @@ var SENSOR_CAP_VOCABULARY = {
86875
87451
  noun: t("Network link", "Collegamento di rete"),
86876
87452
  state: [{
86877
87453
  kind: "numeric",
86878
- field: "signalPercent",
87454
+ field: "signal",
86879
87455
  quantity: t("the signal strength", "l’intensità del segnale"),
86880
87456
  label: t("Signal", "Segnale"),
86881
87457
  unit: "%",
@@ -86968,6 +87544,8 @@ var ML = "model and training machinery — no device action";
86968
87544
  var INTERNAL = "internal plumbing between addons — never operator-facing";
86969
87545
  /** Every system-scoped cap, with why it is not a device's vocabulary. */
86970
87546
  var SYSTEM_CAP_VOCABULARY = {
87547
+ "action-source": system(INTERNAL),
87548
+ actions: system("declared actions — run from the Actions page and from the cameras that link them"),
86971
87549
  "addon-pages": system(UI_PLUMBING),
86972
87550
  "addon-pages-source": system(UI_PLUMBING),
86973
87551
  "addon-routes": system(UI_PLUMBING),
@@ -87316,6 +87894,31 @@ Object.freeze({
87316
87894
  form: "single",
87317
87895
  optional: false
87318
87896
  }],
87897
+ "actions.get": [{
87898
+ name: "deviceId",
87899
+ form: "single",
87900
+ optional: true
87901
+ }],
87902
+ "actions.getLinks": [{
87903
+ name: "deviceId",
87904
+ form: "single",
87905
+ optional: false
87906
+ }],
87907
+ "actions.listForCamera": [{
87908
+ name: "deviceId",
87909
+ form: "single",
87910
+ optional: false
87911
+ }],
87912
+ "actions.run": [{
87913
+ name: "deviceId",
87914
+ form: "single",
87915
+ optional: true
87916
+ }],
87917
+ "actions.setLinks": [{
87918
+ name: "deviceId",
87919
+ form: "single",
87920
+ optional: false
87921
+ }],
87319
87922
  "addonSettings.getDeviceSettings": [{
87320
87923
  name: "deviceId",
87321
87924
  form: "single",
@@ -91448,6 +92051,7 @@ DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
91448
92051
  DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
91449
92052
  DEFAULT_NATIVE_LEASE_SETTINGS.sceneBudgetMb;
91450
92053
  DEFAULT_NATIVE_LEASE_SETTINGS.admission;
92054
+ String.raw`(?<=^|["'(\s>,\[{])`;
91451
92055
  var MB = 1024 * 1024;
91452
92056
  1024 * MB, 3072 * MB;
91453
92057
  //#endregion
@@ -200817,7 +201421,7 @@ var FloodlightAccessory = class extends BaseDevice {
200817
201421
  lastChangedAt: ts
200818
201422
  });
200819
201423
  if (brightness !== void 0) this.setCapSlice(brightnessCapability, {
200820
- percentage: brightness,
201424
+ level: brightness,
200821
201425
  lastChangedAt: ts
200822
201426
  });
200823
201427
  this.hasFetchedFromFirmware = true;
@@ -200936,7 +201540,7 @@ var FloodlightAccessory = class extends BaseDevice {
200936
201540
  }
200937
201541
  brightnessView() {
200938
201542
  return this.getCapSlice(brightnessCapability) ?? {
200939
- percentage: 100,
201543
+ level: 100,
200940
201544
  lastChangedAt: 0
200941
201545
  };
200942
201546
  }
@@ -200961,19 +201565,19 @@ var FloodlightAccessory = class extends BaseDevice {
200961
201565
  registerBrightnessCap() {
200962
201566
  this.ctx.registerNativeCap(brightnessCapability, {
200963
201567
  getStatus: async () => this.brightnessView(),
200964
- setBrightness: async ({ deviceId, percentage }) => {
201568
+ setBrightness: async ({ deviceId, level: percentage }) => {
200965
201569
  if (deviceId !== this.id) return;
200966
201570
  const value = Math.max(0, Math.min(100, percentage));
200967
201571
  if (this.switchView().on) await (await this.api).setWhiteLedState(this.channel, void 0, value);
200968
201572
  this.setCapSlice(brightnessCapability, {
200969
- percentage: value,
201573
+ level: value,
200970
201574
  lastChangedAt: Date.now()
200971
201575
  });
200972
201576
  this.lastSetAtMs = Date.now();
200973
201577
  }
200974
201578
  });
200975
201579
  this.setCapSlice(brightnessCapability, {
200976
- percentage: 100,
201580
+ level: 100,
200977
201581
  lastChangedAt: 0
200978
201582
  });
200979
201583
  }
@@ -201649,13 +202253,13 @@ function mapNetworkReadout(readout, now) {
201649
202253
  const type = linkTypeOf(readout);
201650
202254
  const raw = readout.wifiSignal;
201651
202255
  const wireless = type === "wifi" || type === "cellular";
201652
- const signalPercent = wireless ? signalPercentOf(raw) : null;
202256
+ const signal = wireless ? signalPercentOf(raw) : null;
201653
202257
  const rssiDbm = wireless && raw !== void 0 && Number.isFinite(raw) && raw < 0 ? raw : void 0;
201654
202258
  const ssid = wireless && readout.ssid !== void 0 && readout.ssid !== "" ? readout.ssid : void 0;
201655
202259
  return {
201656
202260
  type,
201657
- signalPercent,
201658
- ...rssiDbm !== void 0 ? { rssiDbm } : {},
202261
+ signal,
202262
+ ...rssiDbm !== void 0 ? { rssi: rssiDbm } : {},
201659
202263
  ...ssid !== void 0 ? { ssid } : {},
201660
202264
  lastUpdated: now
201661
202265
  };
@@ -204898,7 +205502,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
204898
205502
  */
204899
205503
  mapBatteryInfo(info) {
204900
205504
  return {
204901
- percentage: typeof info.batteryPercent === "number" ? Math.max(0, Math.min(100, Math.round(info.batteryPercent))) : this.state.battery.percentage ?? null,
205505
+ level: typeof info.batteryPercent === "number" ? Math.max(0, Math.min(100, Math.round(info.batteryPercent))) : this.state.battery.level ?? null,
204902
205506
  charging: reportsPowerSource(info) ? deriveChargingSource(info.adapterStatus, info.chargeStatus) : this.state.battery.charging ?? "unknown",
204903
205507
  sleeping: info.sleeping === true || this.sleeping,
204904
205508
  lastUpdated: Date.now()
@@ -205034,7 +205638,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
205034
205638
  }
205035
205639
  });
205036
205640
  if (this.getCapSlice(batteryCapability) === null) this.setCapSlice(batteryCapability, {
205037
- percentage: null,
205641
+ level: null,
205038
205642
  charging: "none",
205039
205643
  sleeping: false,
205040
205644
  lastUpdated: Date.now()
@@ -205262,7 +205866,7 @@ var ReolinkCamera = class ReolinkCamera extends BaseDevice {
205262
205866
  });
205263
205867
  this.setCapSlice(batteryCapability, {
205264
205868
  ...this.state.battery,
205265
- percentage: mapped.percentage,
205869
+ level: mapped.level,
205266
205870
  charging: mapped.charging,
205267
205871
  lastUpdated: Date.now()
205268
205872
  });