@camstack/types 1.2.423 → 1.2.425

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.
Files changed (48) hide show
  1. package/dist/addon.js +1 -1
  2. package/dist/addon.mjs +1 -1
  3. package/dist/capabilities/broker.cap.d.ts +6 -0
  4. package/dist/capabilities/composer.cap.d.ts +6 -0
  5. package/dist/capabilities/core-blocks.cap.d.ts +43 -0
  6. package/dist/capabilities/group-active.cap.d.ts +46 -0
  7. package/dist/capabilities/group-commands.cap.d.ts +1 -1
  8. package/dist/capabilities/group-status.cap.d.ts +1 -1
  9. package/dist/capabilities/index.d.ts +3 -1
  10. package/dist/capabilities/lock-control.cap.d.ts +1 -0
  11. package/dist/capabilities/switch.cap.d.ts +1 -1
  12. package/dist/client.js +3 -0
  13. package/dist/client.mjs +3 -0
  14. package/dist/composition/composition-report.d.ts +2 -0
  15. package/dist/composition/composition.d.ts +9 -0
  16. package/dist/composition/helpers/actuator-methods.d.ts +39 -0
  17. package/dist/composition/helpers/aggregate.d.ts +2 -0
  18. package/dist/composition/helpers/catalog.d.ts +7 -1
  19. package/dist/composition/helpers/compile-history.d.ts +16 -1
  20. package/dist/composition/helpers/compile-math.d.ts +9 -0
  21. package/dist/composition/helpers/history-math.d.ts +8 -0
  22. package/dist/composition/helpers/index.d.ts +6 -4
  23. package/dist/composition/helpers/source-pick.d.ts +8 -1
  24. package/dist/composition/helpers/spec.d.ts +49 -3
  25. package/dist/{composition-CpETZ4HL.mjs → composition-Bb8iwHEJ.mjs} +175 -5
  26. package/dist/{composition-CPRAP41h.js → composition-CpAc0YfQ.js} +228 -4
  27. package/dist/device/cap-vocabulary/entries/sensors.d.ts +1 -1
  28. package/dist/expression/builtins.d.ts +11 -2
  29. package/dist/expression/expression-source.d.ts +6 -1
  30. package/dist/generated/addon-api.d.ts +14 -0
  31. package/dist/generated/addon-cap-facts.d.ts +1 -1
  32. package/dist/generated/cap-status-types.d.ts +3 -1
  33. package/dist/generated/capability-router-map.d.ts +5 -2
  34. package/dist/generated/device-local-state.d.ts +3 -0
  35. package/dist/generated/device-proxy.d.ts +3 -0
  36. package/dist/generated/device-scoped-caps.d.ts +1 -1
  37. package/dist/generated/history-catalog.d.ts +1 -1
  38. package/dist/generated/method-access-map.d.ts +1 -1
  39. package/dist/generated/method-device-selectors.d.ts +1 -1
  40. package/dist/generated/runtime-state-durability.d.ts +1 -1
  41. package/dist/index.js +650 -34
  42. package/dist/index.mjs +627 -35
  43. package/dist/interfaces/config-ui.d.ts +12 -0
  44. package/dist/node.js +1 -1
  45. package/dist/node.mjs +1 -1
  46. package/dist/{sleep-0sD_LHLI.mjs → sleep--jXS9hWo.mjs} +10 -1
  47. package/dist/{sleep-CEKGW7A5.js → sleep-edKiOXLo.js} +10 -1
  48. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-CEKGW7A5.js");
2
+ const require_sleep = require("./sleep-edKiOXLo.js");
3
3
  const require_event_category = require("./event-category-Ave2VSxY.js");
4
- const require_composition = require("./composition-CPRAP41h.js");
4
+ const require_composition = require("./composition-CpAc0YfQ.js");
5
5
  const require_node_color = require("./node-color.js");
6
6
  const require_err_msg = require("./err-msg-U7lLUMNz.js");
7
7
  const require_enums = require("./enums.js");
@@ -10761,7 +10761,22 @@ var BrokerProviderInfoSchema = zod.z.object({
10761
10761
  */
10762
10762
  interactiveConnectPath: zod.z.string().min(1).optional(),
10763
10763
  /** Relative hub path to disconnect the linked account (same popup pattern). */
10764
- interactiveDisconnectPath: zod.z.string().min(1).optional()
10764
+ interactiveDisconnectPath: zod.z.string().min(1).optional(),
10765
+ /**
10766
+ * The kind signs in through a server-held interactive session instead of
10767
+ * (or before) typed credentials. `basePath` is a hub-relative route set
10768
+ * served by the owning addon (`/addon/<id>/...`) speaking the sign-in
10769
+ * contract: `POST {basePath}/start` (body: the form's settings) answers
10770
+ * `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
10771
+ * `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
10772
+ * 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
10773
+ * (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
10774
+ * existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
10775
+ * (`{ sessionId }`) drops the session. The dialog that edits a broker
10776
+ * offers it as the default path; the fields the session fills are
10777
+ * marked `filledBySignIn` in the kind's settings schema.
10778
+ */
10779
+ signIn: zod.z.object({ basePath: zod.z.string().min(1) }).optional()
10765
10780
  }))
10766
10781
  });
10767
10782
  var ListInputSchema = zod.z.object({
@@ -12922,6 +12937,10 @@ var BUILTIN_RESULT_KINDS = Object.freeze({
12922
12937
  latchedAt: {
12923
12938
  kind: "fixed",
12924
12939
  result: ["number", "null"]
12940
+ },
12941
+ schmitt: {
12942
+ kind: "fixed",
12943
+ result: ["boolean", "null"]
12925
12944
  }
12926
12945
  });
12927
12946
  var KindInferenceError = class extends Error {};
@@ -13286,7 +13305,7 @@ function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
13286
13305
  * One catalog row per base reading a group helper can build (D944 §3).
13287
13306
  * Data, not a form default written into the block.
13288
13307
  */
13289
- var NOW$1 = {
13308
+ var NOW$2 = {
13290
13309
  fieldPath: "lastFetchedAt",
13291
13310
  expr: "now"
13292
13311
  };
@@ -13300,6 +13319,8 @@ function numeric(input) {
13300
13319
  family: "numeric",
13301
13320
  deviceType: require_err_msg.DeviceType.Sensor,
13302
13321
  memberDeviceType: require_err_msg.DeviceType.Sensor,
13322
+ memberDeviceTypes: [require_err_msg.DeviceType.Sensor],
13323
+ activeWhen: void 0,
13303
13324
  commandCaps: [],
13304
13325
  baseUnit: require_sleep.baseUnitOf(input.quantity),
13305
13326
  aggregates: require_composition.NUMERIC_AGGREGATES,
@@ -13315,6 +13336,8 @@ function binary(input) {
13315
13336
  family: "binary",
13316
13337
  deviceType: require_err_msg.DeviceType.Sensor,
13317
13338
  memberDeviceType: require_err_msg.DeviceType.Sensor,
13339
+ memberDeviceTypes: [require_err_msg.DeviceType.Sensor],
13340
+ activeWhen: void 0,
13318
13341
  commandCaps: [],
13319
13342
  quantity: "none",
13320
13343
  baseUnit: void 0,
@@ -13332,7 +13355,7 @@ var GROUP_TEMPLATES = [
13332
13355
  quantity: "temperature",
13333
13356
  defaultAggregate: "mean",
13334
13357
  empty: "null",
13335
- companions: [NOW$1]
13358
+ companions: [NOW$2]
13336
13359
  }),
13337
13360
  numeric({
13338
13361
  id: "humidity",
@@ -13343,7 +13366,7 @@ var GROUP_TEMPLATES = [
13343
13366
  quantity: "humidity",
13344
13367
  defaultAggregate: "mean",
13345
13368
  empty: "null",
13346
- companions: [NOW$1]
13369
+ companions: [NOW$2]
13347
13370
  }),
13348
13371
  numeric({
13349
13372
  id: "pressure",
@@ -13354,7 +13377,7 @@ var GROUP_TEMPLATES = [
13354
13377
  quantity: "pressure",
13355
13378
  defaultAggregate: "mean",
13356
13379
  empty: "null",
13357
- companions: [NOW$1]
13380
+ companions: [NOW$2]
13358
13381
  }),
13359
13382
  numeric({
13360
13383
  id: "illuminance",
@@ -13365,7 +13388,7 @@ var GROUP_TEMPLATES = [
13365
13388
  quantity: "illuminance",
13366
13389
  defaultAggregate: "mean",
13367
13390
  empty: "null",
13368
- companions: [NOW$1]
13391
+ companions: [NOW$2]
13369
13392
  }),
13370
13393
  numeric({
13371
13394
  id: "power",
@@ -13376,7 +13399,7 @@ var GROUP_TEMPLATES = [
13376
13399
  quantity: "power",
13377
13400
  defaultAggregate: "sum",
13378
13401
  empty: "omit",
13379
- companions: [NOW$1]
13402
+ companions: [NOW$2]
13380
13403
  }),
13381
13404
  numeric({
13382
13405
  id: "energy",
@@ -13387,7 +13410,7 @@ var GROUP_TEMPLATES = [
13387
13410
  quantity: "energy",
13388
13411
  defaultAggregate: "sum",
13389
13412
  empty: "omit",
13390
- companions: [NOW$1]
13413
+ companions: [NOW$2]
13391
13414
  }),
13392
13415
  numeric({
13393
13416
  id: "battery",
@@ -13422,7 +13445,7 @@ var GROUP_TEMPLATES = [
13422
13445
  quantity: "device",
13423
13446
  defaultAggregate: "mean",
13424
13447
  empty: "null",
13425
- companions: [NOW$1]
13448
+ companions: [NOW$2]
13426
13449
  }),
13427
13450
  binary({
13428
13451
  id: "motion",
@@ -13516,6 +13539,11 @@ var GROUP_TEMPLATES = [
13516
13539
  summary: "On when at least one switch is on, or when all of them are. Offline and unknown members are left out of that decision, never read as off, and still receive the command.",
13517
13540
  deviceType: require_err_msg.DeviceType.Switch,
13518
13541
  outputCap: "switch",
13542
+ outputField: "on",
13543
+ member: {
13544
+ cap: "switch",
13545
+ fieldPath: "on"
13546
+ },
13519
13547
  commandCaps: ["switch"]
13520
13548
  }),
13521
13549
  actuator({
@@ -13523,29 +13551,130 @@ var GROUP_TEMPLATES = [
13523
13551
  summary: "On when at least one light is on, or when all of them are. Brightness and colour are offered only when every member has them. A command is not sent to a member that lacks it.",
13524
13552
  deviceType: require_err_msg.DeviceType.Light,
13525
13553
  outputCap: "switch",
13554
+ outputField: "on",
13555
+ member: {
13556
+ cap: "switch",
13557
+ fieldPath: "on"
13558
+ },
13526
13559
  commandCaps: [
13527
13560
  "switch",
13528
13561
  "brightness",
13529
13562
  "color"
13530
13563
  ]
13564
+ }),
13565
+ actuator({
13566
+ id: "fan",
13567
+ summary: "On when at least one fan is on, or when all of them are. Speed, preset, direction and oscillation are offered only when every fan has them. A command is not sent to a fan that lacks it.",
13568
+ deviceType: require_err_msg.DeviceType.Fan,
13569
+ outputCap: "switch",
13570
+ outputField: "on",
13571
+ member: {
13572
+ cap: "switch",
13573
+ fieldPath: "on"
13574
+ },
13575
+ commandCaps: ["switch", "fan-control"]
13576
+ }),
13577
+ actuator({
13578
+ id: "cover",
13579
+ summary: "Open when at least one cover is open or part-open, or only when all of them are. Position and tilt are offered only when every cover has them. A cover that reports nothing is left out, never read as closed.",
13580
+ deviceType: require_err_msg.DeviceType.Cover,
13581
+ outputCap: "group-active",
13582
+ outputField: "active",
13583
+ member: {
13584
+ cap: "cover",
13585
+ fieldPath: "state"
13586
+ },
13587
+ activeWhen: [
13588
+ "open",
13589
+ "opening",
13590
+ "stopped"
13591
+ ],
13592
+ commandCaps: ["cover"]
13593
+ }),
13594
+ actuator({
13595
+ id: "valve",
13596
+ summary: "Open when at least one valve is open or part-open, or only when all of them are. Position is offered only when every valve has it. A valve that reports nothing is left out, never read as closed.",
13597
+ deviceType: require_err_msg.DeviceType.Valve,
13598
+ outputCap: "group-active",
13599
+ outputField: "active",
13600
+ member: {
13601
+ cap: "valve",
13602
+ fieldPath: "state"
13603
+ },
13604
+ activeWhen: [
13605
+ "open",
13606
+ "opening",
13607
+ "stopped"
13608
+ ],
13609
+ commandCaps: ["valve"]
13610
+ }),
13611
+ actuator({
13612
+ id: "lock",
13613
+ summary: "Locked when at least one lock is locked, or only when all of them are. A jammed or moving lock is not locked. Locking is one tap; unlocking the group needs a confirmation every time, and nothing is sent without it.",
13614
+ deviceType: require_err_msg.DeviceType.Lock,
13615
+ outputCap: "group-active",
13616
+ outputField: "active",
13617
+ member: {
13618
+ cap: "lock-control",
13619
+ fieldPath: "state"
13620
+ },
13621
+ activeWhen: ["locked"],
13622
+ commandCaps: ["lock-control"]
13623
+ }),
13624
+ actuator({
13625
+ id: "media-player",
13626
+ summary: "Playing when at least one player is playing, or only when all of them are. Volume is offered only when every player has it. A player that reports nothing is left out, never read as stopped.",
13627
+ deviceType: require_err_msg.DeviceType.MediaPlayer,
13628
+ outputCap: "group-active",
13629
+ outputField: "active",
13630
+ member: {
13631
+ cap: "media-player",
13632
+ fieldPath: "state"
13633
+ },
13634
+ activeWhen: ["playing", "buffering"],
13635
+ commandCaps: ["media-player"]
13636
+ }),
13637
+ actuator({
13638
+ id: "climate",
13639
+ summary: "Running when at least one thermostat or air conditioner is not off, or only when all of them are. Target temperature and fan are offered only when every device has them. A device that reports nothing is left out, never read as off.",
13640
+ deviceType: require_err_msg.DeviceType.Thermostat,
13641
+ memberDeviceTypes: [require_err_msg.DeviceType.Thermostat, require_err_msg.DeviceType.Climate],
13642
+ outputCap: "group-active",
13643
+ outputField: "active",
13644
+ member: {
13645
+ cap: "climate-control",
13646
+ fieldPath: "mode"
13647
+ },
13648
+ activeWhen: [
13649
+ "heat",
13650
+ "cool",
13651
+ "auto",
13652
+ "heat_cool",
13653
+ "fan_only",
13654
+ "dry"
13655
+ ],
13656
+ commandCaps: ["climate-control"]
13531
13657
  })
13532
13658
  ];
13533
13659
  function actuator(input) {
13534
13660
  return {
13535
- ...input,
13661
+ id: input.id,
13662
+ summary: input.summary,
13663
+ deviceType: input.deviceType,
13664
+ outputCap: input.outputCap,
13665
+ outputField: input.outputField,
13666
+ commandCaps: input.commandCaps,
13536
13667
  family: "actuator",
13537
13668
  role: void 0,
13538
13669
  memberDeviceType: input.deviceType,
13539
- outputField: "on",
13670
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
13671
+ activeWhen: input.activeWhen,
13540
13672
  quantity: "none",
13541
13673
  baseUnit: void 0,
13542
13674
  aggregates: require_composition.BINARY_AGGREGATES,
13543
13675
  defaultAggregate: "any",
13544
13676
  empty: "offline",
13545
- accept: [{
13546
- cap: "switch",
13547
- fieldPath: "on"
13548
- }],
13677
+ accept: [input.member],
13549
13678
  companions: [CHANGED]
13550
13679
  };
13551
13680
  }
@@ -13742,7 +13871,7 @@ async function runFanOut(calls, invoke) {
13742
13871
  //#region src/generated/history-catalog.ts
13743
13872
  /**
13744
13873
  * Cap history catalog, projected from every `*.cap.ts` `history` block.
13745
- * 42 caps with series (76 series), 32 caps answered `'none'`.
13874
+ * 42 caps with series (76 series), 33 caps answered `'none'`.
13746
13875
  * Field keys are `runtimeState` paths (`a.b` into fixed objects only).
13747
13876
  */
13748
13877
  var HISTORY_CATALOG = {
@@ -14148,6 +14277,7 @@ var HISTORY_NONE_CAPS = [
14148
14277
  "doorbell",
14149
14278
  "event-emitter",
14150
14279
  "feature-probe",
14280
+ "group-active",
14151
14281
  "group-commands",
14152
14282
  "group-status",
14153
14283
  "image",
@@ -14181,7 +14311,7 @@ function historyFieldsFor(capName) {
14181
14311
  * Project a statistics or integral helper onto a new device (D944 §3).
14182
14312
  * The value field is `series`: the composer fills it from history.
14183
14313
  */
14184
- var NOW = {
14314
+ var NOW$1 = {
14185
14315
  kind: "expression",
14186
14316
  expr: "now",
14187
14317
  bindings: {}
@@ -14205,6 +14335,20 @@ function counts(member) {
14205
14335
  total: series(member, "total", "offline")
14206
14336
  };
14207
14337
  }
14338
+ var PER_SYMBOL = {
14339
+ second: "s",
14340
+ minute: "min",
14341
+ hour: "h"
14342
+ };
14343
+ /**
14344
+ * The unit of a rate: the source series' unit per second, minute or hour
14345
+ * (`°C/h`). A source with no unit of its own (a generic number) has none to
14346
+ * borrow, so the label is null and the chart shows the bare number.
14347
+ */
14348
+ function derivativeUnitLabel(spec) {
14349
+ const unit = historyFieldsFor(spec.source.cap)[spec.source.fieldPath]?.unit;
14350
+ return unit === void 0 ? null : `${unit}/${PER_SYMBOL[spec.per]}`;
14351
+ }
14208
14352
  function declaredSeriesKind(member) {
14209
14353
  const field = historyFieldsFor(member.cap)[member.fieldPath];
14210
14354
  if (field === void 0) return null;
@@ -14227,7 +14371,7 @@ function draft(input) {
14227
14371
  cap: input.cap,
14228
14372
  fields: {
14229
14373
  [input.field]: series(input.member, "value", input.empty),
14230
- lastFetchedAt: NOW
14374
+ lastFetchedAt: NOW$1
14231
14375
  }
14232
14376
  }, {
14233
14377
  kind: "fields",
@@ -14255,6 +14399,29 @@ function statisticDraft(spec, retention = require_composition.DEFAULT_HISTORY_RE
14255
14399
  })
14256
14400
  };
14257
14401
  }
14402
+ /**
14403
+ * A derivative reads a gauge or a counter and publishes its rate per second,
14404
+ * minute or hour. The output is a plain number: a rate of a temperature is not
14405
+ * a temperature, so the chart carries no inherited unit.
14406
+ */
14407
+ function derivativeDraft(spec, retention = require_composition.DEFAULT_HISTORY_RETENTION) {
14408
+ const problems = [...historyProblems(spec.source)];
14409
+ const kind = declaredSeriesKind(spec.source);
14410
+ if (kind === "enum" || kind === "boolean") problems.push(problem("kind-mismatch", "helper.source", "a derivative reads a number that moves, not a yes/no or a state"));
14411
+ const tier = require_composition.planStatisticTier(spec.window, retention);
14412
+ if (!tier.ok) problems.push(problem("retention", "helper.window", tier.reason));
14413
+ return {
14414
+ problems,
14415
+ draft: draft({
14416
+ role: require_err_msg.DeviceRole.NumericSensor,
14417
+ cap: "numeric-sensor",
14418
+ field: "value",
14419
+ empty: "null",
14420
+ spec,
14421
+ member: spec.source
14422
+ })
14423
+ };
14424
+ }
14258
14425
  function integralDraft(spec, retention = require_composition.DEFAULT_HISTORY_RETENTION) {
14259
14426
  const problems = [...historyProblems(spec.source)];
14260
14427
  const kind = declaredSeriesKind(spec.source);
@@ -14278,6 +14445,163 @@ function integralDraft(spec, retention = require_composition.DEFAULT_HISTORY_RET
14278
14445
  };
14279
14446
  }
14280
14447
  //#endregion
14448
+ //#region src/composition/helpers/compile-math.ts
14449
+ /**
14450
+ * Math helpers projected onto a new sensor (D944 phase 3). A threshold is the
14451
+ * `schmitt` builtin, a difference and a ratio are small expressions, a sum is
14452
+ * the group reducer (so an unreporting input is left out, not read as 0), and
14453
+ * a free expression is the expression engine unchanged — it still includes a
14454
+ * stale input, and the template says so.
14455
+ */
14456
+ var NOW = {
14457
+ kind: "expression",
14458
+ expr: "now",
14459
+ bindings: {}
14460
+ };
14461
+ function from$1(member) {
14462
+ return {
14463
+ kind: "from",
14464
+ source: member.source,
14465
+ cap: member.cap,
14466
+ fieldPath: member.fieldPath
14467
+ };
14468
+ }
14469
+ function expression$1(expr, bindings) {
14470
+ return {
14471
+ kind: "expression",
14472
+ expr,
14473
+ bindings
14474
+ };
14475
+ }
14476
+ function sameMember$1(a, b) {
14477
+ return a.source.addonId === b.source.addonId && a.source.stableId === b.source.stableId && a.cap === b.cap && a.fieldPath === b.fieldPath;
14478
+ }
14479
+ function numericSensor(helper, value, extra = []) {
14480
+ return {
14481
+ target: {
14482
+ kind: "new",
14483
+ type: require_err_msg.DeviceType.Sensor,
14484
+ role: require_err_msg.DeviceRole.NumericSensor
14485
+ },
14486
+ helper,
14487
+ features: [{
14488
+ kind: "fields",
14489
+ cap: "numeric-sensor",
14490
+ fields: {
14491
+ value,
14492
+ lastFetchedAt: NOW
14493
+ }
14494
+ }, ...extra]
14495
+ };
14496
+ }
14497
+ function binarySensor(helper, on) {
14498
+ return {
14499
+ target: {
14500
+ kind: "new",
14501
+ type: require_err_msg.DeviceType.Sensor,
14502
+ role: require_err_msg.DeviceRole.BinarySensor
14503
+ },
14504
+ helper,
14505
+ features: [{
14506
+ kind: "fields",
14507
+ cap: "binary",
14508
+ fields: {
14509
+ on,
14510
+ lastChangedAt: NOW
14511
+ }
14512
+ }]
14513
+ };
14514
+ }
14515
+ function thresholdDraft(spec) {
14516
+ const problems = [];
14517
+ const high = signedToken(spec.high);
14518
+ const low = signedToken(spec.low);
14519
+ if (high === null) problems.push(problem("kind-mismatch", "helper.high", "the high edge is a finite number"));
14520
+ if (low === null) problems.push(problem("kind-mismatch", "helper.low", "the low edge is a finite number"));
14521
+ if (high !== null && low !== null && spec.low > spec.high) problems.push(problem("kind-mismatch", "helper.low", `the low edge (${spec.low}) is above the high edge (${spec.high}) — it turns on at the high edge and off at the low one`));
14522
+ const onFor = unsignedToken(spec.onForMs);
14523
+ const offFor = unsignedToken(spec.offForMs);
14524
+ if (onFor === null || offFor === null) problems.push(problem("kind-mismatch", "helper.onForMs", "the on and off delays are a non-negative number of milliseconds"));
14525
+ const delays = onFor !== null && offFor !== null && (spec.onForMs > 0 || spec.offForMs > 0) ? `, ${onFor}, ${offFor}` : "";
14526
+ return {
14527
+ problems,
14528
+ draft: binarySensor(spec, expression$1(`coalesce(schmitt(x, ${high ?? "0"}, ${low ?? "0"}${delays}), false)`, { x: from$1(spec.source) }))
14529
+ };
14530
+ }
14531
+ var NAMES = ["a", "b"];
14532
+ function arithmeticProblems(spec) {
14533
+ const problems = [];
14534
+ const exactlyTwo = spec.op !== "sum";
14535
+ if (exactlyTwo && spec.inputs.length !== 2) problems.push(problem("member-constraint", "helper.inputs", `a ${spec.op} takes exactly two readings, the first ${spec.op === "ratio" ? "over" : "minus"} the second`));
14536
+ if (!exactlyTwo && spec.inputs.length < 2) problems.push(problem("member-constraint", "helper.inputs", "a sum takes two or more readings"));
14537
+ spec.inputs.forEach((input, index) => {
14538
+ if (spec.inputs.slice(0, index).some((other) => sameMember$1(other, input))) problems.push(problem("member-constraint", `helper.inputs[${index}]`, "this reading is already an input"));
14539
+ });
14540
+ return problems;
14541
+ }
14542
+ var GROUP_COUNTS = [
14543
+ "included",
14544
+ "excluded",
14545
+ "total"
14546
+ ];
14547
+ function arithmeticDraft(spec) {
14548
+ const problems = arithmeticProblems(spec);
14549
+ if (spec.op === "sum") {
14550
+ const reads = spec.inputs.map((input) => ({
14551
+ source: input.source,
14552
+ cap: input.cap,
14553
+ fieldPath: input.fieldPath
14554
+ }));
14555
+ const aggregate = (publish) => ({
14556
+ kind: "aggregate",
14557
+ reducer: "sum",
14558
+ reads,
14559
+ publish,
14560
+ empty: "null"
14561
+ });
14562
+ const counts = Object.fromEntries(GROUP_COUNTS.map((name) => [name, aggregate(name)]));
14563
+ return {
14564
+ problems,
14565
+ draft: numericSensor(spec, aggregate("value"), [{
14566
+ kind: "fields",
14567
+ cap: "group-status",
14568
+ fields: counts
14569
+ }])
14570
+ };
14571
+ }
14572
+ const bindings = Object.fromEntries(spec.inputs.slice(0, 2).map((input, index) => [NAMES[index] ?? "a", from$1(input)]));
14573
+ return {
14574
+ problems,
14575
+ draft: numericSensor(spec, expression$1(spec.op === "difference" ? "a - b" : "b == 0 ? null : a / b", bindings))
14576
+ };
14577
+ }
14578
+ function expressionProblems(spec) {
14579
+ const problems = [];
14580
+ const seen = /* @__PURE__ */ new Set();
14581
+ spec.inputs.forEach((input, index) => {
14582
+ const at = `helper.inputs[${index}].name`;
14583
+ if (!isIdentifier(input.name)) problems.push(problem("expression-invalid", at, `\`${input.name}\` is not a name — use letters, digits and _, starting with a letter`));
14584
+ if (seen.has(input.name)) problems.push(problem("expression-invalid", at, `the name \`${input.name}\` is used twice`));
14585
+ seen.add(input.name);
14586
+ });
14587
+ if (problems.length > 0) return problems;
14588
+ const bindings = Object.fromEntries(spec.inputs.map((input) => [input.name, from$1(input.member)]));
14589
+ const message = require_composition.validateExpressionSource({
14590
+ expr: spec.expr,
14591
+ bindings
14592
+ });
14593
+ return message === null ? [] : [problem("expression-invalid", "helper.expr", message)];
14594
+ }
14595
+ function expressionDraft(spec) {
14596
+ const problems = expressionProblems(spec);
14597
+ const bindings = Object.fromEntries(spec.inputs.map((input) => [input.name, from$1(input.member)]));
14598
+ const source = expression$1(spec.expr, bindings);
14599
+ return {
14600
+ problems,
14601
+ draft: spec.output === "boolean" ? binarySensor(spec, source) : numericSensor(spec, source)
14602
+ };
14603
+ }
14604
+ //#endregion
14281
14605
  //#region src/composition/helpers/compile.ts
14282
14606
  function sameSource(a, b) {
14283
14607
  return a.addonId === b.addonId && a.stableId === b.stableId;
@@ -14306,7 +14630,8 @@ function aggregateSource(template, spec, reads, publish) {
14306
14630
  reducer: spec.aggregate,
14307
14631
  reads: [...reads],
14308
14632
  publish,
14309
- empty: template.empty
14633
+ empty: template.empty,
14634
+ ...template.activeWhen === void 0 ? {} : { activeWhen: [...template.activeWhen] }
14310
14635
  };
14311
14636
  }
14312
14637
  function draftOf$1(template, spec) {
@@ -14441,8 +14766,26 @@ function compileHelper(spec, retention = require_composition.DEFAULT_HISTORY_RET
14441
14766
  };
14442
14767
  return parseDraft(built.draft);
14443
14768
  }
14769
+ case "derivative": {
14770
+ const built = derivativeDraft(spec, retention);
14771
+ if (built.problems.length > 0) return {
14772
+ ok: false,
14773
+ problems: built.problems
14774
+ };
14775
+ return parseDraft(built.draft);
14776
+ }
14777
+ case "threshold": return compileMath(thresholdDraft(spec));
14778
+ case "arithmetic": return compileMath(arithmeticDraft(spec));
14779
+ case "expression": return compileMath(expressionDraft(spec));
14444
14780
  }
14445
14781
  }
14782
+ function compileMath(built) {
14783
+ if (built.problems.length > 0) return {
14784
+ ok: false,
14785
+ problems: built.problems
14786
+ };
14787
+ return parseDraft(built.draft);
14788
+ }
14446
14789
  function compileGroup(spec) {
14447
14790
  const template = groupTemplate(spec.templateId);
14448
14791
  if (template === null) return {
@@ -14505,8 +14848,8 @@ function deviceTypeProblems(spec, facts) {
14505
14848
  if (template === null) return [];
14506
14849
  return spec.members.flatMap((member, index) => {
14507
14850
  const deviceType = facts.get(require_composition.compositionSourceKey(member.source))?.deviceType;
14508
- if (deviceType === void 0 || deviceType === template.memberDeviceType) return [];
14509
- return [problem("member-constraint", `helper.members[${index}]`, `a ${template.id} group takes ${template.memberDeviceType} devices; this member is a ${deviceType}`)];
14851
+ if (deviceType === void 0 || template.memberDeviceTypes.includes(deviceType)) return [];
14852
+ return [problem("member-constraint", `helper.members[${index}]`, `a ${template.id} group takes ${template.memberDeviceTypes.join(" or ")} devices; this member is a ${deviceType}`)];
14510
14853
  });
14511
14854
  }
14512
14855
  /**
@@ -14520,6 +14863,7 @@ function helperSaveProblems(composition, facts) {
14520
14863
  if (!compiled.ok) return compiled.problems;
14521
14864
  if (!sameHelperBody(composition, compiled.composition)) return [problem("helper-mismatch", "helper", "the stored features are not this template — the helper spec is the only writer")];
14522
14865
  if (spec.kind === "appliance") return applianceMemberProblems(spec.member, facts);
14866
+ if (spec.kind === "arithmetic") return arithmeticQuantityProblems(spec, facts);
14523
14867
  if (spec.kind !== "group") return [];
14524
14868
  return [...quantityProblems(spec, facts), ...deviceTypeProblems(spec, facts)];
14525
14869
  }
@@ -14531,6 +14875,21 @@ function applianceMemberProblems(member, facts) {
14531
14875
  if (fact.quantity !== void 0 && fact.quantity !== "power") problems.push(problem("mixed-quantity", "helper.member", `an appliance helper reads power (W); this member is ${fact.quantity}`));
14532
14876
  return problems;
14533
14877
  }
14878
+ /**
14879
+ * A sum, a difference and a ratio combine readings of ONE quantity. The ratio
14880
+ * of two powers is a plain number, but a power over an energy is not a ratio of
14881
+ * anything, so it is refused too. Inputs that did not report a quantity are not
14882
+ * guessed at.
14883
+ */
14884
+ function arithmeticQuantityProblems(spec, facts) {
14885
+ const known = spec.inputs.flatMap((input) => {
14886
+ const quantity = facts.get(require_composition.compositionSourceKey(input.source))?.quantity;
14887
+ return quantity === void 0 ? [] : [quantity];
14888
+ });
14889
+ const distinct = [...new Set(known)];
14890
+ if (distinct.length <= 1) return [];
14891
+ return [problem("mixed-quantity", "helper.inputs", `a ${spec.op} needs readings of one quantity; these inputs report ${distinct.join(" and ")}`)];
14892
+ }
14534
14893
  //#endregion
14535
14894
  //#region src/composition/composition-graph.ts
14536
14895
  /**
@@ -65697,7 +66056,17 @@ var groupCommandsCapability = {
65697
66056
  scope: "device",
65698
66057
  deviceNative: true,
65699
66058
  mode: "singleton",
65700
- deviceTypes: [require_err_msg.DeviceType.Switch, require_err_msg.DeviceType.Light],
66059
+ deviceTypes: [
66060
+ require_err_msg.DeviceType.Switch,
66061
+ require_err_msg.DeviceType.Light,
66062
+ require_err_msg.DeviceType.Fan,
66063
+ require_err_msg.DeviceType.Cover,
66064
+ require_err_msg.DeviceType.Valve,
66065
+ require_err_msg.DeviceType.Lock,
66066
+ require_err_msg.DeviceType.MediaPlayer,
66067
+ require_err_msg.DeviceType.Thermostat,
66068
+ require_err_msg.DeviceType.Climate
66069
+ ],
65701
66070
  methods: {},
65702
66071
  status: {
65703
66072
  schema: GroupCommandsSchema,
@@ -65715,6 +66084,51 @@ var groupCommandsCapability = {
65715
66084
  history: "none"
65716
66085
  };
65717
66086
  //#endregion
66087
+ //#region src/capabilities/group-active.cap.ts
66088
+ /**
66089
+ * Whether a helper actuator group counts as active (D944): at least one
66090
+ * included member is, or every included member is. What "active" means is the
66091
+ * type's: a cover is open, a lock is locked, a media player is playing, a
66092
+ * climate device is not off. A group of lights, switches and fans reports
66093
+ * `switch.on` instead; this cap is for the types whose own state is not a
66094
+ * yes/no. Unknown members are left out (`group-status` counts them) and an
66095
+ * empty included set takes the device offline, never `active: false`.
66096
+ */
66097
+ var GroupActiveSchema = zod.z.object({
66098
+ active: zod.z.boolean().meta({ label: "Active" }),
66099
+ /** Ms epoch when the slice was last updated. */
66100
+ lastChangedAt: zod.z.number()
66101
+ });
66102
+ var groupActiveCapability = {
66103
+ name: "group-active",
66104
+ scope: "device",
66105
+ deviceNative: true,
66106
+ mode: "singleton",
66107
+ deviceTypes: [
66108
+ require_err_msg.DeviceType.Cover,
66109
+ require_err_msg.DeviceType.Valve,
66110
+ require_err_msg.DeviceType.Lock,
66111
+ require_err_msg.DeviceType.MediaPlayer,
66112
+ require_err_msg.DeviceType.Climate,
66113
+ require_err_msg.DeviceType.Thermostat
66114
+ ],
66115
+ methods: {},
66116
+ status: {
66117
+ schema: GroupActiveSchema,
66118
+ kind: "push"
66119
+ },
66120
+ runtimeState: GroupActiveSchema,
66121
+ /**
66122
+ * Runtime-state durability: **session** — recomputed from the members on the
66123
+ * next source event; a restored value would outlive the members it named.
66124
+ *
66125
+ * See `RuntimeStateDurability`. Enforced by
66126
+ * `scripts/check-runtime-state-durability.ts`.
66127
+ */
66128
+ durability: "session",
66129
+ history: "none"
66130
+ };
66131
+ //#endregion
65718
66132
  //#region src/capabilities/group-status.cap.ts
65719
66133
  /**
65720
66134
  * How many members of a helper group answered (D944). Counts are integers,
@@ -65747,7 +66161,14 @@ var groupStatusCapability = {
65747
66161
  deviceTypes: [
65748
66162
  require_err_msg.DeviceType.Sensor,
65749
66163
  require_err_msg.DeviceType.Switch,
65750
- require_err_msg.DeviceType.Light
66164
+ require_err_msg.DeviceType.Light,
66165
+ require_err_msg.DeviceType.Fan,
66166
+ require_err_msg.DeviceType.Cover,
66167
+ require_err_msg.DeviceType.Valve,
66168
+ require_err_msg.DeviceType.Lock,
66169
+ require_err_msg.DeviceType.MediaPlayer,
66170
+ require_err_msg.DeviceType.Thermostat,
66171
+ require_err_msg.DeviceType.Climate
65751
66172
  ],
65752
66173
  methods: {},
65753
66174
  status: {
@@ -67249,7 +67670,14 @@ var lockControlCapability = {
67249
67670
  }),
67250
67671
  unlock: require_sleep.method(zod.z.object({
67251
67672
  deviceId: zod.z.number().int().nonnegative(),
67252
- code: zod.z.string().min(1).optional()
67673
+ code: zod.z.string().min(1).optional(),
67674
+ /**
67675
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
67676
+ * with one call is refused unless the caller says it was confirmed. A
67677
+ * single lock ignores it. The refusal lives in the callee, so no
67678
+ * automation or API caller reaches the doors by skipping a dialog.
67679
+ */
67680
+ confirm: zod.z.boolean().optional()
67253
67681
  }), zod.z.void(), {
67254
67682
  kind: "mutation",
67255
67683
  auth: "protected"
@@ -75781,7 +76209,8 @@ var switchCapability = {
75781
76209
  deviceTypes: [
75782
76210
  require_err_msg.DeviceType.Switch,
75783
76211
  require_err_msg.DeviceType.Siren,
75784
- require_err_msg.DeviceType.Light
76212
+ require_err_msg.DeviceType.Light,
76213
+ require_err_msg.DeviceType.Fan
75785
76214
  ],
75786
76215
  methods: { setState: require_sleep.method(zod.z.object({
75787
76216
  deviceId: zod.z.number(),
@@ -78666,13 +79095,116 @@ function createDeviceExtensionProvider(options) {
78666
79095
  };
78667
79096
  }
78668
79097
  //#endregion
79098
+ //#region src/composition/helpers/actuator-methods.ts
79099
+ /**
79100
+ * One method table per actuator type (D944). A group offers a method only
79101
+ * when every member can take it, so a command never reaches a member that
79102
+ * lacks the surface: the cap must be bound by every member (the primary cap of
79103
+ * the type is the exception — a member that lacks it is simply not commanded),
79104
+ * and a row that names a device feature needs every member to advertise it.
79105
+ * Offline does not remove a method: capability is the binding, not liveness.
79106
+ */
79107
+ var ACTUATOR_TEMPLATE_IDS = [
79108
+ "switch",
79109
+ "light",
79110
+ "fan",
79111
+ "cover",
79112
+ "valve",
79113
+ "lock",
79114
+ "media-player",
79115
+ "climate"
79116
+ ];
79117
+ function row$1(cap, method, requires = null, confirm = false) {
79118
+ return {
79119
+ cap,
79120
+ method,
79121
+ requires,
79122
+ confirm
79123
+ };
79124
+ }
79125
+ /** The first row's cap is the type's own: always offered, members without it are skipped. */
79126
+ var ACTUATOR_METHODS = {
79127
+ switch: [row$1("switch", "setState")],
79128
+ light: [
79129
+ row$1("switch", "setState"),
79130
+ row$1("brightness", "setBrightness"),
79131
+ row$1("color", "setColor")
79132
+ ],
79133
+ fan: [
79134
+ row$1("switch", "setState"),
79135
+ row$1("fan-control", "setPercentage", require_err_msg.DeviceFeature.FanSpeed),
79136
+ row$1("fan-control", "setPreset", require_err_msg.DeviceFeature.FanPreset),
79137
+ row$1("fan-control", "setDirection", require_err_msg.DeviceFeature.FanDirection),
79138
+ row$1("fan-control", "setOscillating", require_err_msg.DeviceFeature.FanOscillating)
79139
+ ],
79140
+ cover: [
79141
+ row$1("cover", "open"),
79142
+ row$1("cover", "close"),
79143
+ row$1("cover", "stop"),
79144
+ row$1("cover", "setPosition", require_err_msg.DeviceFeature.CoverPositionable),
79145
+ row$1("cover", "setTiltPosition", require_err_msg.DeviceFeature.CoverTilt)
79146
+ ],
79147
+ valve: [
79148
+ row$1("valve", "open"),
79149
+ row$1("valve", "close"),
79150
+ row$1("valve", "setPosition", require_err_msg.DeviceFeature.ValvePositionable)
79151
+ ],
79152
+ lock: [row$1("lock-control", "lock"), row$1("lock-control", "unlock", null, true)],
79153
+ "media-player": [
79154
+ row$1("media-player", "play"),
79155
+ row$1("media-player", "pause"),
79156
+ row$1("media-player", "setVolume", require_err_msg.DeviceFeature.MediaPlayerVolume)
79157
+ ],
79158
+ climate: [
79159
+ row$1("climate-control", "setMode"),
79160
+ row$1("climate-control", "setTarget"),
79161
+ row$1("climate-control", "setFanMode", require_err_msg.DeviceFeature.ClimateFanMode)
79162
+ ]
79163
+ };
79164
+ function actuatorMethodRow(templateId, cap, method) {
79165
+ return ACTUATOR_METHODS[templateId].find((item) => item.cap === cap && item.method === method) ?? null;
79166
+ }
79167
+ /**
79168
+ * The rows every member can take. An empty member list shares nothing; the
79169
+ * caller passes a surface for every member it could read, or none at all.
79170
+ */
79171
+ function sharedActuatorMethods(templateId, members) {
79172
+ if (members.length === 0) return [];
79173
+ const rows = ACTUATOR_METHODS[templateId];
79174
+ const primary = rows[0]?.cap;
79175
+ return rows.filter((item) => {
79176
+ if (!(item.cap === primary || members.every((member) => member.caps.includes(item.cap)))) return false;
79177
+ const needed = item.requires;
79178
+ return needed === null || members.every((member) => member.features.includes(needed));
79179
+ });
79180
+ }
79181
+ /** The device features every member has, among those the table gates on, in table order. */
79182
+ function sharedActuatorFeatures(templateId, featureLists) {
79183
+ if (featureLists.length === 0) return [];
79184
+ const gated = ACTUATOR_METHODS[templateId].flatMap((item) => item.requires === null ? [] : [item.requires]);
79185
+ return [...new Set(gated)].filter((feature) => featureLists.every((features) => features.includes(feature)));
79186
+ }
79187
+ var UNLOCK_CONFIRMATION = "unlocking a group of locks needs an explicit confirmation (confirm: true) — it was not given, so no lock was sent anything";
79188
+ /**
79189
+ * Why a call must not be fanned out, or null. Only a confirmed row passes
79190
+ * without `confirm: true`; anything else is the caller's to refuse by name.
79191
+ */
79192
+ function methodRefusal(method, args) {
79193
+ if (method === null) return "that method is not one this group shares";
79194
+ if (method.confirm && args.confirm !== true) return UNLOCK_CONFIRMATION;
79195
+ return null;
79196
+ }
79197
+ //#endregion
78669
79198
  //#region src/composition/helpers/aggregate.ts
78670
79199
  function isBinaryReducer(reducer) {
78671
79200
  return reducer === "any" || reducer === "all";
78672
79201
  }
78673
- function includedValue(reducer, member) {
79202
+ function includedValue(reducer, member, activeWhen) {
78674
79203
  if (member.state !== "fresh") return null;
78675
- if (isBinaryReducer(reducer)) return typeof member.value === "boolean" ? member.value : null;
79204
+ if (isBinaryReducer(reducer)) {
79205
+ if (activeWhen !== void 0) return typeof member.value === "string" ? activeWhen.includes(member.value) : null;
79206
+ return typeof member.value === "boolean" ? member.value : null;
79207
+ }
78676
79208
  return typeof member.value === "number" && Number.isFinite(member.value) ? member.value : null;
78677
79209
  }
78678
79210
  function median$1(values) {
@@ -78722,7 +79254,7 @@ function emptyOutcome(empty, counts) {
78722
79254
  /** Pure. `members` is not mutated. An empty included set is null or unavailable, never 0 or false. */
78723
79255
  function evaluateAggregate(input) {
78724
79256
  const included = input.members.flatMap((member) => {
78725
- const value = includedValue(input.reducer, member);
79257
+ const value = includedValue(input.reducer, member, input.activeWhen);
78726
79258
  return value === null ? [] : [value];
78727
79259
  });
78728
79260
  const counts = countsOf(included.length, input.members.length);
@@ -78768,12 +79300,12 @@ function evaluateAggregate(input) {
78768
79300
  //#region src/composition/helpers/source-pick.ts
78769
79301
  /** What the member step asks the selector for this template. */
78770
79302
  function sourcePickForTemplate(template) {
78771
- const valueKind = template.family === "numeric" ? "number" : "boolean";
79303
+ const valueKind = template.family === "numeric" ? "number" : template.activeWhen === void 0 ? "boolean" : "state";
78772
79304
  return {
78773
79305
  purpose: "member",
78774
79306
  multiple: true,
78775
79307
  max: 64,
78776
- deviceTypes: [template.memberDeviceType],
79308
+ deviceTypes: [...template.memberDeviceTypes],
78777
79309
  accept: template.accept.map((field) => ({
78778
79310
  ...field,
78779
79311
  valueKind
@@ -78782,7 +79314,7 @@ function sourcePickForTemplate(template) {
78782
79314
  required: false,
78783
79315
  minRetentionMs: null
78784
79316
  },
78785
- mustBindCaps: template.family === "actuator" ? [template.outputCap] : [],
79317
+ mustBindCaps: template.family === "actuator" ? template.accept.map((field) => field.cap) : [],
78786
79318
  exclude: []
78787
79319
  };
78788
79320
  }
@@ -78815,6 +79347,35 @@ function historyAccept(kind) {
78815
79347
  }
78816
79348
  return fields;
78817
79349
  }
79350
+ /**
79351
+ * What the input step asks the selector for a math helper. A threshold reads
79352
+ * one number, a difference or a ratio two, a sum and an expression several.
79353
+ * A derivative reads one historised number.
79354
+ */
79355
+ function sourcePickForMath(kind) {
79356
+ if (kind === "derivative") return {
79357
+ ...sourcePickForHistory("statistic"),
79358
+ accept: numericAccept()
79359
+ };
79360
+ const multiple = kind === "sum" || kind === "expression";
79361
+ const max = kind === "difference" || kind === "ratio" ? 2 : multiple ? 64 : 1;
79362
+ return {
79363
+ purpose: "reading",
79364
+ multiple: multiple || max > 1,
79365
+ max,
79366
+ deviceTypes: [],
79367
+ accept: numericAccept(),
79368
+ history: {
79369
+ required: false,
79370
+ minRetentionMs: null
79371
+ },
79372
+ mustBindCaps: [],
79373
+ exclude: []
79374
+ };
79375
+ }
79376
+ function numericAccept() {
79377
+ return historyAccept("statistic").filter((field) => field.valueKind === "number");
79378
+ }
78818
79379
  //#endregion
78819
79380
  //#region src/units/unit-table.ts
78820
79381
  /**
@@ -79417,6 +79978,7 @@ function aggregateRead(reading) {
79417
79978
  function aggregateField(source, read) {
79418
79979
  const outcome = evaluateAggregate({
79419
79980
  reducer: source.reducer,
79981
+ ...source.activeWhen === void 0 ? {} : { activeWhen: source.activeWhen },
79420
79982
  members: source.reads.map((item) => aggregateRead(read(item))),
79421
79983
  publish: source.publish,
79422
79984
  empty: source.empty
@@ -82211,6 +82773,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
82211
82773
  featureProbe: featureProbeCapability,
82212
82774
  flood: floodCapability,
82213
82775
  gas: gasCapability,
82776
+ groupActive: groupActiveCapability,
82214
82777
  groupCommands: groupCommandsCapability,
82215
82778
  groupStatus: groupStatusCapability,
82216
82779
  heatingValve: heatingValveCapability,
@@ -87550,6 +88113,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
87550
88113
  access: "view",
87551
88114
  role: "viewer"
87552
88115
  },
88116
+ "groupActive.getStatus": {
88117
+ capName: "group-active",
88118
+ capScope: "device",
88119
+ addonId: null,
88120
+ access: "view",
88121
+ role: "viewer"
88122
+ },
87553
88123
  "groupCommands.getStatus": {
87554
88124
  capName: "group-commands",
87555
88125
  capScope: "device",
@@ -94109,6 +94679,7 @@ var KNOWN_CAP_NAMES = [
94109
94679
  "filesystem-browse",
94110
94680
  "flood",
94111
94681
  "gas",
94682
+ "group-active",
94112
94683
  "group-commands",
94113
94684
  "group-status",
94114
94685
  "heating-valve",
@@ -94260,6 +94831,7 @@ var DEVICE_CAP_NAMES = [
94260
94831
  "feature-probe",
94261
94832
  "flood",
94262
94833
  "gas",
94834
+ "group-active",
94263
94835
  "group-commands",
94264
94836
  "group-status",
94265
94837
  "heating-valve",
@@ -97812,6 +98384,10 @@ var SENSOR_CAP_VOCABULARY = {
97812
98384
  icon: "flame"
97813
98385
  }]
97814
98386
  },
98387
+ "group-active": {
98388
+ scope: "device",
98389
+ noun: t("Group state", "Stato del gruppo")
98390
+ },
97815
98391
  "group-commands": {
97816
98392
  scope: "device",
97817
98393
  noun: t("Group command", "Comando di gruppo")
@@ -100066,6 +100642,7 @@ var CAP_NAMES_WITH_STATUS = [
100066
100642
  "feature-probe",
100067
100643
  "flood",
100068
100644
  "gas",
100645
+ "group-active",
100069
100646
  "group-commands",
100070
100647
  "group-status",
100071
100648
  "heating-valve",
@@ -100191,6 +100768,7 @@ var CAPABILITY_NAMES = {
100191
100768
  filesystemBrowse: "filesystem-browse",
100192
100769
  flood: "flood",
100193
100770
  gas: "gas",
100771
+ groupActive: "group-active",
100194
100772
  groupCommands: "group-commands",
100195
100773
  groupStatus: "group-status",
100196
100774
  heatingValve: "heating-valve",
@@ -100600,6 +101178,10 @@ var CAPABILITY_ROUTER_KEYS = [
100600
101178
  key: "gas",
100601
101179
  name: "gas"
100602
101180
  },
101181
+ {
101182
+ key: "groupActive",
101183
+ name: "group-active"
101184
+ },
100603
101185
  {
100604
101186
  key: "groupCommands",
100605
101187
  name: "group-commands"
@@ -101125,6 +101707,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
101125
101707
  filesystemBrowseCapability,
101126
101708
  floodCapability,
101127
101709
  gasCapability,
101710
+ groupActiveCapability,
101128
101711
  groupCommandsCapability,
101129
101712
  groupStatusCapability,
101130
101713
  heatingValveCapability,
@@ -102204,6 +102787,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
102204
102787
  form: "single",
102205
102788
  optional: false
102206
102789
  }],
102790
+ "groupActive.getStatus": [{
102791
+ name: "deviceId",
102792
+ form: "single",
102793
+ optional: false
102794
+ }],
102207
102795
  "groupCommands.getStatus": [{
102208
102796
  name: "deviceId",
102209
102797
  form: "single",
@@ -104230,7 +104818,7 @@ function getCapsByProviderKind(kind) {
104230
104818
  //#region src/generated/runtime-state-durability.ts
104231
104819
  /**
104232
104820
  * Per-cap runtime-state policy, projected from every `*.cap.ts` that declares
104233
- * `runtimeState`. 75 caps: 39 `restored`, 36 `session`.
104821
+ * `runtimeState`. 76 caps: 39 `restored`, 37 `session`.
104234
104822
  *
104235
104823
  * A cap absent from this map has no runtime-state slice at all. A cap PRESENT
104236
104824
  * with `durability: 'session'` has one and has decided not to keep it.
@@ -104348,6 +104936,10 @@ var RUNTIME_STATE_POLICY = {
104348
104936
  durability: "restored",
104349
104937
  volatileFields: ["lastChangedAt"]
104350
104938
  },
104939
+ "group-active": {
104940
+ durability: "session",
104941
+ volatileFields: []
104942
+ },
104351
104943
  "group-commands": {
104352
104944
  durability: "session",
104353
104945
  volatileFields: []
@@ -115950,6 +116542,8 @@ function armRemovalReconcile(opts) {
115950
116542
  exports.ACCESSORY_LABEL = ACCESSORY_LABEL;
115951
116543
  exports.ACCESS_ROLES = ACCESS_ROLES;
115952
116544
  exports.ACTIVE_CRITERIA = require_composition.ACTIVE_CRITERIA;
116545
+ exports.ACTUATOR_METHODS = ACTUATOR_METHODS;
116546
+ exports.ACTUATOR_TEMPLATE_IDS = ACTUATOR_TEMPLATE_IDS;
115953
116547
  exports.ADMIN_SCOPE = ADMIN_SCOPE;
115954
116548
  exports.AGENT_MDNS_QUERY_NAME = AGENT_MDNS_QUERY_NAME;
115955
116549
  exports.AGENT_MDNS_SERVICE_TYPE = AGENT_MDNS_SERVICE_TYPE;
@@ -115976,6 +116570,7 @@ exports.APP_FLOW_STATE_PREFIX = APP_FLOW_STATE_PREFIX;
115976
116570
  exports.APP_REFUSED_PATH = APP_REFUSED_PATH;
115977
116571
  exports.APP_START_REFUSAL_MESSAGES = APP_START_REFUSAL_MESSAGES;
115978
116572
  exports.ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT = ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT;
116573
+ exports.ARITHMETIC_OPS = require_composition.ARITHMETIC_OPS;
115979
116574
  exports.AUDIO_ANALYSIS_CAP_NAME = AUDIO_ANALYSIS_CAP_NAME;
115980
116575
  exports.AUDIO_BACKEND_CHOICES = AUDIO_BACKEND_CHOICES;
115981
116576
  exports.AUDIO_CHUNK_FORMATS = require_sleep.AUDIO_CHUNK_FORMATS;
@@ -116037,6 +116632,7 @@ exports.ArchiveManifestSchema = ArchiveManifestSchema;
116037
116632
  exports.ArchiveSqliteSnapshotSchema = ArchiveSqliteSnapshotSchema;
116038
116633
  exports.ArchivedDebugNoteQueryInputSchema = ArchivedDebugNoteQueryInputSchema;
116039
116634
  exports.ArchivedDebugNoteSchema = ArchivedDebugNoteSchema;
116635
+ exports.ArithmeticHelperSpecSchema = require_composition.ArithmeticHelperSpecSchema;
116040
116636
  exports.AttachmentMediaTypeSchema = AttachmentMediaTypeSchema;
116041
116637
  exports.AttachmentSchema = AttachmentSchema;
116042
116638
  exports.AudioAnalysisResultSchema = AudioAnalysisResultSchema;
@@ -116417,6 +117013,7 @@ exports.DEFAULT_TIMELAPSE_PREVIEW_TEXT = DEFAULT_TIMELAPSE_PREVIEW_TEXT;
116417
117013
  exports.DEFAULT_TOKEN_EXPIRY = require_sleep.DEFAULT_TOKEN_EXPIRY;
116418
117014
  exports.DEFAULT_VIEWER_SCOPE = DEFAULT_VIEWER_SCOPE;
116419
117015
  exports.DEFINITIVE_DEVICE_REFUSALS = DEFINITIVE_DEVICE_REFUSALS;
117016
+ exports.DERIVATIVE_UNITS = require_composition.DERIVATIVE_UNITS;
116420
117017
  exports.DERIVED_CAMERA_SILENCED_CAP_NAMES = DERIVED_CAMERA_SILENCED_CAP_NAMES;
116421
117018
  exports.DETAIL_CROP_PADDING_FIELD = DETAIL_CROP_PADDING_FIELD;
116422
117019
  exports.DETAIL_CROP_PADDING_KEY = DETAIL_CROP_PADDING_KEY;
@@ -116476,6 +117073,7 @@ exports.DeclareKindResultSchema = DeclareKindResultSchema;
116476
117073
  exports.DeclaredDevices = DeclaredDevices;
116477
117074
  exports.DecodedAudioChunkSchema = require_sleep.DecodedAudioChunkSchema;
116478
117075
  exports.DeleteIntegrationResultSchema = DeleteIntegrationResultSchema;
117076
+ exports.DerivativeHelperSpecSchema = require_composition.DerivativeHelperSpecSchema;
116479
117077
  exports.DetailCropConventionSchema = DetailCropConventionSchema;
116480
117078
  exports.DetectionCatalogClassMapSchema = DetectionCatalogClassMapSchema;
116481
117079
  exports.DetectionSourceSchema = DetectionSourceSchema;
@@ -116562,6 +117160,7 @@ exports.EXPRESSION_BUILTIN_NAMES = require_composition.EXPRESSION_BUILTIN_NAMES;
116562
117160
  exports.EXPRESSION_COMPILE_CACHE_CAPACITY = require_composition.EXPRESSION_COMPILE_CACHE_CAPACITY;
116563
117161
  exports.EXPRESSION_IDENTIFIER_RE = require_composition.EXPRESSION_IDENTIFIER_RE;
116564
117162
  exports.EXPRESSION_INJECTED_NOW = require_composition.EXPRESSION_INJECTED_NOW;
117163
+ exports.EXPRESSION_OUTPUTS = require_composition.EXPRESSION_OUTPUTS;
116565
117164
  exports.EXTENSION_HOST_DEVICE_TYPES = EXTENSION_HOST_DEVICE_TYPES;
116566
117165
  exports.EXTENSION_SLOTS = EXTENSION_SLOTS;
116567
117166
  exports.EXTENSION_SLOT_IDS = EXTENSION_SLOT_IDS;
@@ -116628,6 +117227,7 @@ exports.ExpressionBindingSourceSchema = ExpressionBindingSourceSchema;
116628
117227
  exports.ExpressionEvalError = require_composition.ExpressionEvalError;
116629
117228
  exports.ExpressionFieldBindingSchema = ExpressionFieldBindingSchema;
116630
117229
  exports.ExpressionGlobalBindingSchema = ExpressionGlobalBindingSchema;
117230
+ exports.ExpressionHelperSpecSchema = require_composition.ExpressionHelperSpecSchema;
116631
117231
  exports.ExpressionLiteralBindingSchema = ExpressionLiteralBindingSchema;
116632
117232
  exports.ExpressionParseError = require_composition.ExpressionParseError;
116633
117233
  exports.ExpressionSourceSchema = ExpressionSourceSchema;
@@ -116684,6 +117284,7 @@ exports.GetStreamWithCodecInputSchema = GetStreamWithCodecInputSchema;
116684
117284
  exports.GlobalMetricsSchema = GlobalMetricsSchema;
116685
117285
  exports.GridLayoutPatchSchema = GridLayoutPatchSchema;
116686
117286
  exports.GridLayoutViewSchema = GridLayoutViewSchema;
117287
+ exports.GroupActiveSchema = GroupActiveSchema;
116687
117288
  exports.GroupCommandResultSchema = GroupCommandResultSchema;
116688
117289
  exports.GroupCommandsSchema = GroupCommandsSchema;
116689
117290
  exports.GroupHelperSpecSchema = require_composition.GroupHelperSpecSchema;
@@ -117837,6 +118438,7 @@ exports.TerminalSessionInfoSchema = TerminalSessionInfoSchema;
117837
118438
  exports.TestConnectionResultSchema = TestConnectionResultSchema$1;
117838
118439
  exports.TestConnectionStatusEnum = TestConnectionStatusEnum;
117839
118440
  exports.TestResultSchema = TestResultSchema;
118441
+ exports.ThresholdHelperSpecSchema = require_composition.ThresholdHelperSpecSchema;
117840
118442
  exports.TimelapseRuleInputSchema = TimelapseRuleInputSchema;
117841
118443
  exports.TimelapseRulePatchSchema = TimelapseRulePatchSchema;
117842
118444
  exports.TimelapseRuleSchema = TimelapseRuleSchema;
@@ -117904,6 +118506,7 @@ exports.TransportPlaneSchema = TransportPlaneSchema;
117904
118506
  exports.TurnServerSchema = TurnServerSchema;
117905
118507
  exports.UNATTRIBUTED_BUCKET_KEY = UNATTRIBUTED_BUCKET_KEY;
117906
118508
  exports.UNIT_TABLE = UNIT_TABLE;
118509
+ exports.UNLOCK_CONFIRMATION = UNLOCK_CONFIRMATION;
117907
118510
  exports.USE_ROOT_MODEL_DEFAULTS = USE_ROOT_MODEL_DEFAULTS;
117908
118511
  exports.USE_ROOT_MODEL_SETTING_KEY = USE_ROOT_MODEL_SETTING_KEY;
117909
118512
  exports.UnifiedBrokerInfoSchema = BrokerInfoSchema;
@@ -118002,6 +118605,7 @@ exports.actionsForDeviceType = actionsForDeviceType;
118002
118605
  exports.actionsForDevices = actionsForDevices;
118003
118606
  exports.activateAlarmProfile = activateAlarmProfile;
118004
118607
  exports.activeForReducer = activeForReducer;
118608
+ exports.actuatorMethodRow = actuatorMethodRow;
118005
118609
  exports.addonCatalogHref = addonCatalogHref;
118006
118610
  exports.addonPagesCapability = addonPagesCapability;
118007
118611
  exports.addonPagesSourceCapability = addonPagesSourceCapability;
@@ -118038,6 +118642,7 @@ exports.applyModeDeviceListEdit = applyModeDeviceListEdit;
118038
118642
  exports.applyModelBoundSettings = applyModelBoundSettings;
118039
118643
  exports.applyNonBlockingEdit = applyNonBlockingEdit;
118040
118644
  exports.applySecureOnArmEdit = applySecureOnArmEdit;
118645
+ exports.arithmeticDraft = arithmeticDraft;
118041
118646
  exports.armRemovalReconcile = armRemovalReconcile;
118042
118647
  exports.arrayItemFieldPath = require_sleep.arrayItemFieldPath;
118043
118648
  exports.asBoolean = require_sleep.asBoolean;
@@ -118244,6 +118849,8 @@ exports.defineRecordKinds = require_sleep.defineRecordKinds;
118244
118849
  exports.dehydrateConfigField = require_sleep.dehydrateConfigField;
118245
118850
  exports.dehydrateSchema = require_sleep.dehydrateSchema;
118246
118851
  exports.deleteAlarmProfile = deleteAlarmProfile;
118852
+ exports.derivativeDraft = derivativeDraft;
118853
+ exports.derivativeUnitLabel = derivativeUnitLabel;
118247
118854
  exports.deriveBatteryPresence = deriveBatteryPresence;
118248
118855
  exports.deriveCameraSwitches = deriveCameraSwitches;
118249
118856
  exports.deriveDetailCropRect = deriveDetailCropRect;
@@ -118325,6 +118932,7 @@ exports.evaluateAggregate = evaluateAggregate;
118325
118932
  exports.evaluateAst = require_composition.evaluateAst;
118326
118933
  exports.evaluateCompositionField = evaluateCompositionField;
118327
118934
  exports.evaluateCount = require_composition.evaluateCount;
118935
+ exports.evaluateDerivative = require_composition.evaluateDerivative;
118328
118936
  exports.evaluateExpressionSource = require_composition.evaluateExpressionSource;
118329
118937
  exports.evaluatePoolMemory = evaluatePoolMemory;
118330
118938
  exports.evaluateRose = require_composition.evaluateRose;
@@ -118346,6 +118954,7 @@ exports.expandSystemEventClasses = expandSystemEventClasses;
118346
118954
  exports.exportSubjectOf = exportSubjectOf;
118347
118955
  exports.exposeBlockDevices = exposeBlockDevices;
118348
118956
  exports.expressionContainsBuiltinCall = expressionContainsBuiltinCall;
118957
+ exports.expressionDraft = expressionDraft;
118349
118958
  exports.extensionSlotRef = extensionSlotRef;
118350
118959
  exports.extractNestedAddonId = extractNestedAddonId;
118351
118960
  exports.extractSourceInfoFromMetadata = extractSourceInfoFromMetadata;
@@ -118397,6 +119006,7 @@ exports.gifFilterComplex = gifFilterComplex;
118397
119006
  exports.gifFromMp4Args = gifFromMp4Args;
118398
119007
  exports.globalSecretScope = require_sleep.globalSecretScope;
118399
119008
  exports.grantRowsOf = grantRowsOf;
119009
+ exports.groupActiveCapability = groupActiveCapability;
118400
119010
  exports.groupCommandsCapability = groupCommandsCapability;
118401
119011
  exports.groupStatusCapability = groupStatusCapability;
118402
119012
  exports.groupTemplate = groupTemplate;
@@ -118470,6 +119080,7 @@ exports.isEventKindLabelKey = isEventKindLabelKey;
118470
119080
  exports.isEventOwnerType = isEventOwnerType;
118471
119081
  exports.isFirstLevelMacroClass = isFirstLevelMacroClass;
118472
119082
  exports.isHeldBackTemplateVar = isHeldBackTemplateVar;
119083
+ exports.isHistoryHelper = require_composition.isHistoryHelper;
118473
119084
  exports.isIconKey = isIconKey;
118474
119085
  exports.isIsolatedBuiltin = isIsolatedBuiltin;
118475
119086
  exports.isKeychainStoredField = require_sleep.isKeychainStoredField;
@@ -118575,6 +119186,7 @@ exports.meshNetworkCapability = meshNetworkCapability;
118575
119186
  exports.meterCapability = meterCapability;
118576
119187
  exports.method = require_sleep.method;
118577
119188
  exports.methodAccessForHttpMethod = methodAccessForHttpMethod;
119189
+ exports.methodRefusal = methodRefusal;
118578
119190
  exports.methodRoleOf = methodRoleOf;
118579
119191
  exports.metricsProviderCapability = metricsProviderCapability;
118580
119192
  exports.migrateLegacyDeviceSignalConfig = migrateLegacyDeviceSignalConfig;
@@ -118887,6 +119499,8 @@ exports.settingValuesEqual = settingValuesEqual;
118887
119499
  exports.settingsBelow = settingsBelow;
118888
119500
  exports.settingsStoreCapability = settingsStoreCapability;
118889
119501
  exports.shareViewGrantOf = shareViewGrantOf;
119502
+ exports.sharedActuatorFeatures = sharedActuatorFeatures;
119503
+ exports.sharedActuatorMethods = sharedActuatorMethods;
118890
119504
  exports.sharedColorModes = sharedColorModes;
118891
119505
  exports.sharedLightCaps = sharedLightCaps;
118892
119506
  exports.shortHostname = shortHostname;
@@ -118903,6 +119517,7 @@ exports.smtpProviderCapability = smtpProviderCapability;
118903
119517
  exports.snapshotCapability = snapshotCapability;
118904
119518
  exports.sourcePickForAppliance = require_composition.sourcePickForAppliance;
118905
119519
  exports.sourcePickForHistory = sourcePickForHistory;
119520
+ exports.sourcePickForMath = sourcePickForMath;
118906
119521
  exports.sourcePickForTemplate = sourcePickForTemplate;
118907
119522
  exports.splitTranslationRef = splitTranslationRef;
118908
119523
  exports.squareAround = squareAround;
@@ -118975,6 +119590,7 @@ exports.templateVarSystemEventApplies = templateVarSystemEventApplies;
118975
119590
  exports.templateVarsFor = templateVarsFor;
118976
119591
  exports.terminalSessionCapability = terminalSessionCapability;
118977
119592
  exports.textToHtml = textToHtml;
119593
+ exports.thresholdDraft = thresholdDraft;
118978
119594
  exports.thresholdToBase = thresholdToBase;
118979
119595
  exports.thresholdToDisplay = thresholdToDisplay;
118980
119596
  exports.timeOfDayToMinutes = timeOfDayToMinutes;