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