@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.
@@ -5578,7 +5578,7 @@ var ZodIssueCode = {
5578
5578
  var ZodFirstPartyTypeKind;
5579
5579
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5580
5580
  //#endregion
5581
- //#region ../types/dist/sleep-bykKrTgu.mjs
5581
+ //#region ../types/dist/sleep--jXS9hWo.mjs
5582
5582
  /**
5583
5583
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5584
5584
  * window to float samples (D455).
@@ -8987,6 +8987,7 @@ var CAP_NAMES = Object.freeze([
8987
8987
  "filesystem-browse",
8988
8988
  "flood",
8989
8989
  "gas",
8990
+ "group-active",
8990
8991
  "group-commands",
8991
8992
  "group-status",
8992
8993
  "heating-valve",
@@ -9009,6 +9010,7 @@ var CAP_NAMES = Object.freeze([
9009
9010
  "login-method",
9010
9011
  "media-player",
9011
9012
  "mesh-network",
9013
+ "meter",
9012
9014
  "metrics-provider",
9013
9015
  "model-convert",
9014
9016
  "model-distributor",
@@ -9807,6 +9809,10 @@ Object.freeze({
9807
9809
  "path": "detected",
9808
9810
  "valueType": "boolean"
9809
9811
  }],
9812
+ "group-active": [{
9813
+ "path": "active",
9814
+ "valueType": "boolean"
9815
+ }],
9810
9816
  "group-status": [
9811
9817
  {
9812
9818
  "path": "included",
@@ -10066,6 +10072,10 @@ Object.freeze({
10066
10072
  ]
10067
10073
  }
10068
10074
  ],
10075
+ "meter": [{
10076
+ "path": "value",
10077
+ "valueType": "number"
10078
+ }],
10069
10079
  "motion": [
10070
10080
  {
10071
10081
  "path": "detected",
@@ -10809,7 +10819,7 @@ object({
10809
10819
  params: record(string(), union([string(), number()])).optional()
10810
10820
  });
10811
10821
  //#endregion
10812
- //#region ../types/dist/err-msg-BXKzRBwg.mjs
10822
+ //#region ../types/dist/err-msg-DIorGYeC.mjs
10813
10823
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
10814
10824
  DeviceType["Camera"] = "camera";
10815
10825
  DeviceType["Hub"] = "hub";
@@ -10903,8 +10913,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
10903
10913
  DeviceType["PetFeeder"] = "pet-feeder";
10904
10914
  /** Built-in dishwasher — program lifecycle, door / remote-start gates,
10905
10915
  * salt and rinse-aid levels. Installed with the `dishwasher` cap.
10906
- * Sources: native Bosch Home Connect, reusable by similar integrations. */
10916
+ * Sources: native Bosch Home Connect, reusable by similar integrations.
10917
+ * A plug-built dishwasher carries running-state and power instead. */
10907
10918
  DeviceType["Dishwasher"] = "dishwasher";
10919
+ /** Washing machine. A plug-built one is running while its power stays
10920
+ * above a threshold. No program cap — that surface is the dishwasher's. */
10921
+ DeviceType["Washer"] = "washer";
10922
+ /** Tumble dryer. Same plug-built running surface as {@link Washer}. */
10923
+ DeviceType["Dryer"] = "dryer";
10908
10924
  return DeviceType;
10909
10925
  }({});
10910
10926
  var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
@@ -11152,7 +11168,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
11152
11168
  return DeviceRole;
11153
11169
  }({});
11154
11170
  //#endregion
11155
- //#region ../types/dist/composition-OhpuespA.mjs
11171
+ //#region ../types/dist/composition-Bb8iwHEJ.mjs
11156
11172
  /**
11157
11173
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11158
11174
  *
@@ -11467,6 +11483,13 @@ var table = {
11467
11483
  apply: () => {
11468
11484
  throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
11469
11485
  }
11486
+ },
11487
+ schmitt: {
11488
+ minArgs: 3,
11489
+ maxArgs: 5,
11490
+ apply: () => {
11491
+ throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
11492
+ }
11470
11493
  }
11471
11494
  };
11472
11495
  Object.freeze(Object.assign(Object.create(null), table));
@@ -11908,6 +11931,99 @@ function validateExpressionSource(src) {
11908
11931
  return null;
11909
11932
  }
11910
11933
  /**
11934
+ * One power reading becomes a washer, dryer or dishwasher (D944 helper).
11935
+ *
11936
+ * Standby of the control board is under 5 W; a motor or a heater is far
11937
+ * above that, so 5 W is the line. A door lock or a short pump spike is not
11938
+ * a cycle, so running starts only after 30 s above the line.
11939
+ *
11940
+ * A wash, dry or dishwasher pause (soak, heat-wait, heater off between
11941
+ * bursts) lasts several minutes. Ending the cycle on the first dip would
11942
+ * report "finished" in the middle of the program, so the stop dwell is
11943
+ * 10 minutes on every type. The number is stored per type so one machine
11944
+ * can move later without moving the others.
11945
+ */
11946
+ var APPLIANCE_TEMPLATE_ID = "appliance";
11947
+ var APPLIANCE_KINDS = [
11948
+ "washer",
11949
+ "dryer",
11950
+ "dishwasher"
11951
+ ];
11952
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
11953
+ /**
11954
+ * Statistics and integrals over a history read (D944).
11955
+ *
11956
+ * Pure: the same points always give the same answer, so a restart recomputes
11957
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
11958
+ * never the mean of the samples. A hole with no held value is not integrated
11959
+ * as zero. A truncated read is not published.
11960
+ */
11961
+ var STATISTIC_STATS = [
11962
+ "min",
11963
+ "max",
11964
+ "mean",
11965
+ "sum",
11966
+ "count",
11967
+ "change"
11968
+ ];
11969
+ /**
11970
+ * The range a statistics or integral helper asks history for (D944).
11971
+ *
11972
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
11973
+ * or 25 hours across a DST change. A tier is eligible only when its retention
11974
+ * is strictly longer than the longest that range can be. Forever qualifies.
11975
+ * Equal to a tier's retention is a refusal, not a short answer.
11976
+ */
11977
+ var MINUTE_MS = 6e4;
11978
+ var HOUR_MS = 60 * MINUTE_MS;
11979
+ var DAY_MS$1 = 24 * HOUR_MS;
11980
+ var ROLLING_SPANS = [
11981
+ "1h",
11982
+ "24h",
11983
+ "2d",
11984
+ "7d",
11985
+ "30d",
11986
+ "custom"
11987
+ ];
11988
+ var CALENDAR_PERIODS = [
11989
+ "today",
11990
+ "yesterday",
11991
+ "this-week",
11992
+ "this-month"
11993
+ ];
11994
+ var RESET_PERIODS = [
11995
+ "never",
11996
+ "daily",
11997
+ "weekly",
11998
+ "monthly"
11999
+ ];
12000
+ 5 * MINUTE_MS;
12001
+ 24 * HOUR_MS, 2 * DAY_MS$1, 7 * DAY_MS$1, 30 * DAY_MS$1;
12002
+ 7 * DAY_MS$1, 30 * DAY_MS$1, 365 * DAY_MS$1;
12003
+ var rollingWindowObject = object({
12004
+ kind: literal("rolling"),
12005
+ span: _enum(ROLLING_SPANS),
12006
+ customMinutes: number().int().min(5).optional()
12007
+ }).check((payload) => {
12008
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
12009
+ code: "custom",
12010
+ message: "a custom range needs a duration in minutes",
12011
+ path: ["customMinutes"],
12012
+ input: payload.value
12013
+ });
12014
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
12015
+ code: "custom",
12016
+ message: "only a custom range carries a duration",
12017
+ path: ["customMinutes"],
12018
+ input: payload.value
12019
+ });
12020
+ });
12021
+ var RollingWindowSchema = rollingWindowObject;
12022
+ var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
12023
+ kind: literal("calendar"),
12024
+ period: _enum(CALENDAR_PERIODS)
12025
+ })]);
12026
+ /**
11911
12027
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11912
12028
  * id. Split out so helper schemas can name it without a cycle through
11913
12029
  * `composition.ts` (D659).
@@ -11933,7 +12049,13 @@ var GROUP_TEMPLATE_IDS = [
11933
12049
  "occupancy",
11934
12050
  "binary",
11935
12051
  "switch",
11936
- "light"
12052
+ "light",
12053
+ "fan",
12054
+ "cover",
12055
+ "valve",
12056
+ "lock",
12057
+ "media-player",
12058
+ "climate"
11937
12059
  ];
11938
12060
  var NUMERIC_AGGREGATES = [
11939
12061
  "mean",
@@ -11963,14 +12085,73 @@ var HelperMemberSchema = object({
11963
12085
  cap: string().min(1),
11964
12086
  fieldPath: string().min(1)
11965
12087
  });
11966
- var HelperSpecSchema = discriminatedUnion("kind", [object({
11967
- kind: literal("group"),
11968
- templateId: GroupTemplateIdSchema,
11969
- aggregate: AggregateReducerSchema,
11970
- members: array(HelperMemberSchema).min(1).max(64),
11971
- /** Actuator groups only. Readings leave this unset. */
11972
- active: ActiveCriterionSchema.optional()
11973
- })]);
12088
+ var HelperSpecSchema = discriminatedUnion("kind", [
12089
+ object({
12090
+ kind: literal("group"),
12091
+ templateId: GroupTemplateIdSchema,
12092
+ aggregate: AggregateReducerSchema,
12093
+ members: array(HelperMemberSchema).min(1).max(64),
12094
+ /** Actuator groups only. Readings leave this unset. */
12095
+ active: ActiveCriterionSchema.optional()
12096
+ }),
12097
+ object({
12098
+ kind: literal("appliance"),
12099
+ templateId: literal(APPLIANCE_TEMPLATE_ID),
12100
+ appliance: _enum(APPLIANCE_KINDS),
12101
+ thresholdWatts: number().positive(),
12102
+ startDwellMs: number().int().nonnegative(),
12103
+ stopDwellMs: number().int().nonnegative(),
12104
+ member: HelperMemberSchema
12105
+ }),
12106
+ object({
12107
+ kind: literal("statistic"),
12108
+ stat: _enum(STATISTIC_STATS),
12109
+ window: StatisticWindowSchema,
12110
+ source: HelperMemberSchema
12111
+ }),
12112
+ object({
12113
+ kind: literal("integral"),
12114
+ reset: _enum(RESET_PERIODS),
12115
+ output: _enum(["energy", "meter"]),
12116
+ source: HelperMemberSchema
12117
+ }),
12118
+ object({
12119
+ kind: literal("threshold"),
12120
+ source: HelperMemberSchema,
12121
+ high: number(),
12122
+ low: number(),
12123
+ onForMs: number().int().nonnegative(),
12124
+ offForMs: number().int().nonnegative()
12125
+ }),
12126
+ object({
12127
+ kind: literal("arithmetic"),
12128
+ op: _enum([
12129
+ "sum",
12130
+ "difference",
12131
+ "ratio"
12132
+ ]),
12133
+ inputs: array(HelperMemberSchema).min(2).max(64)
12134
+ }),
12135
+ object({
12136
+ kind: literal("expression"),
12137
+ expr: string().min(1),
12138
+ inputs: array(object({
12139
+ name: string().min(1),
12140
+ member: HelperMemberSchema
12141
+ })).min(1).max(64),
12142
+ output: _enum(["number", "boolean"])
12143
+ }),
12144
+ object({
12145
+ kind: literal("derivative"),
12146
+ window: RollingWindowSchema,
12147
+ per: _enum([
12148
+ "second",
12149
+ "minute",
12150
+ "hour"
12151
+ ]),
12152
+ source: HelperMemberSchema
12153
+ })
12154
+ ]);
11974
12155
  /** A composed device's stableId is this prefix plus the block id. */
11975
12156
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
11976
12157
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -12031,6 +12212,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12031
12212
  "all"
12032
12213
  ]),
12033
12214
  reads: array(CompositionFieldReadSchema).min(1).max(64),
12215
+ /**
12216
+ * Set when the reads are an enum state, not a yes/no: the listed states
12217
+ * count as active (a cover is `open`). A state outside the list is inactive;
12218
+ * a read that is not a state at all is left out. Only `any` / `all` use it.
12219
+ */
12220
+ activeWhen: array(string().min(1)).min(1).optional(),
12034
12221
  /** `value` is the reading; the others are the member counts. */
12035
12222
  publish: _enum([
12036
12223
  "value",
@@ -12044,6 +12231,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12044
12231
  "omit",
12045
12232
  "offline"
12046
12233
  ])
12234
+ }),
12235
+ object({
12236
+ kind: literal("series"),
12237
+ read: CompositionFieldReadSchema,
12238
+ /** `value` is the statistic or the integral. The others are the gap counts. */
12239
+ publish: _enum([
12240
+ "value",
12241
+ "included",
12242
+ "excluded",
12243
+ "total"
12244
+ ]),
12245
+ /**
12246
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
12247
+ * device unseeded until history answers, so a restart cannot publish 0.
12248
+ */
12249
+ empty: _enum([
12250
+ "null",
12251
+ "omit",
12252
+ "offline"
12253
+ ])
12047
12254
  })
12048
12255
  ]);
12049
12256
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -17203,7 +17410,22 @@ var BrokerProviderInfoSchema = object({
17203
17410
  */
17204
17411
  interactiveConnectPath: string().min(1).optional(),
17205
17412
  /** Relative hub path to disconnect the linked account (same popup pattern). */
17206
- interactiveDisconnectPath: string().min(1).optional()
17413
+ interactiveDisconnectPath: string().min(1).optional(),
17414
+ /**
17415
+ * The kind signs in through a server-held interactive session instead of
17416
+ * (or before) typed credentials. `basePath` is a hub-relative route set
17417
+ * served by the owning addon (`/addon/<id>/...`) speaking the sign-in
17418
+ * contract: `POST {basePath}/start` (body: the form's settings) answers
17419
+ * `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
17420
+ * `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
17421
+ * 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
17422
+ * (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
17423
+ * existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
17424
+ * (`{ sessionId }`) drops the session. The dialog that edits a broker
17425
+ * offers it as the default path; the fields the session fills are
17426
+ * marked `filledBySignIn` in the kind's settings schema.
17427
+ */
17428
+ signIn: object({ basePath: string().min(1) }).optional()
17207
17429
  }))
17208
17430
  });
17209
17431
  var ListInputSchema = object({
@@ -18202,7 +18424,8 @@ var CompositionProblemSchema = object({
18202
18424
  "native-capability-replace",
18203
18425
  "mixed-quantity",
18204
18426
  "helper-mismatch",
18205
- "member-constraint"
18427
+ "member-constraint",
18428
+ "retention"
18206
18429
  ]),
18207
18430
  path: string(),
18208
18431
  message: string()
@@ -18436,13 +18659,17 @@ Object.freeze({
18436
18659
  latchedAt: {
18437
18660
  kind: "fixed",
18438
18661
  result: ["number", "null"]
18662
+ },
18663
+ schmitt: {
18664
+ kind: "fixed",
18665
+ result: ["boolean", "null"]
18439
18666
  }
18440
18667
  });
18441
18668
  /**
18442
18669
  * One catalog row per base reading a group helper can build (D944 §3).
18443
18670
  * Data, not a form default written into the block.
18444
18671
  */
18445
- var NOW = {
18672
+ var NOW$2 = {
18446
18673
  fieldPath: "lastFetchedAt",
18447
18674
  expr: "now"
18448
18675
  };
@@ -18456,6 +18683,8 @@ function numeric(input) {
18456
18683
  family: "numeric",
18457
18684
  deviceType: DeviceType.Sensor,
18458
18685
  memberDeviceType: DeviceType.Sensor,
18686
+ memberDeviceTypes: [DeviceType.Sensor],
18687
+ activeWhen: void 0,
18459
18688
  commandCaps: [],
18460
18689
  baseUnit: baseUnitOf(input.quantity),
18461
18690
  aggregates: NUMERIC_AGGREGATES,
@@ -18471,6 +18700,8 @@ function binary(input) {
18471
18700
  family: "binary",
18472
18701
  deviceType: DeviceType.Sensor,
18473
18702
  memberDeviceType: DeviceType.Sensor,
18703
+ memberDeviceTypes: [DeviceType.Sensor],
18704
+ activeWhen: void 0,
18474
18705
  commandCaps: [],
18475
18706
  quantity: "none",
18476
18707
  baseUnit: void 0,
@@ -18488,7 +18719,7 @@ var GROUP_TEMPLATES = [
18488
18719
  quantity: "temperature",
18489
18720
  defaultAggregate: "mean",
18490
18721
  empty: "null",
18491
- companions: [NOW]
18722
+ companions: [NOW$2]
18492
18723
  }),
18493
18724
  numeric({
18494
18725
  id: "humidity",
@@ -18499,7 +18730,7 @@ var GROUP_TEMPLATES = [
18499
18730
  quantity: "humidity",
18500
18731
  defaultAggregate: "mean",
18501
18732
  empty: "null",
18502
- companions: [NOW]
18733
+ companions: [NOW$2]
18503
18734
  }),
18504
18735
  numeric({
18505
18736
  id: "pressure",
@@ -18510,7 +18741,7 @@ var GROUP_TEMPLATES = [
18510
18741
  quantity: "pressure",
18511
18742
  defaultAggregate: "mean",
18512
18743
  empty: "null",
18513
- companions: [NOW]
18744
+ companions: [NOW$2]
18514
18745
  }),
18515
18746
  numeric({
18516
18747
  id: "illuminance",
@@ -18521,7 +18752,7 @@ var GROUP_TEMPLATES = [
18521
18752
  quantity: "illuminance",
18522
18753
  defaultAggregate: "mean",
18523
18754
  empty: "null",
18524
- companions: [NOW]
18755
+ companions: [NOW$2]
18525
18756
  }),
18526
18757
  numeric({
18527
18758
  id: "power",
@@ -18532,7 +18763,7 @@ var GROUP_TEMPLATES = [
18532
18763
  quantity: "power",
18533
18764
  defaultAggregate: "sum",
18534
18765
  empty: "omit",
18535
- companions: [NOW]
18766
+ companions: [NOW$2]
18536
18767
  }),
18537
18768
  numeric({
18538
18769
  id: "energy",
@@ -18543,7 +18774,7 @@ var GROUP_TEMPLATES = [
18543
18774
  quantity: "energy",
18544
18775
  defaultAggregate: "sum",
18545
18776
  empty: "omit",
18546
- companions: [NOW]
18777
+ companions: [NOW$2]
18547
18778
  }),
18548
18779
  numeric({
18549
18780
  id: "battery",
@@ -18578,7 +18809,7 @@ var GROUP_TEMPLATES = [
18578
18809
  quantity: "device",
18579
18810
  defaultAggregate: "mean",
18580
18811
  empty: "null",
18581
- companions: [NOW]
18812
+ companions: [NOW$2]
18582
18813
  }),
18583
18814
  binary({
18584
18815
  id: "motion",
@@ -18672,6 +18903,11 @@ var GROUP_TEMPLATES = [
18672
18903
  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.",
18673
18904
  deviceType: DeviceType.Switch,
18674
18905
  outputCap: "switch",
18906
+ outputField: "on",
18907
+ member: {
18908
+ cap: "switch",
18909
+ fieldPath: "on"
18910
+ },
18675
18911
  commandCaps: ["switch"]
18676
18912
  }),
18677
18913
  actuator({
@@ -18679,34 +18915,136 @@ var GROUP_TEMPLATES = [
18679
18915
  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.",
18680
18916
  deviceType: DeviceType.Light,
18681
18917
  outputCap: "switch",
18918
+ outputField: "on",
18919
+ member: {
18920
+ cap: "switch",
18921
+ fieldPath: "on"
18922
+ },
18682
18923
  commandCaps: [
18683
18924
  "switch",
18684
18925
  "brightness",
18685
18926
  "color"
18686
18927
  ]
18928
+ }),
18929
+ actuator({
18930
+ id: "fan",
18931
+ 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.",
18932
+ deviceType: DeviceType.Fan,
18933
+ outputCap: "switch",
18934
+ outputField: "on",
18935
+ member: {
18936
+ cap: "switch",
18937
+ fieldPath: "on"
18938
+ },
18939
+ commandCaps: ["switch", "fan-control"]
18940
+ }),
18941
+ actuator({
18942
+ id: "cover",
18943
+ 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.",
18944
+ deviceType: DeviceType.Cover,
18945
+ outputCap: "group-active",
18946
+ outputField: "active",
18947
+ member: {
18948
+ cap: "cover",
18949
+ fieldPath: "state"
18950
+ },
18951
+ activeWhen: [
18952
+ "open",
18953
+ "opening",
18954
+ "stopped"
18955
+ ],
18956
+ commandCaps: ["cover"]
18957
+ }),
18958
+ actuator({
18959
+ id: "valve",
18960
+ 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.",
18961
+ deviceType: DeviceType.Valve,
18962
+ outputCap: "group-active",
18963
+ outputField: "active",
18964
+ member: {
18965
+ cap: "valve",
18966
+ fieldPath: "state"
18967
+ },
18968
+ activeWhen: [
18969
+ "open",
18970
+ "opening",
18971
+ "stopped"
18972
+ ],
18973
+ commandCaps: ["valve"]
18974
+ }),
18975
+ actuator({
18976
+ id: "lock",
18977
+ 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.",
18978
+ deviceType: DeviceType.Lock,
18979
+ outputCap: "group-active",
18980
+ outputField: "active",
18981
+ member: {
18982
+ cap: "lock-control",
18983
+ fieldPath: "state"
18984
+ },
18985
+ activeWhen: ["locked"],
18986
+ commandCaps: ["lock-control"]
18987
+ }),
18988
+ actuator({
18989
+ id: "media-player",
18990
+ 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.",
18991
+ deviceType: DeviceType.MediaPlayer,
18992
+ outputCap: "group-active",
18993
+ outputField: "active",
18994
+ member: {
18995
+ cap: "media-player",
18996
+ fieldPath: "state"
18997
+ },
18998
+ activeWhen: ["playing", "buffering"],
18999
+ commandCaps: ["media-player"]
19000
+ }),
19001
+ actuator({
19002
+ id: "climate",
19003
+ 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.",
19004
+ deviceType: DeviceType.Thermostat,
19005
+ memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
19006
+ outputCap: "group-active",
19007
+ outputField: "active",
19008
+ member: {
19009
+ cap: "climate-control",
19010
+ fieldPath: "mode"
19011
+ },
19012
+ activeWhen: [
19013
+ "heat",
19014
+ "cool",
19015
+ "auto",
19016
+ "heat_cool",
19017
+ "fan_only",
19018
+ "dry"
19019
+ ],
19020
+ commandCaps: ["climate-control"]
18687
19021
  })
18688
19022
  ];
18689
19023
  function actuator(input) {
18690
19024
  return {
18691
- ...input,
19025
+ id: input.id,
19026
+ summary: input.summary,
19027
+ deviceType: input.deviceType,
19028
+ outputCap: input.outputCap,
19029
+ outputField: input.outputField,
19030
+ commandCaps: input.commandCaps,
18692
19031
  family: "actuator",
18693
19032
  role: void 0,
18694
19033
  memberDeviceType: input.deviceType,
18695
- outputField: "on",
19034
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
19035
+ activeWhen: input.activeWhen,
18696
19036
  quantity: "none",
18697
19037
  baseUnit: void 0,
18698
19038
  aggregates: BINARY_AGGREGATES,
18699
19039
  defaultAggregate: "any",
18700
19040
  empty: "offline",
18701
- accept: [{
18702
- cap: "switch",
18703
- fieldPath: "on"
18704
- }],
19041
+ accept: [input.member],
18705
19042
  companions: [CHANGED]
18706
19043
  };
18707
19044
  }
18708
19045
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
18709
19046
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
19047
+ DeviceType.Camera;
18710
19048
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
18711
19049
  /**
18712
19050
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -43721,7 +44059,7 @@ var NetworkAccessStatusSchema = object({
43721
44059
  });
43722
44060
  /**
43723
44061
  * Optional, richer endpoint shape returned by providers that expose
43724
- * MORE than one ingress concurrently (Tailscale Ingress with mixed
44062
+ * MORE than one ingress concurrently (Tailscale Funnel with mixed
43725
44063
  * serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
43726
44064
  * the originating provider config (mode + sourcePort) so the
43727
44065
  * orchestrator UI can label rows distinctly. Providers that expose only
@@ -46364,7 +46702,20 @@ var NcRuleInputSchema = object({
46364
46702
  * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
46365
46703
  * path does not run Zod defaults.
46366
46704
  */
46367
- groupingSec: number().int().min(5).max(60).optional()
46705
+ groupingSec: number().int().min(5).max(60).optional(),
46706
+ /**
46707
+ * ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
46708
+ * carries "Correct" / "Wrong" buttons (and, where the channel has room, a
46709
+ * "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
46710
+ * same mark the Library writes, and records whose notification it was and
46711
+ * when. A channel with no buttons gets the same two choices as links.
46712
+ *
46713
+ * `.optional()`, never `.default()` (a Zod default does not run on the addon
46714
+ * cap path): absent and `false` both mean off, which is what every rule
46715
+ * authored before this field meant. An editor turns it off by writing
46716
+ * `false`, so it needs no `clear` key.
46717
+ */
46718
+ askVerdict: boolean().optional()
46368
46719
  });
46369
46720
  /**
46370
46721
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -56821,7 +57172,7 @@ var BatteryStatusSchema = object({
56821
57172
  */
56822
57173
  binary: boolean().optional().meta({ label: "Binary indicator" })
56823
57174
  });
56824
- DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
57175
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
56825
57176
  method(object({
56826
57177
  deviceId: number(),
56827
57178
  /** Bound on the wait. Sensible range 3000–10000ms. */
@@ -58575,7 +58926,13 @@ results: array(object({
58575
58926
  /** Ms epoch of the attempt. */
58576
58927
  at: number()
58577
58928
  })) });
58578
- DeviceType.Switch, DeviceType.Light;
58929
+ DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58930
+ object({
58931
+ active: boolean().meta({ label: "Active" }),
58932
+ /** Ms epoch when the slice was last updated. */
58933
+ lastChangedAt: number()
58934
+ });
58935
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
58579
58936
  object({
58580
58937
  /** Members whose current value entered the aggregate. */
58581
58938
  included: number().int().nonnegative().meta(readingMeta("count", {
@@ -58593,7 +58950,7 @@ object({
58593
58950
  label: "Members"
58594
58951
  }))
58595
58952
  });
58596
- DeviceType.Sensor, DeviceType.Switch, DeviceType.Light;
58953
+ DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58597
58954
  object({
58598
58955
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
58599
58956
  position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -59500,7 +59857,14 @@ DeviceType.Lock, method(object({
59500
59857
  auth: "protected"
59501
59858
  }), method(object({
59502
59859
  deviceId: number().int().nonnegative(),
59503
- code: string().min(1).optional()
59860
+ code: string().min(1).optional(),
59861
+ /**
59862
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
59863
+ * with one call is refused unless the caller says it was confirmed. A
59864
+ * single lock ignores it. The refusal lives in the callee, so no
59865
+ * automation or API caller reaches the doors by skipping a dialog.
59866
+ */
59867
+ confirm: boolean().optional()
59504
59868
  }), _void(), {
59505
59869
  kind: "mutation",
59506
59870
  auth: "protected"
@@ -59508,6 +59872,11 @@ DeviceType.Lock, method(object({
59508
59872
  kind: "mutation",
59509
59873
  auth: "protected"
59510
59874
  });
59875
+ object({
59876
+ value: number().nullable().meta(readingMeta("device", { label: "Total" })),
59877
+ lastFetchedAt: number()
59878
+ });
59879
+ DeviceType.Sensor;
59511
59880
  /**
59512
59881
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
59513
59882
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
@@ -61415,9 +61784,9 @@ object({
61415
61784
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
61416
61785
  kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
61417
61786
  /** Voltage in volts. */
61418
- volts: number().optional().meta(readingMeta("voltage")),
61787
+ volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
61419
61788
  /** Current in amperes. */
61420
- amps: number().optional().meta(readingMeta("current")),
61789
+ amps: number().optional().meta(readingMeta("current", { label: "Current" })),
61421
61790
  /** Apparent power in volt-amperes. */
61422
61791
  va: number().optional().meta(readingMeta("apparent-power")),
61423
61792
  /** Power factor (0..1) if reported. */
@@ -61425,7 +61794,23 @@ object({
61425
61794
  /** Ms epoch when the slice was last updated. */
61426
61795
  lastFetchedAt: number()
61427
61796
  });
61428
- DeviceType.Sensor;
61797
+ [
61798
+ DeviceType.Sensor,
61799
+ DeviceType.Switch,
61800
+ DeviceType.Light,
61801
+ DeviceType.Fan,
61802
+ DeviceType.Climate,
61803
+ DeviceType.Thermostat,
61804
+ DeviceType.Humidifier,
61805
+ DeviceType.WaterHeater,
61806
+ DeviceType.MediaPlayer,
61807
+ DeviceType.Washer,
61808
+ DeviceType.Dryer,
61809
+ DeviceType.Dishwasher,
61810
+ DeviceType.Vacuum,
61811
+ DeviceType.LawnMower,
61812
+ DeviceType.PetFeeder
61813
+ ].filter((type) => type !== DeviceType.Sensor);
61429
61814
  /**
61430
61815
  * Presence cap. Models HA `person.*` and `device_tracker.*` entities
61431
61816
  * on `DeviceType.Presence`. Read-only — no setters: presence is
@@ -61872,7 +62257,7 @@ object({
61872
62257
  phase: string().nullable()
61873
62258
  });
61874
62259
  Object.values(DeviceType);
61875
- DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
62260
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
61876
62261
  DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
61877
62262
  kind: "mutation",
61878
62263
  auth: "admin"
@@ -63911,7 +64296,7 @@ object({
63911
64296
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
63912
64297
  lastChangedAt: number()
63913
64298
  });
63914
- DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
64299
+ DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
63915
64300
  deviceId: number(),
63916
64301
  on: boolean()
63917
64302
  }), _void(), {
@@ -65603,8 +65988,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
65603
65988
  kind: "mutation",
65604
65989
  auth: "admin"
65605
65990
  });
65991
+ DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
65606
65992
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
65607
- 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;
65993
+ 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;
65608
65994
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
65609
65995
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
65610
65996
  new Set(CAP_NAMES);
@@ -65657,7 +66043,7 @@ var AccessoryKind = {
65657
66043
  PrivacyMask: DeviceRole.PrivacyMask
65658
66044
  };
65659
66045
  AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
65660
- 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;
66046
+ 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;
65661
66047
  new Set(Object.values(DeviceType));
65662
66048
  Object.freeze({
65663
66049
  "accessories.getStatus": {
@@ -68880,6 +69266,13 @@ Object.freeze({
68880
69266
  access: "view",
68881
69267
  role: "viewer"
68882
69268
  },
69269
+ "groupActive.getStatus": {
69270
+ capName: "group-active",
69271
+ capScope: "device",
69272
+ addonId: null,
69273
+ access: "view",
69274
+ role: "viewer"
69275
+ },
68883
69276
  "groupCommands.getStatus": {
68884
69277
  capName: "group-commands",
68885
69278
  capScope: "device",
@@ -69846,6 +70239,13 @@ Object.freeze({
69846
70239
  access: "create",
69847
70240
  role: "admin"
69848
70241
  },
70242
+ "meter.getStatus": {
70243
+ capName: "meter",
70244
+ capScope: "device",
70245
+ addonId: null,
70246
+ access: "view",
70247
+ role: "viewer"
70248
+ },
69849
70249
  "metricsProvider.collectSnapshot": {
69850
70250
  capName: "metrics-provider",
69851
70251
  capScope: "system",
@@ -77944,7 +78344,39 @@ var APPLIANCE_CAP_VOCABULARY = {
77944
78344
  phrase: t("When {device} finishes", "Quando {device} finisce"),
77945
78345
  icon: "square"
77946
78346
  }
77947
- }
78347
+ },
78348
+ overrides: { byType: {
78349
+ [DeviceType.Washer]: {
78350
+ state: { running: {
78351
+ whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
78352
+ whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
78353
+ } },
78354
+ events: {
78355
+ onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
78356
+ onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
78357
+ }
78358
+ },
78359
+ [DeviceType.Dryer]: {
78360
+ state: { running: {
78361
+ whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
78362
+ whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
78363
+ } },
78364
+ events: {
78365
+ onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
78366
+ onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
78367
+ }
78368
+ },
78369
+ [DeviceType.Dishwasher]: {
78370
+ state: { running: {
78371
+ whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
78372
+ whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
78373
+ } },
78374
+ events: {
78375
+ onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
78376
+ onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
78377
+ }
78378
+ }
78379
+ } }
77948
78380
  },
77949
78381
  update: {
77950
78382
  scope: "device",
@@ -78716,6 +79148,10 @@ var SENSOR_CAP_VOCABULARY = {
78716
79148
  icon: "flame"
78717
79149
  }]
78718
79150
  },
79151
+ "group-active": {
79152
+ scope: "device",
79153
+ noun: t("Group state", "Stato del gruppo")
79154
+ },
78719
79155
  "group-commands": {
78720
79156
  scope: "device",
78721
79157
  noun: t("Group command", "Comando di gruppo")
@@ -78772,6 +79208,17 @@ var SENSOR_CAP_VOCABULARY = {
78772
79208
  }],
78773
79209
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
78774
79210
  },
79211
+ meter: {
79212
+ scope: "device",
79213
+ noun: t("Meter", "Contatore"),
79214
+ state: [{
79215
+ kind: "numeric",
79216
+ field: "value",
79217
+ quantity: t("the total", "il totale"),
79218
+ label: t("Total", "Totale"),
79219
+ icon: "gauge"
79220
+ }]
79221
+ },
78775
79222
  "numeric-sensor": {
78776
79223
  scope: "device",
78777
79224
  noun: t("Sensor", "Sensore"),
@@ -79244,8 +79691,47 @@ function projectAction(cap, action) {
79244
79691
  };
79245
79692
  }
79246
79693
  Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
79247
- 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;
79694
+ 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;
79248
79695
  DeviceFeature.BatteryOperated;
79696
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
79697
+ 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.";
79698
+ 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.";
79699
+ var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
79700
+ var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
79701
+ 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.";
79702
+ function withheld(reason) {
79703
+ return {
79704
+ [DeviceType.Washer]: {
79705
+ exported: false,
79706
+ reason
79707
+ },
79708
+ [DeviceType.Dryer]: {
79709
+ exported: false,
79710
+ reason
79711
+ },
79712
+ [DeviceType.Dishwasher]: {
79713
+ exported: false,
79714
+ reason
79715
+ }
79716
+ };
79717
+ }
79718
+ function offered(received) {
79719
+ return {
79720
+ [DeviceType.Washer]: {
79721
+ exported: true,
79722
+ as: received
79723
+ },
79724
+ [DeviceType.Dryer]: {
79725
+ exported: true,
79726
+ as: received
79727
+ },
79728
+ [DeviceType.Dishwasher]: {
79729
+ exported: true,
79730
+ as: received
79731
+ }
79732
+ };
79733
+ }
79734
+ offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
79249
79735
  Object.freeze({
79250
79736
  "accessories.getStatus": [{
79251
79737
  name: "deviceId",
@@ -80212,6 +80698,11 @@ Object.freeze({
80212
80698
  form: "single",
80213
80699
  optional: false
80214
80700
  }],
80701
+ "groupActive.getStatus": [{
80702
+ name: "deviceId",
80703
+ form: "single",
80704
+ optional: false
80705
+ }],
80215
80706
  "groupCommands.getStatus": [{
80216
80707
  name: "deviceId",
80217
80708
  form: "single",
@@ -80422,6 +80913,11 @@ Object.freeze({
80422
80913
  form: "single",
80423
80914
  optional: false
80424
80915
  }],
80916
+ "meter.getStatus": [{
80917
+ name: "deviceId",
80918
+ form: "single",
80919
+ optional: false
80920
+ }],
80425
80921
  "motion.getStatus": [{
80426
80922
  name: "deviceId",
80427
80923
  form: "single",
@@ -82029,7 +82525,6 @@ Object.freeze({
82029
82525
  "network-access": "ingress",
82030
82526
  "smtp-provider": "email"
82031
82527
  });
82032
- DeviceType.Camera;
82033
82528
  /**
82034
82529
  * A saved Customize assignment (D936). The schema is the type: callers use
82035
82530
  * `z.infer`, they do not restate the shape.