@camstack/addon-provider-ecowitt 0.2.147 → 0.2.148

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
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let http = require("http");
3
3
  let events = require("events");
4
4
  let dgram = require("dgram");
5
- //#region ../types/dist/event-category-DHXxB8t9.mjs
5
+ //#region ../types/dist/event-category-CT-hz5Rb.mjs
6
6
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
7
7
  EventCategory["SystemBoot"] = "system.boot";
8
8
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -328,6 +328,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
328
328
  /** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
329
329
  EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
330
330
  /**
331
+ * A camera's package LLM confirm has failed closed three times in a row
332
+ * (D931, 2026-10-26). One edge per camera until
333
+ * {@link PipelinePackageLlmAnswered}.
334
+ */
335
+ EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
336
+ /** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
337
+ EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
338
+ /**
331
339
  * Per-camera pipeline config was mutated by the orchestrator
332
340
  * (a settings change via `setAgentInferenceDevices` /
333
341
  * `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
@@ -5437,7 +5445,7 @@ var ZodIssueCode$1 = {
5437
5445
  var ZodFirstPartyTypeKind$1;
5438
5446
  ZodFirstPartyTypeKind$1 || (ZodFirstPartyTypeKind$1 = {});
5439
5447
  //#endregion
5440
- //#region ../types/dist/sleep-CARd6wZF.mjs
5448
+ //#region ../types/dist/sleep-bykKrTgu.mjs
5441
5449
  /**
5442
5450
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5443
5451
  * window to float samples (D455).
@@ -8630,6 +8638,8 @@ var CAP_NAMES = Object.freeze([
8630
8638
  "filesystem-browse",
8631
8639
  "flood",
8632
8640
  "gas",
8641
+ "group-commands",
8642
+ "group-status",
8633
8643
  "heating-valve",
8634
8644
  "humidifier",
8635
8645
  "humidity-sensor",
@@ -9448,6 +9458,20 @@ Object.freeze({
9448
9458
  "path": "detected",
9449
9459
  "valueType": "boolean"
9450
9460
  }],
9461
+ "group-status": [
9462
+ {
9463
+ "path": "included",
9464
+ "valueType": "number"
9465
+ },
9466
+ {
9467
+ "path": "excluded",
9468
+ "valueType": "number"
9469
+ },
9470
+ {
9471
+ "path": "total",
9472
+ "valueType": "number"
9473
+ }
9474
+ ],
9451
9475
  "heating-valve": [{
9452
9476
  "path": "position",
9453
9477
  "valueType": "number"
@@ -10803,7 +10827,7 @@ function errMsg(err) {
10803
10827
  return String(err);
10804
10828
  }
10805
10829
  //#endregion
10806
- //#region ../types/dist/composition-kEl9mevu.mjs
10830
+ //#region ../types/dist/composition-OhpuespA.mjs
10807
10831
  /**
10808
10832
  * The ffmpeg build every CamStack node downloads, per platform and arch.
10809
10833
  *
@@ -11558,15 +11582,74 @@ function validateExpressionSource(src) {
11558
11582
  }
11559
11583
  return null;
11560
11584
  }
11561
- /** A composed device's stableId is this prefix plus the block id. */
11562
- var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
11563
- /** Longest snippet a `code` source may carry (slice 4). */
11564
- var MAX_COMPOSITION_CODE_LENGTH = 2e4;
11585
+ /**
11586
+ * A composition source identity: `(addonId, stableId)`, never a numeric device
11587
+ * id. Split out so helper schemas can name it without a cycle through
11588
+ * `composition.ts` (D659).
11589
+ */
11565
11590
  var CompositionSourceRefSchema = object({
11566
11591
  /** The owning addon; `stableId` is unique only within it. */
11567
11592
  addonId: string().min(1),
11568
11593
  stableId: string().min(1)
11569
11594
  });
11595
+ var GROUP_TEMPLATE_IDS = [
11596
+ "temperature",
11597
+ "humidity",
11598
+ "pressure",
11599
+ "illuminance",
11600
+ "power",
11601
+ "energy",
11602
+ "battery",
11603
+ "numeric",
11604
+ "motion",
11605
+ "contact",
11606
+ "leak",
11607
+ "smoke",
11608
+ "occupancy",
11609
+ "binary",
11610
+ "switch",
11611
+ "light"
11612
+ ];
11613
+ var NUMERIC_AGGREGATES = [
11614
+ "mean",
11615
+ "median",
11616
+ "min",
11617
+ "max",
11618
+ "sum"
11619
+ ];
11620
+ var BINARY_AGGREGATES = ["any", "all"];
11621
+ /** How an actuator group decides it is on. Unknown members never count as off. */
11622
+ var ACTIVE_CRITERIA = ["at-least-one", "all"];
11623
+ var AGGREGATE_REDUCERS = [
11624
+ "mean",
11625
+ "median",
11626
+ "min",
11627
+ "max",
11628
+ "sum",
11629
+ "any",
11630
+ "all"
11631
+ ];
11632
+ var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
11633
+ var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
11634
+ var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
11635
+ /** One member. The field is stored so occupancy can name motion or binary. */
11636
+ var HelperMemberSchema = object({
11637
+ source: CompositionSourceRefSchema,
11638
+ cap: string().min(1),
11639
+ fieldPath: string().min(1)
11640
+ });
11641
+ var HelperSpecSchema = discriminatedUnion("kind", [object({
11642
+ kind: literal("group"),
11643
+ templateId: GroupTemplateIdSchema,
11644
+ aggregate: AggregateReducerSchema,
11645
+ members: array(HelperMemberSchema).min(1).max(64),
11646
+ /** Actuator groups only. Readings leave this unset. */
11647
+ active: ActiveCriterionSchema.optional()
11648
+ })]);
11649
+ /** A composed device's stableId is this prefix plus the block id. */
11650
+ var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
11651
+ /** Longest snippet a `code` source may carry (slice 4). */
11652
+ var MAX_COMPOSITION_CODE_LENGTH = 2e4;
11570
11653
  /** One field of one capability of one source device. */
11571
11654
  var CompositionFieldReadSchema = object({
11572
11655
  source: CompositionSourceRefSchema,
@@ -11610,7 +11693,33 @@ var CompositionCodeSourceSchema = object({
11610
11693
  var CompositionFieldSourceSchema = discriminatedUnion("kind", [
11611
11694
  CompositionFromSourceSchema,
11612
11695
  CompositionExpressionSourceSchema,
11613
- CompositionCodeSourceSchema
11696
+ CompositionCodeSourceSchema,
11697
+ object({
11698
+ kind: literal("aggregate"),
11699
+ reducer: _enum([
11700
+ "mean",
11701
+ "median",
11702
+ "min",
11703
+ "max",
11704
+ "sum",
11705
+ "any",
11706
+ "all"
11707
+ ]),
11708
+ reads: array(CompositionFieldReadSchema).min(1).max(64),
11709
+ /** `value` is the reading; the others are the member counts. */
11710
+ publish: _enum([
11711
+ "value",
11712
+ "included",
11713
+ "excluded",
11714
+ "total"
11715
+ ]),
11716
+ /** What a `value` publish does when nobody is included. Counts ignore this. */
11717
+ empty: _enum([
11718
+ "null",
11719
+ "omit",
11720
+ "offline"
11721
+ ])
11722
+ })
11614
11723
  ]);
11615
11724
  var CompositionCommandTargetSchema = discriminatedUnion("kind", [object({
11616
11725
  kind: literal("forward"),
@@ -11656,7 +11765,13 @@ var CompositionSchema = object({
11656
11765
  kind: literal("existing"),
11657
11766
  device: CompositionSourceRefSchema
11658
11767
  })]),
11659
- features: array(CompositionFeatureSchema).min(1).max(16)
11768
+ features: array(CompositionFeatureSchema).min(1).max(16),
11769
+ /**
11770
+ * Present when the block is a helper template. Absent on a free
11771
+ * composition (the room example, device 4603). The editor reads this,
11772
+ * never the compiled features.
11773
+ */
11774
+ helper: HelperSpecSchema.optional()
11660
11775
  }).superRefine((composition, ctx) => {
11661
11776
  const seen = /* @__PURE__ */ new Set();
11662
11777
  composition.features.forEach((feature, index) => {
@@ -17865,7 +17980,10 @@ var CompositionProblemSchema = object({
17865
17980
  "target-missing",
17866
17981
  "target-unreadable",
17867
17982
  "not-replaceable",
17868
- "native-capability-replace"
17983
+ "native-capability-replace",
17984
+ "mixed-quantity",
17985
+ "helper-mismatch",
17986
+ "member-constraint"
17869
17987
  ]),
17870
17988
  path: string(),
17871
17989
  message: string()
@@ -17886,7 +18004,8 @@ var CompositionUnavailableModeSchema = _enum([
17886
18004
  "null",
17887
18005
  "offline",
17888
18006
  "unknown",
17889
- "release"
18007
+ "release",
18008
+ "omit"
17890
18009
  ]);
17891
18010
  /**
17892
18011
  * `derived` reads a source · `clock` reads only `now`, recomputed when a sibling
@@ -18100,6 +18219,275 @@ Object.freeze({
18100
18219
  result: ["number", "null"]
18101
18220
  }
18102
18221
  });
18222
+ /**
18223
+ * One catalog row per base reading a group helper can build (D944 §3).
18224
+ * Data, not a form default written into the block.
18225
+ */
18226
+ var NOW = {
18227
+ fieldPath: "lastFetchedAt",
18228
+ expr: "now"
18229
+ };
18230
+ var CHANGED = {
18231
+ fieldPath: "lastChangedAt",
18232
+ expr: "now"
18233
+ };
18234
+ function numeric(input) {
18235
+ return {
18236
+ ...input,
18237
+ family: "numeric",
18238
+ deviceType: DeviceType.Sensor,
18239
+ memberDeviceType: DeviceType.Sensor,
18240
+ commandCaps: [],
18241
+ baseUnit: baseUnitOf(input.quantity),
18242
+ aggregates: NUMERIC_AGGREGATES,
18243
+ accept: [{
18244
+ cap: input.outputCap,
18245
+ fieldPath: input.outputField
18246
+ }]
18247
+ };
18248
+ }
18249
+ function binary(input) {
18250
+ return {
18251
+ ...input,
18252
+ family: "binary",
18253
+ deviceType: DeviceType.Sensor,
18254
+ memberDeviceType: DeviceType.Sensor,
18255
+ commandCaps: [],
18256
+ quantity: "none",
18257
+ baseUnit: void 0,
18258
+ aggregates: BINARY_AGGREGATES,
18259
+ empty: "offline"
18260
+ };
18261
+ }
18262
+ var GROUP_TEMPLATES = [
18263
+ numeric({
18264
+ id: "temperature",
18265
+ summary: "Mean, median, min, max or sum of temperatures. Offline and unknown members are left out, never read as 0 °C.",
18266
+ role: DeviceRole.TemperatureSensor,
18267
+ outputCap: "temperature-sensor",
18268
+ outputField: "celsius",
18269
+ quantity: "temperature",
18270
+ defaultAggregate: "mean",
18271
+ empty: "null",
18272
+ companions: [NOW]
18273
+ }),
18274
+ numeric({
18275
+ id: "humidity",
18276
+ summary: "Humidity in percent. Offline and unknown members are left out, never read as 0 %.",
18277
+ role: DeviceRole.HumiditySensor,
18278
+ outputCap: "humidity-sensor",
18279
+ outputField: "percent",
18280
+ quantity: "humidity",
18281
+ defaultAggregate: "mean",
18282
+ empty: "null",
18283
+ companions: [NOW]
18284
+ }),
18285
+ numeric({
18286
+ id: "pressure",
18287
+ summary: "Pressure in hectopascals. Offline and unknown members are left out, never read as 0 hPa.",
18288
+ role: DeviceRole.PressureSensor,
18289
+ outputCap: "pressure-sensor",
18290
+ outputField: "hpa",
18291
+ quantity: "pressure",
18292
+ defaultAggregate: "mean",
18293
+ empty: "null",
18294
+ companions: [NOW]
18295
+ }),
18296
+ numeric({
18297
+ id: "illuminance",
18298
+ summary: "Illuminance in lux. Offline and unknown members are left out, never read as 0 lx.",
18299
+ role: DeviceRole.AmbientLightSensor,
18300
+ outputCap: "ambient-light-sensor",
18301
+ outputField: "lux",
18302
+ quantity: "illuminance",
18303
+ defaultAggregate: "mean",
18304
+ empty: "null",
18305
+ companions: [NOW]
18306
+ }),
18307
+ numeric({
18308
+ id: "power",
18309
+ summary: "Power in watts, summed by default. Nobody reporting omits the key rather than writing 0 W.",
18310
+ role: DeviceRole.PowerSensor,
18311
+ outputCap: "power-meter",
18312
+ outputField: "watts",
18313
+ quantity: "power",
18314
+ defaultAggregate: "sum",
18315
+ empty: "omit",
18316
+ companions: [NOW]
18317
+ }),
18318
+ numeric({
18319
+ id: "energy",
18320
+ summary: "Energy in kilowatt-hours, summed by default. Nobody reporting omits the key rather than writing 0 kWh.",
18321
+ role: DeviceRole.EnergySensor,
18322
+ outputCap: "power-meter",
18323
+ outputField: "kwhTotal",
18324
+ quantity: "energy",
18325
+ defaultAggregate: "sum",
18326
+ empty: "omit",
18327
+ companions: [NOW]
18328
+ }),
18329
+ numeric({
18330
+ id: "battery",
18331
+ summary: "Battery charge in percent. Offline and unknown members are left out, never read as 0 %.",
18332
+ role: DeviceRole.BatterySensor,
18333
+ outputCap: "battery",
18334
+ outputField: "percentage",
18335
+ quantity: "percentage",
18336
+ defaultAggregate: "mean",
18337
+ empty: "null",
18338
+ companions: [
18339
+ {
18340
+ fieldPath: "charging",
18341
+ expr: "\"unknown\""
18342
+ },
18343
+ {
18344
+ fieldPath: "sleeping",
18345
+ expr: "false"
18346
+ },
18347
+ {
18348
+ fieldPath: "lastUpdated",
18349
+ expr: "now"
18350
+ }
18351
+ ]
18352
+ }),
18353
+ numeric({
18354
+ id: "numeric",
18355
+ summary: "A numeric reading in the members’ shared quantity. Mixed quantities are refused. Nobody reporting publishes null, not 0.",
18356
+ role: DeviceRole.NumericSensor,
18357
+ outputCap: "numeric-sensor",
18358
+ outputField: "value",
18359
+ quantity: "device",
18360
+ defaultAggregate: "mean",
18361
+ empty: "null",
18362
+ companions: [NOW]
18363
+ }),
18364
+ binary({
18365
+ id: "motion",
18366
+ summary: "Any or all motion. Offline and unknown members are left out, never read as off. Nobody reporting takes the device offline.",
18367
+ role: DeviceRole.MotionSensor,
18368
+ outputCap: "motion",
18369
+ outputField: "detected",
18370
+ defaultAggregate: "any",
18371
+ accept: [{
18372
+ cap: "motion",
18373
+ fieldPath: "detected"
18374
+ }],
18375
+ companions: [{
18376
+ fieldPath: "lastDetectedAt",
18377
+ expr: "null"
18378
+ }, {
18379
+ fieldPath: "autoClearAfterMs",
18380
+ expr: "null"
18381
+ }]
18382
+ }),
18383
+ binary({
18384
+ id: "contact",
18385
+ summary: "Any or all open contacts. Offline and unknown members are left out, never read as closed.",
18386
+ role: DeviceRole.ContactSensor,
18387
+ outputCap: "contact",
18388
+ outputField: "entryOpen",
18389
+ defaultAggregate: "any",
18390
+ accept: [{
18391
+ cap: "contact",
18392
+ fieldPath: "entryOpen"
18393
+ }],
18394
+ companions: [CHANGED]
18395
+ }),
18396
+ binary({
18397
+ id: "leak",
18398
+ summary: "Any or all leak detections. Offline and unknown members are left out, never read as dry.",
18399
+ role: DeviceRole.LeakSensor,
18400
+ outputCap: "flood",
18401
+ outputField: "flooded",
18402
+ defaultAggregate: "any",
18403
+ accept: [{
18404
+ cap: "flood",
18405
+ fieldPath: "flooded"
18406
+ }],
18407
+ companions: [CHANGED]
18408
+ }),
18409
+ binary({
18410
+ id: "smoke",
18411
+ summary: "Any or all smoke detections. Offline and unknown members are left out, never read as clear.",
18412
+ role: DeviceRole.SmokeSensor,
18413
+ outputCap: "smoke",
18414
+ outputField: "detected",
18415
+ defaultAggregate: "any",
18416
+ accept: [{
18417
+ cap: "smoke",
18418
+ fieldPath: "detected"
18419
+ }],
18420
+ companions: [CHANGED]
18421
+ }),
18422
+ binary({
18423
+ id: "occupancy",
18424
+ summary: "Any or all of motion or binary sensors, published as a binary. Presence zones are not aggregated. Nobody reporting is offline, not off.",
18425
+ role: DeviceRole.BinarySensor,
18426
+ outputCap: "binary",
18427
+ outputField: "on",
18428
+ defaultAggregate: "any",
18429
+ accept: [{
18430
+ cap: "motion",
18431
+ fieldPath: "detected"
18432
+ }, {
18433
+ cap: "binary",
18434
+ fieldPath: "on"
18435
+ }],
18436
+ companions: [CHANGED]
18437
+ }),
18438
+ binary({
18439
+ id: "binary",
18440
+ summary: "Any or all generic binary sensors. Offline and unknown members are left out, never read as off.",
18441
+ role: DeviceRole.BinarySensor,
18442
+ outputCap: "binary",
18443
+ outputField: "on",
18444
+ defaultAggregate: "any",
18445
+ accept: [{
18446
+ cap: "binary",
18447
+ fieldPath: "on"
18448
+ }],
18449
+ companions: [CHANGED]
18450
+ }),
18451
+ actuator({
18452
+ id: "switch",
18453
+ 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.",
18454
+ deviceType: DeviceType.Switch,
18455
+ outputCap: "switch",
18456
+ commandCaps: ["switch"]
18457
+ }),
18458
+ actuator({
18459
+ id: "light",
18460
+ 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.",
18461
+ deviceType: DeviceType.Light,
18462
+ outputCap: "switch",
18463
+ commandCaps: [
18464
+ "switch",
18465
+ "brightness",
18466
+ "color"
18467
+ ]
18468
+ })
18469
+ ];
18470
+ function actuator(input) {
18471
+ return {
18472
+ ...input,
18473
+ family: "actuator",
18474
+ role: void 0,
18475
+ memberDeviceType: input.deviceType,
18476
+ outputField: "on",
18477
+ quantity: "none",
18478
+ baseUnit: void 0,
18479
+ aggregates: BINARY_AGGREGATES,
18480
+ defaultAggregate: "any",
18481
+ empty: "offline",
18482
+ accept: [{
18483
+ cap: "switch",
18484
+ fieldPath: "on"
18485
+ }],
18486
+ companions: [CHANGED]
18487
+ };
18488
+ }
18489
+ new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
18490
+ DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
18103
18491
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
18104
18492
  /**
18105
18493
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -45089,6 +45477,8 @@ var NcSystemEventKindSchema = _enum([
45089
45477
  "detection-blind",
45090
45478
  "motion-noisy",
45091
45479
  "motion-calm",
45480
+ "package-llm-silent",
45481
+ "package-llm-answered",
45092
45482
  "recording-stalled",
45093
45483
  "recording-healthy",
45094
45484
  "recording-degraded",
@@ -56180,6 +56570,28 @@ var PackageVersionInfoSchema = object({
56180
56570
  deprecated: string().optional(),
56181
56571
  distTags: array(string()).readonly()
56182
56572
  });
56573
+ /**
56574
+ * One published document. `ok` is markdown from the registry. `missing` means
56575
+ * the registry answered and the file was not there. `error` is a registry or
56576
+ * tarball failure — never an empty string standing in for either.
56577
+ */
56578
+ var PackageDocBodySchema = discriminatedUnion("status", [
56579
+ object({
56580
+ status: literal("ok"),
56581
+ markdown: string()
56582
+ }),
56583
+ object({ status: literal("missing") }),
56584
+ object({
56585
+ status: literal("error"),
56586
+ message: string()
56587
+ })
56588
+ ]);
56589
+ var PackageDocsSchema = object({
56590
+ name: string(),
56591
+ version: string(),
56592
+ readme: PackageDocBodySchema,
56593
+ changelog: PackageDocBodySchema
56594
+ });
56183
56595
  var SearchResultSchema = object({
56184
56596
  name: string(),
56185
56597
  version: string(),
@@ -56398,7 +56810,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
56398
56810
  }), object({ success: literal(true) }), {
56399
56811
  kind: "mutation",
56400
56812
  auth: "admin"
56401
- }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
56813
+ }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
56814
+ name: string().min(1),
56815
+ version: string().min(1).optional()
56816
+ }), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
56402
56817
  kind: "mutation",
56403
56818
  auth: "admin"
56404
56819
  }), method(object({ packageName: string() }), object({ success: literal(true) }), {
@@ -59717,6 +60132,88 @@ var gasCapability = {
59717
60132
  * whether persisting is worth a SQLite commit. */
59718
60133
  volatileStateFields: ["lastChangedAt"]
59719
60134
  };
60135
+ var GroupCommandsSchema = object({
60136
+ /** One row per member that has been commanded. A later command replaces that member's row. */
60137
+ results: array(object({
60138
+ deviceId: number().int().nonnegative(),
60139
+ cap: string().min(1),
60140
+ method: string().min(1),
60141
+ ok: boolean(),
60142
+ error: string().optional(),
60143
+ /** Ms epoch of the attempt. */
60144
+ at: number()
60145
+ })) });
60146
+ var groupCommandsCapability = {
60147
+ name: "group-commands",
60148
+ scope: "device",
60149
+ deviceNative: true,
60150
+ mode: "singleton",
60151
+ deviceTypes: [DeviceType.Switch, DeviceType.Light],
60152
+ methods: {},
60153
+ status: {
60154
+ schema: GroupCommandsSchema,
60155
+ kind: "push"
60156
+ },
60157
+ runtimeState: GroupCommandsSchema,
60158
+ /**
60159
+ * Runtime-state durability: **session** — the last attempt. A restored
60160
+ * failure would outlive the command that caused it.
60161
+ *
60162
+ * See `RuntimeStateDurability`. Enforced by
60163
+ * `scripts/check-runtime-state-durability.ts`.
60164
+ */
60165
+ durability: "session",
60166
+ history: "none"
60167
+ };
60168
+ /**
60169
+ * How many members of a helper group answered (D944). Counts are integers,
60170
+ * not measurements: zero included is a real count, never a stand-in reading.
60171
+ * The reading itself stays on the output capability. History is none — the
60172
+ * series that later statistics read is the output cap's own history block.
60173
+ */
60174
+ var GroupStatusSchema = object({
60175
+ /** Members whose current value entered the aggregate. */
60176
+ included: number().int().nonnegative().meta(readingMeta("count", {
60177
+ precision: 0,
60178
+ label: "Reporting"
60179
+ })),
60180
+ /** Members left out: offline, unknown, or not a finite reading (D393). */
60181
+ excluded: number().int().nonnegative().meta(readingMeta("count", {
60182
+ precision: 0,
60183
+ label: "Excluded"
60184
+ })),
60185
+ /** `included` + `excluded`. */
60186
+ total: number().int().nonnegative().meta(readingMeta("count", {
60187
+ precision: 0,
60188
+ label: "Members"
60189
+ }))
60190
+ });
60191
+ var groupStatusCapability = {
60192
+ name: "group-status",
60193
+ scope: "device",
60194
+ deviceNative: true,
60195
+ mode: "singleton",
60196
+ deviceTypes: [
60197
+ DeviceType.Sensor,
60198
+ DeviceType.Switch,
60199
+ DeviceType.Light
60200
+ ],
60201
+ methods: {},
60202
+ status: {
60203
+ schema: GroupStatusSchema,
60204
+ kind: "push"
60205
+ },
60206
+ runtimeState: GroupStatusSchema,
60207
+ /**
60208
+ * Runtime-state durability: **session** — recomputed from members on the
60209
+ * next source event; a restored count would outlive the readings it named.
60210
+ *
60211
+ * See `RuntimeStateDurability`. Enforced by
60212
+ * `scripts/check-runtime-state-durability.ts`.
60213
+ */
60214
+ durability: "session",
60215
+ history: "none"
60216
+ };
59720
60217
  var HeatingValveStatusSchema = object({
59721
60218
  /** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
59722
60219
  position: number().min(0).max(100).nullable().meta(readingMeta("percentage")),
@@ -61486,12 +61983,18 @@ var motionCapability = {
61486
61983
  methods: {
61487
61984
  /**
61488
61985
  * Pull the current motion state synchronously. Convenience shortcut
61489
- * for consumers that don't need the full status object; equivalent
61490
- * to `getStatus()?.detected ?? false`. Will likely be folded into
61491
- * `getStatus` once the auto-injected status surface lands in every
61492
- * consumer.
61986
+ * for consumers that don't need the full status object. A composed
61987
+ * group answers from its slice (D944): unknown throws, it is not off.
61493
61988
  */
61494
61989
  isDetected: method(object({ deviceId: number() }), boolean()) },
61990
+ /**
61991
+ * A composed motion group serves `isDetected` from `detected` (D944).
61992
+ * Without this the cap stays uncomposable (`has-commands`).
61993
+ */
61994
+ composedMethods: { isDetected: {
61995
+ kind: "slice",
61996
+ field: "detected"
61997
+ } },
61495
61998
  events: {
61496
61999
  /**
61497
62000
  * Fires every time the runner transitions a camera between
@@ -69682,6 +70185,8 @@ var DEVICE_LOCAL_STATE_CAPS = {
69682
70185
  featureProbe: featureProbeCapability,
69683
70186
  flood: floodCapability,
69684
70187
  gas: gasCapability,
70188
+ groupCommands: groupCommandsCapability,
70189
+ groupStatus: groupStatusCapability,
69685
70190
  heatingValve: heatingValveCapability,
69686
70191
  humidifier: humidifierCapability,
69687
70192
  humiditySensor: humiditySensorCapability,
@@ -71058,6 +71563,13 @@ Object.freeze({
71058
71563
  access: "view",
71059
71564
  role: "admin"
71060
71565
  },
71566
+ "addons.getPackageDocs": {
71567
+ capName: "addons",
71568
+ capScope: "system",
71569
+ addonId: null,
71570
+ access: "view",
71571
+ role: "admin"
71572
+ },
71061
71573
  "addons.getVersions": {
71062
71574
  capName: "addons",
71063
71575
  capScope: "system",
@@ -74166,6 +74678,20 @@ Object.freeze({
74166
74678
  access: "view",
74167
74679
  role: "viewer"
74168
74680
  },
74681
+ "groupCommands.getStatus": {
74682
+ capName: "group-commands",
74683
+ capScope: "device",
74684
+ addonId: null,
74685
+ access: "view",
74686
+ role: "viewer"
74687
+ },
74688
+ "groupStatus.getStatus": {
74689
+ capName: "group-status",
74690
+ capScope: "device",
74691
+ addonId: null,
74692
+ access: "view",
74693
+ role: "viewer"
74694
+ },
74169
74695
  "heatingValve.getStatus": {
74170
74696
  capName: "heating-valve",
74171
74697
  capScope: "device",
@@ -83988,6 +84514,37 @@ var SENSOR_CAP_VOCABULARY = {
83988
84514
  icon: "flame"
83989
84515
  }]
83990
84516
  },
84517
+ "group-commands": {
84518
+ scope: "device",
84519
+ noun: t("Group command", "Comando di gruppo")
84520
+ },
84521
+ "group-status": {
84522
+ scope: "device",
84523
+ noun: t("Group", "Gruppo"),
84524
+ state: [
84525
+ {
84526
+ kind: "numeric",
84527
+ field: "included",
84528
+ quantity: t("the members reporting", "i membri che rispondono"),
84529
+ label: t("Reporting", "Rispondono"),
84530
+ icon: "users"
84531
+ },
84532
+ {
84533
+ kind: "numeric",
84534
+ field: "excluded",
84535
+ quantity: t("the members left out", "i membri esclusi"),
84536
+ label: t("Excluded", "Esclusi"),
84537
+ icon: "users"
84538
+ },
84539
+ {
84540
+ kind: "numeric",
84541
+ field: "total",
84542
+ quantity: t("the member count", "il numero di membri"),
84543
+ label: t("Members", "Membri"),
84544
+ icon: "sigma"
84545
+ }
84546
+ ]
84547
+ },
83991
84548
  "humidity-sensor": {
83992
84549
  scope: "device",
83993
84550
  noun: t("Humidity", "Umidità"),
@@ -85453,6 +86010,16 @@ Object.freeze({
85453
86010
  form: "single",
85454
86011
  optional: false
85455
86012
  }],
86013
+ "groupCommands.getStatus": [{
86014
+ name: "deviceId",
86015
+ form: "single",
86016
+ optional: false
86017
+ }],
86018
+ "groupStatus.getStatus": [{
86019
+ name: "deviceId",
86020
+ form: "single",
86021
+ optional: false
86022
+ }],
85456
86023
  "heatingValve.getStatus": [{
85457
86024
  name: "deviceId",
85458
86025
  form: "single",
@@ -87437,6 +88004,8 @@ new Map(Object.entries({
87437
88004
  "detection-blind": "device-events",
87438
88005
  "motion-noisy": "device-events",
87439
88006
  "motion-calm": "device-events",
88007
+ "package-llm-silent": "device-events",
88008
+ "package-llm-answered": "device-events",
87440
88009
  "recording-stalled": "device-events",
87441
88010
  "recording-healthy": "device-events",
87442
88011
  "recording-degraded": "device-events",
@@ -87520,6 +88089,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
87520
88089
  label: "Motion without a subject",
87521
88090
  kinds: ["motion-noisy", "motion-calm"]
87522
88091
  },
88092
+ {
88093
+ id: "package-llm",
88094
+ family: "device-events",
88095
+ label: "Package confirm",
88096
+ kinds: ["package-llm-silent", "package-llm-answered"]
88097
+ },
87523
88098
  {
87524
88099
  id: "recording",
87525
88100
  family: "device-events",
@@ -87701,6 +88276,8 @@ var DEVICE_EVENTS = [
87701
88276
  "detection-blind",
87702
88277
  "motion-noisy",
87703
88278
  "motion-calm",
88279
+ "package-llm-silent",
88280
+ "package-llm-answered",
87704
88281
  "recording-stalled",
87705
88282
  "recording-healthy",
87706
88283
  "recording-degraded",
@@ -87969,6 +88546,15 @@ new Map([
87969
88546
  snapshotLabel: "Cameras with constant motion now",
87970
88547
  snapshotSection: null
87971
88548
  },
88549
+ {
88550
+ id: "package-llm-confirm",
88551
+ family: "device-events",
88552
+ label: "Package confirm (not answering / answering again)",
88553
+ bad: ["package-llm-silent"],
88554
+ recovery: ["package-llm-answered"],
88555
+ snapshotLabel: "Cameras whose package confirm is not answering",
88556
+ snapshotSection: null
88557
+ },
87972
88558
  {
87973
88559
  id: "recording-health",
87974
88560
  family: "device-events",