@camstack/addon-mqtt-broker 1.2.146 → 1.2.147

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.
@@ -5615,7 +5615,7 @@ var ZodIssueCode = {
5615
5615
  var ZodFirstPartyTypeKind;
5616
5616
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5617
5617
  //#endregion
5618
- //#region ../types/dist/sleep-bykKrTgu.mjs
5618
+ //#region ../types/dist/sleep--jXS9hWo.mjs
5619
5619
  /**
5620
5620
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5621
5621
  * window to float samples (D455).
@@ -8992,6 +8992,7 @@ var CAP_NAMES = Object.freeze([
8992
8992
  "filesystem-browse",
8993
8993
  "flood",
8994
8994
  "gas",
8995
+ "group-active",
8995
8996
  "group-commands",
8996
8997
  "group-status",
8997
8998
  "heating-valve",
@@ -9014,6 +9015,7 @@ var CAP_NAMES = Object.freeze([
9014
9015
  "login-method",
9015
9016
  "media-player",
9016
9017
  "mesh-network",
9018
+ "meter",
9017
9019
  "metrics-provider",
9018
9020
  "model-convert",
9019
9021
  "model-distributor",
@@ -9812,6 +9814,10 @@ Object.freeze({
9812
9814
  "path": "detected",
9813
9815
  "valueType": "boolean"
9814
9816
  }],
9817
+ "group-active": [{
9818
+ "path": "active",
9819
+ "valueType": "boolean"
9820
+ }],
9815
9821
  "group-status": [
9816
9822
  {
9817
9823
  "path": "included",
@@ -10071,6 +10077,10 @@ Object.freeze({
10071
10077
  ]
10072
10078
  }
10073
10079
  ],
10080
+ "meter": [{
10081
+ "path": "value",
10082
+ "valueType": "number"
10083
+ }],
10074
10084
  "motion": [
10075
10085
  {
10076
10086
  "path": "detected",
@@ -10814,7 +10824,7 @@ object({
10814
10824
  params: record(string(), union([string(), number()])).optional()
10815
10825
  });
10816
10826
  //#endregion
10817
- //#region ../types/dist/err-msg-BXKzRBwg.mjs
10827
+ //#region ../types/dist/err-msg-DIorGYeC.mjs
10818
10828
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
10819
10829
  DeviceType["Camera"] = "camera";
10820
10830
  DeviceType["Hub"] = "hub";
@@ -10908,8 +10918,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
10908
10918
  DeviceType["PetFeeder"] = "pet-feeder";
10909
10919
  /** Built-in dishwasher — program lifecycle, door / remote-start gates,
10910
10920
  * salt and rinse-aid levels. Installed with the `dishwasher` cap.
10911
- * Sources: native Bosch Home Connect, reusable by similar integrations. */
10921
+ * Sources: native Bosch Home Connect, reusable by similar integrations.
10922
+ * A plug-built dishwasher carries running-state and power instead. */
10912
10923
  DeviceType["Dishwasher"] = "dishwasher";
10924
+ /** Washing machine. A plug-built one is running while its power stays
10925
+ * above a threshold. No program cap — that surface is the dishwasher's. */
10926
+ DeviceType["Washer"] = "washer";
10927
+ /** Tumble dryer. Same plug-built running surface as {@link Washer}. */
10928
+ DeviceType["Dryer"] = "dryer";
10913
10929
  return DeviceType;
10914
10930
  }({});
10915
10931
  var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
@@ -11157,7 +11173,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
11157
11173
  return DeviceRole;
11158
11174
  }({});
11159
11175
  //#endregion
11160
- //#region ../types/dist/composition-OhpuespA.mjs
11176
+ //#region ../types/dist/composition-Bb8iwHEJ.mjs
11161
11177
  /**
11162
11178
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11163
11179
  *
@@ -11472,6 +11488,13 @@ var table = {
11472
11488
  apply: () => {
11473
11489
  throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
11474
11490
  }
11491
+ },
11492
+ schmitt: {
11493
+ minArgs: 3,
11494
+ maxArgs: 5,
11495
+ apply: () => {
11496
+ throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
11497
+ }
11475
11498
  }
11476
11499
  };
11477
11500
  Object.freeze(Object.assign(Object.create(null), table));
@@ -11913,6 +11936,99 @@ function validateExpressionSource(src) {
11913
11936
  return null;
11914
11937
  }
11915
11938
  /**
11939
+ * One power reading becomes a washer, dryer or dishwasher (D944 helper).
11940
+ *
11941
+ * Standby of the control board is under 5 W; a motor or a heater is far
11942
+ * above that, so 5 W is the line. A door lock or a short pump spike is not
11943
+ * a cycle, so running starts only after 30 s above the line.
11944
+ *
11945
+ * A wash, dry or dishwasher pause (soak, heat-wait, heater off between
11946
+ * bursts) lasts several minutes. Ending the cycle on the first dip would
11947
+ * report "finished" in the middle of the program, so the stop dwell is
11948
+ * 10 minutes on every type. The number is stored per type so one machine
11949
+ * can move later without moving the others.
11950
+ */
11951
+ var APPLIANCE_TEMPLATE_ID = "appliance";
11952
+ var APPLIANCE_KINDS = [
11953
+ "washer",
11954
+ "dryer",
11955
+ "dishwasher"
11956
+ ];
11957
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
11958
+ /**
11959
+ * Statistics and integrals over a history read (D944).
11960
+ *
11961
+ * Pure: the same points always give the same answer, so a restart recomputes
11962
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
11963
+ * never the mean of the samples. A hole with no held value is not integrated
11964
+ * as zero. A truncated read is not published.
11965
+ */
11966
+ var STATISTIC_STATS = [
11967
+ "min",
11968
+ "max",
11969
+ "mean",
11970
+ "sum",
11971
+ "count",
11972
+ "change"
11973
+ ];
11974
+ /**
11975
+ * The range a statistics or integral helper asks history for (D944).
11976
+ *
11977
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
11978
+ * or 25 hours across a DST change. A tier is eligible only when its retention
11979
+ * is strictly longer than the longest that range can be. Forever qualifies.
11980
+ * Equal to a tier's retention is a refusal, not a short answer.
11981
+ */
11982
+ var MINUTE_MS = 6e4;
11983
+ var HOUR_MS = 60 * MINUTE_MS;
11984
+ var DAY_MS = 24 * HOUR_MS;
11985
+ var ROLLING_SPANS = [
11986
+ "1h",
11987
+ "24h",
11988
+ "2d",
11989
+ "7d",
11990
+ "30d",
11991
+ "custom"
11992
+ ];
11993
+ var CALENDAR_PERIODS = [
11994
+ "today",
11995
+ "yesterday",
11996
+ "this-week",
11997
+ "this-month"
11998
+ ];
11999
+ var RESET_PERIODS = [
12000
+ "never",
12001
+ "daily",
12002
+ "weekly",
12003
+ "monthly"
12004
+ ];
12005
+ 5 * MINUTE_MS;
12006
+ 24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
12007
+ 7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
12008
+ var rollingWindowObject = object({
12009
+ kind: literal("rolling"),
12010
+ span: _enum(ROLLING_SPANS),
12011
+ customMinutes: number().int().min(5).optional()
12012
+ }).check((payload) => {
12013
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
12014
+ code: "custom",
12015
+ message: "a custom range needs a duration in minutes",
12016
+ path: ["customMinutes"],
12017
+ input: payload.value
12018
+ });
12019
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
12020
+ code: "custom",
12021
+ message: "only a custom range carries a duration",
12022
+ path: ["customMinutes"],
12023
+ input: payload.value
12024
+ });
12025
+ });
12026
+ var RollingWindowSchema = rollingWindowObject;
12027
+ var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
12028
+ kind: literal("calendar"),
12029
+ period: _enum(CALENDAR_PERIODS)
12030
+ })]);
12031
+ /**
11916
12032
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11917
12033
  * id. Split out so helper schemas can name it without a cycle through
11918
12034
  * `composition.ts` (D659).
@@ -11938,7 +12054,13 @@ var GROUP_TEMPLATE_IDS = [
11938
12054
  "occupancy",
11939
12055
  "binary",
11940
12056
  "switch",
11941
- "light"
12057
+ "light",
12058
+ "fan",
12059
+ "cover",
12060
+ "valve",
12061
+ "lock",
12062
+ "media-player",
12063
+ "climate"
11942
12064
  ];
11943
12065
  var NUMERIC_AGGREGATES = [
11944
12066
  "mean",
@@ -11968,14 +12090,73 @@ var HelperMemberSchema = object({
11968
12090
  cap: string().min(1),
11969
12091
  fieldPath: string().min(1)
11970
12092
  });
11971
- var HelperSpecSchema = discriminatedUnion("kind", [object({
11972
- kind: literal("group"),
11973
- templateId: GroupTemplateIdSchema,
11974
- aggregate: AggregateReducerSchema,
11975
- members: array(HelperMemberSchema).min(1).max(64),
11976
- /** Actuator groups only. Readings leave this unset. */
11977
- active: ActiveCriterionSchema.optional()
11978
- })]);
12093
+ var HelperSpecSchema = discriminatedUnion("kind", [
12094
+ object({
12095
+ kind: literal("group"),
12096
+ templateId: GroupTemplateIdSchema,
12097
+ aggregate: AggregateReducerSchema,
12098
+ members: array(HelperMemberSchema).min(1).max(64),
12099
+ /** Actuator groups only. Readings leave this unset. */
12100
+ active: ActiveCriterionSchema.optional()
12101
+ }),
12102
+ object({
12103
+ kind: literal("appliance"),
12104
+ templateId: literal(APPLIANCE_TEMPLATE_ID),
12105
+ appliance: _enum(APPLIANCE_KINDS),
12106
+ thresholdWatts: number().positive(),
12107
+ startDwellMs: number().int().nonnegative(),
12108
+ stopDwellMs: number().int().nonnegative(),
12109
+ member: HelperMemberSchema
12110
+ }),
12111
+ object({
12112
+ kind: literal("statistic"),
12113
+ stat: _enum(STATISTIC_STATS),
12114
+ window: StatisticWindowSchema,
12115
+ source: HelperMemberSchema
12116
+ }),
12117
+ object({
12118
+ kind: literal("integral"),
12119
+ reset: _enum(RESET_PERIODS),
12120
+ output: _enum(["energy", "meter"]),
12121
+ source: HelperMemberSchema
12122
+ }),
12123
+ object({
12124
+ kind: literal("threshold"),
12125
+ source: HelperMemberSchema,
12126
+ high: number(),
12127
+ low: number(),
12128
+ onForMs: number().int().nonnegative(),
12129
+ offForMs: number().int().nonnegative()
12130
+ }),
12131
+ object({
12132
+ kind: literal("arithmetic"),
12133
+ op: _enum([
12134
+ "sum",
12135
+ "difference",
12136
+ "ratio"
12137
+ ]),
12138
+ inputs: array(HelperMemberSchema).min(2).max(64)
12139
+ }),
12140
+ object({
12141
+ kind: literal("expression"),
12142
+ expr: string().min(1),
12143
+ inputs: array(object({
12144
+ name: string().min(1),
12145
+ member: HelperMemberSchema
12146
+ })).min(1).max(64),
12147
+ output: _enum(["number", "boolean"])
12148
+ }),
12149
+ object({
12150
+ kind: literal("derivative"),
12151
+ window: RollingWindowSchema,
12152
+ per: _enum([
12153
+ "second",
12154
+ "minute",
12155
+ "hour"
12156
+ ]),
12157
+ source: HelperMemberSchema
12158
+ })
12159
+ ]);
11979
12160
  /** A composed device's stableId is this prefix plus the block id. */
11980
12161
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
11981
12162
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -12036,6 +12217,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12036
12217
  "all"
12037
12218
  ]),
12038
12219
  reads: array(CompositionFieldReadSchema).min(1).max(64),
12220
+ /**
12221
+ * Set when the reads are an enum state, not a yes/no: the listed states
12222
+ * count as active (a cover is `open`). A state outside the list is inactive;
12223
+ * a read that is not a state at all is left out. Only `any` / `all` use it.
12224
+ */
12225
+ activeWhen: array(string().min(1)).min(1).optional(),
12039
12226
  /** `value` is the reading; the others are the member counts. */
12040
12227
  publish: _enum([
12041
12228
  "value",
@@ -12049,6 +12236,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12049
12236
  "omit",
12050
12237
  "offline"
12051
12238
  ])
12239
+ }),
12240
+ object({
12241
+ kind: literal("series"),
12242
+ read: CompositionFieldReadSchema,
12243
+ /** `value` is the statistic or the integral. The others are the gap counts. */
12244
+ publish: _enum([
12245
+ "value",
12246
+ "included",
12247
+ "excluded",
12248
+ "total"
12249
+ ]),
12250
+ /**
12251
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
12252
+ * device unseeded until history answers, so a restart cannot publish 0.
12253
+ */
12254
+ empty: _enum([
12255
+ "null",
12256
+ "omit",
12257
+ "offline"
12258
+ ])
12052
12259
  })
12053
12260
  ]);
12054
12261
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -17208,7 +17415,22 @@ var BrokerProviderInfoSchema = object({
17208
17415
  */
17209
17416
  interactiveConnectPath: string().min(1).optional(),
17210
17417
  /** Relative hub path to disconnect the linked account (same popup pattern). */
17211
- interactiveDisconnectPath: string().min(1).optional()
17418
+ interactiveDisconnectPath: string().min(1).optional(),
17419
+ /**
17420
+ * The kind signs in through a server-held interactive session instead of
17421
+ * (or before) typed credentials. `basePath` is a hub-relative route set
17422
+ * served by the owning addon (`/addon/<id>/...`) speaking the sign-in
17423
+ * contract: `POST {basePath}/start` (body: the form's settings) answers
17424
+ * `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
17425
+ * `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
17426
+ * 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
17427
+ * (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
17428
+ * existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
17429
+ * (`{ sessionId }`) drops the session. The dialog that edits a broker
17430
+ * offers it as the default path; the fields the session fills are
17431
+ * marked `filledBySignIn` in the kind's settings schema.
17432
+ */
17433
+ signIn: object({ basePath: string().min(1) }).optional()
17212
17434
  }))
17213
17435
  });
17214
17436
  var ListInputSchema = object({
@@ -18256,7 +18478,8 @@ var CompositionProblemSchema = object({
18256
18478
  "native-capability-replace",
18257
18479
  "mixed-quantity",
18258
18480
  "helper-mismatch",
18259
- "member-constraint"
18481
+ "member-constraint",
18482
+ "retention"
18260
18483
  ]),
18261
18484
  path: string(),
18262
18485
  message: string()
@@ -18490,13 +18713,17 @@ Object.freeze({
18490
18713
  latchedAt: {
18491
18714
  kind: "fixed",
18492
18715
  result: ["number", "null"]
18716
+ },
18717
+ schmitt: {
18718
+ kind: "fixed",
18719
+ result: ["boolean", "null"]
18493
18720
  }
18494
18721
  });
18495
18722
  /**
18496
18723
  * One catalog row per base reading a group helper can build (D944 §3).
18497
18724
  * Data, not a form default written into the block.
18498
18725
  */
18499
- var NOW = {
18726
+ var NOW$2 = {
18500
18727
  fieldPath: "lastFetchedAt",
18501
18728
  expr: "now"
18502
18729
  };
@@ -18510,6 +18737,8 @@ function numeric(input) {
18510
18737
  family: "numeric",
18511
18738
  deviceType: DeviceType.Sensor,
18512
18739
  memberDeviceType: DeviceType.Sensor,
18740
+ memberDeviceTypes: [DeviceType.Sensor],
18741
+ activeWhen: void 0,
18513
18742
  commandCaps: [],
18514
18743
  baseUnit: baseUnitOf(input.quantity),
18515
18744
  aggregates: NUMERIC_AGGREGATES,
@@ -18525,6 +18754,8 @@ function binary(input) {
18525
18754
  family: "binary",
18526
18755
  deviceType: DeviceType.Sensor,
18527
18756
  memberDeviceType: DeviceType.Sensor,
18757
+ memberDeviceTypes: [DeviceType.Sensor],
18758
+ activeWhen: void 0,
18528
18759
  commandCaps: [],
18529
18760
  quantity: "none",
18530
18761
  baseUnit: void 0,
@@ -18542,7 +18773,7 @@ var GROUP_TEMPLATES = [
18542
18773
  quantity: "temperature",
18543
18774
  defaultAggregate: "mean",
18544
18775
  empty: "null",
18545
- companions: [NOW]
18776
+ companions: [NOW$2]
18546
18777
  }),
18547
18778
  numeric({
18548
18779
  id: "humidity",
@@ -18553,7 +18784,7 @@ var GROUP_TEMPLATES = [
18553
18784
  quantity: "humidity",
18554
18785
  defaultAggregate: "mean",
18555
18786
  empty: "null",
18556
- companions: [NOW]
18787
+ companions: [NOW$2]
18557
18788
  }),
18558
18789
  numeric({
18559
18790
  id: "pressure",
@@ -18564,7 +18795,7 @@ var GROUP_TEMPLATES = [
18564
18795
  quantity: "pressure",
18565
18796
  defaultAggregate: "mean",
18566
18797
  empty: "null",
18567
- companions: [NOW]
18798
+ companions: [NOW$2]
18568
18799
  }),
18569
18800
  numeric({
18570
18801
  id: "illuminance",
@@ -18575,7 +18806,7 @@ var GROUP_TEMPLATES = [
18575
18806
  quantity: "illuminance",
18576
18807
  defaultAggregate: "mean",
18577
18808
  empty: "null",
18578
- companions: [NOW]
18809
+ companions: [NOW$2]
18579
18810
  }),
18580
18811
  numeric({
18581
18812
  id: "power",
@@ -18586,7 +18817,7 @@ var GROUP_TEMPLATES = [
18586
18817
  quantity: "power",
18587
18818
  defaultAggregate: "sum",
18588
18819
  empty: "omit",
18589
- companions: [NOW]
18820
+ companions: [NOW$2]
18590
18821
  }),
18591
18822
  numeric({
18592
18823
  id: "energy",
@@ -18597,7 +18828,7 @@ var GROUP_TEMPLATES = [
18597
18828
  quantity: "energy",
18598
18829
  defaultAggregate: "sum",
18599
18830
  empty: "omit",
18600
- companions: [NOW]
18831
+ companions: [NOW$2]
18601
18832
  }),
18602
18833
  numeric({
18603
18834
  id: "battery",
@@ -18632,7 +18863,7 @@ var GROUP_TEMPLATES = [
18632
18863
  quantity: "device",
18633
18864
  defaultAggregate: "mean",
18634
18865
  empty: "null",
18635
- companions: [NOW]
18866
+ companions: [NOW$2]
18636
18867
  }),
18637
18868
  binary({
18638
18869
  id: "motion",
@@ -18726,6 +18957,11 @@ var GROUP_TEMPLATES = [
18726
18957
  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.",
18727
18958
  deviceType: DeviceType.Switch,
18728
18959
  outputCap: "switch",
18960
+ outputField: "on",
18961
+ member: {
18962
+ cap: "switch",
18963
+ fieldPath: "on"
18964
+ },
18729
18965
  commandCaps: ["switch"]
18730
18966
  }),
18731
18967
  actuator({
@@ -18733,34 +18969,136 @@ var GROUP_TEMPLATES = [
18733
18969
  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.",
18734
18970
  deviceType: DeviceType.Light,
18735
18971
  outputCap: "switch",
18972
+ outputField: "on",
18973
+ member: {
18974
+ cap: "switch",
18975
+ fieldPath: "on"
18976
+ },
18736
18977
  commandCaps: [
18737
18978
  "switch",
18738
18979
  "brightness",
18739
18980
  "color"
18740
18981
  ]
18982
+ }),
18983
+ actuator({
18984
+ id: "fan",
18985
+ 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.",
18986
+ deviceType: DeviceType.Fan,
18987
+ outputCap: "switch",
18988
+ outputField: "on",
18989
+ member: {
18990
+ cap: "switch",
18991
+ fieldPath: "on"
18992
+ },
18993
+ commandCaps: ["switch", "fan-control"]
18994
+ }),
18995
+ actuator({
18996
+ id: "cover",
18997
+ 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.",
18998
+ deviceType: DeviceType.Cover,
18999
+ outputCap: "group-active",
19000
+ outputField: "active",
19001
+ member: {
19002
+ cap: "cover",
19003
+ fieldPath: "state"
19004
+ },
19005
+ activeWhen: [
19006
+ "open",
19007
+ "opening",
19008
+ "stopped"
19009
+ ],
19010
+ commandCaps: ["cover"]
19011
+ }),
19012
+ actuator({
19013
+ id: "valve",
19014
+ 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.",
19015
+ deviceType: DeviceType.Valve,
19016
+ outputCap: "group-active",
19017
+ outputField: "active",
19018
+ member: {
19019
+ cap: "valve",
19020
+ fieldPath: "state"
19021
+ },
19022
+ activeWhen: [
19023
+ "open",
19024
+ "opening",
19025
+ "stopped"
19026
+ ],
19027
+ commandCaps: ["valve"]
19028
+ }),
19029
+ actuator({
19030
+ id: "lock",
19031
+ 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.",
19032
+ deviceType: DeviceType.Lock,
19033
+ outputCap: "group-active",
19034
+ outputField: "active",
19035
+ member: {
19036
+ cap: "lock-control",
19037
+ fieldPath: "state"
19038
+ },
19039
+ activeWhen: ["locked"],
19040
+ commandCaps: ["lock-control"]
19041
+ }),
19042
+ actuator({
19043
+ id: "media-player",
19044
+ 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.",
19045
+ deviceType: DeviceType.MediaPlayer,
19046
+ outputCap: "group-active",
19047
+ outputField: "active",
19048
+ member: {
19049
+ cap: "media-player",
19050
+ fieldPath: "state"
19051
+ },
19052
+ activeWhen: ["playing", "buffering"],
19053
+ commandCaps: ["media-player"]
19054
+ }),
19055
+ actuator({
19056
+ id: "climate",
19057
+ 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.",
19058
+ deviceType: DeviceType.Thermostat,
19059
+ memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
19060
+ outputCap: "group-active",
19061
+ outputField: "active",
19062
+ member: {
19063
+ cap: "climate-control",
19064
+ fieldPath: "mode"
19065
+ },
19066
+ activeWhen: [
19067
+ "heat",
19068
+ "cool",
19069
+ "auto",
19070
+ "heat_cool",
19071
+ "fan_only",
19072
+ "dry"
19073
+ ],
19074
+ commandCaps: ["climate-control"]
18741
19075
  })
18742
19076
  ];
18743
19077
  function actuator(input) {
18744
19078
  return {
18745
- ...input,
19079
+ id: input.id,
19080
+ summary: input.summary,
19081
+ deviceType: input.deviceType,
19082
+ outputCap: input.outputCap,
19083
+ outputField: input.outputField,
19084
+ commandCaps: input.commandCaps,
18746
19085
  family: "actuator",
18747
19086
  role: void 0,
18748
19087
  memberDeviceType: input.deviceType,
18749
- outputField: "on",
19088
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
19089
+ activeWhen: input.activeWhen,
18750
19090
  quantity: "none",
18751
19091
  baseUnit: void 0,
18752
19092
  aggregates: BINARY_AGGREGATES,
18753
19093
  defaultAggregate: "any",
18754
19094
  empty: "offline",
18755
- accept: [{
18756
- cap: "switch",
18757
- fieldPath: "on"
18758
- }],
19095
+ accept: [input.member],
18759
19096
  companions: [CHANGED]
18760
19097
  };
18761
19098
  }
18762
19099
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
18763
19100
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
19101
+ DeviceType.Camera;
18764
19102
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
18765
19103
  /**
18766
19104
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -43794,7 +44132,7 @@ var NetworkAccessStatusSchema = object({
43794
44132
  });
43795
44133
  /**
43796
44134
  * Optional, richer endpoint shape returned by providers that expose
43797
- * MORE than one ingress concurrently (Tailscale Ingress with mixed
44135
+ * MORE than one ingress concurrently (Tailscale Funnel with mixed
43798
44136
  * serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
43799
44137
  * the originating provider config (mode + sourcePort) so the
43800
44138
  * orchestrator UI can label rows distinctly. Providers that expose only
@@ -46437,7 +46775,20 @@ var NcRuleInputSchema = object({
46437
46775
  * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
46438
46776
  * path does not run Zod defaults.
46439
46777
  */
46440
- groupingSec: number().int().min(5).max(60).optional()
46778
+ groupingSec: number().int().min(5).max(60).optional(),
46779
+ /**
46780
+ * ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
46781
+ * carries "Correct" / "Wrong" buttons (and, where the channel has room, a
46782
+ * "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
46783
+ * same mark the Library writes, and records whose notification it was and
46784
+ * when. A channel with no buttons gets the same two choices as links.
46785
+ *
46786
+ * `.optional()`, never `.default()` (a Zod default does not run on the addon
46787
+ * cap path): absent and `false` both mean off, which is what every rule
46788
+ * authored before this field meant. An editor turns it off by writing
46789
+ * `false`, so it needs no `clear` key.
46790
+ */
46791
+ askVerdict: boolean().optional()
46441
46792
  });
46442
46793
  /**
46443
46794
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -56894,7 +57245,7 @@ var BatteryStatusSchema = object({
56894
57245
  */
56895
57246
  binary: boolean().optional().meta({ label: "Binary indicator" })
56896
57247
  });
56897
- DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
57248
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
56898
57249
  method(object({
56899
57250
  deviceId: number(),
56900
57251
  /** Bound on the wait. Sensible range 3000–10000ms. */
@@ -58638,7 +58989,13 @@ results: array(object({
58638
58989
  /** Ms epoch of the attempt. */
58639
58990
  at: number()
58640
58991
  })) });
58641
- DeviceType.Switch, DeviceType.Light;
58992
+ DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58993
+ object({
58994
+ active: boolean().meta({ label: "Active" }),
58995
+ /** Ms epoch when the slice was last updated. */
58996
+ lastChangedAt: number()
58997
+ });
58998
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
58642
58999
  object({
58643
59000
  /** Members whose current value entered the aggregate. */
58644
59001
  included: number().int().nonnegative().meta(readingMeta("count", {
@@ -58656,7 +59013,7 @@ object({
58656
59013
  label: "Members"
58657
59014
  }))
58658
59015
  });
58659
- DeviceType.Sensor, DeviceType.Switch, DeviceType.Light;
59016
+ DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58660
59017
  object({
58661
59018
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
58662
59019
  position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -59563,7 +59920,14 @@ DeviceType.Lock, method(object({
59563
59920
  auth: "protected"
59564
59921
  }), method(object({
59565
59922
  deviceId: number().int().nonnegative(),
59566
- code: string().min(1).optional()
59923
+ code: string().min(1).optional(),
59924
+ /**
59925
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
59926
+ * with one call is refused unless the caller says it was confirmed. A
59927
+ * single lock ignores it. The refusal lives in the callee, so no
59928
+ * automation or API caller reaches the doors by skipping a dialog.
59929
+ */
59930
+ confirm: boolean().optional()
59567
59931
  }), _void(), {
59568
59932
  kind: "mutation",
59569
59933
  auth: "protected"
@@ -59571,6 +59935,11 @@ DeviceType.Lock, method(object({
59571
59935
  kind: "mutation",
59572
59936
  auth: "protected"
59573
59937
  });
59938
+ object({
59939
+ value: number().nullable().meta(readingMeta("device", { label: "Total" })),
59940
+ lastFetchedAt: number()
59941
+ });
59942
+ DeviceType.Sensor;
59574
59943
  /**
59575
59944
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
59576
59945
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
@@ -61478,9 +61847,9 @@ object({
61478
61847
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
61479
61848
  kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
61480
61849
  /** Voltage in volts. */
61481
- volts: number().optional().meta(readingMeta("voltage")),
61850
+ volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
61482
61851
  /** Current in amperes. */
61483
- amps: number().optional().meta(readingMeta("current")),
61852
+ amps: number().optional().meta(readingMeta("current", { label: "Current" })),
61484
61853
  /** Apparent power in volt-amperes. */
61485
61854
  va: number().optional().meta(readingMeta("apparent-power")),
61486
61855
  /** Power factor (0..1) if reported. */
@@ -61488,7 +61857,23 @@ object({
61488
61857
  /** Ms epoch when the slice was last updated. */
61489
61858
  lastFetchedAt: number()
61490
61859
  });
61491
- DeviceType.Sensor;
61860
+ [
61861
+ DeviceType.Sensor,
61862
+ DeviceType.Switch,
61863
+ DeviceType.Light,
61864
+ DeviceType.Fan,
61865
+ DeviceType.Climate,
61866
+ DeviceType.Thermostat,
61867
+ DeviceType.Humidifier,
61868
+ DeviceType.WaterHeater,
61869
+ DeviceType.MediaPlayer,
61870
+ DeviceType.Washer,
61871
+ DeviceType.Dryer,
61872
+ DeviceType.Dishwasher,
61873
+ DeviceType.Vacuum,
61874
+ DeviceType.LawnMower,
61875
+ DeviceType.PetFeeder
61876
+ ].filter((type) => type !== DeviceType.Sensor);
61492
61877
  /**
61493
61878
  * Presence cap. Models HA `person.*` and `device_tracker.*` entities
61494
61879
  * on `DeviceType.Presence`. Read-only — no setters: presence is
@@ -61935,7 +62320,7 @@ object({
61935
62320
  phase: string().nullable()
61936
62321
  });
61937
62322
  Object.values(DeviceType);
61938
- DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
62323
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
61939
62324
  DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
61940
62325
  kind: "mutation",
61941
62326
  auth: "admin"
@@ -63974,7 +64359,7 @@ object({
63974
64359
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
63975
64360
  lastChangedAt: number()
63976
64361
  });
63977
- DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
64362
+ DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
63978
64363
  deviceId: number(),
63979
64364
  on: boolean()
63980
64365
  }), _void(), {
@@ -65666,8 +66051,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
65666
66051
  kind: "mutation",
65667
66052
  auth: "admin"
65668
66053
  });
66054
+ DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
65669
66055
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
65670
- 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;
66056
+ 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;
65671
66057
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
65672
66058
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
65673
66059
  new Set(CAP_NAMES);
@@ -65720,7 +66106,7 @@ var AccessoryKind = {
65720
66106
  PrivacyMask: DeviceRole.PrivacyMask
65721
66107
  };
65722
66108
  AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
65723
- 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;
66109
+ 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;
65724
66110
  new Set(Object.values(DeviceType));
65725
66111
  Object.freeze({
65726
66112
  "accessories.getStatus": {
@@ -68943,6 +69329,13 @@ Object.freeze({
68943
69329
  access: "view",
68944
69330
  role: "viewer"
68945
69331
  },
69332
+ "groupActive.getStatus": {
69333
+ capName: "group-active",
69334
+ capScope: "device",
69335
+ addonId: null,
69336
+ access: "view",
69337
+ role: "viewer"
69338
+ },
68946
69339
  "groupCommands.getStatus": {
68947
69340
  capName: "group-commands",
68948
69341
  capScope: "device",
@@ -69909,6 +70302,13 @@ Object.freeze({
69909
70302
  access: "create",
69910
70303
  role: "admin"
69911
70304
  },
70305
+ "meter.getStatus": {
70306
+ capName: "meter",
70307
+ capScope: "device",
70308
+ addonId: null,
70309
+ access: "view",
70310
+ role: "viewer"
70311
+ },
69912
70312
  "metricsProvider.collectSnapshot": {
69913
70313
  capName: "metrics-provider",
69914
70314
  capScope: "system",
@@ -78007,7 +78407,39 @@ var APPLIANCE_CAP_VOCABULARY = {
78007
78407
  phrase: t("When {device} finishes", "Quando {device} finisce"),
78008
78408
  icon: "square"
78009
78409
  }
78010
- }
78410
+ },
78411
+ overrides: { byType: {
78412
+ [DeviceType.Washer]: {
78413
+ state: { running: {
78414
+ whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
78415
+ whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
78416
+ } },
78417
+ events: {
78418
+ onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
78419
+ onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
78420
+ }
78421
+ },
78422
+ [DeviceType.Dryer]: {
78423
+ state: { running: {
78424
+ whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
78425
+ whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
78426
+ } },
78427
+ events: {
78428
+ onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
78429
+ onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
78430
+ }
78431
+ },
78432
+ [DeviceType.Dishwasher]: {
78433
+ state: { running: {
78434
+ whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
78435
+ whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
78436
+ } },
78437
+ events: {
78438
+ onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
78439
+ onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
78440
+ }
78441
+ }
78442
+ } }
78011
78443
  },
78012
78444
  update: {
78013
78445
  scope: "device",
@@ -78779,6 +79211,10 @@ var SENSOR_CAP_VOCABULARY = {
78779
79211
  icon: "flame"
78780
79212
  }]
78781
79213
  },
79214
+ "group-active": {
79215
+ scope: "device",
79216
+ noun: t("Group state", "Stato del gruppo")
79217
+ },
78782
79218
  "group-commands": {
78783
79219
  scope: "device",
78784
79220
  noun: t("Group command", "Comando di gruppo")
@@ -78835,6 +79271,17 @@ var SENSOR_CAP_VOCABULARY = {
78835
79271
  }],
78836
79272
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
78837
79273
  },
79274
+ meter: {
79275
+ scope: "device",
79276
+ noun: t("Meter", "Contatore"),
79277
+ state: [{
79278
+ kind: "numeric",
79279
+ field: "value",
79280
+ quantity: t("the total", "il totale"),
79281
+ label: t("Total", "Totale"),
79282
+ icon: "gauge"
79283
+ }]
79284
+ },
78838
79285
  "numeric-sensor": {
78839
79286
  scope: "device",
78840
79287
  noun: t("Sensor", "Sensore"),
@@ -79307,8 +79754,47 @@ function projectAction(cap, action) {
79307
79754
  };
79308
79755
  }
79309
79756
  Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
79310
- 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;
79757
+ 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;
79311
79758
  DeviceFeature.BatteryOperated;
79759
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
79760
+ 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.";
79761
+ 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.";
79762
+ var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
79763
+ var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
79764
+ 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.";
79765
+ function withheld(reason) {
79766
+ return {
79767
+ [DeviceType.Washer]: {
79768
+ exported: false,
79769
+ reason
79770
+ },
79771
+ [DeviceType.Dryer]: {
79772
+ exported: false,
79773
+ reason
79774
+ },
79775
+ [DeviceType.Dishwasher]: {
79776
+ exported: false,
79777
+ reason
79778
+ }
79779
+ };
79780
+ }
79781
+ function offered(received) {
79782
+ return {
79783
+ [DeviceType.Washer]: {
79784
+ exported: true,
79785
+ as: received
79786
+ },
79787
+ [DeviceType.Dryer]: {
79788
+ exported: true,
79789
+ as: received
79790
+ },
79791
+ [DeviceType.Dishwasher]: {
79792
+ exported: true,
79793
+ as: received
79794
+ }
79795
+ };
79796
+ }
79797
+ offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
79312
79798
  Object.freeze({
79313
79799
  "accessories.getStatus": [{
79314
79800
  name: "deviceId",
@@ -80275,6 +80761,11 @@ Object.freeze({
80275
80761
  form: "single",
80276
80762
  optional: false
80277
80763
  }],
80764
+ "groupActive.getStatus": [{
80765
+ name: "deviceId",
80766
+ form: "single",
80767
+ optional: false
80768
+ }],
80278
80769
  "groupCommands.getStatus": [{
80279
80770
  name: "deviceId",
80280
80771
  form: "single",
@@ -80485,6 +80976,11 @@ Object.freeze({
80485
80976
  form: "single",
80486
80977
  optional: false
80487
80978
  }],
80979
+ "meter.getStatus": [{
80980
+ name: "deviceId",
80981
+ form: "single",
80982
+ optional: false
80983
+ }],
80488
80984
  "motion.getStatus": [{
80489
80985
  name: "deviceId",
80490
80986
  form: "single",
@@ -82092,7 +82588,6 @@ Object.freeze({
82092
82588
  "network-access": "ingress",
82093
82589
  "smtp-provider": "email"
82094
82590
  });
82095
- DeviceType.Camera;
82096
82591
  /**
82097
82592
  * A saved Customize assignment (D936). The schema is the type: callers use
82098
82593
  * `z.infer`, they do not restate the shape.