@camstack/addon-agent-ui 1.2.276 → 1.2.278

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/addon.js CHANGED
@@ -5443,7 +5443,7 @@ var ZodIssueCode = {
5443
5443
  var ZodFirstPartyTypeKind;
5444
5444
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5445
5445
  //#endregion
5446
- //#region ../types/dist/sleep-bykKrTgu.mjs
5446
+ //#region ../types/dist/sleep--jXS9hWo.mjs
5447
5447
  /**
5448
5448
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5449
5449
  * window to float samples (D455).
@@ -8583,6 +8583,7 @@ var CAP_NAMES = Object.freeze([
8583
8583
  "filesystem-browse",
8584
8584
  "flood",
8585
8585
  "gas",
8586
+ "group-active",
8586
8587
  "group-commands",
8587
8588
  "group-status",
8588
8589
  "heating-valve",
@@ -8605,6 +8606,7 @@ var CAP_NAMES = Object.freeze([
8605
8606
  "login-method",
8606
8607
  "media-player",
8607
8608
  "mesh-network",
8609
+ "meter",
8608
8610
  "metrics-provider",
8609
8611
  "model-convert",
8610
8612
  "model-distributor",
@@ -9403,6 +9405,10 @@ Object.freeze({
9403
9405
  "path": "detected",
9404
9406
  "valueType": "boolean"
9405
9407
  }],
9408
+ "group-active": [{
9409
+ "path": "active",
9410
+ "valueType": "boolean"
9411
+ }],
9406
9412
  "group-status": [
9407
9413
  {
9408
9414
  "path": "included",
@@ -9662,6 +9668,10 @@ Object.freeze({
9662
9668
  ]
9663
9669
  }
9664
9670
  ],
9671
+ "meter": [{
9672
+ "path": "value",
9673
+ "valueType": "number"
9674
+ }],
9665
9675
  "motion": [
9666
9676
  {
9667
9677
  "path": "detected",
@@ -10754,7 +10764,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
10754
10764
  return DeviceRole;
10755
10765
  }({});
10756
10766
  //#endregion
10757
- //#region ../types/dist/composition-B2rw5L29.mjs
10767
+ //#region ../types/dist/composition-Bb8iwHEJ.mjs
10758
10768
  /**
10759
10769
  * The ffmpeg build every CamStack node downloads, per platform and arch.
10760
10770
  *
@@ -11069,6 +11079,13 @@ var table = {
11069
11079
  apply: () => {
11070
11080
  throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
11071
11081
  }
11082
+ },
11083
+ schmitt: {
11084
+ minArgs: 3,
11085
+ maxArgs: 5,
11086
+ apply: () => {
11087
+ throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
11088
+ }
11072
11089
  }
11073
11090
  };
11074
11091
  Object.freeze(Object.assign(Object.create(null), table));
@@ -11530,6 +11547,79 @@ var APPLIANCE_KINDS = [
11530
11547
  ];
11531
11548
  DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
11532
11549
  /**
11550
+ * Statistics and integrals over a history read (D944).
11551
+ *
11552
+ * Pure: the same points always give the same answer, so a restart recomputes
11553
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
11554
+ * never the mean of the samples. A hole with no held value is not integrated
11555
+ * as zero. A truncated read is not published.
11556
+ */
11557
+ var STATISTIC_STATS = [
11558
+ "min",
11559
+ "max",
11560
+ "mean",
11561
+ "sum",
11562
+ "count",
11563
+ "change"
11564
+ ];
11565
+ /**
11566
+ * The range a statistics or integral helper asks history for (D944).
11567
+ *
11568
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
11569
+ * or 25 hours across a DST change. A tier is eligible only when its retention
11570
+ * is strictly longer than the longest that range can be. Forever qualifies.
11571
+ * Equal to a tier's retention is a refusal, not a short answer.
11572
+ */
11573
+ var MINUTE_MS = 6e4;
11574
+ var HOUR_MS = 60 * MINUTE_MS;
11575
+ var DAY_MS = 24 * HOUR_MS;
11576
+ var ROLLING_SPANS = [
11577
+ "1h",
11578
+ "24h",
11579
+ "2d",
11580
+ "7d",
11581
+ "30d",
11582
+ "custom"
11583
+ ];
11584
+ var CALENDAR_PERIODS = [
11585
+ "today",
11586
+ "yesterday",
11587
+ "this-week",
11588
+ "this-month"
11589
+ ];
11590
+ var RESET_PERIODS = [
11591
+ "never",
11592
+ "daily",
11593
+ "weekly",
11594
+ "monthly"
11595
+ ];
11596
+ 5 * MINUTE_MS;
11597
+ 24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
11598
+ 7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
11599
+ var rollingWindowObject = object({
11600
+ kind: literal("rolling"),
11601
+ span: _enum(ROLLING_SPANS),
11602
+ customMinutes: number().int().min(5).optional()
11603
+ }).check((payload) => {
11604
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
11605
+ code: "custom",
11606
+ message: "a custom range needs a duration in minutes",
11607
+ path: ["customMinutes"],
11608
+ input: payload.value
11609
+ });
11610
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
11611
+ code: "custom",
11612
+ message: "only a custom range carries a duration",
11613
+ path: ["customMinutes"],
11614
+ input: payload.value
11615
+ });
11616
+ });
11617
+ var RollingWindowSchema = rollingWindowObject;
11618
+ var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
11619
+ kind: literal("calendar"),
11620
+ period: _enum(CALENDAR_PERIODS)
11621
+ })]);
11622
+ /**
11533
11623
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11534
11624
  * id. Split out so helper schemas can name it without a cycle through
11535
11625
  * `composition.ts` (D659).
@@ -11555,7 +11645,13 @@ var GROUP_TEMPLATE_IDS = [
11555
11645
  "occupancy",
11556
11646
  "binary",
11557
11647
  "switch",
11558
- "light"
11648
+ "light",
11649
+ "fan",
11650
+ "cover",
11651
+ "valve",
11652
+ "lock",
11653
+ "media-player",
11654
+ "climate"
11559
11655
  ];
11560
11656
  var NUMERIC_AGGREGATES = [
11561
11657
  "mean",
@@ -11585,22 +11681,73 @@ var HelperMemberSchema = object({
11585
11681
  cap: string().min(1),
11586
11682
  fieldPath: string().min(1)
11587
11683
  });
11588
- var HelperSpecSchema = discriminatedUnion("kind", [object({
11589
- kind: literal("group"),
11590
- templateId: GroupTemplateIdSchema,
11591
- aggregate: AggregateReducerSchema,
11592
- members: array(HelperMemberSchema).min(1).max(64),
11593
- /** Actuator groups only. Readings leave this unset. */
11594
- active: ActiveCriterionSchema.optional()
11595
- }), object({
11596
- kind: literal("appliance"),
11597
- templateId: literal(APPLIANCE_TEMPLATE_ID),
11598
- appliance: _enum(APPLIANCE_KINDS),
11599
- thresholdWatts: number().positive(),
11600
- startDwellMs: number().int().nonnegative(),
11601
- stopDwellMs: number().int().nonnegative(),
11602
- member: HelperMemberSchema
11603
- })]);
11684
+ var HelperSpecSchema = discriminatedUnion("kind", [
11685
+ object({
11686
+ kind: literal("group"),
11687
+ templateId: GroupTemplateIdSchema,
11688
+ aggregate: AggregateReducerSchema,
11689
+ members: array(HelperMemberSchema).min(1).max(64),
11690
+ /** Actuator groups only. Readings leave this unset. */
11691
+ active: ActiveCriterionSchema.optional()
11692
+ }),
11693
+ object({
11694
+ kind: literal("appliance"),
11695
+ templateId: literal(APPLIANCE_TEMPLATE_ID),
11696
+ appliance: _enum(APPLIANCE_KINDS),
11697
+ thresholdWatts: number().positive(),
11698
+ startDwellMs: number().int().nonnegative(),
11699
+ stopDwellMs: number().int().nonnegative(),
11700
+ member: HelperMemberSchema
11701
+ }),
11702
+ object({
11703
+ kind: literal("statistic"),
11704
+ stat: _enum(STATISTIC_STATS),
11705
+ window: StatisticWindowSchema,
11706
+ source: HelperMemberSchema
11707
+ }),
11708
+ object({
11709
+ kind: literal("integral"),
11710
+ reset: _enum(RESET_PERIODS),
11711
+ output: _enum(["energy", "meter"]),
11712
+ source: HelperMemberSchema
11713
+ }),
11714
+ object({
11715
+ kind: literal("threshold"),
11716
+ source: HelperMemberSchema,
11717
+ high: number(),
11718
+ low: number(),
11719
+ onForMs: number().int().nonnegative(),
11720
+ offForMs: number().int().nonnegative()
11721
+ }),
11722
+ object({
11723
+ kind: literal("arithmetic"),
11724
+ op: _enum([
11725
+ "sum",
11726
+ "difference",
11727
+ "ratio"
11728
+ ]),
11729
+ inputs: array(HelperMemberSchema).min(2).max(64)
11730
+ }),
11731
+ object({
11732
+ kind: literal("expression"),
11733
+ expr: string().min(1),
11734
+ inputs: array(object({
11735
+ name: string().min(1),
11736
+ member: HelperMemberSchema
11737
+ })).min(1).max(64),
11738
+ output: _enum(["number", "boolean"])
11739
+ }),
11740
+ object({
11741
+ kind: literal("derivative"),
11742
+ window: RollingWindowSchema,
11743
+ per: _enum([
11744
+ "second",
11745
+ "minute",
11746
+ "hour"
11747
+ ]),
11748
+ source: HelperMemberSchema
11749
+ })
11750
+ ]);
11604
11751
  /** A composed device's stableId is this prefix plus the block id. */
11605
11752
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
11606
11753
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -11661,6 +11808,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
11661
11808
  "all"
11662
11809
  ]),
11663
11810
  reads: array(CompositionFieldReadSchema).min(1).max(64),
11811
+ /**
11812
+ * Set when the reads are an enum state, not a yes/no: the listed states
11813
+ * count as active (a cover is `open`). A state outside the list is inactive;
11814
+ * a read that is not a state at all is left out. Only `any` / `all` use it.
11815
+ */
11816
+ activeWhen: array(string().min(1)).min(1).optional(),
11664
11817
  /** `value` is the reading; the others are the member counts. */
11665
11818
  publish: _enum([
11666
11819
  "value",
@@ -11674,6 +11827,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
11674
11827
  "omit",
11675
11828
  "offline"
11676
11829
  ])
11830
+ }),
11831
+ object({
11832
+ kind: literal("series"),
11833
+ read: CompositionFieldReadSchema,
11834
+ /** `value` is the statistic or the integral. The others are the gap counts. */
11835
+ publish: _enum([
11836
+ "value",
11837
+ "included",
11838
+ "excluded",
11839
+ "total"
11840
+ ]),
11841
+ /**
11842
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
11843
+ * device unseeded until history answers, so a restart cannot publish 0.
11844
+ */
11845
+ empty: _enum([
11846
+ "null",
11847
+ "omit",
11848
+ "offline"
11849
+ ])
11677
11850
  })
11678
11851
  ]);
11679
11852
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -17832,7 +18005,8 @@ var CompositionProblemSchema = object({
17832
18005
  "native-capability-replace",
17833
18006
  "mixed-quantity",
17834
18007
  "helper-mismatch",
17835
- "member-constraint"
18008
+ "member-constraint",
18009
+ "retention"
17836
18010
  ]),
17837
18011
  path: string(),
17838
18012
  message: string()
@@ -18066,13 +18240,17 @@ Object.freeze({
18066
18240
  latchedAt: {
18067
18241
  kind: "fixed",
18068
18242
  result: ["number", "null"]
18243
+ },
18244
+ schmitt: {
18245
+ kind: "fixed",
18246
+ result: ["boolean", "null"]
18069
18247
  }
18070
18248
  });
18071
18249
  /**
18072
18250
  * One catalog row per base reading a group helper can build (D944 §3).
18073
18251
  * Data, not a form default written into the block.
18074
18252
  */
18075
- var NOW = {
18253
+ var NOW$2 = {
18076
18254
  fieldPath: "lastFetchedAt",
18077
18255
  expr: "now"
18078
18256
  };
@@ -18086,6 +18264,8 @@ function numeric(input) {
18086
18264
  family: "numeric",
18087
18265
  deviceType: DeviceType.Sensor,
18088
18266
  memberDeviceType: DeviceType.Sensor,
18267
+ memberDeviceTypes: [DeviceType.Sensor],
18268
+ activeWhen: void 0,
18089
18269
  commandCaps: [],
18090
18270
  baseUnit: baseUnitOf(input.quantity),
18091
18271
  aggregates: NUMERIC_AGGREGATES,
@@ -18101,6 +18281,8 @@ function binary(input) {
18101
18281
  family: "binary",
18102
18282
  deviceType: DeviceType.Sensor,
18103
18283
  memberDeviceType: DeviceType.Sensor,
18284
+ memberDeviceTypes: [DeviceType.Sensor],
18285
+ activeWhen: void 0,
18104
18286
  commandCaps: [],
18105
18287
  quantity: "none",
18106
18288
  baseUnit: void 0,
@@ -18118,7 +18300,7 @@ var GROUP_TEMPLATES = [
18118
18300
  quantity: "temperature",
18119
18301
  defaultAggregate: "mean",
18120
18302
  empty: "null",
18121
- companions: [NOW]
18303
+ companions: [NOW$2]
18122
18304
  }),
18123
18305
  numeric({
18124
18306
  id: "humidity",
@@ -18129,7 +18311,7 @@ var GROUP_TEMPLATES = [
18129
18311
  quantity: "humidity",
18130
18312
  defaultAggregate: "mean",
18131
18313
  empty: "null",
18132
- companions: [NOW]
18314
+ companions: [NOW$2]
18133
18315
  }),
18134
18316
  numeric({
18135
18317
  id: "pressure",
@@ -18140,7 +18322,7 @@ var GROUP_TEMPLATES = [
18140
18322
  quantity: "pressure",
18141
18323
  defaultAggregate: "mean",
18142
18324
  empty: "null",
18143
- companions: [NOW]
18325
+ companions: [NOW$2]
18144
18326
  }),
18145
18327
  numeric({
18146
18328
  id: "illuminance",
@@ -18151,7 +18333,7 @@ var GROUP_TEMPLATES = [
18151
18333
  quantity: "illuminance",
18152
18334
  defaultAggregate: "mean",
18153
18335
  empty: "null",
18154
- companions: [NOW]
18336
+ companions: [NOW$2]
18155
18337
  }),
18156
18338
  numeric({
18157
18339
  id: "power",
@@ -18162,7 +18344,7 @@ var GROUP_TEMPLATES = [
18162
18344
  quantity: "power",
18163
18345
  defaultAggregate: "sum",
18164
18346
  empty: "omit",
18165
- companions: [NOW]
18347
+ companions: [NOW$2]
18166
18348
  }),
18167
18349
  numeric({
18168
18350
  id: "energy",
@@ -18173,7 +18355,7 @@ var GROUP_TEMPLATES = [
18173
18355
  quantity: "energy",
18174
18356
  defaultAggregate: "sum",
18175
18357
  empty: "omit",
18176
- companions: [NOW]
18358
+ companions: [NOW$2]
18177
18359
  }),
18178
18360
  numeric({
18179
18361
  id: "battery",
@@ -18208,7 +18390,7 @@ var GROUP_TEMPLATES = [
18208
18390
  quantity: "device",
18209
18391
  defaultAggregate: "mean",
18210
18392
  empty: "null",
18211
- companions: [NOW]
18393
+ companions: [NOW$2]
18212
18394
  }),
18213
18395
  binary({
18214
18396
  id: "motion",
@@ -18302,6 +18484,11 @@ var GROUP_TEMPLATES = [
18302
18484
  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.",
18303
18485
  deviceType: DeviceType.Switch,
18304
18486
  outputCap: "switch",
18487
+ outputField: "on",
18488
+ member: {
18489
+ cap: "switch",
18490
+ fieldPath: "on"
18491
+ },
18305
18492
  commandCaps: ["switch"]
18306
18493
  }),
18307
18494
  actuator({
@@ -18309,34 +18496,136 @@ var GROUP_TEMPLATES = [
18309
18496
  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.",
18310
18497
  deviceType: DeviceType.Light,
18311
18498
  outputCap: "switch",
18499
+ outputField: "on",
18500
+ member: {
18501
+ cap: "switch",
18502
+ fieldPath: "on"
18503
+ },
18312
18504
  commandCaps: [
18313
18505
  "switch",
18314
18506
  "brightness",
18315
18507
  "color"
18316
18508
  ]
18509
+ }),
18510
+ actuator({
18511
+ id: "fan",
18512
+ 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.",
18513
+ deviceType: DeviceType.Fan,
18514
+ outputCap: "switch",
18515
+ outputField: "on",
18516
+ member: {
18517
+ cap: "switch",
18518
+ fieldPath: "on"
18519
+ },
18520
+ commandCaps: ["switch", "fan-control"]
18521
+ }),
18522
+ actuator({
18523
+ id: "cover",
18524
+ 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.",
18525
+ deviceType: DeviceType.Cover,
18526
+ outputCap: "group-active",
18527
+ outputField: "active",
18528
+ member: {
18529
+ cap: "cover",
18530
+ fieldPath: "state"
18531
+ },
18532
+ activeWhen: [
18533
+ "open",
18534
+ "opening",
18535
+ "stopped"
18536
+ ],
18537
+ commandCaps: ["cover"]
18538
+ }),
18539
+ actuator({
18540
+ id: "valve",
18541
+ 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.",
18542
+ deviceType: DeviceType.Valve,
18543
+ outputCap: "group-active",
18544
+ outputField: "active",
18545
+ member: {
18546
+ cap: "valve",
18547
+ fieldPath: "state"
18548
+ },
18549
+ activeWhen: [
18550
+ "open",
18551
+ "opening",
18552
+ "stopped"
18553
+ ],
18554
+ commandCaps: ["valve"]
18555
+ }),
18556
+ actuator({
18557
+ id: "lock",
18558
+ 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.",
18559
+ deviceType: DeviceType.Lock,
18560
+ outputCap: "group-active",
18561
+ outputField: "active",
18562
+ member: {
18563
+ cap: "lock-control",
18564
+ fieldPath: "state"
18565
+ },
18566
+ activeWhen: ["locked"],
18567
+ commandCaps: ["lock-control"]
18568
+ }),
18569
+ actuator({
18570
+ id: "media-player",
18571
+ 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.",
18572
+ deviceType: DeviceType.MediaPlayer,
18573
+ outputCap: "group-active",
18574
+ outputField: "active",
18575
+ member: {
18576
+ cap: "media-player",
18577
+ fieldPath: "state"
18578
+ },
18579
+ activeWhen: ["playing", "buffering"],
18580
+ commandCaps: ["media-player"]
18581
+ }),
18582
+ actuator({
18583
+ id: "climate",
18584
+ 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.",
18585
+ deviceType: DeviceType.Thermostat,
18586
+ memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
18587
+ outputCap: "group-active",
18588
+ outputField: "active",
18589
+ member: {
18590
+ cap: "climate-control",
18591
+ fieldPath: "mode"
18592
+ },
18593
+ activeWhen: [
18594
+ "heat",
18595
+ "cool",
18596
+ "auto",
18597
+ "heat_cool",
18598
+ "fan_only",
18599
+ "dry"
18600
+ ],
18601
+ commandCaps: ["climate-control"]
18317
18602
  })
18318
18603
  ];
18319
18604
  function actuator(input) {
18320
18605
  return {
18321
- ...input,
18606
+ id: input.id,
18607
+ summary: input.summary,
18608
+ deviceType: input.deviceType,
18609
+ outputCap: input.outputCap,
18610
+ outputField: input.outputField,
18611
+ commandCaps: input.commandCaps,
18322
18612
  family: "actuator",
18323
18613
  role: void 0,
18324
18614
  memberDeviceType: input.deviceType,
18325
- outputField: "on",
18615
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
18616
+ activeWhen: input.activeWhen,
18326
18617
  quantity: "none",
18327
18618
  baseUnit: void 0,
18328
18619
  aggregates: BINARY_AGGREGATES,
18329
18620
  defaultAggregate: "any",
18330
18621
  empty: "offline",
18331
- accept: [{
18332
- cap: "switch",
18333
- fieldPath: "on"
18334
- }],
18622
+ accept: [input.member],
18335
18623
  companions: [CHANGED]
18336
18624
  };
18337
18625
  }
18338
18626
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
18339
18627
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
18628
+ DeviceType.Camera;
18340
18629
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
18341
18630
  /**
18342
18631
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -45994,7 +46283,20 @@ var NcRuleInputSchema = object({
45994
46283
  * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
45995
46284
  * path does not run Zod defaults.
45996
46285
  */
45997
- groupingSec: number().int().min(5).max(60).optional()
46286
+ groupingSec: number().int().min(5).max(60).optional(),
46287
+ /**
46288
+ * ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
46289
+ * carries "Correct" / "Wrong" buttons (and, where the channel has room, a
46290
+ * "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
46291
+ * same mark the Library writes, and records whose notification it was and
46292
+ * when. A channel with no buttons gets the same two choices as links.
46293
+ *
46294
+ * `.optional()`, never `.default()` (a Zod default does not run on the addon
46295
+ * cap path): absent and `false` both mean off, which is what every rule
46296
+ * authored before this field meant. An editor turns it off by writing
46297
+ * `false`, so it needs no `clear` key.
46298
+ */
46299
+ askVerdict: boolean().optional()
45998
46300
  });
45999
46301
  /**
46000
46302
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -58195,7 +58497,13 @@ results: array(object({
58195
58497
  /** Ms epoch of the attempt. */
58196
58498
  at: number()
58197
58499
  })) });
58198
- DeviceType.Switch, DeviceType.Light;
58500
+ DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58501
+ object({
58502
+ active: boolean().meta({ label: "Active" }),
58503
+ /** Ms epoch when the slice was last updated. */
58504
+ lastChangedAt: number()
58505
+ });
58506
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
58199
58507
  object({
58200
58508
  /** Members whose current value entered the aggregate. */
58201
58509
  included: number().int().nonnegative().meta(readingMeta("count", {
@@ -58213,7 +58521,7 @@ object({
58213
58521
  label: "Members"
58214
58522
  }))
58215
58523
  });
58216
- DeviceType.Sensor, DeviceType.Switch, DeviceType.Light;
58524
+ DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58217
58525
  object({
58218
58526
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
58219
58527
  position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -59120,7 +59428,14 @@ DeviceType.Lock, method(object({
59120
59428
  auth: "protected"
59121
59429
  }), method(object({
59122
59430
  deviceId: number().int().nonnegative(),
59123
- code: string().min(1).optional()
59431
+ code: string().min(1).optional(),
59432
+ /**
59433
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
59434
+ * with one call is refused unless the caller says it was confirmed. A
59435
+ * single lock ignores it. The refusal lives in the callee, so no
59436
+ * automation or API caller reaches the doors by skipping a dialog.
59437
+ */
59438
+ confirm: boolean().optional()
59124
59439
  }), _void(), {
59125
59440
  kind: "mutation",
59126
59441
  auth: "protected"
@@ -59128,6 +59443,11 @@ DeviceType.Lock, method(object({
59128
59443
  kind: "mutation",
59129
59444
  auth: "protected"
59130
59445
  });
59446
+ object({
59447
+ value: number().nullable().meta(readingMeta("device", { label: "Total" })),
59448
+ lastFetchedAt: number()
59449
+ });
59450
+ DeviceType.Sensor;
59131
59451
  /**
59132
59452
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
59133
59453
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
@@ -63531,7 +63851,7 @@ object({
63531
63851
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
63532
63852
  lastChangedAt: number()
63533
63853
  });
63534
- DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
63854
+ DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
63535
63855
  deviceId: number(),
63536
63856
  on: boolean()
63537
63857
  }), _void(), {
@@ -65223,6 +65543,7 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
65223
65543
  kind: "mutation",
65224
65544
  auth: "admin"
65225
65545
  });
65546
+ DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
65226
65547
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
65227
65548
  DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
65228
65549
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
@@ -68500,6 +68821,13 @@ Object.freeze({
68500
68821
  access: "view",
68501
68822
  role: "viewer"
68502
68823
  },
68824
+ "groupActive.getStatus": {
68825
+ capName: "group-active",
68826
+ capScope: "device",
68827
+ addonId: null,
68828
+ access: "view",
68829
+ role: "viewer"
68830
+ },
68503
68831
  "groupCommands.getStatus": {
68504
68832
  capName: "group-commands",
68505
68833
  capScope: "device",
@@ -69466,6 +69794,13 @@ Object.freeze({
69466
69794
  access: "create",
69467
69795
  role: "admin"
69468
69796
  },
69797
+ "meter.getStatus": {
69798
+ capName: "meter",
69799
+ capScope: "device",
69800
+ addonId: null,
69801
+ access: "view",
69802
+ role: "viewer"
69803
+ },
69469
69804
  "metricsProvider.collectSnapshot": {
69470
69805
  capName: "metrics-provider",
69471
69806
  capScope: "system",
@@ -78368,6 +78703,10 @@ var SENSOR_CAP_VOCABULARY = {
78368
78703
  icon: "flame"
78369
78704
  }]
78370
78705
  },
78706
+ "group-active": {
78707
+ scope: "device",
78708
+ noun: t("Group state", "Stato del gruppo")
78709
+ },
78371
78710
  "group-commands": {
78372
78711
  scope: "device",
78373
78712
  noun: t("Group command", "Comando di gruppo")
@@ -78424,6 +78763,17 @@ var SENSOR_CAP_VOCABULARY = {
78424
78763
  }],
78425
78764
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
78426
78765
  },
78766
+ meter: {
78767
+ scope: "device",
78768
+ noun: t("Meter", "Contatore"),
78769
+ state: [{
78770
+ kind: "numeric",
78771
+ field: "value",
78772
+ quantity: t("the total", "il totale"),
78773
+ label: t("Total", "Totale"),
78774
+ icon: "gauge"
78775
+ }]
78776
+ },
78427
78777
  "numeric-sensor": {
78428
78778
  scope: "device",
78429
78779
  noun: t("Sensor", "Sensore"),
@@ -79903,6 +80253,11 @@ Object.freeze({
79903
80253
  form: "single",
79904
80254
  optional: false
79905
80255
  }],
80256
+ "groupActive.getStatus": [{
80257
+ name: "deviceId",
80258
+ form: "single",
80259
+ optional: false
80260
+ }],
79906
80261
  "groupCommands.getStatus": [{
79907
80262
  name: "deviceId",
79908
80263
  form: "single",
@@ -80113,6 +80468,11 @@ Object.freeze({
80113
80468
  form: "single",
80114
80469
  optional: false
80115
80470
  }],
80471
+ "meter.getStatus": [{
80472
+ name: "deviceId",
80473
+ form: "single",
80474
+ optional: false
80475
+ }],
80116
80476
  "motion.getStatus": [{
80117
80477
  name: "deviceId",
80118
80478
  form: "single",
@@ -81720,7 +82080,6 @@ Object.freeze({
81720
82080
  "network-access": "ingress",
81721
82081
  "smtp-provider": "email"
81722
82082
  });
81723
- DeviceType.Camera;
81724
82083
  /**
81725
82084
  * A saved Customize assignment (D936). The schema is the type: callers use
81726
82085
  * `z.infer`, they do not restate the shape.
@@ -83047,7 +83406,7 @@ var AgentUIAddon = class extends BaseAddon {
83047
83406
  capability: adminUiCapability,
83048
83407
  provider: {
83049
83408
  getStaticDir: async () => ({ staticDir: path.resolve(__dirname) }),
83050
- getVersion: async () => ({ version: "1.2.276" })
83409
+ getVersion: async () => ({ version: "1.2.278" })
83051
83410
  }
83052
83411
  }];
83053
83412
  }