@camstack/addon-provider-homeassistant 1.2.641 → 1.2.643

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 CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.643] - 2026-10-31
11
+
12
+ ### Changed
13
+
14
+ - The power-source capability is not exported to Home Assistant (manual admin recovery action).
15
+
16
+ ## [1.2.642] - 2026-10-31
17
+
18
+ ### Changed
19
+
20
+ - A lock reporting door-open is published to Home Assistant as open.
21
+
10
22
  ## [1.2.641] - 2026-10-31
11
23
 
12
24
  ### Changed
package/dist/addon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_ha_broker_source = require("./ha-broker-source-D3_ZXq6l.js");
2
+ const require_ha_broker_source = require("./ha-broker-source-zbaephU5.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 humiditySensorCapability, $t as array, A as brokerCapability, At as temperatureSensorCapability, Bt as DeviceRole, C as alarmPanelCapability, Ct as runningFromVacuumState, D as bestLocationMatch, Dt as smokeCapability, E as batteryCapability, F as carbonMonoxideCapability, Ft as valveCapability, G as deviceAdoptionCapability, Gt as baseUnitOf, H as controlCapability, Ht as errMsg, I as climateControlCapability, It as vibrationCapability, J as eventEmitterCapability, Jt as defineRecordKinds, Kt as createEvent, L as colorCapability, Lt as waterHeaterCapability, M as buildDeviceAdminUrl, Mt as tryConvertUnit, N as buttonCapability, Nt as updateCapability, O as binaryCapability, Ot as switchCapability, P as calendarSourceCapability, Pt as vacuumControlCapability, Q as humidifierCapability, Qt as _enum, R as connectivityCapability, Rt as weatherCapability, S as airQualitySensorCapability, St as runningFromMediaPlayer, T as automationControlCapability, Tt as scriptRunnerCapability, U as coverCapability, V as contactCapability, Vt as DeviceType, W as deviceAdminLinkCapability, Wt as RecordSecretUnavailableError, X as floodCapability, Y as fanControlCapability, Yt as entryBody, Z as gasCapability, _t as publicEndpointReaderFrom, a as BaseDevice, an as record, at as motionCapability, b as accessoriesCapability, cn as unknown, ct as notifierCapability, dt as parseAdminBase, en as boolean, et as imageCapability, ft as powerMeterCapability, ht as pressureSensorCapability, in as object, it as mediaPlayerCapability, j as buildAddonRouteProvider, jt as tryConvertDelta, k as brightnessCapability, kt as tamperCapability, ln as url, lt as numericSensorCapability, mt as presenceCapability, nn as literal, nt as lawnMowerControlCapability, o as BaseDeviceProvider, on as string, ot as normalizeUnit, p as EnumSensorDateTimeFormatSchema, pt as prepareNotification, q as enumSensorCapability, qt as defineEntryKind, rn as number, rt as lockControlCapability, sn as union, st as notificationOutputCapability, t as HA_BROKER_KIND, tn as discriminatedUnion, tt as ingestReading, un as EventCategory, v as RUNNING_STATE_COLD, vt as quantityFromUnit, w as ambientLightSensorCapability, wt as runningStateCapability, x as addonRoutesCapability, xt as runningFromLawnMower, y as TargetSchema, yt as resolveAttachmentUrls, zt as DeviceFeature } from "./ha-broker-source-vytM8SXk.mjs";
1
+ import { $ as humiditySensorCapability, $t as array, A as brokerCapability, At as temperatureSensorCapability, Bt as DeviceRole, C as alarmPanelCapability, Ct as runningFromVacuumState, D as bestLocationMatch, Dt as smokeCapability, E as batteryCapability, F as carbonMonoxideCapability, Ft as valveCapability, G as deviceAdoptionCapability, Gt as baseUnitOf, H as controlCapability, Ht as errMsg, I as climateControlCapability, It as vibrationCapability, J as eventEmitterCapability, Jt as defineRecordKinds, Kt as createEvent, L as colorCapability, Lt as waterHeaterCapability, M as buildDeviceAdminUrl, Mt as tryConvertUnit, N as buttonCapability, Nt as updateCapability, O as binaryCapability, Ot as switchCapability, P as calendarSourceCapability, Pt as vacuumControlCapability, Q as humidifierCapability, Qt as _enum, R as connectivityCapability, Rt as weatherCapability, S as airQualitySensorCapability, St as runningFromMediaPlayer, T as automationControlCapability, Tt as scriptRunnerCapability, U as coverCapability, V as contactCapability, Vt as DeviceType, W as deviceAdminLinkCapability, Wt as RecordSecretUnavailableError, X as floodCapability, Y as fanControlCapability, Yt as entryBody, Z as gasCapability, _t as publicEndpointReaderFrom, a as BaseDevice, an as record, at as motionCapability, b as accessoriesCapability, cn as unknown, ct as notifierCapability, dt as parseAdminBase, en as boolean, et as imageCapability, ft as powerMeterCapability, ht as pressureSensorCapability, in as object, it as mediaPlayerCapability, j as buildAddonRouteProvider, jt as tryConvertDelta, k as brightnessCapability, kt as tamperCapability, ln as url, lt as numericSensorCapability, mt as presenceCapability, nn as literal, nt as lawnMowerControlCapability, o as BaseDeviceProvider, on as string, ot as normalizeUnit, p as EnumSensorDateTimeFormatSchema, pt as prepareNotification, q as enumSensorCapability, qt as defineEntryKind, rn as number, rt as lockControlCapability, sn as union, st as notificationOutputCapability, t as HA_BROKER_KIND, tn as discriminatedUnion, tt as ingestReading, un as EventCategory, v as RUNNING_STATE_COLD, vt as quantityFromUnit, w as ambientLightSensorCapability, wt as runningStateCapability, x as addonRoutesCapability, xt as runningFromLawnMower, y as TargetSchema, yt as resolveAttachmentUrls, zt as DeviceFeature } from "./ha-broker-source-DxSvfCed.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
@@ -5587,7 +5587,7 @@ var ZodIssueCode = {
5587
5587
  var ZodFirstPartyTypeKind;
5588
5588
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5589
5589
  //#endregion
5590
- //#region ../types/dist/sleep-0RR2wzNB.mjs
5590
+ //#region ../types/dist/sleep-dco0-jRo.mjs
5591
5591
  /**
5592
5592
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5593
5593
  * window to float samples (D455).
@@ -7290,6 +7290,26 @@ var BaseAddon = class {
7290
7290
  * alternative — skip it — turns a rename into a surface that quietly
7291
7291
  * empties, which looks exactly like an addon with nothing to configure.
7292
7292
  */
7293
+ /**
7294
+ * The form schema of ONE integration instance, or `null` to use {@link globalSettingsSchema}.
7295
+ *
7296
+ * Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
7297
+ * needs its connection fields, the default integration the addon's own sections. It is the
7298
+ * SHAPE of the form only — the values live in `integrations.getSettings`, and the write path is
7299
+ * unchanged (`integrations.setSettings` for an account integration).
7300
+ */
7301
+ async integrationSettingsSchema(_instance) {
7302
+ return null;
7303
+ }
7304
+ /**
7305
+ * What the create wizard and the integration edit page render for one instance: the addon's
7306
+ * per-instance schema when it declares one, else its global schema (what they always showed).
7307
+ */
7308
+ async getIntegrationFormSchema(instance, nodeId) {
7309
+ const scoped = await this.integrationSettingsSchema(instance);
7310
+ if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
7311
+ return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
7312
+ }
7293
7313
  async getIntegrationSettings(nodeId) {
7294
7314
  const declared = this.integrationSettingSections();
7295
7315
  if (declared.length === 0) return null;
@@ -9263,6 +9283,7 @@ var CAP_NAMES = Object.freeze([
9263
9283
  "plate-gallery",
9264
9284
  "platform-probe",
9265
9285
  "power-meter",
9286
+ "power-source",
9266
9287
  "presence",
9267
9288
  "pressure-sensor",
9268
9289
  "privacy-mask",
@@ -10226,7 +10247,8 @@ Object.freeze({
10226
10247
  "unlocked",
10227
10248
  "locking",
10228
10249
  "unlocking",
10229
- "jammed"
10250
+ "jammed",
10251
+ "door-open"
10230
10252
  ]
10231
10253
  }],
10232
10254
  "media-player": [
@@ -10613,6 +10635,13 @@ Object.freeze({
10613
10635
  "valueType": "number"
10614
10636
  }
10615
10637
  ],
10638
+ "power-source": [{
10639
+ "path": "switchOn",
10640
+ "valueType": "boolean"
10641
+ }, {
10642
+ "path": "offSeconds",
10643
+ "valueType": "number"
10644
+ }],
10616
10645
  "presence": [
10617
10646
  {
10618
10647
  "path": "state",
@@ -12715,6 +12744,25 @@ var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
12715
12744
  var MediaPresenceOwnerKindSchema = _enum([...EVENT_OWNER_TYPES, "track"]);
12716
12745
  new Set(EVENT_OWNER_TYPES);
12717
12746
  /**
12747
+ * Which integration instance a settings form is for. An addon that serves several instances
12748
+ * (`instanceMode: multiple`) can show a different form per instance — an NVR integration
12749
+ * needs its connection, the default integration needs the addon's own sections.
12750
+ *
12751
+ * - `integrationId` is `null` in the create wizard: nothing exists yet, the operator is
12752
+ * setting up a NEW instance.
12753
+ * - `mode` is the wizard mode of the integration type (`getAvailableTypes`).
12754
+ * - `candidateStableId` is the discovery candidate a wizard was seeded from, if any.
12755
+ */
12756
+ var IntegrationInstanceRefSchema = object({
12757
+ integrationId: string().nullable(),
12758
+ mode: _enum([
12759
+ "standalone",
12760
+ "account",
12761
+ "broker"
12762
+ ]),
12763
+ candidateStableId: string().optional()
12764
+ });
12765
+ /**
12718
12766
  * Build an `IAddonRouteProvider` from a list of routes. Implements
12719
12767
  * both the operator-facing `getRoutes` (returning route descriptors
12720
12768
  * minus the handlers, which can't cross JSON) and the framework-
@@ -16716,6 +16764,41 @@ var ACTUATOR_CAP_VOCABULARY = {
16716
16764
  icon: "droplets"
16717
16765
  }]
16718
16766
  },
16767
+ "power-source": {
16768
+ scope: "device",
16769
+ noun: t("Power source", "Alimentazione"),
16770
+ actions: [
16771
+ {
16772
+ id: "powerSource.on",
16773
+ method: "powerOn",
16774
+ label: t("Power on", "Dai corrente"),
16775
+ phrase: t("Power on {device}", "Dai corrente a {device}"),
16776
+ icon: "power"
16777
+ },
16778
+ {
16779
+ id: "powerSource.off",
16780
+ method: "powerOff",
16781
+ label: t("Power off", "Togli corrente"),
16782
+ phrase: t("Cut the power of {device}", "Togli la corrente a {device}"),
16783
+ icon: "power-off"
16784
+ },
16785
+ {
16786
+ id: "powerSource.forceRestart",
16787
+ method: "forceRestart",
16788
+ label: t("Force restart", "Riavvio forzato"),
16789
+ phrase: t("Force restart {device} by cutting its power", "Riavvia {device} togliendo la corrente"),
16790
+ icon: "refresh-cw"
16791
+ }
16792
+ ],
16793
+ state: [{
16794
+ kind: "boolean",
16795
+ field: "switchOn",
16796
+ label: t("Power switch on", "Presa accesa"),
16797
+ whenTrue: t("When the power of {device} comes on", "Quando arriva la corrente a {device}"),
16798
+ whenFalse: t("When the power of {device} is cut", "Quando manca la corrente a {device}"),
16799
+ icon: "power"
16800
+ }]
16801
+ },
16719
16802
  "lock-control": {
16720
16803
  scope: "device",
16721
16804
  noun: t("Lock", "Serratura"),
@@ -16797,6 +16880,11 @@ var ACTUATOR_CAP_VOCABULARY = {
16797
16880
  value: "jammed",
16798
16881
  label: t("Jammed", "Inceppata"),
16799
16882
  phrase: t("When {device} jams", "Quando {device} si inceppa")
16883
+ },
16884
+ {
16885
+ value: "door-open",
16886
+ label: t("Door open", "Porta aperta"),
16887
+ phrase: t("When the door of {device} opens", "Quando la porta di {device} si apre")
16800
16888
  }
16801
16889
  ],
16802
16890
  icon: "lock"
@@ -17186,7 +17274,7 @@ var ACTUATOR_CAP_VOCABULARY = {
17186
17274
  method: "setDirection",
17187
17275
  label: t("Spin forward", "Rotazione avanti"),
17188
17276
  phrase: t("Spin {device} forward", "Fai girare {device} in avanti"),
17189
- icon: "rotate-cw",
17277
+ icon: "refresh-cw",
17190
17278
  effect: {
17191
17279
  field: "direction",
17192
17280
  value: "forward"
@@ -43005,6 +43093,10 @@ method(object({
43005
43093
  }), method(object({
43006
43094
  addonId: string(),
43007
43095
  nodeId: string().optional()
43096
+ }), SettingsSchemaWithValuesSchema.nullable()), method(object({
43097
+ addonId: string(),
43098
+ nodeId: string().optional(),
43099
+ instance: IntegrationInstanceRefSchema
43008
43100
  }), SettingsSchemaWithValuesSchema.nullable()), method(object({
43009
43101
  addonId: string(),
43010
43102
  nodeId: string().optional()
@@ -45821,6 +45913,7 @@ method(object({
45821
45913
  kind: "mutation",
45822
45914
  auth: "admin"
45823
45915
  }), method(object({ blockIds: array(string()) }), object({ states: array(CompositionBlockStateSchema) }), { auth: "admin" });
45916
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, 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.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Gateway, DeviceType.Camera, DeviceType.Lock, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Gateway, DeviceType.Hub, DeviceType.Camera, DeviceType.Sensor, DeviceType.MediaPlayer, DeviceType.Vacuum, DeviceType.Generic, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
45824
45917
  var NUMBER = {
45825
45918
  kind: "fixed",
45826
45919
  result: ["number"]
@@ -65846,19 +65939,19 @@ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status:
65846
65939
  reason: _enum(["unknown-template", "not-a-media-player"]),
65847
65940
  detail: string()
65848
65941
  })]);
65849
- var deviceInput = object({ deviceId: number().int().nonnegative() });
65942
+ var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
65850
65943
  DeviceType.MediaPlayer;
65851
- method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
65944
+ method(deviceInput$1, RemoteConfigSchema, { auth: "admin" }), method(deviceInput$1.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
65852
65945
  kind: "mutation",
65853
65946
  auth: "admin"
65854
- }), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
65947
+ }), method(deviceInput$1, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput$1.extend({
65855
65948
  role: RemoteRoleSchema,
65856
65949
  /** Sends in a row (volume steps). */
65857
65950
  repeat: number().int().min(1).max(50).default(1)
65858
65951
  }), RemoteSendResultSchema, {
65859
65952
  kind: "mutation",
65860
65953
  auth: "protected"
65861
- }), method(deviceInput.extend({
65954
+ }), method(deviceInput$1.extend({
65862
65955
  command: RemoteMediaCommandSchema,
65863
65956
  muted: boolean().optional(),
65864
65957
  source: string().optional(),
@@ -69240,6 +69333,8 @@ var IntegrationWithStateSchema = object({
69240
69333
  name: string(),
69241
69334
  enabled: boolean(),
69242
69335
  info: record(string(), unknown()).readonly(),
69336
+ /** The discovery candidate this integration was set up from (D984). */
69337
+ originStableId: string().optional(),
69243
69338
  createdAt: number(),
69244
69339
  updatedAt: number(),
69245
69340
  processState: string()
@@ -69250,6 +69345,8 @@ var IntegrationLiteSchema = object({
69250
69345
  name: string(),
69251
69346
  enabled: boolean(),
69252
69347
  info: record(string(), unknown()).readonly(),
69348
+ /** The discovery candidate this integration was set up from (D984). */
69349
+ originStableId: string().optional(),
69253
69350
  createdAt: number(),
69254
69351
  updatedAt: number()
69255
69352
  });
@@ -69347,6 +69444,8 @@ var CreateIntegrationInputSchema = object({
69347
69444
  name: string(),
69348
69445
  enabled: boolean().optional(),
69349
69446
  info: record(string(), unknown()).optional(),
69447
+ /** `stableId` of the discovery candidate the form was seeded from (D984). */
69448
+ originStableId: string().optional(),
69350
69449
  settings: record(string(), unknown()).optional(),
69351
69450
  /** Keys of `settings` the form's schema declares secret (by type) — kept in
69352
69451
  * the keychain, not the table (D787). */
@@ -70115,11 +70214,44 @@ var LockControlStatusSchema = object({
70115
70214
  "unlocked",
70116
70215
  "locking",
70117
70216
  "unlocking",
70118
- "jammed"
70217
+ "jammed",
70218
+ "door-open"
70119
70219
  ]),
70120
70220
  /** Ms epoch when the slice was last updated. */
70121
70221
  lastChangedAt: number()
70122
70222
  });
70223
+ /**
70224
+ * "Door contact" Customize extension (D984): the ONE extension that replaces a
70225
+ * native field. `state` is listed in `overridable` for this target, so the
70226
+ * validator and the guard accept it and nothing else.
70227
+ */
70228
+ var lockControlCustomize = {
70229
+ version: 1,
70230
+ overridable: [{
70231
+ path: "state",
70232
+ by: "door-contact"
70233
+ }],
70234
+ targets: [{
70235
+ id: "door-contact",
70236
+ cardinality: "scalar",
70237
+ vocabulary: {
70238
+ cap: "lock-control",
70239
+ stateField: "state"
70240
+ },
70241
+ deviceTypes: [DeviceType.Lock],
70242
+ apply: "replace",
70243
+ path: "state",
70244
+ override: {
70245
+ whenSourceTrue: "door-open",
70246
+ unlessNative: ["jammed"]
70247
+ },
70248
+ sources: [{
70249
+ kind: "binary",
70250
+ transforms: [{ kind: "identity" }]
70251
+ }],
70252
+ sourceReport: { status: "assignment-status" }
70253
+ }]
70254
+ };
70123
70255
  var lockControlCapability = {
70124
70256
  name: "lock-control",
70125
70257
  scope: "device",
@@ -70165,6 +70297,7 @@ var lockControlCapability = {
70165
70297
  * transitions.
70166
70298
  */
70167
70299
  runtimeState: LockControlStatusSchema,
70300
+ customize: lockControlCustomize,
70168
70301
  /**
70169
70302
  * Runtime-state durability: **restored** — a lock left locked must still read locked.
70170
70303
  *
@@ -70181,6 +70314,109 @@ var lockControlCapability = {
70181
70314
  * whether persisting is worth a SQLite commit. */
70182
70315
  volatileStateFields: ["lastChangedAt"]
70183
70316
  };
70317
+ var PowerSourceRefusalReasonSchema = _enum([
70318
+ "no-power-source",
70319
+ "switch-missing",
70320
+ "switch-offline",
70321
+ "switch-unknown",
70322
+ "restart-in-progress",
70323
+ "switch-call-failed"
70324
+ ]);
70325
+ var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
70326
+ accepted: literal(false),
70327
+ reason: PowerSourceRefusalReasonSchema,
70328
+ /** One line for the operator, naming the switch. */
70329
+ message: string()
70330
+ })]);
70331
+ var PowerSourceInfoSchema = object({
70332
+ /** False when the device has no power source linked; the rest is then empty. */
70333
+ linked: boolean(),
70334
+ switchDeviceId: number().nullable(),
70335
+ switchName: string().nullable(),
70336
+ /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
70337
+ switchOn: boolean().nullable(),
70338
+ switchOnline: boolean().nullable(),
70339
+ restartInProgress: boolean(),
70340
+ offSeconds: number().int()
70341
+ });
70342
+ /** The composed slice: the switch state the link mirrors, plus the stored off time. */
70343
+ var PowerSourceStateSchema = object({
70344
+ /** Null while the switch has not reported: unknown is never `false` (D393). */
70345
+ switchOn: boolean().nullable(),
70346
+ offSeconds: number().int(),
70347
+ lastFetchedAt: number()
70348
+ });
70349
+ var POWER_SOURCE_DEVICE_TYPES = [
70350
+ DeviceType.Gateway,
70351
+ DeviceType.Hub,
70352
+ DeviceType.Camera,
70353
+ DeviceType.Sensor,
70354
+ DeviceType.MediaPlayer,
70355
+ DeviceType.Vacuum,
70356
+ DeviceType.Generic
70357
+ ];
70358
+ var powerSourceCustomize = {
70359
+ version: 1,
70360
+ targets: [{
70361
+ id: "switch",
70362
+ cardinality: "scalar",
70363
+ vocabulary: {
70364
+ cap: "power-source",
70365
+ stateField: "switchOn"
70366
+ },
70367
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
70368
+ apply: "add",
70369
+ path: "switchOn",
70370
+ sources: [{
70371
+ kind: "switch",
70372
+ transforms: [{ kind: "identity" }]
70373
+ }],
70374
+ companions: [{
70375
+ kind: "constant",
70376
+ path: "offSeconds",
70377
+ value: 10,
70378
+ when: "add"
70379
+ }, {
70380
+ kind: "clock",
70381
+ path: "lastFetchedAt",
70382
+ when: "always"
70383
+ }],
70384
+ sourceReport: { status: "assignment-status" }
70385
+ }]
70386
+ };
70387
+ var deviceInput = object({ deviceId: number().int().nonnegative() });
70388
+ var powerSourceCapability = {
70389
+ name: "power-source",
70390
+ scope: "device",
70391
+ mode: "singleton",
70392
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
70393
+ methods: {
70394
+ getStatus: systemMethod(deviceInput, PowerSourceInfoSchema, { auth: "admin" }),
70395
+ powerOn: systemMethod(deviceInput, PowerSourceActionResultSchema, {
70396
+ kind: "mutation",
70397
+ auth: "admin"
70398
+ }),
70399
+ powerOff: systemMethod(deviceInput, PowerSourceActionResultSchema, {
70400
+ kind: "mutation",
70401
+ auth: "admin"
70402
+ }),
70403
+ forceRestart: systemMethod(deviceInput, PowerSourceActionResultSchema, {
70404
+ kind: "mutation",
70405
+ auth: "admin"
70406
+ })
70407
+ },
70408
+ runtimeState: PowerSourceStateSchema,
70409
+ customize: powerSourceCustomize,
70410
+ /**
70411
+ * Runtime-state durability: **session** — mirrored from the linked switch on
70412
+ * its next report; a restored value would outlive the reading it names.
70413
+ *
70414
+ * See `RuntimeStateDurability`. Enforced by
70415
+ * `scripts/check-runtime-state-durability.ts`.
70416
+ */
70417
+ durability: "session",
70418
+ history: "none"
70419
+ };
70184
70420
  /**
70185
70421
  * A monotonic total between resets (D944). Energy uses `power-meter.energy`
70186
70422
  * so dashboards keep one series; every other instantaneous reading lands here.
@@ -78614,7 +78850,6 @@ function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
78614
78850
  }
78615
78851
  DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
78616
78852
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
78617
- DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, 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.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Gateway, DeviceType.Camera, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
78618
78853
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
78619
78854
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
78620
78855
  new Set(CAP_NAMES);
@@ -78967,6 +79202,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
78967
79202
  petFeeder: petFeederCapability,
78968
79203
  petFountain: petFountainCapability,
78969
79204
  powerMeter: powerMeterCapability,
79205
+ powerSource: powerSourceCapability,
78970
79206
  presence: presenceCapability,
78971
79207
  pressureSensor: pressureSensorCapability,
78972
79208
  privacyMask: privacyMaskCapability,
@@ -80636,6 +80872,13 @@ Object.freeze({
80636
80872
  access: "view",
80637
80873
  role: "admin"
80638
80874
  },
80875
+ "addonSettings.getIntegrationFormSchema": {
80876
+ capName: "addon-settings",
80877
+ capScope: "system",
80878
+ addonId: null,
80879
+ access: "view",
80880
+ role: "admin"
80881
+ },
80639
80882
  "addonSettings.getIntegrationSettings": {
80640
80883
  capName: "addon-settings",
80641
80884
  capScope: "system",
@@ -87356,6 +87599,34 @@ Object.freeze({
87356
87599
  access: "view",
87357
87600
  role: "viewer"
87358
87601
  },
87602
+ "powerSource.forceRestart": {
87603
+ capName: "power-source",
87604
+ capScope: "device",
87605
+ addonId: null,
87606
+ access: "create",
87607
+ role: "admin"
87608
+ },
87609
+ "powerSource.getStatus": {
87610
+ capName: "power-source",
87611
+ capScope: "device",
87612
+ addonId: null,
87613
+ access: "view",
87614
+ role: "admin"
87615
+ },
87616
+ "powerSource.powerOff": {
87617
+ capName: "power-source",
87618
+ capScope: "device",
87619
+ addonId: null,
87620
+ access: "create",
87621
+ role: "admin"
87622
+ },
87623
+ "powerSource.powerOn": {
87624
+ capName: "power-source",
87625
+ capScope: "device",
87626
+ addonId: null,
87627
+ access: "create",
87628
+ role: "admin"
87629
+ },
87359
87630
  "presence.getStatus": {
87360
87631
  capName: "presence",
87361
87632
  capScope: "device",
@@ -92515,6 +92786,26 @@ Object.freeze({
92515
92786
  form: "single",
92516
92787
  optional: false
92517
92788
  }],
92789
+ "powerSource.forceRestart": [{
92790
+ name: "deviceId",
92791
+ form: "single",
92792
+ optional: false
92793
+ }],
92794
+ "powerSource.getStatus": [{
92795
+ name: "deviceId",
92796
+ form: "single",
92797
+ optional: false
92798
+ }],
92799
+ "powerSource.powerOff": [{
92800
+ name: "deviceId",
92801
+ form: "single",
92802
+ optional: false
92803
+ }],
92804
+ "powerSource.powerOn": [{
92805
+ name: "deviceId",
92806
+ form: "single",
92807
+ optional: false
92808
+ }],
92518
92809
  "presence.getStatus": [{
92519
92810
  name: "deviceId",
92520
92811
  form: "single",
@@ -94445,6 +94736,7 @@ new Set([
94445
94736
  "locking",
94446
94737
  "unlocking",
94447
94738
  "jammed",
94739
+ "door-open",
94448
94740
  "on",
94449
94741
  "off",
94450
94742
  "home",
@@ -5588,7 +5588,7 @@ var ZodIssueCode = {
5588
5588
  var ZodFirstPartyTypeKind;
5589
5589
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5590
5590
  //#endregion
5591
- //#region ../types/dist/sleep-0RR2wzNB.mjs
5591
+ //#region ../types/dist/sleep-dco0-jRo.mjs
5592
5592
  /**
5593
5593
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5594
5594
  * window to float samples (D455).
@@ -7291,6 +7291,26 @@ var BaseAddon = class {
7291
7291
  * alternative — skip it — turns a rename into a surface that quietly
7292
7292
  * empties, which looks exactly like an addon with nothing to configure.
7293
7293
  */
7294
+ /**
7295
+ * The form schema of ONE integration instance, or `null` to use {@link globalSettingsSchema}.
7296
+ *
7297
+ * Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
7298
+ * needs its connection fields, the default integration the addon's own sections. It is the
7299
+ * SHAPE of the form only — the values live in `integrations.getSettings`, and the write path is
7300
+ * unchanged (`integrations.setSettings` for an account integration).
7301
+ */
7302
+ async integrationSettingsSchema(_instance) {
7303
+ return null;
7304
+ }
7305
+ /**
7306
+ * What the create wizard and the integration edit page render for one instance: the addon's
7307
+ * per-instance schema when it declares one, else its global schema (what they always showed).
7308
+ */
7309
+ async getIntegrationFormSchema(instance, nodeId) {
7310
+ const scoped = await this.integrationSettingsSchema(instance);
7311
+ if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
7312
+ return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
7313
+ }
7294
7314
  async getIntegrationSettings(nodeId) {
7295
7315
  const declared = this.integrationSettingSections();
7296
7316
  if (declared.length === 0) return null;
@@ -9264,6 +9284,7 @@ var CAP_NAMES = Object.freeze([
9264
9284
  "plate-gallery",
9265
9285
  "platform-probe",
9266
9286
  "power-meter",
9287
+ "power-source",
9267
9288
  "presence",
9268
9289
  "pressure-sensor",
9269
9290
  "privacy-mask",
@@ -10227,7 +10248,8 @@ Object.freeze({
10227
10248
  "unlocked",
10228
10249
  "locking",
10229
10250
  "unlocking",
10230
- "jammed"
10251
+ "jammed",
10252
+ "door-open"
10231
10253
  ]
10232
10254
  }],
10233
10255
  "media-player": [
@@ -10614,6 +10636,13 @@ Object.freeze({
10614
10636
  "valueType": "number"
10615
10637
  }
10616
10638
  ],
10639
+ "power-source": [{
10640
+ "path": "switchOn",
10641
+ "valueType": "boolean"
10642
+ }, {
10643
+ "path": "offSeconds",
10644
+ "valueType": "number"
10645
+ }],
10617
10646
  "presence": [
10618
10647
  {
10619
10648
  "path": "state",
@@ -12716,6 +12745,25 @@ var EventOwnerTypeSchema = _enum(EVENT_OWNER_TYPES);
12716
12745
  var MediaPresenceOwnerKindSchema = _enum([...EVENT_OWNER_TYPES, "track"]);
12717
12746
  new Set(EVENT_OWNER_TYPES);
12718
12747
  /**
12748
+ * Which integration instance a settings form is for. An addon that serves several instances
12749
+ * (`instanceMode: multiple`) can show a different form per instance — an NVR integration
12750
+ * needs its connection, the default integration needs the addon's own sections.
12751
+ *
12752
+ * - `integrationId` is `null` in the create wizard: nothing exists yet, the operator is
12753
+ * setting up a NEW instance.
12754
+ * - `mode` is the wizard mode of the integration type (`getAvailableTypes`).
12755
+ * - `candidateStableId` is the discovery candidate a wizard was seeded from, if any.
12756
+ */
12757
+ var IntegrationInstanceRefSchema = object({
12758
+ integrationId: string().nullable(),
12759
+ mode: _enum([
12760
+ "standalone",
12761
+ "account",
12762
+ "broker"
12763
+ ]),
12764
+ candidateStableId: string().optional()
12765
+ });
12766
+ /**
12719
12767
  * Build an `IAddonRouteProvider` from a list of routes. Implements
12720
12768
  * both the operator-facing `getRoutes` (returning route descriptors
12721
12769
  * minus the handlers, which can't cross JSON) and the framework-
@@ -16717,6 +16765,41 @@ var ACTUATOR_CAP_VOCABULARY = {
16717
16765
  icon: "droplets"
16718
16766
  }]
16719
16767
  },
16768
+ "power-source": {
16769
+ scope: "device",
16770
+ noun: t("Power source", "Alimentazione"),
16771
+ actions: [
16772
+ {
16773
+ id: "powerSource.on",
16774
+ method: "powerOn",
16775
+ label: t("Power on", "Dai corrente"),
16776
+ phrase: t("Power on {device}", "Dai corrente a {device}"),
16777
+ icon: "power"
16778
+ },
16779
+ {
16780
+ id: "powerSource.off",
16781
+ method: "powerOff",
16782
+ label: t("Power off", "Togli corrente"),
16783
+ phrase: t("Cut the power of {device}", "Togli la corrente a {device}"),
16784
+ icon: "power-off"
16785
+ },
16786
+ {
16787
+ id: "powerSource.forceRestart",
16788
+ method: "forceRestart",
16789
+ label: t("Force restart", "Riavvio forzato"),
16790
+ phrase: t("Force restart {device} by cutting its power", "Riavvia {device} togliendo la corrente"),
16791
+ icon: "refresh-cw"
16792
+ }
16793
+ ],
16794
+ state: [{
16795
+ kind: "boolean",
16796
+ field: "switchOn",
16797
+ label: t("Power switch on", "Presa accesa"),
16798
+ whenTrue: t("When the power of {device} comes on", "Quando arriva la corrente a {device}"),
16799
+ whenFalse: t("When the power of {device} is cut", "Quando manca la corrente a {device}"),
16800
+ icon: "power"
16801
+ }]
16802
+ },
16720
16803
  "lock-control": {
16721
16804
  scope: "device",
16722
16805
  noun: t("Lock", "Serratura"),
@@ -16798,6 +16881,11 @@ var ACTUATOR_CAP_VOCABULARY = {
16798
16881
  value: "jammed",
16799
16882
  label: t("Jammed", "Inceppata"),
16800
16883
  phrase: t("When {device} jams", "Quando {device} si inceppa")
16884
+ },
16885
+ {
16886
+ value: "door-open",
16887
+ label: t("Door open", "Porta aperta"),
16888
+ phrase: t("When the door of {device} opens", "Quando la porta di {device} si apre")
16801
16889
  }
16802
16890
  ],
16803
16891
  icon: "lock"
@@ -17187,7 +17275,7 @@ var ACTUATOR_CAP_VOCABULARY = {
17187
17275
  method: "setDirection",
17188
17276
  label: t("Spin forward", "Rotazione avanti"),
17189
17277
  phrase: t("Spin {device} forward", "Fai girare {device} in avanti"),
17190
- icon: "rotate-cw",
17278
+ icon: "refresh-cw",
17191
17279
  effect: {
17192
17280
  field: "direction",
17193
17281
  value: "forward"
@@ -43006,6 +43094,10 @@ method(object({
43006
43094
  }), method(object({
43007
43095
  addonId: string(),
43008
43096
  nodeId: string().optional()
43097
+ }), SettingsSchemaWithValuesSchema.nullable()), method(object({
43098
+ addonId: string(),
43099
+ nodeId: string().optional(),
43100
+ instance: IntegrationInstanceRefSchema
43009
43101
  }), SettingsSchemaWithValuesSchema.nullable()), method(object({
43010
43102
  addonId: string(),
43011
43103
  nodeId: string().optional()
@@ -45822,6 +45914,7 @@ method(object({
45822
45914
  kind: "mutation",
45823
45915
  auth: "admin"
45824
45916
  }), method(object({ blockIds: array(string()) }), object({ states: array(CompositionBlockStateSchema) }), { auth: "admin" });
45917
+ DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, 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.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Gateway, DeviceType.Camera, DeviceType.Lock, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Gateway, DeviceType.Hub, DeviceType.Camera, DeviceType.Sensor, DeviceType.MediaPlayer, DeviceType.Vacuum, DeviceType.Generic, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
45825
45918
  var NUMBER = {
45826
45919
  kind: "fixed",
45827
45920
  result: ["number"]
@@ -65847,19 +65940,19 @@ var RemoteSetConfigResultSchema = discriminatedUnion("status", [object({ status:
65847
65940
  reason: _enum(["unknown-template", "not-a-media-player"]),
65848
65941
  detail: string()
65849
65942
  })]);
65850
- var deviceInput = object({ deviceId: number().int().nonnegative() });
65943
+ var deviceInput$1 = object({ deviceId: number().int().nonnegative() });
65851
65944
  DeviceType.MediaPlayer;
65852
- method(deviceInput, RemoteConfigSchema, { auth: "admin" }), method(deviceInput.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
65945
+ method(deviceInput$1, RemoteConfigSchema, { auth: "admin" }), method(deviceInput$1.extend({ config: RemoteConfigSchema }), RemoteSetConfigResultSchema, {
65853
65946
  kind: "mutation",
65854
65947
  auth: "admin"
65855
- }), method(deviceInput, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput.extend({
65948
+ }), method(deviceInput$1, RemoteCommandListSchema, { auth: "protected" }), method(deviceInput$1.extend({
65856
65949
  role: RemoteRoleSchema,
65857
65950
  /** Sends in a row (volume steps). */
65858
65951
  repeat: number().int().min(1).max(50).default(1)
65859
65952
  }), RemoteSendResultSchema, {
65860
65953
  kind: "mutation",
65861
65954
  auth: "protected"
65862
- }), method(deviceInput.extend({
65955
+ }), method(deviceInput$1.extend({
65863
65956
  command: RemoteMediaCommandSchema,
65864
65957
  muted: boolean().optional(),
65865
65958
  source: string().optional(),
@@ -69241,6 +69334,8 @@ var IntegrationWithStateSchema = object({
69241
69334
  name: string(),
69242
69335
  enabled: boolean(),
69243
69336
  info: record(string(), unknown()).readonly(),
69337
+ /** The discovery candidate this integration was set up from (D984). */
69338
+ originStableId: string().optional(),
69244
69339
  createdAt: number(),
69245
69340
  updatedAt: number(),
69246
69341
  processState: string()
@@ -69251,6 +69346,8 @@ var IntegrationLiteSchema = object({
69251
69346
  name: string(),
69252
69347
  enabled: boolean(),
69253
69348
  info: record(string(), unknown()).readonly(),
69349
+ /** The discovery candidate this integration was set up from (D984). */
69350
+ originStableId: string().optional(),
69254
69351
  createdAt: number(),
69255
69352
  updatedAt: number()
69256
69353
  });
@@ -69348,6 +69445,8 @@ var CreateIntegrationInputSchema = object({
69348
69445
  name: string(),
69349
69446
  enabled: boolean().optional(),
69350
69447
  info: record(string(), unknown()).optional(),
69448
+ /** `stableId` of the discovery candidate the form was seeded from (D984). */
69449
+ originStableId: string().optional(),
69351
69450
  settings: record(string(), unknown()).optional(),
69352
69451
  /** Keys of `settings` the form's schema declares secret (by type) — kept in
69353
69452
  * the keychain, not the table (D787). */
@@ -70116,11 +70215,44 @@ var LockControlStatusSchema = object({
70116
70215
  "unlocked",
70117
70216
  "locking",
70118
70217
  "unlocking",
70119
- "jammed"
70218
+ "jammed",
70219
+ "door-open"
70120
70220
  ]),
70121
70221
  /** Ms epoch when the slice was last updated. */
70122
70222
  lastChangedAt: number()
70123
70223
  });
70224
+ /**
70225
+ * "Door contact" Customize extension (D984): the ONE extension that replaces a
70226
+ * native field. `state` is listed in `overridable` for this target, so the
70227
+ * validator and the guard accept it and nothing else.
70228
+ */
70229
+ var lockControlCustomize = {
70230
+ version: 1,
70231
+ overridable: [{
70232
+ path: "state",
70233
+ by: "door-contact"
70234
+ }],
70235
+ targets: [{
70236
+ id: "door-contact",
70237
+ cardinality: "scalar",
70238
+ vocabulary: {
70239
+ cap: "lock-control",
70240
+ stateField: "state"
70241
+ },
70242
+ deviceTypes: [DeviceType.Lock],
70243
+ apply: "replace",
70244
+ path: "state",
70245
+ override: {
70246
+ whenSourceTrue: "door-open",
70247
+ unlessNative: ["jammed"]
70248
+ },
70249
+ sources: [{
70250
+ kind: "binary",
70251
+ transforms: [{ kind: "identity" }]
70252
+ }],
70253
+ sourceReport: { status: "assignment-status" }
70254
+ }]
70255
+ };
70124
70256
  var lockControlCapability = {
70125
70257
  name: "lock-control",
70126
70258
  scope: "device",
@@ -70166,6 +70298,7 @@ var lockControlCapability = {
70166
70298
  * transitions.
70167
70299
  */
70168
70300
  runtimeState: LockControlStatusSchema,
70301
+ customize: lockControlCustomize,
70169
70302
  /**
70170
70303
  * Runtime-state durability: **restored** — a lock left locked must still read locked.
70171
70304
  *
@@ -70182,6 +70315,109 @@ var lockControlCapability = {
70182
70315
  * whether persisting is worth a SQLite commit. */
70183
70316
  volatileStateFields: ["lastChangedAt"]
70184
70317
  };
70318
+ var PowerSourceRefusalReasonSchema = _enum([
70319
+ "no-power-source",
70320
+ "switch-missing",
70321
+ "switch-offline",
70322
+ "switch-unknown",
70323
+ "restart-in-progress",
70324
+ "switch-call-failed"
70325
+ ]);
70326
+ var PowerSourceActionResultSchema = discriminatedUnion("accepted", [object({ accepted: literal(true) }), object({
70327
+ accepted: literal(false),
70328
+ reason: PowerSourceRefusalReasonSchema,
70329
+ /** One line for the operator, naming the switch. */
70330
+ message: string()
70331
+ })]);
70332
+ var PowerSourceInfoSchema = object({
70333
+ /** False when the device has no power source linked; the rest is then empty. */
70334
+ linked: boolean(),
70335
+ switchDeviceId: number().nullable(),
70336
+ switchName: string().nullable(),
70337
+ /** The switch's on/off state, or null when it is unknown. Never false for unknown (D393). */
70338
+ switchOn: boolean().nullable(),
70339
+ switchOnline: boolean().nullable(),
70340
+ restartInProgress: boolean(),
70341
+ offSeconds: number().int()
70342
+ });
70343
+ /** The composed slice: the switch state the link mirrors, plus the stored off time. */
70344
+ var PowerSourceStateSchema = object({
70345
+ /** Null while the switch has not reported: unknown is never `false` (D393). */
70346
+ switchOn: boolean().nullable(),
70347
+ offSeconds: number().int(),
70348
+ lastFetchedAt: number()
70349
+ });
70350
+ var POWER_SOURCE_DEVICE_TYPES = [
70351
+ DeviceType.Gateway,
70352
+ DeviceType.Hub,
70353
+ DeviceType.Camera,
70354
+ DeviceType.Sensor,
70355
+ DeviceType.MediaPlayer,
70356
+ DeviceType.Vacuum,
70357
+ DeviceType.Generic
70358
+ ];
70359
+ var powerSourceCustomize = {
70360
+ version: 1,
70361
+ targets: [{
70362
+ id: "switch",
70363
+ cardinality: "scalar",
70364
+ vocabulary: {
70365
+ cap: "power-source",
70366
+ stateField: "switchOn"
70367
+ },
70368
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
70369
+ apply: "add",
70370
+ path: "switchOn",
70371
+ sources: [{
70372
+ kind: "switch",
70373
+ transforms: [{ kind: "identity" }]
70374
+ }],
70375
+ companions: [{
70376
+ kind: "constant",
70377
+ path: "offSeconds",
70378
+ value: 10,
70379
+ when: "add"
70380
+ }, {
70381
+ kind: "clock",
70382
+ path: "lastFetchedAt",
70383
+ when: "always"
70384
+ }],
70385
+ sourceReport: { status: "assignment-status" }
70386
+ }]
70387
+ };
70388
+ var deviceInput = object({ deviceId: number().int().nonnegative() });
70389
+ var powerSourceCapability = {
70390
+ name: "power-source",
70391
+ scope: "device",
70392
+ mode: "singleton",
70393
+ deviceTypes: POWER_SOURCE_DEVICE_TYPES,
70394
+ methods: {
70395
+ getStatus: systemMethod(deviceInput, PowerSourceInfoSchema, { auth: "admin" }),
70396
+ powerOn: systemMethod(deviceInput, PowerSourceActionResultSchema, {
70397
+ kind: "mutation",
70398
+ auth: "admin"
70399
+ }),
70400
+ powerOff: systemMethod(deviceInput, PowerSourceActionResultSchema, {
70401
+ kind: "mutation",
70402
+ auth: "admin"
70403
+ }),
70404
+ forceRestart: systemMethod(deviceInput, PowerSourceActionResultSchema, {
70405
+ kind: "mutation",
70406
+ auth: "admin"
70407
+ })
70408
+ },
70409
+ runtimeState: PowerSourceStateSchema,
70410
+ customize: powerSourceCustomize,
70411
+ /**
70412
+ * Runtime-state durability: **session** — mirrored from the linked switch on
70413
+ * its next report; a restored value would outlive the reading it names.
70414
+ *
70415
+ * See `RuntimeStateDurability`. Enforced by
70416
+ * `scripts/check-runtime-state-durability.ts`.
70417
+ */
70418
+ durability: "session",
70419
+ history: "none"
70420
+ };
70185
70421
  /**
70186
70422
  * A monotonic total between resets (D944). Energy uses `power-meter.energy`
70187
70423
  * so dashboards keep one series; every other instantaneous reading lands here.
@@ -78615,7 +78851,6 @@ function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
78615
78851
  }
78616
78852
  DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
78617
78853
  SOURCE_CAPS.filter((cap) => cap !== "switch" && cap !== "motion");
78618
- DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, DeviceType.EventEmitter, 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.PetFountain, DeviceType.Dishwasher, DeviceType.Washer, DeviceType.Dryer, DeviceType.Gateway, DeviceType.Camera, DeviceType.Camera, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.Switch, DeviceType.Light, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.PetFeeder, DeviceType.MediaPlayer, DeviceType.Washer, DeviceType.Dryer, DeviceType.Dishwasher, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.MediaPlayer, DeviceType.WaterHeater, DeviceType.Humidifier, DeviceType.Fan, DeviceType.Climate, DeviceType.Thermostat, DeviceType.PetFeeder;
78619
78854
  String.raw`rose\(active(\d+), changed(\d+), (\d+(?:\.\d+)?)\)`;
78620
78855
  DeviceRole.BinarySensor, DeviceRole.MotionSensor;
78621
78856
  new Set(CAP_NAMES);
@@ -78968,6 +79203,7 @@ var DEVICE_LOCAL_STATE_CAPS = {
78968
79203
  petFeeder: petFeederCapability,
78969
79204
  petFountain: petFountainCapability,
78970
79205
  powerMeter: powerMeterCapability,
79206
+ powerSource: powerSourceCapability,
78971
79207
  presence: presenceCapability,
78972
79208
  pressureSensor: pressureSensorCapability,
78973
79209
  privacyMask: privacyMaskCapability,
@@ -80637,6 +80873,13 @@ Object.freeze({
80637
80873
  access: "view",
80638
80874
  role: "admin"
80639
80875
  },
80876
+ "addonSettings.getIntegrationFormSchema": {
80877
+ capName: "addon-settings",
80878
+ capScope: "system",
80879
+ addonId: null,
80880
+ access: "view",
80881
+ role: "admin"
80882
+ },
80640
80883
  "addonSettings.getIntegrationSettings": {
80641
80884
  capName: "addon-settings",
80642
80885
  capScope: "system",
@@ -87357,6 +87600,34 @@ Object.freeze({
87357
87600
  access: "view",
87358
87601
  role: "viewer"
87359
87602
  },
87603
+ "powerSource.forceRestart": {
87604
+ capName: "power-source",
87605
+ capScope: "device",
87606
+ addonId: null,
87607
+ access: "create",
87608
+ role: "admin"
87609
+ },
87610
+ "powerSource.getStatus": {
87611
+ capName: "power-source",
87612
+ capScope: "device",
87613
+ addonId: null,
87614
+ access: "view",
87615
+ role: "admin"
87616
+ },
87617
+ "powerSource.powerOff": {
87618
+ capName: "power-source",
87619
+ capScope: "device",
87620
+ addonId: null,
87621
+ access: "create",
87622
+ role: "admin"
87623
+ },
87624
+ "powerSource.powerOn": {
87625
+ capName: "power-source",
87626
+ capScope: "device",
87627
+ addonId: null,
87628
+ access: "create",
87629
+ role: "admin"
87630
+ },
87360
87631
  "presence.getStatus": {
87361
87632
  capName: "presence",
87362
87633
  capScope: "device",
@@ -92516,6 +92787,26 @@ Object.freeze({
92516
92787
  form: "single",
92517
92788
  optional: false
92518
92789
  }],
92790
+ "powerSource.forceRestart": [{
92791
+ name: "deviceId",
92792
+ form: "single",
92793
+ optional: false
92794
+ }],
92795
+ "powerSource.getStatus": [{
92796
+ name: "deviceId",
92797
+ form: "single",
92798
+ optional: false
92799
+ }],
92800
+ "powerSource.powerOff": [{
92801
+ name: "deviceId",
92802
+ form: "single",
92803
+ optional: false
92804
+ }],
92805
+ "powerSource.powerOn": [{
92806
+ name: "deviceId",
92807
+ form: "single",
92808
+ optional: false
92809
+ }],
92519
92810
  "presence.getStatus": [{
92520
92811
  name: "deviceId",
92521
92812
  form: "single",
@@ -94446,6 +94737,7 @@ new Set([
94446
94737
  "locking",
94447
94738
  "unlocking",
94448
94739
  "jammed",
94740
+ "door-open",
94449
94741
  "on",
94450
94742
  "off",
94451
94743
  "home",
@@ -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_ha_broker_source = require("../ha-broker-source-D3_ZXq6l.js");
27
+ const require_ha_broker_source = require("../ha-broker-source-zbaephU5.js");
28
28
  let node_crypto = require("node:crypto");
29
29
  require("node:zlib");
30
30
  let node_fs = require("node:fs");
@@ -1030,7 +1030,7 @@ var NATIVE_CAP_PLATFORMS = {
1030
1030
  },
1031
1031
  /**
1032
1032
  * The reason this platform exists. `LockStateSchema` is
1033
- * `locked | unlocked | locking | unlocking | jammed`, and every one of
1033
+ * `locked | unlocked | locking | unlocking | jammed | door-open`, and every one of
1034
1034
  * those is a state Home Assistant's `lock` has — including the one a
1035
1035
  * `switch` silently reports as "unlocked".
1036
1036
  *
@@ -1047,7 +1047,17 @@ var NATIVE_CAP_PLATFORMS = {
1047
1047
  controls: { open: {
1048
1048
  from: "open",
1049
1049
  commandOnly: true
1050
- } }
1050
+ } },
1051
+ /**
1052
+ * `door-open` (D984: the linked door contact reads open) is no state of
1053
+ * Home Assistant's lock, but `open` is — the platform's own word for a
1054
+ * door standing open. The enum is rewritten on the way in, so the enum
1055
+ * sensor beside it keeps the cap's own value.
1056
+ */
1057
+ constants: {
1058
+ state_open: "open",
1059
+ value_template: "{{ 'open' if value == 'door-open' else value }}"
1060
+ }
1051
1061
  },
1052
1062
  /**
1053
1063
  * `AlarmStateSchema` IS Home Assistant's alarm vocabulary, and
@@ -3475,6 +3485,10 @@ function controlEntitySpecs(slice, quantity) {
3475
3485
  }, kindExtra];
3476
3486
  }
3477
3487
  var CAPS_NOT_EXPORTED = [
3488
+ {
3489
+ cap: "power-source",
3490
+ reason: "A manual admin recovery action (cut the power of a device that hangs) on a switch that is already exported as itself; publishing a restart button beside it would hand an ecosystem the means to cut a device off by mistake."
3491
+ },
3478
3492
  {
3479
3493
  cap: "pet-fountain",
3480
3494
  reason: "A fountain is BUILT here from the loose entities Home Assistant already holds (a pump switch, two number boxes, a button), so exporting it back would publish a second copy of entities that already exist there. A dedicated mapping can follow when an ecosystem asks for the built device."
@@ -1,4 +1,4 @@
1
- import { $t as array, B as consumableKindOf, Et as sendToExportedTarget, Gt as baseUnitOf, K as deviceExportCapability, Ut as BaseAddon, Xt as isReadingQuantity, Zt as nodePin, _ as PLUG_APPLIANCE_TYPES, bt as runExportedAction, c as COCO_TO_MACRO, cn as unknown, d as ConsumableItemSchema, f as ConsumableStatusSchema, g as MediaPlayerRepeatSchema, gt as pruneDeletedEntities, h as HvacModeSchema, i as AlarmArmModeSchema, in as object, j as buildAddonRouteProvider, l as CameraSwitchIdSchema, m as FanDirectionSchema, on as string, r as listHomeAssistantBrokers, s as CAMERA_SWITCH_ORDER, u as ConsumableFormSchema, un as EventCategory, ut as oauthIntegrationCapability, x as addonRoutesCapability, z as consumableFormOf } from "../ha-broker-source-vytM8SXk.mjs";
1
+ import { $t as array, B as consumableKindOf, Et as sendToExportedTarget, Gt as baseUnitOf, K as deviceExportCapability, Ut as BaseAddon, Xt as isReadingQuantity, Zt as nodePin, _ as PLUG_APPLIANCE_TYPES, bt as runExportedAction, c as COCO_TO_MACRO, cn as unknown, d as ConsumableItemSchema, f as ConsumableStatusSchema, g as MediaPlayerRepeatSchema, gt as pruneDeletedEntities, h as HvacModeSchema, i as AlarmArmModeSchema, in as object, j as buildAddonRouteProvider, l as CameraSwitchIdSchema, m as FanDirectionSchema, on as string, r as listHomeAssistantBrokers, s as CAMERA_SWITCH_ORDER, u as ConsumableFormSchema, un as EventCategory, ut as oauthIntegrationCapability, x as addonRoutesCapability, z as consumableFormOf } from "../ha-broker-source-DxSvfCed.mjs";
2
2
  import { createHmac, timingSafeEqual } from "node:crypto";
3
3
  import "node:zlib";
4
4
  import "node:fs";
@@ -995,7 +995,7 @@ var NATIVE_CAP_PLATFORMS = {
995
995
  },
996
996
  /**
997
997
  * The reason this platform exists. `LockStateSchema` is
998
- * `locked | unlocked | locking | unlocking | jammed`, and every one of
998
+ * `locked | unlocked | locking | unlocking | jammed | door-open`, and every one of
999
999
  * those is a state Home Assistant's `lock` has — including the one a
1000
1000
  * `switch` silently reports as "unlocked".
1001
1001
  *
@@ -1012,7 +1012,17 @@ var NATIVE_CAP_PLATFORMS = {
1012
1012
  controls: { open: {
1013
1013
  from: "open",
1014
1014
  commandOnly: true
1015
- } }
1015
+ } },
1016
+ /**
1017
+ * `door-open` (D984: the linked door contact reads open) is no state of
1018
+ * Home Assistant's lock, but `open` is — the platform's own word for a
1019
+ * door standing open. The enum is rewritten on the way in, so the enum
1020
+ * sensor beside it keeps the cap's own value.
1021
+ */
1022
+ constants: {
1023
+ state_open: "open",
1024
+ value_template: "{{ 'open' if value == 'door-open' else value }}"
1025
+ }
1016
1026
  },
1017
1027
  /**
1018
1028
  * `AlarmStateSchema` IS Home Assistant's alarm vocabulary, and
@@ -3440,6 +3450,10 @@ function controlEntitySpecs(slice, quantity) {
3440
3450
  }, kindExtra];
3441
3451
  }
3442
3452
  var CAPS_NOT_EXPORTED = [
3453
+ {
3454
+ cap: "power-source",
3455
+ reason: "A manual admin recovery action (cut the power of a device that hangs) on a switch that is already exported as itself; publishing a restart button beside it would hand an ecosystem the means to cut a device off by mistake."
3456
+ },
3443
3457
  {
3444
3458
  cap: "pet-fountain",
3445
3459
  reason: "A fountain is BUILT here from the loose entities Home Assistant already holds (a pump switch, two number boxes, a button), so exporting it back would publish a second copy of entities that already exist there. A dedicated mapping can follow when an ecosystem asks for the built device."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homeassistant",
3
- "version": "1.2.641",
3
+ "version": "1.2.643",
4
4
  "description": "Home Assistant device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",