@camstack/addon-model-studio 1.1.304 → 1.1.306

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 (18) hide show
  1. package/dist/{MotionZonesSettings-DBGT8Nj8.mjs → MotionZonesSettings-BdAF3Lx2.mjs} +2 -2
  2. package/dist/{PrivacyMaskSettings-CLQVQM7P.mjs → PrivacyMaskSettings-bRMKWnGr.mjs} +4 -4
  3. package/dist/{SceneMonitorEditor-Bh49Hy9u.mjs → SceneMonitorEditor-DffVOhzN.mjs} +3 -3
  4. package/dist/_stub.js +628 -627
  5. package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-C21hMYtP.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_model_studio_page-DVVRygHY.mjs} +3 -3
  6. package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CsIeC3fr.mjs +26 -0
  7. package/dist/{hostInit-ZZzTzmNI.mjs → hostInit-fNjQtgdi.mjs} +2 -2
  8. package/dist/model-studio.addon.js +399 -40
  9. package/dist/model-studio.addon.mjs +399 -40
  10. package/dist/{player-overlays-Cyvfs2Sv.mjs → player-overlays-BQux3aXS.mjs} +1 -1
  11. package/dist/remoteEntry.js +1 -1
  12. package/dist/{responsive-m4ExMXS1.mjs → responsive-BOS8RfJa.mjs} +1 -1
  13. package/dist/{scene-monitor-copy-BQJaiY--.mjs → scene-monitor-copy-CaVNQakt.mjs} +1 -1
  14. package/dist/{square-CfhGQSpr.mjs → square-DCA-7eaY.mjs} +1 -1
  15. package/dist/{trash-2-a_u-D224.mjs → trash-2-DYZFq4gu.mjs} +1 -1
  16. package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-D2OpYesY.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_model_studio_page__remoteEntry_js-CWXLGHpz.mjs} +1 -1
  17. package/package.json +1 -1
  18. package/dist/_virtual_mf___mfe_internal__addon_model_studio_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-ClO1ZruD.mjs +0 -26
@@ -5837,7 +5837,7 @@ var ZodIssueCode = {
5837
5837
  var ZodFirstPartyTypeKind;
5838
5838
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5839
5839
  //#endregion
5840
- //#region ../types/dist/sleep-bykKrTgu.mjs
5840
+ //#region ../types/dist/sleep--jXS9hWo.mjs
5841
5841
  /**
5842
5842
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5843
5843
  * window to float samples (D455).
@@ -9040,6 +9040,7 @@ var CAP_NAMES = Object.freeze([
9040
9040
  "filesystem-browse",
9041
9041
  "flood",
9042
9042
  "gas",
9043
+ "group-active",
9043
9044
  "group-commands",
9044
9045
  "group-status",
9045
9046
  "heating-valve",
@@ -9062,6 +9063,7 @@ var CAP_NAMES = Object.freeze([
9062
9063
  "login-method",
9063
9064
  "media-player",
9064
9065
  "mesh-network",
9066
+ "meter",
9065
9067
  "metrics-provider",
9066
9068
  "model-convert",
9067
9069
  "model-distributor",
@@ -9860,6 +9862,10 @@ Object.freeze({
9860
9862
  "path": "detected",
9861
9863
  "valueType": "boolean"
9862
9864
  }],
9865
+ "group-active": [{
9866
+ "path": "active",
9867
+ "valueType": "boolean"
9868
+ }],
9863
9869
  "group-status": [
9864
9870
  {
9865
9871
  "path": "included",
@@ -10119,6 +10125,10 @@ Object.freeze({
10119
10125
  ]
10120
10126
  }
10121
10127
  ],
10128
+ "meter": [{
10129
+ "path": "value",
10130
+ "valueType": "number"
10131
+ }],
10122
10132
  "motion": [
10123
10133
  {
10124
10134
  "path": "detected",
@@ -11211,7 +11221,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
11211
11221
  return DeviceRole;
11212
11222
  }({});
11213
11223
  //#endregion
11214
- //#region ../types/dist/composition-B2rw5L29.mjs
11224
+ //#region ../types/dist/composition-Bb8iwHEJ.mjs
11215
11225
  /**
11216
11226
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11217
11227
  *
@@ -11526,6 +11536,13 @@ var table = {
11526
11536
  apply: () => {
11527
11537
  throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
11528
11538
  }
11539
+ },
11540
+ schmitt: {
11541
+ minArgs: 3,
11542
+ maxArgs: 5,
11543
+ apply: () => {
11544
+ throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
11545
+ }
11529
11546
  }
11530
11547
  };
11531
11548
  Object.freeze(Object.assign(Object.create(null), table));
@@ -11987,6 +12004,79 @@ var APPLIANCE_KINDS = [
11987
12004
  ];
11988
12005
  DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
11989
12006
  /**
12007
+ * Statistics and integrals over a history read (D944).
12008
+ *
12009
+ * Pure: the same points always give the same answer, so a restart recomputes
12010
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
12011
+ * never the mean of the samples. A hole with no held value is not integrated
12012
+ * as zero. A truncated read is not published.
12013
+ */
12014
+ var STATISTIC_STATS = [
12015
+ "min",
12016
+ "max",
12017
+ "mean",
12018
+ "sum",
12019
+ "count",
12020
+ "change"
12021
+ ];
12022
+ /**
12023
+ * The range a statistics or integral helper asks history for (D944).
12024
+ *
12025
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
12026
+ * or 25 hours across a DST change. A tier is eligible only when its retention
12027
+ * is strictly longer than the longest that range can be. Forever qualifies.
12028
+ * Equal to a tier's retention is a refusal, not a short answer.
12029
+ */
12030
+ var MINUTE_MS = 6e4;
12031
+ var HOUR_MS = 60 * MINUTE_MS;
12032
+ var DAY_MS = 24 * HOUR_MS;
12033
+ var ROLLING_SPANS = [
12034
+ "1h",
12035
+ "24h",
12036
+ "2d",
12037
+ "7d",
12038
+ "30d",
12039
+ "custom"
12040
+ ];
12041
+ var CALENDAR_PERIODS = [
12042
+ "today",
12043
+ "yesterday",
12044
+ "this-week",
12045
+ "this-month"
12046
+ ];
12047
+ var RESET_PERIODS = [
12048
+ "never",
12049
+ "daily",
12050
+ "weekly",
12051
+ "monthly"
12052
+ ];
12053
+ 5 * MINUTE_MS;
12054
+ 24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
12055
+ 7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
12056
+ var rollingWindowObject = object({
12057
+ kind: literal("rolling"),
12058
+ span: _enum(ROLLING_SPANS),
12059
+ customMinutes: number().int().min(5).optional()
12060
+ }).check((payload) => {
12061
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
12062
+ code: "custom",
12063
+ message: "a custom range needs a duration in minutes",
12064
+ path: ["customMinutes"],
12065
+ input: payload.value
12066
+ });
12067
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
12068
+ code: "custom",
12069
+ message: "only a custom range carries a duration",
12070
+ path: ["customMinutes"],
12071
+ input: payload.value
12072
+ });
12073
+ });
12074
+ var RollingWindowSchema = rollingWindowObject;
12075
+ var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
12076
+ kind: literal("calendar"),
12077
+ period: _enum(CALENDAR_PERIODS)
12078
+ })]);
12079
+ /**
11990
12080
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11991
12081
  * id. Split out so helper schemas can name it without a cycle through
11992
12082
  * `composition.ts` (D659).
@@ -12012,7 +12102,13 @@ var GROUP_TEMPLATE_IDS = [
12012
12102
  "occupancy",
12013
12103
  "binary",
12014
12104
  "switch",
12015
- "light"
12105
+ "light",
12106
+ "fan",
12107
+ "cover",
12108
+ "valve",
12109
+ "lock",
12110
+ "media-player",
12111
+ "climate"
12016
12112
  ];
12017
12113
  var NUMERIC_AGGREGATES = [
12018
12114
  "mean",
@@ -12042,22 +12138,73 @@ var HelperMemberSchema = object({
12042
12138
  cap: string().min(1),
12043
12139
  fieldPath: string().min(1)
12044
12140
  });
12045
- var HelperSpecSchema = discriminatedUnion("kind", [object({
12046
- kind: literal("group"),
12047
- templateId: GroupTemplateIdSchema,
12048
- aggregate: AggregateReducerSchema,
12049
- members: array(HelperMemberSchema).min(1).max(64),
12050
- /** Actuator groups only. Readings leave this unset. */
12051
- active: ActiveCriterionSchema.optional()
12052
- }), object({
12053
- kind: literal("appliance"),
12054
- templateId: literal(APPLIANCE_TEMPLATE_ID),
12055
- appliance: _enum(APPLIANCE_KINDS),
12056
- thresholdWatts: number().positive(),
12057
- startDwellMs: number().int().nonnegative(),
12058
- stopDwellMs: number().int().nonnegative(),
12059
- member: HelperMemberSchema
12060
- })]);
12141
+ var HelperSpecSchema = discriminatedUnion("kind", [
12142
+ object({
12143
+ kind: literal("group"),
12144
+ templateId: GroupTemplateIdSchema,
12145
+ aggregate: AggregateReducerSchema,
12146
+ members: array(HelperMemberSchema).min(1).max(64),
12147
+ /** Actuator groups only. Readings leave this unset. */
12148
+ active: ActiveCriterionSchema.optional()
12149
+ }),
12150
+ object({
12151
+ kind: literal("appliance"),
12152
+ templateId: literal(APPLIANCE_TEMPLATE_ID),
12153
+ appliance: _enum(APPLIANCE_KINDS),
12154
+ thresholdWatts: number().positive(),
12155
+ startDwellMs: number().int().nonnegative(),
12156
+ stopDwellMs: number().int().nonnegative(),
12157
+ member: HelperMemberSchema
12158
+ }),
12159
+ object({
12160
+ kind: literal("statistic"),
12161
+ stat: _enum(STATISTIC_STATS),
12162
+ window: StatisticWindowSchema,
12163
+ source: HelperMemberSchema
12164
+ }),
12165
+ object({
12166
+ kind: literal("integral"),
12167
+ reset: _enum(RESET_PERIODS),
12168
+ output: _enum(["energy", "meter"]),
12169
+ source: HelperMemberSchema
12170
+ }),
12171
+ object({
12172
+ kind: literal("threshold"),
12173
+ source: HelperMemberSchema,
12174
+ high: number(),
12175
+ low: number(),
12176
+ onForMs: number().int().nonnegative(),
12177
+ offForMs: number().int().nonnegative()
12178
+ }),
12179
+ object({
12180
+ kind: literal("arithmetic"),
12181
+ op: _enum([
12182
+ "sum",
12183
+ "difference",
12184
+ "ratio"
12185
+ ]),
12186
+ inputs: array(HelperMemberSchema).min(2).max(64)
12187
+ }),
12188
+ object({
12189
+ kind: literal("expression"),
12190
+ expr: string().min(1),
12191
+ inputs: array(object({
12192
+ name: string().min(1),
12193
+ member: HelperMemberSchema
12194
+ })).min(1).max(64),
12195
+ output: _enum(["number", "boolean"])
12196
+ }),
12197
+ object({
12198
+ kind: literal("derivative"),
12199
+ window: RollingWindowSchema,
12200
+ per: _enum([
12201
+ "second",
12202
+ "minute",
12203
+ "hour"
12204
+ ]),
12205
+ source: HelperMemberSchema
12206
+ })
12207
+ ]);
12061
12208
  /** A composed device's stableId is this prefix plus the block id. */
12062
12209
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
12063
12210
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -12118,6 +12265,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12118
12265
  "all"
12119
12266
  ]),
12120
12267
  reads: array(CompositionFieldReadSchema).min(1).max(64),
12268
+ /**
12269
+ * Set when the reads are an enum state, not a yes/no: the listed states
12270
+ * count as active (a cover is `open`). A state outside the list is inactive;
12271
+ * a read that is not a state at all is left out. Only `any` / `all` use it.
12272
+ */
12273
+ activeWhen: array(string().min(1)).min(1).optional(),
12121
12274
  /** `value` is the reading; the others are the member counts. */
12122
12275
  publish: _enum([
12123
12276
  "value",
@@ -12131,6 +12284,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12131
12284
  "omit",
12132
12285
  "offline"
12133
12286
  ])
12287
+ }),
12288
+ object({
12289
+ kind: literal("series"),
12290
+ read: CompositionFieldReadSchema,
12291
+ /** `value` is the statistic or the integral. The others are the gap counts. */
12292
+ publish: _enum([
12293
+ "value",
12294
+ "included",
12295
+ "excluded",
12296
+ "total"
12297
+ ]),
12298
+ /**
12299
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
12300
+ * device unseeded until history answers, so a restart cannot publish 0.
12301
+ */
12302
+ empty: _enum([
12303
+ "null",
12304
+ "omit",
12305
+ "offline"
12306
+ ])
12134
12307
  })
12135
12308
  ]);
12136
12309
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -18445,7 +18618,8 @@ var CompositionProblemSchema = object({
18445
18618
  "native-capability-replace",
18446
18619
  "mixed-quantity",
18447
18620
  "helper-mismatch",
18448
- "member-constraint"
18621
+ "member-constraint",
18622
+ "retention"
18449
18623
  ]),
18450
18624
  path: string(),
18451
18625
  message: string()
@@ -18679,13 +18853,17 @@ Object.freeze({
18679
18853
  latchedAt: {
18680
18854
  kind: "fixed",
18681
18855
  result: ["number", "null"]
18856
+ },
18857
+ schmitt: {
18858
+ kind: "fixed",
18859
+ result: ["boolean", "null"]
18682
18860
  }
18683
18861
  });
18684
18862
  /**
18685
18863
  * One catalog row per base reading a group helper can build (D944 §3).
18686
18864
  * Data, not a form default written into the block.
18687
18865
  */
18688
- var NOW = {
18866
+ var NOW$2 = {
18689
18867
  fieldPath: "lastFetchedAt",
18690
18868
  expr: "now"
18691
18869
  };
@@ -18699,6 +18877,8 @@ function numeric(input) {
18699
18877
  family: "numeric",
18700
18878
  deviceType: DeviceType.Sensor,
18701
18879
  memberDeviceType: DeviceType.Sensor,
18880
+ memberDeviceTypes: [DeviceType.Sensor],
18881
+ activeWhen: void 0,
18702
18882
  commandCaps: [],
18703
18883
  baseUnit: baseUnitOf(input.quantity),
18704
18884
  aggregates: NUMERIC_AGGREGATES,
@@ -18714,6 +18894,8 @@ function binary(input) {
18714
18894
  family: "binary",
18715
18895
  deviceType: DeviceType.Sensor,
18716
18896
  memberDeviceType: DeviceType.Sensor,
18897
+ memberDeviceTypes: [DeviceType.Sensor],
18898
+ activeWhen: void 0,
18717
18899
  commandCaps: [],
18718
18900
  quantity: "none",
18719
18901
  baseUnit: void 0,
@@ -18731,7 +18913,7 @@ var GROUP_TEMPLATES = [
18731
18913
  quantity: "temperature",
18732
18914
  defaultAggregate: "mean",
18733
18915
  empty: "null",
18734
- companions: [NOW]
18916
+ companions: [NOW$2]
18735
18917
  }),
18736
18918
  numeric({
18737
18919
  id: "humidity",
@@ -18742,7 +18924,7 @@ var GROUP_TEMPLATES = [
18742
18924
  quantity: "humidity",
18743
18925
  defaultAggregate: "mean",
18744
18926
  empty: "null",
18745
- companions: [NOW]
18927
+ companions: [NOW$2]
18746
18928
  }),
18747
18929
  numeric({
18748
18930
  id: "pressure",
@@ -18753,7 +18935,7 @@ var GROUP_TEMPLATES = [
18753
18935
  quantity: "pressure",
18754
18936
  defaultAggregate: "mean",
18755
18937
  empty: "null",
18756
- companions: [NOW]
18938
+ companions: [NOW$2]
18757
18939
  }),
18758
18940
  numeric({
18759
18941
  id: "illuminance",
@@ -18764,7 +18946,7 @@ var GROUP_TEMPLATES = [
18764
18946
  quantity: "illuminance",
18765
18947
  defaultAggregate: "mean",
18766
18948
  empty: "null",
18767
- companions: [NOW]
18949
+ companions: [NOW$2]
18768
18950
  }),
18769
18951
  numeric({
18770
18952
  id: "power",
@@ -18775,7 +18957,7 @@ var GROUP_TEMPLATES = [
18775
18957
  quantity: "power",
18776
18958
  defaultAggregate: "sum",
18777
18959
  empty: "omit",
18778
- companions: [NOW]
18960
+ companions: [NOW$2]
18779
18961
  }),
18780
18962
  numeric({
18781
18963
  id: "energy",
@@ -18786,7 +18968,7 @@ var GROUP_TEMPLATES = [
18786
18968
  quantity: "energy",
18787
18969
  defaultAggregate: "sum",
18788
18970
  empty: "omit",
18789
- companions: [NOW]
18971
+ companions: [NOW$2]
18790
18972
  }),
18791
18973
  numeric({
18792
18974
  id: "battery",
@@ -18821,7 +19003,7 @@ var GROUP_TEMPLATES = [
18821
19003
  quantity: "device",
18822
19004
  defaultAggregate: "mean",
18823
19005
  empty: "null",
18824
- companions: [NOW]
19006
+ companions: [NOW$2]
18825
19007
  }),
18826
19008
  binary({
18827
19009
  id: "motion",
@@ -18915,6 +19097,11 @@ var GROUP_TEMPLATES = [
18915
19097
  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.",
18916
19098
  deviceType: DeviceType.Switch,
18917
19099
  outputCap: "switch",
19100
+ outputField: "on",
19101
+ member: {
19102
+ cap: "switch",
19103
+ fieldPath: "on"
19104
+ },
18918
19105
  commandCaps: ["switch"]
18919
19106
  }),
18920
19107
  actuator({
@@ -18922,34 +19109,136 @@ var GROUP_TEMPLATES = [
18922
19109
  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.",
18923
19110
  deviceType: DeviceType.Light,
18924
19111
  outputCap: "switch",
19112
+ outputField: "on",
19113
+ member: {
19114
+ cap: "switch",
19115
+ fieldPath: "on"
19116
+ },
18925
19117
  commandCaps: [
18926
19118
  "switch",
18927
19119
  "brightness",
18928
19120
  "color"
18929
19121
  ]
19122
+ }),
19123
+ actuator({
19124
+ id: "fan",
19125
+ 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.",
19126
+ deviceType: DeviceType.Fan,
19127
+ outputCap: "switch",
19128
+ outputField: "on",
19129
+ member: {
19130
+ cap: "switch",
19131
+ fieldPath: "on"
19132
+ },
19133
+ commandCaps: ["switch", "fan-control"]
19134
+ }),
19135
+ actuator({
19136
+ id: "cover",
19137
+ 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.",
19138
+ deviceType: DeviceType.Cover,
19139
+ outputCap: "group-active",
19140
+ outputField: "active",
19141
+ member: {
19142
+ cap: "cover",
19143
+ fieldPath: "state"
19144
+ },
19145
+ activeWhen: [
19146
+ "open",
19147
+ "opening",
19148
+ "stopped"
19149
+ ],
19150
+ commandCaps: ["cover"]
19151
+ }),
19152
+ actuator({
19153
+ id: "valve",
19154
+ 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.",
19155
+ deviceType: DeviceType.Valve,
19156
+ outputCap: "group-active",
19157
+ outputField: "active",
19158
+ member: {
19159
+ cap: "valve",
19160
+ fieldPath: "state"
19161
+ },
19162
+ activeWhen: [
19163
+ "open",
19164
+ "opening",
19165
+ "stopped"
19166
+ ],
19167
+ commandCaps: ["valve"]
19168
+ }),
19169
+ actuator({
19170
+ id: "lock",
19171
+ 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.",
19172
+ deviceType: DeviceType.Lock,
19173
+ outputCap: "group-active",
19174
+ outputField: "active",
19175
+ member: {
19176
+ cap: "lock-control",
19177
+ fieldPath: "state"
19178
+ },
19179
+ activeWhen: ["locked"],
19180
+ commandCaps: ["lock-control"]
19181
+ }),
19182
+ actuator({
19183
+ id: "media-player",
19184
+ 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.",
19185
+ deviceType: DeviceType.MediaPlayer,
19186
+ outputCap: "group-active",
19187
+ outputField: "active",
19188
+ member: {
19189
+ cap: "media-player",
19190
+ fieldPath: "state"
19191
+ },
19192
+ activeWhen: ["playing", "buffering"],
19193
+ commandCaps: ["media-player"]
19194
+ }),
19195
+ actuator({
19196
+ id: "climate",
19197
+ 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.",
19198
+ deviceType: DeviceType.Thermostat,
19199
+ memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
19200
+ outputCap: "group-active",
19201
+ outputField: "active",
19202
+ member: {
19203
+ cap: "climate-control",
19204
+ fieldPath: "mode"
19205
+ },
19206
+ activeWhen: [
19207
+ "heat",
19208
+ "cool",
19209
+ "auto",
19210
+ "heat_cool",
19211
+ "fan_only",
19212
+ "dry"
19213
+ ],
19214
+ commandCaps: ["climate-control"]
18930
19215
  })
18931
19216
  ];
18932
19217
  function actuator(input) {
18933
19218
  return {
18934
- ...input,
19219
+ id: input.id,
19220
+ summary: input.summary,
19221
+ deviceType: input.deviceType,
19222
+ outputCap: input.outputCap,
19223
+ outputField: input.outputField,
19224
+ commandCaps: input.commandCaps,
18935
19225
  family: "actuator",
18936
19226
  role: void 0,
18937
19227
  memberDeviceType: input.deviceType,
18938
- outputField: "on",
19228
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
19229
+ activeWhen: input.activeWhen,
18939
19230
  quantity: "none",
18940
19231
  baseUnit: void 0,
18941
19232
  aggregates: BINARY_AGGREGATES,
18942
19233
  defaultAggregate: "any",
18943
19234
  empty: "offline",
18944
- accept: [{
18945
- cap: "switch",
18946
- fieldPath: "on"
18947
- }],
19235
+ accept: [input.member],
18948
19236
  companions: [CHANGED]
18949
19237
  };
18950
19238
  }
18951
19239
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
18952
19240
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
19241
+ DeviceType.Camera;
18953
19242
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
18954
19243
  /**
18955
19244
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -46641,7 +46930,20 @@ var NcRuleInputSchema = object({
46641
46930
  * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
46642
46931
  * path does not run Zod defaults.
46643
46932
  */
46644
- groupingSec: number().int().min(5).max(60).optional()
46933
+ groupingSec: number().int().min(5).max(60).optional(),
46934
+ /**
46935
+ * ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
46936
+ * carries "Correct" / "Wrong" buttons (and, where the channel has room, a
46937
+ * "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
46938
+ * same mark the Library writes, and records whose notification it was and
46939
+ * when. A channel with no buttons gets the same two choices as links.
46940
+ *
46941
+ * `.optional()`, never `.default()` (a Zod default does not run on the addon
46942
+ * cap path): absent and `false` both mean off, which is what every rule
46943
+ * authored before this field meant. An editor turns it off by writing
46944
+ * `false`, so it needs no `clear` key.
46945
+ */
46946
+ askVerdict: boolean().optional()
46645
46947
  });
46646
46948
  /**
46647
46949
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -58842,7 +59144,13 @@ results: array(object({
58842
59144
  /** Ms epoch of the attempt. */
58843
59145
  at: number()
58844
59146
  })) });
58845
- DeviceType.Switch, DeviceType.Light;
59147
+ DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
59148
+ object({
59149
+ active: boolean().meta({ label: "Active" }),
59150
+ /** Ms epoch when the slice was last updated. */
59151
+ lastChangedAt: number()
59152
+ });
59153
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
58846
59154
  object({
58847
59155
  /** Members whose current value entered the aggregate. */
58848
59156
  included: number().int().nonnegative().meta(readingMeta("count", {
@@ -58860,7 +59168,7 @@ object({
58860
59168
  label: "Members"
58861
59169
  }))
58862
59170
  });
58863
- DeviceType.Sensor, DeviceType.Switch, DeviceType.Light;
59171
+ DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58864
59172
  object({
58865
59173
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
58866
59174
  position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -59767,7 +60075,14 @@ DeviceType.Lock, method(object({
59767
60075
  auth: "protected"
59768
60076
  }), method(object({
59769
60077
  deviceId: number().int().nonnegative(),
59770
- code: string().min(1).optional()
60078
+ code: string().min(1).optional(),
60079
+ /**
60080
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
60081
+ * with one call is refused unless the caller says it was confirmed. A
60082
+ * single lock ignores it. The refusal lives in the callee, so no
60083
+ * automation or API caller reaches the doors by skipping a dialog.
60084
+ */
60085
+ confirm: boolean().optional()
59771
60086
  }), _void(), {
59772
60087
  kind: "mutation",
59773
60088
  auth: "protected"
@@ -59775,6 +60090,11 @@ DeviceType.Lock, method(object({
59775
60090
  kind: "mutation",
59776
60091
  auth: "protected"
59777
60092
  });
60093
+ object({
60094
+ value: number().nullable().meta(readingMeta("device", { label: "Total" })),
60095
+ lastFetchedAt: number()
60096
+ });
60097
+ DeviceType.Sensor;
59778
60098
  /**
59779
60099
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
59780
60100
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
@@ -64178,7 +64498,7 @@ object({
64178
64498
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
64179
64499
  lastChangedAt: number()
64180
64500
  });
64181
- DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
64501
+ DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
64182
64502
  deviceId: number(),
64183
64503
  on: boolean()
64184
64504
  }), _void(), {
@@ -65870,6 +66190,7 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
65870
66190
  kind: "mutation",
65871
66191
  auth: "admin"
65872
66192
  });
66193
+ DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
65873
66194
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
65874
66195
  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;
65875
66196
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
@@ -69245,6 +69566,13 @@ Object.freeze({
69245
69566
  access: "view",
69246
69567
  role: "viewer"
69247
69568
  },
69569
+ "groupActive.getStatus": {
69570
+ capName: "group-active",
69571
+ capScope: "device",
69572
+ addonId: null,
69573
+ access: "view",
69574
+ role: "viewer"
69575
+ },
69248
69576
  "groupCommands.getStatus": {
69249
69577
  capName: "group-commands",
69250
69578
  capScope: "device",
@@ -70211,6 +70539,13 @@ Object.freeze({
70211
70539
  access: "create",
70212
70540
  role: "admin"
70213
70541
  },
70542
+ "meter.getStatus": {
70543
+ capName: "meter",
70544
+ capScope: "device",
70545
+ addonId: null,
70546
+ access: "view",
70547
+ role: "viewer"
70548
+ },
70214
70549
  "metricsProvider.collectSnapshot": {
70215
70550
  capName: "metrics-provider",
70216
70551
  capScope: "system",
@@ -79113,6 +79448,10 @@ var SENSOR_CAP_VOCABULARY = {
79113
79448
  icon: "flame"
79114
79449
  }]
79115
79450
  },
79451
+ "group-active": {
79452
+ scope: "device",
79453
+ noun: t("Group state", "Stato del gruppo")
79454
+ },
79116
79455
  "group-commands": {
79117
79456
  scope: "device",
79118
79457
  noun: t("Group command", "Comando di gruppo")
@@ -79169,6 +79508,17 @@ var SENSOR_CAP_VOCABULARY = {
79169
79508
  }],
79170
79509
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
79171
79510
  },
79511
+ meter: {
79512
+ scope: "device",
79513
+ noun: t("Meter", "Contatore"),
79514
+ state: [{
79515
+ kind: "numeric",
79516
+ field: "value",
79517
+ quantity: t("the total", "il totale"),
79518
+ label: t("Total", "Totale"),
79519
+ icon: "gauge"
79520
+ }]
79521
+ },
79172
79522
  "numeric-sensor": {
79173
79523
  scope: "device",
79174
79524
  noun: t("Sensor", "Sensore"),
@@ -80648,6 +80998,11 @@ Object.freeze({
80648
80998
  form: "single",
80649
80999
  optional: false
80650
81000
  }],
81001
+ "groupActive.getStatus": [{
81002
+ name: "deviceId",
81003
+ form: "single",
81004
+ optional: false
81005
+ }],
80651
81006
  "groupCommands.getStatus": [{
80652
81007
  name: "deviceId",
80653
81008
  form: "single",
@@ -80858,6 +81213,11 @@ Object.freeze({
80858
81213
  form: "single",
80859
81214
  optional: false
80860
81215
  }],
81216
+ "meter.getStatus": [{
81217
+ name: "deviceId",
81218
+ form: "single",
81219
+ optional: false
81220
+ }],
80861
81221
  "motion.getStatus": [{
80862
81222
  name: "deviceId",
80863
81223
  form: "single",
@@ -82465,7 +82825,6 @@ Object.freeze({
82465
82825
  "network-access": "ingress",
82466
82826
  "smtp-provider": "email"
82467
82827
  });
82468
- DeviceType.Camera;
82469
82828
  /**
82470
82829
  * A saved Customize assignment (D936). The schema is the type: callers use
82471
82830
  * `z.infer`, they do not restate the shape.