@riddix/hamh 2.0.34 → 2.0.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/README.md +30 -12
- package/dist/backend/cli.js +1664 -806
- package/dist/backend/cli.js.map +4 -4
- package/dist/frontend/assets/index-Ch5MWPnH.js +499 -0
- package/dist/frontend/index.html +1 -1
- package/package.json +4 -4
- package/dist/frontend/assets/index-ranhrLWH.js +0 -499
package/dist/backend/cli.js
CHANGED
|
@@ -1743,8 +1743,8 @@ var init_Cancelable = __esm({
|
|
|
1743
1743
|
};
|
|
1744
1744
|
return result;
|
|
1745
1745
|
}
|
|
1746
|
-
static set logger(
|
|
1747
|
-
this.#logger =
|
|
1746
|
+
static set logger(logger204) {
|
|
1747
|
+
this.#logger = logger204;
|
|
1748
1748
|
}
|
|
1749
1749
|
static get logger() {
|
|
1750
1750
|
return this.#logger;
|
|
@@ -3422,13 +3422,13 @@ var init_Logger = __esm({
|
|
|
3422
3422
|
*
|
|
3423
3423
|
* @deprecated use {@link destinations}
|
|
3424
3424
|
*/
|
|
3425
|
-
static addLogger(identifier,
|
|
3425
|
+
static addLogger(identifier, logger204, options) {
|
|
3426
3426
|
if (identifier in this.destinations) {
|
|
3427
3427
|
throw new ImplementationError(`Logger "${identifier}" already exists`);
|
|
3428
3428
|
}
|
|
3429
3429
|
const dest = LogDestination({ name: identifier });
|
|
3430
3430
|
const legacy = adaptDestinationToLegacy(dest);
|
|
3431
|
-
legacy.log =
|
|
3431
|
+
legacy.log = logger204;
|
|
3432
3432
|
if (options?.defaultLogLevel !== void 0) {
|
|
3433
3433
|
legacy.defaultLogLevel = options.defaultLogLevel;
|
|
3434
3434
|
}
|
|
@@ -5538,8 +5538,8 @@ function Construction(subject, initializer) {
|
|
|
5538
5538
|
}
|
|
5539
5539
|
}
|
|
5540
5540
|
function unhandledError(...args) {
|
|
5541
|
-
const
|
|
5542
|
-
|
|
5541
|
+
const logger204 = Logger.get(subject.constructor.name);
|
|
5542
|
+
logger204.error(...args);
|
|
5543
5543
|
}
|
|
5544
5544
|
function createErrorHandler(name) {
|
|
5545
5545
|
return (e) => {
|
|
@@ -9825,12 +9825,12 @@ var init_StandardCrypto = __esm({
|
|
|
9825
9825
|
implementationName = "JS";
|
|
9826
9826
|
#crypto;
|
|
9827
9827
|
#subtle;
|
|
9828
|
-
constructor(
|
|
9829
|
-
const { subtle } =
|
|
9830
|
-
assertInterface("crypto",
|
|
9828
|
+
constructor(crypto8 = globalThis.crypto) {
|
|
9829
|
+
const { subtle } = crypto8;
|
|
9830
|
+
assertInterface("crypto", crypto8, requiredCryptoMethods);
|
|
9831
9831
|
assertInterface("crypto.subtle", subtle, requiredSubtleMethods);
|
|
9832
9832
|
super();
|
|
9833
|
-
this.#crypto =
|
|
9833
|
+
this.#crypto = crypto8;
|
|
9834
9834
|
this.#subtle = subtle;
|
|
9835
9835
|
}
|
|
9836
9836
|
get subtle() {
|
|
@@ -10013,9 +10013,9 @@ var init_StandardCrypto = __esm({
|
|
|
10013
10013
|
}
|
|
10014
10014
|
};
|
|
10015
10015
|
if ("crypto" in globalThis && globalThis.crypto?.subtle) {
|
|
10016
|
-
const
|
|
10017
|
-
Environment.default.set(Entropy,
|
|
10018
|
-
Environment.default.set(Crypto,
|
|
10016
|
+
const crypto8 = new StandardCrypto();
|
|
10017
|
+
Environment.default.set(Entropy, crypto8);
|
|
10018
|
+
Environment.default.set(Crypto, crypto8);
|
|
10019
10019
|
}
|
|
10020
10020
|
}
|
|
10021
10021
|
});
|
|
@@ -10025,9 +10025,9 @@ function MockCrypto(index = 128, implementation = StandardCrypto) {
|
|
|
10025
10025
|
if (index < 0 || index > 255) {
|
|
10026
10026
|
throw new ImplementationError(`Index for stable crypto must be 0-255`);
|
|
10027
10027
|
}
|
|
10028
|
-
const
|
|
10029
|
-
const { randomBytes: randomBytes2, createKeyPair } =
|
|
10030
|
-
Object.defineProperties(
|
|
10028
|
+
const crypto8 = new implementation();
|
|
10029
|
+
const { randomBytes: randomBytes2, createKeyPair } = crypto8;
|
|
10030
|
+
Object.defineProperties(crypto8, {
|
|
10031
10031
|
index: {
|
|
10032
10032
|
get() {
|
|
10033
10033
|
return index;
|
|
@@ -10038,12 +10038,12 @@ function MockCrypto(index = 128, implementation = StandardCrypto) {
|
|
|
10038
10038
|
},
|
|
10039
10039
|
entropic: {
|
|
10040
10040
|
get() {
|
|
10041
|
-
return
|
|
10041
|
+
return crypto8.randomBytes === randomBytes2;
|
|
10042
10042
|
},
|
|
10043
10043
|
set(entropic) {
|
|
10044
10044
|
if (entropic) {
|
|
10045
|
-
|
|
10046
|
-
|
|
10045
|
+
crypto8.randomBytes = randomBytes2;
|
|
10046
|
+
crypto8.createKeyPair = createKeyPair;
|
|
10047
10047
|
} else {
|
|
10048
10048
|
disableEntropy();
|
|
10049
10049
|
}
|
|
@@ -10051,15 +10051,15 @@ function MockCrypto(index = 128, implementation = StandardCrypto) {
|
|
|
10051
10051
|
}
|
|
10052
10052
|
});
|
|
10053
10053
|
disableEntropy();
|
|
10054
|
-
return
|
|
10054
|
+
return crypto8;
|
|
10055
10055
|
function disableEntropy() {
|
|
10056
|
-
|
|
10056
|
+
crypto8.randomBytes = function getRandomDataNONENTROPIC(length) {
|
|
10057
10057
|
const result = new Uint8Array(length);
|
|
10058
10058
|
result.fill(index);
|
|
10059
10059
|
return result;
|
|
10060
10060
|
};
|
|
10061
|
-
|
|
10062
|
-
const privateBits = ec.mapHashToField(Bytes.of(
|
|
10061
|
+
crypto8.createKeyPair = function getRandomDataNONENTROPIC() {
|
|
10062
|
+
const privateBits = ec.mapHashToField(Bytes.of(crypto8.randomBytes(48)), ec.p256.Point.CURVE().n);
|
|
10063
10063
|
return Key({
|
|
10064
10064
|
kty: KeyType.EC,
|
|
10065
10065
|
crv: CurveType.p256,
|
|
@@ -10092,9 +10092,9 @@ var init_NodeJsStyleCrypto = __esm({
|
|
|
10092
10092
|
NodeJsStyleCrypto = class extends Crypto {
|
|
10093
10093
|
implementationName = "Node.js";
|
|
10094
10094
|
#crypto;
|
|
10095
|
-
constructor(
|
|
10095
|
+
constructor(crypto8) {
|
|
10096
10096
|
super();
|
|
10097
|
-
this.#crypto =
|
|
10097
|
+
this.#crypto = crypto8;
|
|
10098
10098
|
}
|
|
10099
10099
|
encrypt(key, data, nonce, aad) {
|
|
10100
10100
|
const cipher = this.#crypto.createCipheriv(CRYPTO_ENCRYPT_ALGORITHM, Bytes.of(key), Bytes.of(nonce), {
|
|
@@ -10368,29 +10368,29 @@ var init_Spake2p = __esm({
|
|
|
10368
10368
|
#context;
|
|
10369
10369
|
#random;
|
|
10370
10370
|
#w0;
|
|
10371
|
-
static async computeW0W1(
|
|
10371
|
+
static async computeW0W1(crypto8, { iterations, salt }, pin) {
|
|
10372
10372
|
const pinWriter = new DataWriter(Endian.Little);
|
|
10373
10373
|
pinWriter.writeUInt32(pin);
|
|
10374
10374
|
const ws2 = Bytes.of(
|
|
10375
|
-
await
|
|
10375
|
+
await crypto8.createPbkdf2Key(pinWriter.toByteArray(), salt, iterations, CRYPTO_W_SIZE_BYTES * 2)
|
|
10376
10376
|
);
|
|
10377
10377
|
const curve = Point2.CURVE();
|
|
10378
10378
|
const w0 = mod2(bytesToNumberBE(ws2.slice(0, 40)), curve.n);
|
|
10379
10379
|
const w1 = mod2(bytesToNumberBE(ws2.slice(40, 80)), curve.n);
|
|
10380
10380
|
return { w0, w1 };
|
|
10381
10381
|
}
|
|
10382
|
-
static async computeW0L(
|
|
10383
|
-
const { w0, w1 } = await this.computeW0W1(
|
|
10382
|
+
static async computeW0L(crypto8, pbkdfParameters, pin) {
|
|
10383
|
+
const { w0, w1 } = await this.computeW0W1(crypto8, pbkdfParameters, pin);
|
|
10384
10384
|
const L = Point2.BASE.multiply(w1).toBytes(false);
|
|
10385
10385
|
return { w0, L };
|
|
10386
10386
|
}
|
|
10387
|
-
static create(
|
|
10387
|
+
static create(crypto8, context, w0) {
|
|
10388
10388
|
const curve = Point2.CURVE();
|
|
10389
|
-
const random =
|
|
10390
|
-
return new _Spake2p(
|
|
10389
|
+
const random = crypto8.randomBigInt(32, curve.p);
|
|
10390
|
+
return new _Spake2p(crypto8, context, random, w0);
|
|
10391
10391
|
}
|
|
10392
|
-
constructor(
|
|
10393
|
-
this.#crypto =
|
|
10392
|
+
constructor(crypto8, context, random, w0) {
|
|
10393
|
+
this.#crypto = crypto8;
|
|
10394
10394
|
this.#context = context;
|
|
10395
10395
|
this.#random = random;
|
|
10396
10396
|
this.#w0 = w0;
|
|
@@ -10521,10 +10521,10 @@ var init_X509 = __esm({
|
|
|
10521
10521
|
init_Pem();
|
|
10522
10522
|
init_X962();
|
|
10523
10523
|
((X5092) => {
|
|
10524
|
-
async function sign(
|
|
10524
|
+
async function sign(crypto8, key, cert) {
|
|
10525
10525
|
return {
|
|
10526
10526
|
...cert,
|
|
10527
|
-
signature: (await
|
|
10527
|
+
signature: (await crypto8.signEcdsa(key, certificateToDer(cert))).der
|
|
10528
10528
|
};
|
|
10529
10529
|
}
|
|
10530
10530
|
X5092.sign = sign;
|
|
@@ -46460,9 +46460,9 @@ var init_NodeId = __esm({
|
|
|
46460
46460
|
return hex.fixed(nodeId3, 16);
|
|
46461
46461
|
}
|
|
46462
46462
|
NodeId2.strOf = strOf;
|
|
46463
|
-
NodeId2.randomOperationalNodeId = (
|
|
46463
|
+
NodeId2.randomOperationalNodeId = (crypto8) => {
|
|
46464
46464
|
while (true) {
|
|
46465
|
-
const randomBigInt =
|
|
46465
|
+
const randomBigInt = crypto8.randomBigInt(8);
|
|
46466
46466
|
if (randomBigInt >= OPERATIONAL_NODE_MIN && randomBigInt <= OPERATIONAL_NODE_MAX) {
|
|
46467
46467
|
return NodeId2(randomBigInt);
|
|
46468
46468
|
}
|
|
@@ -88338,11 +88338,11 @@ var init_GlobalFabricId = __esm({
|
|
|
88338
88338
|
return hex.fixed(id, 16);
|
|
88339
88339
|
}
|
|
88340
88340
|
GlobalFabricId2.strOf = strOf;
|
|
88341
|
-
async function compute(
|
|
88341
|
+
async function compute(crypto8, id, caKey) {
|
|
88342
88342
|
const saltWriter = new DataWriter();
|
|
88343
88343
|
saltWriter.writeUInt64(id);
|
|
88344
88344
|
return GlobalFabricId2(
|
|
88345
|
-
await
|
|
88345
|
+
await crypto8.createHkdfKey(
|
|
88346
88346
|
Bytes.of(caKey).slice(1),
|
|
88347
88347
|
saltWriter.toByteArray(),
|
|
88348
88348
|
COMPRESSED_FABRIC_ID_INFO,
|
|
@@ -90621,8 +90621,8 @@ var init_Certificate = __esm({
|
|
|
90621
90621
|
* Sign the certificate using the provided crypto and key.
|
|
90622
90622
|
* It throws a CertificateError if the certificate is already signed.
|
|
90623
90623
|
*/
|
|
90624
|
-
async sign(
|
|
90625
|
-
this.signature = await
|
|
90624
|
+
async sign(crypto8, key) {
|
|
90625
|
+
this.signature = await crypto8.signEcdsa(key, this.asUnsignedDer());
|
|
90626
90626
|
}
|
|
90627
90627
|
/**
|
|
90628
90628
|
* Serialize as signed DER.
|
|
@@ -90684,7 +90684,7 @@ var init_Certificate = __esm({
|
|
|
90684
90684
|
}
|
|
90685
90685
|
};
|
|
90686
90686
|
((Certificate2) => {
|
|
90687
|
-
async function createCertificateSigningRequest(
|
|
90687
|
+
async function createCertificateSigningRequest(crypto8, key) {
|
|
90688
90688
|
const request = {
|
|
90689
90689
|
version: 0,
|
|
90690
90690
|
subject: { organization: X520.OrganisationName("CSR") },
|
|
@@ -90694,7 +90694,7 @@ var init_Certificate = __esm({
|
|
|
90694
90694
|
return DerCodec.encode({
|
|
90695
90695
|
request,
|
|
90696
90696
|
signAlgorithm: X962.EcdsaWithSHA256,
|
|
90697
|
-
signature: DerBitString((await
|
|
90697
|
+
signature: DerBitString((await crypto8.signEcdsa(key, DerCodec.encode(request))).der)
|
|
90698
90698
|
});
|
|
90699
90699
|
}
|
|
90700
90700
|
Certificate2.createCertificateSigningRequest = createCertificateSigningRequest;
|
|
@@ -90973,7 +90973,7 @@ var init_Certificate = __esm({
|
|
|
90973
90973
|
};
|
|
90974
90974
|
}
|
|
90975
90975
|
Certificate2.parseAsn1Certificate = parseAsn1Certificate;
|
|
90976
|
-
async function getPublicKeyFromCsr(
|
|
90976
|
+
async function getPublicKeyFromCsr(crypto8, encodedCsr) {
|
|
90977
90977
|
const { _elements: rootElements } = DerCodec.decode(encodedCsr);
|
|
90978
90978
|
if (rootElements?.length !== 3) {
|
|
90979
90979
|
throw new CertificateError("Invalid CSR data");
|
|
@@ -91011,7 +91011,7 @@ var init_Certificate = __esm({
|
|
|
91011
91011
|
if (signatureAlgorithmBytes === void 0 || !Bytes.areEqual(X962.EcdsaWithSHA256._objectId._bytes, signatureAlgorithmBytes)) {
|
|
91012
91012
|
throw new CertificateError("Unsupported signature algorithm in CSR");
|
|
91013
91013
|
}
|
|
91014
|
-
await
|
|
91014
|
+
await crypto8.verifyEcdsa(
|
|
91015
91015
|
PublicKey(publicKey),
|
|
91016
91016
|
DerCodec.encode(requestNode),
|
|
91017
91017
|
new EcdsaSignature(signatureNode._bytes, "der")
|
|
@@ -91240,7 +91240,7 @@ var init_Icac = __esm({
|
|
|
91240
91240
|
* Verify requirements a Matter Intermediate CA certificate must fulfill.
|
|
91241
91241
|
* Rules for this are listed in @see {@link MatterSpecification.v12.Core} §6.5.x
|
|
91242
91242
|
*/
|
|
91243
|
-
async verify(
|
|
91243
|
+
async verify(crypto8, root) {
|
|
91244
91244
|
this.generalVerify();
|
|
91245
91245
|
const {
|
|
91246
91246
|
subject,
|
|
@@ -91316,7 +91316,7 @@ var init_Icac = __esm({
|
|
|
91316
91316
|
`Ica certificate authorityKeyIdentifier must be equal to root cert subjectKeyIdentifier.`
|
|
91317
91317
|
);
|
|
91318
91318
|
}
|
|
91319
|
-
await
|
|
91319
|
+
await crypto8.verifyEcdsa(PublicKey(root.cert.ellipticCurvePublicKey), this.asUnsignedDer(), this.signature);
|
|
91320
91320
|
}
|
|
91321
91321
|
};
|
|
91322
91322
|
}
|
|
@@ -91367,7 +91367,7 @@ var init_Noc = __esm({
|
|
|
91367
91367
|
* Verify requirements a Matter Node Operational certificate must fulfill.
|
|
91368
91368
|
* Rules for this are listed in @see {@link MatterSpecification.v12.Core} §6.5.x
|
|
91369
91369
|
*/
|
|
91370
|
-
async verify(
|
|
91370
|
+
async verify(crypto8, root, ica) {
|
|
91371
91371
|
this.generalVerify();
|
|
91372
91372
|
const {
|
|
91373
91373
|
subject,
|
|
@@ -91452,7 +91452,7 @@ var init_Noc = __esm({
|
|
|
91452
91452
|
`Noc certificate authorityKeyIdentifier must be equal to Root/Ica subjectKeyIdentifier.`
|
|
91453
91453
|
);
|
|
91454
91454
|
}
|
|
91455
|
-
await
|
|
91455
|
+
await crypto8.verifyEcdsa(PublicKey(issuer.cert.ellipticCurvePublicKey), this.asUnsignedDer(), this.signature);
|
|
91456
91456
|
}
|
|
91457
91457
|
};
|
|
91458
91458
|
}
|
|
@@ -93037,10 +93037,10 @@ var init_MessageCounter = __esm({
|
|
|
93037
93037
|
* counter is not allowed to rollover and the callback is called before a rollover would happen. Optionally provide
|
|
93038
93038
|
* a number of messages before the rollover callback is called (Default 1000).
|
|
93039
93039
|
*/
|
|
93040
|
-
constructor(
|
|
93040
|
+
constructor(crypto8, onRollover, rolloverInfoDifference = ROLLOVER_INFO_DIFFERENCE) {
|
|
93041
93041
|
this.onRollover = onRollover;
|
|
93042
93042
|
this.rolloverInfoDifference = rolloverInfoDifference;
|
|
93043
|
-
this.messageCounter = (
|
|
93043
|
+
this.messageCounter = (crypto8.randomUint32 >>> 4) + 1;
|
|
93044
93044
|
}
|
|
93045
93045
|
messageCounter;
|
|
93046
93046
|
async getIncrementedCounter() {
|
|
@@ -93058,8 +93058,8 @@ var init_MessageCounter = __esm({
|
|
|
93058
93058
|
}
|
|
93059
93059
|
};
|
|
93060
93060
|
PersistedMessageCounter = class _PersistedMessageCounter extends MessageCounter {
|
|
93061
|
-
constructor(
|
|
93062
|
-
super(
|
|
93061
|
+
constructor(crypto8, storageContext, storageKey, aboutToRolloverCallback, rolloverInfoDifference = ROLLOVER_INFO_DIFFERENCE) {
|
|
93062
|
+
super(crypto8, aboutToRolloverCallback, rolloverInfoDifference);
|
|
93063
93063
|
this.storageContext = storageContext;
|
|
93064
93064
|
this.storageKey = storageKey;
|
|
93065
93065
|
this.#construction = Construction(this, async () => {
|
|
@@ -93078,10 +93078,10 @@ var init_MessageCounter = __esm({
|
|
|
93078
93078
|
get construction() {
|
|
93079
93079
|
return this.#construction;
|
|
93080
93080
|
}
|
|
93081
|
-
static async create(
|
|
93081
|
+
static async create(crypto8, storageContext, storageKey, aboutToRolloverCallback, rolloverInfoDifference = ROLLOVER_INFO_DIFFERENCE) {
|
|
93082
93082
|
return asyncNew(
|
|
93083
93083
|
_PersistedMessageCounter,
|
|
93084
|
-
|
|
93084
|
+
crypto8,
|
|
93085
93085
|
storageContext,
|
|
93086
93086
|
storageKey,
|
|
93087
93087
|
aboutToRolloverCallback,
|
|
@@ -93994,7 +93994,7 @@ var init_NodeSession = __esm({
|
|
|
93994
93994
|
}
|
|
93995
93995
|
constructor(config10) {
|
|
93996
93996
|
const {
|
|
93997
|
-
crypto:
|
|
93997
|
+
crypto: crypto8,
|
|
93998
93998
|
manager,
|
|
93999
93999
|
id,
|
|
94000
94000
|
fabric,
|
|
@@ -94012,14 +94012,14 @@ var init_NodeSession = __esm({
|
|
|
94012
94012
|
setActiveTimestamp: true,
|
|
94013
94013
|
// We always set the active timestamp for Secure sessions
|
|
94014
94014
|
// Can be changed to a PersistedMessageCounter if we implement session storage
|
|
94015
|
-
messageCounter: new MessageCounter(
|
|
94015
|
+
messageCounter: new MessageCounter(crypto8, async () => {
|
|
94016
94016
|
await this.initiateClose(async () => {
|
|
94017
94017
|
await this.closeSubscriptions(true);
|
|
94018
94018
|
});
|
|
94019
94019
|
}),
|
|
94020
94020
|
messageReceptionState: new MessageReceptionStateEncryptedWithoutRollover(0)
|
|
94021
94021
|
});
|
|
94022
|
-
this.#crypto =
|
|
94022
|
+
this.#crypto = crypto8;
|
|
94023
94023
|
this.#id = id;
|
|
94024
94024
|
this.#fabric = fabric;
|
|
94025
94025
|
this.#peerNodeId = peerNodeId;
|
|
@@ -94468,22 +94468,22 @@ var init_CaseClient = __esm({
|
|
|
94468
94468
|
}
|
|
94469
94469
|
}
|
|
94470
94470
|
async #doPair(messenger, exchange, fabric, peerNodeId, caseAuthenticatedTags) {
|
|
94471
|
-
const { crypto:
|
|
94472
|
-
const initiatorRandom =
|
|
94471
|
+
const { crypto: crypto8 } = fabric;
|
|
94472
|
+
const initiatorRandom = crypto8.randomBytes(32);
|
|
94473
94473
|
const initiatorSessionId = await this.#sessions.getNextAvailableSessionId();
|
|
94474
94474
|
const { operationalIdentityProtectionKey, operationalCert: localNoc, intermediateCACert: localIcac } = fabric;
|
|
94475
|
-
const localKey = await
|
|
94475
|
+
const localKey = await crypto8.createKeyPair();
|
|
94476
94476
|
let sigma1Bytes;
|
|
94477
94477
|
let resumed = false;
|
|
94478
94478
|
let resumptionRecord = this.#sessions.findResumptionRecordByAddress(fabric.addressOf(peerNodeId));
|
|
94479
94479
|
if (resumptionRecord !== void 0) {
|
|
94480
94480
|
const { sharedSecret, resumptionId } = resumptionRecord;
|
|
94481
|
-
const resumeKey = await
|
|
94481
|
+
const resumeKey = await crypto8.createHkdfKey(
|
|
94482
94482
|
sharedSecret,
|
|
94483
94483
|
Bytes.concat(initiatorRandom, resumptionId),
|
|
94484
94484
|
KDFSR1_KEY_INFO
|
|
94485
94485
|
);
|
|
94486
|
-
const initiatorResumeMic =
|
|
94486
|
+
const initiatorResumeMic = crypto8.encrypt(resumeKey, new Uint8Array(0), RESUME1_MIC_NONCE);
|
|
94487
94487
|
sigma1Bytes = await messenger.sendSigma1({
|
|
94488
94488
|
initiatorSessionId,
|
|
94489
94489
|
destinationId: await fabric.currentDestinationIdFor(peerNodeId, initiatorRandom),
|
|
@@ -94518,8 +94518,8 @@ var init_CaseClient = __esm({
|
|
|
94518
94518
|
...resumptionSessionParams ?? {}
|
|
94519
94519
|
};
|
|
94520
94520
|
const resumeSalt = Bytes.concat(initiatorRandom, resumptionId);
|
|
94521
|
-
const resumeKey = await
|
|
94522
|
-
|
|
94521
|
+
const resumeKey = await crypto8.createHkdfKey(sharedSecret, resumeSalt, KDFSR2_KEY_INFO);
|
|
94522
|
+
crypto8.decrypt(resumeKey, resumeMic, RESUME2_MIC_NONCE);
|
|
94523
94523
|
const secureSessionSalt = Bytes.concat(initiatorRandom, resumptionRecord.resumptionId);
|
|
94524
94524
|
secureSession = await this.#sessions.createSecureSession({
|
|
94525
94525
|
channel: exchange.channel.channel,
|
|
@@ -94563,15 +94563,15 @@ var init_CaseClient = __esm({
|
|
|
94563
94563
|
...exchange.session.parameters,
|
|
94564
94564
|
...responderSessionParams ?? {}
|
|
94565
94565
|
};
|
|
94566
|
-
const sharedSecret = await
|
|
94566
|
+
const sharedSecret = await crypto8.generateDhSecret(localKey, PublicKey(peerKey));
|
|
94567
94567
|
const sigma2Salt = Bytes.concat(
|
|
94568
94568
|
operationalIdentityProtectionKey,
|
|
94569
94569
|
responderRandom,
|
|
94570
94570
|
peerKey,
|
|
94571
|
-
await
|
|
94571
|
+
await crypto8.computeHash(sigma1Bytes)
|
|
94572
94572
|
);
|
|
94573
|
-
const sigma2Key = await
|
|
94574
|
-
const peerEncryptedData =
|
|
94573
|
+
const sigma2Key = await crypto8.createHkdfKey(sharedSecret, sigma2Salt, KDFSR2_INFO);
|
|
94574
|
+
const peerEncryptedData = crypto8.decrypt(sigma2Key, peerEncrypted, TBE_DATA2_NONCE);
|
|
94575
94575
|
const {
|
|
94576
94576
|
responderNoc: peerNoc,
|
|
94577
94577
|
responderIcac: peerIcac,
|
|
@@ -94588,7 +94588,7 @@ var init_CaseClient = __esm({
|
|
|
94588
94588
|
ellipticCurvePublicKey: peerPublicKey,
|
|
94589
94589
|
subject: { fabricId: peerFabricIdNOCert, nodeId: peerNodeIdNOCert }
|
|
94590
94590
|
} = Noc.fromTlv(peerNoc).cert;
|
|
94591
|
-
await
|
|
94591
|
+
await crypto8.verifyEcdsa(PublicKey(peerPublicKey), peerSignatureData, new EcdsaSignature(peerSignature));
|
|
94592
94592
|
if (peerNodeIdNOCert !== peerNodeId) {
|
|
94593
94593
|
throw new UnexpectedDataError(
|
|
94594
94594
|
`The node ID in the peer certificate ${peerNodeIdNOCert} doesn't match the expected peer node ID ${peerNodeId}`
|
|
@@ -94612,9 +94612,9 @@ var init_CaseClient = __esm({
|
|
|
94612
94612
|
await fabric.verifyCredentials(peerNoc, peerIcac);
|
|
94613
94613
|
const sigma3Salt = Bytes.concat(
|
|
94614
94614
|
operationalIdentityProtectionKey,
|
|
94615
|
-
await
|
|
94615
|
+
await crypto8.computeHash([sigma1Bytes, sigma2Bytes])
|
|
94616
94616
|
);
|
|
94617
|
-
const sigma3Key = await
|
|
94617
|
+
const sigma3Key = await crypto8.createHkdfKey(sharedSecret, sigma3Salt, KDFSR3_INFO);
|
|
94618
94618
|
const signatureData = TlvSignedData.encode({
|
|
94619
94619
|
responderNoc: localNoc,
|
|
94620
94620
|
responderIcac: localIcac,
|
|
@@ -94627,13 +94627,13 @@ var init_CaseClient = __esm({
|
|
|
94627
94627
|
responderIcac: localIcac,
|
|
94628
94628
|
signature: signature.bytes
|
|
94629
94629
|
});
|
|
94630
|
-
const encrypted =
|
|
94630
|
+
const encrypted = crypto8.encrypt(sigma3Key, encryptedData, TBE_DATA3_NONCE);
|
|
94631
94631
|
const sigma3Bytes = await messenger.sendSigma3({ encrypted });
|
|
94632
94632
|
await messenger.waitForSuccess("Sigma3-Success");
|
|
94633
94633
|
const sessionCaseAuthenticatedTags = caseAuthenticatedTags ?? resumptionRecord?.caseAuthenticatedTags;
|
|
94634
94634
|
const secureSessionSalt = Bytes.concat(
|
|
94635
94635
|
operationalIdentityProtectionKey,
|
|
94636
|
-
await
|
|
94636
|
+
await crypto8.computeHash([sigma1Bytes, sigma2Bytes, sigma3Bytes])
|
|
94637
94637
|
);
|
|
94638
94638
|
secureSession = await this.#sessions.createSecureSession({
|
|
94639
94639
|
channel: exchange.channel.channel,
|
|
@@ -94711,7 +94711,7 @@ var init_Rcac = __esm({
|
|
|
94711
94711
|
* Verify requirements a Matter Root certificate must fulfill.
|
|
94712
94712
|
* Rules for this are listed in @see {@link MatterSpecification.v12.Core} §6.5.x
|
|
94713
94713
|
*/
|
|
94714
|
-
async verify(
|
|
94714
|
+
async verify(crypto8) {
|
|
94715
94715
|
this.generalVerify();
|
|
94716
94716
|
const { subject, extensions } = this.cert;
|
|
94717
94717
|
const { fabricId: fabricId3, rcacId } = subject;
|
|
@@ -94768,7 +94768,7 @@ var init_Rcac = __esm({
|
|
|
94768
94768
|
`Root certificate authorityKeyIdentifier must be equal to subjectKeyIdentifier.`
|
|
94769
94769
|
);
|
|
94770
94770
|
}
|
|
94771
|
-
await
|
|
94771
|
+
await crypto8.verifyEcdsa(PublicKey(this.cert.ellipticCurvePublicKey), this.asUnsignedDer(), this.signature);
|
|
94772
94772
|
}
|
|
94773
94773
|
};
|
|
94774
94774
|
}
|
|
@@ -94903,8 +94903,8 @@ var init_KeySets = __esm({
|
|
|
94903
94903
|
};
|
|
94904
94904
|
}
|
|
94905
94905
|
/** Calculates a group session id based on the operational group key. */
|
|
94906
|
-
async sessionIdFromKey(
|
|
94907
|
-
const groupKeyHash = await
|
|
94906
|
+
async sessionIdFromKey(crypto8, operationalGroupKey) {
|
|
94907
|
+
const groupKeyHash = await crypto8.createHkdfKey(operationalGroupKey, new Uint8Array(), GROUP_KEY_INFO, 2);
|
|
94908
94908
|
return new DataReader(groupKeyHash).readUInt16();
|
|
94909
94909
|
}
|
|
94910
94910
|
/**
|
|
@@ -94957,8 +94957,8 @@ var init_MessagingState = __esm({
|
|
|
94957
94957
|
#messageDataReceptionState = /* @__PURE__ */ new Map();
|
|
94958
94958
|
#crypto;
|
|
94959
94959
|
#storage;
|
|
94960
|
-
constructor(
|
|
94961
|
-
this.#crypto =
|
|
94960
|
+
constructor(crypto8, storage2) {
|
|
94961
|
+
this.#crypto = crypto8;
|
|
94962
94962
|
if (storage2 !== void 0) {
|
|
94963
94963
|
this.#storage = storage2;
|
|
94964
94964
|
}
|
|
@@ -95491,8 +95491,8 @@ var init_Fabric = __esm({
|
|
|
95491
95491
|
* Certain derived fields that require async crypto operations to compute must be supplied here. Use {@link create}
|
|
95492
95492
|
* to populate these fields automatically.
|
|
95493
95493
|
*/
|
|
95494
|
-
constructor(
|
|
95495
|
-
this.#crypto =
|
|
95494
|
+
constructor(crypto8, config10) {
|
|
95495
|
+
this.#crypto = crypto8;
|
|
95496
95496
|
this.fabricIndex = config10.fabricIndex;
|
|
95497
95497
|
this.fabricId = config10.fabricId;
|
|
95498
95498
|
this.nodeId = config10.nodeId;
|
|
@@ -95521,20 +95521,20 @@ var init_Fabric = __esm({
|
|
|
95521
95521
|
*
|
|
95522
95522
|
* This async creation path populates derived fields that require async crypto operations to compute.
|
|
95523
95523
|
*/
|
|
95524
|
-
static async create(
|
|
95524
|
+
static async create(crypto8, config10) {
|
|
95525
95525
|
let { globalId, operationalIdentityProtectionKey } = config10;
|
|
95526
95526
|
if (globalId === void 0) {
|
|
95527
95527
|
const caKey = config10.rootPublicKey ?? Rcac.publicKeyOfTlv(config10.rootCert);
|
|
95528
|
-
globalId = await GlobalFabricId.compute(
|
|
95528
|
+
globalId = await GlobalFabricId.compute(crypto8, config10.fabricId, caKey);
|
|
95529
95529
|
}
|
|
95530
95530
|
if (operationalIdentityProtectionKey === void 0) {
|
|
95531
|
-
operationalIdentityProtectionKey = await
|
|
95531
|
+
operationalIdentityProtectionKey = await crypto8.createHkdfKey(
|
|
95532
95532
|
config10.identityProtectionKey,
|
|
95533
95533
|
Bytes.fromBigInt(globalId, 8),
|
|
95534
95534
|
GROUP_SECURITY_INFO
|
|
95535
95535
|
);
|
|
95536
95536
|
}
|
|
95537
|
-
return new _Fabric(
|
|
95537
|
+
return new _Fabric(crypto8, {
|
|
95538
95538
|
...config10,
|
|
95539
95539
|
globalId,
|
|
95540
95540
|
operationalIdentityProtectionKey
|
|
@@ -95791,12 +95791,12 @@ var init_Fabric = __esm({
|
|
|
95791
95791
|
#vvsc;
|
|
95792
95792
|
#fabricIndex;
|
|
95793
95793
|
#label = "";
|
|
95794
|
-
constructor(
|
|
95795
|
-
this.#crypto =
|
|
95794
|
+
constructor(crypto8, key) {
|
|
95795
|
+
this.#crypto = crypto8;
|
|
95796
95796
|
this.#keyPair = key;
|
|
95797
95797
|
}
|
|
95798
|
-
static async create(
|
|
95799
|
-
return new _FabricBuilder(
|
|
95798
|
+
static async create(crypto8) {
|
|
95799
|
+
return new _FabricBuilder(crypto8, await crypto8.createKeyPair());
|
|
95800
95800
|
}
|
|
95801
95801
|
get publicKey() {
|
|
95802
95802
|
return this.#keyPair.publicKey;
|
|
@@ -95955,8 +95955,8 @@ var init_FabricManager = __esm({
|
|
|
95955
95955
|
failsafeClosed: Observable()
|
|
95956
95956
|
};
|
|
95957
95957
|
#construction;
|
|
95958
|
-
constructor(
|
|
95959
|
-
this.#crypto =
|
|
95958
|
+
constructor(crypto8, storage2) {
|
|
95959
|
+
this.#crypto = crypto8;
|
|
95960
95960
|
this.#storage = storage2;
|
|
95961
95961
|
let construct;
|
|
95962
95962
|
if (this.#storage === void 0) {
|
|
@@ -95969,7 +95969,7 @@ var init_FabricManager = __esm({
|
|
|
95969
95969
|
}
|
|
95970
95970
|
const fabrics = await this.#storage.get("fabrics", []);
|
|
95971
95971
|
for (const fabricConfig of fabrics) {
|
|
95972
|
-
this.#addNewFabric(await Fabric.create(
|
|
95972
|
+
this.#addNewFabric(await Fabric.create(crypto8, fabricConfig));
|
|
95973
95973
|
}
|
|
95974
95974
|
this.#nextFabricIndex = await this.#storage.get("nextFabricIndex", this.#nextFabricIndex);
|
|
95975
95975
|
this.#initializationDone = true;
|
|
@@ -96265,14 +96265,14 @@ var init_CaseServer = __esm({
|
|
|
96265
96265
|
return false;
|
|
96266
96266
|
}
|
|
96267
96267
|
const { sharedSecret, fabric, peerNodeId, caseAuthenticatedTags } = cx.resumptionRecord;
|
|
96268
|
-
const { crypto:
|
|
96269
|
-
const peerResumeKey = await
|
|
96268
|
+
const { crypto: crypto8 } = this.#fabrics;
|
|
96269
|
+
const peerResumeKey = await crypto8.createHkdfKey(
|
|
96270
96270
|
sharedSecret,
|
|
96271
96271
|
Bytes.concat(cx.peerRandom, cx.peerResumptionId),
|
|
96272
96272
|
KDFSR1_KEY_INFO
|
|
96273
96273
|
);
|
|
96274
96274
|
try {
|
|
96275
|
-
|
|
96275
|
+
crypto8.decrypt(peerResumeKey, cx.peerResumeMic, RESUME1_MIC_NONCE);
|
|
96276
96276
|
} catch (e) {
|
|
96277
96277
|
CryptoDecryptError.accept(e);
|
|
96278
96278
|
cx.peerResumptionId = cx.peerResumeMic = void 0;
|
|
@@ -96296,8 +96296,8 @@ var init_CaseServer = __esm({
|
|
|
96296
96296
|
// Session establishment could still fail, so add session ourselves to the manager
|
|
96297
96297
|
});
|
|
96298
96298
|
const resumeSalt = Bytes.concat(cx.peerRandom, cx.localResumptionId);
|
|
96299
|
-
const resumeKey = await
|
|
96300
|
-
const resumeMic =
|
|
96299
|
+
const resumeKey = await crypto8.createHkdfKey(sharedSecret, resumeSalt, KDFSR2_KEY_INFO);
|
|
96300
|
+
const resumeMic = crypto8.encrypt(resumeKey, new Uint8Array(0), RESUME2_MIC_NONCE);
|
|
96301
96301
|
try {
|
|
96302
96302
|
const responderSessionParams = this.#sessions.sessionParameters;
|
|
96303
96303
|
await cx.messenger.sendSigma2Resume({
|
|
@@ -96326,20 +96326,20 @@ var init_CaseServer = __esm({
|
|
|
96326
96326
|
) {
|
|
96327
96327
|
return false;
|
|
96328
96328
|
}
|
|
96329
|
-
const { crypto:
|
|
96330
|
-
const responderRandom =
|
|
96329
|
+
const { crypto: crypto8 } = this.#fabrics;
|
|
96330
|
+
const responderRandom = crypto8.randomBytes(32);
|
|
96331
96331
|
const fabric = await this.#fabrics.findFabricFromDestinationId(cx.destinationId, cx.peerRandom);
|
|
96332
96332
|
const { operationalCert: nodeOpCert, intermediateCACert, operationalIdentityProtectionKey } = fabric;
|
|
96333
|
-
const key = await
|
|
96333
|
+
const key = await crypto8.createKeyPair();
|
|
96334
96334
|
const responderEcdhPublicKey = key.publicBits;
|
|
96335
|
-
const sharedSecret = await
|
|
96335
|
+
const sharedSecret = await crypto8.generateDhSecret(key, PublicKey(cx.peerEcdhPublicKey));
|
|
96336
96336
|
const sigma2Salt = Bytes.concat(
|
|
96337
96337
|
operationalIdentityProtectionKey,
|
|
96338
96338
|
responderRandom,
|
|
96339
96339
|
responderEcdhPublicKey,
|
|
96340
|
-
await
|
|
96340
|
+
await crypto8.computeHash(cx.bytes)
|
|
96341
96341
|
);
|
|
96342
|
-
const sigma2Key = await
|
|
96342
|
+
const sigma2Key = await crypto8.createHkdfKey(sharedSecret, sigma2Salt, KDFSR2_INFO);
|
|
96343
96343
|
const signatureData = TlvSignedData.encode({
|
|
96344
96344
|
responderNoc: nodeOpCert,
|
|
96345
96345
|
responderIcac: intermediateCACert,
|
|
@@ -96353,7 +96353,7 @@ var init_CaseServer = __esm({
|
|
|
96353
96353
|
signature: signature.bytes,
|
|
96354
96354
|
resumptionId: cx.localResumptionId
|
|
96355
96355
|
});
|
|
96356
|
-
const encrypted =
|
|
96356
|
+
const encrypted = crypto8.encrypt(sigma2Key, encryptedData, TBE_DATA2_NONCE);
|
|
96357
96357
|
const responderSessionId = await this.#sessions.getNextAvailableSessionId();
|
|
96358
96358
|
const sigma2Bytes = await cx.messenger.sendSigma2({
|
|
96359
96359
|
responderRandom,
|
|
@@ -96369,10 +96369,10 @@ var init_CaseServer = __esm({
|
|
|
96369
96369
|
} = await cx.messenger.readSigma3();
|
|
96370
96370
|
const sigma3Salt = Bytes.concat(
|
|
96371
96371
|
operationalIdentityProtectionKey,
|
|
96372
|
-
await
|
|
96372
|
+
await crypto8.computeHash([cx.bytes, sigma2Bytes])
|
|
96373
96373
|
);
|
|
96374
|
-
const sigma3Key = await
|
|
96375
|
-
const peerDecryptedData =
|
|
96374
|
+
const sigma3Key = await crypto8.createHkdfKey(sharedSecret, sigma3Salt, KDFSR3_INFO);
|
|
96375
|
+
const peerDecryptedData = crypto8.decrypt(sigma3Key, peerEncrypted, TBE_DATA3_NONCE);
|
|
96376
96376
|
const {
|
|
96377
96377
|
responderNoc: peerNewOpCert,
|
|
96378
96378
|
responderIcac: peerIntermediateCACert,
|
|
@@ -96392,10 +96392,10 @@ var init_CaseServer = __esm({
|
|
|
96392
96392
|
if (fabric.fabricId !== peerFabricId) {
|
|
96393
96393
|
throw new UnexpectedDataError(`Fabric ID mismatch: ${fabric.fabricId} !== ${peerFabricId}`);
|
|
96394
96394
|
}
|
|
96395
|
-
await
|
|
96395
|
+
await crypto8.verifyEcdsa(PublicKey(peerPublicKey), peerSignatureData, new EcdsaSignature(peerSignature));
|
|
96396
96396
|
const secureSessionSalt = Bytes.concat(
|
|
96397
96397
|
operationalIdentityProtectionKey,
|
|
96398
|
-
await
|
|
96398
|
+
await crypto8.computeHash([cx.bytes, sigma2Bytes, sigma3Bytes])
|
|
96399
96399
|
);
|
|
96400
96400
|
const secureSession = await this.#sessions.createSecureSession({
|
|
96401
96401
|
channel,
|
|
@@ -96440,8 +96440,8 @@ var init_CaseServer = __esm({
|
|
|
96440
96440
|
peerSessionParams;
|
|
96441
96441
|
resumptionRecord;
|
|
96442
96442
|
#localResumptionId;
|
|
96443
|
-
constructor(
|
|
96444
|
-
this.crypto =
|
|
96443
|
+
constructor(crypto8, messenger, bytes, sigma1, resumptionRecord) {
|
|
96444
|
+
this.crypto = crypto8;
|
|
96445
96445
|
this.messenger = messenger;
|
|
96446
96446
|
this.bytes = bytes;
|
|
96447
96447
|
this.peerSessionId = sigma1.initiatorSessionId;
|
|
@@ -96937,25 +96937,25 @@ var init_PaseClient = __esm({
|
|
|
96937
96937
|
constructor(sessions) {
|
|
96938
96938
|
this.#sessions = sessions;
|
|
96939
96939
|
}
|
|
96940
|
-
static async generatePakePasscodeVerifier(
|
|
96941
|
-
const { w0, L } = await Spake2p.computeW0L(
|
|
96940
|
+
static async generatePakePasscodeVerifier(crypto8, setupPinCode, pbkdfParameters) {
|
|
96941
|
+
const { w0, L } = await Spake2p.computeW0L(crypto8, pbkdfParameters, setupPinCode);
|
|
96942
96942
|
return Bytes.concat(numberToBytesBE3(w0, 32), L);
|
|
96943
96943
|
}
|
|
96944
|
-
static generateRandomPasscode(
|
|
96944
|
+
static generateRandomPasscode(crypto8) {
|
|
96945
96945
|
let passcode;
|
|
96946
|
-
passcode =
|
|
96946
|
+
passcode = crypto8.randomUint32 % 99999998 + 1;
|
|
96947
96947
|
if (CommissioningOptions.FORBIDDEN_PASSCODES.includes(passcode)) {
|
|
96948
96948
|
passcode += 1;
|
|
96949
96949
|
}
|
|
96950
96950
|
return passcode;
|
|
96951
96951
|
}
|
|
96952
|
-
static generateRandomDiscriminator(
|
|
96953
|
-
return
|
|
96952
|
+
static generateRandomDiscriminator(crypto8) {
|
|
96953
|
+
return crypto8.randomUint16 % 4096;
|
|
96954
96954
|
}
|
|
96955
96955
|
async pair(initiatorSessionParams, exchange, channel, setupPin) {
|
|
96956
96956
|
const messenger = new PaseClientMessenger(exchange);
|
|
96957
|
-
const { crypto:
|
|
96958
|
-
const initiatorRandom =
|
|
96957
|
+
const { crypto: crypto8 } = this.#sessions;
|
|
96958
|
+
const initiatorRandom = crypto8.randomBytes(32);
|
|
96959
96959
|
const initiatorSessionId = await this.#sessions.getNextAvailableSessionId();
|
|
96960
96960
|
const requestPayload = await messenger.sendPbkdfParamRequest({
|
|
96961
96961
|
initiatorRandom,
|
|
@@ -96979,10 +96979,10 @@ var init_PaseClient = __esm({
|
|
|
96979
96979
|
...exchange.session.parameters,
|
|
96980
96980
|
...responderSessionParams ?? {}
|
|
96981
96981
|
};
|
|
96982
|
-
const { w0, w1 } = await Spake2p.computeW0W1(
|
|
96982
|
+
const { w0, w1 } = await Spake2p.computeW0W1(crypto8, pbkdfParameters, setupPin);
|
|
96983
96983
|
const spake2p = Spake2p.create(
|
|
96984
|
-
|
|
96985
|
-
await
|
|
96984
|
+
crypto8,
|
|
96985
|
+
await crypto8.computeHash([SPAKE_CONTEXT, requestPayload, responsePayload]),
|
|
96986
96986
|
w0
|
|
96987
96987
|
);
|
|
96988
96988
|
const X = spake2p.computeX();
|
|
@@ -97093,7 +97093,7 @@ var init_PaseServer = __esm({
|
|
|
97093
97093
|
}
|
|
97094
97094
|
}
|
|
97095
97095
|
}
|
|
97096
|
-
async handlePairingRequest(
|
|
97096
|
+
async handlePairingRequest(crypto8, channel) {
|
|
97097
97097
|
const messenger = this.#pairingMessenger;
|
|
97098
97098
|
logger40.info("Received pairing request", Mark.INBOUND, Diagnostic.via(messenger.channelName));
|
|
97099
97099
|
this.#pairingTimer = Time.getTimer(
|
|
@@ -97115,7 +97115,7 @@ var init_PaseServer = __esm({
|
|
|
97115
97115
|
throw new UnexpectedDataError(`Unsupported passcode ID ${passcodeId}.`);
|
|
97116
97116
|
}
|
|
97117
97117
|
const responderSessionId = await this.sessions.getNextAvailableSessionId();
|
|
97118
|
-
const responderRandom =
|
|
97118
|
+
const responderRandom = crypto8.randomBytes(32);
|
|
97119
97119
|
const responderSessionParams = this.sessions.sessionParameters;
|
|
97120
97120
|
if (initiatorSessionParams !== void 0) {
|
|
97121
97121
|
messenger.channel.session.timingParameters = initiatorSessionParams;
|
|
@@ -97128,8 +97128,8 @@ var init_PaseServer = __esm({
|
|
|
97128
97128
|
responderSessionParams
|
|
97129
97129
|
});
|
|
97130
97130
|
const spake2p = Spake2p.create(
|
|
97131
|
-
|
|
97132
|
-
await
|
|
97131
|
+
crypto8,
|
|
97132
|
+
await crypto8.computeHash([SPAKE_CONTEXT, requestPayload, responsePayload]),
|
|
97133
97133
|
this.w0
|
|
97134
97134
|
);
|
|
97135
97135
|
const { x: X } = await messenger.readPasePake1();
|
|
@@ -97197,14 +97197,14 @@ var init_UnsecuredSession = __esm({
|
|
|
97197
97197
|
supportsMRP = true;
|
|
97198
97198
|
type = SessionType.Unicast;
|
|
97199
97199
|
constructor(config10) {
|
|
97200
|
-
const { crypto:
|
|
97200
|
+
const { crypto: crypto8, initiatorNodeId, isInitiator } = config10;
|
|
97201
97201
|
super({
|
|
97202
97202
|
...config10,
|
|
97203
97203
|
setActiveTimestamp: !isInitiator,
|
|
97204
97204
|
// When we are the initiator we assume the node is in idle mode
|
|
97205
97205
|
messageReceptionState: new MessageReceptionStateUnencryptedWithRollover()
|
|
97206
97206
|
});
|
|
97207
|
-
this.#initiatorNodeId = initiatorNodeId ?? NodeId.randomOperationalNodeId(
|
|
97207
|
+
this.#initiatorNodeId = initiatorNodeId ?? NodeId.randomOperationalNodeId(crypto8);
|
|
97208
97208
|
}
|
|
97209
97209
|
get isSecure() {
|
|
97210
97210
|
return false;
|
|
@@ -97291,11 +97291,11 @@ var init_SessionManager = __esm({
|
|
|
97291
97291
|
constructor(context) {
|
|
97292
97292
|
this.#context = context;
|
|
97293
97293
|
const {
|
|
97294
|
-
fabrics: { crypto:
|
|
97294
|
+
fabrics: { crypto: crypto8 }
|
|
97295
97295
|
} = context;
|
|
97296
97296
|
this.#sessionParameters = SessionParameters({ ...SessionParameters.defaults, ...context.parameters });
|
|
97297
|
-
this.#nextSessionId =
|
|
97298
|
-
this.#globalUnencryptedMessageCounter = new MessageCounter(
|
|
97297
|
+
this.#nextSessionId = crypto8.randomUint16;
|
|
97298
|
+
this.#globalUnencryptedMessageCounter = new MessageCounter(crypto8);
|
|
97299
97299
|
this.#observers.on(context.fabrics.events.deleting, async (fabric) => {
|
|
97300
97300
|
await this.deleteResumptionRecordsForFabric(fabric);
|
|
97301
97301
|
});
|
|
@@ -100871,18 +100871,18 @@ var init_ProtocolMocks = __esm({
|
|
|
100871
100871
|
init_MessageExchange();
|
|
100872
100872
|
((ProtocolMocks2) => {
|
|
100873
100873
|
class Fabric2 extends Fabric {
|
|
100874
|
-
constructor(config10,
|
|
100875
|
-
if (!
|
|
100876
|
-
|
|
100877
|
-
if (!(
|
|
100878
|
-
|
|
100874
|
+
constructor(config10, crypto8) {
|
|
100875
|
+
if (!crypto8) {
|
|
100876
|
+
crypto8 = Environment.default.maybeGet(Crypto);
|
|
100877
|
+
if (!(crypto8 instanceof MockCrypto)) {
|
|
100878
|
+
crypto8 = MockCrypto();
|
|
100879
100879
|
}
|
|
100880
100880
|
}
|
|
100881
|
-
const keyPair = config10?.keyPair ??
|
|
100881
|
+
const keyPair = config10?.keyPair ?? crypto8.createKeyPair();
|
|
100882
100882
|
if (MaybePromise.is(keyPair)) {
|
|
100883
100883
|
throw new ImplementationError("Must provide key pair with async crypto");
|
|
100884
100884
|
}
|
|
100885
|
-
super(
|
|
100885
|
+
super(crypto8, {
|
|
100886
100886
|
...Fabric2.defaults,
|
|
100887
100887
|
...config10,
|
|
100888
100888
|
keyPair
|
|
@@ -100912,7 +100912,7 @@ var init_ProtocolMocks = __esm({
|
|
|
100912
100912
|
constructor(config10) {
|
|
100913
100913
|
const index = config10?.index ?? 1;
|
|
100914
100914
|
const fabricIndex = config10?.fabricIndex ?? 1;
|
|
100915
|
-
const
|
|
100915
|
+
const crypto8 = config10?.crypto ?? Environment.default.get(Crypto);
|
|
100916
100916
|
const fabric = config10 && "fabric" in config10 ? config10.fabric : new Fabric2({ fabricIndex });
|
|
100917
100917
|
const maxPayloadSize = config10?.maxPayloadSize;
|
|
100918
100918
|
let channel;
|
|
@@ -100931,7 +100931,7 @@ var init_ProtocolMocks = __esm({
|
|
|
100931
100931
|
encryptKey: Bytes.empty,
|
|
100932
100932
|
isInitiator: true,
|
|
100933
100933
|
...config10,
|
|
100934
|
-
crypto:
|
|
100934
|
+
crypto: crypto8,
|
|
100935
100935
|
fabric
|
|
100936
100936
|
};
|
|
100937
100937
|
delete fullConfig.channel;
|
|
@@ -100940,11 +100940,11 @@ var init_ProtocolMocks = __esm({
|
|
|
100940
100940
|
this.lifetime = Lifetime.mock;
|
|
100941
100941
|
}
|
|
100942
100942
|
static async create(config10) {
|
|
100943
|
-
const
|
|
100943
|
+
const crypto8 = config10?.crypto ?? config10?.manager?.crypto ?? Environment.default.get(Crypto);
|
|
100944
100944
|
const index = config10?.index ?? 1;
|
|
100945
100945
|
return NodeSession.create.call(this, {
|
|
100946
100946
|
id: index,
|
|
100947
|
-
crypto:
|
|
100947
|
+
crypto: crypto8,
|
|
100948
100948
|
peerNodeId: NodeId(0),
|
|
100949
100949
|
peerSessionId: index,
|
|
100950
100950
|
sharedSecret: Bytes.empty,
|
|
@@ -106671,9 +106671,9 @@ var init_MdnsAdvertiser = __esm({
|
|
|
106671
106671
|
init_CommissionerMdnsAdvertisement();
|
|
106672
106672
|
init_OperationalMdnsAdvertisement();
|
|
106673
106673
|
MdnsAdvertiser = class _MdnsAdvertiser extends Advertiser {
|
|
106674
|
-
constructor(
|
|
106674
|
+
constructor(crypto8, server, options) {
|
|
106675
106675
|
super(options?.lifetime);
|
|
106676
|
-
this.crypto =
|
|
106676
|
+
this.crypto = crypto8;
|
|
106677
106677
|
this.server = server;
|
|
106678
106678
|
this.port = options?.port ?? STANDARD_MATTER_PORT;
|
|
106679
106679
|
this.omitPrivateDetails = options?.omitPrivateDetails ?? false;
|
|
@@ -108118,8 +108118,8 @@ var init_AttestationCertificates = __esm({
|
|
|
108118
108118
|
* Sign the certificate using the provided crypto and key.
|
|
108119
108119
|
* If the certificate is already signed, it throws a CertificateError.
|
|
108120
108120
|
*/
|
|
108121
|
-
async sign(
|
|
108122
|
-
this.signature = await
|
|
108121
|
+
async sign(crypto8, key) {
|
|
108122
|
+
this.signature = await crypto8.signEcdsa(key, this.asUnsignedDer());
|
|
108123
108123
|
}
|
|
108124
108124
|
};
|
|
108125
108125
|
Paa = class _Paa extends AttestationBaseCertificate {
|
|
@@ -108168,17 +108168,17 @@ var init_AttestationCertificateManager = __esm({
|
|
|
108168
108168
|
#paiCertId = BigInt(1);
|
|
108169
108169
|
#paiCertBytes;
|
|
108170
108170
|
#nextCertificateId = 2;
|
|
108171
|
-
constructor(
|
|
108172
|
-
this.#crypto =
|
|
108171
|
+
constructor(crypto8, vendorId3, paiKeyPair, paiKeyIdentifier) {
|
|
108172
|
+
this.#crypto = crypto8;
|
|
108173
108173
|
this.#vendorId = vendorId3;
|
|
108174
108174
|
this.#paiKeyPair = paiKeyPair;
|
|
108175
108175
|
this.#paiKeyIdentifier = paiKeyIdentifier;
|
|
108176
108176
|
this.#paiCertBytes = this.generatePAICert(vendorId3);
|
|
108177
108177
|
}
|
|
108178
|
-
static async create(
|
|
108179
|
-
const key = await
|
|
108180
|
-
const identifier = Bytes.of(await
|
|
108181
|
-
return new _AttestationCertificateManager(
|
|
108178
|
+
static async create(crypto8, vendorId3) {
|
|
108179
|
+
const key = await crypto8.createKeyPair();
|
|
108180
|
+
const identifier = Bytes.of(await crypto8.computeHash(key.publicKey));
|
|
108181
|
+
return new _AttestationCertificateManager(crypto8, vendorId3, key, identifier.slice(0, 20));
|
|
108182
108182
|
}
|
|
108183
108183
|
getPAICert() {
|
|
108184
108184
|
return this.#paiCertBytes;
|
|
@@ -108324,11 +108324,11 @@ var init_CertificateAuthority = __esm({
|
|
|
108324
108324
|
get construction() {
|
|
108325
108325
|
return this.#construction;
|
|
108326
108326
|
}
|
|
108327
|
-
static async create(
|
|
108328
|
-
return asyncNew(_CertificateAuthority,
|
|
108327
|
+
static async create(crypto8, options, generateIntermediateCert) {
|
|
108328
|
+
return asyncNew(_CertificateAuthority, crypto8, options, generateIntermediateCert);
|
|
108329
108329
|
}
|
|
108330
|
-
constructor(
|
|
108331
|
-
this.#crypto =
|
|
108330
|
+
constructor(crypto8, options, generateIntermediateCert) {
|
|
108331
|
+
this.#crypto = crypto8;
|
|
108332
108332
|
this.#construction = Construction(this, async () => {
|
|
108333
108333
|
if (typeof options === "boolean") {
|
|
108334
108334
|
generateIntermediateCert = options;
|
|
@@ -108610,7 +108610,7 @@ var init_CertificationDeclaration = __esm({
|
|
|
108610
108610
|
* Generator which is the main usage for the class from outside.
|
|
108611
108611
|
* It constructs the class with the relevant details and returns a signed ASN.1 DER version of the CD.
|
|
108612
108612
|
*/
|
|
108613
|
-
static generate(
|
|
108613
|
+
static generate(crypto8, vendorId3, productId, provisional = false) {
|
|
108614
108614
|
const cd = new _CertificationDeclaration(
|
|
108615
108615
|
{
|
|
108616
108616
|
formatVersion: 1,
|
|
@@ -108626,7 +108626,7 @@ var init_CertificationDeclaration = __esm({
|
|
|
108626
108626
|
},
|
|
108627
108627
|
TestCMS_SignerSubjectKeyIdentifier
|
|
108628
108628
|
);
|
|
108629
|
-
return cd.asSignedAsn1(
|
|
108629
|
+
return cd.asSignedAsn1(crypto8, PrivateKey(TestCMS_SignerPrivateKey));
|
|
108630
108630
|
}
|
|
108631
108631
|
constructor(content, subjectKeyIdentifier) {
|
|
108632
108632
|
this.#eContent = CertificationDeclaration.TlvDc.encode(content);
|
|
@@ -108635,7 +108635,7 @@ var init_CertificationDeclaration = __esm({
|
|
|
108635
108635
|
/**
|
|
108636
108636
|
* Returns the signed certificate in ASN.1 DER format.
|
|
108637
108637
|
*/
|
|
108638
|
-
async asSignedAsn1(
|
|
108638
|
+
async asSignedAsn1(crypto8, privateKey) {
|
|
108639
108639
|
const cert = {
|
|
108640
108640
|
version: 3,
|
|
108641
108641
|
digestAlgorithm: [Shs.SHA256_CMS],
|
|
@@ -108646,7 +108646,7 @@ var init_CertificationDeclaration = __esm({
|
|
|
108646
108646
|
subjectKeyIdentifier: ContextTaggedBytes(0, this.#subjectKeyIdentifier),
|
|
108647
108647
|
digestAlgorithm: Shs.SHA256_CMS,
|
|
108648
108648
|
signatureAlgorithm: X962.EcdsaWithSHA256,
|
|
108649
|
-
signature: (await
|
|
108649
|
+
signature: (await crypto8.signEcdsa(privateKey, this.#eContent)).der
|
|
108650
108650
|
}
|
|
108651
108651
|
]
|
|
108652
108652
|
};
|
|
@@ -108684,8 +108684,8 @@ var init_DeviceCertification = __esm({
|
|
|
108684
108684
|
get declaration() {
|
|
108685
108685
|
return this.#assertInitialized().declaration;
|
|
108686
108686
|
}
|
|
108687
|
-
constructor(
|
|
108688
|
-
this.#crypto =
|
|
108687
|
+
constructor(crypto8, config10, product) {
|
|
108688
|
+
this.#crypto = crypto8;
|
|
108689
108689
|
let configProvider;
|
|
108690
108690
|
if (typeof config10 === "function") {
|
|
108691
108691
|
configProvider = config10;
|
|
@@ -108696,13 +108696,13 @@ var init_DeviceCertification = __esm({
|
|
|
108696
108696
|
if (product === void 0) {
|
|
108697
108697
|
throw new ImplementationError(`Cannot generate device certification without product information`);
|
|
108698
108698
|
}
|
|
108699
|
-
const paa = await AttestationCertificateManager.create(
|
|
108699
|
+
const paa = await AttestationCertificateManager.create(crypto8, product.vendorId);
|
|
108700
108700
|
const { keyPair: dacKeyPair, dac } = await paa.getDACert(product.productId);
|
|
108701
108701
|
return {
|
|
108702
108702
|
privateKey: PrivateKey(dacKeyPair.privateKey),
|
|
108703
108703
|
certificate: dac,
|
|
108704
108704
|
intermediateCertificate: await paa.getPAICert(),
|
|
108705
|
-
declaration: await CertificationDeclaration2.generate(
|
|
108705
|
+
declaration: await CertificationDeclaration2.generate(crypto8, product.vendorId, product.productId)
|
|
108706
108706
|
};
|
|
108707
108707
|
};
|
|
108708
108708
|
}
|
|
@@ -109493,8 +109493,8 @@ var init_OtaImageReader = __esm({
|
|
|
109493
109493
|
return reader.#headerData;
|
|
109494
109494
|
}
|
|
109495
109495
|
/** Read and validate the full OTA image file from the stream and returns the header data on success. */
|
|
109496
|
-
static async file(streamReader,
|
|
109497
|
-
const reader = new _OtaImageReader(streamReader,
|
|
109496
|
+
static async file(streamReader, crypto8, expectedTotalSize, options) {
|
|
109497
|
+
const reader = new _OtaImageReader(streamReader, crypto8);
|
|
109498
109498
|
if (options?.checksumType !== void 0) {
|
|
109499
109499
|
reader.#fullFileChecksumType = options.checksumType;
|
|
109500
109500
|
}
|
|
@@ -109528,8 +109528,8 @@ var init_OtaImageReader = __esm({
|
|
|
109528
109528
|
* Read and validate OTA file, extracting payload to a writable stream.
|
|
109529
109529
|
* Returns the header information after successful validation and extraction.
|
|
109530
109530
|
*/
|
|
109531
|
-
static async extractPayload(streamReader, payloadWriter,
|
|
109532
|
-
const reader = new _OtaImageReader(streamReader,
|
|
109531
|
+
static async extractPayload(streamReader, payloadWriter, crypto8, expectedTotalSize) {
|
|
109532
|
+
const reader = new _OtaImageReader(streamReader, crypto8);
|
|
109533
109533
|
const { remainingData } = await reader.#processHeader(false);
|
|
109534
109534
|
if (reader.#headerData === void 0) {
|
|
109535
109535
|
throw new InternalError("OTA header not read");
|
|
@@ -109545,9 +109545,9 @@ var init_OtaImageReader = __esm({
|
|
|
109545
109545
|
}
|
|
109546
109546
|
return reader.#headerData;
|
|
109547
109547
|
}
|
|
109548
|
-
constructor(streamReader,
|
|
109548
|
+
constructor(streamReader, crypto8) {
|
|
109549
109549
|
this.#streamReader = streamReader;
|
|
109550
|
-
this.#crypto =
|
|
109550
|
+
this.#crypto = crypto8;
|
|
109551
109551
|
}
|
|
109552
109552
|
get totalSize() {
|
|
109553
109553
|
return this.#totalSize;
|
|
@@ -125833,8 +125833,8 @@ var init_VendorIdVerification = __esm({
|
|
|
125833
125833
|
}
|
|
125834
125834
|
VendorIdVerification2.dataToSign = dataToSign;
|
|
125835
125835
|
async function verify(node, options) {
|
|
125836
|
-
const
|
|
125837
|
-
const clientChallenge =
|
|
125836
|
+
const crypto8 = node.env.get(Crypto);
|
|
125837
|
+
const clientChallenge = crypto8.randomBytes(32);
|
|
125838
125838
|
const {
|
|
125839
125839
|
fabric: { fabricIndex }
|
|
125840
125840
|
} = options;
|
|
@@ -125857,7 +125857,7 @@ var init_VendorIdVerification = __esm({
|
|
|
125857
125857
|
return void 0;
|
|
125858
125858
|
}
|
|
125859
125859
|
const { noc, rcac, fabric } = options;
|
|
125860
|
-
return await verifyData(
|
|
125860
|
+
return await verifyData(crypto8, {
|
|
125861
125861
|
clientChallenge,
|
|
125862
125862
|
attChallenge: session.attestationChallengeKey,
|
|
125863
125863
|
signVerificationResponse,
|
|
@@ -125867,7 +125867,7 @@ var init_VendorIdVerification = __esm({
|
|
|
125867
125867
|
});
|
|
125868
125868
|
}
|
|
125869
125869
|
VendorIdVerification2.verify = verify;
|
|
125870
|
-
async function verifyData(
|
|
125870
|
+
async function verifyData(crypto8, options) {
|
|
125871
125871
|
const {
|
|
125872
125872
|
clientChallenge,
|
|
125873
125873
|
attChallenge,
|
|
@@ -125893,14 +125893,14 @@ var init_VendorIdVerification = __esm({
|
|
|
125893
125893
|
}
|
|
125894
125894
|
}).signatureData;
|
|
125895
125895
|
try {
|
|
125896
|
-
await
|
|
125896
|
+
await crypto8.verifyEcdsa(PublicKey(rootPublicKey), tbs, new EcdsaSignature(signature));
|
|
125897
125897
|
const rootCert = Rcac.fromTlv(rcac);
|
|
125898
125898
|
const nocCert = Noc.fromTlv(noc);
|
|
125899
125899
|
const icaCert = icac ? Icac.fromTlv(icac) : void 0;
|
|
125900
125900
|
if (icaCert !== void 0) {
|
|
125901
|
-
await icaCert.verify(
|
|
125901
|
+
await icaCert.verify(crypto8, rootCert);
|
|
125902
125902
|
}
|
|
125903
|
-
await nocCert.verify(
|
|
125903
|
+
await nocCert.verify(crypto8, rootCert, icaCert);
|
|
125904
125904
|
} catch (error) {
|
|
125905
125905
|
CryptoError.accept(error);
|
|
125906
125906
|
logger103.error("Could not verify VendorId", error);
|
|
@@ -125930,13 +125930,13 @@ var init_VendorIdVerification = __esm({
|
|
|
125930
125930
|
`VVSC SubjectKeyIdentifier does not match signerSkid in VID Verification Statement`
|
|
125931
125931
|
);
|
|
125932
125932
|
}
|
|
125933
|
-
await vvscCert.verify(
|
|
125933
|
+
await vvscCert.verify(crypto8);
|
|
125934
125934
|
const ourStatement = createStatementBytes({
|
|
125935
125935
|
version: vidStatementVersion,
|
|
125936
125936
|
fabricBindingMessage: tbs,
|
|
125937
125937
|
signerSkid
|
|
125938
125938
|
});
|
|
125939
|
-
await
|
|
125939
|
+
await crypto8.verifyEcdsa(
|
|
125940
125940
|
PublicKey(ellipticCurvePublicKey),
|
|
125941
125941
|
ourStatement,
|
|
125942
125942
|
new EcdsaSignature(vidStatementSignature)
|
|
@@ -130205,8 +130205,8 @@ var init_OtaSoftwareUpdateProviderServer = __esm({
|
|
|
130205
130205
|
// the usual bdx session timeout is 5 minutes, so let's use this
|
|
130206
130206
|
};
|
|
130207
130207
|
}
|
|
130208
|
-
const
|
|
130209
|
-
const updateToken =
|
|
130208
|
+
const crypto8 = this.env.get(Crypto);
|
|
130209
|
+
const updateToken = crypto8.randomBytes(OTA_UPDATE_TOKEN_LENGTH_BYTES);
|
|
130210
130210
|
if (consentRequired && !request.requestorCanConsent) {
|
|
130211
130211
|
this.#updateInProgressDetails(peerAddress, updateToken, OtaUpdateStatus.WaitForConsent, newSoftwareVersion);
|
|
130212
130212
|
const { consentState, delayTime = Seconds(120) } = await this.requestUserConsentForUpdate(
|
|
@@ -132681,8 +132681,8 @@ var init_OtaSoftwareUpdateRequestorServer = __esm({
|
|
|
132681
132681
|
try {
|
|
132682
132682
|
const blob = await this.downloadLocation.openBlob();
|
|
132683
132683
|
totalSize = blob.size;
|
|
132684
|
-
const
|
|
132685
|
-
const header = await OtaImageReader.file(blob.stream().getReader(),
|
|
132684
|
+
const crypto8 = this.env.get(Crypto);
|
|
132685
|
+
const header = await OtaImageReader.file(blob.stream().getReader(), crypto8);
|
|
132686
132686
|
const { softwareVersion: otaFileSoftwareVersion } = header;
|
|
132687
132687
|
if (newSoftwareVersion === void 0) {
|
|
132688
132688
|
const { softwareVersion: currentSoftwareVersion } = this.#basicInformationState();
|
|
@@ -135998,11 +135998,11 @@ var init_Api = __esm({
|
|
|
135998
135998
|
}
|
|
135999
135999
|
Api2.resourceFor = resourceFor;
|
|
136000
136000
|
function log(level, facility, id, ...message) {
|
|
136001
|
-
let
|
|
136002
|
-
if (!
|
|
136003
|
-
loggers.set(facility,
|
|
136001
|
+
let logger204 = loggers.get(facility);
|
|
136002
|
+
if (!logger204) {
|
|
136003
|
+
loggers.set(facility, logger204 = Logger.get(facility));
|
|
136004
136004
|
}
|
|
136005
|
-
|
|
136005
|
+
logger204[level](Diagnostic.via(id || "(anon)"), message);
|
|
136006
136006
|
}
|
|
136007
136007
|
Api2.log = log;
|
|
136008
136008
|
function logRequest(facility, id, method, target) {
|
|
@@ -141853,9 +141853,9 @@ var init_ServerNetworkRuntime = __esm({
|
|
|
141853
141853
|
lifetime: this.construction,
|
|
141854
141854
|
...this.owner.state.commissioning.mdns
|
|
141855
141855
|
};
|
|
141856
|
-
const
|
|
141856
|
+
const crypto8 = this.owner.env.get(Crypto);
|
|
141857
141857
|
const { server } = this.#services.get(MdnsService);
|
|
141858
|
-
this.#mdnsAdvertiser = new MdnsAdvertiser(
|
|
141858
|
+
this.#mdnsAdvertiser = new MdnsAdvertiser(crypto8, server, { ...options, port });
|
|
141859
141859
|
}
|
|
141860
141860
|
return this.#mdnsAdvertiser;
|
|
141861
141861
|
}
|
|
@@ -145421,14 +145421,14 @@ function rootDirOf(env) {
|
|
|
145421
145421
|
function configureCrypto(env) {
|
|
145422
145422
|
Boot.init(() => {
|
|
145423
145423
|
if (env.vars.boolean("nodejs.crypto")) {
|
|
145424
|
-
let
|
|
145424
|
+
let crypto8;
|
|
145425
145425
|
if (!isBunjs()) {
|
|
145426
|
-
|
|
145426
|
+
crypto8 = new NodeJsCrypto();
|
|
145427
145427
|
} else {
|
|
145428
|
-
|
|
145428
|
+
crypto8 = new StandardCrypto(global.crypto);
|
|
145429
145429
|
}
|
|
145430
|
-
env.set(Entropy,
|
|
145431
|
-
env.set(Crypto,
|
|
145430
|
+
env.set(Entropy, crypto8);
|
|
145431
|
+
env.set(Crypto, crypto8);
|
|
145432
145432
|
return;
|
|
145433
145433
|
}
|
|
145434
145434
|
if (Environment.default.has(Entropy)) {
|
|
@@ -146411,6 +146411,7 @@ var init_vacuum = __esm({
|
|
|
146411
146411
|
VacuumDeviceFeature2[VacuumDeviceFeature2["MAP"] = 2048] = "MAP";
|
|
146412
146412
|
VacuumDeviceFeature2[VacuumDeviceFeature2["STATE"] = 4096] = "STATE";
|
|
146413
146413
|
VacuumDeviceFeature2[VacuumDeviceFeature2["START"] = 8192] = "START";
|
|
146414
|
+
VacuumDeviceFeature2[VacuumDeviceFeature2["CLEAN_AREA"] = 16384] = "CLEAN_AREA";
|
|
146414
146415
|
})(VacuumDeviceFeature || (VacuumDeviceFeature = {}));
|
|
146415
146416
|
(function(VacuumFanSpeed2) {
|
|
146416
146417
|
VacuumFanSpeed2["off"] = "off";
|
|
@@ -147220,10 +147221,10 @@ var init_home_assistant_actions = __esm({
|
|
|
147220
147221
|
circuitBreakerResetMs: 3e4
|
|
147221
147222
|
};
|
|
147222
147223
|
HomeAssistantActions = class extends Service {
|
|
147223
|
-
constructor(
|
|
147224
|
+
constructor(logger204, client, config10) {
|
|
147224
147225
|
super("HomeAssistantActions");
|
|
147225
147226
|
this.client = client;
|
|
147226
|
-
this.log =
|
|
147227
|
+
this.log = logger204.get(this);
|
|
147227
147228
|
this.config = { ...defaultConfig, ...config10 };
|
|
147228
147229
|
this.circuitBreaker = new CircuitBreaker(
|
|
147229
147230
|
this.config.circuitBreakerThreshold,
|
|
@@ -147566,7 +147567,7 @@ var DiagnosticService = class {
|
|
|
147566
147567
|
}
|
|
147567
147568
|
}
|
|
147568
147569
|
}
|
|
147569
|
-
const entities = this.collectEntities(bridge.aggregator);
|
|
147570
|
+
const entities = bridge.aggregator ? this.collectEntities(bridge.aggregator) : [];
|
|
147570
147571
|
return {
|
|
147571
147572
|
bridgeId: data.id,
|
|
147572
147573
|
bridgeName: data.name,
|
|
@@ -147595,10 +147596,10 @@ var DiagnosticService = class {
|
|
|
147595
147596
|
};
|
|
147596
147597
|
|
|
147597
147598
|
// src/api/access-log.ts
|
|
147598
|
-
function accessLogger(
|
|
147599
|
+
function accessLogger(logger204) {
|
|
147599
147600
|
return (req, res, next) => {
|
|
147600
147601
|
res.on("finish", () => {
|
|
147601
|
-
|
|
147602
|
+
logger204.debug(
|
|
147602
147603
|
`${req.method} ${decodeURI(req.originalUrl)} ${res.statusCode} ${res.statusMessage} from ${req.socket.remoteAddress}`
|
|
147603
147604
|
);
|
|
147604
147605
|
});
|
|
@@ -147765,6 +147766,7 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
|
|
|
147765
147766
|
disabled: config10.disabled,
|
|
147766
147767
|
filterLifeEntity: config10.filterLifeEntity,
|
|
147767
147768
|
cleaningModeEntity: config10.cleaningModeEntity,
|
|
147769
|
+
temperatureEntity: config10.temperatureEntity,
|
|
147768
147770
|
humidityEntity: config10.humidityEntity,
|
|
147769
147771
|
pressureEntity: config10.pressureEntity,
|
|
147770
147772
|
batteryEntity: config10.batteryEntity,
|
|
@@ -147773,7 +147775,9 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
|
|
|
147773
147775
|
powerEntity: config10.powerEntity,
|
|
147774
147776
|
energyEntity: config10.energyEntity,
|
|
147775
147777
|
suctionLevelEntity: config10.suctionLevelEntity,
|
|
147776
|
-
mopIntensityEntity: config10.mopIntensityEntity
|
|
147778
|
+
mopIntensityEntity: config10.mopIntensityEntity,
|
|
147779
|
+
valetudoIdentifier: config10.valetudoIdentifier,
|
|
147780
|
+
coverSwapOpenClose: config10.coverSwapOpenClose
|
|
147777
147781
|
});
|
|
147778
147782
|
mappingsRestored++;
|
|
147779
147783
|
}
|
|
@@ -148512,6 +148516,15 @@ function logsApi(_logger) {
|
|
|
148512
148516
|
}
|
|
148513
148517
|
|
|
148514
148518
|
// src/api/diagnostic-api.ts
|
|
148519
|
+
function endpointTreeNode(ep) {
|
|
148520
|
+
return {
|
|
148521
|
+
id: ep.id,
|
|
148522
|
+
endpoint: ep.number,
|
|
148523
|
+
deviceType: `0x${ep.type.deviceType.toString(16).padStart(4, "0")}`,
|
|
148524
|
+
deviceTypeName: ep.type.name,
|
|
148525
|
+
parts: [...ep.parts].map((p) => endpointTreeNode(p))
|
|
148526
|
+
};
|
|
148527
|
+
}
|
|
148515
148528
|
function detectEnvironment() {
|
|
148516
148529
|
if (process.env.SUPERVISOR_TOKEN || process.env.HASSIO_TOKEN) {
|
|
148517
148530
|
return "Home Assistant Add-on";
|
|
@@ -148586,7 +148599,14 @@ function diagnosticApi(bridgeService, haClient, haRegistry, version, startTime)
|
|
|
148586
148599
|
failedEntities: failedEntities.map((fe) => ({
|
|
148587
148600
|
entityId: anonymize ? anonymizeEntityId(fe.entityId) : fe.entityId,
|
|
148588
148601
|
reason: fe.reason
|
|
148589
|
-
}))
|
|
148602
|
+
})),
|
|
148603
|
+
endpointTree: (() => {
|
|
148604
|
+
try {
|
|
148605
|
+
return endpointTreeNode(b.server);
|
|
148606
|
+
} catch {
|
|
148607
|
+
return void 0;
|
|
148608
|
+
}
|
|
148609
|
+
})()
|
|
148590
148610
|
};
|
|
148591
148611
|
});
|
|
148592
148612
|
const recentLogs = logBuffer.entries.slice(-logLimit).map((entry) => ({
|
|
@@ -148658,6 +148678,7 @@ function entityMappingApi(mappingStorage) {
|
|
|
148658
148678
|
disabled: body.disabled,
|
|
148659
148679
|
filterLifeEntity: body.filterLifeEntity,
|
|
148660
148680
|
cleaningModeEntity: body.cleaningModeEntity,
|
|
148681
|
+
temperatureEntity: body.temperatureEntity,
|
|
148661
148682
|
humidityEntity: body.humidityEntity,
|
|
148662
148683
|
pressureEntity: body.pressureEntity,
|
|
148663
148684
|
batteryEntity: body.batteryEntity,
|
|
@@ -148668,7 +148689,10 @@ function entityMappingApi(mappingStorage) {
|
|
|
148668
148689
|
suctionLevelEntity: body.suctionLevelEntity,
|
|
148669
148690
|
mopIntensityEntity: body.mopIntensityEntity,
|
|
148670
148691
|
customServiceAreas: body.customServiceAreas,
|
|
148671
|
-
customFanSpeedTags: body.customFanSpeedTags
|
|
148692
|
+
customFanSpeedTags: body.customFanSpeedTags,
|
|
148693
|
+
valetudoIdentifier: body.valetudoIdentifier,
|
|
148694
|
+
coverSwapOpenClose: body.coverSwapOpenClose,
|
|
148695
|
+
composedEntities: body.composedEntities
|
|
148672
148696
|
};
|
|
148673
148697
|
const config10 = await mappingStorage.setMapping(request);
|
|
148674
148698
|
res.status(200).json(config10);
|
|
@@ -149118,6 +149142,7 @@ function configToProfileEntry(config10) {
|
|
|
149118
149142
|
disabled: config10.disabled,
|
|
149119
149143
|
filterLifeEntity: config10.filterLifeEntity,
|
|
149120
149144
|
cleaningModeEntity: config10.cleaningModeEntity,
|
|
149145
|
+
temperatureEntity: config10.temperatureEntity,
|
|
149121
149146
|
humidityEntity: config10.humidityEntity,
|
|
149122
149147
|
pressureEntity: config10.pressureEntity,
|
|
149123
149148
|
batteryEntity: config10.batteryEntity,
|
|
@@ -149128,7 +149153,9 @@ function configToProfileEntry(config10) {
|
|
|
149128
149153
|
suctionLevelEntity: config10.suctionLevelEntity,
|
|
149129
149154
|
mopIntensityEntity: config10.mopIntensityEntity,
|
|
149130
149155
|
customServiceAreas: config10.customServiceAreas,
|
|
149131
|
-
customFanSpeedTags: config10.customFanSpeedTags
|
|
149156
|
+
customFanSpeedTags: config10.customFanSpeedTags,
|
|
149157
|
+
valetudoIdentifier: config10.valetudoIdentifier,
|
|
149158
|
+
coverSwapOpenClose: config10.coverSwapOpenClose
|
|
149132
149159
|
};
|
|
149133
149160
|
}
|
|
149134
149161
|
function mappingProfileApi(mappingStorage) {
|
|
@@ -149236,6 +149263,7 @@ function mappingProfileApi(mappingStorage) {
|
|
|
149236
149263
|
disabled: entry.disabled,
|
|
149237
149264
|
filterLifeEntity: entry.filterLifeEntity,
|
|
149238
149265
|
cleaningModeEntity: entry.cleaningModeEntity,
|
|
149266
|
+
temperatureEntity: entry.temperatureEntity,
|
|
149239
149267
|
humidityEntity: entry.humidityEntity,
|
|
149240
149268
|
pressureEntity: entry.pressureEntity,
|
|
149241
149269
|
batteryEntity: entry.batteryEntity,
|
|
@@ -149246,7 +149274,9 @@ function mappingProfileApi(mappingStorage) {
|
|
|
149246
149274
|
suctionLevelEntity: entry.suctionLevelEntity,
|
|
149247
149275
|
mopIntensityEntity: entry.mopIntensityEntity,
|
|
149248
149276
|
customServiceAreas: entry.customServiceAreas,
|
|
149249
|
-
customFanSpeedTags: entry.customFanSpeedTags
|
|
149277
|
+
customFanSpeedTags: entry.customFanSpeedTags,
|
|
149278
|
+
valetudoIdentifier: entry.valetudoIdentifier,
|
|
149279
|
+
coverSwapOpenClose: entry.coverSwapOpenClose
|
|
149250
149280
|
});
|
|
149251
149281
|
applied++;
|
|
149252
149282
|
} catch (e) {
|
|
@@ -149283,6 +149313,9 @@ function testMatchers(matchers, device, entity, mode = "any", entityState, label
|
|
|
149283
149313
|
);
|
|
149284
149314
|
}
|
|
149285
149315
|
function testMatcher(matcher, device, entity, entityState, labels) {
|
|
149316
|
+
if (matcher.value == null) {
|
|
149317
|
+
return false;
|
|
149318
|
+
}
|
|
149286
149319
|
switch (matcher.type) {
|
|
149287
149320
|
case "domain":
|
|
149288
149321
|
return entity.entity_id.split(".")[0] === matcher.value;
|
|
@@ -151079,7 +151112,7 @@ var WebSocketApi = class {
|
|
|
151079
151112
|
|
|
151080
151113
|
// src/api/web-api.ts
|
|
151081
151114
|
var WebApi = class extends Service {
|
|
151082
|
-
constructor(
|
|
151115
|
+
constructor(logger204, bridgeService, haClient, haRegistry, bridgeStorage, mappingStorage, lockCredentialStorage, settingsStorage, backupService, props) {
|
|
151083
151116
|
super("WebApi");
|
|
151084
151117
|
this.bridgeService = bridgeService;
|
|
151085
151118
|
this.haClient = haClient;
|
|
@@ -151090,8 +151123,8 @@ var WebApi = class extends Service {
|
|
|
151090
151123
|
this.settingsStorage = settingsStorage;
|
|
151091
151124
|
this.backupService = backupService;
|
|
151092
151125
|
this.props = props;
|
|
151093
|
-
this.logger =
|
|
151094
|
-
this.log =
|
|
151126
|
+
this.logger = logger204;
|
|
151127
|
+
this.log = logger204.get(this);
|
|
151095
151128
|
this.accessLogger = accessLogger(this.log.createChild("Access Log"));
|
|
151096
151129
|
this.startTime = Date.now();
|
|
151097
151130
|
this.wsApi = new WebSocketApi(
|
|
@@ -151529,12 +151562,12 @@ var CustomStorage = class extends StorageBackendDisk {
|
|
|
151529
151562
|
|
|
151530
151563
|
// src/core/app/storage.ts
|
|
151531
151564
|
function storage(environment, options) {
|
|
151532
|
-
const
|
|
151565
|
+
const logger204 = environment.get(LoggerService).get("CustomStorage");
|
|
151533
151566
|
const location2 = resolveStorageLocation(options.location);
|
|
151534
151567
|
fs8.mkdirSync(location2, { recursive: true });
|
|
151535
151568
|
const storageService = environment.get(StorageService);
|
|
151536
151569
|
storageService.location = location2;
|
|
151537
|
-
storageService.factory = (ns) => new CustomStorage(
|
|
151570
|
+
storageService.factory = (ns) => new CustomStorage(logger204, path8.resolve(location2, ns));
|
|
151538
151571
|
}
|
|
151539
151572
|
function resolveStorageLocation(storageLocation) {
|
|
151540
151573
|
const homedir = os3.homedir();
|
|
@@ -151560,17 +151593,17 @@ import { createRequire } from "node:module";
|
|
|
151560
151593
|
import os4 from "node:os";
|
|
151561
151594
|
import path9 from "node:path";
|
|
151562
151595
|
function resolveAppVersion() {
|
|
151563
|
-
if (process.env.APP_VERSION) {
|
|
151564
|
-
return process.env.APP_VERSION;
|
|
151565
|
-
}
|
|
151566
151596
|
try {
|
|
151567
151597
|
const require2 = createRequire(import.meta.url);
|
|
151568
151598
|
const pkg = require2("home-assistant-matter-hub/package.json");
|
|
151569
|
-
if (pkg.version) {
|
|
151599
|
+
if (pkg.version && pkg.version !== "0.0.0") {
|
|
151570
151600
|
return pkg.version;
|
|
151571
151601
|
}
|
|
151572
151602
|
} catch {
|
|
151573
151603
|
}
|
|
151604
|
+
if (process.env.APP_VERSION) {
|
|
151605
|
+
return process.env.APP_VERSION;
|
|
151606
|
+
}
|
|
151574
151607
|
return "0.0.0-dev";
|
|
151575
151608
|
}
|
|
151576
151609
|
var Options = class {
|
|
@@ -151983,6 +152016,7 @@ var BridgeService = class extends Service {
|
|
|
151983
152016
|
for (const bridge of this.bridges) {
|
|
151984
152017
|
try {
|
|
151985
152018
|
await bridge.refreshDevices();
|
|
152019
|
+
this.onBridgeChanged?.(bridge.id);
|
|
151986
152020
|
} catch (e) {
|
|
151987
152021
|
this.log.error(`Failed to refresh bridge ${bridge.id}:`, e);
|
|
151988
152022
|
}
|
|
@@ -152083,10 +152117,10 @@ import {
|
|
|
152083
152117
|
getConfig
|
|
152084
152118
|
} from "home-assistant-js-websocket";
|
|
152085
152119
|
var HomeAssistantClient = class extends Service {
|
|
152086
|
-
constructor(
|
|
152120
|
+
constructor(logger204, options) {
|
|
152087
152121
|
super("HomeAssistantClient");
|
|
152088
152122
|
this.options = options;
|
|
152089
|
-
this.log =
|
|
152123
|
+
this.log = logger204.get(this);
|
|
152090
152124
|
}
|
|
152091
152125
|
static Options = /* @__PURE__ */ Symbol.for("HomeAssistantClientProps");
|
|
152092
152126
|
_connection;
|
|
@@ -152273,7 +152307,7 @@ var HomeAssistantRegistry = class extends Service {
|
|
|
152273
152307
|
try {
|
|
152274
152308
|
const changed = await this.reload();
|
|
152275
152309
|
if (changed) {
|
|
152276
|
-
onRefresh();
|
|
152310
|
+
await onRefresh();
|
|
152277
152311
|
}
|
|
152278
152312
|
} catch (e) {
|
|
152279
152313
|
logger145.warn("Failed to refresh registry, will retry next interval:", e);
|
|
@@ -152317,14 +152351,20 @@ var HomeAssistantRegistry = class extends Service {
|
|
|
152317
152351
|
const hash2 = createHash("md5");
|
|
152318
152352
|
for (const e of entityRegistry) {
|
|
152319
152353
|
hash2.update(
|
|
152320
|
-
`${e.entity_id}\0${e.device_id ?? ""}\0${e.disabled_by ?? ""}\0${e.hidden_by ?? ""}
|
|
152354
|
+
`${e.entity_id}\0${e.device_id ?? ""}\0${e.disabled_by ?? ""}\0${e.hidden_by ?? ""}\0${e.area_id ?? ""}\0${(e.labels ?? []).join(",")}\0${e.platform ?? ""}\0${e.entity_category ?? ""}
|
|
152321
152355
|
`
|
|
152322
152356
|
);
|
|
152323
152357
|
}
|
|
152324
|
-
for (const s of statesList)
|
|
152325
|
-
|
|
152326
|
-
for (const d of deviceRegistry) hash2.update(`${d.id}
|
|
152358
|
+
for (const s of statesList) {
|
|
152359
|
+
hash2.update(`${s.entity_id}\0${s.attributes?.device_class ?? ""}
|
|
152327
152360
|
`);
|
|
152361
|
+
}
|
|
152362
|
+
for (const d of deviceRegistry) {
|
|
152363
|
+
hash2.update(
|
|
152364
|
+
`${d.id}\0${(d.labels ?? []).join(",")}\0${d.area_id ?? ""}\0${d.name_by_user ?? ""}\0${d.name ?? ""}\0${d.model ?? ""}
|
|
152365
|
+
`
|
|
152366
|
+
);
|
|
152367
|
+
}
|
|
152328
152368
|
for (const l of labels) hash2.update(`${l.label_id}
|
|
152329
152369
|
`);
|
|
152330
152370
|
for (const a of areas) hash2.update(`${a.area_id}\0${a.name}
|
|
@@ -152658,6 +152698,7 @@ var EntityMappingStorage = class extends Service {
|
|
|
152658
152698
|
disabled: request.disabled,
|
|
152659
152699
|
filterLifeEntity: request.filterLifeEntity?.trim() || void 0,
|
|
152660
152700
|
cleaningModeEntity: request.cleaningModeEntity?.trim() || void 0,
|
|
152701
|
+
temperatureEntity: request.temperatureEntity?.trim() || void 0,
|
|
152661
152702
|
humidityEntity: request.humidityEntity?.trim() || void 0,
|
|
152662
152703
|
batteryEntity: request.batteryEntity?.trim() || void 0,
|
|
152663
152704
|
roomEntities: roomEntities.length > 0 ? roomEntities : void 0,
|
|
@@ -152670,9 +152711,12 @@ var EntityMappingStorage = class extends Service {
|
|
|
152670
152711
|
customServiceAreas: request.customServiceAreas?.filter(
|
|
152671
152712
|
(a) => a.name?.trim() && a.service?.trim()
|
|
152672
152713
|
) ?? void 0,
|
|
152673
|
-
customFanSpeedTags: request.customFanSpeedTags && Object.keys(request.customFanSpeedTags).length > 0 ? request.customFanSpeedTags : void 0
|
|
152714
|
+
customFanSpeedTags: request.customFanSpeedTags && Object.keys(request.customFanSpeedTags).length > 0 ? request.customFanSpeedTags : void 0,
|
|
152715
|
+
valetudoIdentifier: request.valetudoIdentifier?.trim() || void 0,
|
|
152716
|
+
coverSwapOpenClose: request.coverSwapOpenClose || void 0,
|
|
152717
|
+
composedEntities: request.composedEntities?.filter((e) => e.entityId?.trim()) ?? void 0
|
|
152674
152718
|
};
|
|
152675
|
-
if (!config10.matterDeviceType && !config10.customName && config10.disabled !== true && !config10.filterLifeEntity && !config10.cleaningModeEntity && !config10.humidityEntity && !config10.batteryEntity && !config10.roomEntities && !config10.disableLockPin && !config10.powerEntity && !config10.energyEntity && !config10.pressureEntity && !config10.suctionLevelEntity && !config10.mopIntensityEntity && (!config10.customServiceAreas || config10.customServiceAreas.length === 0) && (!config10.customFanSpeedTags || Object.keys(config10.customFanSpeedTags).length === 0)) {
|
|
152719
|
+
if (!config10.matterDeviceType && !config10.customName && config10.disabled !== true && !config10.filterLifeEntity && !config10.cleaningModeEntity && !config10.temperatureEntity && !config10.humidityEntity && !config10.batteryEntity && !config10.roomEntities && !config10.disableLockPin && !config10.powerEntity && !config10.energyEntity && !config10.pressureEntity && !config10.suctionLevelEntity && !config10.mopIntensityEntity && (!config10.customServiceAreas || config10.customServiceAreas.length === 0) && (!config10.customFanSpeedTags || Object.keys(config10.customFanSpeedTags).length === 0) && !config10.valetudoIdentifier && !config10.coverSwapOpenClose && (!config10.composedEntities || config10.composedEntities.length === 0)) {
|
|
152676
152720
|
bridgeMap.delete(request.entityId);
|
|
152677
152721
|
} else {
|
|
152678
152722
|
bridgeMap.set(request.entityId, config10);
|
|
@@ -159413,6 +159457,7 @@ var DimmablePlugInUnitDeviceDefinition = MutableEndpoint({
|
|
|
159413
159457
|
)
|
|
159414
159458
|
});
|
|
159415
159459
|
Object.freeze(DimmablePlugInUnitDeviceDefinition);
|
|
159460
|
+
var DimmablePlugInUnitDevice = DimmablePlugInUnitDeviceDefinition;
|
|
159416
159461
|
|
|
159417
159462
|
// ../../node_modules/.pnpm/@matter+node@0.16.10/node_modules/@matter/node/dist/esm/devices/dimmer-switch.js
|
|
159418
159463
|
init_IdentifyServer();
|
|
@@ -164692,10 +164737,6 @@ import * as path12 from "node:path";
|
|
|
164692
164737
|
// src/plugins/plugin-device-factory.ts
|
|
164693
164738
|
init_esm();
|
|
164694
164739
|
|
|
164695
|
-
// src/matter/behaviors/basic-information-server.ts
|
|
164696
|
-
init_esm7();
|
|
164697
|
-
import crypto4 from "node:crypto";
|
|
164698
|
-
|
|
164699
164740
|
// ../../node_modules/.pnpm/@matter+main@0.16.10/node_modules/@matter/main/dist/esm/behaviors.js
|
|
164700
164741
|
init_nodejs();
|
|
164701
164742
|
|
|
@@ -165653,6 +165694,65 @@ init_window_covering();
|
|
|
165653
165694
|
init_ClientBehavior();
|
|
165654
165695
|
var WindowCoveringClientConstructor = ClientBehavior(WindowCovering3.Complete);
|
|
165655
165696
|
|
|
165697
|
+
// src/matter/behaviors/identify-server.ts
|
|
165698
|
+
var IdentifyServer2 = class extends IdentifyServer {
|
|
165699
|
+
};
|
|
165700
|
+
|
|
165701
|
+
// src/matter/endpoints/validate-endpoint-type.ts
|
|
165702
|
+
init_esm();
|
|
165703
|
+
init_esm7();
|
|
165704
|
+
var logger158 = Logger.get("EndpointValidation");
|
|
165705
|
+
function toCamelCase(name) {
|
|
165706
|
+
return name.charAt(0).toLowerCase() + name.slice(1);
|
|
165707
|
+
}
|
|
165708
|
+
function validateEndpointType(endpointType, entityId) {
|
|
165709
|
+
const deviceTypeModel = Matter.deviceTypes.find(
|
|
165710
|
+
(dt) => dt.id === endpointType.deviceType
|
|
165711
|
+
);
|
|
165712
|
+
if (!deviceTypeModel) {
|
|
165713
|
+
return void 0;
|
|
165714
|
+
}
|
|
165715
|
+
const serverClusterReqs = deviceTypeModel.requirements.filter(
|
|
165716
|
+
(r) => r.element === "serverCluster"
|
|
165717
|
+
);
|
|
165718
|
+
const behaviorKeys = new Set(Object.keys(endpointType.behaviors));
|
|
165719
|
+
const missingMandatory = [];
|
|
165720
|
+
const availableOptional = [];
|
|
165721
|
+
const presentClusters = [];
|
|
165722
|
+
for (const req of serverClusterReqs) {
|
|
165723
|
+
const key = toCamelCase(req.name);
|
|
165724
|
+
if (behaviorKeys.has(key)) {
|
|
165725
|
+
presentClusters.push(req.name);
|
|
165726
|
+
} else if (req.isMandatory) {
|
|
165727
|
+
missingMandatory.push(req.name);
|
|
165728
|
+
} else {
|
|
165729
|
+
availableOptional.push(req.name);
|
|
165730
|
+
}
|
|
165731
|
+
}
|
|
165732
|
+
const prefix = entityId ? `[${entityId}] ` : "";
|
|
165733
|
+
if (missingMandatory.length > 0) {
|
|
165734
|
+
logger158.warn(
|
|
165735
|
+
`${prefix}${deviceTypeModel.name} (0x${endpointType.deviceType.toString(16)}): missing mandatory clusters: ${missingMandatory.join(", ")}`
|
|
165736
|
+
);
|
|
165737
|
+
}
|
|
165738
|
+
if (availableOptional.length > 0) {
|
|
165739
|
+
logger158.debug(
|
|
165740
|
+
`${prefix}${deviceTypeModel.name} (0x${endpointType.deviceType.toString(16)}): optional clusters not used: ${availableOptional.join(", ")}`
|
|
165741
|
+
);
|
|
165742
|
+
}
|
|
165743
|
+
return {
|
|
165744
|
+
deviceTypeName: deviceTypeModel.name,
|
|
165745
|
+
deviceTypeId: endpointType.deviceType,
|
|
165746
|
+
missingMandatory,
|
|
165747
|
+
availableOptional,
|
|
165748
|
+
presentClusters
|
|
165749
|
+
};
|
|
165750
|
+
}
|
|
165751
|
+
|
|
165752
|
+
// src/plugins/plugin-basic-information-server.ts
|
|
165753
|
+
init_esm7();
|
|
165754
|
+
import crypto4 from "node:crypto";
|
|
165755
|
+
|
|
165656
165756
|
// src/services/bridges/bridge-data-provider.ts
|
|
165657
165757
|
init_service();
|
|
165658
165758
|
import { values as values2 } from "lodash-es";
|
|
@@ -165741,7 +165841,7 @@ var BridgeDataProvider = class extends Service {
|
|
|
165741
165841
|
|
|
165742
165842
|
// src/utils/apply-patch-state.ts
|
|
165743
165843
|
init_esm();
|
|
165744
|
-
var
|
|
165844
|
+
var logger159 = Logger.get("ApplyPatchState");
|
|
165745
165845
|
function applyPatchState(state, patch, options) {
|
|
165746
165846
|
return applyPatch(state, patch, options?.force);
|
|
165747
165847
|
}
|
|
@@ -165768,23 +165868,23 @@ function applyPatch(state, patch, force = false) {
|
|
|
165768
165868
|
if (errorMessage.includes(
|
|
165769
165869
|
"Endpoint storage inaccessible because endpoint is not a node and is not owned by another endpoint"
|
|
165770
165870
|
)) {
|
|
165771
|
-
|
|
165871
|
+
logger159.debug(
|
|
165772
165872
|
`Suppressed endpoint storage error, patch not applied: ${JSON.stringify(actualPatch)}`
|
|
165773
165873
|
);
|
|
165774
165874
|
return actualPatch;
|
|
165775
165875
|
}
|
|
165776
165876
|
if (errorMessage.includes("synchronous-transaction-conflict")) {
|
|
165777
|
-
|
|
165877
|
+
logger159.warn(
|
|
165778
165878
|
`Transaction conflict, state update DROPPED: ${JSON.stringify(actualPatch)}`
|
|
165779
165879
|
);
|
|
165780
165880
|
return actualPatch;
|
|
165781
165881
|
}
|
|
165782
165882
|
failedKeys.push(key);
|
|
165783
|
-
|
|
165883
|
+
logger159.warn(`Failed to set property '${key}': ${errorMessage}`);
|
|
165784
165884
|
}
|
|
165785
165885
|
}
|
|
165786
165886
|
if (failedKeys.length > 0) {
|
|
165787
|
-
|
|
165887
|
+
logger159.warn(
|
|
165788
165888
|
`${failedKeys.length} properties failed to update: [${failedKeys.join(", ")}]`
|
|
165789
165889
|
);
|
|
165790
165890
|
}
|
|
@@ -165807,56 +165907,6 @@ function deepEqual(a, b) {
|
|
|
165807
165907
|
return a === b;
|
|
165808
165908
|
}
|
|
165809
165909
|
|
|
165810
|
-
// src/matter/behaviors/basic-information-server.ts
|
|
165811
|
-
init_home_assistant_entity_behavior();
|
|
165812
|
-
var BasicInformationServer2 = class extends BridgedDeviceBasicInformationServer {
|
|
165813
|
-
async initialize() {
|
|
165814
|
-
await super.initialize();
|
|
165815
|
-
const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
|
|
165816
|
-
this.update(homeAssistant.entity);
|
|
165817
|
-
this.reactTo(homeAssistant.onChange, this.update);
|
|
165818
|
-
}
|
|
165819
|
-
update(entity) {
|
|
165820
|
-
if (!entity.state) {
|
|
165821
|
-
return;
|
|
165822
|
-
}
|
|
165823
|
-
const { basicInformation } = this.env.get(BridgeDataProvider);
|
|
165824
|
-
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
165825
|
-
const device = entity.deviceRegistry;
|
|
165826
|
-
applyPatchState(this.state, {
|
|
165827
|
-
vendorId: VendorId(basicInformation.vendorId),
|
|
165828
|
-
vendorName: ellipse(32, device?.manufacturer) ?? hash(32, basicInformation.vendorName),
|
|
165829
|
-
productName: ellipse(32, device?.model_id) ?? ellipse(32, device?.model) ?? hash(32, basicInformation.productName),
|
|
165830
|
-
productLabel: ellipse(64, device?.model) ?? hash(64, basicInformation.productLabel),
|
|
165831
|
-
hardwareVersion: basicInformation.hardwareVersion,
|
|
165832
|
-
softwareVersion: basicInformation.softwareVersion,
|
|
165833
|
-
hardwareVersionString: ellipse(64, device?.hw_version),
|
|
165834
|
-
softwareVersionString: ellipse(64, device?.sw_version),
|
|
165835
|
-
nodeLabel: ellipse(32, homeAssistant.state.customName) ?? ellipse(32, entity.state?.attributes?.friendly_name) ?? ellipse(32, entity.entity_id),
|
|
165836
|
-
reachable: entity.state?.state != null && entity.state.state !== "unavailable",
|
|
165837
|
-
// The device serial number is available in `device?.serial_number`, but
|
|
165838
|
-
// we're keeping it as the entity ID for now to avoid breaking existing
|
|
165839
|
-
// deployments.
|
|
165840
|
-
serialNumber: hash(32, entity.entity_id),
|
|
165841
|
-
// UniqueId helps controllers (especially Alexa) identify devices across
|
|
165842
|
-
// multiple fabric connections. Using MD5 hash of entity_id for stability.
|
|
165843
|
-
uniqueId: crypto4.createHash("md5").update(entity.entity_id).digest("hex").substring(0, 32)
|
|
165844
|
-
});
|
|
165845
|
-
}
|
|
165846
|
-
};
|
|
165847
|
-
function ellipse(maxLength, value) {
|
|
165848
|
-
return trimToLength(value, maxLength, "...");
|
|
165849
|
-
}
|
|
165850
|
-
function hash(maxLength, value) {
|
|
165851
|
-
const hashLength = 4;
|
|
165852
|
-
const suffix = crypto4.createHash("md5").update(value ?? "").digest("hex").substring(0, hashLength);
|
|
165853
|
-
return trimToLength(value, maxLength, suffix);
|
|
165854
|
-
}
|
|
165855
|
-
|
|
165856
|
-
// src/matter/behaviors/identify-server.ts
|
|
165857
|
-
var IdentifyServer2 = class extends IdentifyServer {
|
|
165858
|
-
};
|
|
165859
|
-
|
|
165860
165910
|
// src/plugins/plugin-behavior.ts
|
|
165861
165911
|
init_esm7();
|
|
165862
165912
|
var PluginDeviceBehavior = class extends Behavior {
|
|
@@ -165880,72 +165930,142 @@ var PluginDeviceBehavior = class extends Behavior {
|
|
|
165880
165930
|
PluginDeviceBehavior2.Events = Events2;
|
|
165881
165931
|
})(PluginDeviceBehavior || (PluginDeviceBehavior = {}));
|
|
165882
165932
|
|
|
165933
|
+
// src/plugins/plugin-basic-information-server.ts
|
|
165934
|
+
var PluginBasicInformationServer = class extends BridgedDeviceBasicInformationServer {
|
|
165935
|
+
async initialize() {
|
|
165936
|
+
await super.initialize();
|
|
165937
|
+
const pluginDevice = this.agent.get(PluginDeviceBehavior);
|
|
165938
|
+
const device = pluginDevice.device;
|
|
165939
|
+
const { basicInformation } = this.env.get(BridgeDataProvider);
|
|
165940
|
+
applyPatchState(this.state, {
|
|
165941
|
+
vendorId: VendorId(basicInformation.vendorId),
|
|
165942
|
+
vendorName: truncate(32, pluginDevice.pluginName),
|
|
165943
|
+
productName: truncate(32, device.deviceType),
|
|
165944
|
+
nodeLabel: truncate(32, device.name),
|
|
165945
|
+
serialNumber: crypto4.createHash("md5").update(`plugin_${device.id}`).digest("hex").substring(0, 32),
|
|
165946
|
+
uniqueId: crypto4.createHash("md5").update(`plugin_${device.id}`).digest("hex").substring(0, 32),
|
|
165947
|
+
reachable: true
|
|
165948
|
+
});
|
|
165949
|
+
}
|
|
165950
|
+
};
|
|
165951
|
+
function truncate(maxLength, value) {
|
|
165952
|
+
if (value.length <= maxLength) return value;
|
|
165953
|
+
return `${value.substring(0, maxLength - 3)}...`;
|
|
165954
|
+
}
|
|
165955
|
+
|
|
165883
165956
|
// src/plugins/plugin-device-factory.ts
|
|
165884
|
-
var
|
|
165957
|
+
var logger160 = Logger.get("PluginDeviceFactory");
|
|
165885
165958
|
var deviceTypeMap = {
|
|
165886
165959
|
on_off_light: () => OnOffLightDevice.with(
|
|
165887
165960
|
IdentifyServer2,
|
|
165888
|
-
|
|
165961
|
+
PluginBasicInformationServer,
|
|
165889
165962
|
PluginDeviceBehavior
|
|
165890
165963
|
),
|
|
165891
165964
|
dimmable_light: () => DimmableLightDevice.with(
|
|
165892
165965
|
IdentifyServer2,
|
|
165893
|
-
|
|
165966
|
+
PluginBasicInformationServer,
|
|
165967
|
+
PluginDeviceBehavior
|
|
165968
|
+
),
|
|
165969
|
+
color_temperature_light: () => ColorTemperatureLightDevice.with(
|
|
165970
|
+
IdentifyServer2,
|
|
165971
|
+
PluginBasicInformationServer,
|
|
165972
|
+
PluginDeviceBehavior
|
|
165973
|
+
),
|
|
165974
|
+
extended_color_light: () => ExtendedColorLightDevice.with(
|
|
165975
|
+
IdentifyServer2,
|
|
165976
|
+
PluginBasicInformationServer,
|
|
165894
165977
|
PluginDeviceBehavior
|
|
165895
165978
|
),
|
|
165896
165979
|
on_off_plugin_unit: () => OnOffPlugInUnitDevice.with(
|
|
165897
165980
|
IdentifyServer2,
|
|
165898
|
-
|
|
165981
|
+
PluginBasicInformationServer,
|
|
165982
|
+
PluginDeviceBehavior
|
|
165983
|
+
),
|
|
165984
|
+
dimmable_plug_in_unit: () => DimmablePlugInUnitDevice.with(
|
|
165985
|
+
IdentifyServer2,
|
|
165986
|
+
PluginBasicInformationServer,
|
|
165899
165987
|
PluginDeviceBehavior
|
|
165900
165988
|
),
|
|
165901
165989
|
temperature_sensor: () => TemperatureSensorDevice.with(
|
|
165902
165990
|
IdentifyServer2,
|
|
165903
|
-
|
|
165991
|
+
PluginBasicInformationServer,
|
|
165904
165992
|
PluginDeviceBehavior
|
|
165905
165993
|
),
|
|
165906
165994
|
humidity_sensor: () => HumiditySensorDevice.with(
|
|
165907
165995
|
IdentifyServer2,
|
|
165908
|
-
|
|
165996
|
+
PluginBasicInformationServer,
|
|
165997
|
+
PluginDeviceBehavior
|
|
165998
|
+
),
|
|
165999
|
+
pressure_sensor: () => PressureSensorDevice.with(
|
|
166000
|
+
IdentifyServer2,
|
|
166001
|
+
PluginBasicInformationServer,
|
|
166002
|
+
PluginDeviceBehavior
|
|
166003
|
+
),
|
|
166004
|
+
flow_sensor: () => FlowSensorDevice.with(
|
|
166005
|
+
IdentifyServer2,
|
|
166006
|
+
PluginBasicInformationServer,
|
|
165909
166007
|
PluginDeviceBehavior
|
|
165910
166008
|
),
|
|
165911
166009
|
light_sensor: () => LightSensorDevice.with(
|
|
165912
166010
|
IdentifyServer2,
|
|
165913
|
-
|
|
166011
|
+
PluginBasicInformationServer,
|
|
165914
166012
|
PluginDeviceBehavior
|
|
165915
166013
|
),
|
|
165916
166014
|
occupancy_sensor: () => OccupancySensorDevice.with(
|
|
165917
166015
|
IdentifyServer2,
|
|
165918
|
-
|
|
166016
|
+
PluginBasicInformationServer,
|
|
165919
166017
|
PluginDeviceBehavior
|
|
165920
166018
|
),
|
|
165921
166019
|
contact_sensor: () => ContactSensorDevice.with(
|
|
165922
166020
|
IdentifyServer2,
|
|
165923
|
-
|
|
166021
|
+
PluginBasicInformationServer,
|
|
166022
|
+
PluginDeviceBehavior
|
|
166023
|
+
),
|
|
166024
|
+
air_quality_sensor: () => AirQualitySensorDevice.with(
|
|
166025
|
+
IdentifyServer2,
|
|
166026
|
+
PluginBasicInformationServer,
|
|
165924
166027
|
PluginDeviceBehavior
|
|
165925
166028
|
),
|
|
165926
166029
|
thermostat: () => ThermostatDevice.with(
|
|
165927
166030
|
IdentifyServer2,
|
|
165928
|
-
|
|
166031
|
+
PluginBasicInformationServer,
|
|
165929
166032
|
PluginDeviceBehavior
|
|
165930
166033
|
),
|
|
165931
166034
|
door_lock: () => DoorLockDevice.with(
|
|
165932
166035
|
IdentifyServer2,
|
|
165933
|
-
|
|
166036
|
+
PluginBasicInformationServer,
|
|
165934
166037
|
PluginDeviceBehavior
|
|
165935
166038
|
),
|
|
165936
166039
|
fan: () => FanDevice.with(
|
|
165937
166040
|
IdentifyServer2,
|
|
165938
|
-
|
|
166041
|
+
PluginBasicInformationServer,
|
|
166042
|
+
PluginDeviceBehavior
|
|
166043
|
+
),
|
|
166044
|
+
window_covering: () => WindowCoveringDevice.with(
|
|
166045
|
+
IdentifyServer2,
|
|
166046
|
+
PluginBasicInformationServer,
|
|
166047
|
+
PluginDeviceBehavior
|
|
166048
|
+
),
|
|
166049
|
+
generic_switch: () => GenericSwitchDevice.with(
|
|
166050
|
+
IdentifyServer2,
|
|
166051
|
+
PluginBasicInformationServer,
|
|
166052
|
+
PluginDeviceBehavior
|
|
166053
|
+
),
|
|
166054
|
+
water_leak_detector: () => WaterLeakDetectorDevice.with(
|
|
166055
|
+
IdentifyServer2,
|
|
166056
|
+
PluginBasicInformationServer,
|
|
165939
166057
|
PluginDeviceBehavior
|
|
165940
166058
|
)
|
|
165941
166059
|
};
|
|
165942
166060
|
function createPluginEndpointType(deviceType) {
|
|
165943
166061
|
const factory = deviceTypeMap[deviceType];
|
|
165944
166062
|
if (!factory) {
|
|
165945
|
-
|
|
166063
|
+
logger160.warn(`Unsupported plugin device type: "${deviceType}"`);
|
|
165946
166064
|
return void 0;
|
|
165947
166065
|
}
|
|
165948
|
-
|
|
166066
|
+
const endpoint = factory();
|
|
166067
|
+
validateEndpointType(endpoint, `plugin:${deviceType}`);
|
|
166068
|
+
return endpoint;
|
|
165949
166069
|
}
|
|
165950
166070
|
function getSupportedPluginDeviceTypes() {
|
|
165951
166071
|
return Object.keys(deviceTypeMap);
|
|
@@ -165955,11 +166075,13 @@ function getSupportedPluginDeviceTypes() {
|
|
|
165955
166075
|
init_esm();
|
|
165956
166076
|
import * as fs10 from "node:fs";
|
|
165957
166077
|
import * as path11 from "node:path";
|
|
165958
|
-
var
|
|
166078
|
+
var logger161 = Logger.get("PluginStorage");
|
|
166079
|
+
var SAVE_DEBOUNCE_MS = 500;
|
|
165959
166080
|
var FilePluginStorage = class {
|
|
165960
166081
|
data = {};
|
|
165961
166082
|
dirty = false;
|
|
165962
166083
|
filePath;
|
|
166084
|
+
saveTimer;
|
|
165963
166085
|
constructor(storageDir, pluginName) {
|
|
165964
166086
|
const safePluginName = pluginName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
165965
166087
|
this.filePath = path11.join(storageDir, `plugin-${safePluginName}.json`);
|
|
@@ -165972,12 +166094,12 @@ var FilePluginStorage = class {
|
|
|
165972
166094
|
async set(key, value) {
|
|
165973
166095
|
this.data[key] = value;
|
|
165974
166096
|
this.dirty = true;
|
|
165975
|
-
this.
|
|
166097
|
+
this.scheduleSave();
|
|
165976
166098
|
}
|
|
165977
166099
|
async delete(key) {
|
|
165978
166100
|
delete this.data[key];
|
|
165979
166101
|
this.dirty = true;
|
|
165980
|
-
this.
|
|
166102
|
+
this.scheduleSave();
|
|
165981
166103
|
}
|
|
165982
166104
|
async keys() {
|
|
165983
166105
|
return Object.keys(this.data);
|
|
@@ -165989,12 +166111,20 @@ var FilePluginStorage = class {
|
|
|
165989
166111
|
this.data = JSON.parse(raw);
|
|
165990
166112
|
}
|
|
165991
166113
|
} catch (e) {
|
|
165992
|
-
|
|
166114
|
+
logger161.warn(`Failed to load plugin storage from ${this.filePath}:`, e);
|
|
165993
166115
|
this.data = {};
|
|
165994
166116
|
}
|
|
165995
166117
|
}
|
|
166118
|
+
scheduleSave() {
|
|
166119
|
+
if (this.saveTimer) clearTimeout(this.saveTimer);
|
|
166120
|
+
this.saveTimer = setTimeout(() => this.save(), SAVE_DEBOUNCE_MS);
|
|
166121
|
+
}
|
|
165996
166122
|
save() {
|
|
165997
166123
|
if (!this.dirty) return;
|
|
166124
|
+
if (this.saveTimer) {
|
|
166125
|
+
clearTimeout(this.saveTimer);
|
|
166126
|
+
this.saveTimer = void 0;
|
|
166127
|
+
}
|
|
165998
166128
|
try {
|
|
165999
166129
|
const dir = path11.dirname(this.filePath);
|
|
166000
166130
|
if (!fs10.existsSync(dir)) {
|
|
@@ -166003,14 +166133,17 @@ var FilePluginStorage = class {
|
|
|
166003
166133
|
fs10.writeFileSync(this.filePath, JSON.stringify(this.data, null, 2));
|
|
166004
166134
|
this.dirty = false;
|
|
166005
166135
|
} catch (e) {
|
|
166006
|
-
|
|
166136
|
+
logger161.warn(`Failed to save plugin storage to ${this.filePath}:`, e);
|
|
166007
166137
|
}
|
|
166008
166138
|
}
|
|
166139
|
+
flush() {
|
|
166140
|
+
this.save();
|
|
166141
|
+
}
|
|
166009
166142
|
};
|
|
166010
166143
|
|
|
166011
166144
|
// src/plugins/safe-plugin-runner.ts
|
|
166012
166145
|
init_esm();
|
|
166013
|
-
var
|
|
166146
|
+
var logger162 = Logger.get("SafePluginRunner");
|
|
166014
166147
|
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
166015
166148
|
var CIRCUIT_BREAKER_THRESHOLD = 3;
|
|
166016
166149
|
var SafePluginRunner = class {
|
|
@@ -166043,7 +166176,7 @@ var SafePluginRunner = class {
|
|
|
166043
166176
|
async run(pluginName, operation, fn, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
166044
166177
|
const state = this.getState(pluginName);
|
|
166045
166178
|
if (state.disabled) {
|
|
166046
|
-
|
|
166179
|
+
logger162.debug(
|
|
166047
166180
|
`Plugin "${pluginName}" is disabled (circuit breaker open), skipping ${operation}`
|
|
166048
166181
|
);
|
|
166049
166182
|
return void 0;
|
|
@@ -166061,13 +166194,13 @@ var SafePluginRunner = class {
|
|
|
166061
166194
|
timeout.clear();
|
|
166062
166195
|
state.failures++;
|
|
166063
166196
|
state.lastError = error instanceof Error ? error.message : String(error);
|
|
166064
|
-
|
|
166197
|
+
logger162.error(
|
|
166065
166198
|
`Plugin "${pluginName}" failed during ${operation} (failure ${state.failures}/${CIRCUIT_BREAKER_THRESHOLD}): ${state.lastError}`
|
|
166066
166199
|
);
|
|
166067
166200
|
if (state.failures >= CIRCUIT_BREAKER_THRESHOLD) {
|
|
166068
166201
|
state.disabled = true;
|
|
166069
166202
|
state.disabledAt = Date.now();
|
|
166070
|
-
|
|
166203
|
+
logger162.error(
|
|
166071
166204
|
`Plugin "${pluginName}" DISABLED after ${CIRCUIT_BREAKER_THRESHOLD} consecutive failures. Last error: ${state.lastError}`
|
|
166072
166205
|
);
|
|
166073
166206
|
}
|
|
@@ -166089,13 +166222,13 @@ var SafePluginRunner = class {
|
|
|
166089
166222
|
} catch (error) {
|
|
166090
166223
|
state.failures++;
|
|
166091
166224
|
state.lastError = error instanceof Error ? error.message : String(error);
|
|
166092
|
-
|
|
166225
|
+
logger162.error(
|
|
166093
166226
|
`Plugin "${pluginName}" failed during ${operation} (sync, failure ${state.failures}/${CIRCUIT_BREAKER_THRESHOLD}): ${state.lastError}`
|
|
166094
166227
|
);
|
|
166095
166228
|
if (state.failures >= CIRCUIT_BREAKER_THRESHOLD) {
|
|
166096
166229
|
state.disabled = true;
|
|
166097
166230
|
state.disabledAt = Date.now();
|
|
166098
|
-
|
|
166231
|
+
logger162.error(
|
|
166099
166232
|
`Plugin "${pluginName}" DISABLED after ${CIRCUIT_BREAKER_THRESHOLD} consecutive failures.`
|
|
166100
166233
|
);
|
|
166101
166234
|
}
|
|
@@ -166121,12 +166254,16 @@ var SafePluginRunner = class {
|
|
|
166121
166254
|
};
|
|
166122
166255
|
|
|
166123
166256
|
// src/plugins/plugin-manager.ts
|
|
166124
|
-
var
|
|
166257
|
+
var logger163 = Logger.get("PluginManager");
|
|
166258
|
+
var PLUGIN_API_VERSION = 1;
|
|
166259
|
+
var MAX_PLUGIN_DEVICE_ID_LENGTH = 100;
|
|
166125
166260
|
function validatePluginDevice(device) {
|
|
166126
166261
|
if (!device || typeof device !== "object") return "device must be an object";
|
|
166127
166262
|
const d = device;
|
|
166128
166263
|
if (!d.id || typeof d.id !== "string")
|
|
166129
166264
|
return "device.id must be a non-empty string";
|
|
166265
|
+
if (d.id.length > MAX_PLUGIN_DEVICE_ID_LENGTH)
|
|
166266
|
+
return `device.id too long (${d.id.length} chars, max ${MAX_PLUGIN_DEVICE_ID_LENGTH})`;
|
|
166130
166267
|
if (!d.name || typeof d.name !== "string")
|
|
166131
166268
|
return "device.name must be a non-empty string";
|
|
166132
166269
|
if (!d.deviceType || typeof d.deviceType !== "string")
|
|
@@ -166146,6 +166283,7 @@ function validatePluginDevice(device) {
|
|
|
166146
166283
|
}
|
|
166147
166284
|
var PluginManager = class {
|
|
166148
166285
|
instances = /* @__PURE__ */ new Map();
|
|
166286
|
+
domainMappings = /* @__PURE__ */ new Map();
|
|
166149
166287
|
storageDir;
|
|
166150
166288
|
bridgeId;
|
|
166151
166289
|
runner = new SafePluginRunner();
|
|
@@ -166193,6 +166331,11 @@ var PluginManager = class {
|
|
|
166193
166331
|
if (!manifest.main || typeof manifest.main !== "string") {
|
|
166194
166332
|
throw new Error(`Plugin at ${packagePath} package.json missing "main"`);
|
|
166195
166333
|
}
|
|
166334
|
+
if (manifest.hamhPluginApiVersion != null && manifest.hamhPluginApiVersion !== PLUGIN_API_VERSION) {
|
|
166335
|
+
logger163.warn(
|
|
166336
|
+
`Plugin "${manifest.name}" declares API version ${manifest.hamhPluginApiVersion}, current is ${PLUGIN_API_VERSION}. It may not work correctly.`
|
|
166337
|
+
);
|
|
166338
|
+
}
|
|
166196
166339
|
const module = await this.runner.run(
|
|
166197
166340
|
manifest.name,
|
|
166198
166341
|
"import",
|
|
@@ -166220,7 +166363,7 @@ var PluginManager = class {
|
|
|
166220
166363
|
};
|
|
166221
166364
|
await this.register(plugin, metadata);
|
|
166222
166365
|
} catch (e) {
|
|
166223
|
-
|
|
166366
|
+
logger163.error(`Failed to load external plugin from ${packagePath}:`, e);
|
|
166224
166367
|
throw e;
|
|
166225
166368
|
}
|
|
166226
166369
|
}
|
|
@@ -166272,6 +166415,21 @@ var PluginManager = class {
|
|
|
166272
166415
|
clusterId3,
|
|
166273
166416
|
attributes7
|
|
166274
166417
|
);
|
|
166418
|
+
},
|
|
166419
|
+
registerDomainMapping: (mapping) => {
|
|
166420
|
+
if (!mapping.domain || typeof mapping.domain !== "string" || !mapping.matterDeviceType || typeof mapping.matterDeviceType !== "string") {
|
|
166421
|
+
pluginLogger.warn("Invalid domain mapping, skipping");
|
|
166422
|
+
return;
|
|
166423
|
+
}
|
|
166424
|
+
if (this.domainMappings.has(mapping.domain)) {
|
|
166425
|
+
pluginLogger.warn(
|
|
166426
|
+
`Domain "${mapping.domain}" already mapped by another plugin, overwriting`
|
|
166427
|
+
);
|
|
166428
|
+
}
|
|
166429
|
+
this.domainMappings.set(mapping.domain, mapping);
|
|
166430
|
+
pluginLogger.info(
|
|
166431
|
+
`Registered domain mapping: ${mapping.domain} \u2192 ${mapping.matterDeviceType}`
|
|
166432
|
+
);
|
|
166275
166433
|
}
|
|
166276
166434
|
};
|
|
166277
166435
|
this.instances.set(plugin.name, {
|
|
@@ -166281,7 +166439,7 @@ var PluginManager = class {
|
|
|
166281
166439
|
devices,
|
|
166282
166440
|
started: false
|
|
166283
166441
|
});
|
|
166284
|
-
|
|
166442
|
+
logger163.info(
|
|
166285
166443
|
`Registered plugin: ${plugin.name} v${plugin.version} (${metadata.source})`
|
|
166286
166444
|
);
|
|
166287
166445
|
}
|
|
@@ -166292,13 +166450,13 @@ var PluginManager = class {
|
|
|
166292
166450
|
for (const [name, instance] of this.instances) {
|
|
166293
166451
|
if (!instance.metadata.enabled) continue;
|
|
166294
166452
|
if (this.runner.isDisabled(name)) {
|
|
166295
|
-
|
|
166453
|
+
logger163.warn(
|
|
166296
166454
|
`Plugin "${name}" is disabled (circuit breaker), skipping start`
|
|
166297
166455
|
);
|
|
166298
166456
|
instance.metadata.enabled = false;
|
|
166299
166457
|
continue;
|
|
166300
166458
|
}
|
|
166301
|
-
|
|
166459
|
+
logger163.info(`Starting plugin: ${name}`);
|
|
166302
166460
|
await this.runner.run(
|
|
166303
166461
|
name,
|
|
166304
166462
|
"onStart",
|
|
@@ -166341,8 +166499,12 @@ var PluginManager = class {
|
|
|
166341
166499
|
() => instance.plugin.onShutdown(reason)
|
|
166342
166500
|
);
|
|
166343
166501
|
}
|
|
166502
|
+
const storage2 = instance.context.storage;
|
|
166503
|
+
if (storage2 instanceof FilePluginStorage) {
|
|
166504
|
+
storage2.flush();
|
|
166505
|
+
}
|
|
166344
166506
|
instance.started = false;
|
|
166345
|
-
|
|
166507
|
+
logger163.info(`Plugin "${name}" shut down`);
|
|
166346
166508
|
}
|
|
166347
166509
|
this.instances.clear();
|
|
166348
166510
|
}
|
|
@@ -166393,6 +166555,9 @@ var PluginManager = class {
|
|
|
166393
166555
|
if (!instance) return void 0;
|
|
166394
166556
|
return instance.plugin.getConfigSchema?.();
|
|
166395
166557
|
}
|
|
166558
|
+
getDomainMappings() {
|
|
166559
|
+
return new Map(this.domainMappings);
|
|
166560
|
+
}
|
|
166396
166561
|
async updateConfig(pluginName, config10) {
|
|
166397
166562
|
const instance = this.instances.get(pluginName);
|
|
166398
166563
|
if (!instance) return false;
|
|
@@ -166738,11 +166903,12 @@ function ensureCommissioningConfig(server) {
|
|
|
166738
166903
|
|
|
166739
166904
|
// src/services/bridges/bridge.ts
|
|
166740
166905
|
var AUTO_FORCE_SYNC_INTERVAL_MS = 9e4;
|
|
166906
|
+
var DEAD_SESSION_TIMEOUT_MS = 6e4;
|
|
166741
166907
|
var Bridge = class {
|
|
166742
|
-
constructor(env,
|
|
166908
|
+
constructor(env, logger204, dataProvider, endpointManager) {
|
|
166743
166909
|
this.dataProvider = dataProvider;
|
|
166744
166910
|
this.endpointManager = endpointManager;
|
|
166745
|
-
this.log =
|
|
166911
|
+
this.log = logger204.get(`Bridge / ${dataProvider.id}`);
|
|
166746
166912
|
this.server = new BridgeServerNode(
|
|
166747
166913
|
env,
|
|
166748
166914
|
this.dataProvider,
|
|
@@ -166760,6 +166926,8 @@ var Bridge = class {
|
|
|
166760
166926
|
// (e.g. Stopped → Starting → Running).
|
|
166761
166927
|
onStatusChange;
|
|
166762
166928
|
autoForceSyncTimer = null;
|
|
166929
|
+
deadSessionTimer = null;
|
|
166930
|
+
staleSessionTimers = /* @__PURE__ */ new Map();
|
|
166763
166931
|
// Tracks the last synced state JSON per entity to avoid pushing unchanged states.
|
|
166764
166932
|
// Key: entity_id, Value: JSON.stringify of entity.state
|
|
166765
166933
|
lastSyncedStates = /* @__PURE__ */ new Map();
|
|
@@ -166936,6 +167104,33 @@ ${e?.toString()}`);
|
|
|
166936
167104
|
this.log.warn(
|
|
166937
167105
|
`All subscriptions lost \u2014 ${sessions.length} session(s) still active, waiting for controller to re-subscribe`
|
|
166938
167106
|
);
|
|
167107
|
+
if (!this.deadSessionTimer) {
|
|
167108
|
+
this.deadSessionTimer = setTimeout(() => {
|
|
167109
|
+
this.deadSessionTimer = null;
|
|
167110
|
+
this.closeDeadSessions();
|
|
167111
|
+
}, DEAD_SESSION_TIMEOUT_MS);
|
|
167112
|
+
this.log.info(
|
|
167113
|
+
`Scheduled dead session cleanup in ${DEAD_SESSION_TIMEOUT_MS / 1e3}s`
|
|
167114
|
+
);
|
|
167115
|
+
}
|
|
167116
|
+
} else if (totalSubs > 0 && this.deadSessionTimer) {
|
|
167117
|
+
clearTimeout(this.deadSessionTimer);
|
|
167118
|
+
this.deadSessionTimer = null;
|
|
167119
|
+
this.log.info(
|
|
167120
|
+
"Subscriptions recovered, canceled dead session cleanup"
|
|
167121
|
+
);
|
|
167122
|
+
}
|
|
167123
|
+
if (session.subscriptions.size === 0 && !this.staleSessionTimers.has(session.id)) {
|
|
167124
|
+
this.staleSessionTimers.set(
|
|
167125
|
+
session.id,
|
|
167126
|
+
setTimeout(() => {
|
|
167127
|
+
this.staleSessionTimers.delete(session.id);
|
|
167128
|
+
this.closeStaleSession(session.id);
|
|
167129
|
+
}, DEAD_SESSION_TIMEOUT_MS)
|
|
167130
|
+
);
|
|
167131
|
+
} else if (session.subscriptions.size > 0 && this.staleSessionTimers.has(session.id)) {
|
|
167132
|
+
clearTimeout(this.staleSessionTimers.get(session.id));
|
|
167133
|
+
this.staleSessionTimers.delete(session.id);
|
|
166939
167134
|
}
|
|
166940
167135
|
};
|
|
166941
167136
|
sessionManager.subscriptionsChanged.on(this.sessionDiagHandler);
|
|
@@ -166964,6 +167159,62 @@ ${e?.toString()}`);
|
|
|
166964
167159
|
} catch {
|
|
166965
167160
|
}
|
|
166966
167161
|
}
|
|
167162
|
+
closeStaleSession(sessionId) {
|
|
167163
|
+
try {
|
|
167164
|
+
const sessionManager = this.server.env.get(SessionManager);
|
|
167165
|
+
for (const s of [...sessionManager.sessions]) {
|
|
167166
|
+
if (s.id === sessionId && !s.isClosing && s.subscriptions.size === 0) {
|
|
167167
|
+
this.log.warn(
|
|
167168
|
+
`Closing stale session ${s.id} (peer ${s.peerNodeId}, no subscriptions for ${DEAD_SESSION_TIMEOUT_MS / 1e3}s)`
|
|
167169
|
+
);
|
|
167170
|
+
s.initiateClose().catch(() => {
|
|
167171
|
+
return s.initiateForceClose();
|
|
167172
|
+
}).catch(() => {
|
|
167173
|
+
}).finally(() => this.triggerMdnsReAnnounce());
|
|
167174
|
+
break;
|
|
167175
|
+
}
|
|
167176
|
+
}
|
|
167177
|
+
} catch {
|
|
167178
|
+
}
|
|
167179
|
+
}
|
|
167180
|
+
closeDeadSessions() {
|
|
167181
|
+
try {
|
|
167182
|
+
const sessionManager = this.server.env.get(SessionManager);
|
|
167183
|
+
const sessions = [...sessionManager.sessions];
|
|
167184
|
+
const closes = [];
|
|
167185
|
+
for (const s of sessions) {
|
|
167186
|
+
if (!s.isClosing && s.subscriptions.size === 0) {
|
|
167187
|
+
this.log.warn(
|
|
167188
|
+
`Closing dead session ${s.id} (peer ${s.peerNodeId}, no subscriptions for ${DEAD_SESSION_TIMEOUT_MS / 1e3}s)`
|
|
167189
|
+
);
|
|
167190
|
+
closes.push(
|
|
167191
|
+
s.initiateClose().catch(() => {
|
|
167192
|
+
return s.initiateForceClose();
|
|
167193
|
+
})
|
|
167194
|
+
);
|
|
167195
|
+
}
|
|
167196
|
+
}
|
|
167197
|
+
if (closes.length > 0) {
|
|
167198
|
+
Promise.allSettled(closes).then(() => this.triggerMdnsReAnnounce());
|
|
167199
|
+
}
|
|
167200
|
+
} catch {
|
|
167201
|
+
}
|
|
167202
|
+
}
|
|
167203
|
+
/**
|
|
167204
|
+
* Force a fresh mDNS operational advertisement after session cleanup.
|
|
167205
|
+
* matter.js DeviceAdvertiser only re-announces when a subscription is
|
|
167206
|
+
* canceled BY THE PEER. When the server cancels after 3 delivery
|
|
167207
|
+
* timeouts, no re-announcement happens and the controller may not
|
|
167208
|
+
* realize it should reconnect (#266).
|
|
167209
|
+
*/
|
|
167210
|
+
triggerMdnsReAnnounce() {
|
|
167211
|
+
try {
|
|
167212
|
+
const advertiser = this.server.env.get(DeviceAdvertiser);
|
|
167213
|
+
advertiser.restartAdvertisement();
|
|
167214
|
+
this.log.info("Triggered mDNS re-announcement after session cleanup");
|
|
167215
|
+
} catch {
|
|
167216
|
+
}
|
|
167217
|
+
}
|
|
166967
167218
|
unwireSessionDiagnostics() {
|
|
166968
167219
|
try {
|
|
166969
167220
|
const sessionManager = this.server.env.get(SessionManager);
|
|
@@ -166981,6 +167232,14 @@ ${e?.toString()}`);
|
|
|
166981
167232
|
this.sessionDiagHandler = void 0;
|
|
166982
167233
|
this.sessionAddedHandler = void 0;
|
|
166983
167234
|
this.sessionDeletedHandler = void 0;
|
|
167235
|
+
if (this.deadSessionTimer) {
|
|
167236
|
+
clearTimeout(this.deadSessionTimer);
|
|
167237
|
+
this.deadSessionTimer = null;
|
|
167238
|
+
}
|
|
167239
|
+
for (const timer of this.staleSessionTimers.values()) {
|
|
167240
|
+
clearTimeout(timer);
|
|
167241
|
+
}
|
|
167242
|
+
this.staleSessionTimers.clear();
|
|
166984
167243
|
}
|
|
166985
167244
|
stopAutoForceSync() {
|
|
166986
167245
|
if (this.autoForceSyncTimer) {
|
|
@@ -167114,7 +167373,7 @@ var AggregatorEndpoint2 = class extends Endpoint {
|
|
|
167114
167373
|
init_dist();
|
|
167115
167374
|
init_esm();
|
|
167116
167375
|
init_home_assistant_entity_behavior();
|
|
167117
|
-
import
|
|
167376
|
+
import debounce5 from "debounce";
|
|
167118
167377
|
|
|
167119
167378
|
// src/matter/endpoints/entity-endpoint.ts
|
|
167120
167379
|
init_esm7();
|
|
@@ -167148,6 +167407,7 @@ function getMappedEntityIds(mapping) {
|
|
|
167148
167407
|
if (!mapping) return [];
|
|
167149
167408
|
const ids = [];
|
|
167150
167409
|
if (mapping.batteryEntity) ids.push(mapping.batteryEntity);
|
|
167410
|
+
if (mapping.temperatureEntity) ids.push(mapping.temperatureEntity);
|
|
167151
167411
|
if (mapping.humidityEntity) ids.push(mapping.humidityEntity);
|
|
167152
167412
|
if (mapping.pressureEntity) ids.push(mapping.pressureEntity);
|
|
167153
167413
|
if (mapping.cleaningModeEntity) ids.push(mapping.cleaningModeEntity);
|
|
@@ -167156,6 +167416,11 @@ function getMappedEntityIds(mapping) {
|
|
|
167156
167416
|
if (mapping.filterLifeEntity) ids.push(mapping.filterLifeEntity);
|
|
167157
167417
|
if (mapping.powerEntity) ids.push(mapping.powerEntity);
|
|
167158
167418
|
if (mapping.energyEntity) ids.push(mapping.energyEntity);
|
|
167419
|
+
if (mapping.composedEntities) {
|
|
167420
|
+
for (const sub of mapping.composedEntities) {
|
|
167421
|
+
if (sub.entityId) ids.push(sub.entityId);
|
|
167422
|
+
}
|
|
167423
|
+
}
|
|
167159
167424
|
return ids;
|
|
167160
167425
|
}
|
|
167161
167426
|
|
|
@@ -167304,13 +167569,61 @@ function testBit(value, bitValue) {
|
|
|
167304
167569
|
return !!(value & bitValue);
|
|
167305
167570
|
}
|
|
167306
167571
|
|
|
167572
|
+
// src/matter/behaviors/basic-information-server.ts
|
|
167573
|
+
init_esm7();
|
|
167574
|
+
import crypto6 from "node:crypto";
|
|
167575
|
+
init_home_assistant_entity_behavior();
|
|
167576
|
+
var BasicInformationServer2 = class extends BridgedDeviceBasicInformationServer {
|
|
167577
|
+
async initialize() {
|
|
167578
|
+
await super.initialize();
|
|
167579
|
+
const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
|
|
167580
|
+
this.update(homeAssistant.entity);
|
|
167581
|
+
this.reactTo(homeAssistant.onChange, this.update);
|
|
167582
|
+
}
|
|
167583
|
+
update(entity) {
|
|
167584
|
+
if (!entity.state) {
|
|
167585
|
+
return;
|
|
167586
|
+
}
|
|
167587
|
+
const { basicInformation } = this.env.get(BridgeDataProvider);
|
|
167588
|
+
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
167589
|
+
const device = entity.deviceRegistry;
|
|
167590
|
+
applyPatchState(this.state, {
|
|
167591
|
+
vendorId: VendorId(basicInformation.vendorId),
|
|
167592
|
+
vendorName: ellipse(32, device?.manufacturer) ?? hash(32, basicInformation.vendorName),
|
|
167593
|
+
productName: ellipse(32, device?.model_id) ?? ellipse(32, device?.model) ?? hash(32, basicInformation.productName),
|
|
167594
|
+
productLabel: ellipse(64, device?.model) ?? hash(64, basicInformation.productLabel),
|
|
167595
|
+
hardwareVersion: basicInformation.hardwareVersion,
|
|
167596
|
+
softwareVersion: basicInformation.softwareVersion,
|
|
167597
|
+
hardwareVersionString: ellipse(64, device?.hw_version),
|
|
167598
|
+
softwareVersionString: ellipse(64, device?.sw_version),
|
|
167599
|
+
nodeLabel: ellipse(32, homeAssistant.state.customName) ?? ellipse(32, entity.state?.attributes?.friendly_name) ?? ellipse(32, entity.entity_id),
|
|
167600
|
+
reachable: entity.state?.state != null && entity.state.state !== "unavailable",
|
|
167601
|
+
// The device serial number is available in `device?.serial_number`, but
|
|
167602
|
+
// we're keeping it as the entity ID for now to avoid breaking existing
|
|
167603
|
+
// deployments.
|
|
167604
|
+
serialNumber: hash(32, entity.entity_id),
|
|
167605
|
+
// UniqueId helps controllers (especially Alexa) identify devices across
|
|
167606
|
+
// multiple fabric connections. Using MD5 hash of entity_id for stability.
|
|
167607
|
+
uniqueId: crypto6.createHash("md5").update(entity.entity_id).digest("hex").substring(0, 32)
|
|
167608
|
+
});
|
|
167609
|
+
}
|
|
167610
|
+
};
|
|
167611
|
+
function ellipse(maxLength, value) {
|
|
167612
|
+
return trimToLength(value, maxLength, "...");
|
|
167613
|
+
}
|
|
167614
|
+
function hash(maxLength, value) {
|
|
167615
|
+
const hashLength = 4;
|
|
167616
|
+
const suffix = crypto6.createHash("md5").update(value ?? "").digest("hex").substring(0, hashLength);
|
|
167617
|
+
return trimToLength(value, maxLength, suffix);
|
|
167618
|
+
}
|
|
167619
|
+
|
|
167307
167620
|
// src/matter/endpoints/composed/composed-air-purifier-endpoint.ts
|
|
167308
167621
|
init_home_assistant_entity_behavior();
|
|
167309
167622
|
|
|
167310
167623
|
// src/matter/behaviors/humidity-measurement-server.ts
|
|
167311
167624
|
init_esm();
|
|
167312
167625
|
init_home_assistant_entity_behavior();
|
|
167313
|
-
var
|
|
167626
|
+
var logger164 = Logger.get("HumidityMeasurementServer");
|
|
167314
167627
|
var HumidityMeasurementServerBase = class extends RelativeHumidityMeasurementServer {
|
|
167315
167628
|
async initialize() {
|
|
167316
167629
|
await super.initialize();
|
|
@@ -167323,7 +167636,7 @@ var HumidityMeasurementServerBase = class extends RelativeHumidityMeasurementSer
|
|
|
167323
167636
|
return;
|
|
167324
167637
|
}
|
|
167325
167638
|
const humidity = this.getHumidity(this.state.config, entity.state);
|
|
167326
|
-
|
|
167639
|
+
logger164.debug(
|
|
167327
167640
|
`Humidity ${entity.state.entity_id} raw=${entity.state.state} measuredValue=${humidity}`
|
|
167328
167641
|
);
|
|
167329
167642
|
applyPatchState(this.state, {
|
|
@@ -167359,7 +167672,7 @@ init_clusters();
|
|
|
167359
167672
|
|
|
167360
167673
|
// src/matter/behaviors/power-source-server.ts
|
|
167361
167674
|
init_home_assistant_entity_behavior();
|
|
167362
|
-
var
|
|
167675
|
+
var logger165 = Logger.get("PowerSourceServer");
|
|
167363
167676
|
var FeaturedBase = PowerSourceServer.with("Battery", "Rechargeable");
|
|
167364
167677
|
var PowerSourceServerBase = class extends FeaturedBase {
|
|
167365
167678
|
async initialize() {
|
|
@@ -167371,17 +167684,17 @@ var PowerSourceServerBase = class extends FeaturedBase {
|
|
|
167371
167684
|
applyPatchState(this.state, {
|
|
167372
167685
|
endpointList: [endpointNumber]
|
|
167373
167686
|
});
|
|
167374
|
-
|
|
167687
|
+
logger165.debug(
|
|
167375
167688
|
`[${entityId}] PowerSource initialized with endpointList=[${endpointNumber}]`
|
|
167376
167689
|
);
|
|
167377
167690
|
} else {
|
|
167378
|
-
|
|
167691
|
+
logger165.warn(
|
|
167379
167692
|
`[${entityId}] PowerSource endpoint number is null during initialize - endpointList will be empty!`
|
|
167380
167693
|
);
|
|
167381
167694
|
}
|
|
167382
167695
|
const batteryEntity = homeAssistant.state.mapping?.batteryEntity;
|
|
167383
167696
|
if (batteryEntity) {
|
|
167384
|
-
|
|
167697
|
+
logger165.debug(
|
|
167385
167698
|
`[${entityId}] PowerSource using mapped battery entity: ${batteryEntity}`
|
|
167386
167699
|
);
|
|
167387
167700
|
}
|
|
@@ -167444,6 +167757,26 @@ function PowerSourceServer2(config10) {
|
|
|
167444
167757
|
order: PowerSource3.Cluster.id
|
|
167445
167758
|
});
|
|
167446
167759
|
}
|
|
167760
|
+
var defaultBatteryConfig = {
|
|
167761
|
+
getBatteryPercent: (entity, agent) => {
|
|
167762
|
+
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
167763
|
+
const batteryEntity = homeAssistant.state.mapping?.batteryEntity;
|
|
167764
|
+
if (batteryEntity) {
|
|
167765
|
+
const stateProvider = agent.env.get(EntityStateProvider);
|
|
167766
|
+
const battery = stateProvider.getBatteryPercent(batteryEntity);
|
|
167767
|
+
if (battery != null) {
|
|
167768
|
+
return Math.max(0, Math.min(100, battery));
|
|
167769
|
+
}
|
|
167770
|
+
}
|
|
167771
|
+
const attrs = entity.attributes;
|
|
167772
|
+
const level = attrs.battery_level ?? attrs.battery;
|
|
167773
|
+
if (level == null || Number.isNaN(Number(level))) {
|
|
167774
|
+
return null;
|
|
167775
|
+
}
|
|
167776
|
+
return Number(level);
|
|
167777
|
+
}
|
|
167778
|
+
};
|
|
167779
|
+
var DefaultPowerSourceServer = PowerSourceServer2(defaultBatteryConfig);
|
|
167447
167780
|
|
|
167448
167781
|
// src/matter/behaviors/temperature-measurement-server.ts
|
|
167449
167782
|
init_home_assistant_entity_behavior();
|
|
@@ -167688,7 +168021,7 @@ var OPTIMISTIC_TOLERANCE = 5;
|
|
|
167688
168021
|
function notifyLightTurnedOn(entityId) {
|
|
167689
168022
|
lastTurnOnTimestamps.set(entityId, Date.now());
|
|
167690
168023
|
}
|
|
167691
|
-
var
|
|
168024
|
+
var logger166 = Logger.get("LevelControlServer");
|
|
167692
168025
|
var FeaturedBase3 = LevelControlServer.with("OnOff", "Lighting");
|
|
167693
168026
|
var LevelControlServerBase = class extends FeaturedBase3 {
|
|
167694
168027
|
pendingTransitionTime;
|
|
@@ -167703,12 +168036,12 @@ var LevelControlServerBase = class extends FeaturedBase3 {
|
|
|
167703
168036
|
this.state.maxLevel = 254;
|
|
167704
168037
|
}
|
|
167705
168038
|
this.state.onLevel = null;
|
|
167706
|
-
|
|
168039
|
+
logger166.debug(`initialize: calling super.initialize()`);
|
|
167707
168040
|
try {
|
|
167708
168041
|
await super.initialize();
|
|
167709
|
-
|
|
168042
|
+
logger166.debug(`initialize: super.initialize() completed successfully`);
|
|
167710
168043
|
} catch (error) {
|
|
167711
|
-
|
|
168044
|
+
logger166.error(`initialize: super.initialize() FAILED:`, error);
|
|
167712
168045
|
throw error;
|
|
167713
168046
|
}
|
|
167714
168047
|
const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
|
|
@@ -167784,7 +168117,7 @@ var LevelControlServerBase = class extends FeaturedBase3 {
|
|
|
167784
168117
|
const timeSinceTurnOn = lastTurnOn ? Date.now() - lastTurnOn : Infinity;
|
|
167785
168118
|
const isMaxBrightness = level >= this.maxLevel;
|
|
167786
168119
|
if (isMaxBrightness && timeSinceTurnOn < 200) {
|
|
167787
|
-
|
|
168120
|
+
logger166.debug(
|
|
167788
168121
|
`[${entityId}] Ignoring moveToLevel(${level}) - Alexa brightness reset detected (${timeSinceTurnOn}ms after turn-on)`
|
|
167789
168122
|
);
|
|
167790
168123
|
return;
|
|
@@ -167827,7 +168160,7 @@ function LevelControlServer2(config10) {
|
|
|
167827
168160
|
}
|
|
167828
168161
|
|
|
167829
168162
|
// src/matter/behaviors/on-off-server.ts
|
|
167830
|
-
var
|
|
168163
|
+
var logger167 = Logger.get("OnOffServer");
|
|
167831
168164
|
var optimisticOnOffState = /* @__PURE__ */ new Map();
|
|
167832
168165
|
var OPTIMISTIC_TIMEOUT_MS2 = 3e3;
|
|
167833
168166
|
var OnOffServerBase = class extends OnOffServer {
|
|
@@ -167862,12 +168195,13 @@ var OnOffServerBase = class extends OnOffServer {
|
|
|
167862
168195
|
return;
|
|
167863
168196
|
}
|
|
167864
168197
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
167865
|
-
const action = turnOn
|
|
167866
|
-
action: "homeassistant.turn_on"
|
|
167867
|
-
};
|
|
167868
|
-
logger166.info(`[${homeAssistant.entityId}] Turning ON -> ${action.action}`);
|
|
167869
|
-
notifyLightTurnedOn(homeAssistant.entityId);
|
|
168198
|
+
const action = turnOn ? turnOn(void 0, this.agent) : { action: "homeassistant.turn_on" };
|
|
167870
168199
|
applyPatchState(this.state, { onOff: true });
|
|
168200
|
+
if (!action) {
|
|
168201
|
+
return;
|
|
168202
|
+
}
|
|
168203
|
+
logger167.info(`[${homeAssistant.entityId}] Turning ON -> ${action.action}`);
|
|
168204
|
+
notifyLightTurnedOn(homeAssistant.entityId);
|
|
167871
168205
|
optimisticOnOffState.set(homeAssistant.entityId, {
|
|
167872
168206
|
expectedOnOff: true,
|
|
167873
168207
|
timestamp: Date.now()
|
|
@@ -167884,11 +168218,12 @@ var OnOffServerBase = class extends OnOffServer {
|
|
|
167884
168218
|
return;
|
|
167885
168219
|
}
|
|
167886
168220
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
167887
|
-
const action = turnOff
|
|
167888
|
-
action: "homeassistant.turn_off"
|
|
167889
|
-
};
|
|
167890
|
-
logger166.info(`[${homeAssistant.entityId}] Turning OFF -> ${action.action}`);
|
|
168221
|
+
const action = turnOff ? turnOff(void 0, this.agent) : { action: "homeassistant.turn_off" };
|
|
167891
168222
|
applyPatchState(this.state, { onOff: false });
|
|
168223
|
+
if (!action) {
|
|
168224
|
+
return;
|
|
168225
|
+
}
|
|
168226
|
+
logger167.info(`[${homeAssistant.entityId}] Turning OFF -> ${action.action}`);
|
|
167892
168227
|
optimisticOnOffState.set(homeAssistant.entityId, {
|
|
167893
168228
|
expectedOnOff: false,
|
|
167894
168229
|
timestamp: Date.now()
|
|
@@ -167897,6 +168232,7 @@ var OnOffServerBase = class extends OnOffServer {
|
|
|
167897
168232
|
}
|
|
167898
168233
|
autoReset() {
|
|
167899
168234
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
168235
|
+
optimisticOnOffState.delete(homeAssistant.entityId);
|
|
167900
168236
|
this.update(homeAssistant.entity);
|
|
167901
168237
|
}
|
|
167902
168238
|
};
|
|
@@ -167917,7 +168253,7 @@ function setOptimisticOnOff(entityId, expectedOnOff) {
|
|
|
167917
168253
|
}
|
|
167918
168254
|
|
|
167919
168255
|
// src/matter/behaviors/fan-control-server.ts
|
|
167920
|
-
var
|
|
168256
|
+
var logger168 = Logger.get("FanControlServer");
|
|
167921
168257
|
var defaultStepSize = 33.33;
|
|
167922
168258
|
var minSpeedMax = 3;
|
|
167923
168259
|
var maxSpeedMax = 100;
|
|
@@ -168276,7 +168612,7 @@ var FanControlServerBase = class extends FeaturedBase4 {
|
|
|
168276
168612
|
const entityId = this.agent.get(HomeAssistantEntityBehavior).entity.entity_id;
|
|
168277
168613
|
setOptimisticOnOff(entityId, on);
|
|
168278
168614
|
} catch (e) {
|
|
168279
|
-
|
|
168615
|
+
logger168.debug(
|
|
168280
168616
|
`syncOnOff(${on}) failed: ${e instanceof Error ? e.message : String(e)}`
|
|
168281
168617
|
);
|
|
168282
168618
|
}
|
|
@@ -168364,36 +168700,26 @@ var FanOnOffServer = OnOffServer2({
|
|
|
168364
168700
|
});
|
|
168365
168701
|
|
|
168366
168702
|
// src/matter/endpoints/composed/composed-air-purifier-endpoint.ts
|
|
168367
|
-
var
|
|
168368
|
-
|
|
168369
|
-
|
|
168370
|
-
|
|
168371
|
-
|
|
168372
|
-
|
|
168373
|
-
|
|
168374
|
-
|
|
168375
|
-
|
|
168376
|
-
|
|
168377
|
-
|
|
168378
|
-
|
|
168379
|
-
|
|
168380
|
-
|
|
168381
|
-
|
|
168382
|
-
|
|
168383
|
-
|
|
168384
|
-
|
|
168385
|
-
|
|
168386
|
-
|
|
168387
|
-
getValue(_entity, agent) {
|
|
168388
|
-
const stateProvider = agent.env.get(EntityStateProvider);
|
|
168389
|
-
const humState = stateProvider.getState(humidityEntityId);
|
|
168390
|
-
if (!humState) return null;
|
|
168391
|
-
const humidity = Number.parseFloat(humState.state);
|
|
168392
|
-
if (Number.isNaN(humidity)) return null;
|
|
168393
|
-
return humidity;
|
|
168394
|
-
}
|
|
168395
|
-
};
|
|
168396
|
-
}
|
|
168703
|
+
var logger169 = Logger.get("ComposedAirPurifierEndpoint");
|
|
168704
|
+
var temperatureConfig = {
|
|
168705
|
+
getValue(entity, agent) {
|
|
168706
|
+
const fallbackUnit = agent.env.get(HomeAssistantConfig).unitSystem.temperature;
|
|
168707
|
+
const state = entity.state;
|
|
168708
|
+
const attributes7 = entity.attributes;
|
|
168709
|
+
const temperature3 = state == null || Number.isNaN(+state) ? null : +state;
|
|
168710
|
+
if (temperature3 == null) return void 0;
|
|
168711
|
+
return Temperature.withUnit(
|
|
168712
|
+
temperature3,
|
|
168713
|
+
attributes7.unit_of_measurement ?? fallbackUnit
|
|
168714
|
+
);
|
|
168715
|
+
}
|
|
168716
|
+
};
|
|
168717
|
+
var humidityConfig = {
|
|
168718
|
+
getValue({ state }) {
|
|
168719
|
+
if (state == null || Number.isNaN(+state)) return null;
|
|
168720
|
+
return +state;
|
|
168721
|
+
}
|
|
168722
|
+
};
|
|
168397
168723
|
var batteryConfig = {
|
|
168398
168724
|
getBatteryPercent: (_entity, agent) => {
|
|
168399
168725
|
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
@@ -168406,6 +168732,16 @@ var batteryConfig = {
|
|
|
168406
168732
|
return null;
|
|
168407
168733
|
}
|
|
168408
168734
|
};
|
|
168735
|
+
var TemperatureSubType = TemperatureSensorDevice.with(
|
|
168736
|
+
IdentifyServer2,
|
|
168737
|
+
HomeAssistantEntityBehavior,
|
|
168738
|
+
TemperatureMeasurementServer2(temperatureConfig)
|
|
168739
|
+
);
|
|
168740
|
+
var HumiditySubType = HumiditySensorDevice.with(
|
|
168741
|
+
IdentifyServer2,
|
|
168742
|
+
HomeAssistantEntityBehavior,
|
|
168743
|
+
HumidityMeasurementServer(humidityConfig)
|
|
168744
|
+
);
|
|
168409
168745
|
function createEndpointId2(entityId, customName) {
|
|
168410
168746
|
const baseName = customName || entityId;
|
|
168411
168747
|
return baseName.replace(/\./g, "_").replace(/\s+/g, "_");
|
|
@@ -168425,9 +168761,9 @@ function buildEntityPayload(registry2, entityId) {
|
|
|
168425
168761
|
var ComposedAirPurifierEndpoint = class _ComposedAirPurifierEndpoint extends Endpoint {
|
|
168426
168762
|
entityId;
|
|
168427
168763
|
mappedEntityIds;
|
|
168428
|
-
|
|
168764
|
+
subEndpoints = /* @__PURE__ */ new Map();
|
|
168429
168765
|
lastStates = /* @__PURE__ */ new Map();
|
|
168430
|
-
|
|
168766
|
+
debouncedUpdates = /* @__PURE__ */ new Map();
|
|
168431
168767
|
static async create(config10) {
|
|
168432
168768
|
const { registry: registry2, primaryEntityId } = config10;
|
|
168433
168769
|
const primaryPayload = buildEntityPayload(registry2, primaryEntityId);
|
|
@@ -168455,8 +168791,7 @@ var ComposedAirPurifierEndpoint = class _ComposedAirPurifierEndpoint extends End
|
|
|
168455
168791
|
if (hasWindModes) {
|
|
168456
168792
|
features2.add("Wind");
|
|
168457
168793
|
}
|
|
168458
|
-
let
|
|
168459
|
-
BasicInformationServer2,
|
|
168794
|
+
let airPurifierSubType = AirPurifierDevice.with(
|
|
168460
168795
|
IdentifyServer2,
|
|
168461
168796
|
HomeAssistantEntityBehavior,
|
|
168462
168797
|
FanOnOffServer,
|
|
@@ -168464,27 +168799,23 @@ var ComposedAirPurifierEndpoint = class _ComposedAirPurifierEndpoint extends End
|
|
|
168464
168799
|
);
|
|
168465
168800
|
const hasFilterLife = airPurifierAttributes.filter_life != null || airPurifierAttributes.filter_life_remaining != null || airPurifierAttributes.filter_life_level != null || !!config10.mapping?.filterLifeEntity;
|
|
168466
168801
|
if (hasFilterLife) {
|
|
168467
|
-
|
|
168468
|
-
|
|
168469
|
-
if (config10.temperatureEntityId) {
|
|
168470
|
-
parentType = parentType.with(
|
|
168471
|
-
TemperatureMeasurementServer2(
|
|
168472
|
-
createTemperatureConfig(config10.temperatureEntityId)
|
|
168473
|
-
)
|
|
168474
|
-
);
|
|
168475
|
-
}
|
|
168476
|
-
if (config10.humidityEntityId) {
|
|
168477
|
-
parentType = parentType.with(
|
|
168478
|
-
HumidityMeasurementServer(
|
|
168479
|
-
createHumidityConfig(config10.humidityEntityId)
|
|
168480
|
-
)
|
|
168802
|
+
airPurifierSubType = airPurifierSubType.with(
|
|
168803
|
+
AirPurifierHepaFilterMonitoringServer
|
|
168481
168804
|
);
|
|
168482
168805
|
}
|
|
168483
|
-
const
|
|
168806
|
+
const airPurifierMapping = {
|
|
168484
168807
|
entityId: primaryEntityId,
|
|
168485
|
-
...config10.batteryEntityId ? { batteryEntity: config10.batteryEntityId } : {},
|
|
168486
168808
|
...config10.mapping?.filterLifeEntity ? { filterLifeEntity: config10.mapping.filterLifeEntity } : {}
|
|
168487
168809
|
};
|
|
168810
|
+
let parentType = BridgedNodeEndpoint.with(
|
|
168811
|
+
BasicInformationServer2,
|
|
168812
|
+
IdentifyServer2,
|
|
168813
|
+
HomeAssistantEntityBehavior
|
|
168814
|
+
);
|
|
168815
|
+
const parentMapping = {
|
|
168816
|
+
entityId: primaryEntityId,
|
|
168817
|
+
...config10.batteryEntityId ? { batteryEntity: config10.batteryEntityId } : {}
|
|
168818
|
+
};
|
|
168488
168819
|
if (config10.batteryEntityId) {
|
|
168489
168820
|
parentType = parentType.with(PowerSourceServer2(batteryConfig));
|
|
168490
168821
|
}
|
|
@@ -168497,75 +168828,125 @@ var ComposedAirPurifierEndpoint = class _ComposedAirPurifierEndpoint extends End
|
|
|
168497
168828
|
);
|
|
168498
168829
|
}
|
|
168499
168830
|
const endpointId = createEndpointId2(primaryEntityId, config10.customName);
|
|
168831
|
+
const parts = [];
|
|
168832
|
+
const airPurifierSub = new Endpoint(
|
|
168833
|
+
airPurifierSubType.set({
|
|
168834
|
+
homeAssistantEntity: {
|
|
168835
|
+
entity: primaryPayload,
|
|
168836
|
+
mapping: airPurifierMapping
|
|
168837
|
+
}
|
|
168838
|
+
}),
|
|
168839
|
+
{ id: `${endpointId}_air_purifier` }
|
|
168840
|
+
);
|
|
168841
|
+
parts.push(airPurifierSub);
|
|
168842
|
+
let tempSub;
|
|
168843
|
+
if (config10.temperatureEntityId) {
|
|
168844
|
+
const tempPayload = buildEntityPayload(
|
|
168845
|
+
registry2,
|
|
168846
|
+
config10.temperatureEntityId
|
|
168847
|
+
);
|
|
168848
|
+
if (tempPayload) {
|
|
168849
|
+
tempSub = new Endpoint(
|
|
168850
|
+
TemperatureSubType.set({
|
|
168851
|
+
homeAssistantEntity: { entity: tempPayload }
|
|
168852
|
+
}),
|
|
168853
|
+
{ id: `${endpointId}_temp` }
|
|
168854
|
+
);
|
|
168855
|
+
parts.push(tempSub);
|
|
168856
|
+
}
|
|
168857
|
+
}
|
|
168858
|
+
let humSub;
|
|
168859
|
+
if (config10.humidityEntityId) {
|
|
168860
|
+
const humPayload = buildEntityPayload(registry2, config10.humidityEntityId);
|
|
168861
|
+
if (humPayload) {
|
|
168862
|
+
humSub = new Endpoint(
|
|
168863
|
+
HumiditySubType.set({
|
|
168864
|
+
homeAssistantEntity: { entity: humPayload }
|
|
168865
|
+
}),
|
|
168866
|
+
{ id: `${endpointId}_humidity` }
|
|
168867
|
+
);
|
|
168868
|
+
parts.push(humSub);
|
|
168869
|
+
}
|
|
168870
|
+
}
|
|
168500
168871
|
const parentTypeWithState = parentType.set({
|
|
168501
168872
|
homeAssistantEntity: {
|
|
168502
168873
|
entity: primaryPayload,
|
|
168503
168874
|
customName: config10.customName,
|
|
168504
|
-
mapping
|
|
168875
|
+
mapping: parentMapping
|
|
168505
168876
|
}
|
|
168506
168877
|
});
|
|
168507
|
-
const
|
|
168508
|
-
if (config10.temperatureEntityId)
|
|
168509
|
-
|
|
168510
|
-
if (config10.
|
|
168511
|
-
|
|
168878
|
+
const mappedIds = [];
|
|
168879
|
+
if (config10.temperatureEntityId) mappedIds.push(config10.temperatureEntityId);
|
|
168880
|
+
if (config10.humidityEntityId) mappedIds.push(config10.humidityEntityId);
|
|
168881
|
+
if (config10.mapping?.filterLifeEntity)
|
|
168882
|
+
mappedIds.push(config10.mapping.filterLifeEntity);
|
|
168512
168883
|
const endpoint = new _ComposedAirPurifierEndpoint(
|
|
168513
168884
|
parentTypeWithState,
|
|
168514
168885
|
primaryEntityId,
|
|
168515
168886
|
endpointId,
|
|
168516
|
-
|
|
168887
|
+
parts,
|
|
168517
168888
|
mappedIds
|
|
168518
168889
|
);
|
|
168890
|
+
endpoint.subEndpoints.set(primaryEntityId, airPurifierSub);
|
|
168891
|
+
if (config10.temperatureEntityId && tempSub) {
|
|
168892
|
+
endpoint.subEndpoints.set(config10.temperatureEntityId, tempSub);
|
|
168893
|
+
}
|
|
168894
|
+
if (config10.humidityEntityId && humSub) {
|
|
168895
|
+
endpoint.subEndpoints.set(config10.humidityEntityId, humSub);
|
|
168896
|
+
}
|
|
168519
168897
|
const clusterLabels = [
|
|
168520
168898
|
"AirPurifier",
|
|
168521
168899
|
config10.temperatureEntityId ? "+Temp" : "",
|
|
168522
168900
|
config10.humidityEntityId ? "+Hum" : "",
|
|
168523
|
-
config10.batteryEntityId ? "+Bat" : ""
|
|
168901
|
+
config10.batteryEntityId ? "+Bat" : "",
|
|
168902
|
+
hasFilterLife ? "+HEPA" : ""
|
|
168524
168903
|
].filter(Boolean).join("");
|
|
168525
|
-
|
|
168904
|
+
logger169.info(
|
|
168905
|
+
`Created composed air purifier ${primaryEntityId}: ${clusterLabels}`
|
|
168906
|
+
);
|
|
168526
168907
|
return endpoint;
|
|
168527
168908
|
}
|
|
168528
|
-
constructor(type, entityId, id,
|
|
168529
|
-
super(type, { id });
|
|
168909
|
+
constructor(type, entityId, id, parts, mappedEntityIds) {
|
|
168910
|
+
super(type, { id, parts });
|
|
168530
168911
|
this.entityId = entityId;
|
|
168531
|
-
this.trackedEntityIds = trackedEntityIds;
|
|
168532
168912
|
this.mappedEntityIds = mappedEntityIds;
|
|
168533
168913
|
}
|
|
168534
168914
|
async updateStates(states) {
|
|
168535
|
-
|
|
168536
|
-
for (const entityId of this.
|
|
168537
|
-
|
|
168538
|
-
if (!state) continue;
|
|
168539
|
-
const stateJson = JSON.stringify({
|
|
168540
|
-
s: state.state,
|
|
168541
|
-
a: state.attributes
|
|
168542
|
-
});
|
|
168543
|
-
if (this.lastStates.get(entityId) !== stateJson) {
|
|
168544
|
-
this.lastStates.set(entityId, stateJson);
|
|
168545
|
-
anyChanged = true;
|
|
168546
|
-
}
|
|
168915
|
+
this.scheduleUpdate(this, this.entityId, states);
|
|
168916
|
+
for (const [entityId, sub] of this.subEndpoints) {
|
|
168917
|
+
this.scheduleUpdate(sub, entityId, states);
|
|
168547
168918
|
}
|
|
168548
|
-
|
|
168549
|
-
|
|
168550
|
-
|
|
168551
|
-
if (!
|
|
168552
|
-
|
|
168553
|
-
|
|
168919
|
+
}
|
|
168920
|
+
scheduleUpdate(endpoint, entityId, states) {
|
|
168921
|
+
const state = states[entityId];
|
|
168922
|
+
if (!state) return;
|
|
168923
|
+
const key = endpoint === this ? `_parent_:${entityId}` : entityId;
|
|
168924
|
+
const stateJson = JSON.stringify({
|
|
168925
|
+
s: state.state,
|
|
168926
|
+
a: state.attributes
|
|
168927
|
+
});
|
|
168928
|
+
if (this.lastStates.get(key) === stateJson) return;
|
|
168929
|
+
this.lastStates.set(key, stateJson);
|
|
168930
|
+
let debouncedFn = this.debouncedUpdates.get(key);
|
|
168931
|
+
if (!debouncedFn) {
|
|
168932
|
+
debouncedFn = debounce2(
|
|
168933
|
+
(ep, s) => this.flushUpdate(ep, s),
|
|
168554
168934
|
50
|
|
168555
168935
|
);
|
|
168936
|
+
this.debouncedUpdates.set(key, debouncedFn);
|
|
168556
168937
|
}
|
|
168557
|
-
|
|
168938
|
+
debouncedFn(endpoint, state);
|
|
168558
168939
|
}
|
|
168559
|
-
async flushUpdate(state) {
|
|
168940
|
+
async flushUpdate(endpoint, state) {
|
|
168560
168941
|
try {
|
|
168561
|
-
await
|
|
168942
|
+
await endpoint.construction.ready;
|
|
168562
168943
|
} catch {
|
|
168563
168944
|
return;
|
|
168564
168945
|
}
|
|
168565
168946
|
try {
|
|
168566
|
-
const current =
|
|
168567
|
-
await
|
|
168568
|
-
entity: { ...current, state
|
|
168947
|
+
const current = endpoint.stateOf(HomeAssistantEntityBehavior).entity;
|
|
168948
|
+
await endpoint.setStateOf(HomeAssistantEntityBehavior, {
|
|
168949
|
+
entity: { ...current, state }
|
|
168569
168950
|
});
|
|
168570
168951
|
} catch (error) {
|
|
168571
168952
|
if (error instanceof TransactionDestroyedError || error instanceof DestroyedDependencyError) {
|
|
@@ -168581,7 +168962,9 @@ var ComposedAirPurifierEndpoint = class _ComposedAirPurifierEndpoint extends End
|
|
|
168581
168962
|
}
|
|
168582
168963
|
}
|
|
168583
168964
|
async delete() {
|
|
168584
|
-
this.
|
|
168965
|
+
for (const fn of this.debouncedUpdates.values()) {
|
|
168966
|
+
fn.clear();
|
|
168967
|
+
}
|
|
168585
168968
|
await super.delete();
|
|
168586
168969
|
}
|
|
168587
168970
|
};
|
|
@@ -168618,7 +169001,7 @@ init_home_assistant_entity_behavior();
|
|
|
168618
169001
|
// src/matter/behaviors/pressure-measurement-server.ts
|
|
168619
169002
|
init_esm();
|
|
168620
169003
|
init_home_assistant_entity_behavior();
|
|
168621
|
-
var
|
|
169004
|
+
var logger170 = Logger.get("PressureMeasurementServer");
|
|
168622
169005
|
var MIN_PRESSURE = 300;
|
|
168623
169006
|
var MAX_PRESSURE = 1100;
|
|
168624
169007
|
var PressureMeasurementServerBase = class extends PressureMeasurementServer {
|
|
@@ -168646,7 +169029,7 @@ var PressureMeasurementServerBase = class extends PressureMeasurementServer {
|
|
|
168646
169029
|
}
|
|
168647
169030
|
const rounded = Math.round(value);
|
|
168648
169031
|
if (rounded < MIN_PRESSURE || rounded > MAX_PRESSURE) {
|
|
168649
|
-
|
|
169032
|
+
logger170.warn(
|
|
168650
169033
|
`Pressure value ${rounded} (raw: ${value}) for ${entity.entity_id} is outside valid range [${MIN_PRESSURE}-${MAX_PRESSURE}], ignoring`
|
|
168651
169034
|
);
|
|
168652
169035
|
return null;
|
|
@@ -168665,8 +169048,8 @@ function PressureMeasurementServer2(config10) {
|
|
|
168665
169048
|
}
|
|
168666
169049
|
|
|
168667
169050
|
// src/matter/endpoints/composed/composed-sensor-endpoint.ts
|
|
168668
|
-
var
|
|
168669
|
-
var
|
|
169051
|
+
var logger171 = Logger.get("ComposedSensorEndpoint");
|
|
169052
|
+
var temperatureConfig2 = {
|
|
168670
169053
|
getValue(entity, agent) {
|
|
168671
169054
|
const fallbackUnit = agent.env.get(HomeAssistantConfig).unitSystem.temperature;
|
|
168672
169055
|
const state = entity.state;
|
|
@@ -168679,7 +169062,7 @@ var temperatureConfig = {
|
|
|
168679
169062
|
);
|
|
168680
169063
|
}
|
|
168681
169064
|
};
|
|
168682
|
-
var
|
|
169065
|
+
var humidityConfig2 = {
|
|
168683
169066
|
getValue({ state }) {
|
|
168684
169067
|
if (state == null || Number.isNaN(+state)) return null;
|
|
168685
169068
|
return +state;
|
|
@@ -168706,15 +169089,15 @@ var batteryConfig2 = {
|
|
|
168706
169089
|
return null;
|
|
168707
169090
|
}
|
|
168708
169091
|
};
|
|
168709
|
-
var
|
|
169092
|
+
var TemperatureSubType2 = TemperatureSensorDevice.with(
|
|
168710
169093
|
IdentifyServer2,
|
|
168711
169094
|
HomeAssistantEntityBehavior,
|
|
168712
|
-
TemperatureMeasurementServer2(
|
|
169095
|
+
TemperatureMeasurementServer2(temperatureConfig2)
|
|
168713
169096
|
);
|
|
168714
|
-
var
|
|
169097
|
+
var HumiditySubType2 = HumiditySensorDevice.with(
|
|
168715
169098
|
IdentifyServer2,
|
|
168716
169099
|
HomeAssistantEntityBehavior,
|
|
168717
|
-
HumidityMeasurementServer(
|
|
169100
|
+
HumidityMeasurementServer(humidityConfig2)
|
|
168718
169101
|
);
|
|
168719
169102
|
var PressureSubType = PressureSensorDevice.with(
|
|
168720
169103
|
IdentifyServer2,
|
|
@@ -168770,7 +169153,7 @@ var ComposedSensorEndpoint = class _ComposedSensorEndpoint extends Endpoint {
|
|
|
168770
169153
|
const endpointId = createEndpointId3(primaryEntityId, config10.customName);
|
|
168771
169154
|
const parts = [];
|
|
168772
169155
|
const tempSub = new Endpoint(
|
|
168773
|
-
|
|
169156
|
+
TemperatureSubType2.set({
|
|
168774
169157
|
homeAssistantEntity: { entity: primaryPayload }
|
|
168775
169158
|
}),
|
|
168776
169159
|
{ id: `${endpointId}_temp` }
|
|
@@ -168781,7 +169164,7 @@ var ComposedSensorEndpoint = class _ComposedSensorEndpoint extends Endpoint {
|
|
|
168781
169164
|
const humPayload = buildEntityPayload2(registry2, config10.humidityEntityId);
|
|
168782
169165
|
if (humPayload) {
|
|
168783
169166
|
humSub = new Endpoint(
|
|
168784
|
-
|
|
169167
|
+
HumiditySubType2.set({
|
|
168785
169168
|
homeAssistantEntity: { entity: humPayload }
|
|
168786
169169
|
}),
|
|
168787
169170
|
{ id: `${endpointId}_humidity` }
|
|
@@ -168829,7 +169212,7 @@ var ComposedSensorEndpoint = class _ComposedSensorEndpoint extends Endpoint {
|
|
|
168829
169212
|
if (config10.pressureEntityId && pressSub) {
|
|
168830
169213
|
endpoint.subEndpoints.set(config10.pressureEntityId, pressSub);
|
|
168831
169214
|
}
|
|
168832
|
-
|
|
169215
|
+
logger171.info(
|
|
168833
169216
|
`Created composed sensor ${primaryEntityId} with ${parts.length} sub-endpoint(s): T${humSub ? "+H" : ""}${pressSub ? "+P" : ""}${config10.batteryEntityId ? "+Bat" : ""}`
|
|
168834
169217
|
);
|
|
168835
169218
|
return endpoint;
|
|
@@ -168897,56 +169280,14 @@ var ComposedSensorEndpoint = class _ComposedSensorEndpoint extends Endpoint {
|
|
|
168897
169280
|
}
|
|
168898
169281
|
};
|
|
168899
169282
|
|
|
168900
|
-
// src/matter/endpoints/
|
|
169283
|
+
// src/matter/endpoints/composed/user-composed-endpoint.ts
|
|
168901
169284
|
init_esm();
|
|
168902
169285
|
init_esm7();
|
|
168903
|
-
|
|
168904
|
-
|
|
168905
|
-
|
|
168906
|
-
|
|
168907
|
-
|
|
168908
|
-
const deviceTypeModel = Matter.deviceTypes.find(
|
|
168909
|
-
(dt) => dt.id === endpointType.deviceType
|
|
168910
|
-
);
|
|
168911
|
-
if (!deviceTypeModel) {
|
|
168912
|
-
return void 0;
|
|
168913
|
-
}
|
|
168914
|
-
const serverClusterReqs = deviceTypeModel.requirements.filter(
|
|
168915
|
-
(r) => r.element === "serverCluster"
|
|
168916
|
-
);
|
|
168917
|
-
const behaviorKeys = new Set(Object.keys(endpointType.behaviors));
|
|
168918
|
-
const missingMandatory = [];
|
|
168919
|
-
const availableOptional = [];
|
|
168920
|
-
const presentClusters = [];
|
|
168921
|
-
for (const req of serverClusterReqs) {
|
|
168922
|
-
const key = toCamelCase(req.name);
|
|
168923
|
-
if (behaviorKeys.has(key)) {
|
|
168924
|
-
presentClusters.push(req.name);
|
|
168925
|
-
} else if (req.isMandatory) {
|
|
168926
|
-
missingMandatory.push(req.name);
|
|
168927
|
-
} else {
|
|
168928
|
-
availableOptional.push(req.name);
|
|
168929
|
-
}
|
|
168930
|
-
}
|
|
168931
|
-
const prefix = entityId ? `[${entityId}] ` : "";
|
|
168932
|
-
if (missingMandatory.length > 0) {
|
|
168933
|
-
logger171.warn(
|
|
168934
|
-
`${prefix}${deviceTypeModel.name} (0x${endpointType.deviceType.toString(16)}): missing mandatory clusters: ${missingMandatory.join(", ")}`
|
|
168935
|
-
);
|
|
168936
|
-
}
|
|
168937
|
-
if (availableOptional.length > 0) {
|
|
168938
|
-
logger171.debug(
|
|
168939
|
-
`${prefix}${deviceTypeModel.name} (0x${endpointType.deviceType.toString(16)}): optional clusters not used: ${availableOptional.join(", ")}`
|
|
168940
|
-
);
|
|
168941
|
-
}
|
|
168942
|
-
return {
|
|
168943
|
-
deviceTypeName: deviceTypeModel.name,
|
|
168944
|
-
deviceTypeId: endpointType.deviceType,
|
|
168945
|
-
missingMandatory,
|
|
168946
|
-
availableOptional,
|
|
168947
|
-
presentClusters
|
|
168948
|
-
};
|
|
168949
|
-
}
|
|
169286
|
+
import debounce4 from "debounce";
|
|
169287
|
+
init_home_assistant_entity_behavior();
|
|
169288
|
+
|
|
169289
|
+
// src/matter/endpoints/legacy/create-legacy-endpoint-type.ts
|
|
169290
|
+
init_esm();
|
|
168950
169291
|
|
|
168951
169292
|
// src/matter/endpoints/legacy/air-purifier/index.ts
|
|
168952
169293
|
init_dist();
|
|
@@ -169208,10 +169549,6 @@ function AutomationDevice(homeAssistantEntity) {
|
|
|
169208
169549
|
return AutomationDeviceType.set({ homeAssistantEntity });
|
|
169209
169550
|
}
|
|
169210
169551
|
|
|
169211
|
-
// src/matter/endpoints/legacy/binary-sensor/index.ts
|
|
169212
|
-
init_dist();
|
|
169213
|
-
init_esm();
|
|
169214
|
-
|
|
169215
169552
|
// ../../node_modules/.pnpm/@matter+main@0.16.10/node_modules/@matter/main/dist/esm/forwards/behaviors/boolean-state.js
|
|
169216
169553
|
init_nodejs();
|
|
169217
169554
|
|
|
@@ -169281,6 +169618,10 @@ var ContactSensorWithBatteryType = ContactSensorDevice.with(
|
|
|
169281
169618
|
})
|
|
169282
169619
|
);
|
|
169283
169620
|
|
|
169621
|
+
// src/matter/endpoints/legacy/binary-sensor/index.ts
|
|
169622
|
+
init_dist();
|
|
169623
|
+
init_esm();
|
|
169624
|
+
|
|
169284
169625
|
// src/matter/endpoints/legacy/binary-sensor/motion-sensor.ts
|
|
169285
169626
|
init_home_assistant_entity_behavior();
|
|
169286
169627
|
|
|
@@ -169741,7 +170082,7 @@ var ClimateFanControlServer = FanControlServer2(config3).with(
|
|
|
169741
170082
|
);
|
|
169742
170083
|
|
|
169743
170084
|
// src/matter/endpoints/legacy/climate/behaviors/climate-humidity-measurement-server.ts
|
|
169744
|
-
var
|
|
170085
|
+
var humidityConfig3 = {
|
|
169745
170086
|
getValue(entity) {
|
|
169746
170087
|
const attributes7 = entity.attributes;
|
|
169747
170088
|
const humidity = attributes7.current_humidity;
|
|
@@ -169751,11 +170092,18 @@ var humidityConfig2 = {
|
|
|
169751
170092
|
return +humidity;
|
|
169752
170093
|
}
|
|
169753
170094
|
};
|
|
169754
|
-
var ClimateHumidityMeasurementServer = HumidityMeasurementServer(
|
|
170095
|
+
var ClimateHumidityMeasurementServer = HumidityMeasurementServer(humidityConfig3);
|
|
169755
170096
|
|
|
169756
170097
|
// src/matter/endpoints/legacy/climate/behaviors/climate-on-off-server.ts
|
|
170098
|
+
init_home_assistant_entity_behavior();
|
|
169757
170099
|
var ClimateOnOffServer = OnOffServer2({
|
|
169758
|
-
turnOn: () =>
|
|
170100
|
+
turnOn: (_value, agent) => {
|
|
170101
|
+
const entity = agent.get(HomeAssistantEntityBehavior).entity;
|
|
170102
|
+
if (entity.state.state !== "off") {
|
|
170103
|
+
return void 0;
|
|
170104
|
+
}
|
|
170105
|
+
return { action: "climate.turn_on" };
|
|
170106
|
+
},
|
|
169759
170107
|
turnOff: () => ({ action: "climate.turn_off" })
|
|
169760
170108
|
}).with("Lighting");
|
|
169761
170109
|
|
|
@@ -169932,7 +170280,8 @@ var ThermostatServerBase = class extends FullFeaturedBase {
|
|
|
169932
170280
|
logger174.debug(
|
|
169933
170281
|
`update: limits heat=[${minHeatLimit}, ${maxHeatLimit}], cool=[${minCoolLimit}, ${maxCoolLimit}], systemMode=${systemMode}, runningMode=${runningMode}`
|
|
169934
170282
|
);
|
|
169935
|
-
|
|
170283
|
+
let controlSequence = config10.getControlSequence(entity.state, this.agent);
|
|
170284
|
+
controlSequence = this.clampControlSequence(controlSequence);
|
|
169936
170285
|
this.internal.controlSequenceOfOperation = controlSequence;
|
|
169937
170286
|
applyPatchState(this.state, {
|
|
169938
170287
|
...this.features.heating ? {
|
|
@@ -170187,6 +170536,26 @@ var ThermostatServerBase = class extends FullFeaturedBase {
|
|
|
170187
170536
|
}
|
|
170188
170537
|
}
|
|
170189
170538
|
}
|
|
170539
|
+
clampControlSequence(value) {
|
|
170540
|
+
const hasHeat = this.features.heating;
|
|
170541
|
+
const hasCool = this.features.cooling;
|
|
170542
|
+
const needsHeat = value === Thermostat3.ControlSequenceOfOperation.HeatingOnly || value === Thermostat3.ControlSequenceOfOperation.HeatingWithReheat;
|
|
170543
|
+
const needsCool = value === Thermostat3.ControlSequenceOfOperation.CoolingOnly || value === Thermostat3.ControlSequenceOfOperation.CoolingWithReheat;
|
|
170544
|
+
const needsBoth = value === Thermostat3.ControlSequenceOfOperation.CoolingAndHeating || value === Thermostat3.ControlSequenceOfOperation.CoolingAndHeatingWithReheat;
|
|
170545
|
+
if (needsHeat && !hasHeat) {
|
|
170546
|
+
return Thermostat3.ControlSequenceOfOperation.CoolingOnly;
|
|
170547
|
+
}
|
|
170548
|
+
if (needsCool && !hasCool) {
|
|
170549
|
+
return Thermostat3.ControlSequenceOfOperation.HeatingOnly;
|
|
170550
|
+
}
|
|
170551
|
+
if (needsBoth && !hasHeat) {
|
|
170552
|
+
return Thermostat3.ControlSequenceOfOperation.CoolingOnly;
|
|
170553
|
+
}
|
|
170554
|
+
if (needsBoth && !hasCool) {
|
|
170555
|
+
return Thermostat3.ControlSequenceOfOperation.HeatingOnly;
|
|
170556
|
+
}
|
|
170557
|
+
return value;
|
|
170558
|
+
}
|
|
170190
170559
|
clampSetpoint(value, min, max, type) {
|
|
170191
170560
|
const effectiveMin = min ?? 0;
|
|
170192
170561
|
const effectiveMax = max ?? 5e3;
|
|
@@ -170435,7 +170804,7 @@ var config4 = {
|
|
|
170435
170804
|
(m) => m === ClimateHvacMode.cool || m === ClimateHvacMode.heat_cool
|
|
170436
170805
|
);
|
|
170437
170806
|
const hasHeating = modes.some(
|
|
170438
|
-
(m) => m === ClimateHvacMode.heat || m === ClimateHvacMode.heat_cool
|
|
170807
|
+
(m) => m === ClimateHvacMode.heat || m === ClimateHvacMode.heat_cool
|
|
170439
170808
|
);
|
|
170440
170809
|
if (hasCooling && hasHeating) {
|
|
170441
170810
|
const hasAutoMode = modes.includes(ClimateHvacMode.heat_cool) && (modes.includes(ClimateHvacMode.heat) || modes.includes(ClimateHvacMode.cool));
|
|
@@ -170495,25 +170864,6 @@ function ClimateThermostatServer(initialState = {}, features2) {
|
|
|
170495
170864
|
}
|
|
170496
170865
|
|
|
170497
170866
|
// src/matter/endpoints/legacy/climate/index.ts
|
|
170498
|
-
var ClimatePowerSourceServer = PowerSourceServer2({
|
|
170499
|
-
getBatteryPercent: (entity, agent) => {
|
|
170500
|
-
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
170501
|
-
const batteryEntity = homeAssistant.state.mapping?.batteryEntity;
|
|
170502
|
-
if (batteryEntity) {
|
|
170503
|
-
const stateProvider = agent.env.get(EntityStateProvider);
|
|
170504
|
-
const battery = stateProvider.getBatteryPercent(batteryEntity);
|
|
170505
|
-
if (battery != null) {
|
|
170506
|
-
return Math.max(0, Math.min(100, battery));
|
|
170507
|
-
}
|
|
170508
|
-
}
|
|
170509
|
-
const attrs = entity.attributes;
|
|
170510
|
-
const level = attrs.battery_level ?? attrs.battery;
|
|
170511
|
-
if (level == null || Number.isNaN(Number(level))) {
|
|
170512
|
-
return null;
|
|
170513
|
-
}
|
|
170514
|
-
return Number(level);
|
|
170515
|
-
}
|
|
170516
|
-
});
|
|
170517
170867
|
var ClimateDeviceType = (supportsOnOff, supportsHumidity, supportsFanMode, hasBattery, features2, initialState = {}) => {
|
|
170518
170868
|
const additionalClusters = [];
|
|
170519
170869
|
if (supportsOnOff) {
|
|
@@ -170523,7 +170873,7 @@ var ClimateDeviceType = (supportsOnOff, supportsHumidity, supportsFanMode, hasBa
|
|
|
170523
170873
|
additionalClusters.push(ClimateHumidityMeasurementServer);
|
|
170524
170874
|
}
|
|
170525
170875
|
if (hasBattery) {
|
|
170526
|
-
additionalClusters.push(
|
|
170876
|
+
additionalClusters.push(DefaultPowerSourceServer);
|
|
170527
170877
|
}
|
|
170528
170878
|
const thermostatServer = ClimateThermostatServer(initialState, features2);
|
|
170529
170879
|
if (supportsFanMode) {
|
|
@@ -170743,6 +171093,22 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
|
|
|
170743
171093
|
);
|
|
170744
171094
|
const currentTilt100ths = currentTilt != null ? currentTilt * 100 : null;
|
|
170745
171095
|
const isStopped = movementStatus === MovementStatus.Stopped;
|
|
171096
|
+
const inferTarget = (current100ths, existing100ths) => {
|
|
171097
|
+
if (isStopped) return current100ths;
|
|
171098
|
+
if (movementStatus === MovementStatus.Opening) {
|
|
171099
|
+
if (existing100ths != null && current100ths != null && existing100ths < current100ths) {
|
|
171100
|
+
return existing100ths;
|
|
171101
|
+
}
|
|
171102
|
+
return 0;
|
|
171103
|
+
}
|
|
171104
|
+
if (movementStatus === MovementStatus.Closing) {
|
|
171105
|
+
if (existing100ths != null && current100ths != null && existing100ths > current100ths) {
|
|
171106
|
+
return existing100ths;
|
|
171107
|
+
}
|
|
171108
|
+
return 1e4;
|
|
171109
|
+
}
|
|
171110
|
+
return existing100ths ?? current100ths;
|
|
171111
|
+
};
|
|
170746
171112
|
logger175.debug(
|
|
170747
171113
|
`Cover update for ${entity.entity_id}: state=${state.state}, lift=${currentLift}%, tilt=${currentTilt}%, movement=${MovementStatus[movementStatus]}`
|
|
170748
171114
|
);
|
|
@@ -170769,14 +171135,18 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
|
|
|
170769
171135
|
...this.features.positionAwareLift ? {
|
|
170770
171136
|
currentPositionLiftPercentage: currentLift,
|
|
170771
171137
|
currentPositionLiftPercent100ths: currentLift100ths,
|
|
170772
|
-
|
|
170773
|
-
|
|
171138
|
+
targetPositionLiftPercent100ths: inferTarget(
|
|
171139
|
+
currentLift100ths,
|
|
171140
|
+
this.state.targetPositionLiftPercent100ths
|
|
171141
|
+
)
|
|
170774
171142
|
} : {},
|
|
170775
171143
|
...this.features.positionAwareTilt ? {
|
|
170776
171144
|
currentPositionTiltPercentage: currentTilt,
|
|
170777
171145
|
currentPositionTiltPercent100ths: currentTilt100ths,
|
|
170778
|
-
|
|
170779
|
-
|
|
171146
|
+
targetPositionTiltPercent100ths: inferTarget(
|
|
171147
|
+
currentTilt100ths,
|
|
171148
|
+
this.state.targetPositionTiltPercent100ths
|
|
171149
|
+
)
|
|
170780
171150
|
} : {}
|
|
170781
171151
|
}
|
|
170782
171152
|
);
|
|
@@ -170998,6 +171368,9 @@ var adjustPositionForWriting2 = (position, agent) => {
|
|
|
170998
171368
|
return adjustPositionForWriting(position, featureFlags, matterSem);
|
|
170999
171369
|
};
|
|
171000
171370
|
var shouldSwapOpenClose = (agent) => {
|
|
171371
|
+
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
171372
|
+
const entitySwap = homeAssistant.state.mapping?.coverSwapOpenClose;
|
|
171373
|
+
if (entitySwap !== void 0) return entitySwap;
|
|
171001
171374
|
const { featureFlags } = agent.env.get(BridgeDataProvider);
|
|
171002
171375
|
return featureFlags?.coverSwapOpenClose === true;
|
|
171003
171376
|
};
|
|
@@ -171094,25 +171467,6 @@ var CoverWindowCoveringServer = WindowCoveringServer2(config5);
|
|
|
171094
171467
|
|
|
171095
171468
|
// src/matter/endpoints/legacy/cover/index.ts
|
|
171096
171469
|
var logger177 = Logger.get("CoverDevice");
|
|
171097
|
-
var CoverPowerSourceServer = PowerSourceServer2({
|
|
171098
|
-
getBatteryPercent: (entity, agent) => {
|
|
171099
|
-
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
171100
|
-
const batteryEntity = homeAssistant.state.mapping?.batteryEntity;
|
|
171101
|
-
if (batteryEntity) {
|
|
171102
|
-
const stateProvider = agent.env.get(EntityStateProvider);
|
|
171103
|
-
const battery = stateProvider.getBatteryPercent(batteryEntity);
|
|
171104
|
-
if (battery != null) {
|
|
171105
|
-
return Math.max(0, Math.min(100, battery));
|
|
171106
|
-
}
|
|
171107
|
-
}
|
|
171108
|
-
const attrs = entity.attributes;
|
|
171109
|
-
const level = attrs.battery_level ?? attrs.battery;
|
|
171110
|
-
if (level == null || Number.isNaN(Number(level))) {
|
|
171111
|
-
return null;
|
|
171112
|
-
}
|
|
171113
|
-
return Number(level);
|
|
171114
|
-
}
|
|
171115
|
-
});
|
|
171116
171470
|
var CoverDeviceType = (supportedFeatures, hasBattery, entityId) => {
|
|
171117
171471
|
const features2 = /* @__PURE__ */ new Set();
|
|
171118
171472
|
if (testBit(supportedFeatures, CoverSupportedFeatures.support_open)) {
|
|
@@ -171147,7 +171501,10 @@ var CoverDeviceType = (supportedFeatures, hasBattery, entityId) => {
|
|
|
171147
171501
|
CoverWindowCoveringServer.with(...features2)
|
|
171148
171502
|
];
|
|
171149
171503
|
if (hasBattery) {
|
|
171150
|
-
return WindowCoveringDevice.with(
|
|
171504
|
+
return WindowCoveringDevice.with(
|
|
171505
|
+
...baseBehaviors,
|
|
171506
|
+
DefaultPowerSourceServer
|
|
171507
|
+
);
|
|
171151
171508
|
}
|
|
171152
171509
|
return WindowCoveringDevice.with(...baseBehaviors);
|
|
171153
171510
|
};
|
|
@@ -171268,25 +171625,6 @@ function EventDevice(homeAssistantEntity) {
|
|
|
171268
171625
|
// src/matter/endpoints/legacy/fan/index.ts
|
|
171269
171626
|
init_dist();
|
|
171270
171627
|
init_home_assistant_entity_behavior();
|
|
171271
|
-
var FanPowerSourceServer = PowerSourceServer2({
|
|
171272
|
-
getBatteryPercent: (entity, agent) => {
|
|
171273
|
-
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
171274
|
-
const batteryEntity = homeAssistant.state.mapping?.batteryEntity;
|
|
171275
|
-
if (batteryEntity) {
|
|
171276
|
-
const stateProvider = agent.env.get(EntityStateProvider);
|
|
171277
|
-
const battery = stateProvider.getBatteryPercent(batteryEntity);
|
|
171278
|
-
if (battery != null) {
|
|
171279
|
-
return Math.max(0, Math.min(100, battery));
|
|
171280
|
-
}
|
|
171281
|
-
}
|
|
171282
|
-
const attrs = entity.attributes;
|
|
171283
|
-
const level = attrs.battery_level ?? attrs.battery;
|
|
171284
|
-
if (level == null || Number.isNaN(Number(level))) {
|
|
171285
|
-
return null;
|
|
171286
|
-
}
|
|
171287
|
-
return Number(level);
|
|
171288
|
-
}
|
|
171289
|
-
});
|
|
171290
171628
|
function FanDevice2(homeAssistantEntity) {
|
|
171291
171629
|
const attributes7 = homeAssistantEntity.entity.state.attributes;
|
|
171292
171630
|
const supportedFeatures = attributes7.supported_features ?? 0;
|
|
@@ -171306,7 +171644,7 @@ function FanDevice2(homeAssistantEntity) {
|
|
|
171306
171644
|
BasicInformationServer2,
|
|
171307
171645
|
HomeAssistantEntityBehavior,
|
|
171308
171646
|
FanOnOffServer,
|
|
171309
|
-
|
|
171647
|
+
DefaultPowerSourceServer
|
|
171310
171648
|
) : OnOffPlugInUnitDevice.with(
|
|
171311
171649
|
IdentifyServer2,
|
|
171312
171650
|
BasicInformationServer2,
|
|
@@ -171341,7 +171679,7 @@ function FanDevice2(homeAssistantEntity) {
|
|
|
171341
171679
|
HomeAssistantEntityBehavior,
|
|
171342
171680
|
FanOnOffServer,
|
|
171343
171681
|
FanFanControlServer.with(...features2),
|
|
171344
|
-
|
|
171682
|
+
DefaultPowerSourceServer
|
|
171345
171683
|
) : FanDevice.with(
|
|
171346
171684
|
IdentifyServer2,
|
|
171347
171685
|
BasicInformationServer2,
|
|
@@ -171866,25 +172204,6 @@ var ColorTemperatureLightType = ColorTemperatureLightDevice.with(
|
|
|
171866
172204
|
|
|
171867
172205
|
// src/matter/endpoints/legacy/light/devices/dimmable-light.ts
|
|
171868
172206
|
init_home_assistant_entity_behavior();
|
|
171869
|
-
var LightPowerSourceServer = PowerSourceServer2({
|
|
171870
|
-
getBatteryPercent: (entity, agent) => {
|
|
171871
|
-
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
171872
|
-
const batteryEntity = homeAssistant.state.mapping?.batteryEntity;
|
|
171873
|
-
if (batteryEntity) {
|
|
171874
|
-
const stateProvider = agent.env.get(EntityStateProvider);
|
|
171875
|
-
const battery = stateProvider.getBatteryPercent(batteryEntity);
|
|
171876
|
-
if (battery != null) {
|
|
171877
|
-
return Math.max(0, Math.min(100, battery));
|
|
171878
|
-
}
|
|
171879
|
-
}
|
|
171880
|
-
const attrs = entity.attributes;
|
|
171881
|
-
const level = attrs.battery_level ?? attrs.battery;
|
|
171882
|
-
if (level == null || Number.isNaN(Number(level))) {
|
|
171883
|
-
return null;
|
|
171884
|
-
}
|
|
171885
|
-
return Number(level);
|
|
171886
|
-
}
|
|
171887
|
-
});
|
|
171888
172207
|
var DimmableLightType = DimmableLightDevice.with(
|
|
171889
172208
|
IdentifyServer2,
|
|
171890
172209
|
BasicInformationServer2,
|
|
@@ -171898,30 +172217,11 @@ var DimmableLightWithBatteryType = DimmableLightDevice.with(
|
|
|
171898
172217
|
HomeAssistantEntityBehavior,
|
|
171899
172218
|
LightOnOffServer,
|
|
171900
172219
|
LightLevelControlServer,
|
|
171901
|
-
|
|
172220
|
+
DefaultPowerSourceServer
|
|
171902
172221
|
);
|
|
171903
172222
|
|
|
171904
172223
|
// src/matter/endpoints/legacy/light/devices/extended-color-light.ts
|
|
171905
172224
|
init_home_assistant_entity_behavior();
|
|
171906
|
-
var LightPowerSourceServer2 = PowerSourceServer2({
|
|
171907
|
-
getBatteryPercent: (entity, agent) => {
|
|
171908
|
-
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
171909
|
-
const batteryEntity = homeAssistant.state.mapping?.batteryEntity;
|
|
171910
|
-
if (batteryEntity) {
|
|
171911
|
-
const stateProvider = agent.env.get(EntityStateProvider);
|
|
171912
|
-
const battery = stateProvider.getBatteryPercent(batteryEntity);
|
|
171913
|
-
if (battery != null) {
|
|
171914
|
-
return Math.max(0, Math.min(100, battery));
|
|
171915
|
-
}
|
|
171916
|
-
}
|
|
171917
|
-
const attrs = entity.attributes;
|
|
171918
|
-
const level = attrs.battery_level ?? attrs.battery;
|
|
171919
|
-
if (level == null || Number.isNaN(Number(level))) {
|
|
171920
|
-
return null;
|
|
171921
|
-
}
|
|
171922
|
-
return Number(level);
|
|
171923
|
-
}
|
|
171924
|
-
});
|
|
171925
172225
|
var ExtendedColorLightType = (supportsColorControl, supportsTemperature, hasBattery = false) => {
|
|
171926
172226
|
const features2 = /* @__PURE__ */ new Set();
|
|
171927
172227
|
if (supportsColorControl) {
|
|
@@ -171938,7 +172238,7 @@ var ExtendedColorLightType = (supportsColorControl, supportsTemperature, hasBatt
|
|
|
171938
172238
|
LightOnOffServer,
|
|
171939
172239
|
LightLevelControlServer,
|
|
171940
172240
|
LightColorControlServer.with(...features2),
|
|
171941
|
-
|
|
172241
|
+
DefaultPowerSourceServer
|
|
171942
172242
|
);
|
|
171943
172243
|
}
|
|
171944
172244
|
return ExtendedColorLightDevice.with(
|
|
@@ -171953,25 +172253,6 @@ var ExtendedColorLightType = (supportsColorControl, supportsTemperature, hasBatt
|
|
|
171953
172253
|
|
|
171954
172254
|
// src/matter/endpoints/legacy/light/devices/on-off-light-device.ts
|
|
171955
172255
|
init_home_assistant_entity_behavior();
|
|
171956
|
-
var LightPowerSourceServer3 = PowerSourceServer2({
|
|
171957
|
-
getBatteryPercent: (entity, agent) => {
|
|
171958
|
-
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
171959
|
-
const batteryEntity = homeAssistant.state.mapping?.batteryEntity;
|
|
171960
|
-
if (batteryEntity) {
|
|
171961
|
-
const stateProvider = agent.env.get(EntityStateProvider);
|
|
171962
|
-
const battery = stateProvider.getBatteryPercent(batteryEntity);
|
|
171963
|
-
if (battery != null) {
|
|
171964
|
-
return Math.max(0, Math.min(100, battery));
|
|
171965
|
-
}
|
|
171966
|
-
}
|
|
171967
|
-
const attrs = entity.attributes;
|
|
171968
|
-
const level = attrs.battery_level ?? attrs.battery;
|
|
171969
|
-
if (level == null || Number.isNaN(Number(level))) {
|
|
171970
|
-
return null;
|
|
171971
|
-
}
|
|
171972
|
-
return Number(level);
|
|
171973
|
-
}
|
|
171974
|
-
});
|
|
171975
172256
|
var OnOffLightType = OnOffLightDevice.with(
|
|
171976
172257
|
IdentifyServer2,
|
|
171977
172258
|
BasicInformationServer2,
|
|
@@ -171983,7 +172264,7 @@ var OnOffLightWithBatteryType = OnOffLightDevice.with(
|
|
|
171983
172264
|
BasicInformationServer2,
|
|
171984
172265
|
HomeAssistantEntityBehavior,
|
|
171985
172266
|
LightOnOffServer,
|
|
171986
|
-
|
|
172267
|
+
DefaultPowerSourceServer
|
|
171987
172268
|
);
|
|
171988
172269
|
|
|
171989
172270
|
// src/matter/endpoints/legacy/light/index.ts
|
|
@@ -172674,25 +172955,6 @@ var lockServerConfig = {
|
|
|
172674
172955
|
unlock: () => ({ action: "lock.unlock" }),
|
|
172675
172956
|
unlatch: () => ({ action: "lock.open" })
|
|
172676
172957
|
};
|
|
172677
|
-
var LockPowerSourceServer = PowerSourceServer2({
|
|
172678
|
-
getBatteryPercent: (entity, agent) => {
|
|
172679
|
-
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
172680
|
-
const batteryEntity = homeAssistant.state.mapping?.batteryEntity;
|
|
172681
|
-
if (batteryEntity) {
|
|
172682
|
-
const stateProvider = agent.env.get(EntityStateProvider);
|
|
172683
|
-
const battery = stateProvider.getBatteryPercent(batteryEntity);
|
|
172684
|
-
if (battery != null) {
|
|
172685
|
-
return Math.max(0, Math.min(100, battery));
|
|
172686
|
-
}
|
|
172687
|
-
}
|
|
172688
|
-
const attrs = entity.attributes;
|
|
172689
|
-
const level = attrs.battery_level ?? attrs.battery;
|
|
172690
|
-
if (level == null || Number.isNaN(Number(level))) {
|
|
172691
|
-
return null;
|
|
172692
|
-
}
|
|
172693
|
-
return Number(level);
|
|
172694
|
-
}
|
|
172695
|
-
});
|
|
172696
172958
|
var LockDeviceType = DoorLockDevice.with(
|
|
172697
172959
|
BasicInformationServer2,
|
|
172698
172960
|
IdentifyServer2,
|
|
@@ -172704,7 +172966,7 @@ var LockWithBatteryDeviceType = DoorLockDevice.with(
|
|
|
172704
172966
|
IdentifyServer2,
|
|
172705
172967
|
HomeAssistantEntityBehavior,
|
|
172706
172968
|
LockServerWithPin(lockServerConfig),
|
|
172707
|
-
|
|
172969
|
+
DefaultPowerSourceServer
|
|
172708
172970
|
);
|
|
172709
172971
|
var LockWithUnlatchDeviceType = DoorLockDevice.with(
|
|
172710
172972
|
BasicInformationServer2,
|
|
@@ -172717,7 +172979,7 @@ var LockWithUnlatchAndBatteryDeviceType = DoorLockDevice.with(
|
|
|
172717
172979
|
IdentifyServer2,
|
|
172718
172980
|
HomeAssistantEntityBehavior,
|
|
172719
172981
|
LockServerWithPinAndUnbolt(lockServerConfig),
|
|
172720
|
-
|
|
172982
|
+
DefaultPowerSourceServer
|
|
172721
172983
|
);
|
|
172722
172984
|
function LockDevice(homeAssistantEntity) {
|
|
172723
172985
|
const attrs = homeAssistantEntity.entity.state.attributes;
|
|
@@ -173293,8 +173555,20 @@ var PumpType = PumpDevice.with(
|
|
|
173293
173555
|
PumpOnOffServer,
|
|
173294
173556
|
PumpConfigurationAndControlServer2
|
|
173295
173557
|
);
|
|
173558
|
+
var PumpWithBatteryType = PumpDevice.with(
|
|
173559
|
+
IdentifyServer2,
|
|
173560
|
+
BasicInformationServer2,
|
|
173561
|
+
HomeAssistantEntityBehavior,
|
|
173562
|
+
PumpOnOffServer,
|
|
173563
|
+
PumpConfigurationAndControlServer2,
|
|
173564
|
+
DefaultPowerSourceServer
|
|
173565
|
+
);
|
|
173296
173566
|
function PumpEndpoint(homeAssistantEntity) {
|
|
173297
|
-
|
|
173567
|
+
const attrs = homeAssistantEntity.entity.state.attributes;
|
|
173568
|
+
const hasBatteryAttr = attrs.battery_level != null || attrs.battery != null;
|
|
173569
|
+
const hasBatteryEntity = !!homeAssistantEntity.mapping?.batteryEntity;
|
|
173570
|
+
const device = hasBatteryAttr || hasBatteryEntity ? PumpWithBatteryType : PumpType;
|
|
173571
|
+
return device.set({ homeAssistantEntity });
|
|
173298
173572
|
}
|
|
173299
173573
|
|
|
173300
173574
|
// src/matter/endpoints/legacy/remote/index.ts
|
|
@@ -173339,12 +173613,11 @@ function SceneDevice(homeAssistantEntity) {
|
|
|
173339
173613
|
// src/matter/endpoints/legacy/script/index.ts
|
|
173340
173614
|
init_home_assistant_entity_behavior();
|
|
173341
173615
|
var ScriptOnOffServer = OnOffServer2({
|
|
173616
|
+
isOn: () => false,
|
|
173342
173617
|
turnOn: () => ({
|
|
173343
173618
|
action: "script.turn_on"
|
|
173344
173619
|
}),
|
|
173345
|
-
turnOff:
|
|
173346
|
-
action: "script.turn_off"
|
|
173347
|
-
})
|
|
173620
|
+
turnOff: null
|
|
173348
173621
|
});
|
|
173349
173622
|
var ScriptDeviceType = OnOffPlugInUnitDevice.with(
|
|
173350
173623
|
BasicInformationServer2,
|
|
@@ -174816,7 +175089,7 @@ var Pm25SensorType = AirQualitySensorDevice.with(
|
|
|
174816
175089
|
|
|
174817
175090
|
// src/matter/endpoints/legacy/sensor/devices/temperature-humidity-sensor.ts
|
|
174818
175091
|
init_home_assistant_entity_behavior();
|
|
174819
|
-
var
|
|
175092
|
+
var temperatureConfig3 = {
|
|
174820
175093
|
getValue(entity, agent) {
|
|
174821
175094
|
const fallbackUnit = agent.env.get(HomeAssistantConfig).unitSystem.temperature;
|
|
174822
175095
|
const state = entity.state;
|
|
@@ -174831,7 +175104,7 @@ var temperatureConfig2 = {
|
|
|
174831
175104
|
);
|
|
174832
175105
|
}
|
|
174833
175106
|
};
|
|
174834
|
-
var
|
|
175107
|
+
var humidityConfig4 = {
|
|
174835
175108
|
getValue(_entity, agent) {
|
|
174836
175109
|
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
174837
175110
|
const humidityEntity = homeAssistant.state.mapping?.humidityEntity;
|
|
@@ -174881,38 +175154,38 @@ var TemperatureHumiditySensorType = TemperatureSensorDevice.with(
|
|
|
174881
175154
|
BasicInformationServer2,
|
|
174882
175155
|
IdentifyServer2,
|
|
174883
175156
|
HomeAssistantEntityBehavior,
|
|
174884
|
-
TemperatureMeasurementServer2(
|
|
174885
|
-
HumidityMeasurementServer(
|
|
175157
|
+
TemperatureMeasurementServer2(temperatureConfig3),
|
|
175158
|
+
HumidityMeasurementServer(humidityConfig4)
|
|
174886
175159
|
);
|
|
174887
175160
|
var TemperatureHumiditySensorWithBatteryType = TemperatureSensorDevice.with(
|
|
174888
175161
|
BasicInformationServer2,
|
|
174889
175162
|
IdentifyServer2,
|
|
174890
175163
|
HomeAssistantEntityBehavior,
|
|
174891
|
-
TemperatureMeasurementServer2(
|
|
174892
|
-
HumidityMeasurementServer(
|
|
175164
|
+
TemperatureMeasurementServer2(temperatureConfig3),
|
|
175165
|
+
HumidityMeasurementServer(humidityConfig4),
|
|
174893
175166
|
PowerSourceServer2(batteryConfig4)
|
|
174894
175167
|
);
|
|
174895
175168
|
var TemperatureHumidityPressureSensorType = TemperatureSensorDevice.with(
|
|
174896
175169
|
BasicInformationServer2,
|
|
174897
175170
|
IdentifyServer2,
|
|
174898
175171
|
HomeAssistantEntityBehavior,
|
|
174899
|
-
TemperatureMeasurementServer2(
|
|
174900
|
-
HumidityMeasurementServer(
|
|
175172
|
+
TemperatureMeasurementServer2(temperatureConfig3),
|
|
175173
|
+
HumidityMeasurementServer(humidityConfig4),
|
|
174901
175174
|
PressureMeasurementServer2(pressureConfig2)
|
|
174902
175175
|
);
|
|
174903
175176
|
var TemperatureHumidityPressureSensorWithBatteryType = TemperatureSensorDevice.with(
|
|
174904
175177
|
BasicInformationServer2,
|
|
174905
175178
|
IdentifyServer2,
|
|
174906
175179
|
HomeAssistantEntityBehavior,
|
|
174907
|
-
TemperatureMeasurementServer2(
|
|
174908
|
-
HumidityMeasurementServer(
|
|
175180
|
+
TemperatureMeasurementServer2(temperatureConfig3),
|
|
175181
|
+
HumidityMeasurementServer(humidityConfig4),
|
|
174909
175182
|
PressureMeasurementServer2(pressureConfig2),
|
|
174910
175183
|
PowerSourceServer2(batteryConfig4)
|
|
174911
175184
|
);
|
|
174912
175185
|
|
|
174913
175186
|
// src/matter/endpoints/legacy/sensor/devices/temperature-pressure-sensor.ts
|
|
174914
175187
|
init_home_assistant_entity_behavior();
|
|
174915
|
-
var
|
|
175188
|
+
var temperatureConfig4 = {
|
|
174916
175189
|
getValue(entity, agent) {
|
|
174917
175190
|
const fallbackUnit = agent.env.get(HomeAssistantConfig).unitSystem.temperature;
|
|
174918
175191
|
const state = entity.state;
|
|
@@ -174963,14 +175236,14 @@ var TemperaturePressureSensorType = TemperatureSensorDevice.with(
|
|
|
174963
175236
|
BasicInformationServer2,
|
|
174964
175237
|
IdentifyServer2,
|
|
174965
175238
|
HomeAssistantEntityBehavior,
|
|
174966
|
-
TemperatureMeasurementServer2(
|
|
175239
|
+
TemperatureMeasurementServer2(temperatureConfig4),
|
|
174967
175240
|
PressureMeasurementServer2(pressureConfig3)
|
|
174968
175241
|
);
|
|
174969
175242
|
var TemperaturePressureSensorWithBatteryType = TemperatureSensorDevice.with(
|
|
174970
175243
|
BasicInformationServer2,
|
|
174971
175244
|
IdentifyServer2,
|
|
174972
175245
|
HomeAssistantEntityBehavior,
|
|
174973
|
-
TemperatureMeasurementServer2(
|
|
175246
|
+
TemperatureMeasurementServer2(temperatureConfig4),
|
|
174974
175247
|
PressureMeasurementServer2(pressureConfig3),
|
|
174975
175248
|
PowerSourceServer2(batteryConfig5)
|
|
174976
175249
|
);
|
|
@@ -175076,6 +175349,16 @@ function SensorDevice(homeAssistantEntity) {
|
|
|
175076
175349
|
return void 0;
|
|
175077
175350
|
}
|
|
175078
175351
|
|
|
175352
|
+
// src/matter/endpoints/legacy/switch/dimmable-plugin-unit.ts
|
|
175353
|
+
init_home_assistant_entity_behavior();
|
|
175354
|
+
var DimmablePlugInUnitType = DimmablePlugInUnitDevice.with(
|
|
175355
|
+
IdentifyServer2,
|
|
175356
|
+
BasicInformationServer2,
|
|
175357
|
+
HomeAssistantEntityBehavior,
|
|
175358
|
+
LightOnOffServer,
|
|
175359
|
+
LightLevelControlServer
|
|
175360
|
+
);
|
|
175361
|
+
|
|
175079
175362
|
// src/matter/endpoints/legacy/switch/index.ts
|
|
175080
175363
|
init_home_assistant_entity_behavior();
|
|
175081
175364
|
var SwitchOnOffServer = OnOffServer2();
|
|
@@ -175090,25 +175373,7 @@ var SwitchWithBatteryEndpointType = OnOffPlugInUnitDevice.with(
|
|
|
175090
175373
|
IdentifyServer2,
|
|
175091
175374
|
HomeAssistantEntityBehavior,
|
|
175092
175375
|
SwitchOnOffServer,
|
|
175093
|
-
|
|
175094
|
-
getBatteryPercent: (entity, agent) => {
|
|
175095
|
-
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
175096
|
-
const batteryEntity = homeAssistant.state.mapping?.batteryEntity;
|
|
175097
|
-
if (batteryEntity) {
|
|
175098
|
-
const stateProvider = agent.env.get(EntityStateProvider);
|
|
175099
|
-
const battery = stateProvider.getBatteryPercent(batteryEntity);
|
|
175100
|
-
if (battery != null) {
|
|
175101
|
-
return Math.max(0, Math.min(100, battery));
|
|
175102
|
-
}
|
|
175103
|
-
}
|
|
175104
|
-
const attrs = entity.attributes;
|
|
175105
|
-
const level = attrs.battery_level ?? attrs.battery;
|
|
175106
|
-
if (level == null || Number.isNaN(Number(level))) {
|
|
175107
|
-
return null;
|
|
175108
|
-
}
|
|
175109
|
-
return Number(level);
|
|
175110
|
-
}
|
|
175111
|
-
})
|
|
175376
|
+
DefaultPowerSourceServer
|
|
175112
175377
|
);
|
|
175113
175378
|
function SwitchDevice(homeAssistantEntity) {
|
|
175114
175379
|
const attrs = homeAssistantEntity.entity.state.attributes;
|
|
@@ -175703,9 +175968,51 @@ function createCustomServiceAreaServer(customAreas) {
|
|
|
175703
175968
|
currentArea: null
|
|
175704
175969
|
});
|
|
175705
175970
|
}
|
|
175971
|
+
function createCleanAreaServiceAreaServer(cleanAreaRooms) {
|
|
175972
|
+
const supportedAreas = cleanAreaRooms.map((room) => ({
|
|
175973
|
+
areaId: room.areaId,
|
|
175974
|
+
mapId: null,
|
|
175975
|
+
areaInfo: {
|
|
175976
|
+
locationInfo: {
|
|
175977
|
+
locationName: room.name,
|
|
175978
|
+
floorNumber: null,
|
|
175979
|
+
areaType: null
|
|
175980
|
+
},
|
|
175981
|
+
landmarkInfo: null
|
|
175982
|
+
}
|
|
175983
|
+
}));
|
|
175984
|
+
logger190.info(
|
|
175985
|
+
`Using ${cleanAreaRooms.length} HA areas via CLEAN_AREA: ${cleanAreaRooms.map((r) => r.name).join(", ")}`
|
|
175986
|
+
);
|
|
175987
|
+
return ServiceAreaServer2({
|
|
175988
|
+
supportedAreas,
|
|
175989
|
+
selectedAreas: [],
|
|
175990
|
+
currentArea: null
|
|
175991
|
+
});
|
|
175992
|
+
}
|
|
175706
175993
|
|
|
175707
175994
|
// src/matter/endpoints/legacy/vacuum/behaviors/vacuum-rvc-run-mode-server.ts
|
|
175708
175995
|
var logger191 = Logger.get("VacuumRvcRunModeServer");
|
|
175996
|
+
function buildValetudoSegmentAction(vacuumEntityId, segmentIds, valetudoIdentifier) {
|
|
175997
|
+
const identifier = valetudoIdentifier || vacuumEntityId.replace(/^vacuum\.valetudo_/, "");
|
|
175998
|
+
const topic = `valetudo/${identifier}/MapSegmentationCapability/clean/set`;
|
|
175999
|
+
logger191.info(
|
|
176000
|
+
`Valetudo: mqtt.publish to ${topic}, segments: ${segmentIds.join(", ")}`
|
|
176001
|
+
);
|
|
176002
|
+
return {
|
|
176003
|
+
action: "mqtt.publish",
|
|
176004
|
+
target: false,
|
|
176005
|
+
data: {
|
|
176006
|
+
topic,
|
|
176007
|
+
payload: JSON.stringify({
|
|
176008
|
+
action: "start_segment_action",
|
|
176009
|
+
segment_ids: segmentIds.map(String),
|
|
176010
|
+
iterations: 1,
|
|
176011
|
+
customOrder: true
|
|
176012
|
+
})
|
|
176013
|
+
}
|
|
176014
|
+
};
|
|
176015
|
+
}
|
|
175709
176016
|
function buildSupportedModes2(attributes7, includeUnnamedRooms = false, customAreas) {
|
|
175710
176017
|
const modes = [
|
|
175711
176018
|
{
|
|
@@ -175774,6 +176081,16 @@ function handleCustomServiceAreas(selectedAreas, customAreas, homeAssistant, ser
|
|
|
175774
176081
|
data: first.data
|
|
175775
176082
|
};
|
|
175776
176083
|
}
|
|
176084
|
+
function resolveCleanAreaIds(selectedAreas, cleanAreaRooms) {
|
|
176085
|
+
const haAreaIds = [];
|
|
176086
|
+
for (const areaId of selectedAreas) {
|
|
176087
|
+
const room = cleanAreaRooms.find((r) => r.areaId === areaId);
|
|
176088
|
+
if (room) {
|
|
176089
|
+
haAreaIds.push(room.haAreaId);
|
|
176090
|
+
}
|
|
176091
|
+
}
|
|
176092
|
+
return haAreaIds;
|
|
176093
|
+
}
|
|
175777
176094
|
var vacuumRvcRunModeConfig = {
|
|
175778
176095
|
getCurrentMode: (entity) => {
|
|
175779
176096
|
const state = entity.state;
|
|
@@ -175812,6 +176129,20 @@ var vacuumRvcRunModeConfig = {
|
|
|
175812
176129
|
serviceArea
|
|
175813
176130
|
);
|
|
175814
176131
|
}
|
|
176132
|
+
const cleanAreaRooms = homeAssistant.state.mapping?.cleanAreaRooms;
|
|
176133
|
+
if (cleanAreaRooms && cleanAreaRooms.length > 0) {
|
|
176134
|
+
const haAreaIds = resolveCleanAreaIds(selectedAreas, cleanAreaRooms);
|
|
176135
|
+
serviceArea.state.selectedAreas = [];
|
|
176136
|
+
if (haAreaIds.length > 0) {
|
|
176137
|
+
logger191.info(
|
|
176138
|
+
`CLEAN_AREA: cleaning HA areas: ${haAreaIds.join(", ")}`
|
|
176139
|
+
);
|
|
176140
|
+
return {
|
|
176141
|
+
action: "vacuum.clean_area",
|
|
176142
|
+
data: { cleaning_area_id: haAreaIds }
|
|
176143
|
+
};
|
|
176144
|
+
}
|
|
176145
|
+
}
|
|
175815
176146
|
const roomEntities = homeAssistant.state.mapping?.roomEntities;
|
|
175816
176147
|
if (roomEntities && roomEntities.length > 0) {
|
|
175817
176148
|
const buttonEntityIds = [];
|
|
@@ -175840,6 +176171,15 @@ var vacuumRvcRunModeConfig = {
|
|
|
175840
176171
|
};
|
|
175841
176172
|
}
|
|
175842
176173
|
}
|
|
176174
|
+
const vacuumEntityId = homeAssistant.entityId;
|
|
176175
|
+
if (vacuumEntityId.startsWith("vacuum.valetudo_")) {
|
|
176176
|
+
serviceArea.state.selectedAreas = [];
|
|
176177
|
+
return buildValetudoSegmentAction(
|
|
176178
|
+
vacuumEntityId,
|
|
176179
|
+
selectedAreas,
|
|
176180
|
+
homeAssistant.state.mapping?.valetudoIdentifier
|
|
176181
|
+
);
|
|
176182
|
+
}
|
|
175843
176183
|
const rooms = parseVacuumRooms(attributes7);
|
|
175844
176184
|
const roomIds = [];
|
|
175845
176185
|
let targetMapName;
|
|
@@ -175857,25 +176197,6 @@ var vacuumRvcRunModeConfig = {
|
|
|
175857
176197
|
`Starting cleaning with selected areas: ${roomIds.join(", ")}`
|
|
175858
176198
|
);
|
|
175859
176199
|
serviceArea.state.selectedAreas = [];
|
|
175860
|
-
const vacuumEntityId = homeAssistant.entityId;
|
|
175861
|
-
if (vacuumEntityId.startsWith("vacuum.valetudo_")) {
|
|
175862
|
-
const identifier = vacuumEntityId.replace(/^vacuum\.valetudo_/, "");
|
|
175863
|
-
logger191.info(
|
|
175864
|
-
`Valetudo vacuum: Using mqtt.publish segment_cleanup for rooms: ${roomIds.join(", ")}`
|
|
175865
|
-
);
|
|
175866
|
-
return {
|
|
175867
|
-
action: "mqtt.publish",
|
|
175868
|
-
target: false,
|
|
175869
|
-
data: {
|
|
175870
|
-
topic: `valetudo/${identifier}/MapSegmentationCapability/clean/set`,
|
|
175871
|
-
payload: JSON.stringify({
|
|
175872
|
-
segment_ids: roomIds.map(String),
|
|
175873
|
-
iterations: 1,
|
|
175874
|
-
customOrder: true
|
|
175875
|
-
})
|
|
175876
|
-
}
|
|
175877
|
-
};
|
|
175878
|
-
}
|
|
175879
176200
|
if (isDreameVacuum(attributes7)) {
|
|
175880
176201
|
if (targetMapName) {
|
|
175881
176202
|
const vacName = vacuumEntityId.replace("vacuum.", "");
|
|
@@ -175945,6 +176266,23 @@ var vacuumRvcRunModeConfig = {
|
|
|
175945
176266
|
const entity = homeAssistant.entity;
|
|
175946
176267
|
const attributes7 = entity.state.attributes;
|
|
175947
176268
|
logger191.info(`cleanRoom called: roomMode=${roomMode}`);
|
|
176269
|
+
const cleanAreaRooms = homeAssistant.state.mapping?.cleanAreaRooms;
|
|
176270
|
+
if (cleanAreaRooms && cleanAreaRooms.length > 0) {
|
|
176271
|
+
const sorted = [...cleanAreaRooms].sort(
|
|
176272
|
+
(a, b) => a.name.localeCompare(b.name)
|
|
176273
|
+
);
|
|
176274
|
+
const areaIndex = roomMode - ROOM_MODE_BASE2 - 1;
|
|
176275
|
+
if (areaIndex >= 0 && areaIndex < sorted.length) {
|
|
176276
|
+
const area = sorted[areaIndex];
|
|
176277
|
+
logger191.info(
|
|
176278
|
+
`cleanRoom: CLEAN_AREA "${area.name}" \u2192 vacuum.clean_area(${area.haAreaId})`
|
|
176279
|
+
);
|
|
176280
|
+
return {
|
|
176281
|
+
action: "vacuum.clean_area",
|
|
176282
|
+
data: { cleaning_area_id: [area.haAreaId] }
|
|
176283
|
+
};
|
|
176284
|
+
}
|
|
176285
|
+
}
|
|
175948
176286
|
const customAreas = homeAssistant.state.mapping?.customServiceAreas;
|
|
175949
176287
|
if (customAreas && customAreas.length > 0) {
|
|
175950
176288
|
const sorted = [...customAreas].sort(
|
|
@@ -175963,6 +176301,15 @@ var vacuumRvcRunModeConfig = {
|
|
|
175963
176301
|
};
|
|
175964
176302
|
}
|
|
175965
176303
|
}
|
|
176304
|
+
const vacuumEntityId = entity.entity_id;
|
|
176305
|
+
if (vacuumEntityId.startsWith("vacuum.valetudo_")) {
|
|
176306
|
+
const segmentId = getRoomIdFromMode(roomMode);
|
|
176307
|
+
return buildValetudoSegmentAction(
|
|
176308
|
+
vacuumEntityId,
|
|
176309
|
+
[segmentId],
|
|
176310
|
+
homeAssistant.state.mapping?.valetudoIdentifier
|
|
176311
|
+
);
|
|
176312
|
+
}
|
|
175966
176313
|
const rooms = parseVacuumRooms(attributes7);
|
|
175967
176314
|
const numericIdFromMode = getRoomIdFromMode(roomMode);
|
|
175968
176315
|
logger191.info(
|
|
@@ -175971,25 +176318,6 @@ var vacuumRvcRunModeConfig = {
|
|
|
175971
176318
|
const room = rooms.find((r) => getRoomModeValue(r) === roomMode);
|
|
175972
176319
|
if (room) {
|
|
175973
176320
|
const commandId3 = room.originalId ?? room.id;
|
|
175974
|
-
const vacuumEntityId = entity.entity_id;
|
|
175975
|
-
if (vacuumEntityId.startsWith("vacuum.valetudo_")) {
|
|
175976
|
-
const identifier = vacuumEntityId.replace(/^vacuum\.valetudo_/, "");
|
|
175977
|
-
logger191.info(
|
|
175978
|
-
`Valetudo vacuum: Using mqtt.publish segment_cleanup for room ${room.name} (id: ${commandId3})`
|
|
175979
|
-
);
|
|
175980
|
-
return {
|
|
175981
|
-
action: "mqtt.publish",
|
|
175982
|
-
target: false,
|
|
175983
|
-
data: {
|
|
175984
|
-
topic: `valetudo/${identifier}/MapSegmentationCapability/clean/set`,
|
|
175985
|
-
payload: JSON.stringify({
|
|
175986
|
-
segment_ids: [String(commandId3)],
|
|
175987
|
-
iterations: 1,
|
|
175988
|
-
customOrder: true
|
|
175989
|
-
})
|
|
175990
|
-
}
|
|
175991
|
-
};
|
|
175992
|
-
}
|
|
175993
176321
|
if (isDreameVacuum(attributes7)) {
|
|
175994
176322
|
if (room.mapName) {
|
|
175995
176323
|
const vacuumName = vacuumEntityId.replace("vacuum.", "");
|
|
@@ -176080,6 +176408,39 @@ function createVacuumRvcRunModeServer(attributes7, includeUnnamedRooms = false,
|
|
|
176080
176408
|
currentMode: 0 /* Idle */
|
|
176081
176409
|
});
|
|
176082
176410
|
}
|
|
176411
|
+
function createCleanAreaRvcRunModeServer(cleanAreaRooms) {
|
|
176412
|
+
const modes = [
|
|
176413
|
+
{
|
|
176414
|
+
label: "Idle",
|
|
176415
|
+
mode: 0 /* Idle */,
|
|
176416
|
+
modeTags: [{ value: RvcRunMode3.ModeTag.Idle }]
|
|
176417
|
+
},
|
|
176418
|
+
{
|
|
176419
|
+
label: "Cleaning",
|
|
176420
|
+
mode: 1 /* Cleaning */,
|
|
176421
|
+
modeTags: [{ value: RvcRunMode3.ModeTag.Cleaning }]
|
|
176422
|
+
}
|
|
176423
|
+
];
|
|
176424
|
+
const sorted = [...cleanAreaRooms].sort(
|
|
176425
|
+
(a, b) => a.name.localeCompare(b.name)
|
|
176426
|
+
);
|
|
176427
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
176428
|
+
const modeValue = ROOM_MODE_BASE2 + i + 1;
|
|
176429
|
+
if (modeValue > 255) continue;
|
|
176430
|
+
modes.push({
|
|
176431
|
+
label: sorted[i].name,
|
|
176432
|
+
mode: modeValue,
|
|
176433
|
+
modeTags: [{ value: RvcRunMode3.ModeTag.Cleaning }]
|
|
176434
|
+
});
|
|
176435
|
+
}
|
|
176436
|
+
logger191.info(
|
|
176437
|
+
`Creating CLEAN_AREA RvcRunModeServer with ${cleanAreaRooms.length} HA areas, ${modes.length} total modes`
|
|
176438
|
+
);
|
|
176439
|
+
return RvcRunModeServer2(vacuumRvcRunModeConfig, {
|
|
176440
|
+
supportedModes: modes,
|
|
176441
|
+
currentMode: 0 /* Idle */
|
|
176442
|
+
});
|
|
176443
|
+
}
|
|
176083
176444
|
var VacuumRvcRunModeServer = RvcRunModeServer2(vacuumRvcRunModeConfig);
|
|
176084
176445
|
|
|
176085
176446
|
// src/matter/endpoints/legacy/vacuum/behaviors/vacuum-on-off-server.ts
|
|
@@ -176105,10 +176466,14 @@ var VacuumPowerSourceServer = PowerSourceServer2({
|
|
|
176105
176466
|
}
|
|
176106
176467
|
const attributes7 = entity.attributes;
|
|
176107
176468
|
const batteryLevel = attributes7.battery_level ?? attributes7.battery;
|
|
176108
|
-
if (batteryLevel == null
|
|
176469
|
+
if (batteryLevel == null) {
|
|
176109
176470
|
return null;
|
|
176110
176471
|
}
|
|
176111
|
-
|
|
176472
|
+
if (typeof batteryLevel === "number") {
|
|
176473
|
+
return batteryLevel;
|
|
176474
|
+
}
|
|
176475
|
+
const parsed = Number.parseFloat(String(batteryLevel));
|
|
176476
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
176112
176477
|
},
|
|
176113
176478
|
isCharging(entity) {
|
|
176114
176479
|
const state = entity.state;
|
|
@@ -177077,8 +177442,9 @@ function VacuumDevice(homeAssistantEntity, includeOnOff = false, cleaningModeOpt
|
|
|
177077
177442
|
logger196.info(
|
|
177078
177443
|
`Creating vacuum endpoint for ${entityId}, mapping: ${JSON.stringify(homeAssistantEntity.mapping ?? "none")}`
|
|
177079
177444
|
);
|
|
177445
|
+
const cleanAreaRooms = homeAssistantEntity.mapping?.cleanAreaRooms;
|
|
177080
177446
|
let device = VacuumEndpointType.with(
|
|
177081
|
-
createVacuumRvcRunModeServer(
|
|
177447
|
+
cleanAreaRooms && cleanAreaRooms.length > 0 ? createCleanAreaRvcRunModeServer(cleanAreaRooms) : createVacuumRvcRunModeServer(
|
|
177082
177448
|
attributes7,
|
|
177083
177449
|
false,
|
|
177084
177450
|
customAreas && customAreas.length > 0 ? customAreas : void 0
|
|
@@ -177092,9 +177458,14 @@ function VacuumDevice(homeAssistantEntity, includeOnOff = false, cleaningModeOpt
|
|
|
177092
177458
|
const roomEntities = homeAssistantEntity.mapping?.roomEntities;
|
|
177093
177459
|
const rooms = parseVacuumRooms(attributes7);
|
|
177094
177460
|
logger196.info(
|
|
177095
|
-
`${entityId}: customAreas=${customAreas?.length ?? 0}, roomEntities=${JSON.stringify(roomEntities ?? [])}, parsedRooms=${rooms.length}`
|
|
177461
|
+
`${entityId}: customAreas=${customAreas?.length ?? 0}, roomEntities=${JSON.stringify(roomEntities ?? [])}, parsedRooms=${rooms.length}, cleanAreaRooms=${cleanAreaRooms?.length ?? 0}`
|
|
177096
177462
|
);
|
|
177097
|
-
if (
|
|
177463
|
+
if (cleanAreaRooms && cleanAreaRooms.length > 0) {
|
|
177464
|
+
logger196.info(
|
|
177465
|
+
`${entityId}: Adding ServiceArea (${cleanAreaRooms.length} HA areas via CLEAN_AREA)`
|
|
177466
|
+
);
|
|
177467
|
+
device = device.with(createCleanAreaServiceAreaServer(cleanAreaRooms));
|
|
177468
|
+
} else if (customAreas && customAreas.length > 0) {
|
|
177098
177469
|
logger196.info(
|
|
177099
177470
|
`${entityId}: Adding ServiceArea (${customAreas.length} custom areas)`
|
|
177100
177471
|
);
|
|
@@ -177199,8 +177570,19 @@ var ValveEndpointType = WaterValveDevice.with(
|
|
|
177199
177570
|
HomeAssistantEntityBehavior,
|
|
177200
177571
|
ValveServer
|
|
177201
177572
|
);
|
|
177573
|
+
var ValveWithBatteryEndpointType = WaterValveDevice.with(
|
|
177574
|
+
BasicInformationServer2,
|
|
177575
|
+
IdentifyServer2,
|
|
177576
|
+
HomeAssistantEntityBehavior,
|
|
177577
|
+
ValveServer,
|
|
177578
|
+
DefaultPowerSourceServer
|
|
177579
|
+
);
|
|
177202
177580
|
function ValveDevice(homeAssistantEntity) {
|
|
177203
|
-
|
|
177581
|
+
const attrs = homeAssistantEntity.entity.state.attributes;
|
|
177582
|
+
const hasBatteryAttr = attrs.battery_level != null || attrs.battery != null;
|
|
177583
|
+
const hasBatteryEntity = !!homeAssistantEntity.mapping?.batteryEntity;
|
|
177584
|
+
const device = hasBatteryAttr || hasBatteryEntity ? ValveWithBatteryEndpointType : ValveEndpointType;
|
|
177585
|
+
return device.set({ homeAssistantEntity });
|
|
177204
177586
|
}
|
|
177205
177587
|
|
|
177206
177588
|
// src/matter/endpoints/legacy/water-heater/index.ts
|
|
@@ -177321,6 +177703,7 @@ function WaterHeaterDevice(homeAssistantEntity) {
|
|
|
177321
177703
|
}
|
|
177322
177704
|
|
|
177323
177705
|
// src/matter/endpoints/legacy/create-legacy-endpoint-type.ts
|
|
177706
|
+
var legacyLogger = Logger.get("LegacyEndpointType");
|
|
177324
177707
|
function createLegacyEndpointType(entity, mapping, areaName, options) {
|
|
177325
177708
|
const domain = entity.entity_id.split(".")[0];
|
|
177326
177709
|
const customName = mapping?.customName;
|
|
@@ -177340,10 +177723,20 @@ function createLegacyEndpointType(entity, mapping, areaName, options) {
|
|
|
177340
177723
|
);
|
|
177341
177724
|
} else {
|
|
177342
177725
|
const factory = deviceCtrs[domain];
|
|
177343
|
-
if (
|
|
177726
|
+
if (factory) {
|
|
177727
|
+
type = factory({ entity, customName, mapping });
|
|
177728
|
+
} else if (options?.pluginDomainMappings?.has(domain)) {
|
|
177729
|
+
const mappedType = options.pluginDomainMappings.get(domain);
|
|
177730
|
+
const mappedFactory = matterDeviceTypeFactories[mappedType];
|
|
177731
|
+
if (mappedFactory) {
|
|
177732
|
+
legacyLogger.info(
|
|
177733
|
+
`Using plugin domain mapping for "${domain}" \u2192 "${mappedType}"`
|
|
177734
|
+
);
|
|
177735
|
+
type = mappedFactory({ entity, customName, mapping });
|
|
177736
|
+
}
|
|
177737
|
+
} else {
|
|
177344
177738
|
return void 0;
|
|
177345
177739
|
}
|
|
177346
|
-
type = factory({ entity, customName, mapping });
|
|
177347
177740
|
}
|
|
177348
177741
|
}
|
|
177349
177742
|
if (!type) {
|
|
@@ -177415,6 +177808,9 @@ var matterDeviceTypeFactories = {
|
|
|
177415
177808
|
}
|
|
177416
177809
|
return SwitchDevice(ha);
|
|
177417
177810
|
},
|
|
177811
|
+
dimmable_plugin_unit: (ha) => DimmablePlugInUnitType.set({
|
|
177812
|
+
homeAssistantEntity: { entity: ha.entity, customName: ha.customName }
|
|
177813
|
+
}),
|
|
177418
177814
|
on_off_switch: SwitchDevice,
|
|
177419
177815
|
door_lock: LockDevice,
|
|
177420
177816
|
window_covering: CoverDevice,
|
|
@@ -177470,9 +177866,15 @@ var matterDeviceTypeFactories = {
|
|
|
177470
177866
|
electrical_sensor: (ha) => ElectricalSensorType.set({
|
|
177471
177867
|
homeAssistantEntity: { entity: ha.entity, customName: ha.customName }
|
|
177472
177868
|
}),
|
|
177869
|
+
contact_sensor: (ha) => ContactSensorType.set({
|
|
177870
|
+
homeAssistantEntity: { entity: ha.entity, customName: ha.customName }
|
|
177871
|
+
}),
|
|
177473
177872
|
motion_sensor: (ha) => MotionSensorType.set({
|
|
177474
177873
|
homeAssistantEntity: { entity: ha.entity, customName: ha.customName }
|
|
177475
177874
|
}),
|
|
177875
|
+
occupancy_sensor: (ha) => OccupancySensorType.set({
|
|
177876
|
+
homeAssistantEntity: { entity: ha.entity, customName: ha.customName }
|
|
177877
|
+
}),
|
|
177476
177878
|
mode_select: SelectDevice,
|
|
177477
177879
|
water_valve: ValveDevice,
|
|
177478
177880
|
pump: PumpEndpoint,
|
|
@@ -177492,10 +177894,192 @@ var matterDeviceTypeFactories = {
|
|
|
177492
177894
|
})
|
|
177493
177895
|
};
|
|
177494
177896
|
|
|
177897
|
+
// src/matter/endpoints/composed/user-composed-endpoint.ts
|
|
177898
|
+
var logger198 = Logger.get("UserComposedEndpoint");
|
|
177899
|
+
function createEndpointId4(entityId, customName) {
|
|
177900
|
+
const baseName = customName || entityId;
|
|
177901
|
+
return baseName.replace(/\./g, "_").replace(/\s+/g, "_");
|
|
177902
|
+
}
|
|
177903
|
+
function buildEntityPayload3(registry2, entityId) {
|
|
177904
|
+
const state = registry2.initialState(entityId);
|
|
177905
|
+
if (!state) return void 0;
|
|
177906
|
+
const entity = registry2.entity(entityId);
|
|
177907
|
+
const deviceRegistry = registry2.deviceOf(entityId);
|
|
177908
|
+
return {
|
|
177909
|
+
entity_id: entityId,
|
|
177910
|
+
state,
|
|
177911
|
+
registry: entity,
|
|
177912
|
+
deviceRegistry
|
|
177913
|
+
};
|
|
177914
|
+
}
|
|
177915
|
+
var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
177916
|
+
entityId;
|
|
177917
|
+
mappedEntityIds;
|
|
177918
|
+
subEndpoints = /* @__PURE__ */ new Map();
|
|
177919
|
+
lastStates = /* @__PURE__ */ new Map();
|
|
177920
|
+
debouncedUpdates = /* @__PURE__ */ new Map();
|
|
177921
|
+
static async create(config10) {
|
|
177922
|
+
const { registry: registry2, primaryEntityId, composedEntities } = config10;
|
|
177923
|
+
const primaryPayload = buildEntityPayload3(registry2, primaryEntityId);
|
|
177924
|
+
if (!primaryPayload) return void 0;
|
|
177925
|
+
let parentType = BridgedNodeEndpoint.with(
|
|
177926
|
+
BasicInformationServer2,
|
|
177927
|
+
IdentifyServer2,
|
|
177928
|
+
HomeAssistantEntityBehavior
|
|
177929
|
+
);
|
|
177930
|
+
if (config10.areaName) {
|
|
177931
|
+
const truncatedName = config10.areaName.length > 16 ? config10.areaName.substring(0, 16) : config10.areaName;
|
|
177932
|
+
parentType = parentType.with(
|
|
177933
|
+
FixedLabelServer.set({
|
|
177934
|
+
labelList: [{ label: "room", value: truncatedName }]
|
|
177935
|
+
})
|
|
177936
|
+
);
|
|
177937
|
+
}
|
|
177938
|
+
const endpointId = createEndpointId4(primaryEntityId, config10.customName);
|
|
177939
|
+
const parts = [];
|
|
177940
|
+
const subEndpointMap = /* @__PURE__ */ new Map();
|
|
177941
|
+
const mappedIds = [];
|
|
177942
|
+
const primaryType = createLegacyEndpointType(
|
|
177943
|
+
primaryPayload,
|
|
177944
|
+
config10.mapping,
|
|
177945
|
+
void 0,
|
|
177946
|
+
{ vacuumOnOff: registry2.isVacuumOnOffEnabled() }
|
|
177947
|
+
);
|
|
177948
|
+
if (!primaryType) {
|
|
177949
|
+
logger198.warn(
|
|
177950
|
+
`Cannot create endpoint type for primary entity ${primaryEntityId}`
|
|
177951
|
+
);
|
|
177952
|
+
return void 0;
|
|
177953
|
+
}
|
|
177954
|
+
const primarySub = new Endpoint(primaryType, {
|
|
177955
|
+
id: `${endpointId}_primary`
|
|
177956
|
+
});
|
|
177957
|
+
parts.push(primarySub);
|
|
177958
|
+
subEndpointMap.set(primaryEntityId, primarySub);
|
|
177959
|
+
for (let i = 0; i < composedEntities.length; i++) {
|
|
177960
|
+
const sub = composedEntities[i];
|
|
177961
|
+
if (!sub.entityId) continue;
|
|
177962
|
+
const subPayload = buildEntityPayload3(registry2, sub.entityId);
|
|
177963
|
+
if (!subPayload) {
|
|
177964
|
+
logger198.warn(
|
|
177965
|
+
`Cannot find entity state for composed sub-entity ${sub.entityId}`
|
|
177966
|
+
);
|
|
177967
|
+
continue;
|
|
177968
|
+
}
|
|
177969
|
+
const subMapping = {
|
|
177970
|
+
entityId: sub.entityId,
|
|
177971
|
+
matterDeviceType: sub.matterDeviceType
|
|
177972
|
+
};
|
|
177973
|
+
const subType = createLegacyEndpointType(subPayload, subMapping);
|
|
177974
|
+
if (!subType) {
|
|
177975
|
+
logger198.warn(
|
|
177976
|
+
`Cannot create endpoint type for composed sub-entity ${sub.entityId}`
|
|
177977
|
+
);
|
|
177978
|
+
continue;
|
|
177979
|
+
}
|
|
177980
|
+
const subEndpoint = new Endpoint(subType, {
|
|
177981
|
+
id: `${endpointId}_sub_${i}`
|
|
177982
|
+
});
|
|
177983
|
+
parts.push(subEndpoint);
|
|
177984
|
+
subEndpointMap.set(sub.entityId, subEndpoint);
|
|
177985
|
+
mappedIds.push(sub.entityId);
|
|
177986
|
+
}
|
|
177987
|
+
if (parts.length < 2) {
|
|
177988
|
+
logger198.warn(
|
|
177989
|
+
`User composed device ${primaryEntityId}: only ${parts.length} sub-endpoint(s), need at least 2 (primary + one sub-entity). Falling back to standalone.`
|
|
177990
|
+
);
|
|
177991
|
+
return void 0;
|
|
177992
|
+
}
|
|
177993
|
+
const parentTypeWithState = parentType.set({
|
|
177994
|
+
homeAssistantEntity: {
|
|
177995
|
+
entity: primaryPayload,
|
|
177996
|
+
customName: config10.customName,
|
|
177997
|
+
mapping: config10.mapping
|
|
177998
|
+
}
|
|
177999
|
+
});
|
|
178000
|
+
const endpoint = new _UserComposedEndpoint(
|
|
178001
|
+
parentTypeWithState,
|
|
178002
|
+
primaryEntityId,
|
|
178003
|
+
endpointId,
|
|
178004
|
+
parts,
|
|
178005
|
+
mappedIds
|
|
178006
|
+
);
|
|
178007
|
+
endpoint.subEndpoints = subEndpointMap;
|
|
178008
|
+
const labels = parts.map(
|
|
178009
|
+
(_, i) => i === 0 ? primaryEntityId.split(".")[0] : composedEntities[i - 1]?.entityId?.split(".")[0] ?? "?"
|
|
178010
|
+
).join("+");
|
|
178011
|
+
logger198.info(
|
|
178012
|
+
`Created user composed device ${primaryEntityId}: ${parts.length} sub-endpoint(s) [${labels}]`
|
|
178013
|
+
);
|
|
178014
|
+
return endpoint;
|
|
178015
|
+
}
|
|
178016
|
+
constructor(type, entityId, id, parts, mappedEntityIds) {
|
|
178017
|
+
super(type, { id, parts });
|
|
178018
|
+
this.entityId = entityId;
|
|
178019
|
+
this.mappedEntityIds = mappedEntityIds;
|
|
178020
|
+
}
|
|
178021
|
+
async updateStates(states) {
|
|
178022
|
+
this.scheduleUpdate(this, this.entityId, states);
|
|
178023
|
+
for (const [entityId, sub] of this.subEndpoints) {
|
|
178024
|
+
this.scheduleUpdate(sub, entityId, states);
|
|
178025
|
+
}
|
|
178026
|
+
}
|
|
178027
|
+
scheduleUpdate(endpoint, entityId, states) {
|
|
178028
|
+
const state = states[entityId];
|
|
178029
|
+
if (!state) return;
|
|
178030
|
+
const key = endpoint === this ? `_parent_:${entityId}` : entityId;
|
|
178031
|
+
const stateJson = JSON.stringify({
|
|
178032
|
+
s: state.state,
|
|
178033
|
+
a: state.attributes
|
|
178034
|
+
});
|
|
178035
|
+
if (this.lastStates.get(key) === stateJson) return;
|
|
178036
|
+
this.lastStates.set(key, stateJson);
|
|
178037
|
+
let debouncedFn = this.debouncedUpdates.get(key);
|
|
178038
|
+
if (!debouncedFn) {
|
|
178039
|
+
debouncedFn = debounce4(
|
|
178040
|
+
(ep, s) => this.flushUpdate(ep, s),
|
|
178041
|
+
50
|
|
178042
|
+
);
|
|
178043
|
+
this.debouncedUpdates.set(key, debouncedFn);
|
|
178044
|
+
}
|
|
178045
|
+
debouncedFn(endpoint, state);
|
|
178046
|
+
}
|
|
178047
|
+
async flushUpdate(endpoint, state) {
|
|
178048
|
+
try {
|
|
178049
|
+
await endpoint.construction.ready;
|
|
178050
|
+
} catch {
|
|
178051
|
+
return;
|
|
178052
|
+
}
|
|
178053
|
+
try {
|
|
178054
|
+
const current = endpoint.stateOf(HomeAssistantEntityBehavior).entity;
|
|
178055
|
+
await endpoint.setStateOf(HomeAssistantEntityBehavior, {
|
|
178056
|
+
entity: { ...current, state }
|
|
178057
|
+
});
|
|
178058
|
+
} catch (error) {
|
|
178059
|
+
if (error instanceof TransactionDestroyedError || error instanceof DestroyedDependencyError) {
|
|
178060
|
+
return;
|
|
178061
|
+
}
|
|
178062
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
178063
|
+
if (errorMessage.includes(
|
|
178064
|
+
"Endpoint storage inaccessible because endpoint is not a node and is not owned by another endpoint"
|
|
178065
|
+
)) {
|
|
178066
|
+
return;
|
|
178067
|
+
}
|
|
178068
|
+
throw error;
|
|
178069
|
+
}
|
|
178070
|
+
}
|
|
178071
|
+
async delete() {
|
|
178072
|
+
for (const fn of this.debouncedUpdates.values()) {
|
|
178073
|
+
fn.clear();
|
|
178074
|
+
}
|
|
178075
|
+
await super.delete();
|
|
178076
|
+
}
|
|
178077
|
+
};
|
|
178078
|
+
|
|
177495
178079
|
// src/matter/endpoints/legacy/legacy-endpoint.ts
|
|
177496
|
-
var
|
|
178080
|
+
var logger199 = Logger.get("LegacyEndpoint");
|
|
177497
178081
|
var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
177498
|
-
static async create(registry2, entityId, mapping) {
|
|
178082
|
+
static async create(registry2, entityId, mapping, pluginDomainMappings) {
|
|
177499
178083
|
const deviceRegistry = registry2.deviceOf(entityId);
|
|
177500
178084
|
let state = registry2.initialState(entityId);
|
|
177501
178085
|
const entity = registry2.entity(entityId);
|
|
@@ -177503,25 +178087,25 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177503
178087
|
return;
|
|
177504
178088
|
}
|
|
177505
178089
|
if (registry2.isAutoBatteryMappingEnabled() && registry2.isBatteryEntityUsed(entityId)) {
|
|
177506
|
-
|
|
178090
|
+
logger199.debug(
|
|
177507
178091
|
`Skipping ${entityId} - already auto-assigned as battery to another device`
|
|
177508
178092
|
);
|
|
177509
178093
|
return;
|
|
177510
178094
|
}
|
|
177511
178095
|
if (registry2.isAutoHumidityMappingEnabled() && registry2.isHumidityEntityUsed(entityId)) {
|
|
177512
|
-
|
|
178096
|
+
logger199.debug(
|
|
177513
178097
|
`Skipping ${entityId} - already auto-assigned as humidity to a temperature sensor`
|
|
177514
178098
|
);
|
|
177515
178099
|
return;
|
|
177516
178100
|
}
|
|
177517
178101
|
if (registry2.isAutoPressureMappingEnabled() && registry2.isPressureEntityUsed(entityId)) {
|
|
177518
|
-
|
|
178102
|
+
logger199.debug(
|
|
177519
178103
|
`Skipping ${entityId} - already auto-assigned as pressure to a temperature sensor`
|
|
177520
178104
|
);
|
|
177521
178105
|
return;
|
|
177522
178106
|
}
|
|
177523
178107
|
if (registry2.isAutoComposedDevicesEnabled() && registry2.isComposedSubEntityUsed(entityId)) {
|
|
177524
|
-
|
|
178108
|
+
logger199.debug(
|
|
177525
178109
|
`Skipping ${entityId} - already consumed by a composed device`
|
|
177526
178110
|
);
|
|
177527
178111
|
return;
|
|
@@ -177541,7 +178125,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177541
178125
|
humidityEntity: humidityEntityId
|
|
177542
178126
|
};
|
|
177543
178127
|
registry2.markHumidityEntityUsed(humidityEntityId);
|
|
177544
|
-
|
|
178128
|
+
logger199.debug(
|
|
177545
178129
|
`Auto-assigned humidity ${humidityEntityId} to ${entityId}`
|
|
177546
178130
|
);
|
|
177547
178131
|
}
|
|
@@ -177560,7 +178144,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177560
178144
|
pressureEntity: pressureEntityId
|
|
177561
178145
|
};
|
|
177562
178146
|
registry2.markPressureEntityUsed(pressureEntityId);
|
|
177563
|
-
|
|
178147
|
+
logger199.debug(
|
|
177564
178148
|
`Auto-assigned pressure ${pressureEntityId} to ${entityId}`
|
|
177565
178149
|
);
|
|
177566
178150
|
}
|
|
@@ -177578,7 +178162,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177578
178162
|
batteryEntity: batteryEntityId
|
|
177579
178163
|
};
|
|
177580
178164
|
registry2.markBatteryEntityUsed(batteryEntityId);
|
|
177581
|
-
|
|
178165
|
+
logger199.debug(
|
|
177582
178166
|
`Auto-assigned battery ${batteryEntityId} to ${entityId}`
|
|
177583
178167
|
);
|
|
177584
178168
|
}
|
|
@@ -177596,7 +178180,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177596
178180
|
powerEntity: powerEntityId
|
|
177597
178181
|
};
|
|
177598
178182
|
registry2.markPowerEntityUsed(powerEntityId);
|
|
177599
|
-
|
|
178183
|
+
logger199.debug(`Auto-assigned power ${powerEntityId} to ${entityId}`);
|
|
177600
178184
|
}
|
|
177601
178185
|
}
|
|
177602
178186
|
}
|
|
@@ -177613,7 +178197,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177613
178197
|
energyEntity: energyEntityId
|
|
177614
178198
|
};
|
|
177615
178199
|
registry2.markEnergyEntityUsed(energyEntityId);
|
|
177616
|
-
|
|
178200
|
+
logger199.debug(
|
|
177617
178201
|
`Auto-assigned energy ${energyEntityId} to ${entityId}`
|
|
177618
178202
|
);
|
|
177619
178203
|
}
|
|
@@ -177629,7 +178213,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177629
178213
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
177630
178214
|
cleaningModeEntity: vacuumEntities.cleaningModeEntity
|
|
177631
178215
|
};
|
|
177632
|
-
|
|
178216
|
+
logger199.debug(
|
|
177633
178217
|
`Auto-assigned cleaningMode ${vacuumEntities.cleaningModeEntity} to ${entityId}`
|
|
177634
178218
|
);
|
|
177635
178219
|
}
|
|
@@ -177639,7 +178223,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177639
178223
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
177640
178224
|
suctionLevelEntity: vacuumEntities.suctionLevelEntity
|
|
177641
178225
|
};
|
|
177642
|
-
|
|
178226
|
+
logger199.debug(
|
|
177643
178227
|
`Auto-assigned suctionLevel ${vacuumEntities.suctionLevelEntity} to ${entityId}`
|
|
177644
178228
|
);
|
|
177645
178229
|
}
|
|
@@ -177649,12 +178233,27 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177649
178233
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
177650
178234
|
mopIntensityEntity: vacuumEntities.mopIntensityEntity
|
|
177651
178235
|
};
|
|
177652
|
-
|
|
178236
|
+
logger199.debug(
|
|
177653
178237
|
`Auto-assigned mopIntensity ${vacuumEntities.mopIntensityEntity} to ${entityId}`
|
|
177654
178238
|
);
|
|
177655
178239
|
}
|
|
178240
|
+
const supportedFeatures = state.attributes.supported_features ?? 0;
|
|
178241
|
+
const cleanAreaRooms = await registry2.resolveCleanAreaRooms(
|
|
178242
|
+
entityId,
|
|
178243
|
+
supportedFeatures
|
|
178244
|
+
);
|
|
178245
|
+
if (cleanAreaRooms.length > 0) {
|
|
178246
|
+
effectiveMapping = {
|
|
178247
|
+
...effectiveMapping,
|
|
178248
|
+
entityId: effectiveMapping?.entityId ?? entityId,
|
|
178249
|
+
cleanAreaRooms
|
|
178250
|
+
};
|
|
178251
|
+
logger199.debug(
|
|
178252
|
+
`Using ${cleanAreaRooms.length} HA areas via CLEAN_AREA for ${entityId}`
|
|
178253
|
+
);
|
|
178254
|
+
}
|
|
177656
178255
|
const vacAttrs = state.attributes;
|
|
177657
|
-
if (!vacAttrs.rooms && !vacAttrs.segments && !vacAttrs.room_mapping) {
|
|
178256
|
+
if (cleanAreaRooms.length === 0 && !vacAttrs.rooms && !vacAttrs.segments && !vacAttrs.room_mapping) {
|
|
177658
178257
|
const valetudoRooms = registry2.findValetudoMapSegments(
|
|
177659
178258
|
entity.device_id
|
|
177660
178259
|
);
|
|
@@ -177670,7 +178269,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177670
178269
|
rooms: roomsObj
|
|
177671
178270
|
}
|
|
177672
178271
|
};
|
|
177673
|
-
|
|
178272
|
+
logger199.debug(
|
|
177674
178273
|
`Auto-detected ${valetudoRooms.length} Valetudo segments for ${entityId}`
|
|
177675
178274
|
);
|
|
177676
178275
|
} else {
|
|
@@ -177687,7 +178286,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177687
178286
|
rooms: roomsObj
|
|
177688
178287
|
}
|
|
177689
178288
|
};
|
|
177690
|
-
|
|
178289
|
+
logger199.debug(
|
|
177691
178290
|
`Auto-detected ${roborockRooms.length} Roborock rooms for ${entityId}`
|
|
177692
178291
|
);
|
|
177693
178292
|
}
|
|
@@ -177695,6 +178294,23 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177695
178294
|
}
|
|
177696
178295
|
}
|
|
177697
178296
|
}
|
|
178297
|
+
if (registry2.isAutoComposedDevicesEnabled() && effectiveMapping?.composedEntities && effectiveMapping.composedEntities.length > 0) {
|
|
178298
|
+
const composedAreaName = registry2.getAreaName(entityId);
|
|
178299
|
+
const composed = await UserComposedEndpoint.create({
|
|
178300
|
+
registry: registry2,
|
|
178301
|
+
primaryEntityId: entityId,
|
|
178302
|
+
mapping: effectiveMapping,
|
|
178303
|
+
composedEntities: effectiveMapping.composedEntities,
|
|
178304
|
+
customName: effectiveMapping?.customName,
|
|
178305
|
+
areaName: composedAreaName
|
|
178306
|
+
});
|
|
178307
|
+
if (composed) {
|
|
178308
|
+
return composed;
|
|
178309
|
+
}
|
|
178310
|
+
logger199.warn(
|
|
178311
|
+
`User composed device creation failed for ${entityId}, falling back to standalone`
|
|
178312
|
+
);
|
|
178313
|
+
}
|
|
177698
178314
|
if (registry2.isAutoComposedDevicesEnabled()) {
|
|
177699
178315
|
const attrs = state.attributes;
|
|
177700
178316
|
if (entityId.startsWith("sensor.") && attrs.device_class === SensorDeviceClass.temperature && (effectiveMapping?.humidityEntity || effectiveMapping?.pressureEntity)) {
|
|
@@ -177711,13 +178327,9 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177711
178327
|
return composed;
|
|
177712
178328
|
}
|
|
177713
178329
|
const resolvedMatterType = mapping?.matterDeviceType ?? (entityId.startsWith("fan.") ? "fan" : void 0);
|
|
177714
|
-
if (resolvedMatterType === "air_purifier"
|
|
177715
|
-
const temperatureEntityId = registry2.findTemperatureEntityForDevice(
|
|
177716
|
-
|
|
177717
|
-
);
|
|
177718
|
-
const humidityEntityId = registry2.findHumidityEntityForDevice(
|
|
177719
|
-
entity.device_id
|
|
177720
|
-
);
|
|
178330
|
+
if (resolvedMatterType === "air_purifier") {
|
|
178331
|
+
const temperatureEntityId = effectiveMapping?.temperatureEntity || (entity.device_id ? registry2.findTemperatureEntityForDevice(entity.device_id) : void 0);
|
|
178332
|
+
const humidityEntityId = effectiveMapping?.humidityEntity || (entity.device_id ? registry2.findHumidityEntityForDevice(entity.device_id) : void 0);
|
|
177721
178333
|
if (temperatureEntityId || humidityEntityId) {
|
|
177722
178334
|
const composedAreaName = registry2.getAreaName(entityId);
|
|
177723
178335
|
const composed = await ComposedAirPurifierEndpoint.create({
|
|
@@ -177762,7 +178374,8 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177762
178374
|
const areaName = registry2.getAreaName(entityId);
|
|
177763
178375
|
const type = createLegacyEndpointType(payload, effectiveMapping, areaName, {
|
|
177764
178376
|
vacuumOnOff: registry2.isVacuumOnOffEnabled(),
|
|
177765
|
-
cleaningModeOptions
|
|
178377
|
+
cleaningModeOptions,
|
|
178378
|
+
pluginDomainMappings
|
|
177766
178379
|
});
|
|
177767
178380
|
if (!type) {
|
|
177768
178381
|
return;
|
|
@@ -177773,9 +178386,10 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177773
178386
|
}
|
|
177774
178387
|
constructor(type, entityId, customName, mappedEntityIds) {
|
|
177775
178388
|
super(type, entityId, customName, mappedEntityIds);
|
|
177776
|
-
this.flushUpdate =
|
|
178389
|
+
this.flushUpdate = debounce5(this.flushPendingUpdate.bind(this), 50);
|
|
177777
178390
|
}
|
|
177778
178391
|
lastState;
|
|
178392
|
+
pendingMappedChange = false;
|
|
177779
178393
|
flushUpdate;
|
|
177780
178394
|
async delete() {
|
|
177781
178395
|
this.flushUpdate.clear();
|
|
@@ -177788,11 +178402,12 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177788
178402
|
return;
|
|
177789
178403
|
}
|
|
177790
178404
|
if (mappedChanged) {
|
|
177791
|
-
|
|
178405
|
+
this.pendingMappedChange = true;
|
|
178406
|
+
logger199.debug(
|
|
177792
178407
|
`Mapped entity change detected for ${this.entityId}, forcing update`
|
|
177793
178408
|
);
|
|
177794
178409
|
}
|
|
177795
|
-
|
|
178410
|
+
logger199.debug(
|
|
177796
178411
|
`State update received for ${this.entityId}: state=${state.state}`
|
|
177797
178412
|
);
|
|
177798
178413
|
this.lastState = state;
|
|
@@ -177806,8 +178421,13 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177806
178421
|
}
|
|
177807
178422
|
try {
|
|
177808
178423
|
const current = this.stateOf(HomeAssistantEntityBehavior).entity;
|
|
178424
|
+
let effectiveState = state;
|
|
178425
|
+
if (this.pendingMappedChange) {
|
|
178426
|
+
this.pendingMappedChange = false;
|
|
178427
|
+
effectiveState = { ...state, last_updated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
178428
|
+
}
|
|
177809
178429
|
await this.setStateOf(HomeAssistantEntityBehavior, {
|
|
177810
|
-
entity: { ...current, state }
|
|
178430
|
+
entity: { ...current, state: effectiveState }
|
|
177811
178431
|
});
|
|
177812
178432
|
} catch (error) {
|
|
177813
178433
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -177826,12 +178446,12 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
177826
178446
|
|
|
177827
178447
|
// src/services/home-assistant/api/subscribe-entities.ts
|
|
177828
178448
|
init_esm();
|
|
177829
|
-
import
|
|
178449
|
+
import crypto7 from "node:crypto";
|
|
177830
178450
|
import {
|
|
177831
178451
|
getCollection
|
|
177832
178452
|
} from "home-assistant-js-websocket";
|
|
177833
178453
|
import { atLeastHaVersion } from "home-assistant-js-websocket/dist/util.js";
|
|
177834
|
-
var
|
|
178454
|
+
var logger200 = Logger.get("SubscribeEntities");
|
|
177835
178455
|
function processEvent(store, updates) {
|
|
177836
178456
|
const state = { ...store.state };
|
|
177837
178457
|
if (updates.a) {
|
|
@@ -177857,7 +178477,7 @@ function processEvent(store, updates) {
|
|
|
177857
178477
|
for (const entityId in updates.c) {
|
|
177858
178478
|
let entityState = state[entityId];
|
|
177859
178479
|
if (!entityState) {
|
|
177860
|
-
|
|
178480
|
+
logger200.warn("Received state update for unknown entity", entityId);
|
|
177861
178481
|
continue;
|
|
177862
178482
|
}
|
|
177863
178483
|
entityState = { ...entityState };
|
|
@@ -177910,7 +178530,7 @@ var subscribeUpdates = (conn, store, entityIds) => {
|
|
|
177910
178530
|
});
|
|
177911
178531
|
};
|
|
177912
178532
|
function createEntitiesHash(entityIds) {
|
|
177913
|
-
return
|
|
178533
|
+
return crypto7.createHash("sha256").update(entityIds.join(",")).digest("hex").substring(0, 16);
|
|
177914
178534
|
}
|
|
177915
178535
|
var entitiesColl = (conn, entityIds) => {
|
|
177916
178536
|
if (atLeastHaVersion(conn.haVersion, 2022, 4, 0)) {
|
|
@@ -177927,7 +178547,7 @@ var subscribeEntities = (conn, onChange, entityIds) => entitiesColl(conn, entity
|
|
|
177927
178547
|
|
|
177928
178548
|
// src/services/bridges/entity-isolation-service.ts
|
|
177929
178549
|
init_esm();
|
|
177930
|
-
var
|
|
178550
|
+
var logger201 = Logger.get("EntityIsolation");
|
|
177931
178551
|
var EntityIsolationServiceImpl = class {
|
|
177932
178552
|
isolatedEntities = /* @__PURE__ */ new Map();
|
|
177933
178553
|
isolationCallbacks = /* @__PURE__ */ new Map();
|
|
@@ -177992,13 +178612,13 @@ var EntityIsolationServiceImpl = class {
|
|
|
177992
178612
|
}
|
|
177993
178613
|
const parsed = this.parseEndpointPath(msg);
|
|
177994
178614
|
if (!parsed) {
|
|
177995
|
-
|
|
178615
|
+
logger201.warn("Could not parse entity from error:", msg);
|
|
177996
178616
|
return false;
|
|
177997
178617
|
}
|
|
177998
178618
|
const { bridgeId, entityName } = parsed;
|
|
177999
178619
|
const callback = this.isolationCallbacks.get(bridgeId);
|
|
178000
178620
|
if (!callback) {
|
|
178001
|
-
|
|
178621
|
+
logger201.warn(
|
|
178002
178622
|
`No isolation callback registered for bridge ${bridgeId}, entity: ${entityName}`
|
|
178003
178623
|
);
|
|
178004
178624
|
return false;
|
|
@@ -178009,14 +178629,14 @@ var EntityIsolationServiceImpl = class {
|
|
|
178009
178629
|
}
|
|
178010
178630
|
const reason = `${classification}. Entity isolated to protect bridge stability.`;
|
|
178011
178631
|
this.isolatedEntities.set(key, { entityId: entityName, reason });
|
|
178012
|
-
|
|
178632
|
+
logger201.warn(
|
|
178013
178633
|
`Isolating entity "${entityName}" from bridge ${bridgeId} due to: ${reason}`
|
|
178014
178634
|
);
|
|
178015
178635
|
try {
|
|
178016
178636
|
await callback(entityName);
|
|
178017
178637
|
return true;
|
|
178018
178638
|
} catch (e) {
|
|
178019
|
-
|
|
178639
|
+
logger201.error(`Failed to isolate entity ${entityName}:`, e);
|
|
178020
178640
|
return false;
|
|
178021
178641
|
}
|
|
178022
178642
|
}
|
|
@@ -178259,6 +178879,16 @@ var BridgeEndpointManager = class extends Service {
|
|
|
178259
178879
|
}
|
|
178260
178880
|
}
|
|
178261
178881
|
}
|
|
178882
|
+
getPluginDomainMappings() {
|
|
178883
|
+
if (!this.pluginManager) return void 0;
|
|
178884
|
+
const mappings = this.pluginManager.getDomainMappings();
|
|
178885
|
+
if (mappings.size === 0) return void 0;
|
|
178886
|
+
const result = /* @__PURE__ */ new Map();
|
|
178887
|
+
for (const [domain, mapping] of mappings) {
|
|
178888
|
+
result.set(domain, mapping.matterDeviceType);
|
|
178889
|
+
}
|
|
178890
|
+
return result;
|
|
178891
|
+
}
|
|
178262
178892
|
getEntityMapping(entityId) {
|
|
178263
178893
|
return this.mappingStorage.getMapping(this.bridgeId, entityId);
|
|
178264
178894
|
}
|
|
@@ -178315,16 +178945,20 @@ var BridgeEndpointManager = class extends Service {
|
|
|
178315
178945
|
this.entityIds = this.registry.entityIds;
|
|
178316
178946
|
if (this.registry.isAutoComposedDevicesEnabled()) {
|
|
178317
178947
|
for (const eid of this.entityIds) {
|
|
178318
|
-
if (!eid.startsWith("fan.")) continue;
|
|
178319
178948
|
const m = this.getEntityMapping(eid);
|
|
178949
|
+
if (m?.composedEntities) {
|
|
178950
|
+
for (const sub of m.composedEntities) {
|
|
178951
|
+
if (sub.entityId) {
|
|
178952
|
+
this.registry.markComposedSubEntityUsed(sub.entityId);
|
|
178953
|
+
}
|
|
178954
|
+
}
|
|
178955
|
+
}
|
|
178956
|
+
if (!eid.startsWith("fan.")) continue;
|
|
178320
178957
|
const matterType = m?.matterDeviceType ?? "fan";
|
|
178321
178958
|
if (matterType !== "air_purifier") continue;
|
|
178322
178959
|
const ent = this.registry.entity(eid);
|
|
178323
|
-
|
|
178324
|
-
const
|
|
178325
|
-
ent.device_id
|
|
178326
|
-
);
|
|
178327
|
-
const humId = this.registry.findHumidityEntityForDevice(ent.device_id);
|
|
178960
|
+
const tempId = m?.temperatureEntity || (ent?.device_id ? this.registry.findTemperatureEntityForDevice(ent.device_id) : void 0);
|
|
178961
|
+
const humId = m?.humidityEntity || (ent?.device_id ? this.registry.findHumidityEntityForDevice(ent.device_id) : void 0);
|
|
178328
178962
|
if (tempId) this.registry.markComposedSubEntityUsed(tempId);
|
|
178329
178963
|
if (humId) this.registry.markComposedSubEntityUsed(humId);
|
|
178330
178964
|
}
|
|
@@ -178395,6 +179029,12 @@ var BridgeEndpointManager = class extends Service {
|
|
|
178395
179029
|
this.log.debug(`Skipping disabled entity: ${entityId}`);
|
|
178396
179030
|
continue;
|
|
178397
179031
|
}
|
|
179032
|
+
if (this.registry.isAutoComposedDevicesEnabled() && this.registry.isComposedSubEntityUsed(entityId)) {
|
|
179033
|
+
this.log.debug(
|
|
179034
|
+
`Skipping ${entityId} \u2014 already part of a composed device`
|
|
179035
|
+
);
|
|
179036
|
+
continue;
|
|
179037
|
+
}
|
|
178398
179038
|
if (entityId.length > MAX_ENTITY_ID_LENGTH) {
|
|
178399
179039
|
const reason = `Entity ID too long (${entityId.length} chars, max ${MAX_ENTITY_ID_LENGTH}). This would cause filesystem errors.`;
|
|
178400
179040
|
this.log.warn(`Skipping entity: ${entityId}. Reason: ${reason}`);
|
|
@@ -178404,10 +179044,12 @@ var BridgeEndpointManager = class extends Service {
|
|
|
178404
179044
|
let endpoint = existingEndpoints.find((e) => e.entityId === entityId);
|
|
178405
179045
|
if (!endpoint) {
|
|
178406
179046
|
try {
|
|
179047
|
+
const domainMappings = this.getPluginDomainMappings();
|
|
178407
179048
|
endpoint = await LegacyEndpoint.create(
|
|
178408
179049
|
this.registry,
|
|
178409
179050
|
entityId,
|
|
178410
|
-
mapping
|
|
179051
|
+
mapping,
|
|
179052
|
+
domainMappings
|
|
178411
179053
|
);
|
|
178412
179054
|
} catch (e) {
|
|
178413
179055
|
const reason = this.extractErrorReason(e);
|
|
@@ -178843,6 +179485,85 @@ var BridgeRegistry = class _BridgeRegistry {
|
|
|
178843
179485
|
return [];
|
|
178844
179486
|
}
|
|
178845
179487
|
}
|
|
179488
|
+
static cleanAreaLogger = Logger.get("CleanAreaRooms");
|
|
179489
|
+
/**
|
|
179490
|
+
* Resolve HA areas mapped to vacuum segments via HA 2026.3 CLEAN_AREA.
|
|
179491
|
+
* Fetches the full entity registry entry (including options.vacuum.area_mapping)
|
|
179492
|
+
* and resolves HA area names from the area registry.
|
|
179493
|
+
* Returns CleanAreaRoom[] sorted alphabetically, or empty array if
|
|
179494
|
+
* CLEAN_AREA is not supported or no area_mapping is configured.
|
|
179495
|
+
*/
|
|
179496
|
+
async resolveCleanAreaRooms(entityId, supportedFeatures) {
|
|
179497
|
+
if (!this.client) return [];
|
|
179498
|
+
if (!(supportedFeatures & VacuumDeviceFeature.CLEAN_AREA)) return [];
|
|
179499
|
+
try {
|
|
179500
|
+
const entry = await this.client.connection.sendMessagePromise({
|
|
179501
|
+
type: "config/entity_registry/get",
|
|
179502
|
+
entity_id: entityId
|
|
179503
|
+
});
|
|
179504
|
+
const vacuumOptions = entry?.options?.vacuum;
|
|
179505
|
+
const areaMapping = vacuumOptions?.area_mapping;
|
|
179506
|
+
if (!areaMapping || Object.keys(areaMapping).length === 0) {
|
|
179507
|
+
_BridgeRegistry.cleanAreaLogger.debug(
|
|
179508
|
+
`${entityId}: CLEAN_AREA supported but no area_mapping configured`
|
|
179509
|
+
);
|
|
179510
|
+
return [];
|
|
179511
|
+
}
|
|
179512
|
+
let validSegmentIds;
|
|
179513
|
+
try {
|
|
179514
|
+
const segmentsResponse = await this.client.connection.sendMessagePromise({
|
|
179515
|
+
type: "vacuum/get_segments",
|
|
179516
|
+
entity_id: entityId
|
|
179517
|
+
});
|
|
179518
|
+
if (Array.isArray(segmentsResponse)) {
|
|
179519
|
+
validSegmentIds = new Set(segmentsResponse.map((s) => s.id));
|
|
179520
|
+
_BridgeRegistry.cleanAreaLogger.debug(
|
|
179521
|
+
`${entityId}: Current vacuum segments: ${[...validSegmentIds].join(", ")}`
|
|
179522
|
+
);
|
|
179523
|
+
}
|
|
179524
|
+
} catch {
|
|
179525
|
+
_BridgeRegistry.cleanAreaLogger.debug(
|
|
179526
|
+
`${entityId}: vacuum/get_segments not available, skipping stale entry detection`
|
|
179527
|
+
);
|
|
179528
|
+
}
|
|
179529
|
+
const rooms = [];
|
|
179530
|
+
for (const haAreaId of Object.keys(areaMapping)) {
|
|
179531
|
+
const segments = areaMapping[haAreaId];
|
|
179532
|
+
if (!segments || segments.length === 0) {
|
|
179533
|
+
_BridgeRegistry.cleanAreaLogger.debug(
|
|
179534
|
+
`${entityId}: Skipping HA area ${haAreaId} \u2014 no segments mapped`
|
|
179535
|
+
);
|
|
179536
|
+
continue;
|
|
179537
|
+
}
|
|
179538
|
+
if (validSegmentIds && !segments.some((sid) => validSegmentIds.has(sid))) {
|
|
179539
|
+
const areaName2 = this.registry.areas.get(haAreaId) ?? haAreaId;
|
|
179540
|
+
_BridgeRegistry.cleanAreaLogger.info(
|
|
179541
|
+
`${entityId}: Skipping stale HA area "${areaName2}" (${haAreaId}) \u2014 segments [${segments.join(", ")}] no longer exist on vacuum`
|
|
179542
|
+
);
|
|
179543
|
+
continue;
|
|
179544
|
+
}
|
|
179545
|
+
const areaName = this.registry.areas.get(haAreaId) ?? haAreaId;
|
|
179546
|
+
rooms.push({
|
|
179547
|
+
areaId: hashAreaId(haAreaId),
|
|
179548
|
+
haAreaId,
|
|
179549
|
+
name: areaName
|
|
179550
|
+
});
|
|
179551
|
+
}
|
|
179552
|
+
rooms.sort((a, b) => a.name.localeCompare(b.name));
|
|
179553
|
+
if (rooms.length > 0) {
|
|
179554
|
+
_BridgeRegistry.cleanAreaLogger.info(
|
|
179555
|
+
`${entityId}: Resolved ${rooms.length} HA areas via CLEAN_AREA mapping`
|
|
179556
|
+
);
|
|
179557
|
+
}
|
|
179558
|
+
return rooms;
|
|
179559
|
+
} catch (error) {
|
|
179560
|
+
const msg = error instanceof Error ? error.message : typeof error === "object" && error !== null ? JSON.stringify(error) : String(error);
|
|
179561
|
+
_BridgeRegistry.cleanAreaLogger.warn(
|
|
179562
|
+
`${entityId}: Failed to resolve CLEAN_AREA mapping: ${msg}`
|
|
179563
|
+
);
|
|
179564
|
+
return [];
|
|
179565
|
+
}
|
|
179566
|
+
}
|
|
178846
179567
|
/**
|
|
178847
179568
|
* Find a pressure sensor entity that belongs to the same HA device.
|
|
178848
179569
|
* Returns the entity_id of the pressure sensor, or undefined if none found.
|
|
@@ -179073,16 +179794,26 @@ var BridgeRegistry = class _BridgeRegistry {
|
|
|
179073
179794
|
return true;
|
|
179074
179795
|
}
|
|
179075
179796
|
};
|
|
179797
|
+
function hashAreaId(areaId) {
|
|
179798
|
+
let hash2 = 0;
|
|
179799
|
+
for (let i = 0; i < areaId.length; i++) {
|
|
179800
|
+
const char = areaId.charCodeAt(i);
|
|
179801
|
+
hash2 = (hash2 << 5) - hash2 + char;
|
|
179802
|
+
hash2 |= 0;
|
|
179803
|
+
}
|
|
179804
|
+
return Math.abs(hash2);
|
|
179805
|
+
}
|
|
179076
179806
|
|
|
179077
179807
|
// src/services/bridges/server-mode-bridge.ts
|
|
179078
179808
|
init_dist();
|
|
179079
179809
|
var AUTO_FORCE_SYNC_INTERVAL_MS2 = 9e4;
|
|
179810
|
+
var DEAD_SESSION_TIMEOUT_MS2 = 6e4;
|
|
179080
179811
|
var ServerModeBridge = class {
|
|
179081
|
-
constructor(
|
|
179812
|
+
constructor(logger204, dataProvider, endpointManager, server) {
|
|
179082
179813
|
this.dataProvider = dataProvider;
|
|
179083
179814
|
this.endpointManager = endpointManager;
|
|
179084
179815
|
this.server = server;
|
|
179085
|
-
this.log =
|
|
179816
|
+
this.log = logger204.get(`ServerModeBridge / ${dataProvider.id}`);
|
|
179086
179817
|
}
|
|
179087
179818
|
log;
|
|
179088
179819
|
status = {
|
|
@@ -179093,6 +179824,8 @@ var ServerModeBridge = class {
|
|
|
179093
179824
|
// broadcast updates via WebSocket so the frontend sees every transition.
|
|
179094
179825
|
onStatusChange;
|
|
179095
179826
|
autoForceSyncTimer = null;
|
|
179827
|
+
deadSessionTimer = null;
|
|
179828
|
+
staleSessionTimers = /* @__PURE__ */ new Map();
|
|
179096
179829
|
warmStartTimer = null;
|
|
179097
179830
|
// Tracks the last synced state JSON per entity to avoid pushing unchanged states.
|
|
179098
179831
|
lastSyncedState;
|
|
@@ -179274,6 +180007,33 @@ ${e?.toString()}`);
|
|
|
179274
180007
|
this.log.warn(
|
|
179275
180008
|
`All subscriptions lost \u2014 ${sessions.length} session(s) still active, waiting for controller to re-subscribe`
|
|
179276
180009
|
);
|
|
180010
|
+
if (!this.deadSessionTimer) {
|
|
180011
|
+
this.deadSessionTimer = setTimeout(() => {
|
|
180012
|
+
this.deadSessionTimer = null;
|
|
180013
|
+
this.closeDeadSessions();
|
|
180014
|
+
}, DEAD_SESSION_TIMEOUT_MS2);
|
|
180015
|
+
this.log.info(
|
|
180016
|
+
`Scheduled dead session cleanup in ${DEAD_SESSION_TIMEOUT_MS2 / 1e3}s`
|
|
180017
|
+
);
|
|
180018
|
+
}
|
|
180019
|
+
} else if (totalSubs > 0 && this.deadSessionTimer) {
|
|
180020
|
+
clearTimeout(this.deadSessionTimer);
|
|
180021
|
+
this.deadSessionTimer = null;
|
|
180022
|
+
this.log.info(
|
|
180023
|
+
"Subscriptions recovered, canceled dead session cleanup"
|
|
180024
|
+
);
|
|
180025
|
+
}
|
|
180026
|
+
if (session.subscriptions.size === 0 && !this.staleSessionTimers.has(session.id)) {
|
|
180027
|
+
this.staleSessionTimers.set(
|
|
180028
|
+
session.id,
|
|
180029
|
+
setTimeout(() => {
|
|
180030
|
+
this.staleSessionTimers.delete(session.id);
|
|
180031
|
+
this.closeStaleSession(session.id);
|
|
180032
|
+
}, DEAD_SESSION_TIMEOUT_MS2)
|
|
180033
|
+
);
|
|
180034
|
+
} else if (session.subscriptions.size > 0 && this.staleSessionTimers.has(session.id)) {
|
|
180035
|
+
clearTimeout(this.staleSessionTimers.get(session.id));
|
|
180036
|
+
this.staleSessionTimers.delete(session.id);
|
|
179277
180037
|
}
|
|
179278
180038
|
};
|
|
179279
180039
|
sessionManager.subscriptionsChanged.on(this.sessionDiagHandler);
|
|
@@ -179302,6 +180062,62 @@ ${e?.toString()}`);
|
|
|
179302
180062
|
} catch {
|
|
179303
180063
|
}
|
|
179304
180064
|
}
|
|
180065
|
+
closeStaleSession(sessionId) {
|
|
180066
|
+
try {
|
|
180067
|
+
const sessionManager = this.server.env.get(SessionManager);
|
|
180068
|
+
for (const s of [...sessionManager.sessions]) {
|
|
180069
|
+
if (s.id === sessionId && !s.isClosing && s.subscriptions.size === 0) {
|
|
180070
|
+
this.log.warn(
|
|
180071
|
+
`Closing stale session ${s.id} (peer ${s.peerNodeId}, no subscriptions for ${DEAD_SESSION_TIMEOUT_MS2 / 1e3}s)`
|
|
180072
|
+
);
|
|
180073
|
+
s.initiateClose().catch(() => {
|
|
180074
|
+
return s.initiateForceClose();
|
|
180075
|
+
}).catch(() => {
|
|
180076
|
+
}).finally(() => this.triggerMdnsReAnnounce());
|
|
180077
|
+
break;
|
|
180078
|
+
}
|
|
180079
|
+
}
|
|
180080
|
+
} catch {
|
|
180081
|
+
}
|
|
180082
|
+
}
|
|
180083
|
+
closeDeadSessions() {
|
|
180084
|
+
try {
|
|
180085
|
+
const sessionManager = this.server.env.get(SessionManager);
|
|
180086
|
+
const sessions = [...sessionManager.sessions];
|
|
180087
|
+
const closes = [];
|
|
180088
|
+
for (const s of sessions) {
|
|
180089
|
+
if (!s.isClosing && s.subscriptions.size === 0) {
|
|
180090
|
+
this.log.warn(
|
|
180091
|
+
`Closing dead session ${s.id} (peer ${s.peerNodeId}, no subscriptions for ${DEAD_SESSION_TIMEOUT_MS2 / 1e3}s)`
|
|
180092
|
+
);
|
|
180093
|
+
closes.push(
|
|
180094
|
+
s.initiateClose().catch(() => {
|
|
180095
|
+
return s.initiateForceClose();
|
|
180096
|
+
})
|
|
180097
|
+
);
|
|
180098
|
+
}
|
|
180099
|
+
}
|
|
180100
|
+
if (closes.length > 0) {
|
|
180101
|
+
Promise.allSettled(closes).then(() => this.triggerMdnsReAnnounce());
|
|
180102
|
+
}
|
|
180103
|
+
} catch {
|
|
180104
|
+
}
|
|
180105
|
+
}
|
|
180106
|
+
/**
|
|
180107
|
+
* Force a fresh mDNS operational advertisement after session cleanup.
|
|
180108
|
+
* matter.js DeviceAdvertiser only re-announces when a subscription is
|
|
180109
|
+
* canceled BY THE PEER. When the server cancels after 3 delivery
|
|
180110
|
+
* timeouts, no re-announcement happens and the controller may not
|
|
180111
|
+
* realize it should reconnect (#266).
|
|
180112
|
+
*/
|
|
180113
|
+
triggerMdnsReAnnounce() {
|
|
180114
|
+
try {
|
|
180115
|
+
const advertiser = this.server.env.get(DeviceAdvertiser);
|
|
180116
|
+
advertiser.restartAdvertisement();
|
|
180117
|
+
this.log.info("Triggered mDNS re-announcement after session cleanup");
|
|
180118
|
+
} catch {
|
|
180119
|
+
}
|
|
180120
|
+
}
|
|
179305
180121
|
unwireSessionDiagnostics() {
|
|
179306
180122
|
try {
|
|
179307
180123
|
const sessionManager = this.server.env.get(SessionManager);
|
|
@@ -179319,6 +180135,14 @@ ${e?.toString()}`);
|
|
|
179319
180135
|
this.sessionDiagHandler = void 0;
|
|
179320
180136
|
this.sessionAddedHandler = void 0;
|
|
179321
180137
|
this.sessionDeletedHandler = void 0;
|
|
180138
|
+
if (this.deadSessionTimer) {
|
|
180139
|
+
clearTimeout(this.deadSessionTimer);
|
|
180140
|
+
this.deadSessionTimer = null;
|
|
180141
|
+
}
|
|
180142
|
+
for (const timer of this.staleSessionTimers.values()) {
|
|
180143
|
+
clearTimeout(timer);
|
|
180144
|
+
}
|
|
180145
|
+
this.staleSessionTimers.clear();
|
|
179322
180146
|
}
|
|
179323
180147
|
stopAutoForceSync() {
|
|
179324
180148
|
if (this.autoForceSyncTimer) {
|
|
@@ -179434,7 +180258,7 @@ init_service();
|
|
|
179434
180258
|
// src/matter/endpoints/server-mode-vacuum-endpoint.ts
|
|
179435
180259
|
init_esm();
|
|
179436
180260
|
init_home_assistant_entity_behavior();
|
|
179437
|
-
import
|
|
180261
|
+
import debounce6 from "debounce";
|
|
179438
180262
|
|
|
179439
180263
|
// src/matter/endpoints/legacy/vacuum/server-mode-vacuum-device.ts
|
|
179440
180264
|
init_home_assistant_entity_behavior();
|
|
@@ -179448,17 +180272,24 @@ function ServerModeVacuumDevice(homeAssistantEntity, includeOnOff = false, clean
|
|
|
179448
180272
|
return void 0;
|
|
179449
180273
|
}
|
|
179450
180274
|
const attributes7 = homeAssistantEntity.entity.state.attributes;
|
|
180275
|
+
const cleanAreaRooms = homeAssistantEntity.mapping?.cleanAreaRooms;
|
|
180276
|
+
const customAreas = homeAssistantEntity.mapping?.customServiceAreas;
|
|
179451
180277
|
let device = ServerModeVacuumEndpointType.with(
|
|
179452
|
-
createVacuumRvcRunModeServer(
|
|
180278
|
+
cleanAreaRooms && cleanAreaRooms.length > 0 ? createCleanAreaRvcRunModeServer(cleanAreaRooms) : createVacuumRvcRunModeServer(
|
|
180279
|
+
attributes7,
|
|
180280
|
+
false,
|
|
180281
|
+
customAreas && customAreas.length > 0 ? customAreas : void 0
|
|
180282
|
+
)
|
|
179453
180283
|
).set({ homeAssistantEntity });
|
|
179454
180284
|
if (includeOnOff) {
|
|
179455
180285
|
device = device.with(VacuumOnOffServer);
|
|
179456
180286
|
}
|
|
179457
180287
|
device = device.with(VacuumPowerSourceServer);
|
|
179458
|
-
const customAreas = homeAssistantEntity.mapping?.customServiceAreas;
|
|
179459
180288
|
const roomEntities = homeAssistantEntity.mapping?.roomEntities;
|
|
179460
180289
|
const rooms = parseVacuumRooms(attributes7);
|
|
179461
|
-
if (
|
|
180290
|
+
if (cleanAreaRooms && cleanAreaRooms.length > 0) {
|
|
180291
|
+
device = device.with(createCleanAreaServiceAreaServer(cleanAreaRooms));
|
|
180292
|
+
} else if (customAreas && customAreas.length > 0) {
|
|
179462
180293
|
device = device.with(createCustomServiceAreaServer(customAreas));
|
|
179463
180294
|
} else if (rooms.length > 0 || roomEntities && roomEntities.length > 0) {
|
|
179464
180295
|
device = device.with(
|
|
@@ -179491,7 +180322,7 @@ function ServerModeVacuumDevice(homeAssistantEntity, includeOnOff = false, clean
|
|
|
179491
180322
|
}
|
|
179492
180323
|
|
|
179493
180324
|
// src/matter/endpoints/server-mode-vacuum-endpoint.ts
|
|
179494
|
-
var
|
|
180325
|
+
var logger202 = Logger.get("ServerModeVacuumEndpoint");
|
|
179495
180326
|
var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEndpoint {
|
|
179496
180327
|
static async create(registry2, entityId, mapping) {
|
|
179497
180328
|
const deviceRegistry = registry2.deviceOf(entityId);
|
|
@@ -179501,7 +180332,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179501
180332
|
return void 0;
|
|
179502
180333
|
}
|
|
179503
180334
|
let effectiveMapping = mapping;
|
|
179504
|
-
|
|
180335
|
+
logger202.info(
|
|
179505
180336
|
`${entityId}: device_id=${entity.device_id}, manualBattery=${mapping?.batteryEntity ?? "none"}`
|
|
179506
180337
|
);
|
|
179507
180338
|
if (entity.device_id) {
|
|
@@ -179516,11 +180347,18 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179516
180347
|
batteryEntity: batteryEntityId
|
|
179517
180348
|
};
|
|
179518
180349
|
registry2.markBatteryEntityUsed(batteryEntityId);
|
|
179519
|
-
|
|
180350
|
+
logger202.info(`${entityId}: Auto-assigned battery ${batteryEntityId}`);
|
|
179520
180351
|
} else {
|
|
179521
|
-
|
|
179522
|
-
|
|
179523
|
-
|
|
180352
|
+
const attrs = state.attributes;
|
|
180353
|
+
if (attrs.battery_level != null || attrs.battery != null) {
|
|
180354
|
+
logger202.info(
|
|
180355
|
+
`${entityId}: No battery entity found, using battery attribute from vacuum state`
|
|
180356
|
+
);
|
|
180357
|
+
} else {
|
|
180358
|
+
logger202.warn(
|
|
180359
|
+
`${entityId}: No battery entity found for device ${entity.device_id}`
|
|
180360
|
+
);
|
|
180361
|
+
}
|
|
179524
180362
|
}
|
|
179525
180363
|
}
|
|
179526
180364
|
const vacuumEntities = registry2.findVacuumSelectEntities(
|
|
@@ -179532,7 +180370,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179532
180370
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
179533
180371
|
cleaningModeEntity: vacuumEntities.cleaningModeEntity
|
|
179534
180372
|
};
|
|
179535
|
-
|
|
180373
|
+
logger202.info(
|
|
179536
180374
|
`${entityId}: Auto-assigned cleaningMode ${vacuumEntities.cleaningModeEntity}`
|
|
179537
180375
|
);
|
|
179538
180376
|
}
|
|
@@ -179542,7 +180380,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179542
180380
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
179543
180381
|
suctionLevelEntity: vacuumEntities.suctionLevelEntity
|
|
179544
180382
|
};
|
|
179545
|
-
|
|
180383
|
+
logger202.info(
|
|
179546
180384
|
`${entityId}: Auto-assigned suctionLevel ${vacuumEntities.suctionLevelEntity}`
|
|
179547
180385
|
);
|
|
179548
180386
|
}
|
|
@@ -179552,12 +180390,27 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179552
180390
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
179553
180391
|
mopIntensityEntity: vacuumEntities.mopIntensityEntity
|
|
179554
180392
|
};
|
|
179555
|
-
|
|
180393
|
+
logger202.info(
|
|
179556
180394
|
`${entityId}: Auto-assigned mopIntensity ${vacuumEntities.mopIntensityEntity}`
|
|
179557
180395
|
);
|
|
179558
180396
|
}
|
|
180397
|
+
const supportedFeatures = state.attributes.supported_features ?? 0;
|
|
180398
|
+
const cleanAreaRooms = await registry2.resolveCleanAreaRooms(
|
|
180399
|
+
entityId,
|
|
180400
|
+
supportedFeatures
|
|
180401
|
+
);
|
|
180402
|
+
if (cleanAreaRooms.length > 0) {
|
|
180403
|
+
effectiveMapping = {
|
|
180404
|
+
...effectiveMapping,
|
|
180405
|
+
entityId: effectiveMapping?.entityId ?? entityId,
|
|
180406
|
+
cleanAreaRooms
|
|
180407
|
+
};
|
|
180408
|
+
logger202.info(
|
|
180409
|
+
`${entityId}: Using ${cleanAreaRooms.length} HA areas via CLEAN_AREA`
|
|
180410
|
+
);
|
|
180411
|
+
}
|
|
179559
180412
|
const vacAttrs = state.attributes;
|
|
179560
|
-
if (!vacAttrs.rooms && !vacAttrs.segments && !vacAttrs.room_mapping) {
|
|
180413
|
+
if (cleanAreaRooms.length === 0 && !vacAttrs.rooms && !vacAttrs.segments && !vacAttrs.room_mapping) {
|
|
179561
180414
|
const valetudoRooms = registry2.findValetudoMapSegments(
|
|
179562
180415
|
entity.device_id
|
|
179563
180416
|
);
|
|
@@ -179573,7 +180426,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179573
180426
|
rooms: roomsObj
|
|
179574
180427
|
}
|
|
179575
180428
|
};
|
|
179576
|
-
|
|
180429
|
+
logger202.info(
|
|
179577
180430
|
`${entityId}: Auto-detected ${valetudoRooms.length} Valetudo segments`
|
|
179578
180431
|
);
|
|
179579
180432
|
} else {
|
|
@@ -179590,14 +180443,14 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179590
180443
|
rooms: roomsObj
|
|
179591
180444
|
}
|
|
179592
180445
|
};
|
|
179593
|
-
|
|
180446
|
+
logger202.info(
|
|
179594
180447
|
`${entityId}: Auto-detected ${roborockRooms.length} Roborock rooms`
|
|
179595
180448
|
);
|
|
179596
180449
|
}
|
|
179597
180450
|
}
|
|
179598
180451
|
}
|
|
179599
180452
|
} else {
|
|
179600
|
-
|
|
180453
|
+
logger202.warn(`${entityId}: No device_id \u2014 cannot auto-assign battery`);
|
|
179601
180454
|
}
|
|
179602
180455
|
const payload = {
|
|
179603
180456
|
entity_id: entityId,
|
|
@@ -179643,10 +180496,11 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179643
180496
|
);
|
|
179644
180497
|
}
|
|
179645
180498
|
lastState;
|
|
180499
|
+
pendingMappedChange = false;
|
|
179646
180500
|
flushUpdate;
|
|
179647
180501
|
constructor(type, entityId, customName, mappedEntityIds) {
|
|
179648
180502
|
super(type, entityId, customName, mappedEntityIds);
|
|
179649
|
-
this.flushUpdate =
|
|
180503
|
+
this.flushUpdate = debounce6(this.flushPendingUpdate.bind(this), 50);
|
|
179650
180504
|
}
|
|
179651
180505
|
async delete() {
|
|
179652
180506
|
this.flushUpdate.clear();
|
|
@@ -179659,11 +180513,12 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179659
180513
|
return;
|
|
179660
180514
|
}
|
|
179661
180515
|
if (mappedChanged) {
|
|
179662
|
-
|
|
180516
|
+
this.pendingMappedChange = true;
|
|
180517
|
+
logger202.debug(
|
|
179663
180518
|
`Mapped entity change detected for ${this.entityId}, forcing update`
|
|
179664
180519
|
);
|
|
179665
180520
|
}
|
|
179666
|
-
|
|
180521
|
+
logger202.debug(
|
|
179667
180522
|
`State update received for ${this.entityId}: state=${state.state}`
|
|
179668
180523
|
);
|
|
179669
180524
|
this.lastState = state;
|
|
@@ -179677,8 +180532,13 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179677
180532
|
}
|
|
179678
180533
|
try {
|
|
179679
180534
|
const current = this.stateOf(HomeAssistantEntityBehavior).entity;
|
|
180535
|
+
let effectiveState = state;
|
|
180536
|
+
if (this.pendingMappedChange) {
|
|
180537
|
+
this.pendingMappedChange = false;
|
|
180538
|
+
effectiveState = { ...state, last_updated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
180539
|
+
}
|
|
179680
180540
|
await this.setStateOf(HomeAssistantEntityBehavior, {
|
|
179681
|
-
entity: { ...current, state }
|
|
180541
|
+
entity: { ...current, state: effectiveState }
|
|
179682
180542
|
});
|
|
179683
180543
|
} catch (error) {
|
|
179684
180544
|
if (error instanceof TransactionDestroyedError || error instanceof DestroyedDependencyError) {
|
|
@@ -180072,10 +180932,10 @@ var BridgeEnvironmentFactory = class extends BridgeFactory {
|
|
|
180072
180932
|
// src/core/ioc/app-environment.ts
|
|
180073
180933
|
var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
180074
180934
|
constructor(rootEnv, options) {
|
|
180075
|
-
const
|
|
180935
|
+
const logger204 = rootEnv.get(LoggerService);
|
|
180076
180936
|
super({
|
|
180077
180937
|
id: "App",
|
|
180078
|
-
log:
|
|
180938
|
+
log: logger204.get("AppContainer"),
|
|
180079
180939
|
parent: rootEnv
|
|
180080
180940
|
});
|
|
180081
180941
|
this.options = options;
|
|
@@ -180088,8 +180948,8 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
180088
180948
|
}
|
|
180089
180949
|
construction;
|
|
180090
180950
|
async init() {
|
|
180091
|
-
const
|
|
180092
|
-
this.set(LoggerService,
|
|
180951
|
+
const logger204 = this.get(LoggerService);
|
|
180952
|
+
this.set(LoggerService, logger204);
|
|
180093
180953
|
this.set(AppStorage, new AppStorage(await this.load(StorageService)));
|
|
180094
180954
|
this.set(BridgeStorage, new BridgeStorage(await this.load(AppStorage)));
|
|
180095
180955
|
this.set(
|
|
@@ -180106,7 +180966,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
180106
180966
|
);
|
|
180107
180967
|
this.set(
|
|
180108
180968
|
HomeAssistantClient,
|
|
180109
|
-
new HomeAssistantClient(
|
|
180969
|
+
new HomeAssistantClient(logger204, this.options.homeAssistant)
|
|
180110
180970
|
);
|
|
180111
180971
|
this.set(
|
|
180112
180972
|
HomeAssistantConfig,
|
|
@@ -180114,7 +180974,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
180114
180974
|
);
|
|
180115
180975
|
this.set(
|
|
180116
180976
|
HomeAssistantActions,
|
|
180117
|
-
new HomeAssistantActions(
|
|
180977
|
+
new HomeAssistantActions(logger204, await this.load(HomeAssistantClient))
|
|
180118
180978
|
);
|
|
180119
180979
|
this.set(
|
|
180120
180980
|
HomeAssistantRegistry,
|
|
@@ -180150,7 +181010,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
180150
181010
|
this.set(
|
|
180151
181011
|
WebApi,
|
|
180152
181012
|
new WebApi(
|
|
180153
|
-
|
|
181013
|
+
logger204,
|
|
180154
181014
|
await this.load(BridgeService),
|
|
180155
181015
|
await this.load(HomeAssistantClient),
|
|
180156
181016
|
await this.load(HomeAssistantRegistry),
|
|
@@ -180176,7 +181036,7 @@ init_nodejs();
|
|
|
180176
181036
|
init_level_control();
|
|
180177
181037
|
|
|
180178
181038
|
// src/matter/patches/patch-level-control-tlv.ts
|
|
180179
|
-
var
|
|
181039
|
+
var logger203 = Logger.get("PatchLevelControlTlv");
|
|
180180
181040
|
function patchLevelControlTlv() {
|
|
180181
181041
|
let patched = 0;
|
|
180182
181042
|
const moveToLevelFields = LevelControl3.TlvMoveToLevelRequest.fieldDefinitions;
|
|
@@ -180190,11 +181050,11 @@ function patchLevelControlTlv() {
|
|
|
180190
181050
|
patched++;
|
|
180191
181051
|
}
|
|
180192
181052
|
if (patched > 0) {
|
|
180193
|
-
|
|
181053
|
+
logger203.info(
|
|
180194
181054
|
`Patched ${patched} LevelControl TLV schema(s): transitionTime is now optional (Google Home compatibility)`
|
|
180195
181055
|
);
|
|
180196
181056
|
} else {
|
|
180197
|
-
|
|
181057
|
+
logger203.warn(
|
|
180198
181058
|
"Failed to patch LevelControl TLV schemas \u2014 field definitions not found. Google Home brightness adjustment may not work."
|
|
180199
181059
|
);
|
|
180200
181060
|
}
|
|
@@ -180232,8 +181092,7 @@ process.on("unhandledRejection", (reason) => {
|
|
|
180232
181092
|
if (shouldSuppressError(reason)) {
|
|
180233
181093
|
return;
|
|
180234
181094
|
}
|
|
180235
|
-
console.error("Unhandled rejection:", reason);
|
|
180236
|
-
process.exit(1);
|
|
181095
|
+
console.error("Unhandled rejection (process continuing):", reason);
|
|
180237
181096
|
});
|
|
180238
181097
|
function registerFinalErrorHandlers() {
|
|
180239
181098
|
process.removeAllListeners("uncaughtException");
|
|
@@ -180259,8 +181118,7 @@ function registerFinalErrorHandlers() {
|
|
|
180259
181118
|
console.warn("Suppressed Matter.js internal error:", reason);
|
|
180260
181119
|
return;
|
|
180261
181120
|
}
|
|
180262
|
-
console.error("Unhandled rejection:", reason);
|
|
180263
|
-
process.exit(1);
|
|
181121
|
+
console.error("Unhandled rejection (process continuing):", reason);
|
|
180264
181122
|
});
|
|
180265
181123
|
}
|
|
180266
181124
|
async function startHandler(startOptions, webUiDist) {
|