@camstack/addon-provider-bosch 0.1.35 → 0.1.36
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 +6 -0
- package/dist/{account-integration-offline-Bt3N9Zdk.mjs → account-integration-offline-9ooJuNrN.mjs} +1 -1
- package/dist/{account-integration-offline-De_H_EsP.js → account-integration-offline-Bnm17sAE.js} +2 -2
- package/dist/{dist-CyZFf49n.js → bosch-instances-BIvOtuzj.mjs} +33618 -31096
- package/dist/{dist-CkMPcvma.mjs → bosch-instances-CXmuRkef.js} +34363 -31255
- package/dist/home-connect/addon.js +348 -278
- package/dist/home-connect/addon.mjs +174 -104
- package/dist/homecom/addon.js +246 -117
- package/dist/homecom/addon.mjs +164 -35
- package/dist/shc/addon.js +216 -93
- package/dist/shc/addon.mjs +129 -6
- package/package.json +14 -2
package/dist/shc/addon.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $ as errMsg, A as switchCapability, F as defineAddonMigrations, G as number, H as array, I as defineCustomActions, J as string, K as object, L as defineEntryKind, P as customAction, Q as DeviceType, R as entryBody, S as heatingValveCapability, V as _enum, W as literal, _ as defaultIntegrationApiOver, a as BaseDevice, et as EventCategory, f as batteryCapability, h as connectionTestCapability, i as testBoschInstance, j as temperatureSensorCapability, l as RecordIntegrationInstances, m as climateControlCapability, n as boschRowsPorts, o as BaseDeviceProvider, r as keepBodyKeys, t as boschRowsMigration, v as deviceAdoptionCapability, w as integrationInstancesCapability } from "../bosch-instances-BIvOtuzj.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { request } from "node:https";
|
|
@@ -198,6 +198,109 @@ function buildConnectionFormSchema() {
|
|
|
198
198
|
}] };
|
|
199
199
|
}
|
|
200
200
|
//#endregion
|
|
201
|
+
//#region src/shc/shc-instances.ts
|
|
202
|
+
/**
|
|
203
|
+
* Bosch Smart Home Controller integrations as `integration-instances` (planning#416, D985,
|
|
204
|
+
* D1007): one `connections` record per controller under the `integrations` registry id. The body
|
|
205
|
+
* IS the connection (host, the client certificate and key and the optional token, all three in
|
|
206
|
+
* the keychain), so the form the instances page edits is the stored shape.
|
|
207
|
+
*/
|
|
208
|
+
var shcConnectionsEntryKind = defineEntryKind("connections", {
|
|
209
|
+
title: "Smart Home Controllers",
|
|
210
|
+
schema: entryBody({
|
|
211
|
+
host: string().optional(),
|
|
212
|
+
sslCertificate: string().optional().meta({ secret: true }),
|
|
213
|
+
sslKey: string().optional().meta({ secret: true }),
|
|
214
|
+
token: string().optional().meta({ secret: true })
|
|
215
|
+
}),
|
|
216
|
+
writeTrigger: "an operator pairs, edits or removes a Smart Home Controller"
|
|
217
|
+
});
|
|
218
|
+
/** Every kind this addon declares, keyed by its name. */
|
|
219
|
+
var shcRecordKinds = { connections: shcConnectionsEntryKind };
|
|
220
|
+
var LEGACY_KEYS = [
|
|
221
|
+
"host",
|
|
222
|
+
"sslCertificate",
|
|
223
|
+
"sslKey",
|
|
224
|
+
"token"
|
|
225
|
+
];
|
|
226
|
+
var SECRET_KEYS = [
|
|
227
|
+
"sslCertificate",
|
|
228
|
+
"sslKey",
|
|
229
|
+
"token"
|
|
230
|
+
];
|
|
231
|
+
function text(value) {
|
|
232
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
233
|
+
}
|
|
234
|
+
/** The record body of one controller, from its legacy rows (secrets resolved). */
|
|
235
|
+
function shcBodyFromRows(values, log, integration) {
|
|
236
|
+
const dropped = Object.keys(values).filter((key) => !LEGACY_KEYS.includes(key));
|
|
237
|
+
if (dropped.length > 0) log.warn(`integration '${integration.id}': legacy settings nothing reads any more are dropped: ${dropped.join(", ")}`);
|
|
238
|
+
const host = text(values["host"]);
|
|
239
|
+
const sslCertificate = text(values["sslCertificate"]);
|
|
240
|
+
const sslKey = text(values["sslKey"]);
|
|
241
|
+
const token = text(values["token"]);
|
|
242
|
+
return {
|
|
243
|
+
name: integration.name,
|
|
244
|
+
...host !== void 0 ? { host } : {},
|
|
245
|
+
...sslCertificate !== void 0 ? { sslCertificate } : {},
|
|
246
|
+
...sslKey !== void 0 ? { sslKey } : {},
|
|
247
|
+
...token !== void 0 ? { token } : {}
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
/** The whole `bosch-shc` catalogue (D987): offered to the engine at `onInitialize`. */
|
|
251
|
+
var SHC_MIGRATIONS = [boschRowsMigration({
|
|
252
|
+
addonId: "bosch-shc",
|
|
253
|
+
id: "bosch-shc/2026-11-05-integration-rows-to-record",
|
|
254
|
+
description: "Move every Smart Home Controller connection into a typed instance record keyed by its registry id, then clear the legacy integration settings rows and their keychain values",
|
|
255
|
+
fixtureMark: "a legacy setting key the migration does not know",
|
|
256
|
+
kind: shcConnectionsEntryKind,
|
|
257
|
+
bodyFrom: shcBodyFromRows
|
|
258
|
+
})];
|
|
259
|
+
function shcRowsPorts(deps) {
|
|
260
|
+
return boschRowsPorts({
|
|
261
|
+
...deps,
|
|
262
|
+
kind: shcConnectionsEntryKind
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* The live connection of one controller, read from its record. null while the connection is
|
|
267
|
+
* incomplete; a locked keychain throws so the caller keeps the client it has instead of
|
|
268
|
+
* reconfiguring it without its certificate (D49).
|
|
269
|
+
*/
|
|
270
|
+
async function shcConnectionOf(instances, id) {
|
|
271
|
+
const read = await instances.readResolved(id);
|
|
272
|
+
if (read === null) return null;
|
|
273
|
+
if (read.secrets === "unavailable") throw new Error("the keychain is locked, the saved controller credentials cannot be read");
|
|
274
|
+
return connectionFromSettings(read.body);
|
|
275
|
+
}
|
|
276
|
+
function buildShcInstances(records, deps) {
|
|
277
|
+
const handle = records.kind(shcConnectionsEntryKind);
|
|
278
|
+
const instances = new RecordIntegrationInstances(records, shcConnectionsEntryKind, {
|
|
279
|
+
description: {
|
|
280
|
+
role: "devices",
|
|
281
|
+
instanceMode: "multiple",
|
|
282
|
+
kind: "controller",
|
|
283
|
+
canTest: true
|
|
284
|
+
},
|
|
285
|
+
formSchema: () => buildConnectionFormSchema(),
|
|
286
|
+
initialBody: (name) => ({ name }),
|
|
287
|
+
configured: (body) => connectionFromSettings(body) !== null,
|
|
288
|
+
onChanged: async (_id, change) => {
|
|
289
|
+
if (change !== "deleted") await deps.onChanged();
|
|
290
|
+
},
|
|
291
|
+
test: (input) => testBoschInstance({
|
|
292
|
+
...input,
|
|
293
|
+
tester: deps.tester,
|
|
294
|
+
handle,
|
|
295
|
+
secretKeys: SECRET_KEYS
|
|
296
|
+
})
|
|
297
|
+
});
|
|
298
|
+
return {
|
|
299
|
+
instances,
|
|
300
|
+
provider: keepBodyKeys(instances.toProvider(), new Set(Object.keys(shcConnectionsEntryKind.schema.shape)))
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
//#endregion
|
|
201
304
|
//#region src/shc/shc-self-signed.ts
|
|
202
305
|
/**
|
|
203
306
|
* RSA-2048 self-signed certificate. The controller stores this certificate;
|
|
@@ -23732,11 +23835,25 @@ var BoschShcProviderAddon = class extends BaseDeviceProvider {
|
|
|
23732
23835
|
[DeviceType.Switch]: ShcSwitchDevice
|
|
23733
23836
|
};
|
|
23734
23837
|
clients = null;
|
|
23838
|
+
instances = null;
|
|
23735
23839
|
constructor() {
|
|
23736
23840
|
super({});
|
|
23737
23841
|
}
|
|
23738
23842
|
async onInitialize() {
|
|
23739
23843
|
const regs = this.providerRegistrationsFromSuper(await super.onInitialize());
|
|
23844
|
+
const records = this.ctx.records;
|
|
23845
|
+
if (records === void 0) throw new Error("bosch-shc: ctx.records is required (hub-only addon)");
|
|
23846
|
+
await records.declare(shcRecordKinds);
|
|
23847
|
+
await this.runMigrations(defineAddonMigrations(SHC_MIGRATIONS, shcRowsPorts({
|
|
23848
|
+
api: defaultIntegrationApiOver(this.ctx.api),
|
|
23849
|
+
records,
|
|
23850
|
+
warn: (message) => this.ctx.logger.warn(message)
|
|
23851
|
+
})));
|
|
23852
|
+
const built = buildShcInstances(records, {
|
|
23853
|
+
onChanged: () => this.reconcileIntegrations(),
|
|
23854
|
+
tester: this.buildConnectionTestProvider()
|
|
23855
|
+
});
|
|
23856
|
+
this.instances = built.instances;
|
|
23740
23857
|
this.clients = new ShcClientRegistry(this.ctx.logger);
|
|
23741
23858
|
this.clients.setOnConnected((integrationId) => {
|
|
23742
23859
|
this.setIntegrationDevicesOnline(integrationId, true);
|
|
@@ -23756,6 +23873,10 @@ var BoschShcProviderAddon = class extends BaseDeviceProvider {
|
|
|
23756
23873
|
{
|
|
23757
23874
|
capability: connectionTestCapability,
|
|
23758
23875
|
provider: this.buildConnectionTestProvider()
|
|
23876
|
+
},
|
|
23877
|
+
{
|
|
23878
|
+
capability: integrationInstancesCapability,
|
|
23879
|
+
provider: built.provider
|
|
23759
23880
|
}
|
|
23760
23881
|
],
|
|
23761
23882
|
customActions: boschShcActions,
|
|
@@ -23797,11 +23918,9 @@ var BoschShcProviderAddon = class extends BaseDeviceProvider {
|
|
|
23797
23918
|
this.ctx.logger.warn("Bosch SHC: shutdown error", { meta: { error: errMsg(err) } });
|
|
23798
23919
|
}
|
|
23799
23920
|
this.clients = null;
|
|
23921
|
+
this.instances = null;
|
|
23800
23922
|
await super.onShutdown();
|
|
23801
23923
|
}
|
|
23802
|
-
globalSettingsSchema() {
|
|
23803
|
-
return buildConnectionFormSchema();
|
|
23804
|
-
}
|
|
23805
23924
|
async supportsManualCreation() {
|
|
23806
23925
|
return false;
|
|
23807
23926
|
}
|
|
@@ -23844,7 +23963,7 @@ var BoschShcProviderAddon = class extends BaseDeviceProvider {
|
|
|
23844
23963
|
for (const integration of all) {
|
|
23845
23964
|
if (integration.addonId !== this.ctx.id) continue;
|
|
23846
23965
|
try {
|
|
23847
|
-
const connection =
|
|
23966
|
+
const connection = await shcConnectionOf(this.requireInstances(), integration.id);
|
|
23848
23967
|
if (connection) hosts.push(connection.host);
|
|
23849
23968
|
} catch (err) {
|
|
23850
23969
|
this.ctx.logger.warn("SHC discovery: settings read failed", { meta: {
|
|
@@ -23859,6 +23978,10 @@ var BoschShcProviderAddon = class extends BaseDeviceProvider {
|
|
|
23859
23978
|
return [];
|
|
23860
23979
|
}
|
|
23861
23980
|
}
|
|
23981
|
+
requireInstances() {
|
|
23982
|
+
if (!this.instances) throw new Error("Bosch SHC provider not initialised");
|
|
23983
|
+
return this.instances;
|
|
23984
|
+
}
|
|
23862
23985
|
requireClients() {
|
|
23863
23986
|
if (!this.clients) throw new Error("Bosch SHC provider not initialised");
|
|
23864
23987
|
return this.clients;
|
|
@@ -23869,7 +23992,7 @@ var BoschShcProviderAddon = class extends BaseDeviceProvider {
|
|
|
23869
23992
|
const mine = (await this.ctx.api.integrations.list.query()).filter((i) => i.addonId === this.ctx.id && i.enabled);
|
|
23870
23993
|
const surviving = /* @__PURE__ */ new Set();
|
|
23871
23994
|
for (const integration of mine) try {
|
|
23872
|
-
const connection =
|
|
23995
|
+
const connection = await shcConnectionOf(this.requireInstances(), integration.id);
|
|
23873
23996
|
if (!connection) continue;
|
|
23874
23997
|
await reg.upsert(integration.id, integration.name, connection);
|
|
23875
23998
|
surviving.add(integration.id);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-bosch",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"description": "Bosch smart-home device-provider addons for CamStack — SHC, Home Connect, and HomeCom cloud integrations (scaffold)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"addons": [
|
|
37
37
|
{
|
|
38
38
|
"id": "bosch-shc",
|
|
39
|
+
"integrationRole": "devices",
|
|
39
40
|
"category": "providers",
|
|
40
41
|
"name": "Bosch Smart Home",
|
|
41
42
|
"version": "0.1.0",
|
|
@@ -57,11 +58,15 @@
|
|
|
57
58
|
},
|
|
58
59
|
{
|
|
59
60
|
"name": "connection-test"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "integration-instances"
|
|
60
64
|
}
|
|
61
65
|
]
|
|
62
66
|
},
|
|
63
67
|
{
|
|
64
68
|
"id": "bosch-home-connect",
|
|
69
|
+
"integrationRole": "devices",
|
|
65
70
|
"category": "providers",
|
|
66
71
|
"name": "Bosch Home Connect",
|
|
67
72
|
"version": "0.1.0",
|
|
@@ -84,6 +89,9 @@
|
|
|
84
89
|
{
|
|
85
90
|
"name": "connection-test"
|
|
86
91
|
},
|
|
92
|
+
{
|
|
93
|
+
"name": "integration-instances"
|
|
94
|
+
},
|
|
87
95
|
{
|
|
88
96
|
"name": "dishwasher"
|
|
89
97
|
},
|
|
@@ -97,6 +105,7 @@
|
|
|
97
105
|
},
|
|
98
106
|
{
|
|
99
107
|
"id": "bosch-homecom",
|
|
108
|
+
"integrationRole": "devices",
|
|
100
109
|
"category": "providers",
|
|
101
110
|
"name": "Bosch HomeCom",
|
|
102
111
|
"version": "0.1.0",
|
|
@@ -119,6 +128,9 @@
|
|
|
119
128
|
{
|
|
120
129
|
"name": "connection-test"
|
|
121
130
|
},
|
|
131
|
+
{
|
|
132
|
+
"name": "integration-instances"
|
|
133
|
+
},
|
|
122
134
|
{
|
|
123
135
|
"name": "climate-control"
|
|
124
136
|
},
|
|
@@ -129,7 +141,7 @@
|
|
|
129
141
|
}
|
|
130
142
|
],
|
|
131
143
|
"requires": {
|
|
132
|
-
"server": ">=1.2.
|
|
144
|
+
"server": ">=1.2.765"
|
|
133
145
|
}
|
|
134
146
|
},
|
|
135
147
|
"files": [
|