@camstack/addon-provider-bosch 0.1.31 → 0.1.33
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 +13 -0
- package/dist/{account-integration-offline-Cfcp8s5x.mjs → account-integration-offline-Bpa-ZlLg.mjs} +2 -1
- package/dist/{account-integration-offline-IvvrXQDg.js → account-integration-offline-BueUSEv3.js} +2 -1
- package/dist/{dist-NdDwxHvT.js → dist-BHYWG3lC.js} +4465 -1721
- package/dist/{dist-DxO4cucS.mjs → dist-hH1ghdQ4.mjs} +4465 -1721
- package/dist/home-connect/addon.js +10 -10
- package/dist/home-connect/addon.mjs +10 -10
- package/dist/homecom/addon.js +2 -2
- package/dist/homecom/addon.mjs +2 -2
- package/dist/shc/addon.js +53 -246
- package/dist/shc/addon.mjs +53 -246
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_dist = require("../dist-
|
|
3
|
-
const require_account_integration_offline = require("../account-integration-offline-
|
|
2
|
+
const require_dist = require("../dist-BHYWG3lC.js");
|
|
3
|
+
const require_account_integration_offline = require("../account-integration-offline-BueUSEv3.js");
|
|
4
4
|
let node_crypto = require("node:crypto");
|
|
5
5
|
let node_tls = require("node:tls");
|
|
6
6
|
let node_zlib = require("node:zlib");
|
|
@@ -3900,9 +3900,9 @@ var COLD_DISHWASHER_STATUS = {
|
|
|
3900
3900
|
program: null,
|
|
3901
3901
|
selectedProgram: null,
|
|
3902
3902
|
availablePrograms: [],
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3903
|
+
remaining: null,
|
|
3904
|
+
delayedStart: null,
|
|
3905
|
+
progress: null,
|
|
3906
3906
|
doorOpen: null,
|
|
3907
3907
|
doorLocked: null,
|
|
3908
3908
|
remoteStartAllowed: null,
|
|
@@ -3957,9 +3957,9 @@ function dishwasherStatusFromFeatures(input) {
|
|
|
3957
3957
|
program: programKey(valueOf(input, activeEntity)),
|
|
3958
3958
|
selectedProgram: programKey(valueOf(input, selectedEntity)),
|
|
3959
3959
|
availablePrograms: [...availableProgramKeys(description)],
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3960
|
+
remaining: secondsFrom(remaining),
|
|
3961
|
+
delayedStart: secondsFrom(delayed),
|
|
3962
|
+
progress: progress !== null && progress >= 0 && progress <= 100 ? progress : null,
|
|
3963
3963
|
doorOpen: doorRaw === null ? null : doorRaw === "Open",
|
|
3964
3964
|
doorLocked: doorRaw === null ? null : doorRaw === "Locked",
|
|
3965
3965
|
remoteStartAllowed: boolOf(valueOf(input, findEntity(description, ["status"], ["RemoteControlStartAllowed"]))),
|
|
@@ -4315,7 +4315,7 @@ function childSliceFromValue(input) {
|
|
|
4315
4315
|
return kwh === null ? null : {
|
|
4316
4316
|
cap: "power-meter",
|
|
4317
4317
|
status: {
|
|
4318
|
-
|
|
4318
|
+
energy: kwh,
|
|
4319
4319
|
lastFetchedAt: nowMs
|
|
4320
4320
|
}
|
|
4321
4321
|
};
|
|
@@ -4877,7 +4877,7 @@ var HomeConnectDishwasherDevice = class extends require_dist.BaseDevice {
|
|
|
4877
4877
|
publishRunningSlice(slice) {
|
|
4878
4878
|
const fetchedAt = Date.now();
|
|
4879
4879
|
const previous = this.runtimeState.getCapState(RUNNING_CAP);
|
|
4880
|
-
const next = require_dist.runningFromDishwasherOperation(slice.operationState, slice.program, previous, fetchedAt, slice.
|
|
4880
|
+
const next = require_dist.runningFromDishwasherOperation(slice.operationState, slice.program, previous, fetchedAt, slice.remaining);
|
|
4881
4881
|
this.runtimeState.setCapState(RUNNING_CAP, next);
|
|
4882
4882
|
}
|
|
4883
4883
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as customAction, B as record, D as DeviceType, E as DeviceRole, F as array, H as union, I as boolean, L as literal, M as isSecretMarker, N as isSecretMarkerLike, O as errMsg, P as _enum, S as runningStateCapability, U as unknown, V as string, W as EventCategory, _ as ingestReading, b as quantityFromUnit, c as binaryCapability, d as consumablesCapability, f as deviceAdoptionCapability, h as eventEmitterCapability, i as RUNNING_STATE_COLD, j as defineCustomActions, k as createEvent, m as enumSensorCapability, n as BaseDeviceProvider, o as VendorLoginProxy, p as dishwasherCapability, r as DishwasherOperationStateSchema, t as BaseDevice, u as connectionTestCapability, v as numericSensorCapability, x as runningFromDishwasherOperation, y as powerMeterCapability, z as object } from "../dist-
|
|
2
|
-
import { a as createSignInAttemptStore, i as openSignInProxy, n as cascadeRemoveDevicesForIntegration, o as loginFailureForAttempt, r as createSignInClaims, s as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-
|
|
1
|
+
import { A as customAction, B as record, D as DeviceType, E as DeviceRole, F as array, H as union, I as boolean, L as literal, M as isSecretMarker, N as isSecretMarkerLike, O as errMsg, P as _enum, S as runningStateCapability, U as unknown, V as string, W as EventCategory, _ as ingestReading, b as quantityFromUnit, c as binaryCapability, d as consumablesCapability, f as deviceAdoptionCapability, h as eventEmitterCapability, i as RUNNING_STATE_COLD, j as defineCustomActions, k as createEvent, m as enumSensorCapability, n as BaseDeviceProvider, o as VendorLoginProxy, p as dishwasherCapability, r as DishwasherOperationStateSchema, t as BaseDevice, u as connectionTestCapability, v as numericSensorCapability, x as runningFromDishwasherOperation, y as powerMeterCapability, z as object } from "../dist-hH1ghdQ4.mjs";
|
|
2
|
+
import { a as createSignInAttemptStore, i as openSignInProxy, n as cascadeRemoveDevicesForIntegration, o as loginFailureForAttempt, r as createSignInClaims, s as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-Bpa-ZlLg.mjs";
|
|
3
3
|
import { createHash, randomBytes } from "node:crypto";
|
|
4
4
|
import { connect } from "node:tls";
|
|
5
5
|
import { inflateRawSync } from "node:zlib";
|
|
@@ -3899,9 +3899,9 @@ var COLD_DISHWASHER_STATUS = {
|
|
|
3899
3899
|
program: null,
|
|
3900
3900
|
selectedProgram: null,
|
|
3901
3901
|
availablePrograms: [],
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3902
|
+
remaining: null,
|
|
3903
|
+
delayedStart: null,
|
|
3904
|
+
progress: null,
|
|
3905
3905
|
doorOpen: null,
|
|
3906
3906
|
doorLocked: null,
|
|
3907
3907
|
remoteStartAllowed: null,
|
|
@@ -3956,9 +3956,9 @@ function dishwasherStatusFromFeatures(input) {
|
|
|
3956
3956
|
program: programKey(valueOf(input, activeEntity)),
|
|
3957
3957
|
selectedProgram: programKey(valueOf(input, selectedEntity)),
|
|
3958
3958
|
availablePrograms: [...availableProgramKeys(description)],
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3959
|
+
remaining: secondsFrom(remaining),
|
|
3960
|
+
delayedStart: secondsFrom(delayed),
|
|
3961
|
+
progress: progress !== null && progress >= 0 && progress <= 100 ? progress : null,
|
|
3962
3962
|
doorOpen: doorRaw === null ? null : doorRaw === "Open",
|
|
3963
3963
|
doorLocked: doorRaw === null ? null : doorRaw === "Locked",
|
|
3964
3964
|
remoteStartAllowed: boolOf(valueOf(input, findEntity(description, ["status"], ["RemoteControlStartAllowed"]))),
|
|
@@ -4314,7 +4314,7 @@ function childSliceFromValue(input) {
|
|
|
4314
4314
|
return kwh === null ? null : {
|
|
4315
4315
|
cap: "power-meter",
|
|
4316
4316
|
status: {
|
|
4317
|
-
|
|
4317
|
+
energy: kwh,
|
|
4318
4318
|
lastFetchedAt: nowMs
|
|
4319
4319
|
}
|
|
4320
4320
|
};
|
|
@@ -4876,7 +4876,7 @@ var HomeConnectDishwasherDevice = class extends BaseDevice {
|
|
|
4876
4876
|
publishRunningSlice(slice) {
|
|
4877
4877
|
const fetchedAt = Date.now();
|
|
4878
4878
|
const previous = this.runtimeState.getCapState(RUNNING_CAP);
|
|
4879
|
-
const next = runningFromDishwasherOperation(slice.operationState, slice.program, previous, fetchedAt, slice.
|
|
4879
|
+
const next = runningFromDishwasherOperation(slice.operationState, slice.program, previous, fetchedAt, slice.remaining);
|
|
4880
4880
|
this.runtimeState.setCapState(RUNNING_CAP, next);
|
|
4881
4881
|
}
|
|
4882
4882
|
};
|
package/dist/homecom/addon.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_dist = require("../dist-
|
|
3
|
-
const require_account_integration_offline = require("../account-integration-offline-
|
|
2
|
+
const require_dist = require("../dist-BHYWG3lC.js");
|
|
3
|
+
const require_account_integration_offline = require("../account-integration-offline-BueUSEv3.js");
|
|
4
4
|
let node_crypto = require("node:crypto");
|
|
5
5
|
//#region src/homecom/config.ts
|
|
6
6
|
var HOMECOM_BRANDS = ["bosch", "buderus"];
|
package/dist/homecom/addon.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as customAction, D as DeviceType, F as array, I as boolean, L as literal, M as isSecretMarker, N as isSecretMarkerLike, O as errMsg, P as _enum, R as number, T as waterHeaterCapability, V as string, W as EventCategory, f as deviceAdoptionCapability, j as defineCustomActions, l as climateControlCapability, n as BaseDeviceProvider, o as VendorLoginProxy, t as BaseDevice, u as connectionTestCapability, z as object } from "../dist-
|
|
2
|
-
import { a as createSignInAttemptStore, i as openSignInProxy, n as cascadeRemoveDevicesForIntegration, o as loginFailureForAttempt, r as createSignInClaims, s as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-
|
|
1
|
+
import { A as customAction, D as DeviceType, F as array, I as boolean, L as literal, M as isSecretMarker, N as isSecretMarkerLike, O as errMsg, P as _enum, R as number, T as waterHeaterCapability, V as string, W as EventCategory, f as deviceAdoptionCapability, j as defineCustomActions, l as climateControlCapability, n as BaseDeviceProvider, o as VendorLoginProxy, t as BaseDevice, u as connectionTestCapability, z as object } from "../dist-hH1ghdQ4.mjs";
|
|
2
|
+
import { a as createSignInAttemptStore, i as openSignInProxy, n as cascadeRemoveDevicesForIntegration, o as loginFailureForAttempt, r as createSignInClaims, s as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-Bpa-ZlLg.mjs";
|
|
3
3
|
import { createHash, randomBytes } from "node:crypto";
|
|
4
4
|
//#region src/homecom/config.ts
|
|
5
5
|
var HOMECOM_BRANDS = ["bosch", "buderus"];
|
package/dist/shc/addon.js
CHANGED
|
@@ -2,14 +2,13 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
//#region \0rolldown/runtime.js
|
|
3
3
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
4
4
|
//#endregion
|
|
5
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_dist = require("../dist-BHYWG3lC.js");
|
|
6
6
|
let node_crypto = require("node:crypto");
|
|
7
7
|
let node_https = require("node:https");
|
|
8
8
|
let node_child_process = require("node:child_process");
|
|
9
9
|
let node_fs = require("node:fs");
|
|
10
10
|
let node_os = require("node:os");
|
|
11
11
|
let node_path = require("node:path");
|
|
12
|
-
let node_dgram = require("node:dgram");
|
|
13
12
|
let node_net = require("node:net");
|
|
14
13
|
//#region src/shc/custom-actions.ts
|
|
15
14
|
var boschShcActions = require_dist.defineCustomActions({
|
|
@@ -332,78 +331,18 @@ async function registerShcClient(deps) {
|
|
|
332
331
|
}
|
|
333
332
|
//#endregion
|
|
334
333
|
//#region src/shc/shc-controller-discovery.ts
|
|
335
|
-
/**
|
|
336
|
-
var
|
|
337
|
-
/** Top bit of the question class: ask for a unicast reply (RFC 6762). */
|
|
338
|
-
var MDNS_QU_CLASS = 32769;
|
|
339
|
-
var SHC_MDNS_SERVICE = "_http._tcp.local";
|
|
334
|
+
/** The controller announces itself as an `_http._tcp` service named `Bosch SHC`. */
|
|
335
|
+
var SHC_MDNS_SERVICE = "_http._tcp";
|
|
340
336
|
var SHC_CONTROLLER_NAME_PREFIX = "Bosch SHC";
|
|
341
|
-
|
|
342
|
-
var
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
337
|
+
/** How the scan engine finds a controller: one mDNS browse, filtered on the instance name. */
|
|
338
|
+
var SHC_DISCOVERY_MODES = [{
|
|
339
|
+
kind: "mdns",
|
|
340
|
+
serviceType: SHC_MDNS_SERVICE,
|
|
341
|
+
instancePattern: `^${SHC_CONTROLLER_NAME_PREFIX}`
|
|
342
|
+
}];
|
|
347
343
|
function isShcControllerName(name) {
|
|
348
344
|
return (name.split("._")[0] ?? name).toLowerCase().startsWith(SHC_CONTROLLER_NAME_PREFIX.toLowerCase());
|
|
349
345
|
}
|
|
350
|
-
function readName(buf, start) {
|
|
351
|
-
const labels = [];
|
|
352
|
-
let pos = start;
|
|
353
|
-
let end = start;
|
|
354
|
-
let jumped = false;
|
|
355
|
-
for (let hops = 0; hops < 16; hops++) {
|
|
356
|
-
if (pos < 0 || pos >= buf.length) return null;
|
|
357
|
-
const len = buf[pos] ?? 0;
|
|
358
|
-
if (len === 0) {
|
|
359
|
-
if (!jumped) end = pos + 1;
|
|
360
|
-
return {
|
|
361
|
-
name: labels.join("."),
|
|
362
|
-
end
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
if ((len & 192) === 192) {
|
|
366
|
-
if (pos + 1 >= buf.length) return null;
|
|
367
|
-
if (!jumped) end = pos + 2;
|
|
368
|
-
jumped = true;
|
|
369
|
-
pos = (len & 63) << 8 | (buf[pos + 1] ?? 0);
|
|
370
|
-
continue;
|
|
371
|
-
}
|
|
372
|
-
if ((len & 192) !== 0 || pos + 1 + len > buf.length) return null;
|
|
373
|
-
labels.push(buf.subarray(pos + 1, pos + 1 + len).toString("utf8"));
|
|
374
|
-
pos += 1 + len;
|
|
375
|
-
if (!jumped) end = pos;
|
|
376
|
-
}
|
|
377
|
-
return null;
|
|
378
|
-
}
|
|
379
|
-
function readRecords(buf, offset, count) {
|
|
380
|
-
const records = [];
|
|
381
|
-
let pos = offset;
|
|
382
|
-
for (let i = 0; i < count; i++) {
|
|
383
|
-
const name = readName(buf, pos);
|
|
384
|
-
if (name === null || name.end + 10 > buf.length) return null;
|
|
385
|
-
const type = buf.readUInt16BE(name.end);
|
|
386
|
-
const dataLength = buf.readUInt16BE(name.end + 8);
|
|
387
|
-
const dataOffset = name.end + 10;
|
|
388
|
-
if (dataOffset + dataLength > buf.length) return null;
|
|
389
|
-
records.push({
|
|
390
|
-
name: name.name,
|
|
391
|
-
type,
|
|
392
|
-
message: buf,
|
|
393
|
-
dataOffset,
|
|
394
|
-
dataLength
|
|
395
|
-
});
|
|
396
|
-
pos = dataOffset + dataLength;
|
|
397
|
-
}
|
|
398
|
-
return {
|
|
399
|
-
records,
|
|
400
|
-
next: pos
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
function ipv4(buf, offset, length) {
|
|
404
|
-
if (length !== 4 || offset + 4 > buf.length) return null;
|
|
405
|
-
return `${buf[offset] ?? 0}.${buf[offset + 1] ?? 0}.${buf[offset + 2] ?? 0}.${buf[offset + 3] ?? 0}`;
|
|
406
|
-
}
|
|
407
346
|
/** Identity used to recognise a controller already stored on an integration. */
|
|
408
347
|
function shcControllerId(input) {
|
|
409
348
|
const service = input.serviceHost?.trim().toLowerCase() ?? "";
|
|
@@ -412,40 +351,24 @@ function shcControllerId(input) {
|
|
|
412
351
|
if (serial.length > 0) return serial;
|
|
413
352
|
return input.host;
|
|
414
353
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
const srv = /* @__PURE__ */ new Map();
|
|
418
|
-
const addresses = /* @__PURE__ */ new Map();
|
|
419
|
-
for (const rec of records) {
|
|
420
|
-
const key = rec.name.toLowerCase();
|
|
421
|
-
if (rec.type === PTR) {
|
|
422
|
-
const target = readName(rec.message, rec.dataOffset);
|
|
423
|
-
if (target !== null && isShcControllerName(target.name)) instances.push(target.name);
|
|
424
|
-
} else if (rec.type === SRV && rec.dataLength >= 6) {
|
|
425
|
-
const target = readName(rec.message, rec.dataOffset + 6);
|
|
426
|
-
if (target !== null) srv.set(key, target.name);
|
|
427
|
-
} else if (rec.type === A) {
|
|
428
|
-
const ip = ipv4(rec.message, rec.dataOffset, rec.dataLength);
|
|
429
|
-
if (ip !== null) addresses.set(key, ip);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
354
|
+
/** Controllers among the engine's mDNS hits (a `Bosch SHC…` instance), one per host. */
|
|
355
|
+
function shcHostsFromHits(hits) {
|
|
432
356
|
const out = [];
|
|
433
357
|
const seen = /* @__PURE__ */ new Set();
|
|
434
|
-
for (const
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
if (host ===
|
|
438
|
-
seen.add(host);
|
|
439
|
-
const
|
|
440
|
-
const id = shcControllerId({
|
|
441
|
-
name: label,
|
|
442
|
-
host,
|
|
443
|
-
...viaSrv !== void 0 ? { serviceHost: viaSrv } : {}
|
|
444
|
-
});
|
|
358
|
+
for (const hit of hits) {
|
|
359
|
+
const mdns = hit.mdns;
|
|
360
|
+
if (mdns === void 0 || !isShcControllerName(mdns.instance)) continue;
|
|
361
|
+
if (hit.host.length === 0 || seen.has(hit.host)) continue;
|
|
362
|
+
seen.add(hit.host);
|
|
363
|
+
const name = mdns.instance.split("._")[0] ?? mdns.instance;
|
|
445
364
|
out.push({
|
|
446
|
-
host,
|
|
447
|
-
name
|
|
448
|
-
id
|
|
365
|
+
host: hit.host,
|
|
366
|
+
name,
|
|
367
|
+
id: shcControllerId({
|
|
368
|
+
name,
|
|
369
|
+
host: hit.host,
|
|
370
|
+
serviceHost: mdns.host
|
|
371
|
+
})
|
|
449
372
|
});
|
|
450
373
|
}
|
|
451
374
|
return out;
|
|
@@ -465,11 +388,10 @@ function proposeShcControllers(found, existingHosts) {
|
|
|
465
388
|
function shcDiscoveryCandidates(proposals) {
|
|
466
389
|
return proposals.map((found) => ({
|
|
467
390
|
stableId: `bosch-shc:${found.id}`,
|
|
391
|
+
type: require_dist.DeviceType.Hub,
|
|
468
392
|
suggestedName: found.name,
|
|
469
|
-
prefilledConfig: {
|
|
470
|
-
|
|
471
|
-
[SHC_SETUP_INTEGRATION_KEY]: true
|
|
472
|
-
}
|
|
393
|
+
prefilledConfig: { host: found.host },
|
|
394
|
+
setupIntegration: true
|
|
473
395
|
}));
|
|
474
396
|
}
|
|
475
397
|
function shcDiscoverySummary(foundCount, proposedCount) {
|
|
@@ -477,101 +399,6 @@ function shcDiscoverySummary(foundCount, proposedCount) {
|
|
|
477
399
|
if (proposedCount === 0) return "No controller found on the network.";
|
|
478
400
|
return `Found ${proposedCount} ${proposedCount === 1 ? "controller" : "controllers"}.`;
|
|
479
401
|
}
|
|
480
|
-
/** Hosts advertised as a Bosch Smart Home Controller on one mDNS message. */
|
|
481
|
-
function shcHostsFromDnsMessage(buf) {
|
|
482
|
-
if (buf.length < 12) return [];
|
|
483
|
-
const questions = buf.readUInt16BE(4);
|
|
484
|
-
const answers = buf.readUInt16BE(6);
|
|
485
|
-
const authorities = buf.readUInt16BE(8);
|
|
486
|
-
const extra = buf.readUInt16BE(10);
|
|
487
|
-
let pos = 12;
|
|
488
|
-
for (let i = 0; i < questions; i++) {
|
|
489
|
-
const name = readName(buf, pos);
|
|
490
|
-
if (name === null) return [];
|
|
491
|
-
pos = name.end + 4;
|
|
492
|
-
if (pos > buf.length) return [];
|
|
493
|
-
}
|
|
494
|
-
const answerRecords = readRecords(buf, pos, answers);
|
|
495
|
-
if (answerRecords === null) return [];
|
|
496
|
-
const authorityRecords = readRecords(buf, answerRecords.next, authorities);
|
|
497
|
-
if (authorityRecords === null) return [];
|
|
498
|
-
const extraRecords = readRecords(buf, authorityRecords.next, extra);
|
|
499
|
-
if (extraRecords === null) return [];
|
|
500
|
-
return hostsFromRecords([
|
|
501
|
-
...answerRecords.records,
|
|
502
|
-
...authorityRecords.records,
|
|
503
|
-
...extraRecords.records
|
|
504
|
-
]);
|
|
505
|
-
}
|
|
506
|
-
function mdnsPtrQuery(service) {
|
|
507
|
-
const encoded = service.split(".").filter((part) => part.length > 0).map((label) => Buffer.concat([Buffer.from([label.length]), Buffer.from(label)]));
|
|
508
|
-
const header = Buffer.alloc(12);
|
|
509
|
-
header.writeUInt16BE(1, 4);
|
|
510
|
-
const tail = Buffer.alloc(4);
|
|
511
|
-
tail.writeUInt16BE(PTR, 0);
|
|
512
|
-
tail.writeUInt16BE(MDNS_QU_CLASS, 2);
|
|
513
|
-
return Buffer.concat([
|
|
514
|
-
header,
|
|
515
|
-
...encoded,
|
|
516
|
-
Buffer.from([0]),
|
|
517
|
-
tail
|
|
518
|
-
]);
|
|
519
|
-
}
|
|
520
|
-
function closeQuietly(socket) {
|
|
521
|
-
try {
|
|
522
|
-
socket.close();
|
|
523
|
-
} catch {}
|
|
524
|
-
}
|
|
525
|
-
function exchangeMdns(query, timeoutMs) {
|
|
526
|
-
return new Promise((resolve) => {
|
|
527
|
-
let socket;
|
|
528
|
-
try {
|
|
529
|
-
socket = (0, node_dgram.createSocket)({
|
|
530
|
-
type: "udp4",
|
|
531
|
-
reuseAddr: true
|
|
532
|
-
});
|
|
533
|
-
} catch {
|
|
534
|
-
resolve([]);
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
const packets = [];
|
|
538
|
-
let settled = false;
|
|
539
|
-
const finish = () => {
|
|
540
|
-
if (settled) return;
|
|
541
|
-
settled = true;
|
|
542
|
-
closeQuietly(socket);
|
|
543
|
-
resolve(packets);
|
|
544
|
-
};
|
|
545
|
-
socket.on("error", () => finish());
|
|
546
|
-
socket.on("message", (msg) => {
|
|
547
|
-
packets.push(Buffer.from(msg));
|
|
548
|
-
});
|
|
549
|
-
socket.bind(0, () => {
|
|
550
|
-
try {
|
|
551
|
-
socket.send(query, MDNS_PORT, MDNS_ADDRESS);
|
|
552
|
-
} catch {
|
|
553
|
-
finish();
|
|
554
|
-
}
|
|
555
|
-
});
|
|
556
|
-
setTimeout(finish, timeoutMs);
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
async function browseShcControllers(exchange = exchangeMdns) {
|
|
560
|
-
let packets;
|
|
561
|
-
try {
|
|
562
|
-
packets = await exchange(mdnsPtrQuery(SHC_MDNS_SERVICE), SHC_DISCOVERY_TIMEOUT_MS);
|
|
563
|
-
} catch {
|
|
564
|
-
return [];
|
|
565
|
-
}
|
|
566
|
-
const hosts = [];
|
|
567
|
-
const seen = /* @__PURE__ */ new Set();
|
|
568
|
-
for (const packet of packets) for (const found of shcHostsFromDnsMessage(packet)) {
|
|
569
|
-
if (seen.has(found.host)) continue;
|
|
570
|
-
seen.add(found.host);
|
|
571
|
-
hosts.push(found);
|
|
572
|
-
}
|
|
573
|
-
return hosts;
|
|
574
|
-
}
|
|
575
402
|
/** Manual host wins. Otherwise the address discovery filled in. */
|
|
576
403
|
function resolveShcPairingHost(input) {
|
|
577
404
|
const manual = input.hostManual?.trim() ?? "";
|
|
@@ -1096,11 +923,11 @@ var TEMP_CAP = "temperature-sensor";
|
|
|
1096
923
|
var BATTERY_CAP = "battery";
|
|
1097
924
|
var VALVE_CAP = "heating-valve";
|
|
1098
925
|
var TEMP_COLD = {
|
|
1099
|
-
|
|
926
|
+
temperature: 0,
|
|
1100
927
|
lastFetchedAt: 0
|
|
1101
928
|
};
|
|
1102
929
|
var BATTERY_COLD = {
|
|
1103
|
-
|
|
930
|
+
level: null,
|
|
1104
931
|
charging: "unknown",
|
|
1105
932
|
sleeping: false,
|
|
1106
933
|
lastUpdated: 0
|
|
@@ -1137,12 +964,12 @@ var ShcTrvDevice = class extends ShcBaseDevice {
|
|
|
1137
964
|
if (typeof temperature === "number" && Number.isFinite(temperature)) {
|
|
1138
965
|
const prev = this.runtimeState.getCapState(TEMP_CAP);
|
|
1139
966
|
this.runtimeState.setCapState(TEMP_CAP, {
|
|
1140
|
-
|
|
967
|
+
temperature,
|
|
1141
968
|
lastFetchedAt: now
|
|
1142
969
|
});
|
|
1143
|
-
if (prev !== void 0 && prev.
|
|
970
|
+
if (prev !== void 0 && prev.temperature !== temperature && prev.lastFetchedAt !== 0) this.deviceLog("info", "SHC temperature updated from controller", {
|
|
1144
971
|
celsius: temperature,
|
|
1145
|
-
previous: prev.
|
|
972
|
+
previous: prev.temperature
|
|
1146
973
|
});
|
|
1147
974
|
}
|
|
1148
975
|
} catch {}
|
|
@@ -1162,7 +989,7 @@ var ShcTrvDevice = class extends ShcBaseDevice {
|
|
|
1162
989
|
try {
|
|
1163
990
|
const batt = await client.getServiceState(this.shcDeviceId, "BatteryLevel");
|
|
1164
991
|
this.runtimeState.setCapState(BATTERY_CAP, {
|
|
1165
|
-
|
|
992
|
+
level: batt.batteryLevel ?? null,
|
|
1166
993
|
charging: "unknown",
|
|
1167
994
|
sleeping: false,
|
|
1168
995
|
lastUpdated: now
|
|
@@ -23864,14 +23691,15 @@ var BoschShcProviderAddon = class extends require_dist.BaseDeviceProvider {
|
|
|
23864
23691
|
customActions: boschShcActions,
|
|
23865
23692
|
actionHandlers: {
|
|
23866
23693
|
discoverController: async () => {
|
|
23867
|
-
const {
|
|
23694
|
+
const { candidates } = await this.ctx.api.deviceManager.discoverProvider.mutate({ addonId: this.ctx.id });
|
|
23695
|
+
const hosts = candidates.map((candidate) => ({
|
|
23696
|
+
host: String(candidate.prefilledConfig["host"] ?? ""),
|
|
23697
|
+
name: candidate.suggestedName,
|
|
23698
|
+
id: candidate.stableId.replace(/^bosch-shc:/, "")
|
|
23699
|
+
}));
|
|
23868
23700
|
return {
|
|
23869
|
-
hosts
|
|
23870
|
-
|
|
23871
|
-
name: found.name,
|
|
23872
|
-
id: found.id
|
|
23873
|
-
})),
|
|
23874
|
-
summary
|
|
23701
|
+
hosts,
|
|
23702
|
+
summary: shcDiscoverySummary(hosts.length, hosts.length)
|
|
23875
23703
|
};
|
|
23876
23704
|
},
|
|
23877
23705
|
registerClient: async (input) => {
|
|
@@ -23907,24 +23735,21 @@ var BoschShcProviderAddon = class extends require_dist.BaseDeviceProvider {
|
|
|
23907
23735
|
async supportsManualCreation() {
|
|
23908
23736
|
return false;
|
|
23909
23737
|
}
|
|
23910
|
-
/**
|
|
23911
|
-
* LAN mDNS probe. This addon is hub-only, so the socket is the hub's.
|
|
23912
|
-
* The operator's hub is on br0 (its own LAN address), the same path the
|
|
23913
|
-
* hub already uses to announce itself — multicast UDP 5353 reaches the
|
|
23914
|
-
* LAN. The probe asks for a unicast reply and does not bind 5353, which
|
|
23915
|
-
* the hub's announcer holds. Agents do not run this addon.
|
|
23916
|
-
*/
|
|
23738
|
+
/** A controller is found by the scan engine's mDNS browse; this addon only classifies the hits. */
|
|
23917
23739
|
async supportsDiscovery() {
|
|
23918
23740
|
return true;
|
|
23919
23741
|
}
|
|
23920
|
-
async
|
|
23921
|
-
|
|
23922
|
-
|
|
23923
|
-
|
|
23924
|
-
|
|
23925
|
-
|
|
23926
|
-
|
|
23927
|
-
|
|
23742
|
+
async getDiscoveryModes() {
|
|
23743
|
+
return SHC_DISCOVERY_MODES;
|
|
23744
|
+
}
|
|
23745
|
+
async classifyDiscoveryHits(input) {
|
|
23746
|
+
const found = shcHostsFromHits(input.hits);
|
|
23747
|
+
const proposals = proposeShcControllers(found, await this.knownControllerHosts());
|
|
23748
|
+
if (found.length > proposals.length) this.ctx.logger.info("SHC discovery skipped controllers already added", { meta: {
|
|
23749
|
+
found: found.length,
|
|
23750
|
+
proposed: proposals.length
|
|
23751
|
+
} });
|
|
23752
|
+
return shcDiscoveryCandidates(proposals);
|
|
23928
23753
|
}
|
|
23929
23754
|
async adoptDiscoveredDevice(_input) {
|
|
23930
23755
|
throw new Error("Bosch SHC controllers are paired from the integration form");
|
|
@@ -23942,24 +23767,6 @@ var BoschShcProviderAddon = class extends require_dist.BaseDeviceProvider {
|
|
|
23942
23767
|
if (typeof shcDeviceId !== "string" || shcDeviceId.length === 0) throw new Error("bosch-shc generateStableId: shcDeviceId required");
|
|
23943
23768
|
return `bosch-shc:${integrationId}:${shcDeviceId}`;
|
|
23944
23769
|
}
|
|
23945
|
-
async discoverShcControllers() {
|
|
23946
|
-
let found = [];
|
|
23947
|
-
try {
|
|
23948
|
-
found = await browseShcControllers();
|
|
23949
|
-
} catch (err) {
|
|
23950
|
-
this.ctx.logger.warn("SHC controller discovery failed", { meta: { error: require_dist.errMsg(err) } });
|
|
23951
|
-
}
|
|
23952
|
-
const known = await this.knownControllerHosts();
|
|
23953
|
-
const proposals = proposeShcControllers(found, known);
|
|
23954
|
-
if (found.length > proposals.length) this.ctx.logger.info("SHC discovery skipped controllers already added", { meta: {
|
|
23955
|
-
found: found.length,
|
|
23956
|
-
proposed: proposals.length
|
|
23957
|
-
} });
|
|
23958
|
-
return {
|
|
23959
|
-
proposals,
|
|
23960
|
-
summary: shcDiscoverySummary(found.length, proposals.length)
|
|
23961
|
-
};
|
|
23962
|
-
}
|
|
23963
23770
|
async knownControllerHosts() {
|
|
23964
23771
|
try {
|
|
23965
23772
|
const all = await this.ctx.api.integrations.list.query();
|