@camstack/addon-provider-homeassistant 1.2.627 → 1.2.628

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/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ All notable changes to this package are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ - Package README and changelog, included in the published files list.
package/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # @camstack/addon-provider-homeassistant
2
+
3
+ Home Assistant device provider addon for CamStack
4
+
5
+ ## What it does
6
+
7
+ - **Home Assistant Provider** (`provider-homeassistant`): Adopt Home Assistant devices into CamStack via WebSocket
8
+ - Node placement: `hub-only`.
9
+ - Capabilities: `broker`, `device-adoption`, `vacuum-control`, `lawn-mower-control`, `running-state`, `valve`, `humidifier`, `water-heater`, `weather`, `image`, `update`, `notification-output`, `addon-routes`, `calendar-source`.
10
+ - **Home Assistant Export** (`homeassistant-export`): Pushes CamStack entities to the CamStack Home Assistant custom component over HTTP. Chooses which devices reach which Home Assistant instance; Home Assistant never polls the hub for a value.
11
+ - Node placement: `hub-only`.
12
+ - Capabilities: `device-export`, `addon-routes`, `oauth-integration`.
13
+
14
+ ## Settings
15
+
16
+ Settings this addon exposes are edited from System → Addons → this addon → Settings when they apply to the whole cluster, and from the device page when they belong to one device. A password field is stored in the keychain.
17
+
18
+ ## Requirements
19
+
20
+ - Peer packages already on the node: `@camstack/types`.
21
+ - A CamStack hub. An agent is used only when the placement above allows it.
22
+
package/dist/addon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("./dist-CRwUHjY7.js");
2
+ const require_dist = require("./dist-CAyJy-Ek.js");
3
3
  let node_crypto = require("node:crypto");
4
4
  let node_zlib = require("node:zlib");
5
5
  //#region src/ha-admin-link.ts
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as lockControlCapability, $t as unknown, A as calendarSourceCapability, At as DeviceFeature, B as deviceAdminLinkCapability, Bt as entryBody, C as bestLocationMatch, Ct as tryConvertUnit, D as buildAddonRouteProvider, Dt as vibrationCapability, E as brokerCapability, Et as valveCapability, Ft as RecordSecretUnavailableError, G as fanControlCapability, Gt as boolean, It as baseUnitOf, J as humidifierCapability, Jt as number, K as floodCapability, Kt as discriminatedUnion, L as contactCapability, Lt as createEvent, M as climateControlCapability, Mt as DeviceType, N as colorCapability, Nt as errMsg, O as buildDeviceAdminUrl, Ot as waterHeaterCapability, P as connectivityCapability, Q as lawnMowerControlCapability, Qt as union, R as controlCapability, Rt as defineEntryKind, S as batteryCapability, St as tryConvertDelta, T as brightnessCapability, Tt as vacuumControlCapability, U as enumSensorCapability, Ut as _enum, V as deviceAdoptionCapability, W as eventEmitterCapability, Wt as array, X as imageCapability, Xt as record, Y as humiditySensorCapability, Yt as object, Z as ingestReading, Zt as string, _ as addonRoutesCapability, _t as scriptRunnerCapability, at as numericSensorCapability, b as ambientLightSensorCapability, bt as tamperCapability, ct as powerMeterCapability, dt as pressureSensorCapability, en as url, et as mediaPlayerCapability, ft as quantityFromUnit, g as accessoriesCapability, gt as runningStateCapability, h as TargetSchema, ht as runningFromVacuumState, it as notifierCapability, j as carbonMonoxideCapability, jt as DeviceRole, k as buttonCapability, kt as weatherCapability, lt as prepareNotification, m as RUNNING_STATE_COLD, mt as runningFromMediaPlayer, n as BaseDevice, nt as normalizeUnit, pt as runningFromLawnMower, q as gasCapability, qt as literal, r as BaseDeviceProvider, rt as notificationOutputCapability, st as parseAdminBase, tn as EventCategory, tt as motionCapability, u as EnumSensorDateTimeFormatSchema, ut as presenceCapability, v as airQualitySensorCapability, vt as smokeCapability, w as binaryCapability, wt as updateCapability, x as automationControlCapability, xt as temperatureSensorCapability, y as alarmPanelCapability, yt as switchCapability, z as coverCapability, zt as defineRecordKinds } from "./dist-BFnk4bwH.mjs";
1
+ import { $ as lockControlCapability, $t as unknown, A as calendarSourceCapability, At as DeviceFeature, B as deviceAdminLinkCapability, Bt as entryBody, C as bestLocationMatch, Ct as tryConvertUnit, D as buildAddonRouteProvider, Dt as vibrationCapability, E as brokerCapability, Et as valveCapability, Ft as RecordSecretUnavailableError, G as fanControlCapability, Gt as boolean, It as baseUnitOf, J as humidifierCapability, Jt as number, K as floodCapability, Kt as discriminatedUnion, L as contactCapability, Lt as createEvent, M as climateControlCapability, Mt as DeviceType, N as colorCapability, Nt as errMsg, O as buildDeviceAdminUrl, Ot as waterHeaterCapability, P as connectivityCapability, Q as lawnMowerControlCapability, Qt as union, R as controlCapability, Rt as defineEntryKind, S as batteryCapability, St as tryConvertDelta, T as brightnessCapability, Tt as vacuumControlCapability, U as enumSensorCapability, Ut as _enum, V as deviceAdoptionCapability, W as eventEmitterCapability, Wt as array, X as imageCapability, Xt as record, Y as humiditySensorCapability, Yt as object, Z as ingestReading, Zt as string, _ as addonRoutesCapability, _t as scriptRunnerCapability, at as numericSensorCapability, b as ambientLightSensorCapability, bt as tamperCapability, ct as powerMeterCapability, dt as pressureSensorCapability, en as url, et as mediaPlayerCapability, ft as quantityFromUnit, g as accessoriesCapability, gt as runningStateCapability, h as TargetSchema, ht as runningFromVacuumState, it as notifierCapability, j as carbonMonoxideCapability, jt as DeviceRole, k as buttonCapability, kt as weatherCapability, lt as prepareNotification, m as RUNNING_STATE_COLD, mt as runningFromMediaPlayer, n as BaseDevice, nt as normalizeUnit, pt as runningFromLawnMower, q as gasCapability, qt as literal, r as BaseDeviceProvider, rt as notificationOutputCapability, st as parseAdminBase, tn as EventCategory, tt as motionCapability, u as EnumSensorDateTimeFormatSchema, ut as presenceCapability, v as airQualitySensorCapability, vt as smokeCapability, w as binaryCapability, wt as updateCapability, x as automationControlCapability, xt as temperatureSensorCapability, y as alarmPanelCapability, yt as switchCapability, z as coverCapability, zt as defineRecordKinds } from "./dist-BNRaAIW1.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
4
4
  //#region src/ha-admin-link.ts
@@ -1,4 +1,4 @@
1
- //#region ../types/dist/event-category-DHXxB8t9.mjs
1
+ //#region ../types/dist/event-category-CT-hz5Rb.mjs
2
2
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
3
3
  EventCategory["SystemBoot"] = "system.boot";
4
4
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -324,6 +324,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
324
324
  /** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
325
325
  EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
326
326
  /**
327
+ * A camera's package LLM confirm has failed closed three times in a row
328
+ * (D931, 2026-10-26). One edge per camera until
329
+ * {@link PipelinePackageLlmAnswered}.
330
+ */
331
+ EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
332
+ /** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
333
+ EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
334
+ /**
327
335
  * Per-camera pipeline config was mutated by the orchestrator
328
336
  * (a settings change via `setAgentInferenceDevices` /
329
337
  * `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
@@ -5566,7 +5574,7 @@ var ZodIssueCode = {
5566
5574
  var ZodFirstPartyTypeKind;
5567
5575
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5568
5576
  //#endregion
5569
- //#region ../types/dist/sleep-B81gwQuR.mjs
5577
+ //#region ../types/dist/sleep-bykKrTgu.mjs
5570
5578
  /**
5571
5579
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5572
5580
  * window to float samples (D455).
@@ -9009,6 +9017,7 @@ var CAP_NAMES = Object.freeze([
9009
9017
  "filesystem-browse",
9010
9018
  "flood",
9011
9019
  "gas",
9020
+ "group-commands",
9012
9021
  "group-status",
9013
9022
  "heating-valve",
9014
9023
  "humidifier",
@@ -11183,7 +11192,7 @@ function errMsg(err) {
11183
11192
  return String(err);
11184
11193
  }
11185
11194
  //#endregion
11186
- //#region ../types/dist/composition-B85l9j1M.mjs
11195
+ //#region ../types/dist/composition-OhpuespA.mjs
11187
11196
  /**
11188
11197
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11189
11198
  *
@@ -11962,7 +11971,9 @@ var GROUP_TEMPLATE_IDS = [
11962
11971
  "leak",
11963
11972
  "smoke",
11964
11973
  "occupancy",
11965
- "binary"
11974
+ "binary",
11975
+ "switch",
11976
+ "light"
11966
11977
  ];
11967
11978
  var NUMERIC_AGGREGATES = [
11968
11979
  "mean",
@@ -11972,6 +11983,8 @@ var NUMERIC_AGGREGATES = [
11972
11983
  "sum"
11973
11984
  ];
11974
11985
  var BINARY_AGGREGATES = ["any", "all"];
11986
+ /** How an actuator group decides it is on. Unknown members never count as off. */
11987
+ var ACTIVE_CRITERIA = ["at-least-one", "all"];
11975
11988
  var AGGREGATE_REDUCERS = [
11976
11989
  "mean",
11977
11990
  "median",
@@ -11983,6 +11996,7 @@ var AGGREGATE_REDUCERS = [
11983
11996
  ];
11984
11997
  var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
11985
11998
  var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
11999
+ var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
11986
12000
  /** One member. The field is stored so occupancy can name motion or binary. */
11987
12001
  var HelperMemberSchema = object({
11988
12002
  source: CompositionSourceRefSchema,
@@ -11993,7 +12007,9 @@ var HelperSpecSchema = discriminatedUnion("kind", [object({
11993
12007
  kind: literal("group"),
11994
12008
  templateId: GroupTemplateIdSchema,
11995
12009
  aggregate: AggregateReducerSchema,
11996
- members: array(HelperMemberSchema).min(1).max(64)
12010
+ members: array(HelperMemberSchema).min(1).max(64),
12011
+ /** Actuator groups only. Readings leave this unset. */
12012
+ active: ActiveCriterionSchema.optional()
11997
12013
  })]);
11998
12014
  /** A composed device's stableId is this prefix plus the block id. */
11999
12015
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
@@ -18798,6 +18814,7 @@ function numeric(input) {
18798
18814
  family: "numeric",
18799
18815
  deviceType: DeviceType.Sensor,
18800
18816
  memberDeviceType: DeviceType.Sensor,
18817
+ commandCaps: [],
18801
18818
  baseUnit: baseUnitOf(input.quantity),
18802
18819
  aggregates: NUMERIC_AGGREGATES,
18803
18820
  accept: [{
@@ -18812,6 +18829,7 @@ function binary(input) {
18812
18829
  family: "binary",
18813
18830
  deviceType: DeviceType.Sensor,
18814
18831
  memberDeviceType: DeviceType.Sensor,
18832
+ commandCaps: [],
18815
18833
  quantity: "none",
18816
18834
  baseUnit: void 0,
18817
18835
  aggregates: BINARY_AGGREGATES,
@@ -19006,9 +19024,47 @@ var GROUP_TEMPLATES = [
19006
19024
  fieldPath: "on"
19007
19025
  }],
19008
19026
  companions: [CHANGED]
19027
+ }),
19028
+ actuator({
19029
+ id: "switch",
19030
+ 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.",
19031
+ deviceType: DeviceType.Switch,
19032
+ outputCap: "switch",
19033
+ commandCaps: ["switch"]
19034
+ }),
19035
+ actuator({
19036
+ id: "light",
19037
+ 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.",
19038
+ deviceType: DeviceType.Light,
19039
+ outputCap: "switch",
19040
+ commandCaps: [
19041
+ "switch",
19042
+ "brightness",
19043
+ "color"
19044
+ ]
19009
19045
  })
19010
19046
  ];
19047
+ function actuator(input) {
19048
+ return {
19049
+ ...input,
19050
+ family: "actuator",
19051
+ role: void 0,
19052
+ memberDeviceType: input.deviceType,
19053
+ outputField: "on",
19054
+ quantity: "none",
19055
+ baseUnit: void 0,
19056
+ aggregates: BINARY_AGGREGATES,
19057
+ defaultAggregate: "any",
19058
+ empty: "offline",
19059
+ accept: [{
19060
+ cap: "switch",
19061
+ fieldPath: "on"
19062
+ }],
19063
+ companions: [CHANGED]
19064
+ };
19065
+ }
19011
19066
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
19067
+ DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
19012
19068
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
19013
19069
  /**
19014
19070
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -46096,6 +46152,8 @@ var NcSystemEventKindSchema = _enum([
46096
46152
  "detection-blind",
46097
46153
  "motion-noisy",
46098
46154
  "motion-calm",
46155
+ "package-llm-silent",
46156
+ "package-llm-answered",
46099
46157
  "recording-stalled",
46100
46158
  "recording-healthy",
46101
46159
  "recording-degraded",
@@ -57275,6 +57333,28 @@ var PackageVersionInfoSchema = object({
57275
57333
  deprecated: string().optional(),
57276
57334
  distTags: array(string()).readonly()
57277
57335
  });
57336
+ /**
57337
+ * One published document. `ok` is markdown from the registry. `missing` means
57338
+ * the registry answered and the file was not there. `error` is a registry or
57339
+ * tarball failure — never an empty string standing in for either.
57340
+ */
57341
+ var PackageDocBodySchema = discriminatedUnion("status", [
57342
+ object({
57343
+ status: literal("ok"),
57344
+ markdown: string()
57345
+ }),
57346
+ object({ status: literal("missing") }),
57347
+ object({
57348
+ status: literal("error"),
57349
+ message: string()
57350
+ })
57351
+ ]);
57352
+ var PackageDocsSchema = object({
57353
+ name: string(),
57354
+ version: string(),
57355
+ readme: PackageDocBodySchema,
57356
+ changelog: PackageDocBodySchema
57357
+ });
57278
57358
  var SearchResultSchema = object({
57279
57359
  name: string(),
57280
57360
  version: string(),
@@ -57493,7 +57573,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
57493
57573
  }), object({ success: literal(true) }), {
57494
57574
  kind: "mutation",
57495
57575
  auth: "admin"
57496
- }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
57576
+ }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
57577
+ name: string().min(1),
57578
+ version: string().min(1).optional()
57579
+ }), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
57497
57580
  kind: "mutation",
57498
57581
  auth: "admin"
57499
57582
  }), method(object({ packageName: string() }), object({ success: literal(true) }), {
@@ -60863,6 +60946,39 @@ var gasCapability = {
60863
60946
  * whether persisting is worth a SQLite commit. */
60864
60947
  volatileStateFields: ["lastChangedAt"]
60865
60948
  };
60949
+ var GroupCommandsSchema = object({
60950
+ /** One row per member that has been commanded. A later command replaces that member's row. */
60951
+ results: array(object({
60952
+ deviceId: number().int().nonnegative(),
60953
+ cap: string().min(1),
60954
+ method: string().min(1),
60955
+ ok: boolean(),
60956
+ error: string().optional(),
60957
+ /** Ms epoch of the attempt. */
60958
+ at: number()
60959
+ })) });
60960
+ var groupCommandsCapability = {
60961
+ name: "group-commands",
60962
+ scope: "device",
60963
+ deviceNative: true,
60964
+ mode: "singleton",
60965
+ deviceTypes: [DeviceType.Switch, DeviceType.Light],
60966
+ methods: {},
60967
+ status: {
60968
+ schema: GroupCommandsSchema,
60969
+ kind: "push"
60970
+ },
60971
+ runtimeState: GroupCommandsSchema,
60972
+ /**
60973
+ * Runtime-state durability: **session** — the last attempt. A restored
60974
+ * failure would outlive the command that caused it.
60975
+ *
60976
+ * See `RuntimeStateDurability`. Enforced by
60977
+ * `scripts/check-runtime-state-durability.ts`.
60978
+ */
60979
+ durability: "session",
60980
+ history: "none"
60981
+ };
60866
60982
  /**
60867
60983
  * How many members of a helper group answered (D944). Counts are integers,
60868
60984
  * not measurements: zero included is a real count, never a stand-in reading.
@@ -60891,7 +61007,11 @@ var groupStatusCapability = {
60891
61007
  scope: "device",
60892
61008
  deviceNative: true,
60893
61009
  mode: "singleton",
60894
- deviceTypes: [DeviceType.Sensor],
61010
+ deviceTypes: [
61011
+ DeviceType.Sensor,
61012
+ DeviceType.Switch,
61013
+ DeviceType.Light
61014
+ ],
60895
61015
  methods: {},
60896
61016
  status: {
60897
61017
  schema: GroupStatusSchema,
@@ -70939,6 +71059,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
70939
71059
  featureProbe: featureProbeCapability,
70940
71060
  flood: floodCapability,
70941
71061
  gas: gasCapability,
71062
+ groupCommands: groupCommandsCapability,
70942
71063
  groupStatus: groupStatusCapability,
70943
71064
  heatingValve: heatingValveCapability,
70944
71065
  humidifier: humidifierCapability,
@@ -72316,6 +72437,13 @@ Object.freeze({
72316
72437
  access: "view",
72317
72438
  role: "admin"
72318
72439
  },
72440
+ "addons.getPackageDocs": {
72441
+ capName: "addons",
72442
+ capScope: "system",
72443
+ addonId: null,
72444
+ access: "view",
72445
+ role: "admin"
72446
+ },
72319
72447
  "addons.getVersions": {
72320
72448
  capName: "addons",
72321
72449
  capScope: "system",
@@ -75424,6 +75552,13 @@ Object.freeze({
75424
75552
  access: "view",
75425
75553
  role: "viewer"
75426
75554
  },
75555
+ "groupCommands.getStatus": {
75556
+ capName: "group-commands",
75557
+ capScope: "device",
75558
+ addonId: null,
75559
+ access: "view",
75560
+ role: "viewer"
75561
+ },
75427
75562
  "groupStatus.getStatus": {
75428
75563
  capName: "group-status",
75429
75564
  capScope: "device",
@@ -85253,6 +85388,10 @@ var SENSOR_CAP_VOCABULARY = {
85253
85388
  icon: "flame"
85254
85389
  }]
85255
85390
  },
85391
+ "group-commands": {
85392
+ scope: "device",
85393
+ noun: t("Group command", "Comando di gruppo")
85394
+ },
85256
85395
  "group-status": {
85257
85396
  scope: "device",
85258
85397
  noun: t("Group", "Gruppo"),
@@ -86745,6 +86884,11 @@ Object.freeze({
86745
86884
  form: "single",
86746
86885
  optional: false
86747
86886
  }],
86887
+ "groupCommands.getStatus": [{
86888
+ name: "deviceId",
86889
+ form: "single",
86890
+ optional: false
86891
+ }],
86748
86892
  "groupStatus.getStatus": [{
86749
86893
  name: "deviceId",
86750
86894
  form: "single",
@@ -88941,6 +89085,8 @@ new Map(Object.entries({
88941
89085
  "detection-blind": "device-events",
88942
89086
  "motion-noisy": "device-events",
88943
89087
  "motion-calm": "device-events",
89088
+ "package-llm-silent": "device-events",
89089
+ "package-llm-answered": "device-events",
88944
89090
  "recording-stalled": "device-events",
88945
89091
  "recording-healthy": "device-events",
88946
89092
  "recording-degraded": "device-events",
@@ -89024,6 +89170,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
89024
89170
  label: "Motion without a subject",
89025
89171
  kinds: ["motion-noisy", "motion-calm"]
89026
89172
  },
89173
+ {
89174
+ id: "package-llm",
89175
+ family: "device-events",
89176
+ label: "Package confirm",
89177
+ kinds: ["package-llm-silent", "package-llm-answered"]
89178
+ },
89027
89179
  {
89028
89180
  id: "recording",
89029
89181
  family: "device-events",
@@ -89205,6 +89357,8 @@ var DEVICE_EVENTS = [
89205
89357
  "detection-blind",
89206
89358
  "motion-noisy",
89207
89359
  "motion-calm",
89360
+ "package-llm-silent",
89361
+ "package-llm-answered",
89208
89362
  "recording-stalled",
89209
89363
  "recording-healthy",
89210
89364
  "recording-degraded",
@@ -89473,6 +89627,15 @@ new Map([
89473
89627
  snapshotLabel: "Cameras with constant motion now",
89474
89628
  snapshotSection: null
89475
89629
  },
89630
+ {
89631
+ id: "package-llm-confirm",
89632
+ family: "device-events",
89633
+ label: "Package confirm (not answering / answering again)",
89634
+ bad: ["package-llm-silent"],
89635
+ recovery: ["package-llm-answered"],
89636
+ snapshotLabel: "Cameras whose package confirm is not answering",
89637
+ snapshotSection: null
89638
+ },
89476
89639
  {
89477
89640
  id: "recording-health",
89478
89641
  family: "device-events",
@@ -1,5 +1,5 @@
1
1
  require("node:crypto");
2
- //#region ../types/dist/event-category-DHXxB8t9.mjs
2
+ //#region ../types/dist/event-category-CT-hz5Rb.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -325,6 +325,14 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
325
325
  /** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
326
326
  EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
327
327
  /**
328
+ * A camera's package LLM confirm has failed closed three times in a row
329
+ * (D931, 2026-10-26). One edge per camera until
330
+ * {@link PipelinePackageLlmAnswered}.
331
+ */
332
+ EventCategory["PipelinePackageLlmSilent"] = "pipeline.package-llm-silent";
333
+ /** The recovery edge of {@link PipelinePackageLlmSilent}: a confirm returned yes or no. */
334
+ EventCategory["PipelinePackageLlmAnswered"] = "pipeline.package-llm-answered";
335
+ /**
328
336
  * Per-camera pipeline config was mutated by the orchestrator
329
337
  * (a settings change via `setAgentInferenceDevices` /
330
338
  * `setCameraStepToggle` / `setCameraStepSettings`). Orchestrator
@@ -5567,7 +5575,7 @@ var ZodIssueCode = {
5567
5575
  var ZodFirstPartyTypeKind;
5568
5576
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5569
5577
  //#endregion
5570
- //#region ../types/dist/sleep-B81gwQuR.mjs
5578
+ //#region ../types/dist/sleep-bykKrTgu.mjs
5571
5579
  /**
5572
5580
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5573
5581
  * window to float samples (D455).
@@ -9010,6 +9018,7 @@ var CAP_NAMES = Object.freeze([
9010
9018
  "filesystem-browse",
9011
9019
  "flood",
9012
9020
  "gas",
9021
+ "group-commands",
9013
9022
  "group-status",
9014
9023
  "heating-valve",
9015
9024
  "humidifier",
@@ -11184,7 +11193,7 @@ function errMsg(err) {
11184
11193
  return String(err);
11185
11194
  }
11186
11195
  //#endregion
11187
- //#region ../types/dist/composition-B85l9j1M.mjs
11196
+ //#region ../types/dist/composition-OhpuespA.mjs
11188
11197
  /**
11189
11198
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11190
11199
  *
@@ -11963,7 +11972,9 @@ var GROUP_TEMPLATE_IDS = [
11963
11972
  "leak",
11964
11973
  "smoke",
11965
11974
  "occupancy",
11966
- "binary"
11975
+ "binary",
11976
+ "switch",
11977
+ "light"
11967
11978
  ];
11968
11979
  var NUMERIC_AGGREGATES = [
11969
11980
  "mean",
@@ -11973,6 +11984,8 @@ var NUMERIC_AGGREGATES = [
11973
11984
  "sum"
11974
11985
  ];
11975
11986
  var BINARY_AGGREGATES = ["any", "all"];
11987
+ /** How an actuator group decides it is on. Unknown members never count as off. */
11988
+ var ACTIVE_CRITERIA = ["at-least-one", "all"];
11976
11989
  var AGGREGATE_REDUCERS = [
11977
11990
  "mean",
11978
11991
  "median",
@@ -11984,6 +11997,7 @@ var AGGREGATE_REDUCERS = [
11984
11997
  ];
11985
11998
  var GroupTemplateIdSchema = _enum(GROUP_TEMPLATE_IDS);
11986
11999
  var AggregateReducerSchema = _enum(AGGREGATE_REDUCERS);
12000
+ var ActiveCriterionSchema = _enum(ACTIVE_CRITERIA);
11987
12001
  /** One member. The field is stored so occupancy can name motion or binary. */
11988
12002
  var HelperMemberSchema = object({
11989
12003
  source: CompositionSourceRefSchema,
@@ -11994,7 +12008,9 @@ var HelperSpecSchema = discriminatedUnion("kind", [object({
11994
12008
  kind: literal("group"),
11995
12009
  templateId: GroupTemplateIdSchema,
11996
12010
  aggregate: AggregateReducerSchema,
11997
- members: array(HelperMemberSchema).min(1).max(64)
12011
+ members: array(HelperMemberSchema).min(1).max(64),
12012
+ /** Actuator groups only. Readings leave this unset. */
12013
+ active: ActiveCriterionSchema.optional()
11998
12014
  })]);
11999
12015
  /** A composed device's stableId is this prefix plus the block id. */
12000
12016
  var COMPOSED_DEVICE_STABLE_ID_PREFIX = "composed-";
@@ -18799,6 +18815,7 @@ function numeric(input) {
18799
18815
  family: "numeric",
18800
18816
  deviceType: DeviceType.Sensor,
18801
18817
  memberDeviceType: DeviceType.Sensor,
18818
+ commandCaps: [],
18802
18819
  baseUnit: baseUnitOf(input.quantity),
18803
18820
  aggregates: NUMERIC_AGGREGATES,
18804
18821
  accept: [{
@@ -18813,6 +18830,7 @@ function binary(input) {
18813
18830
  family: "binary",
18814
18831
  deviceType: DeviceType.Sensor,
18815
18832
  memberDeviceType: DeviceType.Sensor,
18833
+ commandCaps: [],
18816
18834
  quantity: "none",
18817
18835
  baseUnit: void 0,
18818
18836
  aggregates: BINARY_AGGREGATES,
@@ -19007,9 +19025,47 @@ var GROUP_TEMPLATES = [
19007
19025
  fieldPath: "on"
19008
19026
  }],
19009
19027
  companions: [CHANGED]
19028
+ }),
19029
+ actuator({
19030
+ id: "switch",
19031
+ 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.",
19032
+ deviceType: DeviceType.Switch,
19033
+ outputCap: "switch",
19034
+ commandCaps: ["switch"]
19035
+ }),
19036
+ actuator({
19037
+ id: "light",
19038
+ 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.",
19039
+ deviceType: DeviceType.Light,
19040
+ outputCap: "switch",
19041
+ commandCaps: [
19042
+ "switch",
19043
+ "brightness",
19044
+ "color"
19045
+ ]
19010
19046
  })
19011
19047
  ];
19048
+ function actuator(input) {
19049
+ return {
19050
+ ...input,
19051
+ family: "actuator",
19052
+ role: void 0,
19053
+ memberDeviceType: input.deviceType,
19054
+ outputField: "on",
19055
+ quantity: "none",
19056
+ baseUnit: void 0,
19057
+ aggregates: BINARY_AGGREGATES,
19058
+ defaultAggregate: "any",
19059
+ empty: "offline",
19060
+ accept: [{
19061
+ cap: "switch",
19062
+ fieldPath: "on"
19063
+ }],
19064
+ companions: [CHANGED]
19065
+ };
19066
+ }
19012
19067
  new Map(GROUP_TEMPLATES.map((template) => [template.id, template]));
19068
+ DeviceFeature.LightColorRgb, DeviceFeature.LightColorHsv, DeviceFeature.LightColorMired;
19013
19069
  `${COMPOSED_DEVICE_STABLE_ID_PREFIX}`;
19014
19070
  /**
19015
19071
  * What a composition may BUILD on a device type (G2, D676): the caps a new
@@ -46097,6 +46153,8 @@ var NcSystemEventKindSchema = _enum([
46097
46153
  "detection-blind",
46098
46154
  "motion-noisy",
46099
46155
  "motion-calm",
46156
+ "package-llm-silent",
46157
+ "package-llm-answered",
46100
46158
  "recording-stalled",
46101
46159
  "recording-healthy",
46102
46160
  "recording-degraded",
@@ -57276,6 +57334,28 @@ var PackageVersionInfoSchema = object({
57276
57334
  deprecated: string().optional(),
57277
57335
  distTags: array(string()).readonly()
57278
57336
  });
57337
+ /**
57338
+ * One published document. `ok` is markdown from the registry. `missing` means
57339
+ * the registry answered and the file was not there. `error` is a registry or
57340
+ * tarball failure — never an empty string standing in for either.
57341
+ */
57342
+ var PackageDocBodySchema = discriminatedUnion("status", [
57343
+ object({
57344
+ status: literal("ok"),
57345
+ markdown: string()
57346
+ }),
57347
+ object({ status: literal("missing") }),
57348
+ object({
57349
+ status: literal("error"),
57350
+ message: string()
57351
+ })
57352
+ ]);
57353
+ var PackageDocsSchema = object({
57354
+ name: string(),
57355
+ version: string(),
57356
+ readme: PackageDocBodySchema,
57357
+ changelog: PackageDocBodySchema
57358
+ });
57279
57359
  var SearchResultSchema = object({
57280
57360
  name: string(),
57281
57361
  version: string(),
@@ -57494,7 +57574,10 @@ method(object({ nodeId: string().optional() }).optional(), array(AddonListItemSc
57494
57574
  }), object({ success: literal(true) }), {
57495
57575
  kind: "mutation",
57496
57576
  auth: "admin"
57497
- }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({ addonId: string() }), RestartAddonResultSchema, {
57577
+ }), method(object({ name: string() }), array(PackageVersionInfoSchema).readonly()), method(object({
57578
+ name: string().min(1),
57579
+ version: string().min(1).optional()
57580
+ }), PackageDocsSchema, { auth: "admin" }), method(object({ addonId: string() }), RestartAddonResultSchema, {
57498
57581
  kind: "mutation",
57499
57582
  auth: "admin"
57500
57583
  }), method(object({ packageName: string() }), object({ success: literal(true) }), {
@@ -60864,6 +60947,39 @@ var gasCapability = {
60864
60947
  * whether persisting is worth a SQLite commit. */
60865
60948
  volatileStateFields: ["lastChangedAt"]
60866
60949
  };
60950
+ var GroupCommandsSchema = object({
60951
+ /** One row per member that has been commanded. A later command replaces that member's row. */
60952
+ results: array(object({
60953
+ deviceId: number().int().nonnegative(),
60954
+ cap: string().min(1),
60955
+ method: string().min(1),
60956
+ ok: boolean(),
60957
+ error: string().optional(),
60958
+ /** Ms epoch of the attempt. */
60959
+ at: number()
60960
+ })) });
60961
+ var groupCommandsCapability = {
60962
+ name: "group-commands",
60963
+ scope: "device",
60964
+ deviceNative: true,
60965
+ mode: "singleton",
60966
+ deviceTypes: [DeviceType.Switch, DeviceType.Light],
60967
+ methods: {},
60968
+ status: {
60969
+ schema: GroupCommandsSchema,
60970
+ kind: "push"
60971
+ },
60972
+ runtimeState: GroupCommandsSchema,
60973
+ /**
60974
+ * Runtime-state durability: **session** — the last attempt. A restored
60975
+ * failure would outlive the command that caused it.
60976
+ *
60977
+ * See `RuntimeStateDurability`. Enforced by
60978
+ * `scripts/check-runtime-state-durability.ts`.
60979
+ */
60980
+ durability: "session",
60981
+ history: "none"
60982
+ };
60867
60983
  /**
60868
60984
  * How many members of a helper group answered (D944). Counts are integers,
60869
60985
  * not measurements: zero included is a real count, never a stand-in reading.
@@ -60892,7 +61008,11 @@ var groupStatusCapability = {
60892
61008
  scope: "device",
60893
61009
  deviceNative: true,
60894
61010
  mode: "singleton",
60895
- deviceTypes: [DeviceType.Sensor],
61011
+ deviceTypes: [
61012
+ DeviceType.Sensor,
61013
+ DeviceType.Switch,
61014
+ DeviceType.Light
61015
+ ],
60896
61016
  methods: {},
60897
61017
  status: {
60898
61018
  schema: GroupStatusSchema,
@@ -70940,6 +71060,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
70940
71060
  featureProbe: featureProbeCapability,
70941
71061
  flood: floodCapability,
70942
71062
  gas: gasCapability,
71063
+ groupCommands: groupCommandsCapability,
70943
71064
  groupStatus: groupStatusCapability,
70944
71065
  heatingValve: heatingValveCapability,
70945
71066
  humidifier: humidifierCapability,
@@ -72317,6 +72438,13 @@ Object.freeze({
72317
72438
  access: "view",
72318
72439
  role: "admin"
72319
72440
  },
72441
+ "addons.getPackageDocs": {
72442
+ capName: "addons",
72443
+ capScope: "system",
72444
+ addonId: null,
72445
+ access: "view",
72446
+ role: "admin"
72447
+ },
72320
72448
  "addons.getVersions": {
72321
72449
  capName: "addons",
72322
72450
  capScope: "system",
@@ -75425,6 +75553,13 @@ Object.freeze({
75425
75553
  access: "view",
75426
75554
  role: "viewer"
75427
75555
  },
75556
+ "groupCommands.getStatus": {
75557
+ capName: "group-commands",
75558
+ capScope: "device",
75559
+ addonId: null,
75560
+ access: "view",
75561
+ role: "viewer"
75562
+ },
75428
75563
  "groupStatus.getStatus": {
75429
75564
  capName: "group-status",
75430
75565
  capScope: "device",
@@ -85254,6 +85389,10 @@ var SENSOR_CAP_VOCABULARY = {
85254
85389
  icon: "flame"
85255
85390
  }]
85256
85391
  },
85392
+ "group-commands": {
85393
+ scope: "device",
85394
+ noun: t("Group command", "Comando di gruppo")
85395
+ },
85257
85396
  "group-status": {
85258
85397
  scope: "device",
85259
85398
  noun: t("Group", "Gruppo"),
@@ -86746,6 +86885,11 @@ Object.freeze({
86746
86885
  form: "single",
86747
86886
  optional: false
86748
86887
  }],
86888
+ "groupCommands.getStatus": [{
86889
+ name: "deviceId",
86890
+ form: "single",
86891
+ optional: false
86892
+ }],
86749
86893
  "groupStatus.getStatus": [{
86750
86894
  name: "deviceId",
86751
86895
  form: "single",
@@ -88942,6 +89086,8 @@ new Map(Object.entries({
88942
89086
  "detection-blind": "device-events",
88943
89087
  "motion-noisy": "device-events",
88944
89088
  "motion-calm": "device-events",
89089
+ "package-llm-silent": "device-events",
89090
+ "package-llm-answered": "device-events",
88945
89091
  "recording-stalled": "device-events",
88946
89092
  "recording-healthy": "device-events",
88947
89093
  "recording-degraded": "device-events",
@@ -89025,6 +89171,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
89025
89171
  label: "Motion without a subject",
89026
89172
  kinds: ["motion-noisy", "motion-calm"]
89027
89173
  },
89174
+ {
89175
+ id: "package-llm",
89176
+ family: "device-events",
89177
+ label: "Package confirm",
89178
+ kinds: ["package-llm-silent", "package-llm-answered"]
89179
+ },
89028
89180
  {
89029
89181
  id: "recording",
89030
89182
  family: "device-events",
@@ -89206,6 +89358,8 @@ var DEVICE_EVENTS = [
89206
89358
  "detection-blind",
89207
89359
  "motion-noisy",
89208
89360
  "motion-calm",
89361
+ "package-llm-silent",
89362
+ "package-llm-answered",
89209
89363
  "recording-stalled",
89210
89364
  "recording-healthy",
89211
89365
  "recording-degraded",
@@ -89474,6 +89628,15 @@ new Map([
89474
89628
  snapshotLabel: "Cameras with constant motion now",
89475
89629
  snapshotSection: null
89476
89630
  },
89631
+ {
89632
+ id: "package-llm-confirm",
89633
+ family: "device-events",
89634
+ label: "Package confirm (not answering / answering again)",
89635
+ bad: ["package-llm-silent"],
89636
+ recovery: ["package-llm-answered"],
89637
+ snapshotLabel: "Cameras whose package confirm is not answering",
89638
+ snapshotSection: null
89639
+ },
89477
89640
  {
89478
89641
  id: "recording-health",
89479
89642
  family: "device-events",
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  enumerable: true
25
25
  }) : target, mod));
26
26
  //#endregion
27
- const require_dist = require("../dist-CRwUHjY7.js");
27
+ const require_dist = require("../dist-CAyJy-Ek.js");
28
28
  let node_crypto = require("node:crypto");
29
29
  require("node:zlib");
30
30
  let node_fs = require("node:fs");
@@ -3492,6 +3492,10 @@ var CAPS_NOT_EXPORTED = [
3492
3492
  cap: "group-status",
3493
3493
  reason: "Bookkeeping for a helper group (D944): how many members were included, excluded, or named. The value an operator automates on is the output capability (the temperature, the motion, the watts). These counts are session-only, have no history, and would publish a second entity that never means the reading."
3494
3494
  },
3495
+ {
3496
+ cap: "group-commands",
3497
+ reason: "The last fan-out a helper group attempted (D944), one row per member. It is session-only and has no history. The command an automation sends is the member capability (switch, brightness, colour), not this record."
3498
+ },
3495
3499
  {
3496
3500
  cap: "recording-onboard",
3497
3501
  reason: "An EDITOR of the CAMERA’s own recorder: a weekly schedule of windows per trigger, plus the facts about the card it writes to. The schedule is a document an operator authors, not a reading — an entity would publish 168 slots as a state and nothing in Home Assistant could act on it. The storage side is a reading, but it belongs to the camera’s own health rather than to this cap’s editor surface, and publishing capacity here would put the same number in two places the day a health cap carries it. ONE thing here is arguably a real binary sensor: `recordingToNowhere` — scheduled to record with no usable card. It is deliberately NOT exported yet, because exporting half a cap needs the split decided first, and the two cameras it fires on today are already a danger banner and a WARN."
@@ -1,4 +1,4 @@
1
- import { $t as unknown, D as buildAddonRouteProvider, F as consumableFormOf, H as deviceExportCapability, Ht as nodePin, I as consumableKindOf, It as baseUnitOf, Pt as BaseAddon, Vt as isReadingQuantity, Wt as array, Yt as object, Zt as string, _ as addonRoutesCapability, a as COCO_TO_MACRO, c as ConsumableItemSchema, d as FanDirectionSchema, f as HvacModeSchema, i as CAMERA_SWITCH_ORDER, l as ConsumableStatusSchema, o as CameraSwitchIdSchema, ot as oauthIntegrationCapability, p as MediaPlayerRepeatSchema, s as ConsumableFormSchema, t as AlarmArmModeSchema, tn as EventCategory } from "../dist-BFnk4bwH.mjs";
1
+ import { $t as unknown, D as buildAddonRouteProvider, F as consumableFormOf, H as deviceExportCapability, Ht as nodePin, I as consumableKindOf, It as baseUnitOf, Pt as BaseAddon, Vt as isReadingQuantity, Wt as array, Yt as object, Zt as string, _ as addonRoutesCapability, a as COCO_TO_MACRO, c as ConsumableItemSchema, d as FanDirectionSchema, f as HvacModeSchema, i as CAMERA_SWITCH_ORDER, l as ConsumableStatusSchema, o as CameraSwitchIdSchema, ot as oauthIntegrationCapability, p as MediaPlayerRepeatSchema, s as ConsumableFormSchema, t as AlarmArmModeSchema, tn as EventCategory } from "../dist-BNRaAIW1.mjs";
2
2
  import { createHmac, timingSafeEqual } from "node:crypto";
3
3
  import "node:zlib";
4
4
  import "node:fs";
@@ -3457,6 +3457,10 @@ var CAPS_NOT_EXPORTED = [
3457
3457
  cap: "group-status",
3458
3458
  reason: "Bookkeeping for a helper group (D944): how many members were included, excluded, or named. The value an operator automates on is the output capability (the temperature, the motion, the watts). These counts are session-only, have no history, and would publish a second entity that never means the reading."
3459
3459
  },
3460
+ {
3461
+ cap: "group-commands",
3462
+ reason: "The last fan-out a helper group attempted (D944), one row per member. It is session-only and has no history. The command an automation sends is the member capability (switch, brightness, colour), not this record."
3463
+ },
3460
3464
  {
3461
3465
  cap: "recording-onboard",
3462
3466
  reason: "An EDITOR of the CAMERA’s own recorder: a weekly schedule of windows per trigger, plus the facts about the card it writes to. The schedule is a document an operator authors, not a reading — an entity would publish 168 slots as a state and nothing in Home Assistant could act on it. The storage side is a reading, but it belongs to the camera’s own health rather than to this cap’s editor surface, and publishing capacity here would put the same number in two places the day a health cap carries it. ONE thing here is arguably a real binary sensor: `recordingToNowhere` — scheduled to record with no usable card. It is deliberately NOT exported yet, because exporting half a cap needs the split decided first, and the two cameras it fires on today are already a danger banner and a WARN."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homeassistant",
3
- "version": "1.2.627",
3
+ "version": "1.2.628",
4
4
  "description": "Home Assistant device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",
@@ -129,7 +129,9 @@
129
129
  "files": [
130
130
  "dist",
131
131
  "i18n",
132
- "assets"
132
+ "assets",
133
+ "README.md",
134
+ "CHANGELOG.md"
133
135
  ],
134
136
  "scripts": {
135
137
  "build": "vite build",