@camstack/addon-waste-collections 0.1.30 → 0.1.31

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.
@@ -5582,7 +5582,7 @@ var ZodIssueCode = {
5582
5582
  var ZodFirstPartyTypeKind;
5583
5583
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5584
5584
  //#endregion
5585
- //#region ../types/dist/sleep-bykKrTgu.mjs
5585
+ //#region ../types/dist/sleep--jXS9hWo.mjs
5586
5586
  /**
5587
5587
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5588
5588
  * window to float samples (D455).
@@ -8991,6 +8991,7 @@ var CAP_NAMES = Object.freeze([
8991
8991
  "filesystem-browse",
8992
8992
  "flood",
8993
8993
  "gas",
8994
+ "group-active",
8994
8995
  "group-commands",
8995
8996
  "group-status",
8996
8997
  "heating-valve",
@@ -9013,6 +9014,7 @@ var CAP_NAMES = Object.freeze([
9013
9014
  "login-method",
9014
9015
  "media-player",
9015
9016
  "mesh-network",
9017
+ "meter",
9016
9018
  "metrics-provider",
9017
9019
  "model-convert",
9018
9020
  "model-distributor",
@@ -9811,6 +9813,10 @@ Object.freeze({
9811
9813
  "path": "detected",
9812
9814
  "valueType": "boolean"
9813
9815
  }],
9816
+ "group-active": [{
9817
+ "path": "active",
9818
+ "valueType": "boolean"
9819
+ }],
9814
9820
  "group-status": [
9815
9821
  {
9816
9822
  "path": "included",
@@ -10070,6 +10076,10 @@ Object.freeze({
10070
10076
  ]
10071
10077
  }
10072
10078
  ],
10079
+ "meter": [{
10080
+ "path": "value",
10081
+ "valueType": "number"
10082
+ }],
10073
10083
  "motion": [
10074
10084
  {
10075
10085
  "path": "detected",
@@ -10813,7 +10823,7 @@ object({
10813
10823
  params: record(string(), union([string(), number()])).optional()
10814
10824
  });
10815
10825
  //#endregion
10816
- //#region ../types/dist/err-msg-BXKzRBwg.mjs
10826
+ //#region ../types/dist/err-msg-DIorGYeC.mjs
10817
10827
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
10818
10828
  DeviceType["Camera"] = "camera";
10819
10829
  DeviceType["Hub"] = "hub";
@@ -10907,8 +10917,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
10907
10917
  DeviceType["PetFeeder"] = "pet-feeder";
10908
10918
  /** Built-in dishwasher — program lifecycle, door / remote-start gates,
10909
10919
  * salt and rinse-aid levels. Installed with the `dishwasher` cap.
10910
- * Sources: native Bosch Home Connect, reusable by similar integrations. */
10920
+ * Sources: native Bosch Home Connect, reusable by similar integrations.
10921
+ * A plug-built dishwasher carries running-state and power instead. */
10911
10922
  DeviceType["Dishwasher"] = "dishwasher";
10923
+ /** Washing machine. A plug-built one is running while its power stays
10924
+ * above a threshold. No program cap — that surface is the dishwasher's. */
10925
+ DeviceType["Washer"] = "washer";
10926
+ /** Tumble dryer. Same plug-built running surface as {@link Washer}. */
10927
+ DeviceType["Dryer"] = "dryer";
10912
10928
  return DeviceType;
10913
10929
  }({});
10914
10930
  var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
@@ -11156,7 +11172,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
11156
11172
  return DeviceRole;
11157
11173
  }({});
11158
11174
  //#endregion
11159
- //#region ../types/dist/composition-OhpuespA.mjs
11175
+ //#region ../types/dist/composition-Bb8iwHEJ.mjs
11160
11176
  /**
11161
11177
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11162
11178
  *
@@ -11471,6 +11487,13 @@ var table = {
11471
11487
  apply: () => {
11472
11488
  throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
11473
11489
  }
11490
+ },
11491
+ schmitt: {
11492
+ minArgs: 3,
11493
+ maxArgs: 5,
11494
+ apply: () => {
11495
+ throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
11496
+ }
11474
11497
  }
11475
11498
  };
11476
11499
  Object.freeze(Object.assign(Object.create(null), table));
@@ -11912,6 +11935,99 @@ function validateExpressionSource(src) {
11912
11935
  return null;
11913
11936
  }
11914
11937
  /**
11938
+ * One power reading becomes a washer, dryer or dishwasher (D944 helper).
11939
+ *
11940
+ * Standby of the control board is under 5 W; a motor or a heater is far
11941
+ * above that, so 5 W is the line. A door lock or a short pump spike is not
11942
+ * a cycle, so running starts only after 30 s above the line.
11943
+ *
11944
+ * A wash, dry or dishwasher pause (soak, heat-wait, heater off between
11945
+ * bursts) lasts several minutes. Ending the cycle on the first dip would
11946
+ * report "finished" in the middle of the program, so the stop dwell is
11947
+ * 10 minutes on every type. The number is stored per type so one machine
11948
+ * can move later without moving the others.
11949
+ */
11950
+ var APPLIANCE_TEMPLATE_ID = "appliance";
11951
+ var APPLIANCE_KINDS = [
11952
+ "washer",
11953
+ "dryer",
11954
+ "dishwasher"
11955
+ ];
11956
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
11957
+ /**
11958
+ * Statistics and integrals over a history read (D944).
11959
+ *
11960
+ * Pure: the same points always give the same answer, so a restart recomputes
11961
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
11962
+ * never the mean of the samples. A hole with no held value is not integrated
11963
+ * as zero. A truncated read is not published.
11964
+ */
11965
+ var STATISTIC_STATS = [
11966
+ "min",
11967
+ "max",
11968
+ "mean",
11969
+ "sum",
11970
+ "count",
11971
+ "change"
11972
+ ];
11973
+ /**
11974
+ * The range a statistics or integral helper asks history for (D944).
11975
+ *
11976
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
11977
+ * or 25 hours across a DST change. A tier is eligible only when its retention
11978
+ * is strictly longer than the longest that range can be. Forever qualifies.
11979
+ * Equal to a tier's retention is a refusal, not a short answer.
11980
+ */
11981
+ var MINUTE_MS = 6e4;
11982
+ var HOUR_MS = 60 * MINUTE_MS;
11983
+ var DAY_MS$1 = 24 * HOUR_MS;
11984
+ var ROLLING_SPANS = [
11985
+ "1h",
11986
+ "24h",
11987
+ "2d",
11988
+ "7d",
11989
+ "30d",
11990
+ "custom"
11991
+ ];
11992
+ var CALENDAR_PERIODS = [
11993
+ "today",
11994
+ "yesterday",
11995
+ "this-week",
11996
+ "this-month"
11997
+ ];
11998
+ var RESET_PERIODS = [
11999
+ "never",
12000
+ "daily",
12001
+ "weekly",
12002
+ "monthly"
12003
+ ];
12004
+ 5 * MINUTE_MS;
12005
+ 24 * HOUR_MS, 2 * DAY_MS$1, 7 * DAY_MS$1, 30 * DAY_MS$1;
12006
+ 7 * DAY_MS$1, 30 * DAY_MS$1, 365 * DAY_MS$1;
12007
+ var rollingWindowObject = object({
12008
+ kind: literal("rolling"),
12009
+ span: _enum(ROLLING_SPANS),
12010
+ customMinutes: number().int().min(5).optional()
12011
+ }).check((payload) => {
12012
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
12013
+ code: "custom",
12014
+ message: "a custom range needs a duration in minutes",
12015
+ path: ["customMinutes"],
12016
+ input: payload.value
12017
+ });
12018
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
12019
+ code: "custom",
12020
+ message: "only a custom range carries a duration",
12021
+ path: ["customMinutes"],
12022
+ input: payload.value
12023
+ });
12024
+ });
12025
+ var RollingWindowSchema = rollingWindowObject;
12026
+ var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
12027
+ kind: literal("calendar"),
12028
+ period: _enum(CALENDAR_PERIODS)
12029
+ })]);
12030
+ /**
11915
12031
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11916
12032
  * id. Split out so helper schemas can name it without a cycle through
11917
12033
  * `composition.ts` (D659).
@@ -11937,7 +12053,13 @@ var GROUP_TEMPLATE_IDS = [
11937
12053
  "occupancy",
11938
12054
  "binary",
11939
12055
  "switch",
11940
- "light"
12056
+ "light",
12057
+ "fan",
12058
+ "cover",
12059
+ "valve",
12060
+ "lock",
12061
+ "media-player",
12062
+ "climate"
11941
12063
  ];
11942
12064
  var NUMERIC_AGGREGATES = [
11943
12065
  "mean",
@@ -11967,14 +12089,73 @@ var HelperMemberSchema = object({
11967
12089
  cap: string().min(1),
11968
12090
  fieldPath: string().min(1)
11969
12091
  });
11970
- var HelperSpecSchema = discriminatedUnion("kind", [object({
11971
- kind: literal("group"),
11972
- templateId: GroupTemplateIdSchema,
11973
- aggregate: AggregateReducerSchema,
11974
- members: array(HelperMemberSchema).min(1).max(64),
11975
- /** Actuator groups only. Readings leave this unset. */
11976
- active: ActiveCriterionSchema.optional()
11977
- })]);
12092
+ var HelperSpecSchema = discriminatedUnion("kind", [
12093
+ object({
12094
+ kind: literal("group"),
12095
+ templateId: GroupTemplateIdSchema,
12096
+ aggregate: AggregateReducerSchema,
12097
+ members: array(HelperMemberSchema).min(1).max(64),
12098
+ /** Actuator groups only. Readings leave this unset. */
12099
+ active: ActiveCriterionSchema.optional()
12100
+ }),
12101
+ object({
12102
+ kind: literal("appliance"),
12103
+ templateId: literal(APPLIANCE_TEMPLATE_ID),
12104
+ appliance: _enum(APPLIANCE_KINDS),
12105
+ thresholdWatts: number().positive(),
12106
+ startDwellMs: number().int().nonnegative(),
12107
+ stopDwellMs: number().int().nonnegative(),
12108
+ member: HelperMemberSchema
12109
+ }),
12110
+ object({
12111
+ kind: literal("statistic"),
12112
+ stat: _enum(STATISTIC_STATS),
12113
+ window: StatisticWindowSchema,
12114
+ source: HelperMemberSchema
12115
+ }),
12116
+ object({
12117
+ kind: literal("integral"),
12118
+ reset: _enum(RESET_PERIODS),
12119
+ output: _enum(["energy", "meter"]),
12120
+ source: HelperMemberSchema
12121
+ }),
12122
+ object({
12123
+ kind: literal("threshold"),
12124
+ source: HelperMemberSchema,
12125
+ high: number(),
12126
+ low: number(),
12127
+ onForMs: number().int().nonnegative(),
12128
+ offForMs: number().int().nonnegative()
12129
+ }),
12130
+ object({
12131
+ kind: literal("arithmetic"),
12132
+ op: _enum([
12133
+ "sum",
12134
+ "difference",
12135
+ "ratio"
12136
+ ]),
12137
+ inputs: array(HelperMemberSchema).min(2).max(64)
12138
+ }),
12139
+ object({
12140
+ kind: literal("expression"),
12141
+ expr: string().min(1),
12142
+ inputs: array(object({
12143
+ name: string().min(1),
12144
+ member: HelperMemberSchema
12145
+ })).min(1).max(64),
12146
+ output: _enum(["number", "boolean"])
12147
+ }),
12148
+ object({
12149
+ kind: literal("derivative"),
12150
+ window: RollingWindowSchema,
12151
+ per: _enum([
12152
+ "second",
12153
+ "minute",
12154
+ "hour"
12155
+ ]),
12156
+ source: HelperMemberSchema
12157
+ })
12158
+ ]);
11978
12159
  /** A composed device's stableId is this prefix plus the block id. */
11979
12160
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
11980
12161
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -12035,6 +12216,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12035
12216
  "all"
12036
12217
  ]),
12037
12218
  reads: array(CompositionFieldReadSchema).min(1).max(64),
12219
+ /**
12220
+ * Set when the reads are an enum state, not a yes/no: the listed states
12221
+ * count as active (a cover is `open`). A state outside the list is inactive;
12222
+ * a read that is not a state at all is left out. Only `any` / `all` use it.
12223
+ */
12224
+ activeWhen: array(string().min(1)).min(1).optional(),
12038
12225
  /** `value` is the reading; the others are the member counts. */
12039
12226
  publish: _enum([
12040
12227
  "value",
@@ -12048,6 +12235,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12048
12235
  "omit",
12049
12236
  "offline"
12050
12237
  ])
12238
+ }),
12239
+ object({
12240
+ kind: literal("series"),
12241
+ read: CompositionFieldReadSchema,
12242
+ /** `value` is the statistic or the integral. The others are the gap counts. */
12243
+ publish: _enum([
12244
+ "value",
12245
+ "included",
12246
+ "excluded",
12247
+ "total"
12248
+ ]),
12249
+ /**
12250
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
12251
+ * device unseeded until history answers, so a restart cannot publish 0.
12252
+ */
12253
+ empty: _enum([
12254
+ "null",
12255
+ "omit",
12256
+ "offline"
12257
+ ])
12051
12258
  })
12052
12259
  ]);
12053
12260
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -17207,7 +17414,22 @@ var BrokerProviderInfoSchema = object({
17207
17414
  */
17208
17415
  interactiveConnectPath: string().min(1).optional(),
17209
17416
  /** Relative hub path to disconnect the linked account (same popup pattern). */
17210
- interactiveDisconnectPath: string().min(1).optional()
17417
+ interactiveDisconnectPath: string().min(1).optional(),
17418
+ /**
17419
+ * The kind signs in through a server-held interactive session instead of
17420
+ * (or before) typed credentials. `basePath` is a hub-relative route set
17421
+ * served by the owning addon (`/addon/<id>/...`) speaking the sign-in
17422
+ * contract: `POST {basePath}/start` (body: the form's settings) answers
17423
+ * `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
17424
+ * `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
17425
+ * 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
17426
+ * (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
17427
+ * existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
17428
+ * (`{ sessionId }`) drops the session. The dialog that edits a broker
17429
+ * offers it as the default path; the fields the session fills are
17430
+ * marked `filledBySignIn` in the kind's settings schema.
17431
+ */
17432
+ signIn: object({ basePath: string().min(1) }).optional()
17211
17433
  }))
17212
17434
  });
17213
17435
  var ListInputSchema = object({
@@ -18206,7 +18428,8 @@ var CompositionProblemSchema = object({
18206
18428
  "native-capability-replace",
18207
18429
  "mixed-quantity",
18208
18430
  "helper-mismatch",
18209
- "member-constraint"
18431
+ "member-constraint",
18432
+ "retention"
18210
18433
  ]),
18211
18434
  path: string(),
18212
18435
  message: string()
@@ -18440,13 +18663,17 @@ Object.freeze({
18440
18663
  latchedAt: {
18441
18664
  kind: "fixed",
18442
18665
  result: ["number", "null"]
18666
+ },
18667
+ schmitt: {
18668
+ kind: "fixed",
18669
+ result: ["boolean", "null"]
18443
18670
  }
18444
18671
  });
18445
18672
  /**
18446
18673
  * One catalog row per base reading a group helper can build (D944 §3).
18447
18674
  * Data, not a form default written into the block.
18448
18675
  */
18449
- var NOW = {
18676
+ var NOW$2 = {
18450
18677
  fieldPath: "lastFetchedAt",
18451
18678
  expr: "now"
18452
18679
  };
@@ -18460,6 +18687,8 @@ function numeric(input) {
18460
18687
  family: "numeric",
18461
18688
  deviceType: DeviceType.Sensor,
18462
18689
  memberDeviceType: DeviceType.Sensor,
18690
+ memberDeviceTypes: [DeviceType.Sensor],
18691
+ activeWhen: void 0,
18463
18692
  commandCaps: [],
18464
18693
  baseUnit: baseUnitOf(input.quantity),
18465
18694
  aggregates: NUMERIC_AGGREGATES,
@@ -18475,6 +18704,8 @@ function binary(input) {
18475
18704
  family: "binary",
18476
18705
  deviceType: DeviceType.Sensor,
18477
18706
  memberDeviceType: DeviceType.Sensor,
18707
+ memberDeviceTypes: [DeviceType.Sensor],
18708
+ activeWhen: void 0,
18478
18709
  commandCaps: [],
18479
18710
  quantity: "none",
18480
18711
  baseUnit: void 0,
@@ -18492,7 +18723,7 @@ var GROUP_TEMPLATES = [
18492
18723
  quantity: "temperature",
18493
18724
  defaultAggregate: "mean",
18494
18725
  empty: "null",
18495
- companions: [NOW]
18726
+ companions: [NOW$2]
18496
18727
  }),
18497
18728
  numeric({
18498
18729
  id: "humidity",
@@ -18503,7 +18734,7 @@ var GROUP_TEMPLATES = [
18503
18734
  quantity: "humidity",
18504
18735
  defaultAggregate: "mean",
18505
18736
  empty: "null",
18506
- companions: [NOW]
18737
+ companions: [NOW$2]
18507
18738
  }),
18508
18739
  numeric({
18509
18740
  id: "pressure",
@@ -18514,7 +18745,7 @@ var GROUP_TEMPLATES = [
18514
18745
  quantity: "pressure",
18515
18746
  defaultAggregate: "mean",
18516
18747
  empty: "null",
18517
- companions: [NOW]
18748
+ companions: [NOW$2]
18518
18749
  }),
18519
18750
  numeric({
18520
18751
  id: "illuminance",
@@ -18525,7 +18756,7 @@ var GROUP_TEMPLATES = [
18525
18756
  quantity: "illuminance",
18526
18757
  defaultAggregate: "mean",
18527
18758
  empty: "null",
18528
- companions: [NOW]
18759
+ companions: [NOW$2]
18529
18760
  }),
18530
18761
  numeric({
18531
18762
  id: "power",
@@ -18536,7 +18767,7 @@ var GROUP_TEMPLATES = [
18536
18767
  quantity: "power",
18537
18768
  defaultAggregate: "sum",
18538
18769
  empty: "omit",
18539
- companions: [NOW]
18770
+ companions: [NOW$2]
18540
18771
  }),
18541
18772
  numeric({
18542
18773
  id: "energy",
@@ -18547,7 +18778,7 @@ var GROUP_TEMPLATES = [
18547
18778
  quantity: "energy",
18548
18779
  defaultAggregate: "sum",
18549
18780
  empty: "omit",
18550
- companions: [NOW]
18781
+ companions: [NOW$2]
18551
18782
  }),
18552
18783
  numeric({
18553
18784
  id: "battery",
@@ -18582,7 +18813,7 @@ var GROUP_TEMPLATES = [
18582
18813
  quantity: "device",
18583
18814
  defaultAggregate: "mean",
18584
18815
  empty: "null",
18585
- companions: [NOW]
18816
+ companions: [NOW$2]
18586
18817
  }),
18587
18818
  binary({
18588
18819
  id: "motion",
@@ -18676,6 +18907,11 @@ var GROUP_TEMPLATES = [
18676
18907
  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.",
18677
18908
  deviceType: DeviceType.Switch,
18678
18909
  outputCap: "switch",
18910
+ outputField: "on",
18911
+ member: {
18912
+ cap: "switch",
18913
+ fieldPath: "on"
18914
+ },
18679
18915
  commandCaps: ["switch"]
18680
18916
  }),
18681
18917
  actuator({
@@ -18683,34 +18919,136 @@ var GROUP_TEMPLATES = [
18683
18919
  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.",
18684
18920
  deviceType: DeviceType.Light,
18685
18921
  outputCap: "switch",
18922
+ outputField: "on",
18923
+ member: {
18924
+ cap: "switch",
18925
+ fieldPath: "on"
18926
+ },
18686
18927
  commandCaps: [
18687
18928
  "switch",
18688
18929
  "brightness",
18689
18930
  "color"
18690
18931
  ]
18932
+ }),
18933
+ actuator({
18934
+ id: "fan",
18935
+ 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.",
18936
+ deviceType: DeviceType.Fan,
18937
+ outputCap: "switch",
18938
+ outputField: "on",
18939
+ member: {
18940
+ cap: "switch",
18941
+ fieldPath: "on"
18942
+ },
18943
+ commandCaps: ["switch", "fan-control"]
18944
+ }),
18945
+ actuator({
18946
+ id: "cover",
18947
+ 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.",
18948
+ deviceType: DeviceType.Cover,
18949
+ outputCap: "group-active",
18950
+ outputField: "active",
18951
+ member: {
18952
+ cap: "cover",
18953
+ fieldPath: "state"
18954
+ },
18955
+ activeWhen: [
18956
+ "open",
18957
+ "opening",
18958
+ "stopped"
18959
+ ],
18960
+ commandCaps: ["cover"]
18961
+ }),
18962
+ actuator({
18963
+ id: "valve",
18964
+ 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.",
18965
+ deviceType: DeviceType.Valve,
18966
+ outputCap: "group-active",
18967
+ outputField: "active",
18968
+ member: {
18969
+ cap: "valve",
18970
+ fieldPath: "state"
18971
+ },
18972
+ activeWhen: [
18973
+ "open",
18974
+ "opening",
18975
+ "stopped"
18976
+ ],
18977
+ commandCaps: ["valve"]
18978
+ }),
18979
+ actuator({
18980
+ id: "lock",
18981
+ 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.",
18982
+ deviceType: DeviceType.Lock,
18983
+ outputCap: "group-active",
18984
+ outputField: "active",
18985
+ member: {
18986
+ cap: "lock-control",
18987
+ fieldPath: "state"
18988
+ },
18989
+ activeWhen: ["locked"],
18990
+ commandCaps: ["lock-control"]
18991
+ }),
18992
+ actuator({
18993
+ id: "media-player",
18994
+ 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.",
18995
+ deviceType: DeviceType.MediaPlayer,
18996
+ outputCap: "group-active",
18997
+ outputField: "active",
18998
+ member: {
18999
+ cap: "media-player",
19000
+ fieldPath: "state"
19001
+ },
19002
+ activeWhen: ["playing", "buffering"],
19003
+ commandCaps: ["media-player"]
19004
+ }),
19005
+ actuator({
19006
+ id: "climate",
19007
+ 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.",
19008
+ deviceType: DeviceType.Thermostat,
19009
+ memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
19010
+ outputCap: "group-active",
19011
+ outputField: "active",
19012
+ member: {
19013
+ cap: "climate-control",
19014
+ fieldPath: "mode"
19015
+ },
19016
+ activeWhen: [
19017
+ "heat",
19018
+ "cool",
19019
+ "auto",
19020
+ "heat_cool",
19021
+ "fan_only",
19022
+ "dry"
19023
+ ],
19024
+ commandCaps: ["climate-control"]
18691
19025
  })
18692
19026
  ];
18693
19027
  function actuator(input) {
18694
19028
  return {
18695
- ...input,
19029
+ id: input.id,
19030
+ summary: input.summary,
19031
+ deviceType: input.deviceType,
19032
+ outputCap: input.outputCap,
19033
+ outputField: input.outputField,
19034
+ commandCaps: input.commandCaps,
18696
19035
  family: "actuator",
18697
19036
  role: void 0,
18698
19037
  memberDeviceType: input.deviceType,
18699
- outputField: "on",
19038
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
19039
+ activeWhen: input.activeWhen,
18700
19040
  quantity: "none",
18701
19041
  baseUnit: void 0,
18702
19042
  aggregates: BINARY_AGGREGATES,
18703
19043
  defaultAggregate: "any",
18704
19044
  empty: "offline",
18705
- accept: [{
18706
- cap: "switch",
18707
- fieldPath: "on"
18708
- }],
19045
+ accept: [input.member],
18709
19046
  companions: [CHANGED]
18710
19047
  };
18711
19048
  }
18712
19049
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
18713
19050
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
19051
+ DeviceType.Camera;
18714
19052
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
18715
19053
  /**
18716
19054
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -43725,7 +44063,7 @@ var NetworkAccessStatusSchema = object({
43725
44063
  });
43726
44064
  /**
43727
44065
  * Optional, richer endpoint shape returned by providers that expose
43728
- * MORE than one ingress concurrently (Tailscale Ingress with mixed
44066
+ * MORE than one ingress concurrently (Tailscale Funnel with mixed
43729
44067
  * serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
43730
44068
  * the originating provider config (mode + sourcePort) so the
43731
44069
  * orchestrator UI can label rows distinctly. Providers that expose only
@@ -46368,7 +46706,20 @@ var NcRuleInputSchema = object({
46368
46706
  * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
46369
46707
  * path does not run Zod defaults.
46370
46708
  */
46371
- groupingSec: number().int().min(5).max(60).optional()
46709
+ groupingSec: number().int().min(5).max(60).optional(),
46710
+ /**
46711
+ * ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
46712
+ * carries "Correct" / "Wrong" buttons (and, where the channel has room, a
46713
+ * "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
46714
+ * same mark the Library writes, and records whose notification it was and
46715
+ * when. A channel with no buttons gets the same two choices as links.
46716
+ *
46717
+ * `.optional()`, never `.default()` (a Zod default does not run on the addon
46718
+ * cap path): absent and `false` both mean off, which is what every rule
46719
+ * authored before this field meant. An editor turns it off by writing
46720
+ * `false`, so it needs no `clear` key.
46721
+ */
46722
+ askVerdict: boolean().optional()
46372
46723
  });
46373
46724
  /**
46374
46725
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -56825,7 +57176,7 @@ var BatteryStatusSchema = object({
56825
57176
  */
56826
57177
  binary: boolean().optional().meta({ label: "Binary indicator" })
56827
57178
  });
56828
- DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
57179
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
56829
57180
  method(object({
56830
57181
  deviceId: number(),
56831
57182
  /** Bound on the wait. Sensible range 3000–10000ms. */
@@ -58579,7 +58930,13 @@ results: array(object({
58579
58930
  /** Ms epoch of the attempt. */
58580
58931
  at: number()
58581
58932
  })) });
58582
- DeviceType.Switch, DeviceType.Light;
58933
+ DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58934
+ object({
58935
+ active: boolean().meta({ label: "Active" }),
58936
+ /** Ms epoch when the slice was last updated. */
58937
+ lastChangedAt: number()
58938
+ });
58939
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
58583
58940
  object({
58584
58941
  /** Members whose current value entered the aggregate. */
58585
58942
  included: number().int().nonnegative().meta(readingMeta("count", {
@@ -58597,7 +58954,7 @@ object({
58597
58954
  label: "Members"
58598
58955
  }))
58599
58956
  });
58600
- DeviceType.Sensor, DeviceType.Switch, DeviceType.Light;
58957
+ DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58601
58958
  object({
58602
58959
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
58603
58960
  position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -59504,7 +59861,14 @@ DeviceType.Lock, method(object({
59504
59861
  auth: "protected"
59505
59862
  }), method(object({
59506
59863
  deviceId: number().int().nonnegative(),
59507
- code: string().min(1).optional()
59864
+ code: string().min(1).optional(),
59865
+ /**
59866
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
59867
+ * with one call is refused unless the caller says it was confirmed. A
59868
+ * single lock ignores it. The refusal lives in the callee, so no
59869
+ * automation or API caller reaches the doors by skipping a dialog.
59870
+ */
59871
+ confirm: boolean().optional()
59508
59872
  }), _void(), {
59509
59873
  kind: "mutation",
59510
59874
  auth: "protected"
@@ -59512,6 +59876,11 @@ DeviceType.Lock, method(object({
59512
59876
  kind: "mutation",
59513
59877
  auth: "protected"
59514
59878
  });
59879
+ object({
59880
+ value: number().nullable().meta(readingMeta("device", { label: "Total" })),
59881
+ lastFetchedAt: number()
59882
+ });
59883
+ DeviceType.Sensor;
59515
59884
  /**
59516
59885
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
59517
59886
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
@@ -61419,9 +61788,9 @@ object({
61419
61788
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
61420
61789
  kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
61421
61790
  /** Voltage in volts. */
61422
- volts: number().optional().meta(readingMeta("voltage")),
61791
+ volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
61423
61792
  /** Current in amperes. */
61424
- amps: number().optional().meta(readingMeta("current")),
61793
+ amps: number().optional().meta(readingMeta("current", { label: "Current" })),
61425
61794
  /** Apparent power in volt-amperes. */
61426
61795
  va: number().optional().meta(readingMeta("apparent-power")),
61427
61796
  /** Power factor (0..1) if reported. */
@@ -61429,7 +61798,23 @@ object({
61429
61798
  /** Ms epoch when the slice was last updated. */
61430
61799
  lastFetchedAt: number()
61431
61800
  });
61432
- DeviceType.Sensor;
61801
+ [
61802
+ DeviceType.Sensor,
61803
+ DeviceType.Switch,
61804
+ DeviceType.Light,
61805
+ DeviceType.Fan,
61806
+ DeviceType.Climate,
61807
+ DeviceType.Thermostat,
61808
+ DeviceType.Humidifier,
61809
+ DeviceType.WaterHeater,
61810
+ DeviceType.MediaPlayer,
61811
+ DeviceType.Washer,
61812
+ DeviceType.Dryer,
61813
+ DeviceType.Dishwasher,
61814
+ DeviceType.Vacuum,
61815
+ DeviceType.LawnMower,
61816
+ DeviceType.PetFeeder
61817
+ ].filter((type) => type !== DeviceType.Sensor);
61433
61818
  /**
61434
61819
  * Presence cap. Models HA `person.*` and `device_tracker.*` entities
61435
61820
  * on `DeviceType.Presence`. Read-only — no setters: presence is
@@ -61876,7 +62261,7 @@ object({
61876
62261
  phase: string().nullable()
61877
62262
  });
61878
62263
  Object.values(DeviceType);
61879
- DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
62264
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
61880
62265
  DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
61881
62266
  kind: "mutation",
61882
62267
  auth: "admin"
@@ -63915,7 +64300,7 @@ object({
63915
64300
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
63916
64301
  lastChangedAt: number()
63917
64302
  });
63918
- DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
64303
+ DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
63919
64304
  deviceId: number(),
63920
64305
  on: boolean()
63921
64306
  }), _void(), {
@@ -65607,8 +65992,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
65607
65992
  kind: "mutation",
65608
65993
  auth: "admin"
65609
65994
  });
65995
+ DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
65610
65996
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
65611
- 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;
65997
+ 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;
65612
65998
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
65613
65999
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
65614
66000
  new Set(CAP_NAMES);
@@ -65661,7 +66047,7 @@ var AccessoryKind = {
65661
66047
  PrivacyMask: DeviceRole.PrivacyMask
65662
66048
  };
65663
66049
  AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
65664
- 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;
66050
+ 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;
65665
66051
  new Set(Object.values(DeviceType));
65666
66052
  Object.freeze({
65667
66053
  "accessories.getStatus": {
@@ -68884,6 +69270,13 @@ Object.freeze({
68884
69270
  access: "view",
68885
69271
  role: "viewer"
68886
69272
  },
69273
+ "groupActive.getStatus": {
69274
+ capName: "group-active",
69275
+ capScope: "device",
69276
+ addonId: null,
69277
+ access: "view",
69278
+ role: "viewer"
69279
+ },
68887
69280
  "groupCommands.getStatus": {
68888
69281
  capName: "group-commands",
68889
69282
  capScope: "device",
@@ -69850,6 +70243,13 @@ Object.freeze({
69850
70243
  access: "create",
69851
70244
  role: "admin"
69852
70245
  },
70246
+ "meter.getStatus": {
70247
+ capName: "meter",
70248
+ capScope: "device",
70249
+ addonId: null,
70250
+ access: "view",
70251
+ role: "viewer"
70252
+ },
69853
70253
  "metricsProvider.collectSnapshot": {
69854
70254
  capName: "metrics-provider",
69855
70255
  capScope: "system",
@@ -77948,7 +78348,39 @@ var APPLIANCE_CAP_VOCABULARY = {
77948
78348
  phrase: t("When {device} finishes", "Quando {device} finisce"),
77949
78349
  icon: "square"
77950
78350
  }
77951
- }
78351
+ },
78352
+ overrides: { byType: {
78353
+ [DeviceType.Washer]: {
78354
+ state: { running: {
78355
+ whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
78356
+ whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
78357
+ } },
78358
+ events: {
78359
+ onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
78360
+ onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
78361
+ }
78362
+ },
78363
+ [DeviceType.Dryer]: {
78364
+ state: { running: {
78365
+ whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
78366
+ whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
78367
+ } },
78368
+ events: {
78369
+ onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
78370
+ onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
78371
+ }
78372
+ },
78373
+ [DeviceType.Dishwasher]: {
78374
+ state: { running: {
78375
+ whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
78376
+ whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
78377
+ } },
78378
+ events: {
78379
+ onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
78380
+ onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
78381
+ }
78382
+ }
78383
+ } }
77952
78384
  },
77953
78385
  update: {
77954
78386
  scope: "device",
@@ -78720,6 +79152,10 @@ var SENSOR_CAP_VOCABULARY = {
78720
79152
  icon: "flame"
78721
79153
  }]
78722
79154
  },
79155
+ "group-active": {
79156
+ scope: "device",
79157
+ noun: t("Group state", "Stato del gruppo")
79158
+ },
78723
79159
  "group-commands": {
78724
79160
  scope: "device",
78725
79161
  noun: t("Group command", "Comando di gruppo")
@@ -78776,6 +79212,17 @@ var SENSOR_CAP_VOCABULARY = {
78776
79212
  }],
78777
79213
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
78778
79214
  },
79215
+ meter: {
79216
+ scope: "device",
79217
+ noun: t("Meter", "Contatore"),
79218
+ state: [{
79219
+ kind: "numeric",
79220
+ field: "value",
79221
+ quantity: t("the total", "il totale"),
79222
+ label: t("Total", "Totale"),
79223
+ icon: "gauge"
79224
+ }]
79225
+ },
78779
79226
  "numeric-sensor": {
78780
79227
  scope: "device",
78781
79228
  noun: t("Sensor", "Sensore"),
@@ -79248,8 +79695,47 @@ function projectAction(cap, action) {
79248
79695
  };
79249
79696
  }
79250
79697
  Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
79251
- 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;
79698
+ 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;
79252
79699
  DeviceFeature.BatteryOperated;
79700
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
79701
+ 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.";
79702
+ 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.";
79703
+ var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
79704
+ var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
79705
+ 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.";
79706
+ function withheld(reason) {
79707
+ return {
79708
+ [DeviceType.Washer]: {
79709
+ exported: false,
79710
+ reason
79711
+ },
79712
+ [DeviceType.Dryer]: {
79713
+ exported: false,
79714
+ reason
79715
+ },
79716
+ [DeviceType.Dishwasher]: {
79717
+ exported: false,
79718
+ reason
79719
+ }
79720
+ };
79721
+ }
79722
+ function offered(received) {
79723
+ return {
79724
+ [DeviceType.Washer]: {
79725
+ exported: true,
79726
+ as: received
79727
+ },
79728
+ [DeviceType.Dryer]: {
79729
+ exported: true,
79730
+ as: received
79731
+ },
79732
+ [DeviceType.Dishwasher]: {
79733
+ exported: true,
79734
+ as: received
79735
+ }
79736
+ };
79737
+ }
79738
+ offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
79253
79739
  Object.freeze({
79254
79740
  "accessories.getStatus": [{
79255
79741
  name: "deviceId",
@@ -80216,6 +80702,11 @@ Object.freeze({
80216
80702
  form: "single",
80217
80703
  optional: false
80218
80704
  }],
80705
+ "groupActive.getStatus": [{
80706
+ name: "deviceId",
80707
+ form: "single",
80708
+ optional: false
80709
+ }],
80219
80710
  "groupCommands.getStatus": [{
80220
80711
  name: "deviceId",
80221
80712
  form: "single",
@@ -80426,6 +80917,11 @@ Object.freeze({
80426
80917
  form: "single",
80427
80918
  optional: false
80428
80919
  }],
80920
+ "meter.getStatus": [{
80921
+ name: "deviceId",
80922
+ form: "single",
80923
+ optional: false
80924
+ }],
80429
80925
  "motion.getStatus": [{
80430
80926
  name: "deviceId",
80431
80927
  form: "single",
@@ -82033,7 +82529,6 @@ Object.freeze({
82033
82529
  "network-access": "ingress",
82034
82530
  "smtp-provider": "email"
82035
82531
  });
82036
- DeviceType.Camera;
82037
82532
  /**
82038
82533
  * A saved Customize assignment (D936). The schema is the type: callers use
82039
82534
  * `z.infer`, they do not restate the shape.