@camstack/addon-provider-homematic 1.2.160 → 1.2.162

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
@@ -9,7 +9,7 @@ import { join } from "path";
9
9
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
10
10
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
11
11
  //#endregion
12
- //#region ../types/dist/event-category-CT-hz5Rb.mjs
12
+ //#region ../types/dist/event-category-DmZDPDf_.mjs
13
13
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
14
14
  EventCategory["SystemBoot"] = "system.boot";
15
15
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -636,7 +636,7 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
636
636
  * (a track was promoted to a stationary-registry entry) or departs (the
637
637
  * object moved / was removed). Telemetry (D8): lossy, drives a UI refresh of
638
638
  * the dedicated "Stationary" section — never the live event feed. Payload:
639
- * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp }`.
639
+ * `{ deviceId, entryId, className, phase:'appeared'|'departed', timestamp, observedAt, zones }`.
640
640
  */
641
641
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
642
642
  /**
@@ -774,6 +774,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
774
774
  */
775
775
  EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
776
776
  /**
777
+ * An action run started or ended. Emitted by the `actions` surface.
778
+ * Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
779
+ */
780
+ EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
781
+ /**
777
782
  * Progress update from a running model conversion job.
778
783
  * Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
779
784
  * Emitted by `addon-model-studio` on the converting node.
@@ -5585,7 +5590,7 @@ var ZodIssueCode = {
5585
5590
  var ZodFirstPartyTypeKind;
5586
5591
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5587
5592
  //#endregion
5588
- //#region ../types/dist/sleep--jXS9hWo.mjs
5593
+ //#region ../types/dist/sleep-C_u6cEAJ.mjs
5589
5594
  /**
5590
5595
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5591
5596
  * window to float samples (D455).
@@ -8893,6 +8898,8 @@ Object.freeze({ "doorbell": "lastPressedAt" });
8893
8898
  /** Every capability name, so addon code can check a name without the schema graph. */
8894
8899
  var CAP_NAMES = Object.freeze([
8895
8900
  "accessories",
8901
+ "action-source",
8902
+ "actions",
8896
8903
  "addon-pages",
8897
8904
  "addon-pages-source",
8898
8905
  "addon-routes",
@@ -8976,6 +8983,7 @@ var CAP_NAMES = Object.freeze([
8976
8983
  "image-settings",
8977
8984
  "integrations",
8978
8985
  "intercom",
8986
+ "ir-transmitter",
8979
8987
  "keychain",
8980
8988
  "keychain-admin",
8981
8989
  "lawn-mower-control",
@@ -9004,6 +9012,7 @@ var CAP_NAMES = Object.freeze([
9004
9012
  "network-link",
9005
9013
  "network-quality",
9006
9014
  "node-certificates",
9015
+ "node-removal-hook",
9007
9016
  "nodes",
9008
9017
  "notification-output",
9009
9018
  "notification-rules",
@@ -9034,6 +9043,7 @@ var CAP_NAMES = Object.freeze([
9034
9043
  "recording-onboard",
9035
9044
  "recording-signal",
9036
9045
  "records",
9046
+ "remote",
9037
9047
  "running-state",
9038
9048
  "scene-monitor",
9039
9049
  "script-runner",
@@ -9057,6 +9067,7 @@ var CAP_NAMES = Object.freeze([
9057
9067
  "system",
9058
9068
  "tamper",
9059
9069
  "temperature-sensor",
9070
+ "template",
9060
9071
  "terminal-session",
9061
9072
  "toast",
9062
9073
  "training",
@@ -9081,11 +9092,11 @@ var CAP_NAMES = Object.freeze([
9081
9092
  Object.freeze({
9082
9093
  "air-quality-sensor": [
9083
9094
  {
9084
- "path": "co2Ppm",
9095
+ "path": "co2",
9085
9096
  "valueType": "number"
9086
9097
  },
9087
9098
  {
9088
- "path": "vocPpb",
9099
+ "path": "voc",
9089
9100
  "valueType": "number"
9090
9101
  },
9091
9102
  {
@@ -9135,7 +9146,7 @@ Object.freeze({
9135
9146
  }
9136
9147
  ],
9137
9148
  "ambient-light-sensor": [{
9138
- "path": "lux",
9149
+ "path": "illuminance",
9139
9150
  "valueType": "number"
9140
9151
  }],
9141
9152
  "audio-metrics": [
@@ -9196,7 +9207,7 @@ Object.freeze({
9196
9207
  ],
9197
9208
  "battery": [
9198
9209
  {
9199
- "path": "percentage",
9210
+ "path": "level",
9200
9211
  "valueType": "number"
9201
9212
  },
9202
9213
  {
@@ -9218,7 +9229,7 @@ Object.freeze({
9218
9229
  "valueType": "number"
9219
9230
  },
9220
9231
  {
9221
- "path": "volts",
9232
+ "path": "voltage",
9222
9233
  "valueType": "number"
9223
9234
  },
9224
9235
  {
@@ -9239,7 +9250,7 @@ Object.freeze({
9239
9250
  "valueType": "boolean"
9240
9251
  }],
9241
9252
  "brightness": [{
9242
- "path": "percentage",
9253
+ "path": "level",
9243
9254
  "valueType": "number"
9244
9255
  }],
9245
9256
  "broker": [{
@@ -9440,7 +9451,7 @@ Object.freeze({
9440
9451
  "valueType": "number"
9441
9452
  },
9442
9453
  {
9443
- "path": "mireds",
9454
+ "path": "colorTemperature",
9444
9455
  "valueType": "number"
9445
9456
  }
9446
9457
  ],
@@ -9619,15 +9630,15 @@ Object.freeze({
9619
9630
  "valueType": "string"
9620
9631
  },
9621
9632
  {
9622
- "path": "remainingSeconds",
9633
+ "path": "remaining",
9623
9634
  "valueType": "number"
9624
9635
  },
9625
9636
  {
9626
- "path": "delayedStartSeconds",
9637
+ "path": "delayedStart",
9627
9638
  "valueType": "number"
9628
9639
  },
9629
9640
  {
9630
- "path": "progressPercent",
9641
+ "path": "progress",
9631
9642
  "valueType": "number"
9632
9643
  },
9633
9644
  {
@@ -9741,7 +9752,7 @@ Object.freeze({
9741
9752
  ],
9742
9753
  "fan-control": [
9743
9754
  {
9744
- "path": "percentage",
9755
+ "path": "speed",
9745
9756
  "valueType": "number"
9746
9757
  },
9747
9758
  {
@@ -9841,7 +9852,7 @@ Object.freeze({
9841
9852
  }
9842
9853
  ],
9843
9854
  "humidity-sensor": [{
9844
- "path": "percent",
9855
+ "path": "humidity",
9845
9856
  "valueType": "number"
9846
9857
  }],
9847
9858
  "image": [{
@@ -9951,7 +9962,7 @@ Object.freeze({
9951
9962
  "valueType": "number"
9952
9963
  },
9953
9964
  {
9954
- "path": "progressPercent",
9965
+ "path": "progress",
9955
9966
  "valueType": "number"
9956
9967
  },
9957
9968
  {
@@ -9997,6 +10008,11 @@ Object.freeze({
9997
10008
  "standby"
9998
10009
  ]
9999
10010
  },
10011
+ {
10012
+ "path": "stateSource",
10013
+ "valueType": "enum",
10014
+ "enumValues": ["reported", "assumed"]
10015
+ },
10000
10016
  {
10001
10017
  "path": "volumeLevel",
10002
10018
  "valueType": "number"
@@ -10030,11 +10046,11 @@ Object.freeze({
10030
10046
  "valueType": "string"
10031
10047
  },
10032
10048
  {
10033
- "path": "positionMs",
10049
+ "path": "position",
10034
10050
  "valueType": "number"
10035
10051
  },
10036
10052
  {
10037
- "path": "durationMs",
10053
+ "path": "duration",
10038
10054
  "valueType": "number"
10039
10055
  },
10040
10056
  {
@@ -10136,11 +10152,11 @@ Object.freeze({
10136
10152
  ]
10137
10153
  },
10138
10154
  {
10139
- "path": "signalPercent",
10155
+ "path": "signal",
10140
10156
  "valueType": "number"
10141
10157
  },
10142
10158
  {
10143
- "path": "rssiDbm",
10159
+ "path": "rssi",
10144
10160
  "valueType": "number"
10145
10161
  },
10146
10162
  {
@@ -10195,6 +10211,18 @@ Object.freeze({
10195
10211
  "path": "foodLevel",
10196
10212
  "valueType": "number"
10197
10213
  },
10214
+ {
10215
+ "path": "bowlFood",
10216
+ "valueType": "number"
10217
+ },
10218
+ {
10219
+ "path": "eating",
10220
+ "valueType": "boolean"
10221
+ },
10222
+ {
10223
+ "path": "supportsMarkRefilled",
10224
+ "valueType": "boolean"
10225
+ },
10198
10226
  {
10199
10227
  "path": "food1",
10200
10228
  "valueType": "number"
@@ -10211,6 +10239,11 @@ Object.freeze({
10211
10239
  "path": "batteryPower",
10212
10240
  "valueType": "number"
10213
10241
  },
10242
+ {
10243
+ "path": "powerSource",
10244
+ "valueType": "enum",
10245
+ "enumValues": ["mains", "battery"]
10246
+ },
10214
10247
  {
10215
10248
  "path": "desiccantLeftDays",
10216
10249
  "valueType": "number"
@@ -10255,27 +10288,39 @@ Object.freeze({
10255
10288
  {
10256
10289
  "path": "volume",
10257
10290
  "valueType": "number"
10291
+ },
10292
+ {
10293
+ "path": "lastFeedGrams",
10294
+ "valueType": "number"
10295
+ },
10296
+ {
10297
+ "path": "lastFeedHopper1",
10298
+ "valueType": "number"
10299
+ },
10300
+ {
10301
+ "path": "lastFeedHopper2",
10302
+ "valueType": "number"
10258
10303
  }
10259
10304
  ],
10260
10305
  "power-meter": [
10261
10306
  {
10262
- "path": "watts",
10307
+ "path": "power",
10263
10308
  "valueType": "number"
10264
10309
  },
10265
10310
  {
10266
- "path": "kwhTotal",
10311
+ "path": "energy",
10267
10312
  "valueType": "number"
10268
10313
  },
10269
10314
  {
10270
- "path": "volts",
10315
+ "path": "voltage",
10271
10316
  "valueType": "number"
10272
10317
  },
10273
10318
  {
10274
- "path": "amps",
10319
+ "path": "current",
10275
10320
  "valueType": "number"
10276
10321
  },
10277
10322
  {
10278
- "path": "va",
10323
+ "path": "apparentPower",
10279
10324
  "valueType": "number"
10280
10325
  },
10281
10326
  {
@@ -10303,14 +10348,10 @@ Object.freeze({
10303
10348
  {
10304
10349
  "path": "gps.accuracyMeters",
10305
10350
  "valueType": "number"
10306
- },
10307
- {
10308
- "path": "batteryPercent",
10309
- "valueType": "number"
10310
10351
  }
10311
10352
  ],
10312
10353
  "pressure-sensor": [{
10313
- "path": "hpa",
10354
+ "path": "pressure",
10314
10355
  "valueType": "number"
10315
10356
  }],
10316
10357
  "privacy-mask": [{
@@ -10624,7 +10665,7 @@ Object.freeze({
10624
10665
  "valueType": "boolean"
10625
10666
  }],
10626
10667
  "temperature-sensor": [{
10627
- "path": "celsius",
10668
+ "path": "temperature",
10628
10669
  "valueType": "number"
10629
10670
  }],
10630
10671
  "update": [
@@ -10672,7 +10713,7 @@ Object.freeze({
10672
10713
  "valueType": "string"
10673
10714
  },
10674
10715
  {
10675
- "path": "progressPercent",
10716
+ "path": "progress",
10676
10717
  "valueType": "number"
10677
10718
  },
10678
10719
  {
@@ -10798,7 +10839,7 @@ object({
10798
10839
  params: record(string(), union([string(), number()])).optional()
10799
10840
  });
10800
10841
  //#endregion
10801
- //#region ../types/dist/err-msg-DIorGYeC.mjs
10842
+ //#region ../types/dist/err-msg-BCdlR2Li.mjs
10802
10843
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
10803
10844
  DeviceType["Camera"] = "camera";
10804
10845
  DeviceType["Hub"] = "hub";
@@ -11144,6 +11185,9 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
11144
11185
  /** Fallback when the notifier service name doesn't match a known
11145
11186
  * pattern. */
11146
11187
  DeviceRole["GenericNotifier"] = "generic-notifier";
11188
+ /** Emits a pulse train (infrared or RF) on request — the `ir-transmitter`
11189
+ * cap. A `DeviceType.Generic` device. */
11190
+ DeviceRole["IrTransmitter"] = "ir-transmitter";
11147
11191
  return DeviceRole;
11148
11192
  }({});
11149
11193
  /**
@@ -11157,7 +11201,7 @@ function errMsg(err) {
11157
11201
  return String(err);
11158
11202
  }
11159
11203
  //#endregion
11160
- //#region ../types/dist/composition-Bb8iwHEJ.mjs
11204
+ //#region ../types/dist/composition-bIBW5_13.mjs
11161
11205
  /**
11162
11206
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11163
11207
  *
@@ -15677,6 +15721,14 @@ var AutomationConditionLeafSchema = object({
15677
15721
  array(union([string(), number()]))
15678
15722
  ])
15679
15723
  });
15724
+ var AutomationConditionStationaryPresentSchema = object({
15725
+ kind: literal("stationary-present"),
15726
+ deviceId: number().int().nonnegative(),
15727
+ /** Class names; a macro class matches every raw class that maps to it. */
15728
+ classes: array(string().min(1)).min(1).optional(),
15729
+ /** The parked object must be in at least one of these zones. */
15730
+ zones: array(string().min(1)).min(1).optional()
15731
+ });
15680
15732
  /**
15681
15733
  * The expression leaf, declared as a plain object rather than an intersection
15682
15734
  * with {@link ExpressionSourceSchema}: a discriminated union has to be able to
@@ -15710,7 +15762,8 @@ var AutomationConditionSchema = lazy(() => discriminatedUnion("kind", [
15710
15762
  child: AutomationConditionSchema
15711
15763
  }),
15712
15764
  AutomationConditionLeafSchema,
15713
- AutomationConditionExpressionSchema
15765
+ AutomationConditionExpressionSchema,
15766
+ AutomationConditionStationaryPresentSchema
15714
15767
  ]));
15715
15768
  /**
15716
15769
  * What starts a run.
@@ -15751,7 +15804,34 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
15751
15804
  kind: literal("schedule"),
15752
15805
  cron: string().min(1).max(120)
15753
15806
  }),
15754
- object({ kind: literal("manual") })
15807
+ object({ kind: literal("manual") }),
15808
+ object({
15809
+ kind: literal("detection"),
15810
+ /** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
15811
+ * matches every raw class that maps to it; any other name matches
15812
+ * exactly. */
15813
+ classes: array(string().min(1)).min(1),
15814
+ deviceIds: array(number().int().nonnegative()).min(1),
15815
+ /** The track must have visited at least one of these zones. */
15816
+ zones: array(string().min(1)).min(1).optional(),
15817
+ /** Best-so-far confidence the track must reach. */
15818
+ minScore: number().min(0).max(1).optional()
15819
+ }),
15820
+ object({
15821
+ kind: literal("stationary"),
15822
+ deviceIds: array(number().int().nonnegative()).min(1),
15823
+ /** Class names; a macro class matches like the detection trigger. */
15824
+ classes: array(string().min(1)).min(1).optional(),
15825
+ /** The parked object must be in at least one of these zones. */
15826
+ zones: array(string().min(1)).min(1).optional(),
15827
+ /** `appeared`: it became parked. `departed`: the registry retired it.
15828
+ * The vocabulary of `PipelineAnalyticsStationaryChanged`. */
15829
+ phase: _enum(["appeared", "departed"])
15830
+ }),
15831
+ object({
15832
+ kind: literal("interval"),
15833
+ minutes: number().int().min(1).max(1440)
15834
+ })
15755
15835
  ]);
15756
15836
  /**
15757
15837
  * One action step.
@@ -15771,28 +15851,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
15771
15851
  * is called. The runner still receives a number and is untouched; the
15772
15852
  * resolution is the recipe's job, not the runner's.
15773
15853
  */
15854
+ var AutomationWaitStepSchema = object({
15855
+ kind: literal("wait"),
15856
+ seconds: number().min(0).max(300)
15857
+ });
15858
+ var AutomationCapStepSchema = object({
15859
+ kind: literal("cap"),
15860
+ /**
15861
+ * One device, several same-family devices (locks / climate family / …),
15862
+ * or `{ $var }` for the device that triggered the run. An array is
15863
+ * fan-out at codegen — each id gets the same cap.method call.
15864
+ */
15865
+ deviceId: union([
15866
+ number().int(),
15867
+ array(number().int()).min(1),
15868
+ object({ $var: string().min(1) })
15869
+ ]),
15870
+ cap: string().min(1),
15871
+ method: string().min(1),
15872
+ /** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
15873
+ * SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
15874
+ * the expression leaf. */
15875
+ args: record(string(), unknown()).optional()
15876
+ });
15877
+ /**
15878
+ * The steps an internal Action may contain: cap and wait, and nothing that can
15879
+ * call back into an Action — so an Action can never reach itself (no cycles).
15880
+ */
15881
+ var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
15774
15882
  var AutomationActionSchema = discriminatedUnion("kind", [
15883
+ AutomationWaitStepSchema,
15884
+ AutomationCapStepSchema,
15775
15885
  object({
15776
- kind: literal("wait"),
15777
- seconds: number().min(0).max(300)
15778
- }),
15779
- object({
15780
- kind: literal("cap"),
15781
- /**
15782
- * One device, several same-family devices (locks / climate family / …),
15783
- * or `{ $var }` for the device that triggered the run. An array is
15784
- * fan-out at codegen — each id gets the same cap.method call.
15785
- */
15786
- deviceId: union([
15787
- number().int(),
15788
- array(number().int()).min(1),
15789
- object({ $var: string().min(1) })
15790
- ]),
15791
- cap: string().min(1),
15792
- method: string().min(1),
15793
- /** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
15794
- * evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
15795
- args: record(string(), unknown()).optional()
15886
+ kind: literal("action"),
15887
+ /** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
15888
+ actionId: string().min(1),
15889
+ /** Values for the action's declared variables; the others take their default. */
15890
+ variables: record(string(), union([
15891
+ string(),
15892
+ number(),
15893
+ boolean()
15894
+ ])).optional()
15796
15895
  }),
15797
15896
  object({
15798
15897
  kind: literal("code"),
@@ -15801,10 +15900,357 @@ var AutomationActionSchema = discriminatedUnion("kind", [
15801
15900
  code: string().min(1).max(2e4)
15802
15901
  })
15803
15902
  ]);
15903
+ /**
15904
+ * How a trigger that arrives while the automation is busy (or cooling down) is
15905
+ * handled. One of the automation's execution modes, never a property of its
15906
+ * actions. Absent means `single`.
15907
+ *
15908
+ * - `single` — drop the trigger while a run is in progress (traced + logged).
15909
+ * - `restart` — abort the run in progress (at its next step boundary), start fresh.
15910
+ * - `queued` — queue up to `max` triggers, drop the rest (traced).
15911
+ * - `parallel` — up to `max` runs at once, drop the rest (traced).
15912
+ * - `cooldown` — `single`, and no new run until `minutes` after the last run
15913
+ * STARTED; persisted across a restart. A manual trigger bypasses only this
15914
+ * wait, never the single/queued limits.
15915
+ */
15916
+ var AutomationRunModeSchema = discriminatedUnion("mode", [
15917
+ object({ mode: literal("single") }),
15918
+ object({ mode: literal("restart") }),
15919
+ object({
15920
+ mode: literal("queued"),
15921
+ max: number().int().min(1).max(10)
15922
+ }),
15923
+ object({
15924
+ mode: literal("parallel"),
15925
+ max: number().int().min(1).max(10)
15926
+ }),
15927
+ object({
15928
+ mode: literal("cooldown"),
15929
+ minutes: number().int().min(1).max(1440)
15930
+ })
15931
+ ]);
15804
15932
  var AutomationRecipeSchema = object({
15805
15933
  triggers: array(AutomationTriggerSchema),
15806
15934
  conditions: AutomationConditionSchema.optional(),
15807
- actions: array(AutomationActionSchema)
15935
+ actions: array(AutomationActionSchema),
15936
+ runMode: AutomationRunModeSchema.optional(),
15937
+ /** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
15938
+ keepTraces: number().int().min(1).max(100).optional()
15939
+ });
15940
+ new Set([
15941
+ {
15942
+ id: "person",
15943
+ name: "Person"
15944
+ },
15945
+ {
15946
+ id: "vehicle",
15947
+ name: "Vehicle"
15948
+ },
15949
+ {
15950
+ id: "animal",
15951
+ name: "Animal"
15952
+ },
15953
+ {
15954
+ id: "package",
15955
+ name: "Package"
15956
+ }
15957
+ ].map((l) => l.id));
15958
+ var COCO_TO_MACRO = {
15959
+ mapping: {
15960
+ person: "person",
15961
+ bicycle: "vehicle",
15962
+ car: "vehicle",
15963
+ motorcycle: "vehicle",
15964
+ airplane: "vehicle",
15965
+ bus: "vehicle",
15966
+ train: "vehicle",
15967
+ truck: "vehicle",
15968
+ boat: "vehicle",
15969
+ bird: "animal",
15970
+ cat: "animal",
15971
+ dog: "animal",
15972
+ horse: "animal",
15973
+ sheep: "animal",
15974
+ cow: "animal",
15975
+ elephant: "animal",
15976
+ bear: "animal",
15977
+ zebra: "animal",
15978
+ giraffe: "animal",
15979
+ suitcase: "package",
15980
+ backpack: "package",
15981
+ handbag: "package"
15982
+ },
15983
+ preserveOriginal: false
15984
+ };
15985
+ new Set(Object.values(COCO_TO_MACRO.mapping));
15986
+ /**
15987
+ * Run traces — what an automation (or, later, an Action run) DID, node by node,
15988
+ * so the editor can paint every block green or red with its reason.
15989
+ *
15990
+ * A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
15991
+ * every condition node (containers and leaves, including the ones a
15992
+ * short-circuit never reached), the run-mode verdict and every action step —
15993
+ * each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
15994
+ * for an Action run). Skipped
15995
+ * evaluations are traced too, and identical consecutive skips collapse into a
15996
+ * repeat count so a trigger that fails every 5 minutes cannot flush real runs.
15997
+ *
15998
+ * {@link AutomationStepTraceSchema} is deliberately free of automation
15999
+ * vocabulary so an Action run records the same step shape.
16000
+ */
16001
+ /** A value a trace may show: JSON primitives and short lists, nothing deeper. */
16002
+ var TraceValueSchema = union([
16003
+ string(),
16004
+ number(),
16005
+ boolean(),
16006
+ _null(),
16007
+ array(union([string(), number()]))
16008
+ ]);
16009
+ var AutomationRunOutcomeSchema = _enum([
16010
+ "ran",
16011
+ "skipped-trigger",
16012
+ "skipped-conditions",
16013
+ "skipped-cooldown",
16014
+ "skipped-overlap",
16015
+ "failed",
16016
+ "aborted"
16017
+ ]);
16018
+ /** `not-evaluated` = a short-circuit never reached the node. */
16019
+ var TraceNodeOutcomeSchema = _enum([
16020
+ "pass",
16021
+ "fail",
16022
+ "not-evaluated"
16023
+ ]);
16024
+ var AutomationTriggerTraceSchema = object({
16025
+ kind: string().min(1),
16026
+ outcome: _enum(["pass", "fail"]),
16027
+ /** Why an event was rejected ("class person not in [dog]") or what fired. */
16028
+ reason: string(),
16029
+ /** deviceId, className, trackId, score … — only what the trigger exposes. */
16030
+ vars: record(string(), TraceValueSchema)
16031
+ });
16032
+ var AutomationConditionTraceNodeSchema = object({
16033
+ /** `conditions` for the root, `conditions.<i>` for its i-th child, … */
16034
+ path: string().min(1),
16035
+ kind: _enum([
16036
+ "all",
16037
+ "any",
16038
+ "not",
16039
+ "condition",
16040
+ "expression",
16041
+ "stationary-present"
16042
+ ]),
16043
+ outcome: TraceNodeOutcomeSchema,
16044
+ reason: string(),
16045
+ deviceId: number().int().optional(),
16046
+ cap: string().optional(),
16047
+ fieldPath: string().optional(),
16048
+ operator: string().optional(),
16049
+ expected: TraceValueSchema.optional(),
16050
+ /** What the mirror held; `null` when it held nothing (unknown). */
16051
+ observed: TraceValueSchema.optional()
16052
+ });
16053
+ var AutomationRunVerdictSchema = object({
16054
+ mode: AutomationRunModeSchema,
16055
+ decision: _enum([
16056
+ "run",
16057
+ "queued",
16058
+ "restart",
16059
+ "drop",
16060
+ "cooldown",
16061
+ "bypass"
16062
+ ]),
16063
+ reason: string()
16064
+ });
16065
+ /** One executed (or not-run) step — shared by automations and Action runs. */
16066
+ var AutomationStepTraceSchema = object({
16067
+ /** `actions.<i>` */
16068
+ path: string().min(1),
16069
+ kind: string().min(1),
16070
+ cap: string().optional(),
16071
+ method: string().optional(),
16072
+ deviceId: number().int().optional(),
16073
+ startedAt: number().optional(),
16074
+ endedAt: number().optional(),
16075
+ outcome: _enum([
16076
+ "ok",
16077
+ "error",
16078
+ "not-run"
16079
+ ]),
16080
+ message: string().optional()
16081
+ });
16082
+ var AutomationRunTraceSchema = object({
16083
+ runId: string().min(1),
16084
+ startedAt: number(),
16085
+ endedAt: number(),
16086
+ trigger: AutomationTriggerTraceSchema,
16087
+ conditions: array(AutomationConditionTraceNodeSchema),
16088
+ verdict: AutomationRunVerdictSchema.optional(),
16089
+ steps: array(AutomationStepTraceSchema),
16090
+ outcome: AutomationRunOutcomeSchema,
16091
+ /** How many identical consecutive skips this trace stands for (>= 1). */
16092
+ repeat: number().int().min(1),
16093
+ /** When the latest of those repeats happened. */
16094
+ lastAt: number()
16095
+ });
16096
+ /**
16097
+ * What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
16098
+ * `action:<actionId>`): the cooldown stamp and the trace ring.
16099
+ */
16100
+ var AutomationStateDocSchema = object({
16101
+ version: literal(1),
16102
+ lastRunStartedAt: number().nullable(),
16103
+ traces: array(AutomationRunTraceSchema)
16104
+ });
16105
+ /**
16106
+ * Actions — named, runnable things an operator (or an automation) can start,
16107
+ * declared as LIST ENTRIES, never as devices.
16108
+ *
16109
+ * An entry is either **internal** (a short list of cap/wait steps kept in the
16110
+ * hub's `actions` record kind) or declared by an addon through the
16111
+ * `action-source` collection (a Home Assistant script, a scene …). The one
16112
+ * surface the UI and automations talk to is the `actions` cap; it keeps no
16113
+ * catalog of its own (D3) — every `list` asks the providers live.
16114
+ *
16115
+ * This file is the data half: the entry schema, the variables an entry may
16116
+ * declare, and the pure resolution of the values a run was given. It holds no
16117
+ * runtime.
16118
+ */
16119
+ /** What a variable's value is. `select` takes one of `options`. */
16120
+ var ActionVariableTypeSchema = _enum([
16121
+ "string",
16122
+ "number",
16123
+ "boolean",
16124
+ "select"
16125
+ ]);
16126
+ var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
16127
+ var ActionVariableValueSchema = union([
16128
+ string(),
16129
+ number(),
16130
+ boolean()
16131
+ ]);
16132
+ /**
16133
+ * One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
16134
+ * value) or `{{vars.name}}` (inside a string) in their args.
16135
+ */
16136
+ var ActionVariableSchema = object({
16137
+ name: string().regex(ACTION_VARIABLE_NAME_RE),
16138
+ label: string().min(1).max(120).optional(),
16139
+ type: ActionVariableTypeSchema,
16140
+ required: boolean().optional(),
16141
+ default: ActionVariableValueSchema.optional(),
16142
+ /** The allowed values of a `select`. */
16143
+ options: array(string().min(1)).min(1).optional()
16144
+ }).superRefine((v, ctx) => {
16145
+ if (v.type === "select" && v.options === void 0) ctx.addIssue({
16146
+ code: "custom",
16147
+ message: "a select variable needs options",
16148
+ path: ["options"]
16149
+ });
16150
+ if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
16151
+ code: "custom",
16152
+ message: variableValueError(v, v.default) ?? "invalid default",
16153
+ path: ["default"]
16154
+ });
16155
+ });
16156
+ /** Why `value` is not a legal value for the variable, or null when it is. */
16157
+ function variableValueError(variable, value) {
16158
+ switch (variable.type) {
16159
+ case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
16160
+ case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
16161
+ case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
16162
+ case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
16163
+ }
16164
+ }
16165
+ var ActionSourceKindSchema = _enum(["internal", "addon"]);
16166
+ function isInternalActionId(actionId) {
16167
+ return actionId.startsWith("internal:") && actionId.length > 9;
16168
+ }
16169
+ /** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
16170
+ function addonIdOfActionId(actionId) {
16171
+ if (isInternalActionId(actionId)) return null;
16172
+ const at = actionId.indexOf(":");
16173
+ return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
16174
+ }
16175
+ var ActionStatusSchema = object({
16176
+ isRunning: boolean(),
16177
+ /** Ms epoch the latest run STARTED; null when it never ran. */
16178
+ lastRunAt: number().nullable(),
16179
+ /** The latest run's failure; null on success or when it never ran. */
16180
+ lastError: string().nullable()
16181
+ });
16182
+ var ActionEntrySchema = object({
16183
+ /** `internal:<uuid>` or `<addonId>:<localId>`. */
16184
+ id: string().min(3),
16185
+ name: string().min(1).max(120),
16186
+ /** The addon that declared it; `core-blocks` for an internal one. */
16187
+ addonId: string().min(1),
16188
+ source: ActionSourceKindSchema,
16189
+ /** An addon-declared entry is edited where it was declared. */
16190
+ readOnly: boolean(),
16191
+ /** Internal only: cap and wait steps. No action-in-action, so no cycles. */
16192
+ steps: array(ActionStepSchema).min(1).max(50).optional(),
16193
+ variables: array(ActionVariableSchema).max(20).optional(),
16194
+ status: ActionStatusSchema
16195
+ }).superRefine((entry, ctx) => {
16196
+ if (entry.source === "internal") {
16197
+ if (!isInternalActionId(entry.id)) ctx.addIssue({
16198
+ code: "custom",
16199
+ message: "an internal action id is internal:<uuid>",
16200
+ path: ["id"]
16201
+ });
16202
+ return;
16203
+ }
16204
+ if (entry.steps !== void 0) ctx.addIssue({
16205
+ code: "custom",
16206
+ message: "only an internal action carries steps",
16207
+ path: ["steps"]
16208
+ });
16209
+ if (!entry.readOnly) ctx.addIssue({
16210
+ code: "custom",
16211
+ message: "an addon action is read-only here",
16212
+ path: ["readOnly"]
16213
+ });
16214
+ if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
16215
+ code: "custom",
16216
+ message: "an addon action id is <addonId>:<localId>",
16217
+ path: ["id"]
16218
+ });
16219
+ });
16220
+ /** What an operator writes for an internal action. */
16221
+ var ActionInputSchema = object({
16222
+ name: string().min(1).max(120),
16223
+ steps: array(ActionStepSchema).min(1).max(50),
16224
+ variables: array(ActionVariableSchema).max(20).optional()
16225
+ });
16226
+ /** Who started a run. Absent = the operator pressed it. */
16227
+ var ActionRunOriginSchema = object({
16228
+ /** The automation block whose step started it. */
16229
+ blockId: string().min(1).optional() });
16230
+ /** `started` = the caller did not ask to wait. */
16231
+ var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
16232
+ var ActionRunResultSchema = object({
16233
+ runId: string().min(1),
16234
+ outcome: ActionRunOutcomeSchema,
16235
+ /** Why it did not run, or what failed. */
16236
+ message: string().optional()
16237
+ });
16238
+ _enum([
16239
+ "not-found",
16240
+ "read-only",
16241
+ "invalid-variables",
16242
+ "invalid-steps",
16243
+ "not-linked",
16244
+ "busy"
16245
+ ]);
16246
+ object({
16247
+ actionId: string(),
16248
+ runId: string(),
16249
+ isRunning: boolean(),
16250
+ /** Set when the run ended. */
16251
+ outcome: AutomationRunOutcomeSchema.optional(),
16252
+ lastRunAt: number().nullable(),
16253
+ lastError: string().nullable()
15808
16254
  });
15809
16255
  /**
15810
16256
  * `addon-pages` — system-scoped singleton aggregator cap. Public-facing
@@ -16165,9 +16611,21 @@ var AlertSeveritySchema = _enum([
16165
16611
  "error",
16166
16612
  "critical"
16167
16613
  ]);
16614
+ /**
16615
+ * An action that RUNS something instead of going somewhere: the admin UI calls
16616
+ * the addon's custom action (`addons.custom`) with exactly these fields. The
16617
+ * producer owns the meaning; the UI knows nothing about the addon or the kind.
16618
+ */
16619
+ var AlertActionInvokeSchema = object({
16620
+ addonId: string().min(1),
16621
+ action: string().min(1),
16622
+ input: record(string(), unknown()).optional()
16623
+ });
16624
+ /** An action has `href` (a link) OR `invoke` (a button that runs a custom action). */
16168
16625
  var AlertActionSchema = object({
16169
16626
  label: string(),
16170
16627
  href: string().optional(),
16628
+ invoke: AlertActionInvokeSchema.optional(),
16171
16629
  /**
16172
16630
  * How `href` is followed. Absent / `app`: an admin-ui route (client-side).
16173
16631
  * `server`: a route the HUB serves (an addon HTTP route such as an OAuth
@@ -18540,7 +18998,7 @@ var CompositionEventPlanSchema = object({
18540
18998
  stateField: string(),
18541
18999
  fieldKey: string()
18542
19000
  });
18543
- /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.celsius`. */
19001
+ /** One refusal, named (D391). `path` points into the composition, e.g. `features[0].fields.temperature`. */
18544
19002
  var CompositionProblemSchema = object({
18545
19003
  code: _enum([
18546
19004
  "reserved-variant",
@@ -18822,12 +19280,13 @@ var CHANGED = {
18822
19280
  expr: "now"
18823
19281
  };
18824
19282
  function numeric(input) {
19283
+ const { alsoFrom, ...base } = input;
18825
19284
  return {
18826
- ...input,
19285
+ ...base,
18827
19286
  family: "numeric",
18828
19287
  deviceType: DeviceType.Sensor,
18829
19288
  memberDeviceType: DeviceType.Sensor,
18830
- memberDeviceTypes: [DeviceType.Sensor],
19289
+ memberDeviceTypes: [DeviceType.Sensor, ...alsoFrom?.deviceTypes ?? []],
18831
19290
  activeWhen: void 0,
18832
19291
  commandCaps: [],
18833
19292
  baseUnit: baseUnitOf(input.quantity),
@@ -18835,9 +19294,10 @@ function numeric(input) {
18835
19294
  accept: [{
18836
19295
  cap: input.outputCap,
18837
19296
  fieldPath: input.outputField
18838
- }]
19297
+ }, ...alsoFrom === void 0 ? [] : [alsoFrom.accept]]
18839
19298
  };
18840
19299
  }
19300
+ var CLIMATE_DEVICES = [DeviceType.Thermostat, DeviceType.Climate];
18841
19301
  function binary(input) {
18842
19302
  return {
18843
19303
  ...input,
@@ -18859,29 +19319,43 @@ var GROUP_TEMPLATES = [
18859
19319
  summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
18860
19320
  role: DeviceRole.TemperatureSensor,
18861
19321
  outputCap: "temperature-sensor",
18862
- outputField: "celsius",
19322
+ outputField: "temperature",
18863
19323
  quantity: "temperature",
18864
19324
  defaultAggregate: "mean",
18865
19325
  empty: "null",
18866
- companions: [NOW$2]
19326
+ companions: [NOW$2],
19327
+ alsoFrom: {
19328
+ deviceTypes: CLIMATE_DEVICES,
19329
+ accept: {
19330
+ cap: "climate-control",
19331
+ fieldPath: "currentTemp"
19332
+ }
19333
+ }
18867
19334
  }),
18868
19335
  numeric({
18869
19336
  id: "humidity",
18870
19337
  summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
18871
19338
  role: DeviceRole.HumiditySensor,
18872
19339
  outputCap: "humidity-sensor",
18873
- outputField: "percent",
19340
+ outputField: "humidity",
18874
19341
  quantity: "humidity",
18875
19342
  defaultAggregate: "mean",
18876
19343
  empty: "null",
18877
- companions: [NOW$2]
19344
+ companions: [NOW$2],
19345
+ alsoFrom: {
19346
+ deviceTypes: CLIMATE_DEVICES,
19347
+ accept: {
19348
+ cap: "climate-control",
19349
+ fieldPath: "currentHumidity"
19350
+ }
19351
+ }
18878
19352
  }),
18879
19353
  numeric({
18880
19354
  id: "pressure",
18881
19355
  summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
18882
19356
  role: DeviceRole.PressureSensor,
18883
19357
  outputCap: "pressure-sensor",
18884
- outputField: "hpa",
19358
+ outputField: "pressure",
18885
19359
  quantity: "pressure",
18886
19360
  defaultAggregate: "mean",
18887
19361
  empty: "null",
@@ -18892,7 +19366,7 @@ var GROUP_TEMPLATES = [
18892
19366
  summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
18893
19367
  role: DeviceRole.AmbientLightSensor,
18894
19368
  outputCap: "ambient-light-sensor",
18895
- outputField: "lux",
19369
+ outputField: "illuminance",
18896
19370
  quantity: "illuminance",
18897
19371
  defaultAggregate: "mean",
18898
19372
  empty: "null",
@@ -18903,7 +19377,7 @@ var GROUP_TEMPLATES = [
18903
19377
  summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
18904
19378
  role: DeviceRole.PowerSensor,
18905
19379
  outputCap: "power-meter",
18906
- outputField: "watts",
19380
+ outputField: "power",
18907
19381
  quantity: "power",
18908
19382
  defaultAggregate: "sum",
18909
19383
  empty: "omit",
@@ -18914,7 +19388,7 @@ var GROUP_TEMPLATES = [
18914
19388
  summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
18915
19389
  role: DeviceRole.EnergySensor,
18916
19390
  outputCap: "power-meter",
18917
- outputField: "kwhTotal",
19391
+ outputField: "energy",
18918
19392
  quantity: "energy",
18919
19393
  defaultAggregate: "sum",
18920
19394
  empty: "omit",
@@ -18925,7 +19399,7 @@ var GROUP_TEMPLATES = [
18925
19399
  summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
18926
19400
  role: DeviceRole.BatterySensor,
18927
19401
  outputCap: "battery",
18928
- outputField: "percentage",
19402
+ outputField: "level",
18929
19403
  quantity: "percentage",
18930
19404
  defaultAggregate: "mean",
18931
19405
  empty: "null",
@@ -19503,7 +19977,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
19503
19977
  kind: "mutation",
19504
19978
  auth: "admin",
19505
19979
  access: "view"
19506
- });
19980
+ }), method(object({
19981
+ blockId: string().min(1),
19982
+ trace: AutomationRunTraceSchema.optional(),
19983
+ runStartedAt: number().optional(),
19984
+ keepTraces: number().int().min(1).max(100).optional()
19985
+ }), _void(), {
19986
+ kind: "mutation",
19987
+ auth: "admin"
19988
+ }), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
19989
+ traces: array(AutomationRunTraceSchema),
19990
+ lastError: string().nullable()
19991
+ }), { auth: "admin" });
19507
19992
  /**
19508
19993
  * `custom-model-registry` — collection cap exposing operator-registered
19509
19994
  * custom detection models. Each provider (today: `addon-model-studio`)
@@ -42830,6 +43315,14 @@ method(object({
42830
43315
  kind: "mutation",
42831
43316
  auth: "admin"
42832
43317
  });
43318
+ method(object({
43319
+ nodeId: string().min(1),
43320
+ /** Epoch ms the node was forgotten (the tombstone's `removedAt`). */
43321
+ removedAt: number()
43322
+ }), object({ counts: record(string(), number().int().nonnegative()) }), {
43323
+ kind: "mutation",
43324
+ auth: "admin"
43325
+ });
42833
43326
  /**
42834
43327
  * `device-removal-hook` — the reliable way an addon learns a device was DELETED,
42835
43328
  * so it can delete what it keeps for that device (D865).
@@ -43477,6 +43970,17 @@ var LlmProfileSchema = object({
43477
43970
  * field in its editor only when its descriptor lists it in `profileFields`. */
43478
43971
  topK: number().int().positive().optional(),
43479
43972
  maxTokens: number().int().positive().optional(),
43973
+ /** How hard the model "thinks" before it answers. Omitted = the model's own
43974
+ * default. `off` matters for structured output: a thinking model can spend
43975
+ * the whole completion on reasoning and return an empty `content`. Carried
43976
+ * only by the wires that have it — a kind offers the field in its editor
43977
+ * only when its descriptor lists it in `profileFields`. */
43978
+ reasoningEffort: _enum([
43979
+ "off",
43980
+ "low",
43981
+ "medium",
43982
+ "high"
43983
+ ]).optional(),
43480
43984
  /** Prompt context window. Advisory for cloud kinds (they enforce their own). */
43481
43985
  contextLength: number().int().positive().optional(),
43482
43986
  /** Default system prompt. A caller's `system` REPLACES it (never appends —
@@ -43515,6 +44019,7 @@ var LlmProfileFieldSchema = _enum([
43515
44019
  "topP",
43516
44020
  "topK",
43517
44021
  "maxTokens",
44022
+ "reasoningEffort",
43518
44023
  "contextLength",
43519
44024
  "systemPrompt",
43520
44025
  "timeoutMs",
@@ -44765,6 +45270,43 @@ var NotificationActionSchema = object({
44765
45270
  */
44766
45271
  mode: _enum(["navigate", "background"]).optional()
44767
45272
  });
45273
+ /** A delivery parameter value: what a notifier declared it takes. */
45274
+ var DeliveryParamValueSchema = union([
45275
+ string(),
45276
+ number(),
45277
+ boolean()
45278
+ ]);
45279
+ /**
45280
+ * One extra delivery parameter a notifier KIND declares (D938). A rule that
45281
+ * addresses a target of that kind may set it; a kind that declares nothing is
45282
+ * never handed one. The admin UI derives its control from this descriptor —
45283
+ * no editor knows a service by name.
45284
+ *
45285
+ * Optional fields are `.optional()`, never `.default()` (a Zod default does not
45286
+ * run on the addon cap path).
45287
+ */
45288
+ var DeliveryParamSchema = object({
45289
+ key: string().min(1),
45290
+ label: string(),
45291
+ /** i18n key of the label, resolved by the declaring addon's namespace. */
45292
+ labelKey: string().optional(),
45293
+ type: _enum([
45294
+ "enum",
45295
+ "number",
45296
+ "boolean",
45297
+ "string"
45298
+ ]),
45299
+ /** `enum` only: the closed set of accepted values. */
45300
+ options: array(object({
45301
+ value: string(),
45302
+ label: string()
45303
+ })).optional(),
45304
+ /** `number` only. */
45305
+ min: number().optional(),
45306
+ max: number().optional(),
45307
+ /** What the notifier does when the rule sets nothing; shown as the placeholder. */
45308
+ default: DeliveryParamValueSchema.optional()
45309
+ });
44768
45310
  /**
44769
45311
  * The canonical notification. `body` is the only hard field (Apprise model).
44770
45312
  * `priority` is a 5-level ORDINAL (1=lowest … 3=normal(default) … 5=urgent),
@@ -44787,7 +45329,13 @@ var NotificationSchema = object({
44787
45329
  tag: string().optional(),
44788
45330
  deviceId: number().optional(),
44789
45331
  eventId: string().optional(),
44790
- metadata: record(string(), unknown()).optional()
45332
+ metadata: record(string(), unknown()).optional(),
45333
+ /**
45334
+ * Values for the parameters the target's kind DECLARES in
45335
+ * {@link TargetKindSchema} `deliveryParams`. Already validated against the
45336
+ * declaration by the sender; a notifier reads only the keys it declared.
45337
+ */
45338
+ delivery: record(string(), DeliveryParamValueSchema).optional()
44791
45339
  });
44792
45340
  /** One declared native severity/priority level for a kind. */
44793
45341
  var TargetKindLevelSchema = object({
@@ -44893,6 +45441,11 @@ var TargetKindSchema = object({
44893
45441
  */
44894
45442
  destinationKeys: array(string()).optional(),
44895
45443
  supportsDiscovery: boolean(),
45444
+ /**
45445
+ * Extra delivery parameters a rule may set for a target of this kind (D938).
45446
+ * Absent = none; the rule editor then offers nothing.
45447
+ */
45448
+ deliveryParams: array(DeliveryParamSchema).optional(),
44896
45449
  caps: TargetKindCapsSchema
44897
45450
  });
44898
45451
  /**
@@ -44992,51 +45545,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
44992
45545
  kind: "mutation",
44993
45546
  auth: "admin"
44994
45547
  });
44995
- new Set([
44996
- {
44997
- id: "person",
44998
- name: "Person"
44999
- },
45000
- {
45001
- id: "vehicle",
45002
- name: "Vehicle"
45003
- },
45004
- {
45005
- id: "animal",
45006
- name: "Animal"
45007
- },
45008
- {
45009
- id: "package",
45010
- name: "Package"
45011
- }
45012
- ].map((l) => l.id));
45013
- var COCO_TO_MACRO = {
45014
- mapping: {
45015
- person: "person",
45016
- bicycle: "vehicle",
45017
- car: "vehicle",
45018
- motorcycle: "vehicle",
45019
- airplane: "vehicle",
45020
- bus: "vehicle",
45021
- train: "vehicle",
45022
- truck: "vehicle",
45023
- boat: "vehicle",
45024
- bird: "animal",
45025
- cat: "animal",
45026
- dog: "animal",
45027
- horse: "animal",
45028
- sheep: "animal",
45029
- cow: "animal",
45030
- elephant: "animal",
45031
- bear: "animal",
45032
- zebra: "animal",
45033
- giraffe: "animal",
45034
- suitcase: "package",
45035
- backpack: "package",
45036
- handbag: "package"
45037
- },
45038
- preserveOriginal: false
45039
- };
45040
45548
  var AUDIO_MACRO_LABELS = [
45041
45549
  {
45042
45550
  id: "speech",
@@ -57229,7 +57737,9 @@ var ManifestShapeSchema = object({
57229
57737
  icon: string().optional()
57230
57738
  }).optional(),
57231
57739
  protected: boolean().optional(),
57232
- removable: boolean().optional()
57740
+ removable: boolean().optional(),
57741
+ /** Declared Integrations-page block (mirror of `AddonDeclaration.integrationSection`). */
57742
+ integrationSection: _enum(["system", "providers"]).optional()
57233
57743
  });
57234
57744
  var AddonProcessSchema = object({
57235
57745
  pid: number().optional(),
@@ -57603,9 +58113,9 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
57603
58113
  */
57604
58114
  var AirQualitySensorStatusSchema = object({
57605
58115
  /** Carbon dioxide concentration in ppm. */
57606
- co2Ppm: number().min(0).optional().meta(readingMeta("concentration-volume")),
58116
+ co2: number().min(0).optional().meta(readingMeta("concentration-volume")),
57607
58117
  /** Total volatile organic compounds in ppb. */
57608
- vocPpb: number().min(0).optional().meta(readingMeta("concentration-ppb")),
58118
+ voc: number().min(0).optional().meta(readingMeta("concentration-ppb")),
57609
58119
  /** Particulate matter ≤ 2.5 μm in µg/m³. */
57610
58120
  pm25: number().min(0).optional().meta(readingMeta("concentration-mass")),
57611
58121
  /** Particulate matter ≤ 10 μm in µg/m³. */
@@ -57638,12 +58148,12 @@ var airQualitySensorCapability = {
57638
58148
  * History (D850): recorded series.
57639
58149
  */
57640
58150
  history: { fields: {
57641
- co2Ppm: {
58151
+ co2: {
57642
58152
  kind: "gauge",
57643
58153
  unit: "ppm",
57644
58154
  deadband: 5
57645
58155
  },
57646
- vocPpb: {
58156
+ voc: {
57647
58157
  kind: "gauge",
57648
58158
  unit: "ppb",
57649
58159
  deadband: 5
@@ -57674,7 +58184,7 @@ var airQualitySensorCapability = {
57674
58184
  */
57675
58185
  var AmbientLightSensorStatusSchema = object({
57676
58186
  /** Current illuminance in lux (lx). `null` when the sample was refused (D393). */
57677
- lux: number().min(0).nullable().meta(readingMeta("illuminance", {
58187
+ illuminance: number().min(0).nullable().meta(readingMeta("illuminance", {
57678
58188
  precision: 0,
57679
58189
  label: "Illuminance"
57680
58190
  })),
@@ -57703,7 +58213,7 @@ var ambientLightSensorCapability = {
57703
58213
  /**
57704
58214
  * History (D850): recorded series. Wide range, so a RELATIVE deadband (10 %).
57705
58215
  */
57706
- history: { fields: { lux: {
58216
+ history: { fields: { illuminance: {
57707
58217
  kind: "gauge",
57708
58218
  unit: "lx",
57709
58219
  deadbandPct: 10,
@@ -57842,6 +58352,84 @@ var audioMetricsCapability = {
57842
58352
  */
57843
58353
  history: "none"
57844
58354
  };
58355
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
58356
+ actionId: string().min(1),
58357
+ variables: record(string(), ActionVariableValueSchema).optional()
58358
+ }), _void(), {
58359
+ kind: "mutation",
58360
+ auth: "admin"
58361
+ }), method(object({ actionId: string().min(1) }), _void(), {
58362
+ kind: "mutation",
58363
+ auth: "admin"
58364
+ });
58365
+ /**
58366
+ * actions — the ONE surface for runnable actions, for the UI and for
58367
+ * automations. Provided by the core-blocks builtin on the hub.
58368
+ *
58369
+ * An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
58370
+ * steps, kept in the hub's `actions` record kind) or declared by an addon over
58371
+ * `action-source`. `list` asks every `action-source` provider LIVE and overlays
58372
+ * the run status from the hub's `runs` ledger; there is no catalog here to
58373
+ * drift (D3).
58374
+ *
58375
+ * **Permissions follow the camera, as linked devices do.** An action is linked
58376
+ * to cameras by the operator (`setLinks`, D356: nothing links itself). A
58377
+ * non-admin may `get` / `run` an action only through a camera they may see that
58378
+ * links it: they name the camera (`deviceId`, a top-level field so the scope
58379
+ * gate sees it) and the provider refuses an action that camera does not link.
58380
+ * An admin, and an in-process caller (an automation block), may run any action.
58381
+ * Every refusal is typed (`[not-linked] …`) and logged.
58382
+ *
58383
+ * A second `run` of an action that is already running is REFUSED — traced and
58384
+ * logged — never queued.
58385
+ */
58386
+ var ActionIdInput = object({ actionId: string().min(1) });
58387
+ var ActionLinksSchema = object({
58388
+ deviceId: number().int().nonnegative(),
58389
+ actionIds: array(string().min(1)).max(100)
58390
+ });
58391
+ method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
58392
+ actionId: string().min(1),
58393
+ deviceId: number().int().nonnegative().optional()
58394
+ }), object({ action: ActionEntrySchema.nullable() }), {
58395
+ role: "viewer",
58396
+ auth: "protected",
58397
+ kind: "query",
58398
+ caller: "required"
58399
+ }), method(object({
58400
+ actionId: string().min(1),
58401
+ variables: record(string(), ActionVariableValueSchema).optional(),
58402
+ wait: boolean().optional(),
58403
+ origin: ActionRunOriginSchema.optional(),
58404
+ deviceId: number().int().nonnegative().optional()
58405
+ }), ActionRunResultSchema, {
58406
+ role: "viewer",
58407
+ auth: "protected",
58408
+ kind: "mutation",
58409
+ caller: "required"
58410
+ }), method(ActionIdInput, _void(), {
58411
+ kind: "mutation",
58412
+ auth: "admin"
58413
+ }), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
58414
+ kind: "mutation",
58415
+ auth: "admin"
58416
+ }), method(object({
58417
+ actionId: string().min(1),
58418
+ action: ActionInputSchema.partial()
58419
+ }), object({ action: ActionEntrySchema }), {
58420
+ kind: "mutation",
58421
+ auth: "admin"
58422
+ }), method(ActionIdInput, _void(), {
58423
+ kind: "mutation",
58424
+ auth: "admin"
58425
+ }), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
58426
+ role: "viewer",
58427
+ auth: "protected",
58428
+ kind: "query"
58429
+ }), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
58430
+ kind: "mutation",
58431
+ auth: "admin"
58432
+ });
57845
58433
  /**
57846
58434
  * Automation-control cap. Models HA `automation.*` entities on
57847
58435
  * `DeviceType.Automation`. An automation is a trigger+condition+
@@ -57938,7 +58526,7 @@ var BatteryStatusSchema = object({
57938
58526
  * Consumers must SKIP a null rather than coerce it — `battery-band` already
57939
58527
  * declines to band a non-finite reading, which is the correct shape.
57940
58528
  */
57941
- percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
58529
+ level: number().min(0).max(100).nullable().meta(readingMeta("percentage", { label: "Charge" })),
57942
58530
  /**
57943
58531
  * Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
57944
58532
  * Reolink-specific for the Solar Panel 2 accessory (will become
@@ -57948,7 +58536,7 @@ var BatteryStatusSchema = object({
57948
58536
  * `'unknown'` is the absence of an answer: the provider has not read the
57949
58537
  * power fields yet, or the firmware reported neither. Before it existed,
57950
58538
  * two unreadable fields produced `'none'`, and a camera nobody had reached
57951
- * was drawn "on battery alone" — the same D315 defect `percentage` closed
58539
+ * was drawn "on battery alone" — the same D315 defect `level` closed
57952
58540
  * by going nullable. Consumers SKIP it (no charger state published, no
57953
58541
  * glyph, no HomeKit ChargingState) rather than coerce it either way.
57954
58542
  */
@@ -57972,7 +58560,7 @@ var BatteryStatusSchema = object({
57972
58560
  * that only report charge. A second reading on this cap, not a second
57973
58561
  * `numeric-sensor` on the same device.
57974
58562
  */
57975
- volts: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
58563
+ voltage: number().nullable().optional().meta(readingMeta("voltage", { label: "Voltage" })),
57976
58564
  /**
57977
58565
  * Ms epoch of the last time the device PROVED it was reachable — a
57978
58566
  * completed firmware round-trip, an observed wake, or an inbound push
@@ -58006,7 +58594,7 @@ var BatteryStatusSchema = object({
58006
58594
  /**
58007
58595
  * True when the source is a BINARY low-battery indicator (HA
58008
58596
  * `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
58009
- * charge level — `percentage` is then a coarse stand-in (100 = normal,
58597
+ * charge level — `level` is then a coarse stand-in (100 = normal,
58010
58598
  * sub-threshold = low). UI MUST render "Normal"/"Low" instead of a
58011
58599
  * misleading exact percentage. Absent/false → genuine 0–100 % reading.
58012
58600
  */
@@ -58026,15 +58614,15 @@ var BATTERY_DEVICE_TYPES = [
58026
58614
  var batteryCustomize = {
58027
58615
  version: 1,
58028
58616
  targets: [{
58029
- id: "percentage",
58617
+ id: "level",
58030
58618
  cardinality: "scalar",
58031
58619
  vocabulary: {
58032
58620
  cap: "battery",
58033
- stateField: "percentage"
58621
+ stateField: "level"
58034
58622
  },
58035
58623
  deviceTypes: BATTERY_DEVICE_TYPES,
58036
58624
  apply: "add",
58037
- path: "percentage",
58625
+ path: "level",
58038
58626
  sources: [{
58039
58627
  kind: "field",
58040
58628
  valueKinds: ["number", "string"],
@@ -58128,7 +58716,7 @@ onStatusChanged: { data: object({
58128
58716
  schema: BatteryStatusSchema,
58129
58717
  kind: "push",
58130
58718
  empty: {
58131
- percentage: null,
58719
+ level: null,
58132
58720
  charging: "unknown",
58133
58721
  sleeping: false,
58134
58722
  lastUpdated: 0
@@ -58155,11 +58743,11 @@ onStatusChanged: { data: object({
58155
58743
  * History (D850): recorded series. The generic capture replaces the `battery` series of `pipeline-analytics:stats-5m`.
58156
58744
  */
58157
58745
  history: { fields: {
58158
- percentage: {
58746
+ level: {
58159
58747
  kind: "gauge",
58160
58748
  unit: "%"
58161
58749
  },
58162
- volts: {
58750
+ voltage: {
58163
58751
  kind: "gauge",
58164
58752
  unit: "V"
58165
58753
  }
@@ -58219,14 +58807,14 @@ var binaryCapability = {
58219
58807
  * controls to this single-method surface.
58220
58808
  *
58221
58809
  * The cap is intentionally minimal: a single `setBrightness({deviceId,
58222
- * percentage})` mutation plus the auto-injected `getStatus`. Drivers
58810
+ * level})` mutation plus the auto-injected `getStatus`. Drivers
58223
58811
  * that expose richer controls (color temperature, scenes, schedules)
58224
58812
  * should surface those via the device's `getSettingsUISchema()`
58225
58813
  * instead of bloating this cap.
58226
58814
  */
58227
58815
  var BrightnessStatusSchema = object({
58228
58816
  /** Current level as 0..100 inclusive. Firmware-reported. */
58229
- percentage: number().min(0).max(100).meta(readingMeta("percentage")),
58817
+ level: number().min(0).max(100).meta(readingMeta("percentage")),
58230
58818
  /** Ms epoch of the last operator-driven change. Useful for UI freshness. */
58231
58819
  lastChangedAt: number()
58232
58820
  });
@@ -58238,7 +58826,7 @@ var brightnessCapability = {
58238
58826
  deviceTypes: [DeviceType.Light],
58239
58827
  methods: { setBrightness: method(object({
58240
58828
  deviceId: number().int().nonnegative(),
58241
- percentage: number().min(0).max(100)
58829
+ level: number().min(0).max(100)
58242
58830
  }), _void(), {
58243
58831
  kind: "mutation",
58244
58832
  auth: "protected"
@@ -58251,7 +58839,7 @@ var brightnessCapability = {
58251
58839
  */
58252
58840
  onBrightnessChanged: { data: object({
58253
58841
  deviceId: number(),
58254
- percentage: number().min(0).max(100),
58842
+ level: number().min(0).max(100),
58255
58843
  lastChangedAt: number()
58256
58844
  }) } },
58257
58845
  status: {
@@ -58274,17 +58862,379 @@ onBrightnessChanged: { data: object({
58274
58862
  /**
58275
58863
  * History (D850): recorded series. Actuator tier: level keeps every change.
58276
58864
  */
58277
- history: { fields: { percentage: {
58865
+ history: { fields: { level: {
58278
58866
  kind: "gauge",
58279
58867
  unit: "%",
58280
58868
  minIntervalMs: 0
58281
58869
  } } }
58282
58870
  };
58871
+ /**
58872
+ * The role vocabulary of a remote (D963): what a button MEANS, independent of
58873
+ * how it is wired. A layout template places buttons by role; a device binds a
58874
+ * role to an action; an exporter asks for a role by name. Roles are shared so
58875
+ * one layout fits every appliance and one voice command fits every binding.
58876
+ *
58877
+ * A role outside this list is `custom:<key>` — the operator's own button (a
58878
+ * SmartIR source, a channel preset). The key is a lowercase slug.
58879
+ */
58880
+ var REMOTE_KNOWN_ROLES = [
58881
+ "power",
58882
+ "power_on",
58883
+ "power_off",
58884
+ "volume_up",
58885
+ "volume_down",
58886
+ "mute",
58887
+ "channel_up",
58888
+ "channel_down",
58889
+ "up",
58890
+ "down",
58891
+ "left",
58892
+ "right",
58893
+ "ok",
58894
+ "back",
58895
+ "home",
58896
+ "menu",
58897
+ "info",
58898
+ "guide",
58899
+ "exit",
58900
+ "input",
58901
+ "play",
58902
+ "pause",
58903
+ "play_pause",
58904
+ "stop",
58905
+ "next",
58906
+ "previous",
58907
+ "fast_forward",
58908
+ "rewind",
58909
+ "digit_0",
58910
+ "digit_1",
58911
+ "digit_2",
58912
+ "digit_3",
58913
+ "digit_4",
58914
+ "digit_5",
58915
+ "digit_6",
58916
+ "digit_7",
58917
+ "digit_8",
58918
+ "digit_9"
58919
+ ];
58920
+ var CUSTOM_KEY_RE = /^[a-z0-9][a-z0-9_]{0,47}$/;
58921
+ var KNOWN_ROLES = new Set(REMOTE_KNOWN_ROLES);
58922
+ function isRemoteKnownRole(value) {
58923
+ return KNOWN_ROLES.has(value);
58924
+ }
58925
+ function isRemoteCustomKey(key) {
58926
+ return CUSTOM_KEY_RE.test(key);
58927
+ }
58928
+ /** The key of a `custom:<key>` role, or null for any other string. */
58929
+ function customKeyOfRole(role) {
58930
+ if (!role.startsWith("custom:")) return null;
58931
+ const key = role.slice(7);
58932
+ return isRemoteCustomKey(key) ? key : null;
58933
+ }
58934
+ function isRemoteRole(value) {
58935
+ return isRemoteKnownRole(value) || customKeyOfRole(value) !== null;
58936
+ }
58937
+ var RemoteRoleSchema = string().refine(isRemoteRole, { message: "a role is one of the known roles or custom:<key> (lowercase letters, digits, _)" });
58938
+ var RemoteBindingSchema = object({ action: AutomationCapStepSchema.extend({ deviceId: number().int().nonnegative() }) });
58939
+ var RemoteCustomButtonSchema = object({
58940
+ /** The slug after `custom:` in the role. */
58941
+ key: string().refine(isRemoteCustomKey, { message: "a lowercase slug" }),
58942
+ /** What the operator calls it, and what a voice command may name. */
58943
+ name: string().min(1).max(60)
58944
+ });
58945
+ var RemotePowerModeSchema = _enum(["toggle", "discrete"]);
58946
+ var RemoteConfigSchema = object({
58947
+ layoutTemplateId: string().min(1).nullable(),
58948
+ /**
58949
+ * The transmitter device new bindings and an import send through. A binding
58950
+ * names its own device, so one command may override it.
58951
+ */
58952
+ defaultTransmitterId: number().int().nonnegative().nullable().default(null),
58953
+ /** Keyed by role. A role with no entry falls back to the native cap. */
58954
+ bindings: record(string(), RemoteBindingSchema),
58955
+ customButtons: array(RemoteCustomButtonSchema).max(100),
58956
+ power: object({ mode: RemotePowerModeSchema })
58957
+ }).superRefine((config, ctx) => {
58958
+ const roles = Object.keys(config.bindings);
58959
+ if (roles.length > 200) ctx.addIssue({
58960
+ code: "custom",
58961
+ message: "too many bindings",
58962
+ path: ["bindings"]
58963
+ });
58964
+ for (const role of roles) if (!isRemoteRole(role)) ctx.addIssue({
58965
+ code: "custom",
58966
+ message: `"${role}" is not a role`,
58967
+ path: ["bindings", role]
58968
+ });
58969
+ const keys = /* @__PURE__ */ new Set();
58970
+ config.customButtons.forEach((button, index) => {
58971
+ if (keys.has(button.key)) ctx.addIssue({
58972
+ code: "custom",
58973
+ message: `custom button "${button.key}" is listed twice`,
58974
+ path: [
58975
+ "customButtons",
58976
+ index,
58977
+ "key"
58978
+ ]
58979
+ });
58980
+ keys.add(button.key);
58981
+ });
58982
+ for (const role of roles) {
58983
+ const key = customKeyOfRole(role);
58984
+ if (key !== null && !keys.has(key)) ctx.addIssue({
58985
+ code: "custom",
58986
+ message: `${role} is bound but has no entry in customButtons`,
58987
+ path: ["bindings", role]
58988
+ });
58989
+ }
58990
+ });
58991
+ object({
58992
+ power: object({
58993
+ state: _enum(["on", "off"]),
58994
+ at: number()
58995
+ }).nullable(),
58996
+ muted: object({
58997
+ value: boolean(),
58998
+ at: number()
58999
+ }).nullable()
59000
+ });
59001
+ var RemoteLayoutButtonSchema = object({
59002
+ id: string().min(1).max(40),
59003
+ /** 0-based grid position. */
59004
+ row: number().int().min(0).max(24),
59005
+ col: number().int().min(0).max(24),
59006
+ rowSpan: number().int().min(1).max(24),
59007
+ colSpan: number().int().min(1).max(24),
59008
+ icon: string().min(1).max(60).optional(),
59009
+ label: string().min(1).max(40).optional(),
59010
+ role: RemoteRoleSchema
59011
+ });
59012
+ object({
59013
+ columns: number().int().min(1).max(24),
59014
+ rows: number().int().min(1).max(24),
59015
+ buttons: array(RemoteLayoutButtonSchema).max(200)
59016
+ }).superRefine((grid, ctx) => {
59017
+ const ids = /* @__PURE__ */ new Set();
59018
+ const taken = /* @__PURE__ */ new Map();
59019
+ grid.buttons.forEach((button, index) => {
59020
+ if (ids.has(button.id)) ctx.addIssue({
59021
+ code: "custom",
59022
+ message: `button id "${button.id}" is used twice`,
59023
+ path: [
59024
+ "buttons",
59025
+ index,
59026
+ "id"
59027
+ ]
59028
+ });
59029
+ ids.add(button.id);
59030
+ if (button.row + button.rowSpan > grid.rows || button.col + button.colSpan > grid.columns) {
59031
+ ctx.addIssue({
59032
+ code: "custom",
59033
+ message: `button "${button.id}" leaves the grid`,
59034
+ path: ["buttons", index]
59035
+ });
59036
+ return;
59037
+ }
59038
+ for (let r = button.row; r < button.row + button.rowSpan; r += 1) for (let c = button.col; c < button.col + button.colSpan; c += 1) {
59039
+ const cell = `${r}:${c}`;
59040
+ const other = taken.get(cell);
59041
+ if (other !== void 0) {
59042
+ ctx.addIssue({
59043
+ code: "custom",
59044
+ message: `buttons "${other}" and "${button.id}" overlap`,
59045
+ path: ["buttons", index]
59046
+ });
59047
+ return;
59048
+ }
59049
+ taken.set(cell, button.id);
59050
+ }
59051
+ });
59052
+ });
59053
+ var RemoteBoundCommandSchema = object({
59054
+ role: RemoteRoleSchema,
59055
+ /** The operator's name for a custom button; absent for a known role. */
59056
+ label: string().optional(),
59057
+ custom: boolean()
59058
+ });
59059
+ var RemoteCommandListSchema = object({
59060
+ layoutTemplateId: string().nullable(),
59061
+ power: object({ mode: RemotePowerModeSchema }),
59062
+ /** Only the roles that are BOUND — the ones a press can reach. */
59063
+ commands: array(RemoteBoundCommandSchema)
59064
+ });
59065
+ var RemoteRefusalReasonSchema = _enum([
59066
+ "no-remote",
59067
+ "unbound-role",
59068
+ "action-failed"
59069
+ ]);
59070
+ var RemoteSendResultSchema = discriminatedUnion("status", [
59071
+ object({
59072
+ status: literal("sent"),
59073
+ /** How many times the action ran. */
59074
+ sends: number().int().min(1)
59075
+ }),
59076
+ object({
59077
+ status: literal("skipped"),
59078
+ reason: literal("already-in-state")
59079
+ }),
59080
+ object({
59081
+ status: literal("refused"),
59082
+ reason: RemoteRefusalReasonSchema,
59083
+ detail: string().optional()
59084
+ })
59085
+ ]);
59086
+ var RemoteMediaCommandSchema = _enum([
59087
+ "play",
59088
+ "pause",
59089
+ "stop",
59090
+ "next",
59091
+ "previous",
59092
+ "setMute",
59093
+ "selectSource"
59094
+ ]);
59095
+ /** A send result, or `not-routed`: the role is not bound, so the native cap answers. */
59096
+ var RemoteMediaCommandResultSchema = discriminatedUnion("status", [...RemoteSendResultSchema.options, object({ status: literal("not-routed") })]);
59097
+ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status: literal("saved") }), object({
59098
+ status: literal("refused"),
59099
+ reason: _enum(["unknown-template", "not-a-media-player"]),
59100
+ detail: string()
59101
+ })]);
59102
+ var deviceInput = object({ deviceId: number().int().nonnegative() });
59103
+ DeviceType.MediaPlayer;
59104
+ method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
59105
+ kind: "mutation",
59106
+ auth: "admin"
59107
+ }), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
59108
+ role: RemoteRoleSchema,
59109
+ /** Sends in a row (volume steps). */
59110
+ repeat: number().int().min(1).max(50).default(1)
59111
+ }), RemoteSendResultSchema, {
59112
+ kind: "mutation",
59113
+ auth: "protected"
59114
+ }), method(deviceInput.extend({
59115
+ command: RemoteMediaCommandSchema,
59116
+ muted: boolean().optional(),
59117
+ source: string().optional(),
59118
+ repeat: number().int().min(1).max(50).default(1)
59119
+ }), RemoteMediaCommandResultSchema, {
59120
+ kind: "mutation",
59121
+ auth: "protected"
59122
+ });
59123
+ var TemplateKindSchema = _enum(["remote"]);
59124
+ /**
59125
+ * template — the generic store of reusable, named operator data (D963). A
59126
+ * record is `{ id, kind, name, payload }`; the kinds (today only `remote`, the
59127
+ * button grid of a remote) and the schema each payload must satisfy are
59128
+ * declared by the system in `template-kinds.ts`. Nothing here is specific to a
59129
+ * kind: the engine validates a payload against its kind's schema and, on a
59130
+ * delete, asks the kind's owner whether anything still points at the record.
59131
+ *
59132
+ * Every refusal is a typed result — a UI says "unknown kind" or names the
59133
+ * devices that still use a template, without parsing text.
59134
+ */
59135
+ var TemplateRecordSchema = object({
59136
+ id: string().min(1),
59137
+ kind: TemplateKindSchema,
59138
+ name: string().min(1).max(120),
59139
+ /** Shaped by the kind; `checkTemplatePayload(kind, payload)` reads it. */
59140
+ payload: unknown(),
59141
+ createdAt: number(),
59142
+ updatedAt: number()
59143
+ });
59144
+ var TemplateWriteResultSchema = discriminatedUnion("status", [object({
59145
+ status: literal("saved"),
59146
+ template: TemplateRecordSchema
59147
+ }), object({
59148
+ status: literal("refused"),
59149
+ reason: _enum(["invalid-payload", "not-found"]),
59150
+ detail: string()
59151
+ })]);
59152
+ /** A device still pointing at a template. */
59153
+ var TemplateUserSchema = object({
59154
+ deviceId: number().int().nonnegative(),
59155
+ name: string()
59156
+ });
59157
+ var TemplateDeleteResultSchema = discriminatedUnion("status", [
59158
+ object({ status: literal("deleted") }),
59159
+ object({ status: literal("not-found") }),
59160
+ object({
59161
+ status: literal("in-use"),
59162
+ devices: array(TemplateUserSchema).min(1)
59163
+ })
59164
+ ]);
59165
+ method(object({ kind: TemplateKindSchema.optional() }), array(TemplateRecordSchema), { auth: "protected" }), method(object({ id: string().min(1) }), TemplateRecordSchema.nullable(), { auth: "protected" }), method(object({
59166
+ kind: TemplateKindSchema,
59167
+ name: string().min(1).max(120),
59168
+ payload: unknown()
59169
+ }), TemplateWriteResultSchema, {
59170
+ kind: "mutation",
59171
+ auth: "admin"
59172
+ }), method(object({
59173
+ id: string().min(1),
59174
+ name: string().min(1).max(120).optional(),
59175
+ payload: unknown().optional()
59176
+ }), TemplateWriteResultSchema, {
59177
+ kind: "mutation",
59178
+ auth: "admin"
59179
+ }), method(object({ id: string().min(1) }), TemplateDeleteResultSchema, {
59180
+ kind: "mutation",
59181
+ auth: "admin"
59182
+ });
58283
59183
  DeviceType.Button, method(object({ deviceId: number().int().nonnegative() }), _void(), {
58284
59184
  kind: "mutation",
58285
59185
  auth: "protected"
58286
59186
  });
58287
59187
  /**
59188
+ * A pulse train in signed microseconds: mark (+) first, then space (-), strictly
59189
+ * alternating, no zeros, 2..1024 entries.
59190
+ */
59191
+ var IrTimingsSchema = array(number().int()).min(2).max(1024).superRefine((timings, ctx) => {
59192
+ timings.forEach((value, index) => {
59193
+ const expectMark = index % 2 === 0;
59194
+ if (value === 0 || value > 0 !== expectMark) ctx.addIssue({
59195
+ code: "custom",
59196
+ message: `timing ${index} must be a non-zero ${expectMark ? "mark (positive)" : "space (negative)"}`,
59197
+ path: [index]
59198
+ });
59199
+ });
59200
+ });
59201
+ /** Per-command transmit options. Every key is optional; a transmitter applies what it can. */
59202
+ var TransmitSettingsSchema = object({
59203
+ carrierHz: number().int().positive().optional(),
59204
+ dutyCyclePercent: number().int().min(1).max(100).optional(),
59205
+ repeat: number().int().min(0).max(20).optional(),
59206
+ repeatDelayMs: number().int().min(0).optional()
59207
+ });
59208
+ /** The setting keys a transmitter may declare as settable (`getInfo.settable`). */
59209
+ var TransmitSettingKeySchema = _enum([
59210
+ "carrierHz",
59211
+ "dutyCyclePercent",
59212
+ "repeat",
59213
+ "repeatDelayMs"
59214
+ ]);
59215
+ var IrMediumSchema = _enum(["ir", "rf"]);
59216
+ var IrSendResultSchema = object({
59217
+ ok: literal(true),
59218
+ /** Settings the transmitter could not apply; the train was still sent. */
59219
+ ignoredSettings: array(string())
59220
+ });
59221
+ var IrTransmitterInfoSchema = object({
59222
+ media: array(IrMediumSchema),
59223
+ settable: array(TransmitSettingKeySchema),
59224
+ maxTimings: number().int().positive()
59225
+ });
59226
+ DeviceType.Generic, method(object({
59227
+ deviceId: number().int().nonnegative(),
59228
+ timings: IrTimingsSchema,
59229
+ settings: TransmitSettingsSchema.optional()
59230
+ }), IrSendResultSchema, {
59231
+ kind: "mutation",
59232
+ auth: "protected"
59233
+ }), method(object({ deviceId: number().int().nonnegative() }), IrTransmitterInfoSchema, {
59234
+ kind: "query",
59235
+ auth: "protected"
59236
+ });
59237
+ /**
58288
59238
  * `calendar-source` — collection cap exposing per-provider calendars and
58289
59239
  * their events. Every addon that contributes calendars (Home Assistant,
58290
59240
  * a future Google Calendar addon, …) registers a provider here. The hub
@@ -58871,11 +59821,11 @@ var ColorInputSchema = discriminatedUnion("mode", [
58871
59821
  }),
58872
59822
  object({
58873
59823
  mode: literal("mired"),
58874
- mireds: number().int().min(50).max(1e3)
59824
+ colorTemperature: number().int().min(50).max(1e3)
58875
59825
  })
58876
59826
  ]);
58877
59827
  var ColorStatusSchema = object({
58878
- /** Active color mode — which of `rgb` / `hsv` / `mireds` reflects
59828
+ /** Active color mode — which of `rgb` / `hsv` / `colorTemperature` reflects
58879
59829
  * the bulb's current state. */
58880
59830
  mode: _enum([
58881
59831
  "rgb",
@@ -58887,7 +59837,7 @@ var ColorStatusSchema = object({
58887
59837
  /** Populated when `mode === 'hsv'`. */
58888
59838
  hsv: HsvTripletSchema.optional(),
58889
59839
  /** Populated when `mode === 'mired'`. */
58890
- mireds: number().int().optional().meta(readingMeta("colour-temperature")),
59840
+ colorTemperature: number().int().optional().meta(readingMeta("colour-temperature")),
58891
59841
  /** Ms epoch of the last operator-driven change. */
58892
59842
  lastChangedAt: number()
58893
59843
  });
@@ -58919,7 +59869,7 @@ onColorChanged: { data: object({
58919
59869
  ]),
58920
59870
  rgb: RgbTripletSchema.optional(),
58921
59871
  hsv: HsvTripletSchema.optional(),
58922
- mireds: number().int().optional(),
59872
+ colorTemperature: number().int().optional(),
58923
59873
  lastChangedAt: number()
58924
59874
  }) } },
58925
59875
  status: {
@@ -59796,11 +60746,11 @@ var DishwasherStatusSchema = object({
59796
60746
  /** Feature keys of the programs the appliance currently offers — drives the UI selector. */
59797
60747
  availablePrograms: array(string()),
59798
60748
  /** Seconds remaining on the active cycle, or null when not running / not known. */
59799
- remainingSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
60749
+ remaining: number().int().nonnegative().nullable().meta(readingMeta("duration")),
59800
60750
  /** Seconds the delayed start is set to (time until the cycle starts), or null. */
59801
- delayedStartSeconds: number().int().nonnegative().nullable().meta(readingMeta("duration")),
60751
+ delayedStart: number().int().nonnegative().nullable().meta(readingMeta("duration")),
59802
60752
  /** Cycle completion 0..100, or null when not applicable. */
59803
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
60753
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
59804
60754
  /** True when the door is reported open; null when the door state is not known. */
59805
60755
  doorOpen: boolean().nullable(),
59806
60756
  /** True when the door is latched (locked) during a cycle; null when not reported. */
@@ -60019,14 +60969,14 @@ var dishwasherCapability = {
60019
60969
  runtimeState: DishwasherStatusSchema,
60020
60970
  durability: "session",
60021
60971
  history: { fields: {
60022
- progressPercent: {
60972
+ progress: {
60023
60973
  kind: "gauge",
60024
60974
  unit: "%",
60025
60975
  deadband: 2
60026
60976
  },
60027
60977
  state: { kind: "enum" },
60028
60978
  operationState: { kind: "enum" },
60029
- remainingSeconds: {
60979
+ remaining: {
60030
60980
  kind: "gauge",
60031
60981
  unit: "s",
60032
60982
  minIntervalMs: 6e4
@@ -60617,7 +61567,7 @@ var FanDirectionSchema = _enum(["forward", "reverse"]);
60617
61567
  var FanControlStatusSchema = object({
60618
61568
  /** Active speed as 0..100 inclusive. Null when the device has no
60619
61569
  * speed surface (single-speed fan). */
60620
- percentage: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61570
+ speed: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
60621
61571
  /** Speed granularity the device accepts (HA `percentage_step`, e.g. 25 for
60622
61572
  * a 4-speed fan). Absent when unknown — the UI then falls back to step 1. */
60623
61573
  percentageStep: number().positive().optional().meta(readingMeta("percentage")),
@@ -60644,7 +61594,7 @@ var fanControlCapability = {
60644
61594
  methods: {
60645
61595
  setPercentage: method(object({
60646
61596
  deviceId: number().int().nonnegative(),
60647
- percentage: number().min(0).max(100)
61597
+ speed: number().min(0).max(100)
60648
61598
  }), _void(), {
60649
61599
  kind: "mutation",
60650
61600
  auth: "protected"
@@ -60677,7 +61627,7 @@ var fanControlCapability = {
60677
61627
  },
60678
61628
  /**
60679
61629
  * Runtime-state slice — mirrored by the kernel. UI fan speed
60680
- * sliders read `percentage` for live updates.
61630
+ * sliders read `speed` for live updates.
60681
61631
  */
60682
61632
  runtimeState: FanControlStatusSchema,
60683
61633
  /**
@@ -60691,7 +61641,7 @@ var fanControlCapability = {
60691
61641
  * History (D850): recorded series. Actuator tier: speed keeps every change.
60692
61642
  */
60693
61643
  history: { fields: {
60694
- percentage: {
61644
+ speed: {
60695
61645
  kind: "gauge",
60696
61646
  unit: "%",
60697
61647
  minIntervalMs: 0
@@ -61136,7 +62086,7 @@ var humidifierCapability = {
61136
62086
  */
61137
62087
  var HumiditySensorStatusSchema = object({
61138
62088
  /** Current relative humidity, 0..100. `null` when the sample was refused (D393). */
61139
- percent: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
62089
+ humidity: number().min(0).max(100).nullable().meta(readingMeta("humidity", {
61140
62090
  precision: 0,
61141
62091
  label: "Humidity"
61142
62092
  })),
@@ -61165,7 +62115,7 @@ var humiditySensorCapability = {
61165
62115
  /**
61166
62116
  * History (D850): recorded series.
61167
62117
  */
61168
- history: { fields: { percent: {
62118
+ history: { fields: { humidity: {
61169
62119
  kind: "gauge",
61170
62120
  unit: "%",
61171
62121
  deadband: .5
@@ -61805,7 +62755,7 @@ var LawnMowerControlStatusSchema = object({
61805
62755
  batteryLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61806
62756
  /** 0..100 mowing-completion percentage of the current task, or null when no
61807
62757
  * task is active / progress is unavailable. */
61808
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
62758
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
61809
62759
  /** Current device/event code (dynamic — mostly status, sometimes an error),
61810
62760
  * or null when unknown. */
61811
62761
  currentCode: number().nullable().meta(readingMeta("none")),
@@ -62305,7 +63255,7 @@ var lockControlCapability = {
62305
63255
  volatileStateFields: ["lastChangedAt"]
62306
63256
  };
62307
63257
  /**
62308
- * A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
63258
+ * A monotonic total between resets (D944). Energy uses `power-meter.energy`
62309
63259
  * so dashboards keep one series; every other instantaneous reading lands here.
62310
63260
  * `value` is the time integral in the source quantity's accumulated base
62311
63261
  * (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
@@ -62381,9 +63331,35 @@ var MediaInfoSchema = object({
62381
63331
  /** Optional cover-art / thumbnail URL. */
62382
63332
  imageUrl: string().optional()
62383
63333
  });
63334
+ /**
63335
+ * Where `state`, `volumeLevel`, `isMuted` and `source` come from. `reported`:
63336
+ * the device said so. `assumed`: the driver has no feedback (infrared) and
63337
+ * tracks what it last SENT; it moves only after a send was accepted, and a
63338
+ * human at the real remote makes it wrong. A UI shows an assumed value as a
63339
+ * guess, never as a reading.
63340
+ */
63341
+ var MediaPlayerStateSourceSchema = _enum(["reported", "assumed"]);
63342
+ /** The fields of a media-player status a driver can only guess. */
63343
+ var MediaPlayerAssumedFieldSchema = _enum([
63344
+ "state",
63345
+ "volumeLevel",
63346
+ "isMuted",
63347
+ "source"
63348
+ ]);
62384
63349
  var MediaPlayerStatusSchema = object({
62385
63350
  /** Playback lifecycle state. */
62386
63351
  state: MediaPlayerStateSchema,
63352
+ /**
63353
+ * Whether the state fields are readings or the driver's own bookkeeping.
63354
+ * A slice written before this field existed parses as `reported`.
63355
+ */
63356
+ stateSource: MediaPlayerStateSourceSchema.default("reported"),
63357
+ /**
63358
+ * Which fields are the driver's own guess. `stateSource` is `assumed` when
63359
+ * this is not empty; a field not listed here is a reading even then (power
63360
+ * from a running-state source, mute guessed from the last send).
63361
+ */
63362
+ assumedFields: array(MediaPlayerAssumedFieldSchema).default([]),
62387
63363
  /** Volume as 0..100 inclusive. Null when the device has no volume
62388
63364
  * surface. Pair with `DeviceFeature.MediaPlayerVolume`. */
62389
63365
  volumeLevel: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -62399,10 +63375,10 @@ var MediaPlayerStatusSchema = object({
62399
63375
  currentMedia: MediaInfoSchema.nullable(),
62400
63376
  /** Current playback position in ms. Null when not seekable or
62401
63377
  * nothing is playing. Pair with `DeviceFeature.MediaPlayerSeek`. */
62402
- positionMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
63378
+ position: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
62403
63379
  /** Total duration of the current media in ms. Null when unknown
62404
63380
  * (live stream) or nothing is playing. */
62405
- durationMs: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
63381
+ duration: number().int().nonnegative().nullable().meta(readingMeta("duration-ms")),
62406
63382
  /** Shuffle toggle. Null when no shuffle surface.
62407
63383
  * Pair with `DeviceFeature.MediaPlayerShuffle`. */
62408
63384
  shuffle: boolean().nullable(),
@@ -62441,7 +63417,7 @@ var mediaPlayerCapability = {
62441
63417
  }),
62442
63418
  seek: method(object({
62443
63419
  deviceId: number().int().nonnegative(),
62444
- positionMs: number().int().nonnegative()
63420
+ position: number().int().nonnegative()
62445
63421
  }), _void(), {
62446
63422
  kind: "mutation",
62447
63423
  auth: "protected"
@@ -62513,7 +63489,7 @@ var mediaPlayerCapability = {
62513
63489
  /**
62514
63490
  * History (D850): volume (a level an operator or an automation sets; the
62515
63491
  * default 10 s floor folds a slider drag into its end value) and mute.
62516
- * `positionMs` is not recorded: it moves continuously while playing.
63492
+ * `position` is not recorded: it moves continuously while playing.
62517
63493
  */
62518
63494
  history: { fields: {
62519
63495
  volumeLevel: {
@@ -63475,9 +64451,9 @@ var NetworkLinkStatusSchema = object({
63475
64451
  * one whose reading has not landed must not be drawn at 0 %. Consumers
63476
64452
  * SKIP a null rather than coerce it.
63477
64453
  */
63478
- signalPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
64454
+ signal: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
63479
64455
  /** Raw received signal strength in dBm, when the firmware reports one. */
63480
- rssiDbm: number().optional().meta(readingMeta("signal-level")),
64456
+ rssi: number().optional().meta(readingMeta("signal-level")),
63481
64457
  /** Network name of a wireless link, when the firmware reports it. */
63482
64458
  ssid: string().optional(),
63483
64459
  /** Ms epoch of the last observation. Lets consumers reason about freshness. */
@@ -63513,7 +64489,7 @@ onStatusChanged: { data: object({
63513
64489
  kind: "push",
63514
64490
  empty: {
63515
64491
  type: "unknown",
63516
- signalPercent: null,
64492
+ signal: null,
63517
64493
  lastUpdated: 0
63518
64494
  }
63519
64495
  },
@@ -63536,13 +64512,13 @@ onStatusChanged: { data: object({
63536
64512
  * History (D850): recorded series.
63537
64513
  */
63538
64514
  history: { fields: {
63539
- signalPercent: {
64515
+ signal: {
63540
64516
  kind: "gauge",
63541
64517
  unit: "%",
63542
64518
  deadband: 3,
63543
64519
  minIntervalMs: 6e4
63544
64520
  },
63545
- rssiDbm: {
64521
+ rssi: {
63546
64522
  kind: "gauge",
63547
64523
  unit: "dBm",
63548
64524
  deadband: 2,
@@ -64287,10 +65263,20 @@ var PetFeederDeviceStatusSchema = _enum([
64287
65263
  ]);
64288
65264
  var gramsPortion = number().int().min(4).max(200);
64289
65265
  var PetFeederStatusSchema = object({
64290
- /** Food currently in the bowl (grams). Null when the device has not
64291
- * reported a reading yet. On dual-hopper models this is the combined
64292
- * bowl reading; per-hopper levels live in `food1`/`food2`. */
65266
+ /** Food in the TANK (hopper), as the feeder's own sensor reports it
65267
+ * (`state.food`). A coarse level code, not grams — `0` is empty. The
65268
+ * amount in the bowl is `bowlFood`. On dual-hopper models this is the
65269
+ * combined reading; per-hopper levels live in `food1`/`food2`. Null when
65270
+ * the device has not reported yet. */
64293
65271
  foodLevel: number().nullable().meta(readingMeta("none")),
65272
+ /** Food in the BOWL as the feeder reports it (`state.bowl`), in the
65273
+ * feeder's own units. Null when the model reports none. */
65274
+ bowlFood: number().nullable().meta(readingMeta("none")),
65275
+ /** True while the pet is eating (`state.eating`). */
65276
+ eating: boolean(),
65277
+ /** Whether `markFoodReplenished` does anything on this model. When false
65278
+ * the client must not offer it. */
65279
+ supportsMarkRefilled: boolean(),
64294
65280
  /** Hopper-1 food level (grams) on dual-hopper feeders; null on
64295
65281
  * single-hopper models. */
64296
65282
  food1: number().nullable().meta(readingMeta("none")),
@@ -64298,12 +65284,17 @@ var PetFeederStatusSchema = object({
64298
65284
  * single-hopper models. */
64299
65285
  food2: number().nullable().meta(readingMeta("none")),
64300
65286
  /** Derived low-food flag — mirrors the HA `food_level` binary_sensor
64301
- * (`device_class: problem`, on = low). True when the bowl is empty /
64302
- * below the feeder's low threshold. */
65287
+ * (`device_class: problem`, on = low). True when the tank reports empty,
65288
+ * or, on a dual-hopper model, when EITHER hopper is empty. */
64303
65289
  lowFood: boolean(),
64304
- /** Battery charge 0..100 (%). Null on mains-powered models or when the
64305
- * device has no battery reading. */
65290
+ /** Battery charge 0..100 (%). On a feeder running on `mains` this is the
65291
+ * BACKUP battery's charge, not the power source. Null when the device has
65292
+ * no battery reading. */
64306
65293
  batteryPower: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
65294
+ /** What the feeder is powered from right now: `mains` (plugged in, the
65295
+ * battery is only a backup) or `battery`. Null when the device does not
65296
+ * report it. */
65297
+ powerSource: _enum(["mains", "battery"]).nullable(),
64307
65298
  /**
64308
65299
  * Desiccant life remaining, stored in seconds (duration base, D944).
64309
65300
  * Providers convert from the days the feeder reports. Null when the
@@ -64331,6 +65322,14 @@ var PetFeederStatusSchema = object({
64331
65322
  feedSound: boolean(),
64332
65323
  /** Speaker / prompt volume level (device-scaled integer). */
64333
65324
  volume: number().meta(readingMeta("none")),
65325
+ /** Portion (grams) of the last manual feed sent from a single-hopper
65326
+ * stepper — the default the next manual feed starts from. Persisted per
65327
+ * device by the provider; null until a manual feed has been sent. */
65328
+ lastFeedGrams: gramsPortion.nullable(),
65329
+ /** Hopper-1 portion of the last manual feed (dual-hopper); null until sent. */
65330
+ lastFeedHopper1: gramsPortion.nullable(),
65331
+ /** Hopper-2 portion of the last manual feed (dual-hopper); null until sent. */
65332
+ lastFeedHopper2: gramsPortion.nullable(),
64334
65333
  /** Ms epoch when the slice was last refreshed from the cloud. */
64335
65334
  lastFetchedAt: number()
64336
65335
  });
@@ -64367,7 +65366,9 @@ var petFeederCapability = {
64367
65366
  kind: "mutation",
64368
65367
  auth: "protected"
64369
65368
  }),
64370
- /** Mark a hopper as refilled (D4H/D4S/D4SH). */
65369
+ /** Tell the PetKit cloud a hopper was refilled so it stops its low-food
65370
+ * reminders (D4H/D4S/D4SH only — see `supportsMarkRefilled`). It does not
65371
+ * change any sensor reading. */
64371
65372
  markFoodReplenished: method(object({ deviceId: number().int().nonnegative() }), _void(), {
64372
65373
  kind: "mutation",
64373
65374
  auth: "protected"
@@ -64440,6 +65441,7 @@ var petFeederCapability = {
64440
65441
  */
64441
65442
  history: { fields: {
64442
65443
  foodLevel: { kind: "gauge" },
65444
+ bowlFood: { kind: "gauge" },
64443
65445
  food1: { kind: "gauge" },
64444
65446
  food2: { kind: "gauge" },
64445
65447
  batteryPower: {
@@ -64849,16 +65851,16 @@ method(_void(), PlatformCapabilitiesSchema), method(_void(), HardwareInfoSchema)
64849
65851
  * in real-world devices.
64850
65852
  */
64851
65853
  var PowerMeterStatusSchema = object({
64852
- /** Instantaneous power draw in watts. */
64853
- watts: number().optional().meta(readingMeta("power", { label: "Power" })),
65854
+ /** Instantaneous power draw (watts). */
65855
+ power: number().optional().meta(readingMeta("power", { label: "Power" })),
64854
65856
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
64855
- kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
64856
- /** Voltage in volts. */
64857
- volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
65857
+ energy: number().optional().meta(readingMeta("energy", { label: "Energy" })),
65858
+ /** Voltage (volts). */
65859
+ voltage: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
64858
65860
  /** Current in amperes. */
64859
- amps: number().optional().meta(readingMeta("current", { label: "Current" })),
65861
+ current: number().optional().meta(readingMeta("current", { label: "Current" })),
64860
65862
  /** Apparent power in volt-amperes. */
64861
- va: number().optional().meta(readingMeta("apparent-power")),
65863
+ apparentPower: number().optional().meta(readingMeta("apparent-power")),
64862
65864
  /** Power factor (0..1) if reported. */
64863
65865
  powerFactor: number().min(0).max(1).optional().meta(readingMeta("ratio")),
64864
65866
  /** Ms epoch when the slice was last updated. */
@@ -64916,14 +65918,14 @@ function powerTarget(id, unit) {
64916
65918
  advancedExpression: true
64917
65919
  };
64918
65920
  }
64919
- /** "Power and energy" extension: watts, energy, voltage and current from other devices (D951). */
65921
+ /** "Power and energy" extension: power, energy, voltage and current from other devices (D951). */
64920
65922
  var powerMeterCustomize = {
64921
65923
  version: 1,
64922
65924
  targets: [
64923
- powerTarget("watts", "W"),
64924
- powerTarget("kwhTotal", "kWh"),
64925
- powerTarget("volts", "V"),
64926
- powerTarget("amps", "A")
65925
+ powerTarget("power", "W"),
65926
+ powerTarget("energy", "kWh"),
65927
+ powerTarget("voltage", "V"),
65928
+ powerTarget("current", "A")
64927
65929
  ]
64928
65930
  };
64929
65931
  var powerMeterCapability = {
@@ -64939,41 +65941,41 @@ var powerMeterCapability = {
64939
65941
  },
64940
65942
  runtimeState: PowerMeterStatusSchema,
64941
65943
  /**
64942
- * Runtime-state durability: **restored** — as `numeric-sensor`; `kwhTotal` is an accumulator whose restored value is the baseline.
65944
+ * Runtime-state durability: **restored** — as `numeric-sensor`; `energy` is an accumulator whose restored value is the baseline.
64943
65945
  *
64944
65946
  * See `RuntimeStateDurability`. Enforced by
64945
65947
  * `scripts/check-runtime-state-durability.ts`.
64946
65948
  */
64947
65949
  durability: "restored",
64948
65950
  /**
64949
- * History (D850): recorded series. Gauges are floored at 30 s; `kwhTotal` is the one monotonic meter (counter).
65951
+ * History (D850): recorded series. Gauges are floored at 30 s; `energy` is the one monotonic meter (counter).
64950
65952
  */
64951
65953
  history: { fields: {
64952
- watts: {
65954
+ power: {
64953
65955
  kind: "gauge",
64954
65956
  unit: "W",
64955
65957
  deadband: 1,
64956
65958
  minIntervalMs: 3e4
64957
65959
  },
64958
- kwhTotal: {
65960
+ energy: {
64959
65961
  kind: "counter",
64960
65962
  unit: "kWh",
64961
65963
  deadband: .01,
64962
65964
  minIntervalMs: 6e4
64963
65965
  },
64964
- volts: {
65966
+ voltage: {
64965
65967
  kind: "gauge",
64966
65968
  unit: "V",
64967
65969
  deadband: 1,
64968
65970
  minIntervalMs: 3e4
64969
65971
  },
64970
- amps: {
65972
+ current: {
64971
65973
  kind: "gauge",
64972
65974
  unit: "A",
64973
65975
  deadband: .05,
64974
65976
  minIntervalMs: 3e4
64975
65977
  },
64976
- va: {
65978
+ apparentPower: {
64977
65979
  kind: "gauge",
64978
65980
  unit: "VA",
64979
65981
  deadband: 1,
@@ -65023,9 +66025,6 @@ var PresenceStatusSchema = object({
65023
66025
  location: string().nullable(),
65024
66026
  /** GPS coordinates when available. Null otherwise. */
65025
66027
  gps: GpsLocationSchema.nullable(),
65026
- /** Optional battery level of the tracking device (0..100). Null
65027
- * when not reported. */
65028
- batteryPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
65029
66028
  /** Ms epoch when the slice was last updated. */
65030
66029
  lastChangedAt: number()
65031
66030
  });
@@ -65054,14 +66053,7 @@ var presenceCapability = {
65054
66053
  * `scripts/check-runtime-state-durability.ts`.
65055
66054
  */
65056
66055
  durability: "restored",
65057
- /**
65058
- * History (D850): recorded series.
65059
- */
65060
- history: { fields: { batteryPercent: {
65061
- kind: "gauge",
65062
- unit: "%",
65063
- deadband: 1
65064
- } } },
66056
+ history: "none",
65065
66057
  /** Clock fields: written, but excluded from the compare that decides
65066
66058
  * whether persisting is worth a SQLite commit. */
65067
66059
  volatileStateFields: ["lastChangedAt"]
@@ -65076,7 +66068,7 @@ var presenceCapability = {
65076
66068
  */
65077
66069
  var PressureSensorStatusSchema = object({
65078
66070
  /** Current pressure in hPa. `null` when the sample was refused (D393). */
65079
- hpa: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
66071
+ pressure: number().nullable().meta(readingMeta("pressure", { precision: 0 })),
65080
66072
  /** Ms epoch when the slice was last updated. */
65081
66073
  lastFetchedAt: number()
65082
66074
  });
@@ -65102,7 +66094,7 @@ var pressureSensorCapability = {
65102
66094
  /**
65103
66095
  * History (D850): recorded series.
65104
66096
  */
65105
- history: { fields: { hpa: {
66097
+ history: { fields: { pressure: {
65106
66098
  kind: "gauge",
65107
66099
  unit: "hPa",
65108
66100
  deadband: .1
@@ -68801,7 +69793,7 @@ var tamperCapability = {
68801
69793
  */
68802
69794
  var TemperatureSensorStatusSchema = object({
68803
69795
  /** Current temperature in Celsius. `null` when the sample was refused (D393). */
68804
- celsius: number().nullable().meta(readingMeta("temperature", {
69796
+ temperature: number().nullable().meta(readingMeta("temperature", {
68805
69797
  precision: 1,
68806
69798
  label: "Temperature"
68807
69799
  })),
@@ -68830,7 +69822,7 @@ var temperatureSensorCapability = {
68830
69822
  /**
68831
69823
  * History (D850): recorded series.
68832
69824
  */
68833
- history: { fields: { celsius: {
69825
+ history: { fields: { temperature: {
68834
69826
  kind: "gauge",
68835
69827
  unit: "°C",
68836
69828
  deadband: .1
@@ -69127,7 +70119,7 @@ var VacuumControlStatusSchema = object({
69127
70119
  /** Speed tokens the hardware accepts — drives the UI selector. */
69128
70120
  availableFanSpeeds: array(string()),
69129
70121
  /** 0..100 cleaning-completion percentage of the current task, or null. */
69130
- progressPercent: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
70122
+ progress: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
69131
70123
  /** Current error code (0 / null = no error). */
69132
70124
  errorCode: number().nullable().meta(readingMeta("none")),
69133
70125
  /** Human label for {@link errorCode}, or null when none / undecodable. */
@@ -70375,6 +71367,14 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
70375
71367
  kind: "mutation",
70376
71368
  auth: "admin"
70377
71369
  });
71370
+ discriminatedUnion("kind", [object({
71371
+ kind: literal("raw"),
71372
+ timings: array(number().int()),
71373
+ settings: TransmitSettingsSchema.optional()
71374
+ }), object({
71375
+ kind: literal("pronto"),
71376
+ code: string()
71377
+ })]);
70378
71378
  DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
70379
71379
  /**
70380
71380
  * Frozen unit → spec table. `•` in the doc marks each dimension's canonical
@@ -70760,7 +71760,7 @@ function tryConvertUnit(value, from, to) {
70760
71760
  return fromCanonical(toCanonical(value, fromSpec), toSpec);
70761
71761
  }
70762
71762
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
70763
- DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
71763
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
70764
71764
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
70765
71765
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
70766
71766
  new Set(CAP_NAMES);
@@ -71164,7 +72164,7 @@ var BaseDevice = class {
71164
72164
  * `device-local-state.ts`. Drivers access via:
71165
72165
  *
71166
72166
  * `this.state.battery.sleeping = true` // patches the battery slice
71167
- * `const pct = this.state.battery.percentage` // reads the battery slice
72167
+ * `const pct = this.state.battery.level` // reads the battery slice
71168
72168
  * `this.state.deviceStatus.online = true` // mirrors `markOnline(true)`
71169
72169
  *
71170
72170
  * Adding a new cap with `runtimeState:` automatically extends this
@@ -71204,7 +72204,7 @@ var BaseDevice = class {
71204
72204
  * shape; drivers don't redeclare it, they just write through.
71205
72205
  *
71206
72206
  * Read: `this.runtimeState.getCapState('battery')` →
71207
- * `{percentage, charging, sleeping, lastUpdated}` for any
72207
+ * `{level, charging, sleeping, lastUpdated}` for any
71208
72208
  * provider that registers `batteryCapability`.
71209
72209
  * Write: `this.runtimeState.setCapState('battery', { … })`.
71210
72210
  *
@@ -72378,6 +73378,104 @@ Object.freeze({
72378
73378
  access: "create",
72379
73379
  role: "admin"
72380
73380
  },
73381
+ "actions.create": {
73382
+ capName: "actions",
73383
+ capScope: "system",
73384
+ addonId: null,
73385
+ access: "create",
73386
+ role: "admin"
73387
+ },
73388
+ "actions.delete": {
73389
+ capName: "actions",
73390
+ capScope: "system",
73391
+ addonId: null,
73392
+ access: "delete",
73393
+ role: "admin"
73394
+ },
73395
+ "actions.get": {
73396
+ capName: "actions",
73397
+ capScope: "system",
73398
+ addonId: null,
73399
+ access: "view",
73400
+ role: "viewer"
73401
+ },
73402
+ "actions.getLinks": {
73403
+ capName: "actions",
73404
+ capScope: "system",
73405
+ addonId: null,
73406
+ access: "view",
73407
+ role: "admin"
73408
+ },
73409
+ "actions.getTraces": {
73410
+ capName: "actions",
73411
+ capScope: "system",
73412
+ addonId: null,
73413
+ access: "view",
73414
+ role: "admin"
73415
+ },
73416
+ "actions.list": {
73417
+ capName: "actions",
73418
+ capScope: "system",
73419
+ addonId: null,
73420
+ access: "view",
73421
+ role: "admin"
73422
+ },
73423
+ "actions.listForCamera": {
73424
+ capName: "actions",
73425
+ capScope: "system",
73426
+ addonId: null,
73427
+ access: "view",
73428
+ role: "viewer"
73429
+ },
73430
+ "actions.run": {
73431
+ capName: "actions",
73432
+ capScope: "system",
73433
+ addonId: null,
73434
+ access: "create",
73435
+ role: "viewer"
73436
+ },
73437
+ "actions.setLinks": {
73438
+ capName: "actions",
73439
+ capScope: "system",
73440
+ addonId: null,
73441
+ access: "create",
73442
+ role: "admin"
73443
+ },
73444
+ "actions.stop": {
73445
+ capName: "actions",
73446
+ capScope: "system",
73447
+ addonId: null,
73448
+ access: "create",
73449
+ role: "admin"
73450
+ },
73451
+ "actions.update": {
73452
+ capName: "actions",
73453
+ capScope: "system",
73454
+ addonId: null,
73455
+ access: "create",
73456
+ role: "admin"
73457
+ },
73458
+ "actionSource.listActions": {
73459
+ capName: "action-source",
73460
+ capScope: "system",
73461
+ addonId: null,
73462
+ access: "view",
73463
+ role: "admin"
73464
+ },
73465
+ "actionSource.runAction": {
73466
+ capName: "action-source",
73467
+ capScope: "system",
73468
+ addonId: null,
73469
+ access: "create",
73470
+ role: "admin"
73471
+ },
73472
+ "actionSource.stopAction": {
73473
+ capName: "action-source",
73474
+ capScope: "system",
73475
+ addonId: null,
73476
+ access: "create",
73477
+ role: "admin"
73478
+ },
72381
73479
  "addonPages.listPages": {
72382
73480
  capName: "addon-pages",
72383
73481
  capScope: "system",
@@ -73659,6 +74757,13 @@ Object.freeze({
73659
74757
  access: "view",
73660
74758
  role: "admin"
73661
74759
  },
74760
+ "coreBlocks.getAutomationRunState": {
74761
+ capName: "core-blocks",
74762
+ capScope: "system",
74763
+ addonId: null,
74764
+ access: "view",
74765
+ role: "admin"
74766
+ },
73662
74767
  "coreBlocks.getBlockSettings": {
73663
74768
  capName: "core-blocks",
73664
74769
  capScope: "system",
@@ -73680,6 +74785,13 @@ Object.freeze({
73680
74785
  access: "view",
73681
74786
  role: "admin"
73682
74787
  },
74788
+ "coreBlocks.getTraces": {
74789
+ capName: "core-blocks",
74790
+ capScope: "system",
74791
+ addonId: null,
74792
+ access: "view",
74793
+ role: "admin"
74794
+ },
73683
74795
  "coreBlocks.getTypeDefs": {
73684
74796
  capName: "core-blocks",
73685
74797
  capScope: "system",
@@ -73715,6 +74827,13 @@ Object.freeze({
73715
74827
  access: "create",
73716
74828
  role: "admin"
73717
74829
  },
74830
+ "coreBlocks.reportAutomationRun": {
74831
+ capName: "core-blocks",
74832
+ capScope: "system",
74833
+ addonId: null,
74834
+ access: "create",
74835
+ role: "admin"
74836
+ },
73718
74837
  "coreBlocks.restart": {
73719
74838
  capName: "core-blocks",
73720
74839
  capScope: "system",
@@ -75794,6 +76913,20 @@ Object.freeze({
75794
76913
  access: "create",
75795
76914
  role: "viewer"
75796
76915
  },
76916
+ "irTransmitter.getInfo": {
76917
+ capName: "ir-transmitter",
76918
+ capScope: "device",
76919
+ addonId: null,
76920
+ access: "view",
76921
+ role: "viewer"
76922
+ },
76923
+ "irTransmitter.send": {
76924
+ capName: "ir-transmitter",
76925
+ capScope: "device",
76926
+ addonId: null,
76927
+ access: "create",
76928
+ role: "viewer"
76929
+ },
75797
76930
  "keychain.delete": {
75798
76931
  capName: "keychain",
75799
76932
  capScope: "system",
@@ -77026,6 +78159,13 @@ Object.freeze({
77026
78159
  access: "create",
77027
78160
  role: "admin"
77028
78161
  },
78162
+ "nodeRemovalHook.onNodeRemoved": {
78163
+ capName: "node-removal-hook",
78164
+ capScope: "system",
78165
+ addonId: null,
78166
+ access: "create",
78167
+ role: "admin"
78168
+ },
77029
78169
  "nodes.clusterAddonStatus": {
77030
78170
  capName: "nodes",
77031
78171
  capScope: "system",
@@ -79917,6 +81057,41 @@ Object.freeze({
79917
81057
  access: "create",
79918
81058
  role: "admin"
79919
81059
  },
81060
+ "remote.getConfig": {
81061
+ capName: "remote",
81062
+ capScope: "system",
81063
+ addonId: null,
81064
+ access: "view",
81065
+ role: "admin"
81066
+ },
81067
+ "remote.listCommands": {
81068
+ capName: "remote",
81069
+ capScope: "system",
81070
+ addonId: null,
81071
+ access: "view",
81072
+ role: "admin"
81073
+ },
81074
+ "remote.sendCommand": {
81075
+ capName: "remote",
81076
+ capScope: "system",
81077
+ addonId: null,
81078
+ access: "create",
81079
+ role: "admin"
81080
+ },
81081
+ "remote.sendMediaCommand": {
81082
+ capName: "remote",
81083
+ capScope: "system",
81084
+ addonId: null,
81085
+ access: "create",
81086
+ role: "admin"
81087
+ },
81088
+ "remote.setConfig": {
81089
+ capName: "remote",
81090
+ capScope: "system",
81091
+ addonId: null,
81092
+ access: "create",
81093
+ role: "admin"
81094
+ },
79920
81095
  "runningState.getStatus": {
79921
81096
  capName: "running-state",
79922
81097
  capScope: "device",
@@ -81107,6 +82282,41 @@ Object.freeze({
81107
82282
  access: "view",
81108
82283
  role: "viewer"
81109
82284
  },
82285
+ "template.create": {
82286
+ capName: "template",
82287
+ capScope: "system",
82288
+ addonId: null,
82289
+ access: "create",
82290
+ role: "admin"
82291
+ },
82292
+ "template.delete": {
82293
+ capName: "template",
82294
+ capScope: "system",
82295
+ addonId: null,
82296
+ access: "delete",
82297
+ role: "admin"
82298
+ },
82299
+ "template.get": {
82300
+ capName: "template",
82301
+ capScope: "system",
82302
+ addonId: null,
82303
+ access: "view",
82304
+ role: "admin"
82305
+ },
82306
+ "template.list": {
82307
+ capName: "template",
82308
+ capScope: "system",
82309
+ addonId: null,
82310
+ access: "view",
82311
+ role: "admin"
82312
+ },
82313
+ "template.update": {
82314
+ capName: "template",
82315
+ capScope: "system",
82316
+ addonId: null,
82317
+ access: "create",
82318
+ role: "admin"
82319
+ },
81110
82320
  "terminalSession.adoptLegacyMonitor": {
81111
82321
  capName: "terminal-session",
81112
82322
  capScope: "system",
@@ -82288,7 +83498,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82288
83498
  label: t("Full brightness", "Luminosità massima"),
82289
83499
  phrase: t("Set {device} to full brightness", "Porta {device} alla massima luminosità"),
82290
83500
  icon: "sun",
82291
- args: { percentage: 100 }
83501
+ args: { level: 100 }
82292
83502
  },
82293
83503
  {
82294
83504
  id: "brightness.half",
@@ -82296,7 +83506,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82296
83506
  label: t("Half brightness", "Luminosità a metà"),
82297
83507
  phrase: t("Dim {device} to half", "Abbassa {device} a metà luminosità"),
82298
83508
  icon: "sun-dim",
82299
- args: { percentage: 50 }
83509
+ args: { level: 50 }
82300
83510
  },
82301
83511
  {
82302
83512
  id: "brightness.off",
@@ -82304,16 +83514,16 @@ var ACTUATOR_CAP_VOCABULARY = {
82304
83514
  label: t("Brightness off", "Luminosità a zero"),
82305
83515
  phrase: t("Dim {device} to zero", "Abbassa {device} a zero"),
82306
83516
  icon: "lightbulb-off",
82307
- args: { percentage: 0 }
83517
+ args: { level: 0 }
82308
83518
  },
82309
83519
  {
82310
83520
  id: "brightness.set",
82311
83521
  method: "setBrightness",
82312
83522
  label: t("Set brightness", "Imposta la luminosità"),
82313
- phrase: t("Set the brightness of {device} to {percentage}", "Imposta la luminosità di {device} a {percentage}"),
83523
+ phrase: t("Set the brightness of {device} to {level}", "Imposta la luminosità di {device} a {level}"),
82314
83524
  icon: "sun-medium",
82315
83525
  openArgs: [{
82316
- key: "percentage",
83526
+ key: "level",
82317
83527
  label: PERCENT,
82318
83528
  offer: {
82319
83529
  kind: "number",
@@ -82327,13 +83537,13 @@ var ACTUATOR_CAP_VOCABULARY = {
82327
83537
  ],
82328
83538
  state: [{
82329
83539
  kind: "numeric",
82330
- field: "percentage",
83540
+ field: "level",
82331
83541
  quantity: t("the brightness", "la luminosità"),
82332
83542
  label: t("Brightness", "Luminosità"),
82333
83543
  unit: "%",
82334
83544
  icon: "sun"
82335
83545
  }],
82336
- events: { onBrightnessChanged: { notOperatorFacing: "the `percentage` state trigger reads the same change" } }
83546
+ events: { onBrightnessChanged: { notOperatorFacing: "the `level` state trigger reads the same change" } }
82337
83547
  },
82338
83548
  color: {
82339
83549
  scope: "device",
@@ -82347,7 +83557,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82347
83557
  icon: "sun",
82348
83558
  args: { color: {
82349
83559
  mode: "mired",
82350
- mireds: 370
83560
+ colorTemperature: 370
82351
83561
  } }
82352
83562
  },
82353
83563
  {
@@ -82358,7 +83568,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82358
83568
  icon: "snowflake",
82359
83569
  args: { color: {
82360
83570
  mode: "mired",
82361
- mireds: 200
83571
+ colorTemperature: 200
82362
83572
  } }
82363
83573
  },
82364
83574
  {
@@ -82972,7 +84182,7 @@ var ACTUATOR_CAP_VOCABULARY = {
82972
84182
  label: t("Fan off", "Ventilatore spento"),
82973
84183
  phrase: t("Stop {device}", "Ferma {device}"),
82974
84184
  icon: "power-off",
82975
- args: { percentage: 0 }
84185
+ args: { speed: 0 }
82976
84186
  },
82977
84187
  {
82978
84188
  id: "fan.full",
@@ -82980,16 +84190,16 @@ var ACTUATOR_CAP_VOCABULARY = {
82980
84190
  label: t("Fan full", "Ventilatore al massimo"),
82981
84191
  phrase: t("Run {device} at full speed", "Porta {device} alla massima velocità"),
82982
84192
  icon: "fan",
82983
- args: { percentage: 100 }
84193
+ args: { speed: 100 }
82984
84194
  },
82985
84195
  {
82986
84196
  id: "fan.speed",
82987
84197
  method: "setPercentage",
82988
84198
  label: t("Set speed", "Imposta la velocità"),
82989
- phrase: t("Set the speed of {device} to {percentage}", "Imposta la velocità di {device} al {percentage}"),
84199
+ phrase: t("Set the speed of {device} to {speed}", "Imposta la velocità di {device} al {speed}"),
82990
84200
  icon: "fan",
82991
84201
  openArgs: [{
82992
- key: "percentage",
84202
+ key: "speed",
82993
84203
  label: t("Speed", "Velocità"),
82994
84204
  offer: {
82995
84205
  kind: "number",
@@ -83051,7 +84261,7 @@ var ACTUATOR_CAP_VOCABULARY = {
83051
84261
  ],
83052
84262
  state: [{
83053
84263
  kind: "numeric",
83054
- field: "percentage",
84264
+ field: "speed",
83055
84265
  quantity: t("the speed", "la velocità"),
83056
84266
  label: t("Speed", "Velocità"),
83057
84267
  unit: "%",
@@ -83417,6 +84627,11 @@ var ACTUATOR_CAP_VOCABULARY = {
83417
84627
  icon: "circle-dot"
83418
84628
  }]
83419
84629
  },
84630
+ "ir-transmitter": {
84631
+ scope: "device",
84632
+ noun: t("IR / RF transmitter", "Trasmettitore IR / RF"),
84633
+ notOperatorFacing: { send: "a raw pulse train is not something an operator composes in an automation; the remote that owns the command table sends it" }
84634
+ },
83420
84635
  control: {
83421
84636
  scope: "device",
83422
84637
  noun: t("Control", "Controllo"),
@@ -83849,7 +85064,7 @@ var APPLIANCE_CAP_VOCABULARY = {
83849
85064
  },
83850
85065
  {
83851
85066
  kind: "numeric",
83852
- field: "progressPercent",
85067
+ field: "progress",
83853
85068
  quantity: t("the cycle progress", "l’avanzamento del lavaggio"),
83854
85069
  label: t("Progress", "Avanzamento"),
83855
85070
  unit: "%",
@@ -84207,10 +85422,10 @@ var APPLIANCE_CAP_VOCABULARY = {
84207
85422
  id: "media.seek",
84208
85423
  method: "seek",
84209
85424
  label: t("Seek", "Vai al punto"),
84210
- phrase: t("Move {device} to {positionMs}", "Porta {device} al punto {positionMs}"),
85425
+ phrase: t("Move {device} to {position}", "Porta {device} al punto {position}"),
84211
85426
  icon: "fast-forward",
84212
85427
  openArgs: [{
84213
- key: "positionMs",
85428
+ key: "position",
84214
85429
  label: t("Position", "Posizione"),
84215
85430
  offer: {
84216
85431
  kind: "number",
@@ -85259,7 +86474,7 @@ var SENSOR_CAP_VOCABULARY = {
85259
86474
  state: [
85260
86475
  {
85261
86476
  kind: "numeric",
85262
- field: "co2Ppm",
86477
+ field: "co2",
85263
86478
  quantity: t("the CO₂", "la CO₂"),
85264
86479
  label: t("CO₂", "CO₂"),
85265
86480
  unit: "ppm",
@@ -85267,7 +86482,7 @@ var SENSOR_CAP_VOCABULARY = {
85267
86482
  },
85268
86483
  {
85269
86484
  kind: "numeric",
85270
- field: "vocPpb",
86485
+ field: "voc",
85271
86486
  quantity: t("the VOC level", "il livello di COV"),
85272
86487
  label: t("VOC", "COV"),
85273
86488
  unit: "ppb",
@@ -85303,7 +86518,7 @@ var SENSOR_CAP_VOCABULARY = {
85303
86518
  noun: t("Light level", "Luminosità ambiente"),
85304
86519
  state: [{
85305
86520
  kind: "numeric",
85306
- field: "lux",
86521
+ field: "illuminance",
85307
86522
  quantity: t("the light level", "la luminosità"),
85308
86523
  label: t("Illuminance", "Illuminamento"),
85309
86524
  unit: "lx",
@@ -85506,7 +86721,7 @@ var SENSOR_CAP_VOCABULARY = {
85506
86721
  noun: t("Humidity", "Umidità"),
85507
86722
  state: [{
85508
86723
  kind: "numeric",
85509
- field: "percent",
86724
+ field: "humidity",
85510
86725
  quantity: t("the humidity", "l’umidità"),
85511
86726
  label: t("Humidity", "Umidità"),
85512
86727
  unit: "%",
@@ -85554,7 +86769,7 @@ var SENSOR_CAP_VOCABULARY = {
85554
86769
  state: [
85555
86770
  {
85556
86771
  kind: "numeric",
85557
- field: "watts",
86772
+ field: "power",
85558
86773
  quantity: t("the power draw", "il consumo"),
85559
86774
  label: t("Power", "Potenza"),
85560
86775
  unit: "W",
@@ -85562,7 +86777,7 @@ var SENSOR_CAP_VOCABULARY = {
85562
86777
  },
85563
86778
  {
85564
86779
  kind: "numeric",
85565
- field: "kwhTotal",
86780
+ field: "energy",
85566
86781
  quantity: t("the energy used", "l’energia consumata"),
85567
86782
  label: t("Energy", "Energia"),
85568
86783
  unit: "kWh",
@@ -85570,7 +86785,7 @@ var SENSOR_CAP_VOCABULARY = {
85570
86785
  },
85571
86786
  {
85572
86787
  kind: "numeric",
85573
- field: "volts",
86788
+ field: "voltage",
85574
86789
  quantity: t("the voltage", "la tensione"),
85575
86790
  label: t("Voltage", "Tensione"),
85576
86791
  unit: "V",
@@ -85578,7 +86793,7 @@ var SENSOR_CAP_VOCABULARY = {
85578
86793
  },
85579
86794
  {
85580
86795
  kind: "numeric",
85581
- field: "amps",
86796
+ field: "current",
85582
86797
  quantity: t("the current", "la corrente"),
85583
86798
  label: t("Current", "Corrente"),
85584
86799
  unit: "A",
@@ -85595,13 +86810,6 @@ var SENSOR_CAP_VOCABULARY = {
85595
86810
  label: t("Where", "Posizione"),
85596
86811
  phrase: t("When {device} is at {value}", "Quando {device} è in {value}"),
85597
86812
  icon: "map-pin"
85598
- }, {
85599
- kind: "numeric",
85600
- field: "batteryPercent",
85601
- quantity: t("the phone battery", "la batteria del telefono"),
85602
- label: t("Battery", "Batteria"),
85603
- unit: "%",
85604
- icon: "battery"
85605
86813
  }]
85606
86814
  },
85607
86815
  "pressure-sensor": {
@@ -85609,7 +86817,7 @@ var SENSOR_CAP_VOCABULARY = {
85609
86817
  noun: t("Pressure", "Pressione"),
85610
86818
  state: [{
85611
86819
  kind: "numeric",
85612
- field: "hpa",
86820
+ field: "pressure",
85613
86821
  quantity: t("the pressure", "la pressione"),
85614
86822
  label: t("Pressure", "Pressione"),
85615
86823
  unit: "hPa",
@@ -85645,7 +86853,7 @@ var SENSOR_CAP_VOCABULARY = {
85645
86853
  noun: t("Temperature", "Temperatura"),
85646
86854
  state: [{
85647
86855
  kind: "numeric",
85648
- field: "celsius",
86856
+ field: "temperature",
85649
86857
  quantity: t("the temperature", "la temperatura"),
85650
86858
  label: t("Temperature", "Temperatura"),
85651
86859
  unit: "°C",
@@ -85716,7 +86924,7 @@ var SENSOR_CAP_VOCABULARY = {
85716
86924
  state: [
85717
86925
  {
85718
86926
  kind: "numeric",
85719
- field: "percentage",
86927
+ field: "level",
85720
86928
  quantity: t("the battery level", "il livello della batteria"),
85721
86929
  label: t("Battery", "Batteria"),
85722
86930
  unit: "%",
@@ -85758,7 +86966,7 @@ var SENSOR_CAP_VOCABULARY = {
85758
86966
  icon: "battery-charging"
85759
86967
  }
85760
86968
  ],
85761
- events: { onStatusChanged: { notOperatorFacing: "the percentage / sleeping / charging state triggers each read one field of this change" } },
86969
+ events: { onStatusChanged: { notOperatorFacing: "the level / sleeping / charging state triggers each read one field of this change" } },
85762
86970
  extraEvents: [{
85763
86971
  category: EventCategory.DeviceAwake,
85764
86972
  label: t("Woke up", "Risvegliato"),
@@ -85776,7 +86984,7 @@ var SENSOR_CAP_VOCABULARY = {
85776
86984
  noun: t("Network link", "Collegamento di rete"),
85777
86985
  state: [{
85778
86986
  kind: "numeric",
85779
- field: "signalPercent",
86987
+ field: "signal",
85780
86988
  quantity: t("the signal strength", "l’intensità del segnale"),
85781
86989
  label: t("Signal", "Segnale"),
85782
86990
  unit: "%",
@@ -85869,6 +87077,8 @@ var ML = "model and training machinery — no device action";
85869
87077
  var INTERNAL = "internal plumbing between addons — never operator-facing";
85870
87078
  /** Every system-scoped cap, with why it is not a device's vocabulary. */
85871
87079
  var SYSTEM_CAP_VOCABULARY = {
87080
+ "action-source": system(INTERNAL),
87081
+ actions: system("declared actions — run from the Actions page and from the cameras that link them"),
85872
87082
  "addon-pages": system(UI_PLUMBING),
85873
87083
  "addon-pages-source": system(UI_PLUMBING),
85874
87084
  "addon-routes": system(UI_PLUMBING),
@@ -85899,6 +87109,7 @@ var SYSTEM_CAP_VOCABULARY = {
85899
87109
  "device-manager": system("the device registry itself — rename, move and remove are administration"),
85900
87110
  "device-provider": system(INTERNAL),
85901
87111
  "device-removal-hook": system(INTERNAL),
87112
+ "node-removal-hook": system(INTERNAL),
85902
87113
  "device-state": system("the runtime-state mirror every trigger already reads through"),
85903
87114
  "display-palette": system("the cluster display palette — one colour table for every client, not a device action"),
85904
87115
  "embedding-encoder": system(ML),
@@ -85938,6 +87149,7 @@ var SYSTEM_CAP_VOCABULARY = {
85938
87149
  "recording-archive": system(STORAGE),
85939
87150
  "recording-export": system("recording exports — requested from the timeline, not an automation step"),
85940
87151
  records: system(INTERNAL),
87152
+ remote: system("the per-device remote setup — authored in the Customize remote editor, sent through the remote UI"),
85941
87153
  "server-management": system(CLUSTER),
85942
87154
  "settings-store": system(INTERNAL),
85943
87155
  "smtp-provider": system(INTERNAL),
@@ -85950,6 +87162,7 @@ var SYSTEM_CAP_VOCABULARY = {
85950
87162
  "storage-provider": system(STORAGE),
85951
87163
  "stream-broker": system(PIPELINE),
85952
87164
  system: system(CLUSTER),
87165
+ template: system("operator-authored templates — edited in their own editor, never actuated"),
85953
87166
  "terminal-session": system(CLUSTER),
85954
87167
  toast: system(UI_PLUMBING),
85955
87168
  training: system(ML),
@@ -86065,6 +87278,31 @@ Object.freeze({
86065
87278
  form: "single",
86066
87279
  optional: false
86067
87280
  }],
87281
+ "actions.get": [{
87282
+ name: "deviceId",
87283
+ form: "single",
87284
+ optional: true
87285
+ }],
87286
+ "actions.getLinks": [{
87287
+ name: "deviceId",
87288
+ form: "single",
87289
+ optional: false
87290
+ }],
87291
+ "actions.listForCamera": [{
87292
+ name: "deviceId",
87293
+ form: "single",
87294
+ optional: false
87295
+ }],
87296
+ "actions.run": [{
87297
+ name: "deviceId",
87298
+ form: "single",
87299
+ optional: true
87300
+ }],
87301
+ "actions.setLinks": [{
87302
+ name: "deviceId",
87303
+ form: "single",
87304
+ optional: false
87305
+ }],
86068
87306
  "addonSettings.getDeviceSettings": [{
86069
87307
  name: "deviceId",
86070
87308
  form: "single",
@@ -87116,6 +88354,16 @@ Object.freeze({
87116
88354
  form: "single",
87117
88355
  optional: false
87118
88356
  }],
88357
+ "irTransmitter.getInfo": [{
88358
+ name: "deviceId",
88359
+ form: "single",
88360
+ optional: false
88361
+ }],
88362
+ "irTransmitter.send": [{
88363
+ name: "deviceId",
88364
+ form: "single",
88365
+ optional: false
88366
+ }],
87119
88367
  "keychain.deleteDeviceScope": [{
87120
88368
  name: "deviceId",
87121
88369
  form: "single",
@@ -88341,6 +89589,31 @@ Object.freeze({
88341
89589
  form: "single",
88342
89590
  optional: true
88343
89591
  }],
89592
+ "remote.getConfig": [{
89593
+ name: "deviceId",
89594
+ form: "single",
89595
+ optional: false
89596
+ }],
89597
+ "remote.listCommands": [{
89598
+ name: "deviceId",
89599
+ form: "single",
89600
+ optional: false
89601
+ }],
89602
+ "remote.sendCommand": [{
89603
+ name: "deviceId",
89604
+ form: "single",
89605
+ optional: false
89606
+ }],
89607
+ "remote.sendMediaCommand": [{
89608
+ name: "deviceId",
89609
+ form: "single",
89610
+ optional: false
89611
+ }],
89612
+ "remote.setConfig": [{
89613
+ name: "deviceId",
89614
+ form: "single",
89615
+ optional: false
89616
+ }],
88344
89617
  "runningState.getStatus": [{
88345
89618
  name: "deviceId",
88346
89619
  form: "single",
@@ -90288,8 +91561,17 @@ function bestLocationMatch(externalName, existing, threshold = .8) {
90288
91561
  }
90289
91562
  return best;
90290
91563
  }
91564
+ String.raw`(?<=^|["'(\s>,\[{])`;
90291
91565
  var MB = 1024 * 1024;
90292
91566
  1024 * MB, 3072 * MB;
91567
+ object({
91568
+ manufacturer: string().optional(),
91569
+ supportedModels: array(string()).optional(),
91570
+ supportedController: string().optional(),
91571
+ commandsEncoding: string(),
91572
+ delay: number().nonnegative().optional(),
91573
+ commands: record(string(), unknown())
91574
+ });
90293
91575
  //#endregion
90294
91576
  //#region src/callback-host.ts
90295
91577
  /**
@@ -115053,6 +116335,14 @@ var HmChildDevice = class extends BaseDevice {
115053
116335
  this.valueChangedUnsub = facade.on("valueChanged", (event) => {
115054
116336
  if (event.device !== this.address) return;
115055
116337
  if (!this.ownsEventChannel(event)) return;
116338
+ this.ctx.logger.debug("Homematic value change accepted", {
116339
+ tags: { deviceId: this.ctx.id },
116340
+ meta: {
116341
+ address: this.address,
116342
+ channel: event.channel,
116343
+ parameter: event.parameter
116344
+ }
116345
+ });
115056
116346
  handle(event, "live");
115057
116347
  });
115058
116348
  this.seedTriggerUnsubs = [facade.on("ready", () => this.seedCurrentValues()), facade.on("connection", () => this.seedCurrentValues())];
@@ -115127,13 +116417,33 @@ var HmChildDevice = class extends BaseDevice {
115127
116417
  if (status.includes(event.channel)) return true;
115128
116418
  return this.resolveHmDevice()?.channels.some((c) => status.includes(c.address) && (c.dataPoints ?? []).some((d) => d.parameter === event.parameter)) !== true;
115129
116419
  }
116420
+ /** A value change the filter refused — named, per reason, on the record. */
116421
+ logValueDropped(event, reason) {
116422
+ this.ctx.logger.debug("Homematic value change dropped", {
116423
+ tags: { deviceId: this.ctx.id },
116424
+ meta: {
116425
+ address: this.address,
116426
+ ownedChannel: this.channel,
116427
+ channel: event.channel,
116428
+ parameter: event.parameter,
116429
+ reason
116430
+ }
116431
+ });
116432
+ }
115130
116433
  ownsEventChannel(event) {
115131
116434
  const owned = this.channel;
115132
116435
  if (owned === void 0) return true;
115133
116436
  const channel = event.channel;
115134
116437
  if (typeof channel === "string" && channel.length > 0) {
115135
- if (!this.ownedChannels().includes(channel)) return false;
115136
- return this.isPreferredSource(event);
116438
+ if (!this.ownedChannels().includes(channel)) {
116439
+ this.logValueDropped(event, "foreign-channel");
116440
+ return false;
116441
+ }
116442
+ if (!this.isPreferredSource(event)) {
116443
+ this.logValueDropped(event, "not-status-source");
116444
+ return false;
116445
+ }
116446
+ return true;
115137
116447
  }
115138
116448
  this.ctx.logger.warn("Homematic value event without a channel — dropped", {
115139
116449
  tags: { deviceId: this.ctx.id },
@@ -115640,15 +116950,15 @@ var HmActuatorDevice = class extends HmChildDevice {
115640
116950
  * keep that class a thin actuator-wiring layer.
115641
116951
  */
115642
116952
  var COLD_TEMPERATURE = {
115643
- celsius: 0,
116953
+ temperature: 0,
115644
116954
  lastFetchedAt: 0
115645
116955
  };
115646
116956
  var COLD_HUMIDITY = {
115647
- percent: 0,
116957
+ humidity: 0,
115648
116958
  lastFetchedAt: 0
115649
116959
  };
115650
116960
  var COLD_AMBIENT_LIGHT = {
115651
- lux: 0,
116961
+ illuminance: 0,
115652
116962
  lastFetchedAt: 0
115653
116963
  };
115654
116964
  var COLD_POWER = { lastFetchedAt: 0 };
@@ -115740,15 +117050,15 @@ var HmSensorDevice = class extends HmChildDevice {
115740
117050
  decodeSensorPush(parameter, value, now) {
115741
117051
  if (typeof value !== "number") return;
115742
117052
  if (this.caps.has("temperature-sensor") && parameter === "ACTUAL_TEMPERATURE") this.runtimeState.setCapState("temperature-sensor", {
115743
- celsius: value,
117053
+ temperature: value,
115744
117054
  lastFetchedAt: now
115745
117055
  });
115746
117056
  if (this.caps.has("humidity-sensor") && parameter === "HUMIDITY") this.runtimeState.setCapState("humidity-sensor", {
115747
- percent: value,
117057
+ humidity: value,
115748
117058
  lastFetchedAt: now
115749
117059
  });
115750
117060
  if (this.caps.has("ambient-light-sensor") && parameter === "ILLUMINATION") this.runtimeState.setCapState("ambient-light-sensor", {
115751
- lux: Math.max(0, value),
117061
+ illuminance: Math.max(0, value),
115752
117062
  lastFetchedAt: now
115753
117063
  });
115754
117064
  this.decodePowerPush(parameter, value, now);
@@ -115761,28 +117071,28 @@ var HmSensorDevice = class extends HmChildDevice {
115761
117071
  case "POWER":
115762
117072
  this.runtimeState.setCapState("power-meter", {
115763
117073
  ...prev,
115764
- watts: value,
117074
+ power: value,
115765
117075
  lastFetchedAt: now
115766
117076
  });
115767
117077
  return;
115768
117078
  case "ENERGY_COUNTER":
115769
117079
  this.runtimeState.setCapState("power-meter", {
115770
117080
  ...prev,
115771
- kwhTotal: value / 1e3,
117081
+ energy: value / 1e3,
115772
117082
  lastFetchedAt: now
115773
117083
  });
115774
117084
  return;
115775
117085
  case "VOLTAGE":
115776
117086
  this.runtimeState.setCapState("power-meter", {
115777
117087
  ...prev,
115778
- volts: value,
117088
+ voltage: value,
115779
117089
  lastFetchedAt: now
115780
117090
  });
115781
117091
  return;
115782
117092
  case "CURRENT":
115783
117093
  this.runtimeState.setCapState("power-meter", {
115784
117094
  ...prev,
115785
- amps: value / 1e3,
117095
+ current: value / 1e3,
115786
117096
  lastFetchedAt: now
115787
117097
  });
115788
117098
  return;
@@ -115880,7 +117190,7 @@ var COLD_BINARY = {
115880
117190
  lastChangedAt: 0
115881
117191
  };
115882
117192
  var COLD_TEMP = {
115883
- celsius: 0,
117193
+ temperature: 0,
115884
117194
  lastFetchedAt: 0
115885
117195
  };
115886
117196
  /**
@@ -115944,7 +117254,7 @@ var HmDiagnosticDevice = class extends HmChildDevice {
115944
117254
  if (stored === null) return;
115945
117255
  if (this.capName === "temperature-sensor") {
115946
117256
  this.runtimeState.setCapState("temperature-sensor", {
115947
- celsius: stored,
117257
+ temperature: stored,
115948
117258
  lastFetchedAt: now
115949
117259
  });
115950
117260
  return;