@camstack/addon-auth 1.2.169 → 1.2.170

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).
@@ -8937,6 +8937,7 @@ var CAP_NAMES = Object.freeze([
8937
8937
  "filesystem-browse",
8938
8938
  "flood",
8939
8939
  "gas",
8940
+ "group-active",
8940
8941
  "group-commands",
8941
8942
  "group-status",
8942
8943
  "heating-valve",
@@ -8959,6 +8960,7 @@ var CAP_NAMES = Object.freeze([
8959
8960
  "login-method",
8960
8961
  "media-player",
8961
8962
  "mesh-network",
8963
+ "meter",
8962
8964
  "metrics-provider",
8963
8965
  "model-convert",
8964
8966
  "model-distributor",
@@ -9757,6 +9759,10 @@ Object.freeze({
9757
9759
  "path": "detected",
9758
9760
  "valueType": "boolean"
9759
9761
  }],
9762
+ "group-active": [{
9763
+ "path": "active",
9764
+ "valueType": "boolean"
9765
+ }],
9760
9766
  "group-status": [
9761
9767
  {
9762
9768
  "path": "included",
@@ -10016,6 +10022,10 @@ Object.freeze({
10016
10022
  ]
10017
10023
  }
10018
10024
  ],
10025
+ "meter": [{
10026
+ "path": "value",
10027
+ "valueType": "number"
10028
+ }],
10019
10029
  "motion": [
10020
10030
  {
10021
10031
  "path": "detected",
@@ -10759,7 +10769,7 @@ object({
10759
10769
  params: record(string(), union([string(), number()])).optional()
10760
10770
  });
10761
10771
  //#endregion
10762
- //#region ../types/dist/err-msg-BXKzRBwg.mjs
10772
+ //#region ../types/dist/err-msg-DIorGYeC.mjs
10763
10773
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
10764
10774
  DeviceType["Camera"] = "camera";
10765
10775
  DeviceType["Hub"] = "hub";
@@ -10853,8 +10863,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
10853
10863
  DeviceType["PetFeeder"] = "pet-feeder";
10854
10864
  /** Built-in dishwasher — program lifecycle, door / remote-start gates,
10855
10865
  * salt and rinse-aid levels. Installed with the `dishwasher` cap.
10856
- * Sources: native Bosch Home Connect, reusable by similar integrations. */
10866
+ * Sources: native Bosch Home Connect, reusable by similar integrations.
10867
+ * A plug-built dishwasher carries running-state and power instead. */
10857
10868
  DeviceType["Dishwasher"] = "dishwasher";
10869
+ /** Washing machine. A plug-built one is running while its power stays
10870
+ * above a threshold. No program cap — that surface is the dishwasher's. */
10871
+ DeviceType["Washer"] = "washer";
10872
+ /** Tumble dryer. Same plug-built running surface as {@link Washer}. */
10873
+ DeviceType["Dryer"] = "dryer";
10858
10874
  return DeviceType;
10859
10875
  }({});
10860
10876
  var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
@@ -11112,7 +11128,7 @@ function errMsg(err) {
11112
11128
  return String(err);
11113
11129
  }
11114
11130
  //#endregion
11115
- //#region ../types/dist/composition-OhpuespA.mjs
11131
+ //#region ../types/dist/composition-Bb8iwHEJ.mjs
11116
11132
  /**
11117
11133
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11118
11134
  *
@@ -11427,6 +11443,13 @@ var table = {
11427
11443
  apply: () => {
11428
11444
  throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
11429
11445
  }
11446
+ },
11447
+ schmitt: {
11448
+ minArgs: 3,
11449
+ maxArgs: 5,
11450
+ apply: () => {
11451
+ throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
11452
+ }
11430
11453
  }
11431
11454
  };
11432
11455
  Object.freeze(Object.assign(Object.create(null), table));
@@ -11868,6 +11891,99 @@ function validateExpressionSource(src) {
11868
11891
  return null;
11869
11892
  }
11870
11893
  /**
11894
+ * One power reading becomes a washer, dryer or dishwasher (D944 helper).
11895
+ *
11896
+ * Standby of the control board is under 5 W; a motor or a heater is far
11897
+ * above that, so 5 W is the line. A door lock or a short pump spike is not
11898
+ * a cycle, so running starts only after 30 s above the line.
11899
+ *
11900
+ * A wash, dry or dishwasher pause (soak, heat-wait, heater off between
11901
+ * bursts) lasts several minutes. Ending the cycle on the first dip would
11902
+ * report "finished" in the middle of the program, so the stop dwell is
11903
+ * 10 minutes on every type. The number is stored per type so one machine
11904
+ * can move later without moving the others.
11905
+ */
11906
+ var APPLIANCE_TEMPLATE_ID = "appliance";
11907
+ var APPLIANCE_KINDS = [
11908
+ "washer",
11909
+ "dryer",
11910
+ "dishwasher"
11911
+ ];
11912
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
11913
+ /**
11914
+ * Statistics and integrals over a history read (D944).
11915
+ *
11916
+ * Pure: the same points always give the same answer, so a restart recomputes
11917
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
11918
+ * never the mean of the samples. A hole with no held value is not integrated
11919
+ * as zero. A truncated read is not published.
11920
+ */
11921
+ var STATISTIC_STATS = [
11922
+ "min",
11923
+ "max",
11924
+ "mean",
11925
+ "sum",
11926
+ "count",
11927
+ "change"
11928
+ ];
11929
+ /**
11930
+ * The range a statistics or integral helper asks history for (D944).
11931
+ *
11932
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
11933
+ * or 25 hours across a DST change. A tier is eligible only when its retention
11934
+ * is strictly longer than the longest that range can be. Forever qualifies.
11935
+ * Equal to a tier's retention is a refusal, not a short answer.
11936
+ */
11937
+ var MINUTE_MS = 6e4;
11938
+ var HOUR_MS = 60 * MINUTE_MS;
11939
+ var DAY_MS = 24 * HOUR_MS;
11940
+ var ROLLING_SPANS = [
11941
+ "1h",
11942
+ "24h",
11943
+ "2d",
11944
+ "7d",
11945
+ "30d",
11946
+ "custom"
11947
+ ];
11948
+ var CALENDAR_PERIODS = [
11949
+ "today",
11950
+ "yesterday",
11951
+ "this-week",
11952
+ "this-month"
11953
+ ];
11954
+ var RESET_PERIODS = [
11955
+ "never",
11956
+ "daily",
11957
+ "weekly",
11958
+ "monthly"
11959
+ ];
11960
+ 5 * MINUTE_MS;
11961
+ 24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
11962
+ 7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
11963
+ var rollingWindowObject = object({
11964
+ kind: literal("rolling"),
11965
+ span: _enum(ROLLING_SPANS),
11966
+ customMinutes: number().int().min(5).optional()
11967
+ }).check((payload) => {
11968
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
11969
+ code: "custom",
11970
+ message: "a custom range needs a duration in minutes",
11971
+ path: ["customMinutes"],
11972
+ input: payload.value
11973
+ });
11974
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
11975
+ code: "custom",
11976
+ message: "only a custom range carries a duration",
11977
+ path: ["customMinutes"],
11978
+ input: payload.value
11979
+ });
11980
+ });
11981
+ var RollingWindowSchema = rollingWindowObject;
11982
+ var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
11983
+ kind: literal("calendar"),
11984
+ period: _enum(CALENDAR_PERIODS)
11985
+ })]);
11986
+ /**
11871
11987
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11872
11988
  * id. Split out so helper schemas can name it without a cycle through
11873
11989
  * `composition.ts` (D659).
@@ -11893,7 +12009,13 @@ var GROUP_TEMPLATE_IDS = [
11893
12009
  "occupancy",
11894
12010
  "binary",
11895
12011
  "switch",
11896
- "light"
12012
+ "light",
12013
+ "fan",
12014
+ "cover",
12015
+ "valve",
12016
+ "lock",
12017
+ "media-player",
12018
+ "climate"
11897
12019
  ];
11898
12020
  var NUMERIC_AGGREGATES = [
11899
12021
  "mean",
@@ -11923,14 +12045,73 @@ var HelperMemberSchema = object({
11923
12045
  cap: string().min(1),
11924
12046
  fieldPath: string().min(1)
11925
12047
  });
11926
- var HelperSpecSchema = discriminatedUnion("kind", [object({
11927
- kind: literal("group"),
11928
- templateId: GroupTemplateIdSchema,
11929
- aggregate: AggregateReducerSchema,
11930
- members: array(HelperMemberSchema).min(1).max(64),
11931
- /** Actuator groups only. Readings leave this unset. */
11932
- active: ActiveCriterionSchema.optional()
11933
- })]);
12048
+ var HelperSpecSchema = discriminatedUnion("kind", [
12049
+ object({
12050
+ kind: literal("group"),
12051
+ templateId: GroupTemplateIdSchema,
12052
+ aggregate: AggregateReducerSchema,
12053
+ members: array(HelperMemberSchema).min(1).max(64),
12054
+ /** Actuator groups only. Readings leave this unset. */
12055
+ active: ActiveCriterionSchema.optional()
12056
+ }),
12057
+ object({
12058
+ kind: literal("appliance"),
12059
+ templateId: literal(APPLIANCE_TEMPLATE_ID),
12060
+ appliance: _enum(APPLIANCE_KINDS),
12061
+ thresholdWatts: number().positive(),
12062
+ startDwellMs: number().int().nonnegative(),
12063
+ stopDwellMs: number().int().nonnegative(),
12064
+ member: HelperMemberSchema
12065
+ }),
12066
+ object({
12067
+ kind: literal("statistic"),
12068
+ stat: _enum(STATISTIC_STATS),
12069
+ window: StatisticWindowSchema,
12070
+ source: HelperMemberSchema
12071
+ }),
12072
+ object({
12073
+ kind: literal("integral"),
12074
+ reset: _enum(RESET_PERIODS),
12075
+ output: _enum(["energy", "meter"]),
12076
+ source: HelperMemberSchema
12077
+ }),
12078
+ object({
12079
+ kind: literal("threshold"),
12080
+ source: HelperMemberSchema,
12081
+ high: number(),
12082
+ low: number(),
12083
+ onForMs: number().int().nonnegative(),
12084
+ offForMs: number().int().nonnegative()
12085
+ }),
12086
+ object({
12087
+ kind: literal("arithmetic"),
12088
+ op: _enum([
12089
+ "sum",
12090
+ "difference",
12091
+ "ratio"
12092
+ ]),
12093
+ inputs: array(HelperMemberSchema).min(2).max(64)
12094
+ }),
12095
+ object({
12096
+ kind: literal("expression"),
12097
+ expr: string().min(1),
12098
+ inputs: array(object({
12099
+ name: string().min(1),
12100
+ member: HelperMemberSchema
12101
+ })).min(1).max(64),
12102
+ output: _enum(["number", "boolean"])
12103
+ }),
12104
+ object({
12105
+ kind: literal("derivative"),
12106
+ window: RollingWindowSchema,
12107
+ per: _enum([
12108
+ "second",
12109
+ "minute",
12110
+ "hour"
12111
+ ]),
12112
+ source: HelperMemberSchema
12113
+ })
12114
+ ]);
11934
12115
  /** A composed device's stableId is this prefix plus the block id. */
11935
12116
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
11936
12117
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -11991,6 +12172,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
11991
12172
  "all"
11992
12173
  ]),
11993
12174
  reads: array(CompositionFieldReadSchema).min(1).max(64),
12175
+ /**
12176
+ * Set when the reads are an enum state, not a yes/no: the listed states
12177
+ * count as active (a cover is `open`). A state outside the list is inactive;
12178
+ * a read that is not a state at all is left out. Only `any` / `all` use it.
12179
+ */
12180
+ activeWhen: array(string().min(1)).min(1).optional(),
11994
12181
  /** `value` is the reading; the others are the member counts. */
11995
12182
  publish: _enum([
11996
12183
  "value",
@@ -12004,6 +12191,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12004
12191
  "omit",
12005
12192
  "offline"
12006
12193
  ])
12194
+ }),
12195
+ object({
12196
+ kind: literal("series"),
12197
+ read: CompositionFieldReadSchema,
12198
+ /** `value` is the statistic or the integral. The others are the gap counts. */
12199
+ publish: _enum([
12200
+ "value",
12201
+ "included",
12202
+ "excluded",
12203
+ "total"
12204
+ ]),
12205
+ /**
12206
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
12207
+ * device unseeded until history answers, so a restart cannot publish 0.
12208
+ */
12209
+ empty: _enum([
12210
+ "null",
12211
+ "omit",
12212
+ "offline"
12213
+ ])
12007
12214
  })
12008
12215
  ]);
12009
12216
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -17539,7 +17746,22 @@ var BrokerProviderInfoSchema = object({
17539
17746
  */
17540
17747
  interactiveConnectPath: string().min(1).optional(),
17541
17748
  /** Relative hub path to disconnect the linked account (same popup pattern). */
17542
- interactiveDisconnectPath: string().min(1).optional()
17749
+ interactiveDisconnectPath: string().min(1).optional(),
17750
+ /**
17751
+ * The kind signs in through a server-held interactive session instead of
17752
+ * (or before) typed credentials. `basePath` is a hub-relative route set
17753
+ * served by the owning addon (`/addon/<id>/...`) speaking the sign-in
17754
+ * contract: `POST {basePath}/start` (body: the form's settings) answers
17755
+ * `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
17756
+ * `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
17757
+ * 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
17758
+ * (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
17759
+ * existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
17760
+ * (`{ sessionId }`) drops the session. The dialog that edits a broker
17761
+ * offers it as the default path; the fields the session fills are
17762
+ * marked `filledBySignIn` in the kind's settings schema.
17763
+ */
17764
+ signIn: object({ basePath: string().min(1) }).optional()
17543
17765
  }))
17544
17766
  });
17545
17767
  var ListInputSchema = object({
@@ -18538,7 +18760,8 @@ var CompositionProblemSchema = object({
18538
18760
  "native-capability-replace",
18539
18761
  "mixed-quantity",
18540
18762
  "helper-mismatch",
18541
- "member-constraint"
18763
+ "member-constraint",
18764
+ "retention"
18542
18765
  ]),
18543
18766
  path: string(),
18544
18767
  message: string()
@@ -18772,13 +18995,17 @@ Object.freeze({
18772
18995
  latchedAt: {
18773
18996
  kind: "fixed",
18774
18997
  result: ["number", "null"]
18998
+ },
18999
+ schmitt: {
19000
+ kind: "fixed",
19001
+ result: ["boolean", "null"]
18775
19002
  }
18776
19003
  });
18777
19004
  /**
18778
19005
  * One catalog row per base reading a group helper can build (D944 §3).
18779
19006
  * Data, not a form default written into the block.
18780
19007
  */
18781
- var NOW = {
19008
+ var NOW$2 = {
18782
19009
  fieldPath: "lastFetchedAt",
18783
19010
  expr: "now"
18784
19011
  };
@@ -18792,6 +19019,8 @@ function numeric(input) {
18792
19019
  family: "numeric",
18793
19020
  deviceType: DeviceType.Sensor,
18794
19021
  memberDeviceType: DeviceType.Sensor,
19022
+ memberDeviceTypes: [DeviceType.Sensor],
19023
+ activeWhen: void 0,
18795
19024
  commandCaps: [],
18796
19025
  baseUnit: baseUnitOf(input.quantity),
18797
19026
  aggregates: NUMERIC_AGGREGATES,
@@ -18807,6 +19036,8 @@ function binary(input) {
18807
19036
  family: "binary",
18808
19037
  deviceType: DeviceType.Sensor,
18809
19038
  memberDeviceType: DeviceType.Sensor,
19039
+ memberDeviceTypes: [DeviceType.Sensor],
19040
+ activeWhen: void 0,
18810
19041
  commandCaps: [],
18811
19042
  quantity: "none",
18812
19043
  baseUnit: void 0,
@@ -18824,7 +19055,7 @@ var GROUP_TEMPLATES = [
18824
19055
  quantity: "temperature",
18825
19056
  defaultAggregate: "mean",
18826
19057
  empty: "null",
18827
- companions: [NOW]
19058
+ companions: [NOW$2]
18828
19059
  }),
18829
19060
  numeric({
18830
19061
  id: "humidity",
@@ -18835,7 +19066,7 @@ var GROUP_TEMPLATES = [
18835
19066
  quantity: "humidity",
18836
19067
  defaultAggregate: "mean",
18837
19068
  empty: "null",
18838
- companions: [NOW]
19069
+ companions: [NOW$2]
18839
19070
  }),
18840
19071
  numeric({
18841
19072
  id: "pressure",
@@ -18846,7 +19077,7 @@ var GROUP_TEMPLATES = [
18846
19077
  quantity: "pressure",
18847
19078
  defaultAggregate: "mean",
18848
19079
  empty: "null",
18849
- companions: [NOW]
19080
+ companions: [NOW$2]
18850
19081
  }),
18851
19082
  numeric({
18852
19083
  id: "illuminance",
@@ -18857,7 +19088,7 @@ var GROUP_TEMPLATES = [
18857
19088
  quantity: "illuminance",
18858
19089
  defaultAggregate: "mean",
18859
19090
  empty: "null",
18860
- companions: [NOW]
19091
+ companions: [NOW$2]
18861
19092
  }),
18862
19093
  numeric({
18863
19094
  id: "power",
@@ -18868,7 +19099,7 @@ var GROUP_TEMPLATES = [
18868
19099
  quantity: "power",
18869
19100
  defaultAggregate: "sum",
18870
19101
  empty: "omit",
18871
- companions: [NOW]
19102
+ companions: [NOW$2]
18872
19103
  }),
18873
19104
  numeric({
18874
19105
  id: "energy",
@@ -18879,7 +19110,7 @@ var GROUP_TEMPLATES = [
18879
19110
  quantity: "energy",
18880
19111
  defaultAggregate: "sum",
18881
19112
  empty: "omit",
18882
- companions: [NOW]
19113
+ companions: [NOW$2]
18883
19114
  }),
18884
19115
  numeric({
18885
19116
  id: "battery",
@@ -18914,7 +19145,7 @@ var GROUP_TEMPLATES = [
18914
19145
  quantity: "device",
18915
19146
  defaultAggregate: "mean",
18916
19147
  empty: "null",
18917
- companions: [NOW]
19148
+ companions: [NOW$2]
18918
19149
  }),
18919
19150
  binary({
18920
19151
  id: "motion",
@@ -19008,6 +19239,11 @@ var GROUP_TEMPLATES = [
19008
19239
  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.",
19009
19240
  deviceType: DeviceType.Switch,
19010
19241
  outputCap: "switch",
19242
+ outputField: "on",
19243
+ member: {
19244
+ cap: "switch",
19245
+ fieldPath: "on"
19246
+ },
19011
19247
  commandCaps: ["switch"]
19012
19248
  }),
19013
19249
  actuator({
@@ -19015,34 +19251,136 @@ var GROUP_TEMPLATES = [
19015
19251
  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.",
19016
19252
  deviceType: DeviceType.Light,
19017
19253
  outputCap: "switch",
19254
+ outputField: "on",
19255
+ member: {
19256
+ cap: "switch",
19257
+ fieldPath: "on"
19258
+ },
19018
19259
  commandCaps: [
19019
19260
  "switch",
19020
19261
  "brightness",
19021
19262
  "color"
19022
19263
  ]
19264
+ }),
19265
+ actuator({
19266
+ id: "fan",
19267
+ 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.",
19268
+ deviceType: DeviceType.Fan,
19269
+ outputCap: "switch",
19270
+ outputField: "on",
19271
+ member: {
19272
+ cap: "switch",
19273
+ fieldPath: "on"
19274
+ },
19275
+ commandCaps: ["switch", "fan-control"]
19276
+ }),
19277
+ actuator({
19278
+ id: "cover",
19279
+ 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.",
19280
+ deviceType: DeviceType.Cover,
19281
+ outputCap: "group-active",
19282
+ outputField: "active",
19283
+ member: {
19284
+ cap: "cover",
19285
+ fieldPath: "state"
19286
+ },
19287
+ activeWhen: [
19288
+ "open",
19289
+ "opening",
19290
+ "stopped"
19291
+ ],
19292
+ commandCaps: ["cover"]
19293
+ }),
19294
+ actuator({
19295
+ id: "valve",
19296
+ 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.",
19297
+ deviceType: DeviceType.Valve,
19298
+ outputCap: "group-active",
19299
+ outputField: "active",
19300
+ member: {
19301
+ cap: "valve",
19302
+ fieldPath: "state"
19303
+ },
19304
+ activeWhen: [
19305
+ "open",
19306
+ "opening",
19307
+ "stopped"
19308
+ ],
19309
+ commandCaps: ["valve"]
19310
+ }),
19311
+ actuator({
19312
+ id: "lock",
19313
+ 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.",
19314
+ deviceType: DeviceType.Lock,
19315
+ outputCap: "group-active",
19316
+ outputField: "active",
19317
+ member: {
19318
+ cap: "lock-control",
19319
+ fieldPath: "state"
19320
+ },
19321
+ activeWhen: ["locked"],
19322
+ commandCaps: ["lock-control"]
19323
+ }),
19324
+ actuator({
19325
+ id: "media-player",
19326
+ 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.",
19327
+ deviceType: DeviceType.MediaPlayer,
19328
+ outputCap: "group-active",
19329
+ outputField: "active",
19330
+ member: {
19331
+ cap: "media-player",
19332
+ fieldPath: "state"
19333
+ },
19334
+ activeWhen: ["playing", "buffering"],
19335
+ commandCaps: ["media-player"]
19336
+ }),
19337
+ actuator({
19338
+ id: "climate",
19339
+ 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.",
19340
+ deviceType: DeviceType.Thermostat,
19341
+ memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
19342
+ outputCap: "group-active",
19343
+ outputField: "active",
19344
+ member: {
19345
+ cap: "climate-control",
19346
+ fieldPath: "mode"
19347
+ },
19348
+ activeWhen: [
19349
+ "heat",
19350
+ "cool",
19351
+ "auto",
19352
+ "heat_cool",
19353
+ "fan_only",
19354
+ "dry"
19355
+ ],
19356
+ commandCaps: ["climate-control"]
19023
19357
  })
19024
19358
  ];
19025
19359
  function actuator(input) {
19026
19360
  return {
19027
- ...input,
19361
+ id: input.id,
19362
+ summary: input.summary,
19363
+ deviceType: input.deviceType,
19364
+ outputCap: input.outputCap,
19365
+ outputField: input.outputField,
19366
+ commandCaps: input.commandCaps,
19028
19367
  family: "actuator",
19029
19368
  role: void 0,
19030
19369
  memberDeviceType: input.deviceType,
19031
- outputField: "on",
19370
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
19371
+ activeWhen: input.activeWhen,
19032
19372
  quantity: "none",
19033
19373
  baseUnit: void 0,
19034
19374
  aggregates: BINARY_AGGREGATES,
19035
19375
  defaultAggregate: "any",
19036
19376
  empty: "offline",
19037
- accept: [{
19038
- cap: "switch",
19039
- fieldPath: "on"
19040
- }],
19377
+ accept: [input.member],
19041
19378
  companions: [CHANGED]
19042
19379
  };
19043
19380
  }
19044
19381
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
19045
19382
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
19383
+ DeviceType.Camera;
19046
19384
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
19047
19385
  /**
19048
19386
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -44083,7 +44421,7 @@ var NetworkAccessStatusSchema = object({
44083
44421
  });
44084
44422
  /**
44085
44423
  * Optional, richer endpoint shape returned by providers that expose
44086
- * MORE than one ingress concurrently (Tailscale Ingress with mixed
44424
+ * MORE than one ingress concurrently (Tailscale Funnel with mixed
44087
44425
  * serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
44088
44426
  * the originating provider config (mode + sourcePort) so the
44089
44427
  * orchestrator UI can label rows distinctly. Providers that expose only
@@ -46726,7 +47064,20 @@ var NcRuleInputSchema = object({
46726
47064
  * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
46727
47065
  * path does not run Zod defaults.
46728
47066
  */
46729
- groupingSec: number().int().min(5).max(60).optional()
47067
+ groupingSec: number().int().min(5).max(60).optional(),
47068
+ /**
47069
+ * ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
47070
+ * carries "Correct" / "Wrong" buttons (and, where the channel has room, a
47071
+ * "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
47072
+ * same mark the Library writes, and records whose notification it was and
47073
+ * when. A channel with no buttons gets the same two choices as links.
47074
+ *
47075
+ * `.optional()`, never `.default()` (a Zod default does not run on the addon
47076
+ * cap path): absent and `false` both mean off, which is what every rule
47077
+ * authored before this field meant. An editor turns it off by writing
47078
+ * `false`, so it needs no `clear` key.
47079
+ */
47080
+ askVerdict: boolean().optional()
46730
47081
  });
46731
47082
  /**
46732
47083
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -57234,7 +57585,7 @@ var BatteryStatusSchema = object({
57234
57585
  */
57235
57586
  binary: boolean().optional().meta({ label: "Binary indicator" })
57236
57587
  });
57237
- DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
57588
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
57238
57589
  method(object({
57239
57590
  deviceId: number(),
57240
57591
  /** Bound on the wait. Sensible range 3000–10000ms. */
@@ -58978,7 +59329,13 @@ results: array(object({
58978
59329
  /** Ms epoch of the attempt. */
58979
59330
  at: number()
58980
59331
  })) });
58981
- DeviceType.Switch, DeviceType.Light;
59332
+ DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
59333
+ object({
59334
+ active: boolean().meta({ label: "Active" }),
59335
+ /** Ms epoch when the slice was last updated. */
59336
+ lastChangedAt: number()
59337
+ });
59338
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
58982
59339
  object({
58983
59340
  /** Members whose current value entered the aggregate. */
58984
59341
  included: number().int().nonnegative().meta(readingMeta("count", {
@@ -58996,7 +59353,7 @@ object({
58996
59353
  label: "Members"
58997
59354
  }))
58998
59355
  });
58999
- DeviceType.Sensor, DeviceType.Switch, DeviceType.Light;
59356
+ DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
59000
59357
  object({
59001
59358
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
59002
59359
  position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -59903,7 +60260,14 @@ DeviceType.Lock, method(object({
59903
60260
  auth: "protected"
59904
60261
  }), method(object({
59905
60262
  deviceId: number().int().nonnegative(),
59906
- code: string().min(1).optional()
60263
+ code: string().min(1).optional(),
60264
+ /**
60265
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
60266
+ * with one call is refused unless the caller says it was confirmed. A
60267
+ * single lock ignores it. The refusal lives in the callee, so no
60268
+ * automation or API caller reaches the doors by skipping a dialog.
60269
+ */
60270
+ confirm: boolean().optional()
59907
60271
  }), _void(), {
59908
60272
  kind: "mutation",
59909
60273
  auth: "protected"
@@ -59911,6 +60275,11 @@ DeviceType.Lock, method(object({
59911
60275
  kind: "mutation",
59912
60276
  auth: "protected"
59913
60277
  });
60278
+ object({
60279
+ value: number().nullable().meta(readingMeta("device", { label: "Total" })),
60280
+ lastFetchedAt: number()
60281
+ });
60282
+ DeviceType.Sensor;
59914
60283
  /**
59915
60284
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
59916
60285
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
@@ -61818,9 +62187,9 @@ object({
61818
62187
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
61819
62188
  kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
61820
62189
  /** Voltage in volts. */
61821
- volts: number().optional().meta(readingMeta("voltage")),
62190
+ volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
61822
62191
  /** Current in amperes. */
61823
- amps: number().optional().meta(readingMeta("current")),
62192
+ amps: number().optional().meta(readingMeta("current", { label: "Current" })),
61824
62193
  /** Apparent power in volt-amperes. */
61825
62194
  va: number().optional().meta(readingMeta("apparent-power")),
61826
62195
  /** Power factor (0..1) if reported. */
@@ -61828,7 +62197,23 @@ object({
61828
62197
  /** Ms epoch when the slice was last updated. */
61829
62198
  lastFetchedAt: number()
61830
62199
  });
61831
- DeviceType.Sensor;
62200
+ [
62201
+ DeviceType.Sensor,
62202
+ DeviceType.Switch,
62203
+ DeviceType.Light,
62204
+ DeviceType.Fan,
62205
+ DeviceType.Climate,
62206
+ DeviceType.Thermostat,
62207
+ DeviceType.Humidifier,
62208
+ DeviceType.WaterHeater,
62209
+ DeviceType.MediaPlayer,
62210
+ DeviceType.Washer,
62211
+ DeviceType.Dryer,
62212
+ DeviceType.Dishwasher,
62213
+ DeviceType.Vacuum,
62214
+ DeviceType.LawnMower,
62215
+ DeviceType.PetFeeder
62216
+ ].filter((type) => type !== DeviceType.Sensor);
61832
62217
  /**
61833
62218
  * Presence cap. Models HA `person.*` and `device_tracker.*` entities
61834
62219
  * on `DeviceType.Presence`. Read-only — no setters: presence is
@@ -62275,7 +62660,7 @@ object({
62275
62660
  phase: string().nullable()
62276
62661
  });
62277
62662
  Object.values(DeviceType);
62278
- DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
62663
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
62279
62664
  DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
62280
62665
  kind: "mutation",
62281
62666
  auth: "admin"
@@ -64314,7 +64699,7 @@ object({
64314
64699
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
64315
64700
  lastChangedAt: number()
64316
64701
  });
64317
- DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
64702
+ DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
64318
64703
  deviceId: number(),
64319
64704
  on: boolean()
64320
64705
  }), _void(), {
@@ -66006,8 +66391,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
66006
66391
  kind: "mutation",
66007
66392
  auth: "admin"
66008
66393
  });
66394
+ DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
66009
66395
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
66010
- 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.Camera, DeviceType.Camera, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
66396
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, 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.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
66011
66397
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
66012
66398
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
66013
66399
  new Set(CAP_NAMES);
@@ -66060,7 +66446,7 @@ var AccessoryKind = {
66060
66446
  PrivacyMask: DeviceRole.PrivacyMask
66061
66447
  };
66062
66448
  AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
66063
- DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
66449
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, 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;
66064
66450
  new Set(Object.values(DeviceType));
66065
66451
  Object.freeze({
66066
66452
  "accessories.getStatus": {
@@ -69283,6 +69669,13 @@ Object.freeze({
69283
69669
  access: "view",
69284
69670
  role: "viewer"
69285
69671
  },
69672
+ "groupActive.getStatus": {
69673
+ capName: "group-active",
69674
+ capScope: "device",
69675
+ addonId: null,
69676
+ access: "view",
69677
+ role: "viewer"
69678
+ },
69286
69679
  "groupCommands.getStatus": {
69287
69680
  capName: "group-commands",
69288
69681
  capScope: "device",
@@ -70249,6 +70642,13 @@ Object.freeze({
70249
70642
  access: "create",
70250
70643
  role: "admin"
70251
70644
  },
70645
+ "meter.getStatus": {
70646
+ capName: "meter",
70647
+ capScope: "device",
70648
+ addonId: null,
70649
+ access: "view",
70650
+ role: "viewer"
70651
+ },
70252
70652
  "metricsProvider.collectSnapshot": {
70253
70653
  capName: "metrics-provider",
70254
70654
  capScope: "system",
@@ -78347,7 +78747,39 @@ var APPLIANCE_CAP_VOCABULARY = {
78347
78747
  phrase: t("When {device} finishes", "Quando {device} finisce"),
78348
78748
  icon: "square"
78349
78749
  }
78350
- }
78750
+ },
78751
+ overrides: { byType: {
78752
+ [DeviceType.Washer]: {
78753
+ state: { running: {
78754
+ whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
78755
+ whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
78756
+ } },
78757
+ events: {
78758
+ onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
78759
+ onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
78760
+ }
78761
+ },
78762
+ [DeviceType.Dryer]: {
78763
+ state: { running: {
78764
+ whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
78765
+ whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
78766
+ } },
78767
+ events: {
78768
+ onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
78769
+ onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
78770
+ }
78771
+ },
78772
+ [DeviceType.Dishwasher]: {
78773
+ state: { running: {
78774
+ whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
78775
+ whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
78776
+ } },
78777
+ events: {
78778
+ onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
78779
+ onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
78780
+ }
78781
+ }
78782
+ } }
78351
78783
  },
78352
78784
  update: {
78353
78785
  scope: "device",
@@ -79119,6 +79551,10 @@ var SENSOR_CAP_VOCABULARY = {
79119
79551
  icon: "flame"
79120
79552
  }]
79121
79553
  },
79554
+ "group-active": {
79555
+ scope: "device",
79556
+ noun: t("Group state", "Stato del gruppo")
79557
+ },
79122
79558
  "group-commands": {
79123
79559
  scope: "device",
79124
79560
  noun: t("Group command", "Comando di gruppo")
@@ -79175,6 +79611,17 @@ var SENSOR_CAP_VOCABULARY = {
79175
79611
  }],
79176
79612
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
79177
79613
  },
79614
+ meter: {
79615
+ scope: "device",
79616
+ noun: t("Meter", "Contatore"),
79617
+ state: [{
79618
+ kind: "numeric",
79619
+ field: "value",
79620
+ quantity: t("the total", "il totale"),
79621
+ label: t("Total", "Totale"),
79622
+ icon: "gauge"
79623
+ }]
79624
+ },
79178
79625
  "numeric-sensor": {
79179
79626
  scope: "device",
79180
79627
  noun: t("Sensor", "Sensore"),
@@ -79647,8 +80094,47 @@ function projectAction(cap, action) {
79647
80094
  };
79648
80095
  }
79649
80096
  Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
79650
- 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;
80097
+ 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;
79651
80098
  DeviceFeature.BatteryOperated;
80099
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
80100
+ var HA_AS = "a power sensor (device_class power). Home Assistant has no laundry domain. running-state stays unexported until a null reading can be published as unavailable.";
80101
+ var HOMEKIT_REASON = "HomeKit has no laundry-appliance service. The export tab would pair an accessory with nothing on it: running-state is withheld until a null reading can be unavailable, and power is not a HomeKit service this export honours.";
80102
+ var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
80103
+ var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
80104
+ var MATTER_REASON = "No Matter export is built. The closest device types are Laundry Washer (0x0073) and Laundry Dryer (0x0074); a power threshold is not the Laundry Washer Mode cluster.";
80105
+ function withheld(reason) {
80106
+ return {
80107
+ [DeviceType.Washer]: {
80108
+ exported: false,
80109
+ reason
80110
+ },
80111
+ [DeviceType.Dryer]: {
80112
+ exported: false,
80113
+ reason
80114
+ },
80115
+ [DeviceType.Dishwasher]: {
80116
+ exported: false,
80117
+ reason
80118
+ }
80119
+ };
80120
+ }
80121
+ function offered(received) {
80122
+ return {
80123
+ [DeviceType.Washer]: {
80124
+ exported: true,
80125
+ as: received
80126
+ },
80127
+ [DeviceType.Dryer]: {
80128
+ exported: true,
80129
+ as: received
80130
+ },
80131
+ [DeviceType.Dishwasher]: {
80132
+ exported: true,
80133
+ as: received
80134
+ }
80135
+ };
80136
+ }
80137
+ offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
79652
80138
  Object.freeze({
79653
80139
  "accessories.getStatus": [{
79654
80140
  name: "deviceId",
@@ -80615,6 +81101,11 @@ Object.freeze({
80615
81101
  form: "single",
80616
81102
  optional: false
80617
81103
  }],
81104
+ "groupActive.getStatus": [{
81105
+ name: "deviceId",
81106
+ form: "single",
81107
+ optional: false
81108
+ }],
80618
81109
  "groupCommands.getStatus": [{
80619
81110
  name: "deviceId",
80620
81111
  form: "single",
@@ -80825,6 +81316,11 @@ Object.freeze({
80825
81316
  form: "single",
80826
81317
  optional: false
80827
81318
  }],
81319
+ "meter.getStatus": [{
81320
+ name: "deviceId",
81321
+ form: "single",
81322
+ optional: false
81323
+ }],
80828
81324
  "motion.getStatus": [{
80829
81325
  name: "deviceId",
80830
81326
  form: "single",
@@ -82432,7 +82928,6 @@ Object.freeze({
82432
82928
  "network-access": "ingress",
82433
82929
  "smtp-provider": "email"
82434
82930
  });
82435
- DeviceType.Camera;
82436
82931
  /**
82437
82932
  * A saved Customize assignment (D936). The schema is the type: callers use
82438
82933
  * `z.infer`, they do not restate the shape.