@camstack/addon-provider-homeassistant 1.2.629 → 1.2.631

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.
@@ -5574,7 +5574,7 @@ var ZodIssueCode = {
5574
5574
  var ZodFirstPartyTypeKind;
5575
5575
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5576
5576
  //#endregion
5577
- //#region ../types/dist/sleep-bykKrTgu.mjs
5577
+ //#region ../types/dist/sleep--jXS9hWo.mjs
5578
5578
  /**
5579
5579
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5580
5580
  * window to float samples (D455).
@@ -9017,6 +9017,7 @@ var CAP_NAMES = Object.freeze([
9017
9017
  "filesystem-browse",
9018
9018
  "flood",
9019
9019
  "gas",
9020
+ "group-active",
9020
9021
  "group-commands",
9021
9022
  "group-status",
9022
9023
  "heating-valve",
@@ -9039,6 +9040,7 @@ var CAP_NAMES = Object.freeze([
9039
9040
  "login-method",
9040
9041
  "media-player",
9041
9042
  "mesh-network",
9043
+ "meter",
9042
9044
  "metrics-provider",
9043
9045
  "model-convert",
9044
9046
  "model-distributor",
@@ -9837,6 +9839,10 @@ Object.freeze({
9837
9839
  "path": "detected",
9838
9840
  "valueType": "boolean"
9839
9841
  }],
9842
+ "group-active": [{
9843
+ "path": "active",
9844
+ "valueType": "boolean"
9845
+ }],
9840
9846
  "group-status": [
9841
9847
  {
9842
9848
  "path": "included",
@@ -10096,6 +10102,10 @@ Object.freeze({
10096
10102
  ]
10097
10103
  }
10098
10104
  ],
10105
+ "meter": [{
10106
+ "path": "value",
10107
+ "valueType": "number"
10108
+ }],
10099
10109
  "motion": [
10100
10110
  {
10101
10111
  "path": "detected",
@@ -11198,7 +11208,7 @@ function errMsg(err) {
11198
11208
  return String(err);
11199
11209
  }
11200
11210
  //#endregion
11201
- //#region ../types/dist/composition-B2rw5L29.mjs
11211
+ //#region ../types/dist/composition-Bb8iwHEJ.mjs
11202
11212
  /**
11203
11213
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11204
11214
  *
@@ -11513,6 +11523,13 @@ var table = {
11513
11523
  apply: () => {
11514
11524
  throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
11515
11525
  }
11526
+ },
11527
+ schmitt: {
11528
+ minArgs: 3,
11529
+ maxArgs: 5,
11530
+ apply: () => {
11531
+ throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
11532
+ }
11516
11533
  }
11517
11534
  };
11518
11535
  Object.freeze(Object.assign(Object.create(null), table));
@@ -11974,6 +11991,79 @@ var APPLIANCE_KINDS = [
11974
11991
  ];
11975
11992
  DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
11976
11993
  /**
11994
+ * Statistics and integrals over a history read (D944).
11995
+ *
11996
+ * Pure: the same points always give the same answer, so a restart recomputes
11997
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
11998
+ * never the mean of the samples. A hole with no held value is not integrated
11999
+ * as zero. A truncated read is not published.
12000
+ */
12001
+ var STATISTIC_STATS = [
12002
+ "min",
12003
+ "max",
12004
+ "mean",
12005
+ "sum",
12006
+ "count",
12007
+ "change"
12008
+ ];
12009
+ /**
12010
+ * The range a statistics or integral helper asks history for (D944).
12011
+ *
12012
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
12013
+ * or 25 hours across a DST change. A tier is eligible only when its retention
12014
+ * is strictly longer than the longest that range can be. Forever qualifies.
12015
+ * Equal to a tier's retention is a refusal, not a short answer.
12016
+ */
12017
+ var MINUTE_MS = 6e4;
12018
+ var HOUR_MS = 60 * MINUTE_MS;
12019
+ var DAY_MS = 24 * HOUR_MS;
12020
+ var ROLLING_SPANS = [
12021
+ "1h",
12022
+ "24h",
12023
+ "2d",
12024
+ "7d",
12025
+ "30d",
12026
+ "custom"
12027
+ ];
12028
+ var CALENDAR_PERIODS = [
12029
+ "today",
12030
+ "yesterday",
12031
+ "this-week",
12032
+ "this-month"
12033
+ ];
12034
+ var RESET_PERIODS = [
12035
+ "never",
12036
+ "daily",
12037
+ "weekly",
12038
+ "monthly"
12039
+ ];
12040
+ 5 * MINUTE_MS;
12041
+ 24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
12042
+ 7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
12043
+ var rollingWindowObject = object({
12044
+ kind: literal("rolling"),
12045
+ span: _enum(ROLLING_SPANS),
12046
+ customMinutes: number().int().min(5).optional()
12047
+ }).check((payload) => {
12048
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
12049
+ code: "custom",
12050
+ message: "a custom range needs a duration in minutes",
12051
+ path: ["customMinutes"],
12052
+ input: payload.value
12053
+ });
12054
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
12055
+ code: "custom",
12056
+ message: "only a custom range carries a duration",
12057
+ path: ["customMinutes"],
12058
+ input: payload.value
12059
+ });
12060
+ });
12061
+ var RollingWindowSchema = rollingWindowObject;
12062
+ var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
12063
+ kind: literal("calendar"),
12064
+ period: _enum(CALENDAR_PERIODS)
12065
+ })]);
12066
+ /**
11977
12067
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11978
12068
  * id. Split out so helper schemas can name it without a cycle through
11979
12069
  * `composition.ts` (D659).
@@ -11999,7 +12089,13 @@ var GROUP_TEMPLATE_IDS = [
11999
12089
  "occupancy",
12000
12090
  "binary",
12001
12091
  "switch",
12002
- "light"
12092
+ "light",
12093
+ "fan",
12094
+ "cover",
12095
+ "valve",
12096
+ "lock",
12097
+ "media-player",
12098
+ "climate"
12003
12099
  ];
12004
12100
  var NUMERIC_AGGREGATES = [
12005
12101
  "mean",
@@ -12029,22 +12125,73 @@ var HelperMemberSchema = object({
12029
12125
  cap: string().min(1),
12030
12126
  fieldPath: string().min(1)
12031
12127
  });
12032
- var HelperSpecSchema = discriminatedUnion("kind", [object({
12033
- kind: literal("group"),
12034
- templateId: GroupTemplateIdSchema,
12035
- aggregate: AggregateReducerSchema,
12036
- members: array(HelperMemberSchema).min(1).max(64),
12037
- /** Actuator groups only. Readings leave this unset. */
12038
- active: ActiveCriterionSchema.optional()
12039
- }), object({
12040
- kind: literal("appliance"),
12041
- templateId: literal(APPLIANCE_TEMPLATE_ID),
12042
- appliance: _enum(APPLIANCE_KINDS),
12043
- thresholdWatts: number().positive(),
12044
- startDwellMs: number().int().nonnegative(),
12045
- stopDwellMs: number().int().nonnegative(),
12046
- member: HelperMemberSchema
12047
- })]);
12128
+ var HelperSpecSchema = discriminatedUnion("kind", [
12129
+ object({
12130
+ kind: literal("group"),
12131
+ templateId: GroupTemplateIdSchema,
12132
+ aggregate: AggregateReducerSchema,
12133
+ members: array(HelperMemberSchema).min(1).max(64),
12134
+ /** Actuator groups only. Readings leave this unset. */
12135
+ active: ActiveCriterionSchema.optional()
12136
+ }),
12137
+ object({
12138
+ kind: literal("appliance"),
12139
+ templateId: literal(APPLIANCE_TEMPLATE_ID),
12140
+ appliance: _enum(APPLIANCE_KINDS),
12141
+ thresholdWatts: number().positive(),
12142
+ startDwellMs: number().int().nonnegative(),
12143
+ stopDwellMs: number().int().nonnegative(),
12144
+ member: HelperMemberSchema
12145
+ }),
12146
+ object({
12147
+ kind: literal("statistic"),
12148
+ stat: _enum(STATISTIC_STATS),
12149
+ window: StatisticWindowSchema,
12150
+ source: HelperMemberSchema
12151
+ }),
12152
+ object({
12153
+ kind: literal("integral"),
12154
+ reset: _enum(RESET_PERIODS),
12155
+ output: _enum(["energy", "meter"]),
12156
+ source: HelperMemberSchema
12157
+ }),
12158
+ object({
12159
+ kind: literal("threshold"),
12160
+ source: HelperMemberSchema,
12161
+ high: number(),
12162
+ low: number(),
12163
+ onForMs: number().int().nonnegative(),
12164
+ offForMs: number().int().nonnegative()
12165
+ }),
12166
+ object({
12167
+ kind: literal("arithmetic"),
12168
+ op: _enum([
12169
+ "sum",
12170
+ "difference",
12171
+ "ratio"
12172
+ ]),
12173
+ inputs: array(HelperMemberSchema).min(2).max(64)
12174
+ }),
12175
+ object({
12176
+ kind: literal("expression"),
12177
+ expr: string().min(1),
12178
+ inputs: array(object({
12179
+ name: string().min(1),
12180
+ member: HelperMemberSchema
12181
+ })).min(1).max(64),
12182
+ output: _enum(["number", "boolean"])
12183
+ }),
12184
+ object({
12185
+ kind: literal("derivative"),
12186
+ window: RollingWindowSchema,
12187
+ per: _enum([
12188
+ "second",
12189
+ "minute",
12190
+ "hour"
12191
+ ]),
12192
+ source: HelperMemberSchema
12193
+ })
12194
+ ]);
12048
12195
  /** A composed device's stableId is this prefix plus the block id. */
12049
12196
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
12050
12197
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -12105,6 +12252,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12105
12252
  "all"
12106
12253
  ]),
12107
12254
  reads: array(CompositionFieldReadSchema).min(1).max(64),
12255
+ /**
12256
+ * Set when the reads are an enum state, not a yes/no: the listed states
12257
+ * count as active (a cover is `open`). A state outside the list is inactive;
12258
+ * a read that is not a state at all is left out. Only `any` / `all` use it.
12259
+ */
12260
+ activeWhen: array(string().min(1)).min(1).optional(),
12108
12261
  /** `value` is the reading; the others are the member counts. */
12109
12262
  publish: _enum([
12110
12263
  "value",
@@ -12118,6 +12271,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12118
12271
  "omit",
12119
12272
  "offline"
12120
12273
  ])
12274
+ }),
12275
+ object({
12276
+ kind: literal("series"),
12277
+ read: CompositionFieldReadSchema,
12278
+ /** `value` is the statistic or the integral. The others are the gap counts. */
12279
+ publish: _enum([
12280
+ "value",
12281
+ "included",
12282
+ "excluded",
12283
+ "total"
12284
+ ]),
12285
+ /**
12286
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
12287
+ * device unseeded until history answers, so a restart cannot publish 0.
12288
+ */
12289
+ empty: _enum([
12290
+ "null",
12291
+ "omit",
12292
+ "offline"
12293
+ ])
12121
12294
  })
12122
12295
  ]);
12123
12296
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -18594,7 +18767,8 @@ var CompositionProblemSchema = object({
18594
18767
  "native-capability-replace",
18595
18768
  "mixed-quantity",
18596
18769
  "helper-mismatch",
18597
- "member-constraint"
18770
+ "member-constraint",
18771
+ "retention"
18598
18772
  ]),
18599
18773
  path: string(),
18600
18774
  message: string()
@@ -18828,13 +19002,17 @@ Object.freeze({
18828
19002
  latchedAt: {
18829
19003
  kind: "fixed",
18830
19004
  result: ["number", "null"]
19005
+ },
19006
+ schmitt: {
19007
+ kind: "fixed",
19008
+ result: ["boolean", "null"]
18831
19009
  }
18832
19010
  });
18833
19011
  /**
18834
19012
  * One catalog row per base reading a group helper can build (D944 §3).
18835
19013
  * Data, not a form default written into the block.
18836
19014
  */
18837
- var NOW = {
19015
+ var NOW$2 = {
18838
19016
  fieldPath: "lastFetchedAt",
18839
19017
  expr: "now"
18840
19018
  };
@@ -18848,6 +19026,8 @@ function numeric(input) {
18848
19026
  family: "numeric",
18849
19027
  deviceType: DeviceType.Sensor,
18850
19028
  memberDeviceType: DeviceType.Sensor,
19029
+ memberDeviceTypes: [DeviceType.Sensor],
19030
+ activeWhen: void 0,
18851
19031
  commandCaps: [],
18852
19032
  baseUnit: baseUnitOf(input.quantity),
18853
19033
  aggregates: NUMERIC_AGGREGATES,
@@ -18863,6 +19043,8 @@ function binary(input) {
18863
19043
  family: "binary",
18864
19044
  deviceType: DeviceType.Sensor,
18865
19045
  memberDeviceType: DeviceType.Sensor,
19046
+ memberDeviceTypes: [DeviceType.Sensor],
19047
+ activeWhen: void 0,
18866
19048
  commandCaps: [],
18867
19049
  quantity: "none",
18868
19050
  baseUnit: void 0,
@@ -18880,7 +19062,7 @@ var GROUP_TEMPLATES = [
18880
19062
  quantity: "temperature",
18881
19063
  defaultAggregate: "mean",
18882
19064
  empty: "null",
18883
- companions: [NOW]
19065
+ companions: [NOW$2]
18884
19066
  }),
18885
19067
  numeric({
18886
19068
  id: "humidity",
@@ -18891,7 +19073,7 @@ var GROUP_TEMPLATES = [
18891
19073
  quantity: "humidity",
18892
19074
  defaultAggregate: "mean",
18893
19075
  empty: "null",
18894
- companions: [NOW]
19076
+ companions: [NOW$2]
18895
19077
  }),
18896
19078
  numeric({
18897
19079
  id: "pressure",
@@ -18902,7 +19084,7 @@ var GROUP_TEMPLATES = [
18902
19084
  quantity: "pressure",
18903
19085
  defaultAggregate: "mean",
18904
19086
  empty: "null",
18905
- companions: [NOW]
19087
+ companions: [NOW$2]
18906
19088
  }),
18907
19089
  numeric({
18908
19090
  id: "illuminance",
@@ -18913,7 +19095,7 @@ var GROUP_TEMPLATES = [
18913
19095
  quantity: "illuminance",
18914
19096
  defaultAggregate: "mean",
18915
19097
  empty: "null",
18916
- companions: [NOW]
19098
+ companions: [NOW$2]
18917
19099
  }),
18918
19100
  numeric({
18919
19101
  id: "power",
@@ -18924,7 +19106,7 @@ var GROUP_TEMPLATES = [
18924
19106
  quantity: "power",
18925
19107
  defaultAggregate: "sum",
18926
19108
  empty: "omit",
18927
- companions: [NOW]
19109
+ companions: [NOW$2]
18928
19110
  }),
18929
19111
  numeric({
18930
19112
  id: "energy",
@@ -18935,7 +19117,7 @@ var GROUP_TEMPLATES = [
18935
19117
  quantity: "energy",
18936
19118
  defaultAggregate: "sum",
18937
19119
  empty: "omit",
18938
- companions: [NOW]
19120
+ companions: [NOW$2]
18939
19121
  }),
18940
19122
  numeric({
18941
19123
  id: "battery",
@@ -18970,7 +19152,7 @@ var GROUP_TEMPLATES = [
18970
19152
  quantity: "device",
18971
19153
  defaultAggregate: "mean",
18972
19154
  empty: "null",
18973
- companions: [NOW]
19155
+ companions: [NOW$2]
18974
19156
  }),
18975
19157
  binary({
18976
19158
  id: "motion",
@@ -19064,6 +19246,11 @@ var GROUP_TEMPLATES = [
19064
19246
  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.",
19065
19247
  deviceType: DeviceType.Switch,
19066
19248
  outputCap: "switch",
19249
+ outputField: "on",
19250
+ member: {
19251
+ cap: "switch",
19252
+ fieldPath: "on"
19253
+ },
19067
19254
  commandCaps: ["switch"]
19068
19255
  }),
19069
19256
  actuator({
@@ -19071,34 +19258,136 @@ var GROUP_TEMPLATES = [
19071
19258
  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.",
19072
19259
  deviceType: DeviceType.Light,
19073
19260
  outputCap: "switch",
19261
+ outputField: "on",
19262
+ member: {
19263
+ cap: "switch",
19264
+ fieldPath: "on"
19265
+ },
19074
19266
  commandCaps: [
19075
19267
  "switch",
19076
19268
  "brightness",
19077
19269
  "color"
19078
19270
  ]
19271
+ }),
19272
+ actuator({
19273
+ id: "fan",
19274
+ 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.",
19275
+ deviceType: DeviceType.Fan,
19276
+ outputCap: "switch",
19277
+ outputField: "on",
19278
+ member: {
19279
+ cap: "switch",
19280
+ fieldPath: "on"
19281
+ },
19282
+ commandCaps: ["switch", "fan-control"]
19283
+ }),
19284
+ actuator({
19285
+ id: "cover",
19286
+ 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.",
19287
+ deviceType: DeviceType.Cover,
19288
+ outputCap: "group-active",
19289
+ outputField: "active",
19290
+ member: {
19291
+ cap: "cover",
19292
+ fieldPath: "state"
19293
+ },
19294
+ activeWhen: [
19295
+ "open",
19296
+ "opening",
19297
+ "stopped"
19298
+ ],
19299
+ commandCaps: ["cover"]
19300
+ }),
19301
+ actuator({
19302
+ id: "valve",
19303
+ 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.",
19304
+ deviceType: DeviceType.Valve,
19305
+ outputCap: "group-active",
19306
+ outputField: "active",
19307
+ member: {
19308
+ cap: "valve",
19309
+ fieldPath: "state"
19310
+ },
19311
+ activeWhen: [
19312
+ "open",
19313
+ "opening",
19314
+ "stopped"
19315
+ ],
19316
+ commandCaps: ["valve"]
19317
+ }),
19318
+ actuator({
19319
+ id: "lock",
19320
+ 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.",
19321
+ deviceType: DeviceType.Lock,
19322
+ outputCap: "group-active",
19323
+ outputField: "active",
19324
+ member: {
19325
+ cap: "lock-control",
19326
+ fieldPath: "state"
19327
+ },
19328
+ activeWhen: ["locked"],
19329
+ commandCaps: ["lock-control"]
19330
+ }),
19331
+ actuator({
19332
+ id: "media-player",
19333
+ 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.",
19334
+ deviceType: DeviceType.MediaPlayer,
19335
+ outputCap: "group-active",
19336
+ outputField: "active",
19337
+ member: {
19338
+ cap: "media-player",
19339
+ fieldPath: "state"
19340
+ },
19341
+ activeWhen: ["playing", "buffering"],
19342
+ commandCaps: ["media-player"]
19343
+ }),
19344
+ actuator({
19345
+ id: "climate",
19346
+ 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.",
19347
+ deviceType: DeviceType.Thermostat,
19348
+ memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
19349
+ outputCap: "group-active",
19350
+ outputField: "active",
19351
+ member: {
19352
+ cap: "climate-control",
19353
+ fieldPath: "mode"
19354
+ },
19355
+ activeWhen: [
19356
+ "heat",
19357
+ "cool",
19358
+ "auto",
19359
+ "heat_cool",
19360
+ "fan_only",
19361
+ "dry"
19362
+ ],
19363
+ commandCaps: ["climate-control"]
19079
19364
  })
19080
19365
  ];
19081
19366
  function actuator(input) {
19082
19367
  return {
19083
- ...input,
19368
+ id: input.id,
19369
+ summary: input.summary,
19370
+ deviceType: input.deviceType,
19371
+ outputCap: input.outputCap,
19372
+ outputField: input.outputField,
19373
+ commandCaps: input.commandCaps,
19084
19374
  family: "actuator",
19085
19375
  role: void 0,
19086
19376
  memberDeviceType: input.deviceType,
19087
- outputField: "on",
19377
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
19378
+ activeWhen: input.activeWhen,
19088
19379
  quantity: "none",
19089
19380
  baseUnit: void 0,
19090
19381
  aggregates: BINARY_AGGREGATES,
19091
19382
  defaultAggregate: "any",
19092
19383
  empty: "offline",
19093
- accept: [{
19094
- cap: "switch",
19095
- fieldPath: "on"
19096
- }],
19384
+ accept: [input.member],
19097
19385
  companions: [CHANGED]
19098
19386
  };
19099
19387
  }
19100
19388
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
19101
19389
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
19390
+ DeviceType.Camera;
19102
19391
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
19103
19392
  /**
19104
19393
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -47277,7 +47566,20 @@ var NcRuleInputSchema = object({
47277
47566
  * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
47278
47567
  * path does not run Zod defaults.
47279
47568
  */
47280
- groupingSec: number().int().min(5).max(60).optional()
47569
+ groupingSec: number().int().min(5).max(60).optional(),
47570
+ /**
47571
+ * ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
47572
+ * carries "Correct" / "Wrong" buttons (and, where the channel has room, a
47573
+ * "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
47574
+ * same mark the Library writes, and records whose notification it was and
47575
+ * when. A channel with no buttons gets the same two choices as links.
47576
+ *
47577
+ * `.optional()`, never `.default()` (a Zod default does not run on the addon
47578
+ * cap path): absent and `false` both mean off, which is what every rule
47579
+ * authored before this field meant. An editor turns it off by writing
47580
+ * `false`, so it needs no `clear` key.
47581
+ */
47582
+ askVerdict: boolean().optional()
47281
47583
  });
47282
47584
  /**
47283
47585
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -60996,7 +61298,17 @@ var groupCommandsCapability = {
60996
61298
  scope: "device",
60997
61299
  deviceNative: true,
60998
61300
  mode: "singleton",
60999
- deviceTypes: [DeviceType.Switch, DeviceType.Light],
61301
+ deviceTypes: [
61302
+ DeviceType.Switch,
61303
+ DeviceType.Light,
61304
+ DeviceType.Fan,
61305
+ DeviceType.Cover,
61306
+ DeviceType.Valve,
61307
+ DeviceType.Lock,
61308
+ DeviceType.MediaPlayer,
61309
+ DeviceType.Thermostat,
61310
+ DeviceType.Climate
61311
+ ],
61000
61312
  methods: {},
61001
61313
  status: {
61002
61314
  schema: GroupCommandsSchema,
@@ -61014,6 +61326,49 @@ var groupCommandsCapability = {
61014
61326
  history: "none"
61015
61327
  };
61016
61328
  /**
61329
+ * Whether a helper actuator group counts as active (D944): at least one
61330
+ * included member is, or every included member is. What "active" means is the
61331
+ * type's: a cover is open, a lock is locked, a media player is playing, a
61332
+ * climate device is not off. A group of lights, switches and fans reports
61333
+ * `switch.on` instead; this cap is for the types whose own state is not a
61334
+ * yes/no. Unknown members are left out (`group-status` counts them) and an
61335
+ * empty included set takes the device offline, never `active: false`.
61336
+ */
61337
+ var GroupActiveSchema = object({
61338
+ active: boolean().meta({ label: "Active" }),
61339
+ /** Ms epoch when the slice was last updated. */
61340
+ lastChangedAt: number()
61341
+ });
61342
+ var groupActiveCapability = {
61343
+ name: "group-active",
61344
+ scope: "device",
61345
+ deviceNative: true,
61346
+ mode: "singleton",
61347
+ deviceTypes: [
61348
+ DeviceType.Cover,
61349
+ DeviceType.Valve,
61350
+ DeviceType.Lock,
61351
+ DeviceType.MediaPlayer,
61352
+ DeviceType.Climate,
61353
+ DeviceType.Thermostat
61354
+ ],
61355
+ methods: {},
61356
+ status: {
61357
+ schema: GroupActiveSchema,
61358
+ kind: "push"
61359
+ },
61360
+ runtimeState: GroupActiveSchema,
61361
+ /**
61362
+ * Runtime-state durability: **session** — recomputed from the members on the
61363
+ * next source event; a restored value would outlive the members it named.
61364
+ *
61365
+ * See `RuntimeStateDurability`. Enforced by
61366
+ * `scripts/check-runtime-state-durability.ts`.
61367
+ */
61368
+ durability: "session",
61369
+ history: "none"
61370
+ };
61371
+ /**
61017
61372
  * How many members of a helper group answered (D944). Counts are integers,
61018
61373
  * not measurements: zero included is a real count, never a stand-in reading.
61019
61374
  * The reading itself stays on the output capability. History is none — the
@@ -61044,7 +61399,14 @@ var groupStatusCapability = {
61044
61399
  deviceTypes: [
61045
61400
  DeviceType.Sensor,
61046
61401
  DeviceType.Switch,
61047
- DeviceType.Light
61402
+ DeviceType.Light,
61403
+ DeviceType.Fan,
61404
+ DeviceType.Cover,
61405
+ DeviceType.Valve,
61406
+ DeviceType.Lock,
61407
+ DeviceType.MediaPlayer,
61408
+ DeviceType.Thermostat,
61409
+ DeviceType.Climate
61048
61410
  ],
61049
61411
  methods: {},
61050
61412
  status: {
@@ -62317,7 +62679,14 @@ var lockControlCapability = {
62317
62679
  }),
62318
62680
  unlock: method(object({
62319
62681
  deviceId: number().int().nonnegative(),
62320
- code: string().min(1).optional()
62682
+ code: string().min(1).optional(),
62683
+ /**
62684
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
62685
+ * with one call is refused unless the caller says it was confirmed. A
62686
+ * single lock ignores it. The refusal lives in the callee, so no
62687
+ * automation or API caller reaches the doors by skipping a dialog.
62688
+ */
62689
+ confirm: boolean().optional()
62321
62690
  }), _void(), {
62322
62691
  kind: "mutation",
62323
62692
  auth: "protected"
@@ -62354,6 +62723,44 @@ var lockControlCapability = {
62354
62723
  volatileStateFields: ["lastChangedAt"]
62355
62724
  };
62356
62725
  /**
62726
+ * A monotonic total between resets (D944). Energy uses `power-meter.kwhTotal`
62727
+ * so dashboards keep one series; every other instantaneous reading lands here.
62728
+ * `value` is the time integral in the source quantity's accumulated base
62729
+ * (base-unit seconds, or kWh on the power meter). `null` is a gap, never zero.
62730
+ */
62731
+ var MeterStatusSchema = object({
62732
+ value: number().nullable().meta(readingMeta("device", { label: "Total" })),
62733
+ lastFetchedAt: number()
62734
+ });
62735
+ var meterCapability = {
62736
+ name: "meter",
62737
+ scope: "device",
62738
+ deviceNative: true,
62739
+ mode: "singleton",
62740
+ deviceTypes: [DeviceType.Sensor],
62741
+ methods: {},
62742
+ status: {
62743
+ schema: MeterStatusSchema,
62744
+ kind: "push"
62745
+ },
62746
+ runtimeState: MeterStatusSchema,
62747
+ /**
62748
+ * Runtime-state durability: **restored** — the total is a cache of the
62749
+ * history integral. A restart shows it only until the history pass
62750
+ * recomputes the open period; it is not an in-memory buffer.
62751
+ *
62752
+ * See `RuntimeStateDurability`. Enforced by
62753
+ * `scripts/check-runtime-state-durability.ts`.
62754
+ */
62755
+ durability: "restored",
62756
+ history: { fields: { value: {
62757
+ kind: "counter",
62758
+ deadband: .001,
62759
+ minIntervalMs: 6e4
62760
+ } } },
62761
+ volatileStateFields: ["lastFetchedAt"]
62762
+ };
62763
+ /**
62357
62764
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
62358
62765
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
62359
62766
  * `DeviceType.MediaPlayer`. Disjoint from the camera streaming
@@ -68122,7 +68529,8 @@ var switchCapability = {
68122
68529
  deviceTypes: [
68123
68530
  DeviceType.Switch,
68124
68531
  DeviceType.Siren,
68125
- DeviceType.Light
68532
+ DeviceType.Light,
68533
+ DeviceType.Fan
68126
68534
  ],
68127
68535
  methods: { setState: method(object({
68128
68536
  deviceId: number(),
@@ -70372,6 +70780,7 @@ function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
70372
70780
  if (state === "paused") return nativeSlice(false, "paused", previous, transitionAtMs, fetchedAt, null);
70373
70781
  return nativeSlice(false, state, previous, transitionAtMs, fetchedAt, null);
70374
70782
  }
70783
+ DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
70375
70784
  /**
70376
70785
  * Frozen unit → spec table. `•` in the doc marks each dimension's canonical
70377
70786
  * unit (`factor: 1, offset: 0`). °F derives from `°C = (°F − 32) × 5/9` ⇒
@@ -71100,6 +71509,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
71100
71509
  featureProbe: featureProbeCapability,
71101
71510
  flood: floodCapability,
71102
71511
  gas: gasCapability,
71512
+ groupActive: groupActiveCapability,
71103
71513
  groupCommands: groupCommandsCapability,
71104
71514
  groupStatus: groupStatusCapability,
71105
71515
  heatingValve: heatingValveCapability,
@@ -71111,6 +71521,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
71111
71521
  lawnMowerControl: lawnMowerControlCapability,
71112
71522
  lockControl: lockControlCapability,
71113
71523
  mediaPlayer: mediaPlayerCapability,
71524
+ meter: meterCapability,
71114
71525
  motion: motionCapability,
71115
71526
  motionTrigger: motionTriggerCapability,
71116
71527
  motionZones: motionZonesCapability,
@@ -75593,6 +76004,13 @@ Object.freeze({
75593
76004
  access: "view",
75594
76005
  role: "viewer"
75595
76006
  },
76007
+ "groupActive.getStatus": {
76008
+ capName: "group-active",
76009
+ capScope: "device",
76010
+ addonId: null,
76011
+ access: "view",
76012
+ role: "viewer"
76013
+ },
75596
76014
  "groupCommands.getStatus": {
75597
76015
  capName: "group-commands",
75598
76016
  capScope: "device",
@@ -76559,6 +76977,13 @@ Object.freeze({
76559
76977
  access: "create",
76560
76978
  role: "admin"
76561
76979
  },
76980
+ "meter.getStatus": {
76981
+ capName: "meter",
76982
+ capScope: "device",
76983
+ addonId: null,
76984
+ access: "view",
76985
+ role: "viewer"
76986
+ },
76562
76987
  "metricsProvider.collectSnapshot": {
76563
76988
  capName: "metrics-provider",
76564
76989
  capScope: "system",
@@ -85461,6 +85886,10 @@ var SENSOR_CAP_VOCABULARY = {
85461
85886
  icon: "flame"
85462
85887
  }]
85463
85888
  },
85889
+ "group-active": {
85890
+ scope: "device",
85891
+ noun: t("Group state", "Stato del gruppo")
85892
+ },
85464
85893
  "group-commands": {
85465
85894
  scope: "device",
85466
85895
  noun: t("Group command", "Comando di gruppo")
@@ -85517,6 +85946,17 @@ var SENSOR_CAP_VOCABULARY = {
85517
85946
  }],
85518
85947
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
85519
85948
  },
85949
+ meter: {
85950
+ scope: "device",
85951
+ noun: t("Meter", "Contatore"),
85952
+ state: [{
85953
+ kind: "numeric",
85954
+ field: "value",
85955
+ quantity: t("the total", "il totale"),
85956
+ label: t("Total", "Totale"),
85957
+ icon: "gauge"
85958
+ }]
85959
+ },
85520
85960
  "numeric-sensor": {
85521
85961
  scope: "device",
85522
85962
  noun: t("Sensor", "Sensore"),
@@ -87007,6 +87447,11 @@ Object.freeze({
87007
87447
  form: "single",
87008
87448
  optional: false
87009
87449
  }],
87450
+ "groupActive.getStatus": [{
87451
+ name: "deviceId",
87452
+ form: "single",
87453
+ optional: false
87454
+ }],
87010
87455
  "groupCommands.getStatus": [{
87011
87456
  name: "deviceId",
87012
87457
  form: "single",
@@ -87217,6 +87662,11 @@ Object.freeze({
87217
87662
  form: "single",
87218
87663
  optional: false
87219
87664
  }],
87665
+ "meter.getStatus": [{
87666
+ name: "deviceId",
87667
+ form: "single",
87668
+ optional: false
87669
+ }],
87220
87670
  "motion.getStatus": [{
87221
87671
  name: "deviceId",
87222
87672
  form: "single",
@@ -88824,7 +89274,6 @@ Object.freeze({
88824
89274
  "network-access": "ingress",
88825
89275
  "smtp-provider": "email"
88826
89276
  });
88827
- DeviceType.Camera;
88828
89277
  /**
88829
89278
  * A saved Customize assignment (D936). The schema is the type: callers use
88830
89279
  * `z.infer`, they do not restate the shape.