@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
@@ -5811,7 +5811,7 @@ var ZodIssueCode = {
5811
5811
  var ZodFirstPartyTypeKind;
5812
5812
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5813
5813
  //#endregion
5814
- //#region ../types/dist/sleep-bykKrTgu.mjs
5814
+ //#region ../types/dist/sleep--jXS9hWo.mjs
5815
5815
  /**
5816
5816
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5817
5817
  * window to float samples (D455).
@@ -9014,6 +9014,7 @@ var CAP_NAMES = Object.freeze([
9014
9014
  "filesystem-browse",
9015
9015
  "flood",
9016
9016
  "gas",
9017
+ "group-active",
9017
9018
  "group-commands",
9018
9019
  "group-status",
9019
9020
  "heating-valve",
@@ -9036,6 +9037,7 @@ var CAP_NAMES = Object.freeze([
9036
9037
  "login-method",
9037
9038
  "media-player",
9038
9039
  "mesh-network",
9040
+ "meter",
9039
9041
  "metrics-provider",
9040
9042
  "model-convert",
9041
9043
  "model-distributor",
@@ -9834,6 +9836,10 @@ Object.freeze({
9834
9836
  "path": "detected",
9835
9837
  "valueType": "boolean"
9836
9838
  }],
9839
+ "group-active": [{
9840
+ "path": "active",
9841
+ "valueType": "boolean"
9842
+ }],
9837
9843
  "group-status": [
9838
9844
  {
9839
9845
  "path": "included",
@@ -10093,6 +10099,10 @@ Object.freeze({
10093
10099
  ]
10094
10100
  }
10095
10101
  ],
10102
+ "meter": [{
10103
+ "path": "value",
10104
+ "valueType": "number"
10105
+ }],
10096
10106
  "motion": [
10097
10107
  {
10098
10108
  "path": "detected",
@@ -11185,7 +11195,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
11185
11195
  return DeviceRole;
11186
11196
  }({});
11187
11197
  //#endregion
11188
- //#region ../types/dist/composition-B2rw5L29.mjs
11198
+ //#region ../types/dist/composition-Bb8iwHEJ.mjs
11189
11199
  /**
11190
11200
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11191
11201
  *
@@ -11500,6 +11510,13 @@ var table = {
11500
11510
  apply: () => {
11501
11511
  throw new ExpressionEvalError("latchedAt: stateful evaluation context is required");
11502
11512
  }
11513
+ },
11514
+ schmitt: {
11515
+ minArgs: 3,
11516
+ maxArgs: 5,
11517
+ apply: () => {
11518
+ throw new ExpressionEvalError("schmitt: stateful evaluation context is required");
11519
+ }
11503
11520
  }
11504
11521
  };
11505
11522
  Object.freeze(Object.assign(Object.create(null), table));
@@ -11961,6 +11978,79 @@ var APPLIANCE_KINDS = [
11961
11978
  ];
11962
11979
  DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher;
11963
11980
  /**
11981
+ * Statistics and integrals over a history read (D944).
11982
+ *
11983
+ * Pure: the same points always give the same answer, so a restart recomputes
11984
+ * rather than trusting a buffer. A gauge mean is time-weighted (value × ms),
11985
+ * never the mean of the samples. A hole with no held value is not integrated
11986
+ * as zero. A truncated read is not published.
11987
+ */
11988
+ var STATISTIC_STATS = [
11989
+ "min",
11990
+ "max",
11991
+ "mean",
11992
+ "sum",
11993
+ "count",
11994
+ "change"
11995
+ ];
11996
+ /**
11997
+ * The range a statistics or integral helper asks history for (D944).
11998
+ *
11999
+ * Calendar edges are the hub's timezone, never UTC midnight: a day is 23, 24
12000
+ * or 25 hours across a DST change. A tier is eligible only when its retention
12001
+ * is strictly longer than the longest that range can be. Forever qualifies.
12002
+ * Equal to a tier's retention is a refusal, not a short answer.
12003
+ */
12004
+ var MINUTE_MS = 6e4;
12005
+ var HOUR_MS = 60 * MINUTE_MS;
12006
+ var DAY_MS = 24 * HOUR_MS;
12007
+ var ROLLING_SPANS = [
12008
+ "1h",
12009
+ "24h",
12010
+ "2d",
12011
+ "7d",
12012
+ "30d",
12013
+ "custom"
12014
+ ];
12015
+ var CALENDAR_PERIODS = [
12016
+ "today",
12017
+ "yesterday",
12018
+ "this-week",
12019
+ "this-month"
12020
+ ];
12021
+ var RESET_PERIODS = [
12022
+ "never",
12023
+ "daily",
12024
+ "weekly",
12025
+ "monthly"
12026
+ ];
12027
+ 5 * MINUTE_MS;
12028
+ 24 * HOUR_MS, 2 * DAY_MS, 7 * DAY_MS, 30 * DAY_MS;
12029
+ 7 * DAY_MS, 30 * DAY_MS, 365 * DAY_MS;
12030
+ var rollingWindowObject = object({
12031
+ kind: literal("rolling"),
12032
+ span: _enum(ROLLING_SPANS),
12033
+ customMinutes: number().int().min(5).optional()
12034
+ }).check((payload) => {
12035
+ if (payload.value.span === "custom" && payload.value.customMinutes === void 0) payload.issues.push({
12036
+ code: "custom",
12037
+ message: "a custom range needs a duration in minutes",
12038
+ path: ["customMinutes"],
12039
+ input: payload.value
12040
+ });
12041
+ if (payload.value.span !== "custom" && payload.value.customMinutes !== void 0) payload.issues.push({
12042
+ code: "custom",
12043
+ message: "only a custom range carries a duration",
12044
+ path: ["customMinutes"],
12045
+ input: payload.value
12046
+ });
12047
+ });
12048
+ var RollingWindowSchema = rollingWindowObject;
12049
+ var StatisticWindowSchema = discriminatedUnion("kind", [rollingWindowObject, object({
12050
+ kind: literal("calendar"),
12051
+ period: _enum(CALENDAR_PERIODS)
12052
+ })]);
12053
+ /**
11964
12054
  * A composition source identity: `(addonId, stableId)`, never a numeric device
11965
12055
  * id. Split out so helper schemas can name it without a cycle through
11966
12056
  * `composition.ts` (D659).
@@ -11986,7 +12076,13 @@ var GROUP_TEMPLATE_IDS = [
11986
12076
  "occupancy",
11987
12077
  "binary",
11988
12078
  "switch",
11989
- "light"
12079
+ "light",
12080
+ "fan",
12081
+ "cover",
12082
+ "valve",
12083
+ "lock",
12084
+ "media-player",
12085
+ "climate"
11990
12086
  ];
11991
12087
  var NUMERIC_AGGREGATES = [
11992
12088
  "mean",
@@ -12016,22 +12112,73 @@ var HelperMemberSchema = object({
12016
12112
  cap: string().min(1),
12017
12113
  fieldPath: string().min(1)
12018
12114
  });
12019
- var HelperSpecSchema = discriminatedUnion("kind", [object({
12020
- kind: literal("group"),
12021
- templateId: GroupTemplateIdSchema,
12022
- aggregate: AggregateReducerSchema,
12023
- members: array(HelperMemberSchema).min(1).max(64),
12024
- /** Actuator groups only. Readings leave this unset. */
12025
- active: ActiveCriterionSchema.optional()
12026
- }), object({
12027
- kind: literal("appliance"),
12028
- templateId: literal(APPLIANCE_TEMPLATE_ID),
12029
- appliance: _enum(APPLIANCE_KINDS),
12030
- thresholdWatts: number().positive(),
12031
- startDwellMs: number().int().nonnegative(),
12032
- stopDwellMs: number().int().nonnegative(),
12033
- member: HelperMemberSchema
12034
- })]);
12115
+ var HelperSpecSchema = discriminatedUnion("kind", [
12116
+ object({
12117
+ kind: literal("group"),
12118
+ templateId: GroupTemplateIdSchema,
12119
+ aggregate: AggregateReducerSchema,
12120
+ members: array(HelperMemberSchema).min(1).max(64),
12121
+ /** Actuator groups only. Readings leave this unset. */
12122
+ active: ActiveCriterionSchema.optional()
12123
+ }),
12124
+ object({
12125
+ kind: literal("appliance"),
12126
+ templateId: literal(APPLIANCE_TEMPLATE_ID),
12127
+ appliance: _enum(APPLIANCE_KINDS),
12128
+ thresholdWatts: number().positive(),
12129
+ startDwellMs: number().int().nonnegative(),
12130
+ stopDwellMs: number().int().nonnegative(),
12131
+ member: HelperMemberSchema
12132
+ }),
12133
+ object({
12134
+ kind: literal("statistic"),
12135
+ stat: _enum(STATISTIC_STATS),
12136
+ window: StatisticWindowSchema,
12137
+ source: HelperMemberSchema
12138
+ }),
12139
+ object({
12140
+ kind: literal("integral"),
12141
+ reset: _enum(RESET_PERIODS),
12142
+ output: _enum(["energy", "meter"]),
12143
+ source: HelperMemberSchema
12144
+ }),
12145
+ object({
12146
+ kind: literal("threshold"),
12147
+ source: HelperMemberSchema,
12148
+ high: number(),
12149
+ low: number(),
12150
+ onForMs: number().int().nonnegative(),
12151
+ offForMs: number().int().nonnegative()
12152
+ }),
12153
+ object({
12154
+ kind: literal("arithmetic"),
12155
+ op: _enum([
12156
+ "sum",
12157
+ "difference",
12158
+ "ratio"
12159
+ ]),
12160
+ inputs: array(HelperMemberSchema).min(2).max(64)
12161
+ }),
12162
+ object({
12163
+ kind: literal("expression"),
12164
+ expr: string().min(1),
12165
+ inputs: array(object({
12166
+ name: string().min(1),
12167
+ member: HelperMemberSchema
12168
+ })).min(1).max(64),
12169
+ output: _enum(["number", "boolean"])
12170
+ }),
12171
+ object({
12172
+ kind: literal("derivative"),
12173
+ window: RollingWindowSchema,
12174
+ per: _enum([
12175
+ "second",
12176
+ "minute",
12177
+ "hour"
12178
+ ]),
12179
+ source: HelperMemberSchema
12180
+ })
12181
+ ]);
12035
12182
  /** A composed device's stableId is this prefix plus the block id. */
12036
12183
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
12037
12184
  /** Longest snippet a `code` source may carry (slice 4). */
@@ -12092,6 +12239,12 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12092
12239
  "all"
12093
12240
  ]),
12094
12241
  reads: array(CompositionFieldReadSchema).min(1).max(64),
12242
+ /**
12243
+ * Set when the reads are an enum state, not a yes/no: the listed states
12244
+ * count as active (a cover is `open`). A state outside the list is inactive;
12245
+ * a read that is not a state at all is left out. Only `any` / `all` use it.
12246
+ */
12247
+ activeWhen: array(string().min(1)).min(1).optional(),
12095
12248
  /** `value` is the reading; the others are the member counts. */
12096
12249
  publish: _enum([
12097
12250
  "value",
@@ -12105,6 +12258,26 @@ var CompositionFieldSourceSchema = discriminatedUnion("kind", [
12105
12258
  "omit",
12106
12259
  "offline"
12107
12260
  ])
12261
+ }),
12262
+ object({
12263
+ kind: literal("series"),
12264
+ read: CompositionFieldReadSchema,
12265
+ /** `value` is the statistic or the integral. The others are the gap counts. */
12266
+ publish: _enum([
12267
+ "value",
12268
+ "included",
12269
+ "excluded",
12270
+ "total"
12271
+ ]),
12272
+ /**
12273
+ * What an unanswered `value` does. Counts ignore this. `offline` leaves the
12274
+ * device unseeded until history answers, so a restart cannot publish 0.
12275
+ */
12276
+ empty: _enum([
12277
+ "null",
12278
+ "omit",
12279
+ "offline"
12280
+ ])
12108
12281
  })
12109
12282
  ]);
12110
12283
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
@@ -18419,7 +18592,8 @@ var CompositionProblemSchema = object({
18419
18592
  "native-capability-replace",
18420
18593
  "mixed-quantity",
18421
18594
  "helper-mismatch",
18422
- "member-constraint"
18595
+ "member-constraint",
18596
+ "retention"
18423
18597
  ]),
18424
18598
  path: string(),
18425
18599
  message: string()
@@ -18653,13 +18827,17 @@ Object.freeze({
18653
18827
  latchedAt: {
18654
18828
  kind: "fixed",
18655
18829
  result: ["number", "null"]
18830
+ },
18831
+ schmitt: {
18832
+ kind: "fixed",
18833
+ result: ["boolean", "null"]
18656
18834
  }
18657
18835
  });
18658
18836
  /**
18659
18837
  * One catalog row per base reading a group helper can build (D944 §3).
18660
18838
  * Data, not a form default written into the block.
18661
18839
  */
18662
- var NOW = {
18840
+ var NOW$2 = {
18663
18841
  fieldPath: "lastFetchedAt",
18664
18842
  expr: "now"
18665
18843
  };
@@ -18673,6 +18851,8 @@ function numeric(input) {
18673
18851
  family: "numeric",
18674
18852
  deviceType: DeviceType.Sensor,
18675
18853
  memberDeviceType: DeviceType.Sensor,
18854
+ memberDeviceTypes: [DeviceType.Sensor],
18855
+ activeWhen: void 0,
18676
18856
  commandCaps: [],
18677
18857
  baseUnit: baseUnitOf(input.quantity),
18678
18858
  aggregates: NUMERIC_AGGREGATES,
@@ -18688,6 +18868,8 @@ function binary(input) {
18688
18868
  family: "binary",
18689
18869
  deviceType: DeviceType.Sensor,
18690
18870
  memberDeviceType: DeviceType.Sensor,
18871
+ memberDeviceTypes: [DeviceType.Sensor],
18872
+ activeWhen: void 0,
18691
18873
  commandCaps: [],
18692
18874
  quantity: "none",
18693
18875
  baseUnit: void 0,
@@ -18705,7 +18887,7 @@ var GROUP_TEMPLATES = [
18705
18887
  quantity: "temperature",
18706
18888
  defaultAggregate: "mean",
18707
18889
  empty: "null",
18708
- companions: [NOW]
18890
+ companions: [NOW$2]
18709
18891
  }),
18710
18892
  numeric({
18711
18893
  id: "humidity",
@@ -18716,7 +18898,7 @@ var GROUP_TEMPLATES = [
18716
18898
  quantity: "humidity",
18717
18899
  defaultAggregate: "mean",
18718
18900
  empty: "null",
18719
- companions: [NOW]
18901
+ companions: [NOW$2]
18720
18902
  }),
18721
18903
  numeric({
18722
18904
  id: "pressure",
@@ -18727,7 +18909,7 @@ var GROUP_TEMPLATES = [
18727
18909
  quantity: "pressure",
18728
18910
  defaultAggregate: "mean",
18729
18911
  empty: "null",
18730
- companions: [NOW]
18912
+ companions: [NOW$2]
18731
18913
  }),
18732
18914
  numeric({
18733
18915
  id: "illuminance",
@@ -18738,7 +18920,7 @@ var GROUP_TEMPLATES = [
18738
18920
  quantity: "illuminance",
18739
18921
  defaultAggregate: "mean",
18740
18922
  empty: "null",
18741
- companions: [NOW]
18923
+ companions: [NOW$2]
18742
18924
  }),
18743
18925
  numeric({
18744
18926
  id: "power",
@@ -18749,7 +18931,7 @@ var GROUP_TEMPLATES = [
18749
18931
  quantity: "power",
18750
18932
  defaultAggregate: "sum",
18751
18933
  empty: "omit",
18752
- companions: [NOW]
18934
+ companions: [NOW$2]
18753
18935
  }),
18754
18936
  numeric({
18755
18937
  id: "energy",
@@ -18760,7 +18942,7 @@ var GROUP_TEMPLATES = [
18760
18942
  quantity: "energy",
18761
18943
  defaultAggregate: "sum",
18762
18944
  empty: "omit",
18763
- companions: [NOW]
18945
+ companions: [NOW$2]
18764
18946
  }),
18765
18947
  numeric({
18766
18948
  id: "battery",
@@ -18795,7 +18977,7 @@ var GROUP_TEMPLATES = [
18795
18977
  quantity: "device",
18796
18978
  defaultAggregate: "mean",
18797
18979
  empty: "null",
18798
- companions: [NOW]
18980
+ companions: [NOW$2]
18799
18981
  }),
18800
18982
  binary({
18801
18983
  id: "motion",
@@ -18889,6 +19071,11 @@ var GROUP_TEMPLATES = [
18889
19071
  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.",
18890
19072
  deviceType: DeviceType.Switch,
18891
19073
  outputCap: "switch",
19074
+ outputField: "on",
19075
+ member: {
19076
+ cap: "switch",
19077
+ fieldPath: "on"
19078
+ },
18892
19079
  commandCaps: ["switch"]
18893
19080
  }),
18894
19081
  actuator({
@@ -18896,34 +19083,136 @@ var GROUP_TEMPLATES = [
18896
19083
  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.",
18897
19084
  deviceType: DeviceType.Light,
18898
19085
  outputCap: "switch",
19086
+ outputField: "on",
19087
+ member: {
19088
+ cap: "switch",
19089
+ fieldPath: "on"
19090
+ },
18899
19091
  commandCaps: [
18900
19092
  "switch",
18901
19093
  "brightness",
18902
19094
  "color"
18903
19095
  ]
19096
+ }),
19097
+ actuator({
19098
+ id: "fan",
19099
+ 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.",
19100
+ deviceType: DeviceType.Fan,
19101
+ outputCap: "switch",
19102
+ outputField: "on",
19103
+ member: {
19104
+ cap: "switch",
19105
+ fieldPath: "on"
19106
+ },
19107
+ commandCaps: ["switch", "fan-control"]
19108
+ }),
19109
+ actuator({
19110
+ id: "cover",
19111
+ 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.",
19112
+ deviceType: DeviceType.Cover,
19113
+ outputCap: "group-active",
19114
+ outputField: "active",
19115
+ member: {
19116
+ cap: "cover",
19117
+ fieldPath: "state"
19118
+ },
19119
+ activeWhen: [
19120
+ "open",
19121
+ "opening",
19122
+ "stopped"
19123
+ ],
19124
+ commandCaps: ["cover"]
19125
+ }),
19126
+ actuator({
19127
+ id: "valve",
19128
+ 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.",
19129
+ deviceType: DeviceType.Valve,
19130
+ outputCap: "group-active",
19131
+ outputField: "active",
19132
+ member: {
19133
+ cap: "valve",
19134
+ fieldPath: "state"
19135
+ },
19136
+ activeWhen: [
19137
+ "open",
19138
+ "opening",
19139
+ "stopped"
19140
+ ],
19141
+ commandCaps: ["valve"]
19142
+ }),
19143
+ actuator({
19144
+ id: "lock",
19145
+ 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.",
19146
+ deviceType: DeviceType.Lock,
19147
+ outputCap: "group-active",
19148
+ outputField: "active",
19149
+ member: {
19150
+ cap: "lock-control",
19151
+ fieldPath: "state"
19152
+ },
19153
+ activeWhen: ["locked"],
19154
+ commandCaps: ["lock-control"]
19155
+ }),
19156
+ actuator({
19157
+ id: "media-player",
19158
+ 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.",
19159
+ deviceType: DeviceType.MediaPlayer,
19160
+ outputCap: "group-active",
19161
+ outputField: "active",
19162
+ member: {
19163
+ cap: "media-player",
19164
+ fieldPath: "state"
19165
+ },
19166
+ activeWhen: ["playing", "buffering"],
19167
+ commandCaps: ["media-player"]
19168
+ }),
19169
+ actuator({
19170
+ id: "climate",
19171
+ 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.",
19172
+ deviceType: DeviceType.Thermostat,
19173
+ memberDeviceTypes: [DeviceType.Thermostat, DeviceType.Climate],
19174
+ outputCap: "group-active",
19175
+ outputField: "active",
19176
+ member: {
19177
+ cap: "climate-control",
19178
+ fieldPath: "mode"
19179
+ },
19180
+ activeWhen: [
19181
+ "heat",
19182
+ "cool",
19183
+ "auto",
19184
+ "heat_cool",
19185
+ "fan_only",
19186
+ "dry"
19187
+ ],
19188
+ commandCaps: ["climate-control"]
18904
19189
  })
18905
19190
  ];
18906
19191
  function actuator(input) {
18907
19192
  return {
18908
- ...input,
19193
+ id: input.id,
19194
+ summary: input.summary,
19195
+ deviceType: input.deviceType,
19196
+ outputCap: input.outputCap,
19197
+ outputField: input.outputField,
19198
+ commandCaps: input.commandCaps,
18909
19199
  family: "actuator",
18910
19200
  role: void 0,
18911
19201
  memberDeviceType: input.deviceType,
18912
- outputField: "on",
19202
+ memberDeviceTypes: input.memberDeviceTypes ?? [input.deviceType],
19203
+ activeWhen: input.activeWhen,
18913
19204
  quantity: "none",
18914
19205
  baseUnit: void 0,
18915
19206
  aggregates: BINARY_AGGREGATES,
18916
19207
  defaultAggregate: "any",
18917
19208
  empty: "offline",
18918
- accept: [{
18919
- cap: "switch",
18920
- fieldPath: "on"
18921
- }],
19209
+ accept: [input.member],
18922
19210
  companions: [CHANGED]
18923
19211
  };
18924
19212
  }
18925
19213
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
18926
19214
  DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
19215
+ DeviceType.Camera;
18927
19216
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
18928
19217
  /**
18929
19218
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -46615,7 +46904,20 @@ var NcRuleInputSchema = object({
46615
46904
  * save by the hub's grouping guard). `.optional()`, never `.default()`: the addon cap
46616
46905
  * path does not run Zod defaults.
46617
46906
  */
46618
- groupingSec: number().int().min(5).max(60).optional()
46907
+ groupingSec: number().int().min(5).max(60).optional(),
46908
+ /**
46909
+ * ASK ME TO CONFIRM DETECTIONS (#243): a DETECTION notification of this rule
46910
+ * carries "Correct" / "Wrong" buttons (and, where the channel has room, a
46911
+ * "Wrong, it is a <class>" choice). A tap marks the track for retraining, the
46912
+ * same mark the Library writes, and records whose notification it was and
46913
+ * when. A channel with no buttons gets the same two choices as links.
46914
+ *
46915
+ * `.optional()`, never `.default()` (a Zod default does not run on the addon
46916
+ * cap path): absent and `false` both mean off, which is what every rule
46917
+ * authored before this field meant. An editor turns it off by writing
46918
+ * `false`, so it needs no `clear` key.
46919
+ */
46920
+ askVerdict: boolean().optional()
46619
46921
  });
46620
46922
  /**
46621
46923
  * Partial patch for `updateRule` — any subset of the input fields, plus the
@@ -58816,7 +59118,13 @@ results: array(object({
58816
59118
  /** Ms epoch of the attempt. */
58817
59119
  at: number()
58818
59120
  })) });
58819
- DeviceType.Switch, DeviceType.Light;
59121
+ DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
59122
+ object({
59123
+ active: boolean().meta({ label: "Active" }),
59124
+ /** Ms epoch when the slice was last updated. */
59125
+ lastChangedAt: number()
59126
+ });
59127
+ DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Climate, DeviceType.Thermostat;
58820
59128
  object({
58821
59129
  /** Members whose current value entered the aggregate. */
58822
59130
  included: number().int().nonnegative().meta(readingMeta("count", {
@@ -58834,7 +59142,7 @@ object({
58834
59142
  label: "Members"
58835
59143
  }))
58836
59144
  });
58837
- DeviceType.Sensor, DeviceType.Switch, DeviceType.Light;
59145
+ DeviceType.Sensor, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Cover, DeviceType.Valve, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.Thermostat, DeviceType.Climate;
58838
59146
  object({
58839
59147
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
58840
59148
  position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -59741,7 +60049,14 @@ DeviceType.Lock, method(object({
59741
60049
  auth: "protected"
59742
60050
  }), method(object({
59743
60051
  deviceId: number().int().nonnegative(),
59744
- code: string().min(1).optional()
60052
+ code: string().min(1).optional(),
60053
+ /**
60054
+ * Honoured by a helper lock GROUP only (D944): unlocking several doors
60055
+ * with one call is refused unless the caller says it was confirmed. A
60056
+ * single lock ignores it. The refusal lives in the callee, so no
60057
+ * automation or API caller reaches the doors by skipping a dialog.
60058
+ */
60059
+ confirm: boolean().optional()
59745
60060
  }), _void(), {
59746
60061
  kind: "mutation",
59747
60062
  auth: "protected"
@@ -59749,6 +60064,11 @@ DeviceType.Lock, method(object({
59749
60064
  kind: "mutation",
59750
60065
  auth: "protected"
59751
60066
  });
60067
+ object({
60068
+ value: number().nullable().meta(readingMeta("device", { label: "Total" })),
60069
+ lastFetchedAt: number()
60070
+ });
60071
+ DeviceType.Sensor;
59752
60072
  /**
59753
60073
  * Media-player cap. Models HA `media_player.*` (Sonos, Chromecast,
59754
60074
  * Apple TV, Spotify, Roku, generic OTT receivers, …) on
@@ -64152,7 +64472,7 @@ object({
64152
64472
  /** Ms epoch of the last state change. Useful for UI "X minutes ago". */
64153
64473
  lastChangedAt: number()
64154
64474
  });
64155
- DeviceType.Switch, DeviceType.Siren, DeviceType.Light, method(object({
64475
+ DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, method(object({
64156
64476
  deviceId: number(),
64157
64477
  on: boolean()
64158
64478
  }), _void(), {
@@ -65844,6 +66164,7 @@ method(object({}), array(TrainingBaseModelSchema).readonly(), { auth: "admin" })
65844
66164
  kind: "mutation",
65845
66165
  auth: "admin"
65846
66166
  });
66167
+ DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
65847
66168
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
65848
66169
  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;
65849
66170
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
@@ -69219,6 +69540,13 @@ Object.freeze({
69219
69540
  access: "view",
69220
69541
  role: "viewer"
69221
69542
  },
69543
+ "groupActive.getStatus": {
69544
+ capName: "group-active",
69545
+ capScope: "device",
69546
+ addonId: null,
69547
+ access: "view",
69548
+ role: "viewer"
69549
+ },
69222
69550
  "groupCommands.getStatus": {
69223
69551
  capName: "group-commands",
69224
69552
  capScope: "device",
@@ -70185,6 +70513,13 @@ Object.freeze({
70185
70513
  access: "create",
70186
70514
  role: "admin"
70187
70515
  },
70516
+ "meter.getStatus": {
70517
+ capName: "meter",
70518
+ capScope: "device",
70519
+ addonId: null,
70520
+ access: "view",
70521
+ role: "viewer"
70522
+ },
70188
70523
  "metricsProvider.collectSnapshot": {
70189
70524
  capName: "metrics-provider",
70190
70525
  capScope: "system",
@@ -79087,6 +79422,10 @@ var SENSOR_CAP_VOCABULARY = {
79087
79422
  icon: "flame"
79088
79423
  }]
79089
79424
  },
79425
+ "group-active": {
79426
+ scope: "device",
79427
+ noun: t("Group state", "Stato del gruppo")
79428
+ },
79090
79429
  "group-commands": {
79091
79430
  scope: "device",
79092
79431
  noun: t("Group command", "Comando di gruppo")
@@ -79143,6 +79482,17 @@ var SENSOR_CAP_VOCABULARY = {
79143
79482
  }],
79144
79483
  events: { onMotionChanged: { notOperatorFacing: "the `detected` state trigger phrases both edges, from the mirror that survives a dropped event (D49)" } }
79145
79484
  },
79485
+ meter: {
79486
+ scope: "device",
79487
+ noun: t("Meter", "Contatore"),
79488
+ state: [{
79489
+ kind: "numeric",
79490
+ field: "value",
79491
+ quantity: t("the total", "il totale"),
79492
+ label: t("Total", "Totale"),
79493
+ icon: "gauge"
79494
+ }]
79495
+ },
79146
79496
  "numeric-sensor": {
79147
79497
  scope: "device",
79148
79498
  noun: t("Sensor", "Sensore"),
@@ -80622,6 +80972,11 @@ Object.freeze({
80622
80972
  form: "single",
80623
80973
  optional: false
80624
80974
  }],
80975
+ "groupActive.getStatus": [{
80976
+ name: "deviceId",
80977
+ form: "single",
80978
+ optional: false
80979
+ }],
80625
80980
  "groupCommands.getStatus": [{
80626
80981
  name: "deviceId",
80627
80982
  form: "single",
@@ -80832,6 +81187,11 @@ Object.freeze({
80832
81187
  form: "single",
80833
81188
  optional: false
80834
81189
  }],
81190
+ "meter.getStatus": [{
81191
+ name: "deviceId",
81192
+ form: "single",
81193
+ optional: false
81194
+ }],
80835
81195
  "motion.getStatus": [{
80836
81196
  name: "deviceId",
80837
81197
  form: "single",
@@ -82439,7 +82799,6 @@ Object.freeze({
82439
82799
  "network-access": "ingress",
82440
82800
  "smtp-provider": "email"
82441
82801
  });
82442
- DeviceType.Camera;
82443
82802
  /**
82444
82803
  * A saved Customize assignment (D936). The schema is the type: callers use
82445
82804
  * `z.infer`, they do not restate the shape.