@camstack/types 1.2.423 → 1.2.424

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 (46) hide show
  1. package/dist/addon.js +1 -1
  2. package/dist/addon.mjs +1 -1
  3. package/dist/capabilities/composer.cap.d.ts +6 -0
  4. package/dist/capabilities/core-blocks.cap.d.ts +43 -0
  5. package/dist/capabilities/group-active.cap.d.ts +46 -0
  6. package/dist/capabilities/group-commands.cap.d.ts +1 -1
  7. package/dist/capabilities/group-status.cap.d.ts +1 -1
  8. package/dist/capabilities/index.d.ts +3 -1
  9. package/dist/capabilities/lock-control.cap.d.ts +1 -0
  10. package/dist/capabilities/switch.cap.d.ts +1 -1
  11. package/dist/client.js +3 -0
  12. package/dist/client.mjs +3 -0
  13. package/dist/composition/composition-report.d.ts +2 -0
  14. package/dist/composition/composition.d.ts +9 -0
  15. package/dist/composition/helpers/actuator-methods.d.ts +39 -0
  16. package/dist/composition/helpers/aggregate.d.ts +2 -0
  17. package/dist/composition/helpers/catalog.d.ts +7 -1
  18. package/dist/composition/helpers/compile-history.d.ts +16 -1
  19. package/dist/composition/helpers/compile-math.d.ts +9 -0
  20. package/dist/composition/helpers/history-math.d.ts +8 -0
  21. package/dist/composition/helpers/index.d.ts +6 -4
  22. package/dist/composition/helpers/source-pick.d.ts +8 -1
  23. package/dist/composition/helpers/spec.d.ts +49 -3
  24. package/dist/{composition-CpETZ4HL.mjs → composition-Bb8iwHEJ.mjs} +175 -5
  25. package/dist/{composition-CPRAP41h.js → composition-CpAc0YfQ.js} +228 -4
  26. package/dist/device/cap-vocabulary/entries/sensors.d.ts +1 -1
  27. package/dist/expression/builtins.d.ts +11 -2
  28. package/dist/expression/expression-source.d.ts +6 -1
  29. package/dist/generated/addon-api.d.ts +14 -0
  30. package/dist/generated/addon-cap-facts.d.ts +1 -1
  31. package/dist/generated/cap-status-types.d.ts +3 -1
  32. package/dist/generated/capability-router-map.d.ts +5 -2
  33. package/dist/generated/device-local-state.d.ts +3 -0
  34. package/dist/generated/device-proxy.d.ts +3 -0
  35. package/dist/generated/device-scoped-caps.d.ts +1 -1
  36. package/dist/generated/history-catalog.d.ts +1 -1
  37. package/dist/generated/method-access-map.d.ts +1 -1
  38. package/dist/generated/method-device-selectors.d.ts +1 -1
  39. package/dist/generated/runtime-state-durability.d.ts +1 -1
  40. package/dist/index.js +634 -33
  41. package/dist/index.mjs +611 -34
  42. package/dist/node.js +1 -1
  43. package/dist/node.mjs +1 -1
  44. package/dist/{sleep-0sD_LHLI.mjs → sleep--jXS9hWo.mjs} +10 -1
  45. package/dist/{sleep-CEKGW7A5.js → sleep-edKiOXLo.js} +10 -1
  46. 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");
@@ -12922,6 +12922,10 @@ var BUILTIN_RESULT_KINDS = Object.freeze({
12922
12922
  latchedAt: {
12923
12923
  kind: "fixed",
12924
12924
  result: ["number", "null"]
12925
+ },
12926
+ schmitt: {
12927
+ kind: "fixed",
12928
+ result: ["boolean", "null"]
12925
12929
  }
12926
12930
  });
12927
12931
  var KindInferenceError = class extends Error {};
@@ -13286,7 +13290,7 @@ function planItems(def, feature, featureIndex, lookupCap, mode = "new") {
13286
13290
  * One catalog row per base reading a group helper can build (D944 §3).
13287
13291
  * Data, not a form default written into the block.
13288
13292
  */
13289
- var NOW$1 = {
13293
+ var NOW$2 = {
13290
13294
  fieldPath: "lastFetchedAt",
13291
13295
  expr: "now"
13292
13296
  };
@@ -13300,6 +13304,8 @@ function numeric(input) {
13300
13304
  family: "numeric",
13301
13305
  deviceType: require_err_msg.DeviceType.Sensor,
13302
13306
  memberDeviceType: require_err_msg.DeviceType.Sensor,
13307
+ memberDeviceTypes: [require_err_msg.DeviceType.Sensor],
13308
+ activeWhen: void 0,
13303
13309
  commandCaps: [],
13304
13310
  baseUnit: require_sleep.baseUnitOf(input.quantity),
13305
13311
  aggregates: require_composition.NUMERIC_AGGREGATES,
@@ -13315,6 +13321,8 @@ function binary(input) {
13315
13321
  family: "binary",
13316
13322
  deviceType: require_err_msg.DeviceType.Sensor,
13317
13323
  memberDeviceType: require_err_msg.DeviceType.Sensor,
13324
+ memberDeviceTypes: [require_err_msg.DeviceType.Sensor],
13325
+ activeWhen: void 0,
13318
13326
  commandCaps: [],
13319
13327
  quantity: "none",
13320
13328
  baseUnit: void 0,
@@ -13332,7 +13340,7 @@ var GROUP_TEMPLATES = [
13332
13340
  quantity: "temperature",
13333
13341
  defaultAggregate: "mean",
13334
13342
  empty: "null",
13335
- companions: [NOW$1]
13343
+ companions: [NOW$2]
13336
13344
  }),
13337
13345
  numeric({
13338
13346
  id: "humidity",
@@ -13343,7 +13351,7 @@ var GROUP_TEMPLATES = [
13343
13351
  quantity: "humidity",
13344
13352
  defaultAggregate: "mean",
13345
13353
  empty: "null",
13346
- companions: [NOW$1]
13354
+ companions: [NOW$2]
13347
13355
  }),
13348
13356
  numeric({
13349
13357
  id: "pressure",
@@ -13354,7 +13362,7 @@ var GROUP_TEMPLATES = [
13354
13362
  quantity: "pressure",
13355
13363
  defaultAggregate: "mean",
13356
13364
  empty: "null",
13357
- companions: [NOW$1]
13365
+ companions: [NOW$2]
13358
13366
  }),
13359
13367
  numeric({
13360
13368
  id: "illuminance",
@@ -13365,7 +13373,7 @@ var GROUP_TEMPLATES = [
13365
13373
  quantity: "illuminance",
13366
13374
  defaultAggregate: "mean",
13367
13375
  empty: "null",
13368
- companions: [NOW$1]
13376
+ companions: [NOW$2]
13369
13377
  }),
13370
13378
  numeric({
13371
13379
  id: "power",
@@ -13376,7 +13384,7 @@ var GROUP_TEMPLATES = [
13376
13384
  quantity: "power",
13377
13385
  defaultAggregate: "sum",
13378
13386
  empty: "omit",
13379
- companions: [NOW$1]
13387
+ companions: [NOW$2]
13380
13388
  }),
13381
13389
  numeric({
13382
13390
  id: "energy",
@@ -13387,7 +13395,7 @@ var GROUP_TEMPLATES = [
13387
13395
  quantity: "energy",
13388
13396
  defaultAggregate: "sum",
13389
13397
  empty: "omit",
13390
- companions: [NOW$1]
13398
+ companions: [NOW$2]
13391
13399
  }),
13392
13400
  numeric({
13393
13401
  id: "battery",
@@ -13422,7 +13430,7 @@ var GROUP_TEMPLATES = [
13422
13430
  quantity: "device",
13423
13431
  defaultAggregate: "mean",
13424
13432
  empty: "null",
13425
- companions: [NOW$1]
13433
+ companions: [NOW$2]
13426
13434
  }),
13427
13435
  binary({
13428
13436
  id: "motion",
@@ -13516,6 +13524,11 @@ var GROUP_TEMPLATES = [
13516
13524
  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
13525
  deviceType: require_err_msg.DeviceType.Switch,
13518
13526
  outputCap: "switch",
13527
+ outputField: "on",
13528
+ member: {
13529
+ cap: "switch",
13530
+ fieldPath: "on"
13531
+ },
13519
13532
  commandCaps: ["switch"]
13520
13533
  }),
13521
13534
  actuator({
@@ -13523,29 +13536,130 @@ var GROUP_TEMPLATES = [
13523
13536
  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
13537
  deviceType: require_err_msg.DeviceType.Light,
13525
13538
  outputCap: "switch",
13539
+ outputField: "on",
13540
+ member: {
13541
+ cap: "switch",
13542
+ fieldPath: "on"
13543
+ },
13526
13544
  commandCaps: [
13527
13545
  "switch",
13528
13546
  "brightness",
13529
13547
  "color"
13530
13548
  ]
13549
+ }),
13550
+ actuator({
13551
+ id: "fan",
13552
+ 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.",
13553
+ deviceType: require_err_msg.DeviceType.Fan,
13554
+ outputCap: "switch",
13555
+ outputField: "on",
13556
+ member: {
13557
+ cap: "switch",
13558
+ fieldPath: "on"
13559
+ },
13560
+ commandCaps: ["switch", "fan-control"]
13561
+ }),
13562
+ actuator({
13563
+ id: "cover",
13564
+ 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.",
13565
+ deviceType: require_err_msg.DeviceType.Cover,
13566
+ outputCap: "group-active",
13567
+ outputField: "active",
13568
+ member: {
13569
+ cap: "cover",
13570
+ fieldPath: "state"
13571
+ },
13572
+ activeWhen: [
13573
+ "open",
13574
+ "opening",
13575
+ "stopped"
13576
+ ],
13577
+ commandCaps: ["cover"]
13578
+ }),
13579
+ actuator({
13580
+ id: "valve",
13581
+ 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.",
13582
+ deviceType: require_err_msg.DeviceType.Valve,
13583
+ outputCap: "group-active",
13584
+ outputField: "active",
13585
+ member: {
13586
+ cap: "valve",
13587
+ fieldPath: "state"
13588
+ },
13589
+ activeWhen: [
13590
+ "open",
13591
+ "opening",
13592
+ "stopped"
13593
+ ],
13594
+ commandCaps: ["valve"]
13595
+ }),
13596
+ actuator({
13597
+ id: "lock",
13598
+ 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.",
13599
+ deviceType: require_err_msg.DeviceType.Lock,
13600
+ outputCap: "group-active",
13601
+ outputField: "active",
13602
+ member: {
13603
+ cap: "lock-control",
13604
+ fieldPath: "state"
13605
+ },
13606
+ activeWhen: ["locked"],
13607
+ commandCaps: ["lock-control"]
13608
+ }),
13609
+ actuator({
13610
+ id: "media-player",
13611
+ 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.",
13612
+ deviceType: require_err_msg.DeviceType.MediaPlayer,
13613
+ outputCap: "group-active",
13614
+ outputField: "active",
13615
+ member: {
13616
+ cap: "media-player",
13617
+ fieldPath: "state"
13618
+ },
13619
+ activeWhen: ["playing", "buffering"],
13620
+ commandCaps: ["media-player"]
13621
+ }),
13622
+ actuator({
13623
+ id: "climate",
13624
+ 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.",
13625
+ deviceType: require_err_msg.DeviceType.Thermostat,
13626
+ memberDeviceTypes: [require_err_msg.DeviceType.Thermostat, require_err_msg.DeviceType.Climate],
13627
+ outputCap: "group-active",
13628
+ outputField: "active",
13629
+ member: {
13630
+ cap: "climate-control",
13631
+ fieldPath: "mode"
13632
+ },
13633
+ activeWhen: [
13634
+ "heat",
13635
+ "cool",
13636
+ "auto",
13637
+ "heat_cool",
13638
+ "fan_only",
13639
+ "dry"
13640
+ ],
13641
+ commandCaps: ["climate-control"]
13531
13642
  })
13532
13643
  ];
13533
13644
  function actuator(input) {
13534
13645
  return {
13535
- ...input,
13646
+ id: input.id,
13647
+ summary: input.summary,
13648
+ deviceType: input.deviceType,
13649
+ outputCap: input.outputCap,
13650
+ outputField: input.outputField,
13651
+ commandCaps: input.commandCaps,
13536
13652
  family: "actuator",
13537
13653
  role: void 0,
13538
13654
  memberDeviceType: input.deviceType,
13539
- outputField: "on",
13655
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
13656
+ activeWhen: input.activeWhen,
13540
13657
  quantity: "none",
13541
13658
  baseUnit: void 0,
13542
13659
  aggregates: require_composition.BINARY_AGGREGATES,
13543
13660
  defaultAggregate: "any",
13544
13661
  empty: "offline",
13545
- accept: [{
13546
- cap: "switch",
13547
- fieldPath: "on"
13548
- }],
13662
+ accept: [input.member],
13549
13663
  companions: [CHANGED]
13550
13664
  };
13551
13665
  }
@@ -13742,7 +13856,7 @@ async function runFanOut(calls, invoke) {
13742
13856
  //#region src/generated/history-catalog.ts
13743
13857
  /**
13744
13858
  * Cap history catalog, projected from every `*.cap.ts` `history` block.
13745
- * 42 caps with series (76 series), 32 caps answered `'none'`.
13859
+ * 42 caps with series (76 series), 33 caps answered `'none'`.
13746
13860
  * Field keys are `runtimeState` paths (`a.b` into fixed objects only).
13747
13861
  */
13748
13862
  var HISTORY_CATALOG = {
@@ -14148,6 +14262,7 @@ var HISTORY_NONE_CAPS = [
14148
14262
  "doorbell",
14149
14263
  "event-emitter",
14150
14264
  "feature-probe",
14265
+ "group-active",
14151
14266
  "group-commands",
14152
14267
  "group-status",
14153
14268
  "image",
@@ -14181,7 +14296,7 @@ function historyFieldsFor(capName) {
14181
14296
  * Project a statistics or integral helper onto a new device (D944 §3).
14182
14297
  * The value field is `series`: the composer fills it from history.
14183
14298
  */
14184
- var NOW = {
14299
+ var NOW$1 = {
14185
14300
  kind: "expression",
14186
14301
  expr: "now",
14187
14302
  bindings: {}
@@ -14205,6 +14320,20 @@ function counts(member) {
14205
14320
  total: series(member, "total", "offline")
14206
14321
  };
14207
14322
  }
14323
+ var PER_SYMBOL = {
14324
+ second: "s",
14325
+ minute: "min",
14326
+ hour: "h"
14327
+ };
14328
+ /**
14329
+ * The unit of a rate: the source series' unit per second, minute or hour
14330
+ * (`°C/h`). A source with no unit of its own (a generic number) has none to
14331
+ * borrow, so the label is null and the chart shows the bare number.
14332
+ */
14333
+ function derivativeUnitLabel(spec) {
14334
+ const unit = historyFieldsFor(spec.source.cap)[spec.source.fieldPath]?.unit;
14335
+ return unit === void 0 ? null : `${unit}/${PER_SYMBOL[spec.per]}`;
14336
+ }
14208
14337
  function declaredSeriesKind(member) {
14209
14338
  const field = historyFieldsFor(member.cap)[member.fieldPath];
14210
14339
  if (field === void 0) return null;
@@ -14227,7 +14356,7 @@ function draft(input) {
14227
14356
  cap: input.cap,
14228
14357
  fields: {
14229
14358
  [input.field]: series(input.member, "value", input.empty),
14230
- lastFetchedAt: NOW
14359
+ lastFetchedAt: NOW$1
14231
14360
  }
14232
14361
  }, {
14233
14362
  kind: "fields",
@@ -14255,6 +14384,29 @@ function statisticDraft(spec, retention = require_composition.DEFAULT_HISTORY_RE
14255
14384
  })
14256
14385
  };
14257
14386
  }
14387
+ /**
14388
+ * A derivative reads a gauge or a counter and publishes its rate per second,
14389
+ * minute or hour. The output is a plain number: a rate of a temperature is not
14390
+ * a temperature, so the chart carries no inherited unit.
14391
+ */
14392
+ function derivativeDraft(spec, retention = require_composition.DEFAULT_HISTORY_RETENTION) {
14393
+ const problems = [...historyProblems(spec.source)];
14394
+ const kind = declaredSeriesKind(spec.source);
14395
+ 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"));
14396
+ const tier = require_composition.planStatisticTier(spec.window, retention);
14397
+ if (!tier.ok) problems.push(problem("retention", "helper.window", tier.reason));
14398
+ return {
14399
+ problems,
14400
+ draft: draft({
14401
+ role: require_err_msg.DeviceRole.NumericSensor,
14402
+ cap: "numeric-sensor",
14403
+ field: "value",
14404
+ empty: "null",
14405
+ spec,
14406
+ member: spec.source
14407
+ })
14408
+ };
14409
+ }
14258
14410
  function integralDraft(spec, retention = require_composition.DEFAULT_HISTORY_RETENTION) {
14259
14411
  const problems = [...historyProblems(spec.source)];
14260
14412
  const kind = declaredSeriesKind(spec.source);
@@ -14278,6 +14430,163 @@ function integralDraft(spec, retention = require_composition.DEFAULT_HISTORY_RET
14278
14430
  };
14279
14431
  }
14280
14432
  //#endregion
14433
+ //#region src/composition/helpers/compile-math.ts
14434
+ /**
14435
+ * Math helpers projected onto a new sensor (D944 phase 3). A threshold is the
14436
+ * `schmitt` builtin, a difference and a ratio are small expressions, a sum is
14437
+ * the group reducer (so an unreporting input is left out, not read as 0), and
14438
+ * a free expression is the expression engine unchanged — it still includes a
14439
+ * stale input, and the template says so.
14440
+ */
14441
+ var NOW = {
14442
+ kind: "expression",
14443
+ expr: "now",
14444
+ bindings: {}
14445
+ };
14446
+ function from$1(member) {
14447
+ return {
14448
+ kind: "from",
14449
+ source: member.source,
14450
+ cap: member.cap,
14451
+ fieldPath: member.fieldPath
14452
+ };
14453
+ }
14454
+ function expression$1(expr, bindings) {
14455
+ return {
14456
+ kind: "expression",
14457
+ expr,
14458
+ bindings
14459
+ };
14460
+ }
14461
+ function sameMember$1(a, b) {
14462
+ return a.source.addonId === b.source.addonId && a.source.stableId === b.source.stableId && a.cap === b.cap && a.fieldPath === b.fieldPath;
14463
+ }
14464
+ function numericSensor(helper, value, extra = []) {
14465
+ return {
14466
+ target: {
14467
+ kind: "new",
14468
+ type: require_err_msg.DeviceType.Sensor,
14469
+ role: require_err_msg.DeviceRole.NumericSensor
14470
+ },
14471
+ helper,
14472
+ features: [{
14473
+ kind: "fields",
14474
+ cap: "numeric-sensor",
14475
+ fields: {
14476
+ value,
14477
+ lastFetchedAt: NOW
14478
+ }
14479
+ }, ...extra]
14480
+ };
14481
+ }
14482
+ function binarySensor(helper, on) {
14483
+ return {
14484
+ target: {
14485
+ kind: "new",
14486
+ type: require_err_msg.DeviceType.Sensor,
14487
+ role: require_err_msg.DeviceRole.BinarySensor
14488
+ },
14489
+ helper,
14490
+ features: [{
14491
+ kind: "fields",
14492
+ cap: "binary",
14493
+ fields: {
14494
+ on,
14495
+ lastChangedAt: NOW
14496
+ }
14497
+ }]
14498
+ };
14499
+ }
14500
+ function thresholdDraft(spec) {
14501
+ const problems = [];
14502
+ const high = signedToken(spec.high);
14503
+ const low = signedToken(spec.low);
14504
+ if (high === null) problems.push(problem("kind-mismatch", "helper.high", "the high edge is a finite number"));
14505
+ if (low === null) problems.push(problem("kind-mismatch", "helper.low", "the low edge is a finite number"));
14506
+ 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`));
14507
+ const onFor = unsignedToken(spec.onForMs);
14508
+ const offFor = unsignedToken(spec.offForMs);
14509
+ if (onFor === null || offFor === null) problems.push(problem("kind-mismatch", "helper.onForMs", "the on and off delays are a non-negative number of milliseconds"));
14510
+ const delays = onFor !== null && offFor !== null && (spec.onForMs > 0 || spec.offForMs > 0) ? `, ${onFor}, ${offFor}` : "";
14511
+ return {
14512
+ problems,
14513
+ draft: binarySensor(spec, expression$1(`coalesce(schmitt(x, ${high ?? "0"}, ${low ?? "0"}${delays}), false)`, { x: from$1(spec.source) }))
14514
+ };
14515
+ }
14516
+ var NAMES = ["a", "b"];
14517
+ function arithmeticProblems(spec) {
14518
+ const problems = [];
14519
+ const exactlyTwo = spec.op !== "sum";
14520
+ 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`));
14521
+ if (!exactlyTwo && spec.inputs.length < 2) problems.push(problem("member-constraint", "helper.inputs", "a sum takes two or more readings"));
14522
+ spec.inputs.forEach((input, index) => {
14523
+ 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"));
14524
+ });
14525
+ return problems;
14526
+ }
14527
+ var GROUP_COUNTS = [
14528
+ "included",
14529
+ "excluded",
14530
+ "total"
14531
+ ];
14532
+ function arithmeticDraft(spec) {
14533
+ const problems = arithmeticProblems(spec);
14534
+ if (spec.op === "sum") {
14535
+ const reads = spec.inputs.map((input) => ({
14536
+ source: input.source,
14537
+ cap: input.cap,
14538
+ fieldPath: input.fieldPath
14539
+ }));
14540
+ const aggregate = (publish) => ({
14541
+ kind: "aggregate",
14542
+ reducer: "sum",
14543
+ reads,
14544
+ publish,
14545
+ empty: "null"
14546
+ });
14547
+ const counts = Object.fromEntries(GROUP_COUNTS.map((name) => [name, aggregate(name)]));
14548
+ return {
14549
+ problems,
14550
+ draft: numericSensor(spec, aggregate("value"), [{
14551
+ kind: "fields",
14552
+ cap: "group-status",
14553
+ fields: counts
14554
+ }])
14555
+ };
14556
+ }
14557
+ const bindings = Object.fromEntries(spec.inputs.slice(0, 2).map((input, index) => [NAMES[index] ?? "a", from$1(input)]));
14558
+ return {
14559
+ problems,
14560
+ draft: numericSensor(spec, expression$1(spec.op === "difference" ? "a - b" : "b == 0 ? null : a / b", bindings))
14561
+ };
14562
+ }
14563
+ function expressionProblems(spec) {
14564
+ const problems = [];
14565
+ const seen = /* @__PURE__ */ new Set();
14566
+ spec.inputs.forEach((input, index) => {
14567
+ const at = `helper.inputs[${index}].name`;
14568
+ if (!isIdentifier(input.name)) problems.push(problem("expression-invalid", at, `\`${input.name}\` is not a name — use letters, digits and _, starting with a letter`));
14569
+ if (seen.has(input.name)) problems.push(problem("expression-invalid", at, `the name \`${input.name}\` is used twice`));
14570
+ seen.add(input.name);
14571
+ });
14572
+ if (problems.length > 0) return problems;
14573
+ const bindings = Object.fromEntries(spec.inputs.map((input) => [input.name, from$1(input.member)]));
14574
+ const message = require_composition.validateExpressionSource({
14575
+ expr: spec.expr,
14576
+ bindings
14577
+ });
14578
+ return message === null ? [] : [problem("expression-invalid", "helper.expr", message)];
14579
+ }
14580
+ function expressionDraft(spec) {
14581
+ const problems = expressionProblems(spec);
14582
+ const bindings = Object.fromEntries(spec.inputs.map((input) => [input.name, from$1(input.member)]));
14583
+ const source = expression$1(spec.expr, bindings);
14584
+ return {
14585
+ problems,
14586
+ draft: spec.output === "boolean" ? binarySensor(spec, source) : numericSensor(spec, source)
14587
+ };
14588
+ }
14589
+ //#endregion
14281
14590
  //#region src/composition/helpers/compile.ts
14282
14591
  function sameSource(a, b) {
14283
14592
  return a.addonId === b.addonId && a.stableId === b.stableId;
@@ -14306,7 +14615,8 @@ function aggregateSource(template, spec, reads, publish) {
14306
14615
  reducer: spec.aggregate,
14307
14616
  reads: [...reads],
14308
14617
  publish,
14309
- empty: template.empty
14618
+ empty: template.empty,
14619
+ ...template.activeWhen === void 0 ? {} : { activeWhen: [...template.activeWhen] }
14310
14620
  };
14311
14621
  }
14312
14622
  function draftOf$1(template, spec) {
@@ -14441,8 +14751,26 @@ function compileHelper(spec, retention = require_composition.DEFAULT_HISTORY_RET
14441
14751
  };
14442
14752
  return parseDraft(built.draft);
14443
14753
  }
14754
+ case "derivative": {
14755
+ const built = derivativeDraft(spec, retention);
14756
+ if (built.problems.length > 0) return {
14757
+ ok: false,
14758
+ problems: built.problems
14759
+ };
14760
+ return parseDraft(built.draft);
14761
+ }
14762
+ case "threshold": return compileMath(thresholdDraft(spec));
14763
+ case "arithmetic": return compileMath(arithmeticDraft(spec));
14764
+ case "expression": return compileMath(expressionDraft(spec));
14444
14765
  }
14445
14766
  }
14767
+ function compileMath(built) {
14768
+ if (built.problems.length > 0) return {
14769
+ ok: false,
14770
+ problems: built.problems
14771
+ };
14772
+ return parseDraft(built.draft);
14773
+ }
14446
14774
  function compileGroup(spec) {
14447
14775
  const template = groupTemplate(spec.templateId);
14448
14776
  if (template === null) return {
@@ -14505,8 +14833,8 @@ function deviceTypeProblems(spec, facts) {
14505
14833
  if (template === null) return [];
14506
14834
  return spec.members.flatMap((member, index) => {
14507
14835
  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}`)];
14836
+ if (deviceType === void 0 || template.memberDeviceTypes.includes(deviceType)) return [];
14837
+ return [problem("member-constraint", `helper.members[${index}]`, `a ${template.id} group takes ${template.memberDeviceTypes.join(" or ")} devices; this member is a ${deviceType}`)];
14510
14838
  });
14511
14839
  }
14512
14840
  /**
@@ -14520,6 +14848,7 @@ function helperSaveProblems(composition, facts) {
14520
14848
  if (!compiled.ok) return compiled.problems;
14521
14849
  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
14850
  if (spec.kind === "appliance") return applianceMemberProblems(spec.member, facts);
14851
+ if (spec.kind === "arithmetic") return arithmeticQuantityProblems(spec, facts);
14523
14852
  if (spec.kind !== "group") return [];
14524
14853
  return [...quantityProblems(spec, facts), ...deviceTypeProblems(spec, facts)];
14525
14854
  }
@@ -14531,6 +14860,21 @@ function applianceMemberProblems(member, facts) {
14531
14860
  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
14861
  return problems;
14533
14862
  }
14863
+ /**
14864
+ * A sum, a difference and a ratio combine readings of ONE quantity. The ratio
14865
+ * of two powers is a plain number, but a power over an energy is not a ratio of
14866
+ * anything, so it is refused too. Inputs that did not report a quantity are not
14867
+ * guessed at.
14868
+ */
14869
+ function arithmeticQuantityProblems(spec, facts) {
14870
+ const known = spec.inputs.flatMap((input) => {
14871
+ const quantity = facts.get(require_composition.compositionSourceKey(input.source))?.quantity;
14872
+ return quantity === void 0 ? [] : [quantity];
14873
+ });
14874
+ const distinct = [...new Set(known)];
14875
+ if (distinct.length <= 1) return [];
14876
+ return [problem("mixed-quantity", "helper.inputs", `a ${spec.op} needs readings of one quantity; these inputs report ${distinct.join(" and ")}`)];
14877
+ }
14534
14878
  //#endregion
14535
14879
  //#region src/composition/composition-graph.ts
14536
14880
  /**
@@ -65697,7 +66041,17 @@ var groupCommandsCapability = {
65697
66041
  scope: "device",
65698
66042
  deviceNative: true,
65699
66043
  mode: "singleton",
65700
- deviceTypes: [require_err_msg.DeviceType.Switch, require_err_msg.DeviceType.Light],
66044
+ deviceTypes: [
66045
+ require_err_msg.DeviceType.Switch,
66046
+ require_err_msg.DeviceType.Light,
66047
+ require_err_msg.DeviceType.Fan,
66048
+ require_err_msg.DeviceType.Cover,
66049
+ require_err_msg.DeviceType.Valve,
66050
+ require_err_msg.DeviceType.Lock,
66051
+ require_err_msg.DeviceType.MediaPlayer,
66052
+ require_err_msg.DeviceType.Thermostat,
66053
+ require_err_msg.DeviceType.Climate
66054
+ ],
65701
66055
  methods: {},
65702
66056
  status: {
65703
66057
  schema: GroupCommandsSchema,
@@ -65715,6 +66069,51 @@ var groupCommandsCapability = {
65715
66069
  history: "none"
65716
66070
  };
65717
66071
  //#endregion
66072
+ //#region src/capabilities/group-active.cap.ts
66073
+ /**
66074
+ * Whether a helper actuator group counts as active (D944): at least one
66075
+ * included member is, or every included member is. What "active" means is the
66076
+ * type's: a cover is open, a lock is locked, a media player is playing, a
66077
+ * climate device is not off. A group of lights, switches and fans reports
66078
+ * `switch.on` instead; this cap is for the types whose own state is not a
66079
+ * yes/no. Unknown members are left out (`group-status` counts them) and an
66080
+ * empty included set takes the device offline, never `active: false`.
66081
+ */
66082
+ var GroupActiveSchema = zod.z.object({
66083
+ active: zod.z.boolean().meta({ label: "Active" }),
66084
+ /** Ms epoch when the slice was last updated. */
66085
+ lastChangedAt: zod.z.number()
66086
+ });
66087
+ var groupActiveCapability = {
66088
+ name: "group-active",
66089
+ scope: "device",
66090
+ deviceNative: true,
66091
+ mode: "singleton",
66092
+ deviceTypes: [
66093
+ require_err_msg.DeviceType.Cover,
66094
+ require_err_msg.DeviceType.Valve,
66095
+ require_err_msg.DeviceType.Lock,
66096
+ require_err_msg.DeviceType.MediaPlayer,
66097
+ require_err_msg.DeviceType.Climate,
66098
+ require_err_msg.DeviceType.Thermostat
66099
+ ],
66100
+ methods: {},
66101
+ status: {
66102
+ schema: GroupActiveSchema,
66103
+ kind: "push"
66104
+ },
66105
+ runtimeState: GroupActiveSchema,
66106
+ /**
66107
+ * Runtime-state durability: **session** — recomputed from the members on the
66108
+ * next source event; a restored value would outlive the members it named.
66109
+ *
66110
+ * See `RuntimeStateDurability`. Enforced by
66111
+ * `scripts/check-runtime-state-durability.ts`.
66112
+ */
66113
+ durability: "session",
66114
+ history: "none"
66115
+ };
66116
+ //#endregion
65718
66117
  //#region src/capabilities/group-status.cap.ts
65719
66118
  /**
65720
66119
  * How many members of a helper group answered (D944). Counts are integers,
@@ -65747,7 +66146,14 @@ var groupStatusCapability = {
65747
66146
  deviceTypes: [
65748
66147
  require_err_msg.DeviceType.Sensor,
65749
66148
  require_err_msg.DeviceType.Switch,
65750
- require_err_msg.DeviceType.Light
66149
+ require_err_msg.DeviceType.Light,
66150
+ require_err_msg.DeviceType.Fan,
66151
+ require_err_msg.DeviceType.Cover,
66152
+ require_err_msg.DeviceType.Valve,
66153
+ require_err_msg.DeviceType.Lock,
66154
+ require_err_msg.DeviceType.MediaPlayer,
66155
+ require_err_msg.DeviceType.Thermostat,
66156
+ require_err_msg.DeviceType.Climate
65751
66157
  ],
65752
66158
  methods: {},
65753
66159
  status: {
@@ -67249,7 +67655,14 @@ var lockControlCapability = {
67249
67655
  }),
67250
67656
  unlock: require_sleep.method(zod.z.object({
67251
67657
  deviceId: zod.z.number().int().nonnegative(),
67252
- code: zod.z.string().min(1).optional()
67658
+ code: zod.z.string().min(1).optional(),
67659
+ /**
67660
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
67661
+ * with one call is refused unless the caller says it was confirmed. A
67662
+ * single lock ignores it. The refusal lives in the callee, so no
67663
+ * automation or API caller reaches the doors by skipping a dialog.
67664
+ */
67665
+ confirm: zod.z.boolean().optional()
67253
67666
  }), zod.z.void(), {
67254
67667
  kind: "mutation",
67255
67668
  auth: "protected"
@@ -75781,7 +76194,8 @@ var switchCapability = {
75781
76194
  deviceTypes: [
75782
76195
  require_err_msg.DeviceType.Switch,
75783
76196
  require_err_msg.DeviceType.Siren,
75784
- require_err_msg.DeviceType.Light
76197
+ require_err_msg.DeviceType.Light,
76198
+ require_err_msg.DeviceType.Fan
75785
76199
  ],
75786
76200
  methods: { setState: require_sleep.method(zod.z.object({
75787
76201
  deviceId: zod.z.number(),
@@ -78666,13 +79080,116 @@ function createDeviceExtensionProvider(options) {
78666
79080
  };
78667
79081
  }
78668
79082
  //#endregion
79083
+ //#region src/composition/helpers/actuator-methods.ts
79084
+ /**
79085
+ * One method table per actuator type (D944). A group offers a method only
79086
+ * when every member can take it, so a command never reaches a member that
79087
+ * lacks the surface: the cap must be bound by every member (the primary cap of
79088
+ * the type is the exception — a member that lacks it is simply not commanded),
79089
+ * and a row that names a device feature needs every member to advertise it.
79090
+ * Offline does not remove a method: capability is the binding, not liveness.
79091
+ */
79092
+ var ACTUATOR_TEMPLATE_IDS = [
79093
+ "switch",
79094
+ "light",
79095
+ "fan",
79096
+ "cover",
79097
+ "valve",
79098
+ "lock",
79099
+ "media-player",
79100
+ "climate"
79101
+ ];
79102
+ function row$1(cap, method, requires = null, confirm = false) {
79103
+ return {
79104
+ cap,
79105
+ method,
79106
+ requires,
79107
+ confirm
79108
+ };
79109
+ }
79110
+ /** The first row's cap is the type's own: always offered, members without it are skipped. */
79111
+ var ACTUATOR_METHODS = {
79112
+ switch: [row$1("switch", "setState")],
79113
+ light: [
79114
+ row$1("switch", "setState"),
79115
+ row$1("brightness", "setBrightness"),
79116
+ row$1("color", "setColor")
79117
+ ],
79118
+ fan: [
79119
+ row$1("switch", "setState"),
79120
+ row$1("fan-control", "setPercentage", require_err_msg.DeviceFeature.FanSpeed),
79121
+ row$1("fan-control", "setPreset", require_err_msg.DeviceFeature.FanPreset),
79122
+ row$1("fan-control", "setDirection", require_err_msg.DeviceFeature.FanDirection),
79123
+ row$1("fan-control", "setOscillating", require_err_msg.DeviceFeature.FanOscillating)
79124
+ ],
79125
+ cover: [
79126
+ row$1("cover", "open"),
79127
+ row$1("cover", "close"),
79128
+ row$1("cover", "stop"),
79129
+ row$1("cover", "setPosition", require_err_msg.DeviceFeature.CoverPositionable),
79130
+ row$1("cover", "setTiltPosition", require_err_msg.DeviceFeature.CoverTilt)
79131
+ ],
79132
+ valve: [
79133
+ row$1("valve", "open"),
79134
+ row$1("valve", "close"),
79135
+ row$1("valve", "setPosition", require_err_msg.DeviceFeature.ValvePositionable)
79136
+ ],
79137
+ lock: [row$1("lock-control", "lock"), row$1("lock-control", "unlock", null, true)],
79138
+ "media-player": [
79139
+ row$1("media-player", "play"),
79140
+ row$1("media-player", "pause"),
79141
+ row$1("media-player", "setVolume", require_err_msg.DeviceFeature.MediaPlayerVolume)
79142
+ ],
79143
+ climate: [
79144
+ row$1("climate-control", "setMode"),
79145
+ row$1("climate-control", "setTarget"),
79146
+ row$1("climate-control", "setFanMode", require_err_msg.DeviceFeature.ClimateFanMode)
79147
+ ]
79148
+ };
79149
+ function actuatorMethodRow(templateId, cap, method) {
79150
+ return ACTUATOR_METHODS[templateId].find((item) => item.cap === cap && item.method === method) ?? null;
79151
+ }
79152
+ /**
79153
+ * The rows every member can take. An empty member list shares nothing; the
79154
+ * caller passes a surface for every member it could read, or none at all.
79155
+ */
79156
+ function sharedActuatorMethods(templateId, members) {
79157
+ if (members.length === 0) return [];
79158
+ const rows = ACTUATOR_METHODS[templateId];
79159
+ const primary = rows[0]?.cap;
79160
+ return rows.filter((item) => {
79161
+ if (!(item.cap === primary || members.every((member) => member.caps.includes(item.cap)))) return false;
79162
+ const needed = item.requires;
79163
+ return needed === null || members.every((member) => member.features.includes(needed));
79164
+ });
79165
+ }
79166
+ /** The device features every member has, among those the table gates on, in table order. */
79167
+ function sharedActuatorFeatures(templateId, featureLists) {
79168
+ if (featureLists.length === 0) return [];
79169
+ const gated = ACTUATOR_METHODS[templateId].flatMap((item) => item.requires === null ? [] : [item.requires]);
79170
+ return [...new Set(gated)].filter((feature) => featureLists.every((features) => features.includes(feature)));
79171
+ }
79172
+ var UNLOCK_CONFIRMATION = "unlocking a group of locks needs an explicit confirmation (confirm: true) — it was not given, so no lock was sent anything";
79173
+ /**
79174
+ * Why a call must not be fanned out, or null. Only a confirmed row passes
79175
+ * without `confirm: true`; anything else is the caller's to refuse by name.
79176
+ */
79177
+ function methodRefusal(method, args) {
79178
+ if (method === null) return "that method is not one this group shares";
79179
+ if (method.confirm && args.confirm !== true) return UNLOCK_CONFIRMATION;
79180
+ return null;
79181
+ }
79182
+ //#endregion
78669
79183
  //#region src/composition/helpers/aggregate.ts
78670
79184
  function isBinaryReducer(reducer) {
78671
79185
  return reducer === "any" || reducer === "all";
78672
79186
  }
78673
- function includedValue(reducer, member) {
79187
+ function includedValue(reducer, member, activeWhen) {
78674
79188
  if (member.state !== "fresh") return null;
78675
- if (isBinaryReducer(reducer)) return typeof member.value === "boolean" ? member.value : null;
79189
+ if (isBinaryReducer(reducer)) {
79190
+ if (activeWhen !== void 0) return typeof member.value === "string" ? activeWhen.includes(member.value) : null;
79191
+ return typeof member.value === "boolean" ? member.value : null;
79192
+ }
78676
79193
  return typeof member.value === "number" && Number.isFinite(member.value) ? member.value : null;
78677
79194
  }
78678
79195
  function median$1(values) {
@@ -78722,7 +79239,7 @@ function emptyOutcome(empty, counts) {
78722
79239
  /** Pure. `members` is not mutated. An empty included set is null or unavailable, never 0 or false. */
78723
79240
  function evaluateAggregate(input) {
78724
79241
  const included = input.members.flatMap((member) => {
78725
- const value = includedValue(input.reducer, member);
79242
+ const value = includedValue(input.reducer, member, input.activeWhen);
78726
79243
  return value === null ? [] : [value];
78727
79244
  });
78728
79245
  const counts = countsOf(included.length, input.members.length);
@@ -78768,12 +79285,12 @@ function evaluateAggregate(input) {
78768
79285
  //#region src/composition/helpers/source-pick.ts
78769
79286
  /** What the member step asks the selector for this template. */
78770
79287
  function sourcePickForTemplate(template) {
78771
- const valueKind = template.family === "numeric" ? "number" : "boolean";
79288
+ const valueKind = template.family === "numeric" ? "number" : template.activeWhen === void 0 ? "boolean" : "state";
78772
79289
  return {
78773
79290
  purpose: "member",
78774
79291
  multiple: true,
78775
79292
  max: 64,
78776
- deviceTypes: [template.memberDeviceType],
79293
+ deviceTypes: [...template.memberDeviceTypes],
78777
79294
  accept: template.accept.map((field) => ({
78778
79295
  ...field,
78779
79296
  valueKind
@@ -78782,7 +79299,7 @@ function sourcePickForTemplate(template) {
78782
79299
  required: false,
78783
79300
  minRetentionMs: null
78784
79301
  },
78785
- mustBindCaps: template.family === "actuator" ? [template.outputCap] : [],
79302
+ mustBindCaps: template.family === "actuator" ? template.accept.map((field) => field.cap) : [],
78786
79303
  exclude: []
78787
79304
  };
78788
79305
  }
@@ -78815,6 +79332,35 @@ function historyAccept(kind) {
78815
79332
  }
78816
79333
  return fields;
78817
79334
  }
79335
+ /**
79336
+ * What the input step asks the selector for a math helper. A threshold reads
79337
+ * one number, a difference or a ratio two, a sum and an expression several.
79338
+ * A derivative reads one historised number.
79339
+ */
79340
+ function sourcePickForMath(kind) {
79341
+ if (kind === "derivative") return {
79342
+ ...sourcePickForHistory("statistic"),
79343
+ accept: numericAccept()
79344
+ };
79345
+ const multiple = kind === "sum" || kind === "expression";
79346
+ const max = kind === "difference" || kind === "ratio" ? 2 : multiple ? 64 : 1;
79347
+ return {
79348
+ purpose: "reading",
79349
+ multiple: multiple || max > 1,
79350
+ max,
79351
+ deviceTypes: [],
79352
+ accept: numericAccept(),
79353
+ history: {
79354
+ required: false,
79355
+ minRetentionMs: null
79356
+ },
79357
+ mustBindCaps: [],
79358
+ exclude: []
79359
+ };
79360
+ }
79361
+ function numericAccept() {
79362
+ return historyAccept("statistic").filter((field) => field.valueKind === "number");
79363
+ }
78818
79364
  //#endregion
78819
79365
  //#region src/units/unit-table.ts
78820
79366
  /**
@@ -79417,6 +79963,7 @@ function aggregateRead(reading) {
79417
79963
  function aggregateField(source, read) {
79418
79964
  const outcome = evaluateAggregate({
79419
79965
  reducer: source.reducer,
79966
+ ...source.activeWhen === void 0 ? {} : { activeWhen: source.activeWhen },
79420
79967
  members: source.reads.map((item) => aggregateRead(read(item))),
79421
79968
  publish: source.publish,
79422
79969
  empty: source.empty
@@ -82211,6 +82758,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
82211
82758
  featureProbe: featureProbeCapability,
82212
82759
  flood: floodCapability,
82213
82760
  gas: gasCapability,
82761
+ groupActive: groupActiveCapability,
82214
82762
  groupCommands: groupCommandsCapability,
82215
82763
  groupStatus: groupStatusCapability,
82216
82764
  heatingValve: heatingValveCapability,
@@ -87550,6 +88098,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
87550
88098
  access: "view",
87551
88099
  role: "viewer"
87552
88100
  },
88101
+ "groupActive.getStatus": {
88102
+ capName: "group-active",
88103
+ capScope: "device",
88104
+ addonId: null,
88105
+ access: "view",
88106
+ role: "viewer"
88107
+ },
87553
88108
  "groupCommands.getStatus": {
87554
88109
  capName: "group-commands",
87555
88110
  capScope: "device",
@@ -94109,6 +94664,7 @@ var KNOWN_CAP_NAMES = [
94109
94664
  "filesystem-browse",
94110
94665
  "flood",
94111
94666
  "gas",
94667
+ "group-active",
94112
94668
  "group-commands",
94113
94669
  "group-status",
94114
94670
  "heating-valve",
@@ -94260,6 +94816,7 @@ var DEVICE_CAP_NAMES = [
94260
94816
  "feature-probe",
94261
94817
  "flood",
94262
94818
  "gas",
94819
+ "group-active",
94263
94820
  "group-commands",
94264
94821
  "group-status",
94265
94822
  "heating-valve",
@@ -97812,6 +98369,10 @@ var SENSOR_CAP_VOCABULARY = {
97812
98369
  icon: "flame"
97813
98370
  }]
97814
98371
  },
98372
+ "group-active": {
98373
+ scope: "device",
98374
+ noun: t("Group state", "Stato del gruppo")
98375
+ },
97815
98376
  "group-commands": {
97816
98377
  scope: "device",
97817
98378
  noun: t("Group command", "Comando di gruppo")
@@ -100066,6 +100627,7 @@ var CAP_NAMES_WITH_STATUS = [
100066
100627
  "feature-probe",
100067
100628
  "flood",
100068
100629
  "gas",
100630
+ "group-active",
100069
100631
  "group-commands",
100070
100632
  "group-status",
100071
100633
  "heating-valve",
@@ -100191,6 +100753,7 @@ var CAPABILITY_NAMES = {
100191
100753
  filesystemBrowse: "filesystem-browse",
100192
100754
  flood: "flood",
100193
100755
  gas: "gas",
100756
+ groupActive: "group-active",
100194
100757
  groupCommands: "group-commands",
100195
100758
  groupStatus: "group-status",
100196
100759
  heatingValve: "heating-valve",
@@ -100600,6 +101163,10 @@ var CAPABILITY_ROUTER_KEYS = [
100600
101163
  key: "gas",
100601
101164
  name: "gas"
100602
101165
  },
101166
+ {
101167
+ key: "groupActive",
101168
+ name: "group-active"
101169
+ },
100603
101170
  {
100604
101171
  key: "groupCommands",
100605
101172
  name: "group-commands"
@@ -101125,6 +101692,7 @@ var ALL_CAPABILITY_DEFINITIONS = [
101125
101692
  filesystemBrowseCapability,
101126
101693
  floodCapability,
101127
101694
  gasCapability,
101695
+ groupActiveCapability,
101128
101696
  groupCommandsCapability,
101129
101697
  groupStatusCapability,
101130
101698
  heatingValveCapability,
@@ -102204,6 +102772,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
102204
102772
  form: "single",
102205
102773
  optional: false
102206
102774
  }],
102775
+ "groupActive.getStatus": [{
102776
+ name: "deviceId",
102777
+ form: "single",
102778
+ optional: false
102779
+ }],
102207
102780
  "groupCommands.getStatus": [{
102208
102781
  name: "deviceId",
102209
102782
  form: "single",
@@ -104230,7 +104803,7 @@ function getCapsByProviderKind(kind) {
104230
104803
  //#region src/generated/runtime-state-durability.ts
104231
104804
  /**
104232
104805
  * Per-cap runtime-state policy, projected from every `*.cap.ts` that declares
104233
- * `runtimeState`. 75 caps: 39 `restored`, 36 `session`.
104806
+ * `runtimeState`. 76 caps: 39 `restored`, 37 `session`.
104234
104807
  *
104235
104808
  * A cap absent from this map has no runtime-state slice at all. A cap PRESENT
104236
104809
  * with `durability: 'session'` has one and has decided not to keep it.
@@ -104348,6 +104921,10 @@ var RUNTIME_STATE_POLICY = {
104348
104921
  durability: "restored",
104349
104922
  volatileFields: ["lastChangedAt"]
104350
104923
  },
104924
+ "group-active": {
104925
+ durability: "session",
104926
+ volatileFields: []
104927
+ },
104351
104928
  "group-commands": {
104352
104929
  durability: "session",
104353
104930
  volatileFields: []
@@ -115950,6 +116527,8 @@ function armRemovalReconcile(opts) {
115950
116527
  exports.ACCESSORY_LABEL = ACCESSORY_LABEL;
115951
116528
  exports.ACCESS_ROLES = ACCESS_ROLES;
115952
116529
  exports.ACTIVE_CRITERIA = require_composition.ACTIVE_CRITERIA;
116530
+ exports.ACTUATOR_METHODS = ACTUATOR_METHODS;
116531
+ exports.ACTUATOR_TEMPLATE_IDS = ACTUATOR_TEMPLATE_IDS;
115953
116532
  exports.ADMIN_SCOPE = ADMIN_SCOPE;
115954
116533
  exports.AGENT_MDNS_QUERY_NAME = AGENT_MDNS_QUERY_NAME;
115955
116534
  exports.AGENT_MDNS_SERVICE_TYPE = AGENT_MDNS_SERVICE_TYPE;
@@ -115976,6 +116555,7 @@ exports.APP_FLOW_STATE_PREFIX = APP_FLOW_STATE_PREFIX;
115976
116555
  exports.APP_REFUSED_PATH = APP_REFUSED_PATH;
115977
116556
  exports.APP_START_REFUSAL_MESSAGES = APP_START_REFUSAL_MESSAGES;
115978
116557
  exports.ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT = ARCHIVED_DEBUG_NOTES_DEFAULT_LIMIT;
116558
+ exports.ARITHMETIC_OPS = require_composition.ARITHMETIC_OPS;
115979
116559
  exports.AUDIO_ANALYSIS_CAP_NAME = AUDIO_ANALYSIS_CAP_NAME;
115980
116560
  exports.AUDIO_BACKEND_CHOICES = AUDIO_BACKEND_CHOICES;
115981
116561
  exports.AUDIO_CHUNK_FORMATS = require_sleep.AUDIO_CHUNK_FORMATS;
@@ -116037,6 +116617,7 @@ exports.ArchiveManifestSchema = ArchiveManifestSchema;
116037
116617
  exports.ArchiveSqliteSnapshotSchema = ArchiveSqliteSnapshotSchema;
116038
116618
  exports.ArchivedDebugNoteQueryInputSchema = ArchivedDebugNoteQueryInputSchema;
116039
116619
  exports.ArchivedDebugNoteSchema = ArchivedDebugNoteSchema;
116620
+ exports.ArithmeticHelperSpecSchema = require_composition.ArithmeticHelperSpecSchema;
116040
116621
  exports.AttachmentMediaTypeSchema = AttachmentMediaTypeSchema;
116041
116622
  exports.AttachmentSchema = AttachmentSchema;
116042
116623
  exports.AudioAnalysisResultSchema = AudioAnalysisResultSchema;
@@ -116417,6 +116998,7 @@ exports.DEFAULT_TIMELAPSE_PREVIEW_TEXT = DEFAULT_TIMELAPSE_PREVIEW_TEXT;
116417
116998
  exports.DEFAULT_TOKEN_EXPIRY = require_sleep.DEFAULT_TOKEN_EXPIRY;
116418
116999
  exports.DEFAULT_VIEWER_SCOPE = DEFAULT_VIEWER_SCOPE;
116419
117000
  exports.DEFINITIVE_DEVICE_REFUSALS = DEFINITIVE_DEVICE_REFUSALS;
117001
+ exports.DERIVATIVE_UNITS = require_composition.DERIVATIVE_UNITS;
116420
117002
  exports.DERIVED_CAMERA_SILENCED_CAP_NAMES = DERIVED_CAMERA_SILENCED_CAP_NAMES;
116421
117003
  exports.DETAIL_CROP_PADDING_FIELD = DETAIL_CROP_PADDING_FIELD;
116422
117004
  exports.DETAIL_CROP_PADDING_KEY = DETAIL_CROP_PADDING_KEY;
@@ -116476,6 +117058,7 @@ exports.DeclareKindResultSchema = DeclareKindResultSchema;
116476
117058
  exports.DeclaredDevices = DeclaredDevices;
116477
117059
  exports.DecodedAudioChunkSchema = require_sleep.DecodedAudioChunkSchema;
116478
117060
  exports.DeleteIntegrationResultSchema = DeleteIntegrationResultSchema;
117061
+ exports.DerivativeHelperSpecSchema = require_composition.DerivativeHelperSpecSchema;
116479
117062
  exports.DetailCropConventionSchema = DetailCropConventionSchema;
116480
117063
  exports.DetectionCatalogClassMapSchema = DetectionCatalogClassMapSchema;
116481
117064
  exports.DetectionSourceSchema = DetectionSourceSchema;
@@ -116562,6 +117145,7 @@ exports.EXPRESSION_BUILTIN_NAMES = require_composition.EXPRESSION_BUILTIN_NAMES;
116562
117145
  exports.EXPRESSION_COMPILE_CACHE_CAPACITY = require_composition.EXPRESSION_COMPILE_CACHE_CAPACITY;
116563
117146
  exports.EXPRESSION_IDENTIFIER_RE = require_composition.EXPRESSION_IDENTIFIER_RE;
116564
117147
  exports.EXPRESSION_INJECTED_NOW = require_composition.EXPRESSION_INJECTED_NOW;
117148
+ exports.EXPRESSION_OUTPUTS = require_composition.EXPRESSION_OUTPUTS;
116565
117149
  exports.EXTENSION_HOST_DEVICE_TYPES = EXTENSION_HOST_DEVICE_TYPES;
116566
117150
  exports.EXTENSION_SLOTS = EXTENSION_SLOTS;
116567
117151
  exports.EXTENSION_SLOT_IDS = EXTENSION_SLOT_IDS;
@@ -116628,6 +117212,7 @@ exports.ExpressionBindingSourceSchema = ExpressionBindingSourceSchema;
116628
117212
  exports.ExpressionEvalError = require_composition.ExpressionEvalError;
116629
117213
  exports.ExpressionFieldBindingSchema = ExpressionFieldBindingSchema;
116630
117214
  exports.ExpressionGlobalBindingSchema = ExpressionGlobalBindingSchema;
117215
+ exports.ExpressionHelperSpecSchema = require_composition.ExpressionHelperSpecSchema;
116631
117216
  exports.ExpressionLiteralBindingSchema = ExpressionLiteralBindingSchema;
116632
117217
  exports.ExpressionParseError = require_composition.ExpressionParseError;
116633
117218
  exports.ExpressionSourceSchema = ExpressionSourceSchema;
@@ -116684,6 +117269,7 @@ exports.GetStreamWithCodecInputSchema = GetStreamWithCodecInputSchema;
116684
117269
  exports.GlobalMetricsSchema = GlobalMetricsSchema;
116685
117270
  exports.GridLayoutPatchSchema = GridLayoutPatchSchema;
116686
117271
  exports.GridLayoutViewSchema = GridLayoutViewSchema;
117272
+ exports.GroupActiveSchema = GroupActiveSchema;
116687
117273
  exports.GroupCommandResultSchema = GroupCommandResultSchema;
116688
117274
  exports.GroupCommandsSchema = GroupCommandsSchema;
116689
117275
  exports.GroupHelperSpecSchema = require_composition.GroupHelperSpecSchema;
@@ -117837,6 +118423,7 @@ exports.TerminalSessionInfoSchema = TerminalSessionInfoSchema;
117837
118423
  exports.TestConnectionResultSchema = TestConnectionResultSchema$1;
117838
118424
  exports.TestConnectionStatusEnum = TestConnectionStatusEnum;
117839
118425
  exports.TestResultSchema = TestResultSchema;
118426
+ exports.ThresholdHelperSpecSchema = require_composition.ThresholdHelperSpecSchema;
117840
118427
  exports.TimelapseRuleInputSchema = TimelapseRuleInputSchema;
117841
118428
  exports.TimelapseRulePatchSchema = TimelapseRulePatchSchema;
117842
118429
  exports.TimelapseRuleSchema = TimelapseRuleSchema;
@@ -117904,6 +118491,7 @@ exports.TransportPlaneSchema = TransportPlaneSchema;
117904
118491
  exports.TurnServerSchema = TurnServerSchema;
117905
118492
  exports.UNATTRIBUTED_BUCKET_KEY = UNATTRIBUTED_BUCKET_KEY;
117906
118493
  exports.UNIT_TABLE = UNIT_TABLE;
118494
+ exports.UNLOCK_CONFIRMATION = UNLOCK_CONFIRMATION;
117907
118495
  exports.USE_ROOT_MODEL_DEFAULTS = USE_ROOT_MODEL_DEFAULTS;
117908
118496
  exports.USE_ROOT_MODEL_SETTING_KEY = USE_ROOT_MODEL_SETTING_KEY;
117909
118497
  exports.UnifiedBrokerInfoSchema = BrokerInfoSchema;
@@ -118002,6 +118590,7 @@ exports.actionsForDeviceType = actionsForDeviceType;
118002
118590
  exports.actionsForDevices = actionsForDevices;
118003
118591
  exports.activateAlarmProfile = activateAlarmProfile;
118004
118592
  exports.activeForReducer = activeForReducer;
118593
+ exports.actuatorMethodRow = actuatorMethodRow;
118005
118594
  exports.addonCatalogHref = addonCatalogHref;
118006
118595
  exports.addonPagesCapability = addonPagesCapability;
118007
118596
  exports.addonPagesSourceCapability = addonPagesSourceCapability;
@@ -118038,6 +118627,7 @@ exports.applyModeDeviceListEdit = applyModeDeviceListEdit;
118038
118627
  exports.applyModelBoundSettings = applyModelBoundSettings;
118039
118628
  exports.applyNonBlockingEdit = applyNonBlockingEdit;
118040
118629
  exports.applySecureOnArmEdit = applySecureOnArmEdit;
118630
+ exports.arithmeticDraft = arithmeticDraft;
118041
118631
  exports.armRemovalReconcile = armRemovalReconcile;
118042
118632
  exports.arrayItemFieldPath = require_sleep.arrayItemFieldPath;
118043
118633
  exports.asBoolean = require_sleep.asBoolean;
@@ -118244,6 +118834,8 @@ exports.defineRecordKinds = require_sleep.defineRecordKinds;
118244
118834
  exports.dehydrateConfigField = require_sleep.dehydrateConfigField;
118245
118835
  exports.dehydrateSchema = require_sleep.dehydrateSchema;
118246
118836
  exports.deleteAlarmProfile = deleteAlarmProfile;
118837
+ exports.derivativeDraft = derivativeDraft;
118838
+ exports.derivativeUnitLabel = derivativeUnitLabel;
118247
118839
  exports.deriveBatteryPresence = deriveBatteryPresence;
118248
118840
  exports.deriveCameraSwitches = deriveCameraSwitches;
118249
118841
  exports.deriveDetailCropRect = deriveDetailCropRect;
@@ -118325,6 +118917,7 @@ exports.evaluateAggregate = evaluateAggregate;
118325
118917
  exports.evaluateAst = require_composition.evaluateAst;
118326
118918
  exports.evaluateCompositionField = evaluateCompositionField;
118327
118919
  exports.evaluateCount = require_composition.evaluateCount;
118920
+ exports.evaluateDerivative = require_composition.evaluateDerivative;
118328
118921
  exports.evaluateExpressionSource = require_composition.evaluateExpressionSource;
118329
118922
  exports.evaluatePoolMemory = evaluatePoolMemory;
118330
118923
  exports.evaluateRose = require_composition.evaluateRose;
@@ -118346,6 +118939,7 @@ exports.expandSystemEventClasses = expandSystemEventClasses;
118346
118939
  exports.exportSubjectOf = exportSubjectOf;
118347
118940
  exports.exposeBlockDevices = exposeBlockDevices;
118348
118941
  exports.expressionContainsBuiltinCall = expressionContainsBuiltinCall;
118942
+ exports.expressionDraft = expressionDraft;
118349
118943
  exports.extensionSlotRef = extensionSlotRef;
118350
118944
  exports.extractNestedAddonId = extractNestedAddonId;
118351
118945
  exports.extractSourceInfoFromMetadata = extractSourceInfoFromMetadata;
@@ -118397,6 +118991,7 @@ exports.gifFilterComplex = gifFilterComplex;
118397
118991
  exports.gifFromMp4Args = gifFromMp4Args;
118398
118992
  exports.globalSecretScope = require_sleep.globalSecretScope;
118399
118993
  exports.grantRowsOf = grantRowsOf;
118994
+ exports.groupActiveCapability = groupActiveCapability;
118400
118995
  exports.groupCommandsCapability = groupCommandsCapability;
118401
118996
  exports.groupStatusCapability = groupStatusCapability;
118402
118997
  exports.groupTemplate = groupTemplate;
@@ -118470,6 +119065,7 @@ exports.isEventKindLabelKey = isEventKindLabelKey;
118470
119065
  exports.isEventOwnerType = isEventOwnerType;
118471
119066
  exports.isFirstLevelMacroClass = isFirstLevelMacroClass;
118472
119067
  exports.isHeldBackTemplateVar = isHeldBackTemplateVar;
119068
+ exports.isHistoryHelper = require_composition.isHistoryHelper;
118473
119069
  exports.isIconKey = isIconKey;
118474
119070
  exports.isIsolatedBuiltin = isIsolatedBuiltin;
118475
119071
  exports.isKeychainStoredField = require_sleep.isKeychainStoredField;
@@ -118575,6 +119171,7 @@ exports.meshNetworkCapability = meshNetworkCapability;
118575
119171
  exports.meterCapability = meterCapability;
118576
119172
  exports.method = require_sleep.method;
118577
119173
  exports.methodAccessForHttpMethod = methodAccessForHttpMethod;
119174
+ exports.methodRefusal = methodRefusal;
118578
119175
  exports.methodRoleOf = methodRoleOf;
118579
119176
  exports.metricsProviderCapability = metricsProviderCapability;
118580
119177
  exports.migrateLegacyDeviceSignalConfig = migrateLegacyDeviceSignalConfig;
@@ -118887,6 +119484,8 @@ exports.settingValuesEqual = settingValuesEqual;
118887
119484
  exports.settingsBelow = settingsBelow;
118888
119485
  exports.settingsStoreCapability = settingsStoreCapability;
118889
119486
  exports.shareViewGrantOf = shareViewGrantOf;
119487
+ exports.sharedActuatorFeatures = sharedActuatorFeatures;
119488
+ exports.sharedActuatorMethods = sharedActuatorMethods;
118890
119489
  exports.sharedColorModes = sharedColorModes;
118891
119490
  exports.sharedLightCaps = sharedLightCaps;
118892
119491
  exports.shortHostname = shortHostname;
@@ -118903,6 +119502,7 @@ exports.smtpProviderCapability = smtpProviderCapability;
118903
119502
  exports.snapshotCapability = snapshotCapability;
118904
119503
  exports.sourcePickForAppliance = require_composition.sourcePickForAppliance;
118905
119504
  exports.sourcePickForHistory = sourcePickForHistory;
119505
+ exports.sourcePickForMath = sourcePickForMath;
118906
119506
  exports.sourcePickForTemplate = sourcePickForTemplate;
118907
119507
  exports.splitTranslationRef = splitTranslationRef;
118908
119508
  exports.squareAround = squareAround;
@@ -118975,6 +119575,7 @@ exports.templateVarSystemEventApplies = templateVarSystemEventApplies;
118975
119575
  exports.templateVarsFor = templateVarsFor;
118976
119576
  exports.terminalSessionCapability = terminalSessionCapability;
118977
119577
  exports.textToHtml = textToHtml;
119578
+ exports.thresholdDraft = thresholdDraft;
118978
119579
  exports.thresholdToBase = thresholdToBase;
118979
119580
  exports.thresholdToDisplay = thresholdToDisplay;
118980
119581
  exports.timeOfDayToMinutes = timeOfDayToMinutes;