@camstack/addon-training 0.1.90 → 0.1.92

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.
Files changed (20) hide show
  1. package/dist/{MotionZonesSettings-BmrNAOJO.mjs → MotionZonesSettings-Cli21_S4.mjs} +2 -2
  2. package/dist/{PrivacyMaskSettings-BzPCdIdZ.mjs → PrivacyMaskSettings-BqMnLgR4.mjs} +2 -2
  3. package/dist/{SceneMonitorEditor-Xk84BCuE.mjs → SceneMonitorEditor-TOlMkkSx.mjs} +1 -1
  4. package/dist/_stub.js +18 -17
  5. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-Bc9jWFjH.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_training_page-Ki3rRnXi.mjs} +3 -3
  6. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-COkV6wxS.mjs +26 -0
  7. package/dist/{dist-BypcWIVo.mjs → dist-BLeIfxL-.mjs} +399 -40
  8. package/dist/{dist-CbnB8LuE.js → dist-BYGiAfO5.js} +399 -40
  9. package/dist/{hostInit-D4bIo0lR.mjs → hostInit-SSLNnzqp.mjs} +2 -2
  10. package/dist/index.js +1 -1
  11. package/dist/orchestrator/training.addon.js +1 -1
  12. package/dist/orchestrator/training.addon.mjs +1 -1
  13. package/dist/{player-overlays-CT4LlpcW.mjs → player-overlays-CpnLw8Tf.mjs} +1 -1
  14. package/dist/providers/modal/training-modal.addon.js +1 -1
  15. package/dist/providers/modal/training-modal.addon.mjs +1 -1
  16. package/dist/remoteEntry.js +1 -1
  17. package/dist/{responsive-Sb8JnuVU.mjs → responsive-wZ7jMF7F.mjs} +1 -1
  18. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-Cxqt93xt.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_training_page__remoteEntry_js-CG3LeBz1.mjs} +1 -1
  19. package/package.json +1 -1
  20. package/dist/_virtual_mf___mfe_internal__addon_training_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DZIdVQ_a.mjs +0 -26
@@ -5608,7 +5608,7 @@ var ZodIssueCode = {
5608
5608
  var ZodFirstPartyTypeKind;
5609
5609
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5610
5610
  //#endregion
5611
- //#region ../types/dist/sleep-bykKrTgu.mjs
5611
+ //#region ../types/dist/sleep--jXS9hWo.mjs
5612
5612
  /**
5613
5613
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5614
5614
  * window to float samples (D455).
@@ -8978,6 +8978,7 @@ var CAP_NAMES = Object.freeze([
8978
8978
  "filesystem-browse",
8979
8979
  "flood",
8980
8980
  "gas",
8981
+ "group-active",
8981
8982
  "group-commands",
8982
8983
  "group-status",
8983
8984
  "heating-valve",
@@ -9000,6 +9001,7 @@ var CAP_NAMES = Object.freeze([
9000
9001
  "login-method",
9001
9002
  "media-player",
9002
9003
  "mesh-network",
9004
+ "meter",
9003
9005
  "metrics-provider",
9004
9006
  "model-convert",
9005
9007
  "model-distributor",
@@ -9798,6 +9800,10 @@ Object.freeze({
9798
9800
  "path": "detected",
9799
9801
  "valueType": "boolean"
9800
9802
  }],
9803
+ "group-active": [{
9804
+ "path": "active",
9805
+ "valueType": "boolean"
9806
+ }],
9801
9807
  "group-status": [
9802
9808
  {
9803
9809
  "path": "included",
@@ -10057,6 +10063,10 @@ Object.freeze({
10057
10063
  ]
10058
10064
  }
10059
10065
  ],
10066
+ "meter": [{
10067
+ "path": "value",
10068
+ "valueType": "number"
10069
+ }],
10060
10070
  "motion": [
10061
10071
  {
10062
10072
  "path": "detected",
@@ -11149,7 +11159,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
11149
11159
  return DeviceRole;
11150
11160
  }({});
11151
11161
  //#endregion
11152
- //#region ../types/dist/composition-B2rw5L29.mjs
11162
+ //#region ../types/dist/composition-Bb8iwHEJ.mjs
11153
11163
  /**
11154
11164
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11155
11165
  *
@@ -11464,6 +11474,13 @@ var table = {
11464
11474
  apply: () => {
11465
11475
  throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
11466
11476
  }
11477
+ },
11478
+ schmitt: {
11479
+ minArgs: 3,
11480
+ maxArgs: 5,
11481
+ apply: () => {
11482
+ throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
11483
+ }
11467
11484
  }
11468
11485
  };
11469
11486
  Object.freeze(Object.assign(Object.create(null), table));
@@ -11925,6 +11942,79 @@ var APPLIANCE_KINDS = [
11925
11942
  ];
11926
11943
  DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
11927
11944
  /**
11945
+ * Statistics and integrals over a history read (D944).
11946
+ *
11947
+ * Pure: the same points always give the same answer, so a restart recomputes
11948
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
11949
+ * never the mean of the samples. A hole with no held value is not integrated
11950
+ * as zero. A truncated read is not published.
11951
+ */
11952
+ var STATISTIC_STATS = [
11953
+ "min",
11954
+ "max",
11955
+ "mean",
11956
+ "sum",
11957
+ "count",
11958
+ "change"
11959
+ ];
11960
+ /**
11961
+ * The range a statistics or integral helper asks history for (D944).
11962
+ *
11963
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
11964
+ * or 25 hours across a DST change. A tier is eligible only when its retention
11965
+ * is strictly longer than the longest that range can be. Forever qualifies.
11966
+ * Equal to a tier's retention is a refusal, not a short answer.
11967
+ */
11968
+ var MINUTE_MS = 6e4;
11969
+ var HOUR_MS = 60 * MINUTE_MS;
11970
+ var DAY_MS = 24 * HOUR_MS;
11971
+ var ROLLING_SPANS = [
11972
+ "1h",
11973
+ "24h",
11974
+ "2d",
11975
+ "7d",
11976
+ "30d",
11977
+ "custom"
11978
+ ];
11979
+ var CALENDAR_PERIODS = [
11980
+ "today",
11981
+ "yesterday",
11982
+ "this-week",
11983
+ "this-month"
11984
+ ];
11985
+ var RESET_PERIODS = [
11986
+ "never",
11987
+ "daily",
11988
+ "weekly",
11989
+ "monthly"
11990
+ ];
11991
+ 5 * MINUTE_MS;
11992
+ 24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
11993
+ 7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
11994
+ var rollingWindowObject = object({
11995
+ kind: literal("rolling"),
11996
+ span: _enum(ROLLING_SPANS),
11997
+ customMinutes: number().int().min(5).optional()
11998
+ }).check((payload) => {
11999
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
12000
+ code: "custom",
12001
+ message: "a custom range needs a duration in minutes",
12002
+ path: ["customMinutes"],
12003
+ input: payload.value
12004
+ });
12005
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
12006
+ code: "custom",
12007
+ message: "only a custom range carries a duration",
12008
+ path: ["customMinutes"],
12009
+ input: payload.value
12010
+ });
12011
+ });
12012
+ var RollingWindowSchema = rollingWindowObject;
12013
+ var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
12014
+ kind: literal("calendar"),
12015
+ period: _enum(CALENDAR_PERIODS)
12016
+ })]);
12017
+ /**
11928
12018
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11929
12019
  * id. Split out so helper schemas can name it without a cycle through
11930
12020
  * `composition.ts` (D659).
@@ -11950,7 +12040,13 @@ var GROUP_TEMPLATE_IDS = [
11950
12040
  "occupancy",
11951
12041
  "binary",
11952
12042
  "switch",
11953
- "light"
12043
+ "light",
12044
+ "fan",
12045
+ "cover",
12046
+ "valve",
12047
+ "lock",
12048
+ "media-player",
12049
+ "climate"
11954
12050
  ];
11955
12051
  var NUMERIC_AGGREGATES = [
11956
12052
  "mean",
@@ -11980,22 +12076,73 @@ var HelperMemberSchema = object({
11980
12076
  cap: string().min(1),
11981
12077
  fieldPath: string().min(1)
11982
12078
  });
11983
- var HelperSpecSchema = discriminatedUnion("kind", [object({
11984
- kind: literal("group"),
11985
- templateId: GroupTemplateIdSchema,
11986
- aggregate: AggregateReducerSchema,
11987
- members: array(HelperMemberSchema).min(1).max(64),
11988
- /** Actuator groups only. Readings leave this unset. */
11989
- active: ActiveCriterionSchema.optional()
11990
- }), object({
11991
- kind: literal("appliance"),
11992
- templateId: literal(APPLIANCE_TEMPLATE_ID),
11993
- appliance: _enum(APPLIANCE_KINDS),
11994
- thresholdWatts: number().positive(),
11995
- startDwellMs: number().int().nonnegative(),
11996
- stopDwellMs: number().int().nonnegative(),
11997
- member: HelperMemberSchema
11998
- })]);
12079
+ var HelperSpecSchema = discriminatedUnion("kind", [
12080
+ object({
12081
+ kind: literal("group"),
12082
+ templateId: GroupTemplateIdSchema,
12083
+ aggregate: AggregateReducerSchema,
12084
+ members: array(HelperMemberSchema).min(1).max(64),
12085
+ /** Actuator groups only. Readings leave this unset. */
12086
+ active: ActiveCriterionSchema.optional()
12087
+ }),
12088
+ object({
12089
+ kind: literal("appliance"),
12090
+ templateId: literal(APPLIANCE_TEMPLATE_ID),
12091
+ appliance: _enum(APPLIANCE_KINDS),
12092
+ thresholdWatts: number().positive(),
12093
+ startDwellMs: number().int().nonnegative(),
12094
+ stopDwellMs: number().int().nonnegative(),
12095
+ member: HelperMemberSchema
12096
+ }),
12097
+ object({
12098
+ kind: literal("statistic"),
12099
+ stat: _enum(STATISTIC_STATS),
12100
+ window: StatisticWindowSchema,
12101
+ source: HelperMemberSchema
12102
+ }),
12103
+ object({
12104
+ kind: literal("integral"),
12105
+ reset: _enum(RESET_PERIODS),
12106
+ output: _enum(["energy", "meter"]),
12107
+ source: HelperMemberSchema
12108
+ }),
12109
+ object({
12110
+ kind: literal("threshold"),
12111
+ source: HelperMemberSchema,
12112
+ high: number(),
12113
+ low: number(),
12114
+ onForMs: number().int().nonnegative(),
12115
+ offForMs: number().int().nonnegative()
12116
+ }),
12117
+ object({
12118
+ kind: literal("arithmetic"),
12119
+ op: _enum([
12120
+ "sum",
12121
+ "difference",
12122
+ "ratio"
12123
+ ]),
12124
+ inputs: array(HelperMemberSchema).min(2).max(64)
12125
+ }),
12126
+ object({
12127
+ kind: literal("expression"),
12128
+ expr: string().min(1),
12129
+ inputs: array(object({
12130
+ name: string().min(1),
12131
+ member: HelperMemberSchema
12132
+ })).min(1).max(64),
12133
+ output: _enum(["number", "boolean"])
12134
+ }),
12135
+ object({
12136
+ kind: literal("derivative"),
12137
+ window: RollingWindowSchema,
12138
+ per: _enum([
12139
+ "second",
12140
+ "minute",
12141
+ "hour"
12142
+ ]),
12143
+ source: HelperMemberSchema
12144
+ })
12145
+ ]);
11999
12146
  /** A composed device's stableId is this prefix plus the block id. */
12000
12147
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
12001
12148
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -12056,6 +12203,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12056
12203
  "all"
12057
12204
  ]),
12058
12205
  reads: array(CompositionFieldReadSchema).min(1).max(64),
12206
+ /**
12207
+ * Set when the reads are an enum state, not a yes/no: the listed states
12208
+ * count as active (a cover is `open`). A state outside the list is inactive;
12209
+ * a read that is not a state at all is left out. Only `any` / `all` use it.
12210
+ */
12211
+ activeWhen: array(string().min(1)).min(1).optional(),
12059
12212
  /** `value` is the reading; the others are the member counts. */
12060
12213
  publish: _enum([
12061
12214
  "value",
@@ -12069,6 +12222,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12069
12222
  "omit",
12070
12223
  "offline"
12071
12224
  ])
12225
+ }),
12226
+ object({
12227
+ kind: literal("series"),
12228
+ read: CompositionFieldReadSchema,
12229
+ /** `value` is the statistic or the integral. The others are the gap counts. */
12230
+ publish: _enum([
12231
+ "value",
12232
+ "included",
12233
+ "excluded",
12234
+ "total"
12235
+ ]),
12236
+ /**
12237
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
12238
+ * device unseeded until history answers, so a restart cannot publish 0.
12239
+ */
12240
+ empty: _enum([
12241
+ "null",
12242
+ "omit",
12243
+ "offline"
12244
+ ])
12072
12245
  })
12073
12246
  ]);
12074
12247
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -18262,7 +18435,8 @@ var CompositionProblemSchema = object({
18262
18435
  "native-capability-replace",
18263
18436
  "mixed-quantity",
18264
18437
  "helper-mismatch",
18265
- "member-constraint"
18438
+ "member-constraint",
18439
+ "retention"
18266
18440
  ]),
18267
18441
  path: string(),
18268
18442
  message: string()
@@ -18496,13 +18670,17 @@ Object.freeze({
18496
18670
  latchedAt: {
18497
18671
  kind: "fixed",
18498
18672
  result: ["number", "null"]
18673
+ },
18674
+ schmitt: {
18675
+ kind: "fixed",
18676
+ result: ["boolean", "null"]
18499
18677
  }
18500
18678
  });
18501
18679
  /**
18502
18680
  * One catalog row per base reading a group helper can build (D944 §3).
18503
18681
  * Data, not a form default written into the block.
18504
18682
  */
18505
- var NOW = {
18683
+ var NOW$2 = {
18506
18684
  fieldPath: "lastFetchedAt",
18507
18685
  expr: "now"
18508
18686
  };
@@ -18516,6 +18694,8 @@ function numeric(input) {
18516
18694
  family: "numeric",
18517
18695
  deviceType: DeviceType.Sensor,
18518
18696
  memberDeviceType: DeviceType.Sensor,
18697
+ memberDeviceTypes: [DeviceType.Sensor],
18698
+ activeWhen: void 0,
18519
18699
  commandCaps: [],
18520
18700
  baseUnit: baseUnitOf(input.quantity),
18521
18701
  aggregates: NUMERIC_AGGREGATES,
@@ -18531,6 +18711,8 @@ function binary(input) {
18531
18711
  family: "binary",
18532
18712
  deviceType: DeviceType.Sensor,
18533
18713
  memberDeviceType: DeviceType.Sensor,
18714
+ memberDeviceTypes: [DeviceType.Sensor],
18715
+ activeWhen: void 0,
18534
18716
  commandCaps: [],
18535
18717
  quantity: "none",
18536
18718
  baseUnit: void 0,
@@ -18548,7 +18730,7 @@ var GROUP_TEMPLATES = [
18548
18730
  quantity: "temperature",
18549
18731
  defaultAggregate: "mean",
18550
18732
  empty: "null",
18551
- companions: [NOW]
18733
+ companions: [NOW$2]
18552
18734
  }),
18553
18735
  numeric({
18554
18736
  id: "humidity",
@@ -18559,7 +18741,7 @@ var GROUP_TEMPLATES = [
18559
18741
  quantity: "humidity",
18560
18742
  defaultAggregate: "mean",
18561
18743
  empty: "null",
18562
- companions: [NOW]
18744
+ companions: [NOW$2]
18563
18745
  }),
18564
18746
  numeric({
18565
18747
  id: "pressure",
@@ -18570,7 +18752,7 @@ var GROUP_TEMPLATES = [
18570
18752
  quantity: "pressure",
18571
18753
  defaultAggregate: "mean",
18572
18754
  empty: "null",
18573
- companions: [NOW]
18755
+ companions: [NOW$2]
18574
18756
  }),
18575
18757
  numeric({
18576
18758
  id: "illuminance",
@@ -18581,7 +18763,7 @@ var GROUP_TEMPLATES = [
18581
18763
  quantity: "illuminance",
18582
18764
  defaultAggregate: "mean",
18583
18765
  empty: "null",
18584
- companions: [NOW]
18766
+ companions: [NOW$2]
18585
18767
  }),
18586
18768
  numeric({
18587
18769
  id: "power",
@@ -18592,7 +18774,7 @@ var GROUP_TEMPLATES = [
18592
18774
  quantity: "power",
18593
18775
  defaultAggregate: "sum",
18594
18776
  empty: "omit",
18595
- companions: [NOW]
18777
+ companions: [NOW$2]
18596
18778
  }),
18597
18779
  numeric({
18598
18780
  id: "energy",
@@ -18603,7 +18785,7 @@ var GROUP_TEMPLATES = [
18603
18785
  quantity: "energy",
18604
18786
  defaultAggregate: "sum",
18605
18787
  empty: "omit",
18606
- companions: [NOW]
18788
+ companions: [NOW$2]
18607
18789
  }),
18608
18790
  numeric({
18609
18791
  id: "battery",
@@ -18638,7 +18820,7 @@ var GROUP_TEMPLATES = [
18638
18820
  quantity: "device",
18639
18821
  defaultAggregate: "mean",
18640
18822
  empty: "null",
18641
- companions: [NOW]
18823
+ companions: [NOW$2]
18642
18824
  }),
18643
18825
  binary({
18644
18826
  id: "motion",
@@ -18732,6 +18914,11 @@ var GROUP_TEMPLATES = [
18732
18914
  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.",
18733
18915
  deviceType: DeviceType.Switch,
18734
18916
  outputCap: "switch",
18917
+ outputField: "on",
18918
+ member: {
18919
+ cap: "switch",
18920
+ fieldPath: "on"
18921
+ },
18735
18922
  commandCaps: ["switch"]
18736
18923
  }),
18737
18924
  actuator({
@@ -18739,34 +18926,136 @@ var GROUP_TEMPLATES = [
18739
18926
  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.",
18740
18927
  deviceType: DeviceType.Light,
18741
18928
  outputCap: "switch",
18929
+ outputField: "on",
18930
+ member: {
18931
+ cap: "switch",
18932
+ fieldPath: "on"
18933
+ },
18742
18934
  commandCaps: [
18743
18935
  "switch",
18744
18936
  "brightness",
18745
18937
  "color"
18746
18938
  ]
18939
+ }),
18940
+ actuator({
18941
+ id: "fan",
18942
+ 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.",
18943
+ deviceType: DeviceType.Fan,
18944
+ outputCap: "switch",
18945
+ outputField: "on",
18946
+ member: {
18947
+ cap: "switch",
18948
+ fieldPath: "on"
18949
+ },
18950
+ commandCaps: ["switch", "fan-control"]
18951
+ }),
18952
+ actuator({
18953
+ id: "cover",
18954
+ 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.",
18955
+ deviceType: DeviceType.Cover,
18956
+ outputCap: "group-active",
18957
+ outputField: "active",
18958
+ member: {
18959
+ cap: "cover",
18960
+ fieldPath: "state"
18961
+ },
18962
+ activeWhen: [
18963
+ "open",
18964
+ "opening",
18965
+ "stopped"
18966
+ ],
18967
+ commandCaps: ["cover"]
18968
+ }),
18969
+ actuator({
18970
+ id: "valve",
18971
+ 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.",
18972
+ deviceType: DeviceType.Valve,
18973
+ outputCap: "group-active",
18974
+ outputField: "active",
18975
+ member: {
18976
+ cap: "valve",
18977
+ fieldPath: "state"
18978
+ },
18979
+ activeWhen: [
18980
+ "open",
18981
+ "opening",
18982
+ "stopped"
18983
+ ],
18984
+ commandCaps: ["valve"]
18985
+ }),
18986
+ actuator({
18987
+ id: "lock",
18988
+ 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.",
18989
+ deviceType: DeviceType.Lock,
18990
+ outputCap: "group-active",
18991
+ outputField: "active",
18992
+ member: {
18993
+ cap: "lock-control",
18994
+ fieldPath: "state"
18995
+ },
18996
+ activeWhen: ["locked"],
18997
+ commandCaps: ["lock-control"]
18998
+ }),
18999
+ actuator({
19000
+ id: "media-player",
19001
+ 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.",
19002
+ deviceType: DeviceType.MediaPlayer,
19003
+ outputCap: "group-active",
19004
+ outputField: "active",
19005
+ member: {
19006
+ cap: "media-player",
19007
+ fieldPath: "state"
19008
+ },
19009
+ activeWhen: ["playing", "buffering"],
19010
+ commandCaps: ["media-player"]
19011
+ }),
19012
+ actuator({
19013
+ id: "climate",
19014
+ 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.",
19015
+ deviceType: DeviceType.Thermostat,
19016
+ memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
19017
+ outputCap: "group-active",
19018
+ outputField: "active",
19019
+ member: {
19020
+ cap: "climate-control",
19021
+ fieldPath: "mode"
19022
+ },
19023
+ activeWhen: [
19024
+ "heat",
19025
+ "cool",
19026
+ "auto",
19027
+ "heat_cool",
19028
+ "fan_only",
19029
+ "dry"
19030
+ ],
19031
+ commandCaps: ["climate-control"]
18747
19032
  })
18748
19033
  ];
18749
19034
  function actuator(input) {
18750
19035
  return {
18751
- ...input,
19036
+ id: input.id,
19037
+ summary: input.summary,
19038
+ deviceType: input.deviceType,
19039
+ outputCap: input.outputCap,
19040
+ outputField: input.outputField,
19041
+ commandCaps: input.commandCaps,
18752
19042
  family: "actuator",
18753
19043
  role: void 0,
18754
19044
  memberDeviceType: input.deviceType,
18755
- outputField: "on",
19045
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
19046
+ activeWhen: input.activeWhen,
18756
19047
  quantity: "none",
18757
19048
  baseUnit: void 0,
18758
19049
  aggregates: BINARY_AGGREGATES,
18759
19050
  defaultAggregate: "any",
18760
19051
  empty: "offline",
18761
- accept: [{
18762
- cap: "switch",
18763
- fieldPath: "on"
18764
- }],
19052
+ accept: [input.member],
18765
19053
  companions: [CHANGED]
18766
19054
  };
18767
19055
  }
18768
19056
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
18769
19057
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
19058
+ DeviceType.Camera;
18770
19059
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
18771
19060
  /**
18772
19061
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -46424,7 +46713,20 @@ var NcRuleInputSchema = object({
46424
46713
  * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
46425
46714
  * path does not run Zod defaults.
46426
46715
  */
46427
- groupingSec: number().int().min(5).max(60).optional()
46716
+ groupingSec: number().int().min(5).max(60).optional(),
46717
+ /**
46718
+ * ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
46719
+ * carries "Correct" / "Wrong" buttons (and, where the channel has room, a
46720
+ * "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
46721
+ * same mark the Library writes, and records whose notification it was and
46722
+ * when. A channel with no buttons gets the same two choices as links.
46723
+ *
46724
+ * `.optional()`, never `.default()` (a Zod default does not run on the addon
46725
+ * cap path): absent and `false` both mean off, which is what every rule
46726
+ * authored before this field meant. An editor turns it off by writing
46727
+ * `false`, so it needs no `clear` key.
46728
+ */
46729
+ askVerdict: boolean().optional()
46428
46730
  });
46429
46731
  /**
46430
46732
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -58625,7 +58927,13 @@ results: array(object({
58625
58927
  /** Ms epoch of the attempt. */
58626
58928
  at: number()
58627
58929
  })) });
58628
- DeviceType.Switch, DeviceType.Light;
58930
+ DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58931
+ object({
58932
+ active: boolean().meta({ label: "Active" }),
58933
+ /** Ms epoch when the slice was last updated. */
58934
+ lastChangedAt: number()
58935
+ });
58936
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
58629
58937
  object({
58630
58938
  /** Members whose current value entered the aggregate. */
58631
58939
  included: number().int().nonnegative().meta(readingMeta("count", {
@@ -58643,7 +58951,7 @@ object({
58643
58951
  label: "Members"
58644
58952
  }))
58645
58953
  });
58646
- DeviceType.Sensor, DeviceType.Switch, DeviceType.Light;
58954
+ DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58647
58955
  object({
58648
58956
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
58649
58957
  position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -59550,7 +59858,14 @@ DeviceType.Lock, method(object({
59550
59858
  auth: "protected"
59551
59859
  }), method(object({
59552
59860
  deviceId: number().int().nonnegative(),
59553
- code: string().min(1).optional()
59861
+ code: string().min(1).optional(),
59862
+ /**
59863
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
59864
+ * with one call is refused unless the caller says it was confirmed. A
59865
+ * single lock ignores it. The refusal lives in the callee, so no
59866
+ * automation or API caller reaches the doors by skipping a dialog.
59867
+ */
59868
+ confirm: boolean().optional()
59554
59869
  }), _void(), {
59555
59870
  kind: "mutation",
59556
59871
  auth: "protected"
@@ -59558,6 +59873,11 @@ DeviceType.Lock, method(object({
59558
59873
  kind: "mutation",
59559
59874
  auth: "protected"
59560
59875
  });
59876
+ object({
59877
+ value: number().nullable().meta(readingMeta("device", { label: "Total" })),
59878
+ lastFetchedAt: number()
59879
+ });
59880
+ DeviceType.Sensor;
59561
59881
  /**
59562
59882
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
59563
59883
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
@@ -63961,7 +64281,7 @@ object({
63961
64281
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
63962
64282
  lastChangedAt: number()
63963
64283
  });
63964
- DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
64284
+ DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
63965
64285
  deviceId: number(),
63966
64286
  on: boolean()
63967
64287
  }), _void(), {
@@ -65755,6 +66075,7 @@ var trainingCapability = {
65755
66075
  })
65756
66076
  }
65757
66077
  };
66078
+ DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
65758
66079
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
65759
66080
  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.Washer, DeviceType.Dryer, DeviceType.Camera, DeviceType.Camera, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
65760
66081
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
@@ -69032,6 +69353,13 @@ Object.freeze({
69032
69353
  access: "view",
69033
69354
  role: "viewer"
69034
69355
  },
69356
+ "groupActive.getStatus": {
69357
+ capName: "group-active",
69358
+ capScope: "device",
69359
+ addonId: null,
69360
+ access: "view",
69361
+ role: "viewer"
69362
+ },
69035
69363
  "groupCommands.getStatus": {
69036
69364
  capName: "group-commands",
69037
69365
  capScope: "device",
@@ -69998,6 +70326,13 @@ Object.freeze({
69998
70326
  access: "create",
69999
70327
  role: "admin"
70000
70328
  },
70329
+ "meter.getStatus": {
70330
+ capName: "meter",
70331
+ capScope: "device",
70332
+ addonId: null,
70333
+ access: "view",
70334
+ role: "viewer"
70335
+ },
70001
70336
  "metricsProvider.collectSnapshot": {
70002
70337
  capName: "metrics-provider",
70003
70338
  capScope: "system",
@@ -78900,6 +79235,10 @@ var SENSOR_CAP_VOCABULARY = {
78900
79235
  icon: "flame"
78901
79236
  }]
78902
79237
  },
79238
+ "group-active": {
79239
+ scope: "device",
79240
+ noun: t("Group state", "Stato del gruppo")
79241
+ },
78903
79242
  "group-commands": {
78904
79243
  scope: "device",
78905
79244
  noun: t("Group command", "Comando di gruppo")
@@ -78956,6 +79295,17 @@ var SENSOR_CAP_VOCABULARY = {
78956
79295
  }],
78957
79296
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
78958
79297
  },
79298
+ meter: {
79299
+ scope: "device",
79300
+ noun: t("Meter", "Contatore"),
79301
+ state: [{
79302
+ kind: "numeric",
79303
+ field: "value",
79304
+ quantity: t("the total", "il totale"),
79305
+ label: t("Total", "Totale"),
79306
+ icon: "gauge"
79307
+ }]
79308
+ },
78959
79309
  "numeric-sensor": {
78960
79310
  scope: "device",
78961
79311
  noun: t("Sensor", "Sensore"),
@@ -80435,6 +80785,11 @@ Object.freeze({
80435
80785
  form: "single",
80436
80786
  optional: false
80437
80787
  }],
80788
+ "groupActive.getStatus": [{
80789
+ name: "deviceId",
80790
+ form: "single",
80791
+ optional: false
80792
+ }],
80438
80793
  "groupCommands.getStatus": [{
80439
80794
  name: "deviceId",
80440
80795
  form: "single",
@@ -80645,6 +81000,11 @@ Object.freeze({
80645
81000
  form: "single",
80646
81001
  optional: false
80647
81002
  }],
81003
+ "meter.getStatus": [{
81004
+ name: "deviceId",
81005
+ form: "single",
81006
+ optional: false
81007
+ }],
80648
81008
  "motion.getStatus": [{
80649
81009
  name: "deviceId",
80650
81010
  form: "single",
@@ -82252,7 +82612,6 @@ Object.freeze({
82252
82612
  "network-access": "ingress",
82253
82613
  "smtp-provider": "email"
82254
82614
  });
82255
- DeviceType.Camera;
82256
82615
  /**
82257
82616
  * A saved Customize assignment (D936). The schema is the type: callers use
82258
82617
  * `z.infer`, they do not restate the shape.