@camstack/addon-provider-onvif 1.2.149 → 1.2.150

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.
package/dist/addon.js CHANGED
@@ -5445,7 +5445,7 @@ var ZodIssueCode = {
5445
5445
  var ZodFirstPartyTypeKind;
5446
5446
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5447
5447
  //#endregion
5448
- //#region ../types/dist/sleep-bykKrTgu.mjs
5448
+ //#region ../types/dist/sleep--jXS9hWo.mjs
5449
5449
  /**
5450
5450
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5451
5451
  * window to float samples (D455).
@@ -8567,6 +8567,7 @@ var CAP_NAMES = Object.freeze([
8567
8567
  "filesystem-browse",
8568
8568
  "flood",
8569
8569
  "gas",
8570
+ "group-active",
8570
8571
  "group-commands",
8571
8572
  "group-status",
8572
8573
  "heating-valve",
@@ -8589,6 +8590,7 @@ var CAP_NAMES = Object.freeze([
8589
8590
  "login-method",
8590
8591
  "media-player",
8591
8592
  "mesh-network",
8593
+ "meter",
8592
8594
  "metrics-provider",
8593
8595
  "model-convert",
8594
8596
  "model-distributor",
@@ -9387,6 +9389,10 @@ Object.freeze({
9387
9389
  "path": "detected",
9388
9390
  "valueType": "boolean"
9389
9391
  }],
9392
+ "group-active": [{
9393
+ "path": "active",
9394
+ "valueType": "boolean"
9395
+ }],
9390
9396
  "group-status": [
9391
9397
  {
9392
9398
  "path": "included",
@@ -9646,6 +9652,10 @@ Object.freeze({
9646
9652
  ]
9647
9653
  }
9648
9654
  ],
9655
+ "meter": [{
9656
+ "path": "value",
9657
+ "valueType": "number"
9658
+ }],
9649
9659
  "motion": [
9650
9660
  {
9651
9661
  "path": "detected",
@@ -10389,7 +10399,7 @@ object({
10389
10399
  params: record(string(), union([string(), number()])).optional()
10390
10400
  });
10391
10401
  //#endregion
10392
- //#region ../types/dist/err-msg-BXKzRBwg.mjs
10402
+ //#region ../types/dist/err-msg-DIorGYeC.mjs
10393
10403
  var DeviceType = /* @__PURE__ */ function(DeviceType) {
10394
10404
  DeviceType["Camera"] = "camera";
10395
10405
  DeviceType["Hub"] = "hub";
@@ -10483,8 +10493,14 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
10483
10493
  DeviceType["PetFeeder"] = "pet-feeder";
10484
10494
  /** Built-in dishwasher — program lifecycle, door / remote-start gates,
10485
10495
  * salt and rinse-aid levels. Installed with the `dishwasher` cap.
10486
- * Sources: native Bosch Home Connect, reusable by similar integrations. */
10496
+ * Sources: native Bosch Home Connect, reusable by similar integrations.
10497
+ * A plug-built dishwasher carries running-state and power instead. */
10487
10498
  DeviceType["Dishwasher"] = "dishwasher";
10499
+ /** Washing machine. A plug-built one is running while its power stays
10500
+ * above a threshold. No program cap — that surface is the dishwasher's. */
10501
+ DeviceType["Washer"] = "washer";
10502
+ /** Tumble dryer. Same plug-built running surface as {@link Washer}. */
10503
+ DeviceType["Dryer"] = "dryer";
10488
10504
  return DeviceType;
10489
10505
  }({});
10490
10506
  var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
@@ -10742,7 +10758,7 @@ function errMsg(err) {
10742
10758
  return String(err);
10743
10759
  }
10744
10760
  //#endregion
10745
- //#region ../types/dist/composition-OhpuespA.mjs
10761
+ //#region ../types/dist/composition-Bb8iwHEJ.mjs
10746
10762
  /**
10747
10763
  * The ffmpeg build every CamStack node downloads, per platform and arch.
10748
10764
  *
@@ -11057,6 +11073,13 @@ var table = {
11057
11073
  apply: () => {
11058
11074
  throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
11059
11075
  }
11076
+ },
11077
+ schmitt: {
11078
+ minArgs: 3,
11079
+ maxArgs: 5,
11080
+ apply: () => {
11081
+ throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
11082
+ }
11060
11083
  }
11061
11084
  };
11062
11085
  Object.freeze(Object.assign(Object.create(null), table));
@@ -11498,6 +11521,99 @@ function validateExpressionSource(src) {
11498
11521
  return null;
11499
11522
  }
11500
11523
  /**
11524
+ * One power reading becomes a washer, dryer or dishwasher (D944 helper).
11525
+ *
11526
+ * Standby of the control board is under 5 W; a motor or a heater is far
11527
+ * above that, so 5 W is the line. A door lock or a short pump spike is not
11528
+ * a cycle, so running starts only after 30 s above the line.
11529
+ *
11530
+ * A wash, dry or dishwasher pause (soak, heat-wait, heater off between
11531
+ * bursts) lasts several minutes. Ending the cycle on the first dip would
11532
+ * report "finished" in the middle of the program, so the stop dwell is
11533
+ * 10 minutes on every type. The number is stored per type so one machine
11534
+ * can move later without moving the others.
11535
+ */
11536
+ var APPLIANCE_TEMPLATE_ID = "appliance";
11537
+ var APPLIANCE_KINDS = [
11538
+ "washer",
11539
+ "dryer",
11540
+ "dishwasher"
11541
+ ];
11542
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
11543
+ /**
11544
+ * Statistics and integrals over a history read (D944).
11545
+ *
11546
+ * Pure: the same points always give the same answer, so a restart recomputes
11547
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
11548
+ * never the mean of the samples. A hole with no held value is not integrated
11549
+ * as zero. A truncated read is not published.
11550
+ */
11551
+ var STATISTIC_STATS = [
11552
+ "min",
11553
+ "max",
11554
+ "mean",
11555
+ "sum",
11556
+ "count",
11557
+ "change"
11558
+ ];
11559
+ /**
11560
+ * The range a statistics or integral helper asks history for (D944).
11561
+ *
11562
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
11563
+ * or 25 hours across a DST change. A tier is eligible only when its retention
11564
+ * is strictly longer than the longest that range can be. Forever qualifies.
11565
+ * Equal to a tier's retention is a refusal, not a short answer.
11566
+ */
11567
+ var MINUTE_MS = 6e4;
11568
+ var HOUR_MS = 60 * MINUTE_MS;
11569
+ var DAY_MS = 24 * HOUR_MS;
11570
+ var ROLLING_SPANS = [
11571
+ "1h",
11572
+ "24h",
11573
+ "2d",
11574
+ "7d",
11575
+ "30d",
11576
+ "custom"
11577
+ ];
11578
+ var CALENDAR_PERIODS = [
11579
+ "today",
11580
+ "yesterday",
11581
+ "this-week",
11582
+ "this-month"
11583
+ ];
11584
+ var RESET_PERIODS = [
11585
+ "never",
11586
+ "daily",
11587
+ "weekly",
11588
+ "monthly"
11589
+ ];
11590
+ 5 * MINUTE_MS;
11591
+ 24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
11592
+ 7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
11593
+ var rollingWindowObject = object({
11594
+ kind: literal("rolling"),
11595
+ span: _enum(ROLLING_SPANS),
11596
+ customMinutes: number().int().min(5).optional()
11597
+ }).check((payload) => {
11598
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
11599
+ code: "custom",
11600
+ message: "a custom range needs a duration in minutes",
11601
+ path: ["customMinutes"],
11602
+ input: payload.value
11603
+ });
11604
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
11605
+ code: "custom",
11606
+ message: "only a custom range carries a duration",
11607
+ path: ["customMinutes"],
11608
+ input: payload.value
11609
+ });
11610
+ });
11611
+ var RollingWindowSchema = rollingWindowObject;
11612
+ var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
11613
+ kind: literal("calendar"),
11614
+ period: _enum(CALENDAR_PERIODS)
11615
+ })]);
11616
+ /**
11501
11617
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11502
11618
  * id. Split out so helper schemas can name it without a cycle through
11503
11619
  * `composition.ts` (D659).
@@ -11523,7 +11639,13 @@ var GROUP_TEMPLATE_IDS = [
11523
11639
  "occupancy",
11524
11640
  "binary",
11525
11641
  "switch",
11526
- "light"
11642
+ "light",
11643
+ "fan",
11644
+ "cover",
11645
+ "valve",
11646
+ "lock",
11647
+ "media-player",
11648
+ "climate"
11527
11649
  ];
11528
11650
  var NUMERIC_AGGREGATES = [
11529
11651
  "mean",
@@ -11553,14 +11675,73 @@ var HelperMemberSchema = object({
11553
11675
  cap: string().min(1),
11554
11676
  fieldPath: string().min(1)
11555
11677
  });
11556
- var HelperSpecSchema = discriminatedUnion("kind", [object({
11557
- kind: literal("group"),
11558
- templateId: GroupTemplateIdSchema,
11559
- aggregate: AggregateReducerSchema,
11560
- members: array(HelperMemberSchema).min(1).max(64),
11561
- /** Actuator groups only. Readings leave this unset. */
11562
- active: ActiveCriterionSchema.optional()
11563
- })]);
11678
+ var HelperSpecSchema = discriminatedUnion("kind", [
11679
+ object({
11680
+ kind: literal("group"),
11681
+ templateId: GroupTemplateIdSchema,
11682
+ aggregate: AggregateReducerSchema,
11683
+ members: array(HelperMemberSchema).min(1).max(64),
11684
+ /** Actuator groups only. Readings leave this unset. */
11685
+ active: ActiveCriterionSchema.optional()
11686
+ }),
11687
+ object({
11688
+ kind: literal("appliance"),
11689
+ templateId: literal(APPLIANCE_TEMPLATE_ID),
11690
+ appliance: _enum(APPLIANCE_KINDS),
11691
+ thresholdWatts: number().positive(),
11692
+ startDwellMs: number().int().nonnegative(),
11693
+ stopDwellMs: number().int().nonnegative(),
11694
+ member: HelperMemberSchema
11695
+ }),
11696
+ object({
11697
+ kind: literal("statistic"),
11698
+ stat: _enum(STATISTIC_STATS),
11699
+ window: StatisticWindowSchema,
11700
+ source: HelperMemberSchema
11701
+ }),
11702
+ object({
11703
+ kind: literal("integral"),
11704
+ reset: _enum(RESET_PERIODS),
11705
+ output: _enum(["energy", "meter"]),
11706
+ source: HelperMemberSchema
11707
+ }),
11708
+ object({
11709
+ kind: literal("threshold"),
11710
+ source: HelperMemberSchema,
11711
+ high: number(),
11712
+ low: number(),
11713
+ onForMs: number().int().nonnegative(),
11714
+ offForMs: number().int().nonnegative()
11715
+ }),
11716
+ object({
11717
+ kind: literal("arithmetic"),
11718
+ op: _enum([
11719
+ "sum",
11720
+ "difference",
11721
+ "ratio"
11722
+ ]),
11723
+ inputs: array(HelperMemberSchema).min(2).max(64)
11724
+ }),
11725
+ object({
11726
+ kind: literal("expression"),
11727
+ expr: string().min(1),
11728
+ inputs: array(object({
11729
+ name: string().min(1),
11730
+ member: HelperMemberSchema
11731
+ })).min(1).max(64),
11732
+ output: _enum(["number", "boolean"])
11733
+ }),
11734
+ object({
11735
+ kind: literal("derivative"),
11736
+ window: RollingWindowSchema,
11737
+ per: _enum([
11738
+ "second",
11739
+ "minute",
11740
+ "hour"
11741
+ ]),
11742
+ source: HelperMemberSchema
11743
+ })
11744
+ ]);
11564
11745
  /** A composed device's stableId is this prefix plus the block id. */
11565
11746
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
11566
11747
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -11621,6 +11802,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
11621
11802
  "all"
11622
11803
  ]),
11623
11804
  reads: array(CompositionFieldReadSchema).min(1).max(64),
11805
+ /**
11806
+ * Set when the reads are an enum state, not a yes/no: the listed states
11807
+ * count as active (a cover is `open`). A state outside the list is inactive;
11808
+ * a read that is not a state at all is left out. Only `any` / `all` use it.
11809
+ */
11810
+ activeWhen: array(string().min(1)).min(1).optional(),
11624
11811
  /** `value` is the reading; the others are the member counts. */
11625
11812
  publish: _enum([
11626
11813
  "value",
@@ -11634,6 +11821,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
11634
11821
  "omit",
11635
11822
  "offline"
11636
11823
  ])
11824
+ }),
11825
+ object({
11826
+ kind: literal("series"),
11827
+ read: CompositionFieldReadSchema,
11828
+ /** `value` is the statistic or the integral. The others are the gap counts. */
11829
+ publish: _enum([
11830
+ "value",
11831
+ "included",
11832
+ "excluded",
11833
+ "total"
11834
+ ]),
11835
+ /**
11836
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
11837
+ * device unseeded until history answers, so a restart cannot publish 0.
11838
+ */
11839
+ empty: _enum([
11840
+ "null",
11841
+ "omit",
11842
+ "offline"
11843
+ ])
11637
11844
  })
11638
11845
  ]);
11639
11846
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -16793,7 +17000,22 @@ var BrokerProviderInfoSchema = object({
16793
17000
  */
16794
17001
  interactiveConnectPath: string().min(1).optional(),
16795
17002
  /** Relative hub path to disconnect the linked account (same popup pattern). */
16796
- interactiveDisconnectPath: string().min(1).optional()
17003
+ interactiveDisconnectPath: string().min(1).optional(),
17004
+ /**
17005
+ * The kind signs in through a server-held interactive session instead of
17006
+ * (or before) typed credentials. `basePath` is a hub-relative route set
17007
+ * served by the owning addon (`/addon/<id>/...`) speaking the sign-in
17008
+ * contract: `POST {basePath}/start` (body: the form's settings) answers
17009
+ * `{ sessionId, loginUrl }`; `GET {basePath}/status?sessionId=` answers
17010
+ * `{ phase: 'starting' | 'awaiting-login' | 'captured' | 'error' |
17011
+ * 'cancelled', loginUrl, error }`; `POST {basePath}/commit`
17012
+ * (`{ sessionId, name, brokerId? }`) stores the credentials on a new or
17013
+ * existing broker and answers `{ brokerId }`; `POST {basePath}/cancel`
17014
+ * (`{ sessionId }`) drops the session. The dialog that edits a broker
17015
+ * offers it as the default path; the fields the session fills are
17016
+ * marked `filledBySignIn` in the kind's settings schema.
17017
+ */
17018
+ signIn: object({ basePath: string().min(1) }).optional()
16797
17019
  }))
16798
17020
  });
16799
17021
  var ListInputSchema = object({
@@ -17792,7 +18014,8 @@ var CompositionProblemSchema = object({
17792
18014
  "native-capability-replace",
17793
18015
  "mixed-quantity",
17794
18016
  "helper-mismatch",
17795
- "member-constraint"
18017
+ "member-constraint",
18018
+ "retention"
17796
18019
  ]),
17797
18020
  path: string(),
17798
18021
  message: string()
@@ -18026,13 +18249,17 @@ Object.freeze({
18026
18249
  latchedAt: {
18027
18250
  kind: "fixed",
18028
18251
  result: ["number", "null"]
18252
+ },
18253
+ schmitt: {
18254
+ kind: "fixed",
18255
+ result: ["boolean", "null"]
18029
18256
  }
18030
18257
  });
18031
18258
  /**
18032
18259
  * One catalog row per base reading a group helper can build (D944 §3).
18033
18260
  * Data, not a form default written into the block.
18034
18261
  */
18035
- var NOW = {
18262
+ var NOW$2 = {
18036
18263
  fieldPath: "lastFetchedAt",
18037
18264
  expr: "now"
18038
18265
  };
@@ -18046,6 +18273,8 @@ function numeric(input) {
18046
18273
  family: "numeric",
18047
18274
  deviceType: DeviceType.Sensor,
18048
18275
  memberDeviceType: DeviceType.Sensor,
18276
+ memberDeviceTypes: [DeviceType.Sensor],
18277
+ activeWhen: void 0,
18049
18278
  commandCaps: [],
18050
18279
  baseUnit: baseUnitOf(input.quantity),
18051
18280
  aggregates: NUMERIC_AGGREGATES,
@@ -18061,6 +18290,8 @@ function binary(input) {
18061
18290
  family: "binary",
18062
18291
  deviceType: DeviceType.Sensor,
18063
18292
  memberDeviceType: DeviceType.Sensor,
18293
+ memberDeviceTypes: [DeviceType.Sensor],
18294
+ activeWhen: void 0,
18064
18295
  commandCaps: [],
18065
18296
  quantity: "none",
18066
18297
  baseUnit: void 0,
@@ -18078,7 +18309,7 @@ var GROUP_TEMPLATES = [
18078
18309
  quantity: "temperature",
18079
18310
  defaultAggregate: "mean",
18080
18311
  empty: "null",
18081
- companions: [NOW]
18312
+ companions: [NOW$2]
18082
18313
  }),
18083
18314
  numeric({
18084
18315
  id: "humidity",
@@ -18089,7 +18320,7 @@ var GROUP_TEMPLATES = [
18089
18320
  quantity: "humidity",
18090
18321
  defaultAggregate: "mean",
18091
18322
  empty: "null",
18092
- companions: [NOW]
18323
+ companions: [NOW$2]
18093
18324
  }),
18094
18325
  numeric({
18095
18326
  id: "pressure",
@@ -18100,7 +18331,7 @@ var GROUP_TEMPLATES = [
18100
18331
  quantity: "pressure",
18101
18332
  defaultAggregate: "mean",
18102
18333
  empty: "null",
18103
- companions: [NOW]
18334
+ companions: [NOW$2]
18104
18335
  }),
18105
18336
  numeric({
18106
18337
  id: "illuminance",
@@ -18111,7 +18342,7 @@ var GROUP_TEMPLATES = [
18111
18342
  quantity: "illuminance",
18112
18343
  defaultAggregate: "mean",
18113
18344
  empty: "null",
18114
- companions: [NOW]
18345
+ companions: [NOW$2]
18115
18346
  }),
18116
18347
  numeric({
18117
18348
  id: "power",
@@ -18122,7 +18353,7 @@ var GROUP_TEMPLATES = [
18122
18353
  quantity: "power",
18123
18354
  defaultAggregate: "sum",
18124
18355
  empty: "omit",
18125
- companions: [NOW]
18356
+ companions: [NOW$2]
18126
18357
  }),
18127
18358
  numeric({
18128
18359
  id: "energy",
@@ -18133,7 +18364,7 @@ var GROUP_TEMPLATES = [
18133
18364
  quantity: "energy",
18134
18365
  defaultAggregate: "sum",
18135
18366
  empty: "omit",
18136
- companions: [NOW]
18367
+ companions: [NOW$2]
18137
18368
  }),
18138
18369
  numeric({
18139
18370
  id: "battery",
@@ -18168,7 +18399,7 @@ var GROUP_TEMPLATES = [
18168
18399
  quantity: "device",
18169
18400
  defaultAggregate: "mean",
18170
18401
  empty: "null",
18171
- companions: [NOW]
18402
+ companions: [NOW$2]
18172
18403
  }),
18173
18404
  binary({
18174
18405
  id: "motion",
@@ -18262,6 +18493,11 @@ var GROUP_TEMPLATES = [
18262
18493
  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.",
18263
18494
  deviceType: DeviceType.Switch,
18264
18495
  outputCap: "switch",
18496
+ outputField: "on",
18497
+ member: {
18498
+ cap: "switch",
18499
+ fieldPath: "on"
18500
+ },
18265
18501
  commandCaps: ["switch"]
18266
18502
  }),
18267
18503
  actuator({
@@ -18269,34 +18505,136 @@ var GROUP_TEMPLATES = [
18269
18505
  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.",
18270
18506
  deviceType: DeviceType.Light,
18271
18507
  outputCap: "switch",
18508
+ outputField: "on",
18509
+ member: {
18510
+ cap: "switch",
18511
+ fieldPath: "on"
18512
+ },
18272
18513
  commandCaps: [
18273
18514
  "switch",
18274
18515
  "brightness",
18275
18516
  "color"
18276
18517
  ]
18518
+ }),
18519
+ actuator({
18520
+ id: "fan",
18521
+ 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.",
18522
+ deviceType: DeviceType.Fan,
18523
+ outputCap: "switch",
18524
+ outputField: "on",
18525
+ member: {
18526
+ cap: "switch",
18527
+ fieldPath: "on"
18528
+ },
18529
+ commandCaps: ["switch", "fan-control"]
18530
+ }),
18531
+ actuator({
18532
+ id: "cover",
18533
+ 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.",
18534
+ deviceType: DeviceType.Cover,
18535
+ outputCap: "group-active",
18536
+ outputField: "active",
18537
+ member: {
18538
+ cap: "cover",
18539
+ fieldPath: "state"
18540
+ },
18541
+ activeWhen: [
18542
+ "open",
18543
+ "opening",
18544
+ "stopped"
18545
+ ],
18546
+ commandCaps: ["cover"]
18547
+ }),
18548
+ actuator({
18549
+ id: "valve",
18550
+ 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.",
18551
+ deviceType: DeviceType.Valve,
18552
+ outputCap: "group-active",
18553
+ outputField: "active",
18554
+ member: {
18555
+ cap: "valve",
18556
+ fieldPath: "state"
18557
+ },
18558
+ activeWhen: [
18559
+ "open",
18560
+ "opening",
18561
+ "stopped"
18562
+ ],
18563
+ commandCaps: ["valve"]
18564
+ }),
18565
+ actuator({
18566
+ id: "lock",
18567
+ 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.",
18568
+ deviceType: DeviceType.Lock,
18569
+ outputCap: "group-active",
18570
+ outputField: "active",
18571
+ member: {
18572
+ cap: "lock-control",
18573
+ fieldPath: "state"
18574
+ },
18575
+ activeWhen: ["locked"],
18576
+ commandCaps: ["lock-control"]
18577
+ }),
18578
+ actuator({
18579
+ id: "media-player",
18580
+ 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.",
18581
+ deviceType: DeviceType.MediaPlayer,
18582
+ outputCap: "group-active",
18583
+ outputField: "active",
18584
+ member: {
18585
+ cap: "media-player",
18586
+ fieldPath: "state"
18587
+ },
18588
+ activeWhen: ["playing", "buffering"],
18589
+ commandCaps: ["media-player"]
18590
+ }),
18591
+ actuator({
18592
+ id: "climate",
18593
+ 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.",
18594
+ deviceType: DeviceType.Thermostat,
18595
+ memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
18596
+ outputCap: "group-active",
18597
+ outputField: "active",
18598
+ member: {
18599
+ cap: "climate-control",
18600
+ fieldPath: "mode"
18601
+ },
18602
+ activeWhen: [
18603
+ "heat",
18604
+ "cool",
18605
+ "auto",
18606
+ "heat_cool",
18607
+ "fan_only",
18608
+ "dry"
18609
+ ],
18610
+ commandCaps: ["climate-control"]
18277
18611
  })
18278
18612
  ];
18279
18613
  function actuator(input) {
18280
18614
  return {
18281
- ...input,
18615
+ id: input.id,
18616
+ summary: input.summary,
18617
+ deviceType: input.deviceType,
18618
+ outputCap: input.outputCap,
18619
+ outputField: input.outputField,
18620
+ commandCaps: input.commandCaps,
18282
18621
  family: "actuator",
18283
18622
  role: void 0,
18284
18623
  memberDeviceType: input.deviceType,
18285
- outputField: "on",
18624
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
18625
+ activeWhen: input.activeWhen,
18286
18626
  quantity: "none",
18287
18627
  baseUnit: void 0,
18288
18628
  aggregates: BINARY_AGGREGATES,
18289
18629
  defaultAggregate: "any",
18290
18630
  empty: "offline",
18291
- accept: [{
18292
- cap: "switch",
18293
- fieldPath: "on"
18294
- }],
18631
+ accept: [input.member],
18295
18632
  companions: [CHANGED]
18296
18633
  };
18297
18634
  }
18298
18635
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
18299
18636
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
18637
+ DeviceType.Camera;
18300
18638
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
18301
18639
  /**
18302
18640
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -43505,7 +43843,7 @@ var NetworkAccessStatusSchema = object({
43505
43843
  });
43506
43844
  /**
43507
43845
  * Optional, richer endpoint shape returned by providers that expose
43508
- * MORE than one ingress concurrently (Tailscale Ingress with mixed
43846
+ * MORE than one ingress concurrently (Tailscale Funnel with mixed
43509
43847
  * serve+funnel rules, future ngrok multi-tunnel, …). Each entry carries
43510
43848
  * the originating provider config (mode + sourcePort) so the
43511
43849
  * orchestrator UI can label rows distinctly. Providers that expose only
@@ -46148,7 +46486,20 @@ var NcRuleInputSchema = object({
46148
46486
  * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
46149
46487
  * path does not run Zod defaults.
46150
46488
  */
46151
- groupingSec: number().int().min(5).max(60).optional()
46489
+ groupingSec: number().int().min(5).max(60).optional(),
46490
+ /**
46491
+ * ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
46492
+ * carries "Correct" / "Wrong" buttons (and, where the channel has room, a
46493
+ * "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
46494
+ * same mark the Library writes, and records whose notification it was and
46495
+ * when. A channel with no buttons gets the same two choices as links.
46496
+ *
46497
+ * `.optional()`, never `.default()` (a Zod default does not run on the addon
46498
+ * cap path): absent and `false` both mean off, which is what every rule
46499
+ * authored before this field meant. An editor turns it off by writing
46500
+ * `false`, so it needs no `clear` key.
46501
+ */
46502
+ askVerdict: boolean().optional()
46152
46503
  });
46153
46504
  /**
46154
46505
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -56709,7 +57060,7 @@ var BatteryStatusSchema = object({
56709
57060
  */
56710
57061
  binary: boolean().optional().meta({ label: "Binary indicator" })
56711
57062
  });
56712
- DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat;
57063
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter;
56713
57064
  method(object({
56714
57065
  deviceId: number(),
56715
57066
  /** Bound on the wait. Sensible range 3000–10000ms. */
@@ -58453,7 +58804,13 @@ results: array(object({
58453
58804
  /** Ms epoch of the attempt. */
58454
58805
  at: number()
58455
58806
  })) });
58456
- DeviceType.Switch, DeviceType.Light;
58807
+ DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58808
+ object({
58809
+ active: boolean().meta({ label: "Active" }),
58810
+ /** Ms epoch when the slice was last updated. */
58811
+ lastChangedAt: number()
58812
+ });
58813
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
58457
58814
  object({
58458
58815
  /** Members whose current value entered the aggregate. */
58459
58816
  included: number().int().nonnegative().meta(readingMeta("count", {
@@ -58471,7 +58828,7 @@ object({
58471
58828
  label: "Members"
58472
58829
  }))
58473
58830
  });
58474
- DeviceType.Sensor, DeviceType.Switch, DeviceType.Light;
58831
+ DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58475
58832
  object({
58476
58833
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
58477
58834
  position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -59378,7 +59735,14 @@ DeviceType.Lock, method(object({
59378
59735
  auth: "protected"
59379
59736
  }), method(object({
59380
59737
  deviceId: number().int().nonnegative(),
59381
- code: string().min(1).optional()
59738
+ code: string().min(1).optional(),
59739
+ /**
59740
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
59741
+ * with one call is refused unless the caller says it was confirmed. A
59742
+ * single lock ignores it. The refusal lives in the callee, so no
59743
+ * automation or API caller reaches the doors by skipping a dialog.
59744
+ */
59745
+ confirm: boolean().optional()
59382
59746
  }), _void(), {
59383
59747
  kind: "mutation",
59384
59748
  auth: "protected"
@@ -59386,6 +59750,11 @@ DeviceType.Lock, method(object({
59386
59750
  kind: "mutation",
59387
59751
  auth: "protected"
59388
59752
  });
59753
+ object({
59754
+ value: number().nullable().meta(readingMeta("device", { label: "Total" })),
59755
+ lastFetchedAt: number()
59756
+ });
59757
+ DeviceType.Sensor;
59389
59758
  /**
59390
59759
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
59391
59760
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
@@ -61293,9 +61662,9 @@ object({
61293
61662
  /** Cumulative energy in kilowatt-hours since the meter was reset. */
61294
61663
  kwhTotal: number().optional().meta(readingMeta("energy", { label: "Energy" })),
61295
61664
  /** Voltage in volts. */
61296
- volts: number().optional().meta(readingMeta("voltage")),
61665
+ volts: number().optional().meta(readingMeta("voltage", { label: "Voltage" })),
61297
61666
  /** Current in amperes. */
61298
- amps: number().optional().meta(readingMeta("current")),
61667
+ amps: number().optional().meta(readingMeta("current", { label: "Current" })),
61299
61668
  /** Apparent power in volt-amperes. */
61300
61669
  va: number().optional().meta(readingMeta("apparent-power")),
61301
61670
  /** Power factor (0..1) if reported. */
@@ -61303,7 +61672,23 @@ object({
61303
61672
  /** Ms epoch when the slice was last updated. */
61304
61673
  lastFetchedAt: number()
61305
61674
  });
61306
- DeviceType.Sensor;
61675
+ [
61676
+ DeviceType.Sensor,
61677
+ DeviceType.Switch,
61678
+ DeviceType.Light,
61679
+ DeviceType.Fan,
61680
+ DeviceType.Climate,
61681
+ DeviceType.Thermostat,
61682
+ DeviceType.Humidifier,
61683
+ DeviceType.WaterHeater,
61684
+ DeviceType.MediaPlayer,
61685
+ DeviceType.Washer,
61686
+ DeviceType.Dryer,
61687
+ DeviceType.Dishwasher,
61688
+ DeviceType.Vacuum,
61689
+ DeviceType.LawnMower,
61690
+ DeviceType.PetFeeder
61691
+ ].filter((type) => type !== DeviceType.Sensor);
61307
61692
  /**
61308
61693
  * Presence cap. Models HA `person.*` and `device_tracker.*` entities
61309
61694
  * on `DeviceType.Presence`. Read-only — no setters: presence is
@@ -61842,7 +62227,7 @@ object({
61842
62227
  phase: string().nullable()
61843
62228
  });
61844
62229
  Object.values(DeviceType);
61845
- DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
62230
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
61846
62231
  DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceId: number().int().nonnegative() }), object({ success: literal(true) }), {
61847
62232
  kind: "mutation",
61848
62233
  auth: "admin"
@@ -63881,7 +64266,7 @@ object({
63881
64266
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
63882
64267
  lastChangedAt: number()
63883
64268
  });
63884
- DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
64269
+ DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
63885
64270
  deviceId: number(),
63886
64271
  on: boolean()
63887
64272
  }), _void(), {
@@ -65573,8 +65958,9 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
65573
65958
  kind: "mutation",
65574
65959
  auth: "admin"
65575
65960
  });
65961
+ DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
65576
65962
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
65577
- 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;
65963
+ 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;
65578
65964
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
65579
65965
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
65580
65966
  new Set(CAP_NAMES);
@@ -66452,7 +66838,7 @@ var BaseDeviceProvider = class extends BaseAddon {
66452
66838
  return toDeviceSummary(device, this.addonId);
66453
66839
  }
66454
66840
  };
66455
- 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;
66841
+ 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;
66456
66842
  new Set(Object.values(DeviceType));
66457
66843
  Object.freeze({
66458
66844
  "accessories.getStatus": {
@@ -69675,6 +70061,13 @@ Object.freeze({
69675
70061
  access: "view",
69676
70062
  role: "viewer"
69677
70063
  },
70064
+ "groupActive.getStatus": {
70065
+ capName: "group-active",
70066
+ capScope: "device",
70067
+ addonId: null,
70068
+ access: "view",
70069
+ role: "viewer"
70070
+ },
69678
70071
  "groupCommands.getStatus": {
69679
70072
  capName: "group-commands",
69680
70073
  capScope: "device",
@@ -70641,6 +71034,13 @@ Object.freeze({
70641
71034
  access: "create",
70642
71035
  role: "admin"
70643
71036
  },
71037
+ "meter.getStatus": {
71038
+ capName: "meter",
71039
+ capScope: "device",
71040
+ addonId: null,
71041
+ access: "view",
71042
+ role: "viewer"
71043
+ },
70644
71044
  "metricsProvider.collectSnapshot": {
70645
71045
  capName: "metrics-provider",
70646
71046
  capScope: "system",
@@ -78739,7 +79139,39 @@ var APPLIANCE_CAP_VOCABULARY = {
78739
79139
  phrase: t("When {device} finishes", "Quando {device} finisce"),
78740
79140
  icon: "square"
78741
79141
  }
78742
- }
79142
+ },
79143
+ overrides: { byType: {
79144
+ [DeviceType.Washer]: {
79145
+ state: { running: {
79146
+ whenTrue: t("When the washing machine starts", "Quando la lavatrice inizia"),
79147
+ whenFalse: t("When the washing machine has finished", "Quando la lavatrice ha finito")
79148
+ } },
79149
+ events: {
79150
+ onStarted: { phrase: t("When the washing machine starts", "Quando la lavatrice inizia") },
79151
+ onFinished: { phrase: t("When the washing machine has finished", "Quando la lavatrice ha finito") }
79152
+ }
79153
+ },
79154
+ [DeviceType.Dryer]: {
79155
+ state: { running: {
79156
+ whenTrue: t("When the dryer starts", "Quando l'asciugatrice inizia"),
79157
+ whenFalse: t("When the dryer has finished", "Quando l'asciugatrice ha finito")
79158
+ } },
79159
+ events: {
79160
+ onStarted: { phrase: t("When the dryer starts", "Quando l'asciugatrice inizia") },
79161
+ onFinished: { phrase: t("When the dryer has finished", "Quando l'asciugatrice ha finito") }
79162
+ }
79163
+ },
79164
+ [DeviceType.Dishwasher]: {
79165
+ state: { running: {
79166
+ whenTrue: t("When the dishwasher starts", "Quando la lavastoviglie inizia"),
79167
+ whenFalse: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito")
79168
+ } },
79169
+ events: {
79170
+ onStarted: { phrase: t("When the dishwasher starts", "Quando la lavastoviglie inizia") },
79171
+ onFinished: { phrase: t("When the dishwasher has finished", "Quando la lavastoviglie ha finito") }
79172
+ }
79173
+ }
79174
+ } }
78743
79175
  },
78744
79176
  update: {
78745
79177
  scope: "device",
@@ -79511,6 +79943,10 @@ var SENSOR_CAP_VOCABULARY = {
79511
79943
  icon: "flame"
79512
79944
  }]
79513
79945
  },
79946
+ "group-active": {
79947
+ scope: "device",
79948
+ noun: t("Group state", "Stato del gruppo")
79949
+ },
79514
79950
  "group-commands": {
79515
79951
  scope: "device",
79516
79952
  noun: t("Group command", "Comando di gruppo")
@@ -79567,6 +80003,17 @@ var SENSOR_CAP_VOCABULARY = {
79567
80003
  }],
79568
80004
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
79569
80005
  },
80006
+ meter: {
80007
+ scope: "device",
80008
+ noun: t("Meter", "Contatore"),
80009
+ state: [{
80010
+ kind: "numeric",
80011
+ field: "value",
80012
+ quantity: t("the total", "il totale"),
80013
+ label: t("Total", "Totale"),
80014
+ icon: "gauge"
80015
+ }]
80016
+ },
79570
80017
  "numeric-sensor": {
79571
80018
  scope: "device",
79572
80019
  noun: t("Sensor", "Sensore"),
@@ -80039,8 +80486,47 @@ function projectAction(cap, action) {
80039
80486
  };
80040
80487
  }
80041
80488
  Object.entries(CAP_VOCABULARY_BY_NAME).flatMap(([cap, entry]) => entry.scope === "device" ? (entry.actions ?? []).map((a) => projectAction(cap, a)) : []);
80042
- 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;
80489
+ 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;
80043
80490
  DeviceFeature.BatteryOperated;
80491
+ DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
80492
+ 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.";
80493
+ 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.";
80494
+ var ALEXA_REASON = "Alexa has no laundry category in this export, and neither power nor running has an Alexa interface.";
80495
+ var GOOGLE_REASON = "Google WASHER, DRYER and DISHWASHER require RunCycle. A power threshold is not that trait, and this export does not publish RunCycle.";
80496
+ 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.";
80497
+ function withheld(reason) {
80498
+ return {
80499
+ [DeviceType.Washer]: {
80500
+ exported: false,
80501
+ reason
80502
+ },
80503
+ [DeviceType.Dryer]: {
80504
+ exported: false,
80505
+ reason
80506
+ },
80507
+ [DeviceType.Dishwasher]: {
80508
+ exported: false,
80509
+ reason
80510
+ }
80511
+ };
80512
+ }
80513
+ function offered(received) {
80514
+ return {
80515
+ [DeviceType.Washer]: {
80516
+ exported: true,
80517
+ as: received
80518
+ },
80519
+ [DeviceType.Dryer]: {
80520
+ exported: true,
80521
+ as: received
80522
+ },
80523
+ [DeviceType.Dishwasher]: {
80524
+ exported: true,
80525
+ as: received
80526
+ }
80527
+ };
80528
+ }
80529
+ offered(HA_AS), withheld(HOMEKIT_REASON), withheld(ALEXA_REASON), withheld(GOOGLE_REASON), withheld(MATTER_REASON);
80044
80530
  /** Reject after `ms`; always clears its own timer. */
80045
80531
  async function withTimeout$1(promise, ms, label) {
80046
80532
  let timer;
@@ -81073,6 +81559,11 @@ Object.freeze({
81073
81559
  form: "single",
81074
81560
  optional: false
81075
81561
  }],
81562
+ "groupActive.getStatus": [{
81563
+ name: "deviceId",
81564
+ form: "single",
81565
+ optional: false
81566
+ }],
81076
81567
  "groupCommands.getStatus": [{
81077
81568
  name: "deviceId",
81078
81569
  form: "single",
@@ -81283,6 +81774,11 @@ Object.freeze({
81283
81774
  form: "single",
81284
81775
  optional: false
81285
81776
  }],
81777
+ "meter.getStatus": [{
81778
+ name: "deviceId",
81779
+ form: "single",
81780
+ optional: false
81781
+ }],
81286
81782
  "motion.getStatus": [{
81287
81783
  name: "deviceId",
81288
81784
  form: "single",
@@ -82890,7 +83386,6 @@ Object.freeze({
82890
83386
  "network-access": "ingress",
82891
83387
  "smtp-provider": "email"
82892
83388
  });
82893
- DeviceType.Camera;
82894
83389
  /**
82895
83390
  * A saved Customize assignment (D936). The schema is the type: callers use
82896
83391
  * `z.infer`, they do not restate the shape.