@camstack/addon-smtp-nodemailer 1.2.142 → 1.2.143

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.
@@ -5479,7 +5479,7 @@ var ZodIssueCode = {
5479
5479
  var ZodFirstPartyTypeKind;
5480
5480
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5481
5481
  //#endregion
5482
- //#region ../types/dist/sleep-bykKrTgu.mjs
5482
+ //#region ../types/dist/sleep--jXS9hWo.mjs
5483
5483
  /**
5484
5484
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5485
5485
  * window to float samples (D455).
@@ -8601,6 +8601,7 @@ var CAP_NAMES = Object.freeze([
8601
8601
  "filesystem-browse",
8602
8602
  "flood",
8603
8603
  "gas",
8604
+ "group-active",
8604
8605
  "group-commands",
8605
8606
  "group-status",
8606
8607
  "heating-valve",
@@ -8623,6 +8624,7 @@ var CAP_NAMES = Object.freeze([
8623
8624
  "login-method",
8624
8625
  "media-player",
8625
8626
  "mesh-network",
8627
+ "meter",
8626
8628
  "metrics-provider",
8627
8629
  "model-convert",
8628
8630
  "model-distributor",
@@ -9421,6 +9423,10 @@ Object.freeze({
9421
9423
  "path": "detected",
9422
9424
  "valueType": "boolean"
9423
9425
  }],
9426
+ "group-active": [{
9427
+ "path": "active",
9428
+ "valueType": "boolean"
9429
+ }],
9424
9430
  "group-status": [
9425
9431
  {
9426
9432
  "path": "included",
@@ -9680,6 +9686,10 @@ Object.freeze({
9680
9686
  ]
9681
9687
  }
9682
9688
  ],
9689
+ "meter": [{
9690
+ "path": "value",
9691
+ "valueType": "number"
9692
+ }],
9683
9693
  "motion": [
9684
9694
  {
9685
9695
  "path": "detected",
@@ -10423,7 +10433,7 @@ object({
10423
10433
  params: record(string(), union([string(), number()])).optional()
10424
10434
  });
10425
10435
  //#endregion
10426
- //#region ../types/dist/err-msg-BXKzRBwg.mjs
10436
+ //#region ../types/dist/err-msg-DIorGYeC.mjs
10427
10437
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
10428
10438
  DeviceType["Camera"] = "camera";
10429
10439
  DeviceType["Hub"] = "hub";
@@ -10517,8 +10527,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
10517
10527
  DeviceType["PetFeeder"] = "pet-feeder";
10518
10528
  /** Built-in dishwasher — program lifecycle, door / remote-start gates,
10519
10529
  * salt and rinse-aid levels. Installed with the `dishwasher` cap.
10520
- * Sources: native Bosch Home Connect, reusable by similar integrations. */
10530
+ * Sources: native Bosch Home Connect, reusable by similar integrations.
10531
+ * A plug-built dishwasher carries running-state and power instead. */
10521
10532
  DeviceType["Dishwasher"] = "dishwasher";
10533
+ /** Washing machine. A plug-built one is running while its power stays
10534
+ * above a threshold. No program cap — that surface is the dishwasher's. */
10535
+ DeviceType["Washer"] = "washer";
10536
+ /** Tumble dryer. Same plug-built running surface as {@link Washer}. */
10537
+ DeviceType["Dryer"] = "dryer";
10522
10538
  return DeviceType;
10523
10539
  }({});
10524
10540
  var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
@@ -10766,7 +10782,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
10766
10782
  return DeviceRole;
10767
10783
  }({});
10768
10784
  //#endregion
10769
- //#region ../types/dist/composition-OhpuespA.mjs
10785
+ //#region ../types/dist/composition-Bb8iwHEJ.mjs
10770
10786
  /**
10771
10787
  * The ffmpeg build every CamStack node downloads, per platform and arch.
10772
10788
  *
@@ -11081,6 +11097,13 @@ var table = {
11081
11097
  apply: () => {
11082
11098
  throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
11083
11099
  }
11100
+ },
11101
+ schmitt: {
11102
+ minArgs: 3,
11103
+ maxArgs: 5,
11104
+ apply: () => {
11105
+ throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
11106
+ }
11084
11107
  }
11085
11108
  };
11086
11109
  Object.freeze(Object.assign(Object.create(null), table));
@@ -11522,6 +11545,99 @@ function validateExpressionSource(src) {
11522
11545
  return null;
11523
11546
  }
11524
11547
  /**
11548
+ * One power reading becomes a washer, dryer or dishwasher (D944 helper).
11549
+ *
11550
+ * Standby of the control board is under 5 W; a motor or a heater is far
11551
+ * above that, so 5 W is the line. A door lock or a short pump spike is not
11552
+ * a cycle, so running starts only after 30 s above the line.
11553
+ *
11554
+ * A wash, dry or dishwasher pause (soak, heat-wait, heater off between
11555
+ * bursts) lasts several minutes. Ending the cycle on the first dip would
11556
+ * report "finished" in the middle of the program, so the stop dwell is
11557
+ * 10 minutes on every type. The number is stored per type so one machine
11558
+ * can move later without moving the others.
11559
+ */
11560
+ var APPLIANCE_TEMPLATE_ID = "appliance";
11561
+ var APPLIANCE_KINDS = [
11562
+ "washer",
11563
+ "dryer",
11564
+ "dishwasher"
11565
+ ];
11566
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
11567
+ /**
11568
+ * Statistics and integrals over a history read (D944).
11569
+ *
11570
+ * Pure: the same points always give the same answer, so a restart recomputes
11571
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
11572
+ * never the mean of the samples. A hole with no held value is not integrated
11573
+ * as zero. A truncated read is not published.
11574
+ */
11575
+ var STATISTIC_STATS = [
11576
+ "min",
11577
+ "max",
11578
+ "mean",
11579
+ "sum",
11580
+ "count",
11581
+ "change"
11582
+ ];
11583
+ /**
11584
+ * The range a statistics or integral helper asks history for (D944).
11585
+ *
11586
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
11587
+ * or 25 hours across a DST change. A tier is eligible only when its retention
11588
+ * is strictly longer than the longest that range can be. Forever qualifies.
11589
+ * Equal to a tier's retention is a refusal, not a short answer.
11590
+ */
11591
+ var MINUTE_MS = 6e4;
11592
+ var HOUR_MS = 60 * MINUTE_MS;
11593
+ var DAY_MS = 24 * HOUR_MS;
11594
+ var ROLLING_SPANS = [
11595
+ "1h",
11596
+ "24h",
11597
+ "2d",
11598
+ "7d",
11599
+ "30d",
11600
+ "custom"
11601
+ ];
11602
+ var CALENDAR_PERIODS = [
11603
+ "today",
11604
+ "yesterday",
11605
+ "this-week",
11606
+ "this-month"
11607
+ ];
11608
+ var RESET_PERIODS = [
11609
+ "never",
11610
+ "daily",
11611
+ "weekly",
11612
+ "monthly"
11613
+ ];
11614
+ 5 * MINUTE_MS;
11615
+ 24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
11616
+ 7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
11617
+ var rollingWindowObject = object({
11618
+ kind: literal("rolling"),
11619
+ span: _enum(ROLLING_SPANS),
11620
+ customMinutes: number().int().min(5).optional()
11621
+ }).check((payload) => {
11622
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
11623
+ code: "custom",
11624
+ message: "a custom range needs a duration in minutes",
11625
+ path: ["customMinutes"],
11626
+ input: payload.value
11627
+ });
11628
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
11629
+ code: "custom",
11630
+ message: "only a custom range carries a duration",
11631
+ path: ["customMinutes"],
11632
+ input: payload.value
11633
+ });
11634
+ });
11635
+ var RollingWindowSchema = rollingWindowObject;
11636
+ var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
11637
+ kind: literal("calendar"),
11638
+ period: _enum(CALENDAR_PERIODS)
11639
+ })]);
11640
+ /**
11525
11641
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11526
11642
  * id. Split out so helper schemas can name it without a cycle through
11527
11643
  * `composition.ts` (D659).
@@ -11547,7 +11663,13 @@ var GROUP_TEMPLATE_IDS = [
11547
11663
  "occupancy",
11548
11664
  "binary",
11549
11665
  "switch",
11550
- "light"
11666
+ "light",
11667
+ "fan",
11668
+ "cover",
11669
+ "valve",
11670
+ "lock",
11671
+ "media-player",
11672
+ "climate"
11551
11673
  ];
11552
11674
  var NUMERIC_AGGREGATES = [
11553
11675
  "mean",
@@ -11577,14 +11699,73 @@ var HelperMemberSchema = object({
11577
11699
  cap: string().min(1),
11578
11700
  fieldPath: string().min(1)
11579
11701
  });
11580
- var HelperSpecSchema = discriminatedUnion("kind", [object({
11581
- kind: literal("group"),
11582
- templateId: GroupTemplateIdSchema,
11583
- aggregate: AggregateReducerSchema,
11584
- members: array(HelperMemberSchema).min(1).max(64),
11585
- /** Actuator groups only. Readings leave this unset. */
11586
- active: ActiveCriterionSchema.optional()
11587
- })]);
11702
+ var HelperSpecSchema = discriminatedUnion("kind", [
11703
+ object({
11704
+ kind: literal("group"),
11705
+ templateId: GroupTemplateIdSchema,
11706
+ aggregate: AggregateReducerSchema,
11707
+ members: array(HelperMemberSchema).min(1).max(64),
11708
+ /** Actuator groups only. Readings leave this unset. */
11709
+ active: ActiveCriterionSchema.optional()
11710
+ }),
11711
+ object({
11712
+ kind: literal("appliance"),
11713
+ templateId: literal(APPLIANCE_TEMPLATE_ID),
11714
+ appliance: _enum(APPLIANCE_KINDS),
11715
+ thresholdWatts: number().positive(),
11716
+ startDwellMs: number().int().nonnegative(),
11717
+ stopDwellMs: number().int().nonnegative(),
11718
+ member: HelperMemberSchema
11719
+ }),
11720
+ object({
11721
+ kind: literal("statistic"),
11722
+ stat: _enum(STATISTIC_STATS),
11723
+ window: StatisticWindowSchema,
11724
+ source: HelperMemberSchema
11725
+ }),
11726
+ object({
11727
+ kind: literal("integral"),
11728
+ reset: _enum(RESET_PERIODS),
11729
+ output: _enum(["energy", "meter"]),
11730
+ source: HelperMemberSchema
11731
+ }),
11732
+ object({
11733
+ kind: literal("threshold"),
11734
+ source: HelperMemberSchema,
11735
+ high: number(),
11736
+ low: number(),
11737
+ onForMs: number().int().nonnegative(),
11738
+ offForMs: number().int().nonnegative()
11739
+ }),
11740
+ object({
11741
+ kind: literal("arithmetic"),
11742
+ op: _enum([
11743
+ "sum",
11744
+ "difference",
11745
+ "ratio"
11746
+ ]),
11747
+ inputs: array(HelperMemberSchema).min(2).max(64)
11748
+ }),
11749
+ object({
11750
+ kind: literal("expression"),
11751
+ expr: string().min(1),
11752
+ inputs: array(object({
11753
+ name: string().min(1),
11754
+ member: HelperMemberSchema
11755
+ })).min(1).max(64),
11756
+ output: _enum(["number", "boolean"])
11757
+ }),
11758
+ object({
11759
+ kind: literal("derivative"),
11760
+ window: RollingWindowSchema,
11761
+ per: _enum([
11762
+ "second",
11763
+ "minute",
11764
+ "hour"
11765
+ ]),
11766
+ source: HelperMemberSchema
11767
+ })
11768
+ ]);
11588
11769
  /** A composed device's stableId is this prefix plus the block id. */
11589
11770
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
11590
11771
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -11645,6 +11826,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
11645
11826
  "all"
11646
11827
  ]),
11647
11828
  reads: array(CompositionFieldReadSchema).min(1).max(64),
11829
+ /**
11830
+ * Set when the reads are an enum state, not a yes/no: the listed states
11831
+ * count as active (a cover is `open`). A state outside the list is inactive;
11832
+ * a read that is not a state at all is left out. Only `any` / `all` use it.
11833
+ */
11834
+ activeWhen: array(string().min(1)).min(1).optional(),
11648
11835
  /** `value` is the reading; the others are the member counts. */
11649
11836
  publish: _enum([
11650
11837
  "value",
@@ -11658,6 +11845,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
11658
11845
  "omit",
11659
11846
  "offline"
11660
11847
  ])
11848
+ }),
11849
+ object({
11850
+ kind: literal("series"),
11851
+ read: CompositionFieldReadSchema,
11852
+ /** `value` is the statistic or the integral. The others are the gap counts. */
11853
+ publish: _enum([
11854
+ "value",
11855
+ "included",
11856
+ "excluded",
11857
+ "total"
11858
+ ]),
11859
+ /**
11860
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
11861
+ * device unseeded until history answers, so a restart cannot publish 0.
11862
+ */
11863
+ empty: _enum([
11864
+ "null",
11865
+ "omit",
11866
+ "offline"
11867
+ ])
11661
11868
  })
11662
11869
  ]);
11663
11870
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -16817,7 +17024,22 @@ var BrokerProviderInfoSchema = object({
16817
17024
  */
16818
17025
  interactiveConnectPath: string().min(1).optional(),
16819
17026
  /** Relative hub path to disconnect the linked account (same popup pattern). */
16820
- interactiveDisconnectPath: string().min(1).optional()
17027
+ interactiveDisconnectPath: string().min(1).optional(),
17028
+ /**
17029
+ * The kind signs in through a server-held interactive session instead of
17030
+ * (or before) typed credentials. `basePath` is a hub-relative route set
17031
+ * served by the owning addon (`/addon/<id>/...`) speaking the sign-in
17032
+ * contract: `POST {basePath}/start` (body: the form's settings) answers
17033
+ * `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
17034
+ * `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
17035
+ * 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
17036
+ * (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
17037
+ * existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
17038
+ * (`{ sessionId }`) drops the session. The dialog that edits a broker
17039
+ * offers it as the default path; the fields the session fills are
17040
+ * marked `filledBySignIn` in the kind's settings schema.
17041
+ */
17042
+ signIn: object({ basePath: string().min(1) }).optional()
16821
17043
  }))
16822
17044
  });
16823
17045
  var ListInputSchema = object({
@@ -17816,7 +18038,8 @@ var CompositionProblemSchema = object({
17816
18038
  "native-capability-replace",
17817
18039
  "mixed-quantity",
17818
18040
  "helper-mismatch",
17819
- "member-constraint"
18041
+ "member-constraint",
18042
+ "retention"
17820
18043
  ]),
17821
18044
  path: string(),
17822
18045
  message: string()
@@ -18050,13 +18273,17 @@ Object.freeze({
18050
18273
  latchedAt: {
18051
18274
  kind: "fixed",
18052
18275
  result: ["number", "null"]
18276
+ },
18277
+ schmitt: {
18278
+ kind: "fixed",
18279
+ result: ["boolean", "null"]
18053
18280
  }
18054
18281
  });
18055
18282
  /**
18056
18283
  * One catalog row per base reading a group helper can build (D944 §3).
18057
18284
  * Data, not a form default written into the block.
18058
18285
  */
18059
- var NOW = {
18286
+ var NOW$2 = {
18060
18287
  fieldPath: "lastFetchedAt",
18061
18288
  expr: "now"
18062
18289
  };
@@ -18070,6 +18297,8 @@ function numeric(input) {
18070
18297
  family: "numeric",
18071
18298
  deviceType: DeviceType.Sensor,
18072
18299
  memberDeviceType: DeviceType.Sensor,
18300
+ memberDeviceTypes: [DeviceType.Sensor],
18301
+ activeWhen: void 0,
18073
18302
  commandCaps: [],
18074
18303
  baseUnit: baseUnitOf(input.quantity),
18075
18304
  aggregates: NUMERIC_AGGREGATES,
@@ -18085,6 +18314,8 @@ function binary(input) {
18085
18314
  family: "binary",
18086
18315
  deviceType: DeviceType.Sensor,
18087
18316
  memberDeviceType: DeviceType.Sensor,
18317
+ memberDeviceTypes: [DeviceType.Sensor],
18318
+ activeWhen: void 0,
18088
18319
  commandCaps: [],
18089
18320
  quantity: "none",
18090
18321
  baseUnit: void 0,
@@ -18102,7 +18333,7 @@ var GROUP_TEMPLATES = [
18102
18333
  quantity: "temperature",
18103
18334
  defaultAggregate: "mean",
18104
18335
  empty: "null",
18105
- companions: [NOW]
18336
+ companions: [NOW$2]
18106
18337
  }),
18107
18338
  numeric({
18108
18339
  id: "humidity",
@@ -18113,7 +18344,7 @@ var GROUP_TEMPLATES = [
18113
18344
  quantity: "humidity",
18114
18345
  defaultAggregate: "mean",
18115
18346
  empty: "null",
18116
- companions: [NOW]
18347
+ companions: [NOW$2]
18117
18348
  }),
18118
18349
  numeric({
18119
18350
  id: "pressure",
@@ -18124,7 +18355,7 @@ var GROUP_TEMPLATES = [
18124
18355
  quantity: "pressure",
18125
18356
  defaultAggregate: "mean",
18126
18357
  empty: "null",
18127
- companions: [NOW]
18358
+ companions: [NOW$2]
18128
18359
  }),
18129
18360
  numeric({
18130
18361
  id: "illuminance",
@@ -18135,7 +18366,7 @@ var GROUP_TEMPLATES = [
18135
18366
  quantity: "illuminance",
18136
18367
  defaultAggregate: "mean",
18137
18368
  empty: "null",
18138
- companions: [NOW]
18369
+ companions: [NOW$2]
18139
18370
  }),
18140
18371
  numeric({
18141
18372
  id: "power",
@@ -18146,7 +18377,7 @@ var GROUP_TEMPLATES = [
18146
18377
  quantity: "power",
18147
18378
  defaultAggregate: "sum",
18148
18379
  empty: "omit",
18149
- companions: [NOW]
18380
+ companions: [NOW$2]
18150
18381
  }),
18151
18382
  numeric({
18152
18383
  id: "energy",
@@ -18157,7 +18388,7 @@ var GROUP_TEMPLATES = [
18157
18388
  quantity: "energy",
18158
18389
  defaultAggregate: "sum",
18159
18390
  empty: "omit",
18160
- companions: [NOW]
18391
+ companions: [NOW$2]
18161
18392
  }),
18162
18393
  numeric({
18163
18394
  id: "battery",
@@ -18192,7 +18423,7 @@ var GROUP_TEMPLATES = [
18192
18423
  quantity: "device",
18193
18424
  defaultAggregate: "mean",
18194
18425
  empty: "null",
18195
- companions: [NOW]
18426
+ companions: [NOW$2]
18196
18427
  }),
18197
18428
  binary({
18198
18429
  id: "motion",
@@ -18286,6 +18517,11 @@ var GROUP_TEMPLATES = [
18286
18517
  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.",
18287
18518
  deviceType: DeviceType.Switch,
18288
18519
  outputCap: "switch",
18520
+ outputField: "on",
18521
+ member: {
18522
+ cap: "switch",
18523
+ fieldPath: "on"
18524
+ },
18289
18525
  commandCaps: ["switch"]
18290
18526
  }),
18291
18527
  actuator({
@@ -18293,34 +18529,136 @@ var GROUP_TEMPLATES = [
18293
18529
  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.",
18294
18530
  deviceType: DeviceType.Light,
18295
18531
  outputCap: "switch",
18532
+ outputField: "on",
18533
+ member: {
18534
+ cap: "switch",
18535
+ fieldPath: "on"
18536
+ },
18296
18537
  commandCaps: [
18297
18538
  "switch",
18298
18539
  "brightness",
18299
18540
  "color"
18300
18541
  ]
18542
+ }),
18543
+ actuator({
18544
+ id: "fan",
18545
+ 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.",
18546
+ deviceType: DeviceType.Fan,
18547
+ outputCap: "switch",
18548
+ outputField: "on",
18549
+ member: {
18550
+ cap: "switch",
18551
+ fieldPath: "on"
18552
+ },
18553
+ commandCaps: ["switch", "fan-control"]
18554
+ }),
18555
+ actuator({
18556
+ id: "cover",
18557
+ 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.",
18558
+ deviceType: DeviceType.Cover,
18559
+ outputCap: "group-active",
18560
+ outputField: "active",
18561
+ member: {
18562
+ cap: "cover",
18563
+ fieldPath: "state"
18564
+ },
18565
+ activeWhen: [
18566
+ "open",
18567
+ "opening",
18568
+ "stopped"
18569
+ ],
18570
+ commandCaps: ["cover"]
18571
+ }),
18572
+ actuator({
18573
+ id: "valve",
18574
+ 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.",
18575
+ deviceType: DeviceType.Valve,
18576
+ outputCap: "group-active",
18577
+ outputField: "active",
18578
+ member: {
18579
+ cap: "valve",
18580
+ fieldPath: "state"
18581
+ },
18582
+ activeWhen: [
18583
+ "open",
18584
+ "opening",
18585
+ "stopped"
18586
+ ],
18587
+ commandCaps: ["valve"]
18588
+ }),
18589
+ actuator({
18590
+ id: "lock",
18591
+ 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.",
18592
+ deviceType: DeviceType.Lock,
18593
+ outputCap: "group-active",
18594
+ outputField: "active",
18595
+ member: {
18596
+ cap: "lock-control",
18597
+ fieldPath: "state"
18598
+ },
18599
+ activeWhen: ["locked"],
18600
+ commandCaps: ["lock-control"]
18601
+ }),
18602
+ actuator({
18603
+ id: "media-player",
18604
+ 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.",
18605
+ deviceType: DeviceType.MediaPlayer,
18606
+ outputCap: "group-active",
18607
+ outputField: "active",
18608
+ member: {
18609
+ cap: "media-player",
18610
+ fieldPath: "state"
18611
+ },
18612
+ activeWhen: ["playing", "buffering"],
18613
+ commandCaps: ["media-player"]
18614
+ }),
18615
+ actuator({
18616
+ id: "climate",
18617
+ 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.",
18618
+ deviceType: DeviceType.Thermostat,
18619
+ memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
18620
+ outputCap: "group-active",
18621
+ outputField: "active",
18622
+ member: {
18623
+ cap: "climate-control",
18624
+ fieldPath: "mode"
18625
+ },
18626
+ activeWhen: [
18627
+ "heat",
18628
+ "cool",
18629
+ "auto",
18630
+ "heat_cool",
18631
+ "fan_only",
18632
+ "dry"
18633
+ ],
18634
+ commandCaps: ["climate-control"]
18301
18635
  })
18302
18636
  ];
18303
18637
  function actuator(input) {
18304
18638
  return {
18305
- ...input,
18639
+ id: input.id,
18640
+ summary: input.summary,
18641
+ deviceType: input.deviceType,
18642
+ outputCap: input.outputCap,
18643
+ outputField: input.outputField,
18644
+ commandCaps: input.commandCaps,
18306
18645
  family: "actuator",
18307
18646
  role: void 0,
18308
18647
  memberDeviceType: input.deviceType,
18309
- outputField: "on",
18648
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
18649
+ activeWhen: input.activeWhen,
18310
18650
  quantity: "none",
18311
18651
  baseUnit: void 0,
18312
18652
  aggregates: BINARY_AGGREGATES,
18313
18653
  defaultAggregate: "any",
18314
18654
  empty: "offline",
18315
- accept: [{
18316
- cap: "switch",
18317
- fieldPath: "on"
18318
- }],
18655
+ accept: [input.member],
18319
18656
  companions: [CHANGED]
18320
18657
  };
18321
18658
  }
18322
18659
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
18323
18660
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
18661
+ DeviceType.Camera;
18324
18662
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
18325
18663
  /**
18326
18664
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -43335,7 +43673,7 @@ var NetworkAccessStatusSchema = object({
43335
43673
  });
43336
43674
  /**
43337
43675
  * Optional, richer endpoint shape returned by providers that expose
43338
- * MORE than one ingress concurrently (Tailscale Ingress with mixed
43676
+ * MORE than one ingress concurrently (Tailscale Funnel with mixed
43339
43677
  * serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
43340
43678
  * the originating provider config (mode + sourcePort) so the
43341
43679
  * orchestrator UI can label rows distinctly. Providers that expose only
@@ -45978,7 +46316,20 @@ var NcRuleInputSchema = object({
45978
46316
  * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
45979
46317
  * path does not run Zod defaults.
45980
46318
  */
45981
- groupingSec: number().int().min(5).max(60).optional()
46319
+ groupingSec: number().int().min(5).max(60).optional(),
46320
+ /**
46321
+ * ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
46322
+ * carries "Correct" / "Wrong" buttons (and, where the channel has room, a
46323
+ * "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
46324
+ * same mark the Library writes, and records whose notification it was and
46325
+ * when. A channel with no buttons gets the same two choices as links.
46326
+ *
46327
+ * `.optional()`, never `.default()` (a Zod default does not run on the addon
46328
+ * cap path): absent and `false` both mean off, which is what every rule
46329
+ * authored before this field meant. An editor turns it off by writing
46330
+ * `false`, so it needs no `clear` key.
46331
+ */
46332
+ askVerdict: boolean().optional()
45982
46333
  });
45983
46334
  /**
45984
46335
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -56448,7 +56799,7 @@ var BatteryStatusSchema = object({
56448
56799
  */
56449
56800
  binary: boolean().optional().meta({ label: "Binary indicator" })
56450
56801
  });
56451
- DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
56802
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
56452
56803
  method(object({
56453
56804
  deviceId: number(),
56454
56805
  /** Bound on the wait. Sensible range 3000–10000ms. */
@@ -58192,7 +58543,13 @@ results: array(object({
58192
58543
  /** Ms epoch of the attempt. */
58193
58544
  at: number()
58194
58545
  })) });
58195
- DeviceType.Switch, DeviceType.Light;
58546
+ DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58547
+ object({
58548
+ active: boolean().meta({ label: "Active" }),
58549
+ /** Ms epoch when the slice was last updated. */
58550
+ lastChangedAt: number()
58551
+ });
58552
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
58196
58553
  object({
58197
58554
  /** Members whose current value entered the aggregate. */
58198
58555
  included: number().int().nonnegative().meta(readingMeta("count", {
@@ -58210,7 +58567,7 @@ object({
58210
58567
  label: "Members"
58211
58568
  }))
58212
58569
  });
58213
- DeviceType.Sensor, DeviceType.Switch, DeviceType.Light;
58570
+ DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58214
58571
  object({
58215
58572
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
58216
58573
  position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -59117,7 +59474,14 @@ DeviceType.Lock, method(object({
59117
59474
  auth: "protected"
59118
59475
  }), method(object({
59119
59476
  deviceId: number().int().nonnegative(),
59120
- code: string().min(1).optional()
59477
+ code: string().min(1).optional(),
59478
+ /**
59479
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
59480
+ * with one call is refused unless the caller says it was confirmed. A
59481
+ * single lock ignores it. The refusal lives in the callee, so no
59482
+ * automation or API caller reaches the doors by skipping a dialog.
59483
+ */
59484
+ confirm: boolean().optional()
59121
59485
  }), _void(), {
59122
59486
  kind: "mutation",
59123
59487
  auth: "protected"
@@ -59125,6 +59489,11 @@ DeviceType.Lock, method(object({
59125
59489
  kind: "mutation",
59126
59490
  auth: "protected"
59127
59491
  });
59492
+ object({
59493
+ value: number().nullable().meta(readingMeta("device", { label: "Total" })),
59494
+ lastFetchedAt: number()
59495
+ });
59496
+ DeviceType.Sensor;
59128
59497
  /**
59129
59498
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
59130
59499
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
@@ -61032,9 +61401,9 @@ object({
61032
61401
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
61033
61402
  kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
61034
61403
  /** Voltage in volts. */
61035
- volts: number().optional().meta(readingMeta("voltage")),
61404
+ volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
61036
61405
  /** Current in amperes. */
61037
- amps: number().optional().meta(readingMeta("current")),
61406
+ amps: number().optional().meta(readingMeta("current", { label: "Current" })),
61038
61407
  /** Apparent power in volt-amperes. */
61039
61408
  va: number().optional().meta(readingMeta("apparent-power")),
61040
61409
  /** Power factor (0..1) if reported. */
@@ -61042,7 +61411,23 @@ object({
61042
61411
  /** Ms epoch when the slice was last updated. */
61043
61412
  lastFetchedAt: number()
61044
61413
  });
61045
- DeviceType.Sensor;
61414
+ [
61415
+ DeviceType.Sensor,
61416
+ DeviceType.Switch,
61417
+ DeviceType.Light,
61418
+ DeviceType.Fan,
61419
+ DeviceType.Climate,
61420
+ DeviceType.Thermostat,
61421
+ DeviceType.Humidifier,
61422
+ DeviceType.WaterHeater,
61423
+ DeviceType.MediaPlayer,
61424
+ DeviceType.Washer,
61425
+ DeviceType.Dryer,
61426
+ DeviceType.Dishwasher,
61427
+ DeviceType.Vacuum,
61428
+ DeviceType.LawnMower,
61429
+ DeviceType.PetFeeder
61430
+ ].filter((type) => type !== DeviceType.Sensor);
61046
61431
  /**
61047
61432
  * Presence cap. Models HA `person.*` and `device_tracker.*` entities
61048
61433
  * on `DeviceType.Presence`. Read-only — no setters: presence is
@@ -61489,7 +61874,7 @@ object({
61489
61874
  phase: string().nullable()
61490
61875
  });
61491
61876
  Object.values(DeviceType);
61492
- DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
61877
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
61493
61878
  DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
61494
61879
  kind: "mutation",
61495
61880
  auth: "admin"
@@ -63528,7 +63913,7 @@ object({
63528
63913
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
63529
63914
  lastChangedAt: number()
63530
63915
  });
63531
- DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
63916
+ DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
63532
63917
  deviceId: number(),
63533
63918
  on: boolean()
63534
63919
  }), _void(), {
@@ -65220,8 +65605,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
65220
65605
  kind: "mutation",
65221
65606
  auth: "admin"
65222
65607
  });
65608
+ DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
65223
65609
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
65224
- 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;
65610
+ 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;
65225
65611
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
65226
65612
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
65227
65613
  new Set(CAP_NAMES);
@@ -65274,7 +65660,7 @@ var AccessoryKind = {
65274
65660
  PrivacyMask: DeviceRole.PrivacyMask
65275
65661
  };
65276
65662
  AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
65277
- 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;
65663
+ 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;
65278
65664
  new Set(Object.values(DeviceType));
65279
65665
  Object.freeze({
65280
65666
  "accessories.getStatus": {
@@ -68497,6 +68883,13 @@ Object.freeze({
68497
68883
  access: "view",
68498
68884
  role: "viewer"
68499
68885
  },
68886
+ "groupActive.getStatus": {
68887
+ capName: "group-active",
68888
+ capScope: "device",
68889
+ addonId: null,
68890
+ access: "view",
68891
+ role: "viewer"
68892
+ },
68500
68893
  "groupCommands.getStatus": {
68501
68894
  capName: "group-commands",
68502
68895
  capScope: "device",
@@ -69463,6 +69856,13 @@ Object.freeze({
69463
69856
  access: "create",
69464
69857
  role: "admin"
69465
69858
  },
69859
+ "meter.getStatus": {
69860
+ capName: "meter",
69861
+ capScope: "device",
69862
+ addonId: null,
69863
+ access: "view",
69864
+ role: "viewer"
69865
+ },
69466
69866
  "metricsProvider.collectSnapshot": {
69467
69867
  capName: "metrics-provider",
69468
69868
  capScope: "system",
@@ -77561,7 +77961,39 @@ var APPLIANCE_CAP_VOCABULARY = {
77561
77961
  phrase: t("When {device} finishes", "Quando {device} finisce"),
77562
77962
  icon: "square"
77563
77963
  }
77564
- }
77964
+ },
77965
+ overrides: { byType: {
77966
+ [DeviceType.Washer]: {
77967
+ state: { running: {
77968
+ whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
77969
+ whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
77970
+ } },
77971
+ events: {
77972
+ onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
77973
+ onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
77974
+ }
77975
+ },
77976
+ [DeviceType.Dryer]: {
77977
+ state: { running: {
77978
+ whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
77979
+ whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
77980
+ } },
77981
+ events: {
77982
+ onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
77983
+ onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
77984
+ }
77985
+ },
77986
+ [DeviceType.Dishwasher]: {
77987
+ state: { running: {
77988
+ whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
77989
+ whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
77990
+ } },
77991
+ events: {
77992
+ onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
77993
+ onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
77994
+ }
77995
+ }
77996
+ } }
77565
77997
  },
77566
77998
  update: {
77567
77999
  scope: "device",
@@ -78333,6 +78765,10 @@ var SENSOR_CAP_VOCABULARY = {
78333
78765
  icon: "flame"
78334
78766
  }]
78335
78767
  },
78768
+ "group-active": {
78769
+ scope: "device",
78770
+ noun: t("Group state", "Stato del gruppo")
78771
+ },
78336
78772
  "group-commands": {
78337
78773
  scope: "device",
78338
78774
  noun: t("Group command", "Comando di gruppo")
@@ -78389,6 +78825,17 @@ var SENSOR_CAP_VOCABULARY = {
78389
78825
  }],
78390
78826
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
78391
78827
  },
78828
+ meter: {
78829
+ scope: "device",
78830
+ noun: t("Meter", "Contatore"),
78831
+ state: [{
78832
+ kind: "numeric",
78833
+ field: "value",
78834
+ quantity: t("the total", "il totale"),
78835
+ label: t("Total", "Totale"),
78836
+ icon: "gauge"
78837
+ }]
78838
+ },
78392
78839
  "numeric-sensor": {
78393
78840
  scope: "device",
78394
78841
  noun: t("Sensor", "Sensore"),
@@ -78861,8 +79308,47 @@ function projectAction(cap, action) {
78861
79308
  };
78862
79309
  }
78863
79310
  Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
78864
- 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;
79311
+ 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;
78865
79312
  DeviceFeature.BatteryOperated;
79313
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
79314
+ 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.";
79315
+ 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.";
79316
+ var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
79317
+ var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
79318
+ 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.";
79319
+ function withheld(reason) {
79320
+ return {
79321
+ [DeviceType.Washer]: {
79322
+ exported: false,
79323
+ reason
79324
+ },
79325
+ [DeviceType.Dryer]: {
79326
+ exported: false,
79327
+ reason
79328
+ },
79329
+ [DeviceType.Dishwasher]: {
79330
+ exported: false,
79331
+ reason
79332
+ }
79333
+ };
79334
+ }
79335
+ function offered(received) {
79336
+ return {
79337
+ [DeviceType.Washer]: {
79338
+ exported: true,
79339
+ as: received
79340
+ },
79341
+ [DeviceType.Dryer]: {
79342
+ exported: true,
79343
+ as: received
79344
+ },
79345
+ [DeviceType.Dishwasher]: {
79346
+ exported: true,
79347
+ as: received
79348
+ }
79349
+ };
79350
+ }
79351
+ offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
78866
79352
  Object.freeze({
78867
79353
  "accessories.getStatus": [{
78868
79354
  name: "deviceId",
@@ -79829,6 +80315,11 @@ Object.freeze({
79829
80315
  form: "single",
79830
80316
  optional: false
79831
80317
  }],
80318
+ "groupActive.getStatus": [{
80319
+ name: "deviceId",
80320
+ form: "single",
80321
+ optional: false
80322
+ }],
79832
80323
  "groupCommands.getStatus": [{
79833
80324
  name: "deviceId",
79834
80325
  form: "single",
@@ -80039,6 +80530,11 @@ Object.freeze({
80039
80530
  form: "single",
80040
80531
  optional: false
80041
80532
  }],
80533
+ "meter.getStatus": [{
80534
+ name: "deviceId",
80535
+ form: "single",
80536
+ optional: false
80537
+ }],
80042
80538
  "motion.getStatus": [{
80043
80539
  name: "deviceId",
80044
80540
  form: "single",
@@ -81646,7 +82142,6 @@ Object.freeze({
81646
82142
  "network-access": "ingress",
81647
82143
  "smtp-provider": "email"
81648
82144
  });
81649
- DeviceType.Camera;
81650
82145
  /**
81651
82146
  * A saved Customize assignment (D936). The schema is the type: callers use
81652
82147
  * `z.infer`, they do not restate the shape.