@camstack/addon-provider-homeassistant 1.2.659 → 1.2.661

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as fanControlCapability, $t as createEvent, A as bestLocationMatch, At as runningFromMediaPlayer, B as climateControlCapability, Bt as tryConvertDelta, C as accessoriesCapability, Ct as pressureSensorCapability, D as ambientLightSensorCapability, Dt as resolveAttachmentUrls, E as alarmPanelCapability, Et as quantityFromUnit, F as buildAddonRouteProvider, Ft as smokeCapability, G as contactCapability, Gt as vibrationCapability, H as connectivityCapability, Ht as updateCapability, I as buildDeviceAdminUrl, J as deviceAdminLinkCapability, K as controlCapability, Kt as waterHeaterCapability, L as buttonCapability, Lt as switchCapability, M as boardKeySourceCapability, Mt as runningStateCapability, N as brightnessCapability, Nt as scriptRunnerCapability, O as automationControlCapability, P as brokerCapability, Q as eventEmitterCapability, Qt as baseUnitOf, R as calendarSourceCapability, Rt as tamperCapability, S as TargetSchema, Sn as EventCategory, St as presenceCapability, T as airQualitySensorCapability, Tt as publicEndpointReaderFrom, Ut as vacuumControlCapability, V as colorCapability, Vt as tryConvertUnit, Wt as valveCapability, Xt as RecordSecretUnavailableError, Y as deviceAdoptionCapability, Z as enumSensorCapability, _n as url, at as humiditySensorCapability, b as RUNNING_STATE_COLD, bn as DeviceType, bt as preconditionOf, cn as boolean, ct as integrationInstancesCapability, dn as number, dt as mediaPlayerCapability, en as defineAddonMigrations, et as flattenNestedRecords, fn as object, ft as motionCapability, gn as unknown, gt as numericSensorCapability, hn as union, ht as notifierCapability, it as humidifierCapability, j as binaryCapability, jt as runningFromVacuumState, k as batteryCapability, kt as runningFromLawnMower, ln as discriminatedUnion, lt as lawnMowerControlCapability, m as EnumSensorDateTimeFormatSchema, mn as string, mt as notificationOutputCapability, n as HA_BROKER_KIND, nn as defineRecordKinds, nt as floodCapability, o as BaseDevice, on as _enum, ot as imageCapability, pn as record, pt as normalizeUnit, q as coverCapability, qt as weatherCapability, rn as entryBody, rt as gasCapability, s as BaseDeviceProvider, sn as array, st as ingestReading, t as haInstanceSettingsPortsOver, tn as defineEntryKind, tt as flattenPortsOver, un as literal, ut as lockControlCapability, vn as DeviceFeature, vt as parseAdminBase, w as addonRoutesCapability, x as RecordIntegrationInstances, xn as errMsg, xt as prepareNotification, yn as DeviceRole, yt as powerMeterCapability, z as carbonMonoxideCapability, zt as temperatureSensorCapability } from "./ha-instance-settings-qhCNJbbn.mjs";
1
+ import { $ as fanControlCapability, $t as createEvent, A as bestLocationMatch, At as runningFromMediaPlayer, B as climateControlCapability, Bt as tryConvertDelta, C as accessoriesCapability, Ct as pressureSensorCapability, D as ambientLightSensorCapability, Dt as resolveAttachmentUrls, E as alarmPanelCapability, Et as quantityFromUnit, F as buildAddonRouteProvider, Ft as smokeCapability, G as contactCapability, Gt as vibrationCapability, H as connectivityCapability, Ht as updateCapability, I as buildDeviceAdminUrl, J as deviceAdminLinkCapability, K as controlCapability, Kt as waterHeaterCapability, L as buttonCapability, Lt as switchCapability, M as boardKeySourceCapability, Mt as runningStateCapability, N as brightnessCapability, Nt as scriptRunnerCapability, O as automationControlCapability, P as brokerCapability, Q as eventEmitterCapability, Qt as baseUnitOf, R as calendarSourceCapability, Rt as tamperCapability, S as TargetSchema, Sn as EventCategory, St as presenceCapability, T as airQualitySensorCapability, Tt as publicEndpointReaderFrom, Ut as vacuumControlCapability, V as colorCapability, Vt as tryConvertUnit, Wt as valveCapability, Xt as RecordSecretUnavailableError, Y as deviceAdoptionCapability, Z as enumSensorCapability, _n as url, at as humiditySensorCapability, b as RUNNING_STATE_COLD, bn as DeviceType, bt as preconditionOf, cn as boolean, ct as integrationInstancesCapability, dn as number, dt as mediaPlayerCapability, en as defineAddonMigrations, et as flattenNestedRecords, fn as object, ft as motionCapability, gn as unknown, gt as numericSensorCapability, hn as union, ht as notifierCapability, it as humidifierCapability, j as binaryCapability, jt as runningFromVacuumState, k as batteryCapability, kt as runningFromLawnMower, ln as discriminatedUnion, lt as lawnMowerControlCapability, m as EnumSensorDateTimeFormatSchema, mn as string, mt as notificationOutputCapability, n as HA_BROKER_KIND, nn as defineRecordKinds, nt as floodCapability, o as BaseDevice, on as _enum, ot as imageCapability, pn as record, pt as normalizeUnit, q as coverCapability, qt as weatherCapability, rn as entryBody, rt as gasCapability, s as BaseDeviceProvider, sn as array, st as ingestReading, t as haInstanceSettingsPortsOver, tn as defineEntryKind, tt as flattenPortsOver, un as literal, ut as lockControlCapability, vn as DeviceFeature, vt as parseAdminBase, w as addonRoutesCapability, x as RecordIntegrationInstances, xn as errMsg, xt as prepareNotification, yn as DeviceRole, yt as powerMeterCapability, z as carbonMonoxideCapability, zt as temperatureSensorCapability } from "./legacy-integration-rows-Bhvthv-s.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
@@ -5773,7 +5773,9 @@ var HaBrokerEntrySchema = object({
5773
5773
  /** Optional FK to the integration record that spawned this broker. */
5774
5774
  integrationId: string().optional(),
5775
5775
  /** The instance's own switch (D996); absent means on. */
5776
- enabled: boolean().optional()
5776
+ enabled: boolean().optional(),
5777
+ /** The `calendar.*` entity ids this instance imports (planning#416); absent means the addon default. */
5778
+ calendarIds: array(string()).optional()
5777
5779
  });
5778
5780
  /**
5779
5781
  * Validates a `broker.add` `settings` payload for the HA kind. Accepts:
@@ -6229,6 +6231,27 @@ var haBrokerSettingsSchema = { sections: [{
6229
6231
  }
6230
6232
  ]
6231
6233
  }] };
6234
+ /**
6235
+ * The calendars one instance imports (planning#416): a field of the instance record, offered from
6236
+ * that broker's own `calendar.*` entities, so it sits in the instance form beside the connection.
6237
+ */
6238
+ function haCalendarsSection(options) {
6239
+ return {
6240
+ id: "ha-calendars-import",
6241
+ title: "Calendars to import",
6242
+ titleKey: "provider-homeassistant:globalSettings.s_ha-calendars-import.title",
6243
+ columns: 1,
6244
+ fields: [{
6245
+ type: "multiselect",
6246
+ key: "calendarIds",
6247
+ label: "Calendars",
6248
+ labelKey: "provider-homeassistant:globalSettings.s_ha-calendars-import.calendarIds.label",
6249
+ options: [...options],
6250
+ description: "Discovered from this Home Assistant instance. Select at least one to import; leave empty to import none.",
6251
+ descriptionKey: "provider-homeassistant:globalSettings.s_ha-calendars-import.calendarIds.description"
6252
+ }]
6253
+ };
6254
+ }
6232
6255
  //#endregion
6233
6256
  //#region src/ha-domain-mapping.ts
6234
6257
  function mapHaEntityToCamStack(input) {
@@ -7223,7 +7246,8 @@ var haBrokersEntryKind = defineEntryKind("brokers", {
7223
7246
  accessToken: HaBrokerEntrySchema.shape.accessToken,
7224
7247
  supervisorToken: HaBrokerEntrySchema.shape.supervisorToken,
7225
7248
  integrationId: HaBrokerEntrySchema.shape.integrationId,
7226
- enabled: HaBrokerEntrySchema.shape.enabled
7249
+ enabled: HaBrokerEntrySchema.shape.enabled,
7250
+ calendarIds: HaBrokerEntrySchema.shape.calendarIds
7227
7251
  }),
7228
7252
  writeTrigger: "an operator adds, edits or removes a Home Assistant broker connection",
7229
7253
  retiredSecretPaths: ["auth.accessToken", "auth.supervisorToken"]
@@ -7753,7 +7777,8 @@ function rowToEntry(id, data) {
7753
7777
  accessToken: data.accessToken,
7754
7778
  supervisorToken: data.supervisorToken,
7755
7779
  integrationId: data.integrationId,
7756
- enabled: data.enabled
7780
+ enabled: data.enabled,
7781
+ calendarIds: data.calendarIds
7757
7782
  });
7758
7783
  return parsed.success ? parsed.data : null;
7759
7784
  }
@@ -7857,7 +7882,10 @@ function buildHaInstances(records, deps) {
7857
7882
  }],
7858
7883
  allowRestoreId: true
7859
7884
  },
7860
- formSchema: () => haBrokerSettingsSchema,
7885
+ formSchema: (id) => {
7886
+ const options = id === null ? [] : deps.calendarOptions(id);
7887
+ return options.length === 0 ? haBrokerSettingsSchema : { sections: [...haBrokerSettingsSchema.sections, haCalendarsSection(options)] };
7888
+ },
7861
7889
  initialBody: (name) => ({
7862
7890
  name,
7863
7891
  authKind: "long-lived"
@@ -8080,6 +8108,28 @@ function createHaBoardKeyProvider(source) {
8080
8108
  };
8081
8109
  }
8082
8110
  //#endregion
8111
+ //#region src/ha-instance-settings.ts
8112
+ function valuesOf(body) {
8113
+ return {
8114
+ ...body.integrationId !== void 0 ? { integrationId: body.integrationId } : {},
8115
+ ...body.calendarIds !== void 0 ? { calendarIds: body.calendarIds } : {}
8116
+ };
8117
+ }
8118
+ function haInstanceRecordPortsOver(kind) {
8119
+ return {
8120
+ readInstance: async (brokerId) => {
8121
+ const row = await kind.get(brokerId);
8122
+ return row === null ? null : valuesOf(row.data);
8123
+ },
8124
+ patchInstance: async (brokerId, patch) => {
8125
+ const row = await kind.get(brokerId);
8126
+ if (row === null) return false;
8127
+ await kind.patch(brokerId, patch, { ifRev: row.rev });
8128
+ return true;
8129
+ }
8130
+ };
8131
+ }
8132
+ //#endregion
8083
8133
  //#region src/migrations/flatten-broker-records.ts
8084
8134
  /**
8085
8135
  * The Home Assistant broker records keep their connection flat (planning#408 P3): the nested
@@ -8112,6 +8162,98 @@ async function flattenBrokerRecords(ports) {
8112
8162
  });
8113
8163
  }
8114
8164
  //#endregion
8165
+ //#region src/migrations/instance-settings-to-record.ts
8166
+ var INSTANCE_SETTINGS_TO_RECORD_ID = "provider-homeassistant/2026-11-05-instance-settings-to-record";
8167
+ var CLEAR_INSTANCE_SETTINGS_ROWS_ID = "provider-homeassistant/2026-11-05-clear-instance-settings-rows";
8168
+ /** The legacy row key the clearing migration removes once the record carries it. */
8169
+ var MOVED_ROW_KEYS = ["calendarIds"];
8170
+ var asIds$1 = (value) => Array.isArray(value) && value.every((item) => typeof item === "string") ? value : null;
8171
+ var sameSet$1 = (a, b) => {
8172
+ const left = new Set(a);
8173
+ const right = new Set(b);
8174
+ return left.size === right.size && [...left].every((id) => right.has(id));
8175
+ };
8176
+ /** What the rows of one integration say about its record. */
8177
+ function wanted(row) {
8178
+ const calendarIds = asIds$1(row.settings["calendarIds"]);
8179
+ return {
8180
+ integrationId: row.integrationId,
8181
+ ...calendarIds !== null ? { calendarIds } : {}
8182
+ };
8183
+ }
8184
+ function assertNoAmbiguity(rows) {
8185
+ const seen = /* @__PURE__ */ new Map();
8186
+ for (const row of rows) {
8187
+ if (row.brokerId === null) continue;
8188
+ const other = seen.get(row.brokerId);
8189
+ if (other === void 0) {
8190
+ seen.set(row.brokerId, row);
8191
+ continue;
8192
+ }
8193
+ throw new Error(`provider-homeassistant: integrations ${other.integrationId} and ${row.integrationId} both link broker ${row.brokerId} — nothing moved`);
8194
+ }
8195
+ }
8196
+ async function moveInstanceSettingsToRecords(ports) {
8197
+ const rows = await ports.listInstances();
8198
+ assertNoAmbiguity(rows);
8199
+ let moved = 0;
8200
+ let kept = 0;
8201
+ let gone = 0;
8202
+ for (const row of rows) {
8203
+ if (row.brokerId === null) continue;
8204
+ const record = await ports.readInstance(row.brokerId);
8205
+ if (record === null) {
8206
+ gone += 1;
8207
+ continue;
8208
+ }
8209
+ const want = wanted(row);
8210
+ const patch = {
8211
+ ...record.integrationId === void 0 && want.integrationId !== void 0 ? { integrationId: want.integrationId } : {},
8212
+ ...record.calendarIds === void 0 && want.calendarIds !== void 0 ? { calendarIds: want.calendarIds } : {}
8213
+ };
8214
+ if (Object.keys(patch).length === 0) {
8215
+ kept += 1;
8216
+ continue;
8217
+ }
8218
+ if (!await ports.patchInstance(row.brokerId, patch)) {
8219
+ gone += 1;
8220
+ continue;
8221
+ }
8222
+ const back = await ports.readInstance(row.brokerId);
8223
+ if (back === null || patch.integrationId !== void 0 && back.integrationId !== patch.integrationId || patch.calendarIds !== void 0 && !(back.calendarIds !== void 0 && sameSet$1(back.calendarIds, patch.calendarIds))) throw new Error(`provider-homeassistant: record ${row.brokerId} does not show the values of integration ${row.integrationId} after the write — rows kept`);
8224
+ moved += 1;
8225
+ }
8226
+ return {
8227
+ outcome: moved === 0 ? "already-done" : "done",
8228
+ summary: {
8229
+ moved,
8230
+ kept,
8231
+ gone
8232
+ }
8233
+ };
8234
+ }
8235
+ async function clearInstanceSettingsRows(ports) {
8236
+ let cleared = 0;
8237
+ let parked = 0;
8238
+ for (const row of await ports.listInstances()) {
8239
+ if (!MOVED_ROW_KEYS.some((key) => key in row.settings)) continue;
8240
+ const own = asIds$1(row.settings["calendarIds"]);
8241
+ const onRecord = (row.brokerId === null ? null : await ports.readInstance(row.brokerId))?.calendarIds;
8242
+ if (own === null || onRecord === void 0 || !sameSet$1(own, onRecord)) {
8243
+ parked += 1;
8244
+ continue;
8245
+ }
8246
+ if (await ports.clearInstanceSettingsKeys(row.integrationId, MOVED_ROW_KEYS)) cleared += 1;
8247
+ }
8248
+ return {
8249
+ outcome: cleared === 0 ? "already-done" : "done",
8250
+ summary: {
8251
+ cleared,
8252
+ parked
8253
+ }
8254
+ };
8255
+ }
8256
+ //#endregion
8115
8257
  //#region src/migrations/calendar-ids-to-integration.ts
8116
8258
  /**
8117
8259
  * The HA calendars an instance imports are a fact of THAT instance (D985): each Home Assistant
@@ -8249,6 +8391,38 @@ var ADDON_MIGRATIONS = [
8249
8391
  fixtureMark: "a non-secret field stored beside the auth of a broker record"
8250
8392
  },
8251
8393
  procedure: flattenBrokerRecords
8394
+ },
8395
+ {
8396
+ meta: {
8397
+ id: INSTANCE_SETTINGS_TO_RECORD_ID,
8398
+ owner: "provider-homeassistant",
8399
+ level: "addon-state",
8400
+ seq: 4,
8401
+ dependsOn: ["provider-homeassistant/2026-11-03-drop-shared-calendar-ids", FLATTEN_BROKER_RECORDS_ID],
8402
+ store: "settings",
8403
+ scope: "cluster",
8404
+ onFailure: "block-owner",
8405
+ bodyKind: "procedure",
8406
+ description: "Merge the calendars and the integration link of every Home Assistant integration into the instance record its broker link names; a field the record holds wins; read back",
8407
+ fixtureMark: "a calendar id stored in the integration settings of an instance"
8408
+ },
8409
+ procedure: moveInstanceSettingsToRecords
8410
+ },
8411
+ {
8412
+ meta: {
8413
+ id: CLEAR_INSTANCE_SETTINGS_ROWS_ID,
8414
+ owner: "provider-homeassistant",
8415
+ level: "addon-state",
8416
+ seq: 5,
8417
+ dependsOn: [INSTANCE_SETTINGS_TO_RECORD_ID],
8418
+ store: "settings",
8419
+ scope: "cluster",
8420
+ onFailure: "block-owner",
8421
+ bodyKind: "procedure",
8422
+ description: "Clear the calendars from the integration settings of every Home Assistant instance whose record reads back the same set",
8423
+ fixtureMark: "a calendar set the instance record holds differently"
8424
+ },
8425
+ procedure: clearInstanceSettingsRows
8252
8426
  }
8253
8427
  ];
8254
8428
  //#endregion
@@ -8471,24 +8645,6 @@ async function reconcileBroker(brokerId, deps) {
8471
8645
  function computeBrokerCleanup(brokers, survivingIntegrationIds) {
8472
8646
  return brokers.filter((b) => b.integrationId !== void 0 && !survivingIntegrationIds.has(b.integrationId)).map((b) => b.id);
8473
8647
  }
8474
- /**
8475
- * Stamp the integrationId FK onto each broker that an integration references
8476
- * via its settings.brokerId, so cleanup-on-delete can later collect orphans.
8477
- * Pure: returns a NEW array; does not mutate. Only the entries that change are
8478
- * replaced (immutably) — unchanged entries keep their original object reference.
8479
- */
8480
- function linkBrokersToIntegrations(brokers, integrations) {
8481
- const brokerToIntegration = /* @__PURE__ */ new Map();
8482
- for (const integration of integrations) if (integration.brokerId !== void 0) brokerToIntegration.set(integration.brokerId, integration.id);
8483
- return brokers.map((b) => {
8484
- const integrationId = brokerToIntegration.get(b.id);
8485
- if (integrationId !== void 0 && b.integrationId !== integrationId) return {
8486
- ...b,
8487
- integrationId
8488
- };
8489
- return b;
8490
- });
8491
- }
8492
8648
  //#endregion
8493
8649
  //#region src/ha-standalone-entity.ts
8494
8650
  /**
@@ -8930,7 +9086,13 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
8930
9086
  if (this.ctx.secrets === void 0) throw new Error("provider-homeassistant: ctx.secrets is required");
8931
9087
  return {
8932
9088
  readStored: (key) => this.readStoredGlobalKey(key),
8933
- ...haInstanceSettingsPortsOver(this.ctx.api.integrations),
9089
+ ...haInstanceSettingsPortsOver({
9090
+ list: this.ctx.api.integrations.list,
9091
+ readLegacyIntegrationRows: this.ctx.api.migrations.readLegacyIntegrationRows,
9092
+ patchLegacyIntegrationRows: this.ctx.api.migrations.patchLegacyIntegrationRows,
9093
+ deleteLegacyIntegrationRowKeys: this.ctx.api.migrations.deleteLegacyIntegrationRowKeys
9094
+ }, this.ctx.secrets ?? null),
9095
+ ...haInstanceRecordPortsOver(records.kind(haBrokersEntryKind)),
8934
9096
  ...flattenPortsOver(records.kind(haBrokersEntryKind))
8935
9097
  };
8936
9098
  }
@@ -8942,6 +9104,7 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
8942
9104
  this.instances = buildHaInstances(records, {
8943
9105
  mintId: () => this.requireRegistry().allocateId(),
8944
9106
  infoOf: (id) => this.registry?.get(id) ?? null,
9107
+ calendarOptions: (id) => this.registry ? listHaCalendarCatalog(this.registry, id) : [],
8945
9108
  onChanged: (id) => this.syncBrokerRuntime(id),
8946
9109
  probe: (settings) => this.requireRegistry().testSettings(settings)
8947
9110
  });
@@ -9099,41 +9262,25 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
9099
9262
  * selection yet (the move has not run) uses the legacy shared set, so a boot mid-move never
9100
9263
  * changes what is imported.
9101
9264
  */
9102
- calendarIdsByBroker = /* @__PURE__ */ new Map();
9103
- noteInstanceCalendars(brokerId, raw) {
9104
- if (Array.isArray(raw) && raw.every((id) => typeof id === "string")) this.calendarIdsByBroker.set(brokerId, new Set(raw));
9105
- else this.calendarIdsByBroker.delete(brokerId);
9106
- }
9265
+ /** The calendars one instance imports: its record's set, else the addon default. */
9107
9266
  calendarIdsOf(brokerId) {
9108
- return this.calendarIdsByBroker.get(brokerId) ?? new Set(this.config.calendarIds ?? []);
9267
+ const own = this.activeBrokers.find((b) => b.id === brokerId)?.calendarIds;
9268
+ return new Set(own ?? this.config.calendarIds ?? []);
9109
9269
  }
9110
9270
  async reconcileIntegrationsToBrokers() {
9111
- const api = this.ctx.api;
9112
- if (!api.integrations?.list?.query || !api.integrations.getSettings?.query) return;
9271
+ const api = this.ctx.api.integrations;
9272
+ if (!api?.list?.query) return;
9113
9273
  try {
9114
- const haIntegrations = (await api.integrations.list.query()).filter((i) => i.addonId === this.ctx.id);
9274
+ const haIntegrations = (await api.list.query()).filter((i) => i.addonId === this.ctx.id);
9115
9275
  const survivingIntegrationIds = new Set(haIntegrations.map((i) => i.id));
9116
- const integrationsWithBrokerId = [];
9117
9276
  for (const integration of haIntegrations) {
9118
- const settings = await api.integrations.getSettings.query({ id: integration.id });
9119
- const brokerId = typeof settings["brokerId"] === "string" ? settings["brokerId"] : null;
9120
- if (!brokerId) continue;
9121
- this.noteInstanceCalendars(brokerId, settings["calendarIds"]);
9122
- if (!this.activeBrokers.find((b) => b.id === brokerId)) {
9123
- this.ctx.logger.warn("integration→broker: linked broker not found", { meta: {
9124
- integrationId: integration.id,
9125
- brokerId
9126
- } });
9277
+ const matching = this.activeBrokers.find((b) => b.integrationId === integration.id);
9278
+ if (!matching) {
9279
+ this.ctx.logger.warn("integration→broker: no instance record names this integration", { meta: { integrationId: integration.id } });
9127
9280
  continue;
9128
9281
  }
9129
- this.requireRegistry().linkIntegration(integration.id, brokerId);
9130
- integrationsWithBrokerId.push({
9131
- id: integration.id,
9132
- brokerId
9133
- });
9282
+ this.requireRegistry().linkIntegration(integration.id, matching.id);
9134
9283
  }
9135
- const linkedBrokers = linkBrokersToIntegrations(this.activeBrokers, integrationsWithBrokerId);
9136
- if (linkedBrokers.some((b, i) => b !== this.activeBrokers[i])) await this.persistBrokerEntries(linkedBrokers);
9137
9284
  const orphans = computeBrokerCleanup(this.activeBrokers, survivingIntegrationIds);
9138
9285
  this.ctx.logger.info("integration→broker reconcile", { meta: {
9139
9286
  brokerCount: this.activeBrokers.length,
@@ -9173,40 +9320,6 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
9173
9320
  }]
9174
9321
  }] });
9175
9322
  }
9176
- /**
9177
- * The calendars of ONE Home Assistant instance (D985): picked on its integration, offered from
9178
- * that broker's own `calendar.*` entities.
9179
- */
9180
- async integrationSettingsSchema(instance) {
9181
- if (instance.integrationId === null || !this.registry) return null;
9182
- let brokerId;
9183
- try {
9184
- brokerId = (await this.ctx.api.integrations.getSettings.query({ id: instance.integrationId }))["brokerId"];
9185
- } catch (err) {
9186
- this.ctx.logger.warn("HA integration form: instance lookup failed — broker form shown", { meta: {
9187
- integrationId: instance.integrationId,
9188
- error: errMsg(err)
9189
- } });
9190
- return null;
9191
- }
9192
- if (typeof brokerId !== "string") return null;
9193
- const options = listHaCalendarCatalog(this.registry, brokerId);
9194
- return this.schema({ sections: [{
9195
- id: "ha-calendars-import",
9196
- title: "Calendars to import",
9197
- titleKey: "provider-homeassistant:globalSettings.s_ha-calendars-import.title",
9198
- columns: 1,
9199
- fields: [{
9200
- type: "multiselect",
9201
- key: "calendarIds",
9202
- label: "Calendars",
9203
- labelKey: "provider-homeassistant:globalSettings.s_ha-calendars-import.calendarIds.label",
9204
- options,
9205
- description: "Discovered from this Home Assistant instance. Select at least one to import; leave empty to import none.",
9206
- descriptionKey: "provider-homeassistant:globalSettings.s_ha-calendars-import.calendarIds.description"
9207
- }]
9208
- }] });
9209
- }
9210
9323
  async onShutdown() {
9211
9324
  if (this.resyncTimer) {
9212
9325
  clearInterval(this.resyncTimer);