@riddix/hamh 2.1.0-alpha.839 → 2.1.0-alpha.841
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/backend/cli.js
CHANGED
|
@@ -1767,8 +1767,8 @@ var init_Cancelable = __esm({
|
|
|
1767
1767
|
};
|
|
1768
1768
|
return result;
|
|
1769
1769
|
}
|
|
1770
|
-
static set logger(
|
|
1771
|
-
this.#logger =
|
|
1770
|
+
static set logger(logger251) {
|
|
1771
|
+
this.#logger = logger251;
|
|
1772
1772
|
}
|
|
1773
1773
|
static get logger() {
|
|
1774
1774
|
return this.#logger;
|
|
@@ -3475,13 +3475,13 @@ var init_Logger = __esm({
|
|
|
3475
3475
|
*
|
|
3476
3476
|
* @deprecated use {@link destinations}
|
|
3477
3477
|
*/
|
|
3478
|
-
static addLogger(identifier,
|
|
3478
|
+
static addLogger(identifier, logger251, options) {
|
|
3479
3479
|
if (identifier in this.destinations) {
|
|
3480
3480
|
throw new ImplementationError(`Logger "${identifier}" already exists`);
|
|
3481
3481
|
}
|
|
3482
3482
|
const dest = LogDestination({ name: identifier });
|
|
3483
3483
|
const legacy = adaptDestinationToLegacy(dest);
|
|
3484
|
-
legacy.log =
|
|
3484
|
+
legacy.log = logger251;
|
|
3485
3485
|
if (options?.defaultLogLevel !== void 0) {
|
|
3486
3486
|
legacy.defaultLogLevel = options.defaultLogLevel;
|
|
3487
3487
|
}
|
|
@@ -5687,8 +5687,8 @@ var init_Construction = __esm({
|
|
|
5687
5687
|
}
|
|
5688
5688
|
}
|
|
5689
5689
|
#unhandledError(...args) {
|
|
5690
|
-
const
|
|
5691
|
-
|
|
5690
|
+
const logger251 = Logger.get(this.#subject.constructor.name);
|
|
5691
|
+
logger251.error(...args);
|
|
5692
5692
|
}
|
|
5693
5693
|
#createErrorHandler(name) {
|
|
5694
5694
|
return (e) => {
|
|
@@ -11712,18 +11712,18 @@ var init_FileHandleTracker = __esm({
|
|
|
11712
11712
|
logger12 = Logger.get("FileHandleTracker");
|
|
11713
11713
|
((FileHandleTracker2) => {
|
|
11714
11714
|
const openHandles = /* @__PURE__ */ new Set();
|
|
11715
|
-
const
|
|
11715
|
+
const registry3 = new FinalizationRegistry((info) => {
|
|
11716
11716
|
logger12.warn(`File handle GC'd without close: "${info.purpose}" for ${info.path}`);
|
|
11717
11717
|
});
|
|
11718
11718
|
function register(handle) {
|
|
11719
11719
|
const info = { purpose: handle.purpose, path: handle.path };
|
|
11720
|
-
|
|
11720
|
+
registry3.register(handle, info, handle);
|
|
11721
11721
|
const ref = new WeakRef(handle);
|
|
11722
11722
|
openHandles.add(ref);
|
|
11723
11723
|
}
|
|
11724
11724
|
FileHandleTracker2.register = register;
|
|
11725
11725
|
function unregister(handle) {
|
|
11726
|
-
|
|
11726
|
+
registry3.unregister(handle);
|
|
11727
11727
|
for (const ref of openHandles) {
|
|
11728
11728
|
if (ref.deref() === handle) {
|
|
11729
11729
|
openHandles.delete(ref);
|
|
@@ -64070,8 +64070,8 @@ var init_NodeSession = __esm({
|
|
|
64070
64070
|
return session?.type === SessionType.Unicast;
|
|
64071
64071
|
}
|
|
64072
64072
|
NodeSession2.is = is;
|
|
64073
|
-
function logNew(
|
|
64074
|
-
|
|
64073
|
+
function logNew(logger251, operation, session, messenger, fabric, peerNodeId) {
|
|
64074
|
+
logger251.info(
|
|
64075
64075
|
session.via,
|
|
64076
64076
|
`${operation} session with`,
|
|
64077
64077
|
Diagnostic.strong(PeerAddress({ fabricIndex: fabric.fabricIndex, nodeId: peerNodeId }).toString()),
|
|
@@ -117714,11 +117714,11 @@ var init_Api = __esm({
|
|
|
117714
117714
|
}
|
|
117715
117715
|
Api2.resourceFor = resourceFor;
|
|
117716
117716
|
function log(level, facility, id, ...message) {
|
|
117717
|
-
let
|
|
117718
|
-
if (!
|
|
117719
|
-
loggers.set(facility,
|
|
117717
|
+
let logger251 = loggers.get(facility);
|
|
117718
|
+
if (!logger251) {
|
|
117719
|
+
loggers.set(facility, logger251 = Logger.get(facility));
|
|
117720
117720
|
}
|
|
117721
|
-
|
|
117721
|
+
logger251[level](Diagnostic.via(id || "(anon)"), message);
|
|
117722
117722
|
}
|
|
117723
117723
|
Api2.log = log;
|
|
117724
117724
|
function logRequest(facility, id, method, target) {
|
|
@@ -132631,10 +132631,10 @@ var init_home_assistant_actions = __esm({
|
|
|
132631
132631
|
circuitBreakerResetMs: 3e4
|
|
132632
132632
|
};
|
|
132633
132633
|
HomeAssistantActions = class extends Service {
|
|
132634
|
-
constructor(
|
|
132634
|
+
constructor(logger251, client, config11) {
|
|
132635
132635
|
super("HomeAssistantActions");
|
|
132636
132636
|
this.client = client;
|
|
132637
|
-
this.log =
|
|
132637
|
+
this.log = logger251.get(this);
|
|
132638
132638
|
this.config = { ...defaultConfig, ...config11 };
|
|
132639
132639
|
this.circuitBreaker = new CircuitBreaker(
|
|
132640
132640
|
this.config.circuitBreakerThreshold,
|
|
@@ -132980,10 +132980,10 @@ var DiagnosticService = class {
|
|
|
132980
132980
|
};
|
|
132981
132981
|
|
|
132982
132982
|
// src/api/access-log.ts
|
|
132983
|
-
function accessLogger(
|
|
132983
|
+
function accessLogger(logger251) {
|
|
132984
132984
|
return (req, res, next) => {
|
|
132985
132985
|
res.on("finish", () => {
|
|
132986
|
-
|
|
132986
|
+
logger251.debug(
|
|
132987
132987
|
`${req.method} ${decodeURI(req.originalUrl)} ${res.statusCode} ${res.statusMessage} from ${req.socket.remoteAddress}`
|
|
132988
132988
|
);
|
|
132989
132989
|
});
|
|
@@ -136617,7 +136617,7 @@ var BLOCKED_PREFIXES = [
|
|
|
136617
136617
|
function pluginApi(bridgeService, storageLocation) {
|
|
136618
136618
|
const router = express14.Router();
|
|
136619
136619
|
const installer = new PluginInstaller(storageLocation);
|
|
136620
|
-
const
|
|
136620
|
+
const registry3 = new PluginRegistry(storageLocation);
|
|
136621
136621
|
router.get("/", (_req, res) => {
|
|
136622
136622
|
const result = [];
|
|
136623
136623
|
for (const bridge of bridgeService.bridges) {
|
|
@@ -136702,7 +136702,7 @@ function pluginApi(bridgeService, storageLocation) {
|
|
|
136702
136702
|
res.json({ success: true, pluginName, reset: true });
|
|
136703
136703
|
});
|
|
136704
136704
|
router.get("/installed", (_req, res) => {
|
|
136705
|
-
const registered =
|
|
136705
|
+
const registered = registry3.getAll();
|
|
136706
136706
|
const npmInstalled = installer.listInstalled();
|
|
136707
136707
|
const result = registered.map((entry) => {
|
|
136708
136708
|
const npm = npmInstalled.find((p) => p.name === entry.packageName);
|
|
@@ -136732,7 +136732,7 @@ function pluginApi(bridgeService, storageLocation) {
|
|
|
136732
136732
|
});
|
|
136733
136733
|
return;
|
|
136734
136734
|
}
|
|
136735
|
-
|
|
136735
|
+
registry3.add(packageName, config11 ?? {});
|
|
136736
136736
|
res.json({
|
|
136737
136737
|
success: true,
|
|
136738
136738
|
packageName,
|
|
@@ -136760,7 +136760,7 @@ function pluginApi(bridgeService, storageLocation) {
|
|
|
136760
136760
|
});
|
|
136761
136761
|
return;
|
|
136762
136762
|
}
|
|
136763
|
-
|
|
136763
|
+
registry3.remove(packageName);
|
|
136764
136764
|
res.json({
|
|
136765
136765
|
success: true,
|
|
136766
136766
|
packageName,
|
|
@@ -136800,7 +136800,7 @@ function pluginApi(bridgeService, storageLocation) {
|
|
|
136800
136800
|
});
|
|
136801
136801
|
return;
|
|
136802
136802
|
}
|
|
136803
|
-
|
|
136803
|
+
registry3.add(result.packageName, {});
|
|
136804
136804
|
res.json({
|
|
136805
136805
|
success: true,
|
|
136806
136806
|
packageName: result.packageName,
|
|
@@ -136833,7 +136833,7 @@ function pluginApi(bridgeService, storageLocation) {
|
|
|
136833
136833
|
});
|
|
136834
136834
|
return;
|
|
136835
136835
|
}
|
|
136836
|
-
|
|
136836
|
+
registry3.add(result.packageName, {});
|
|
136837
136837
|
res.json({
|
|
136838
136838
|
success: true,
|
|
136839
136839
|
packageName: result.packageName,
|
|
@@ -137530,7 +137530,7 @@ var WebSocketApi = class {
|
|
|
137530
137530
|
|
|
137531
137531
|
// src/api/web-api.ts
|
|
137532
137532
|
var WebApi = class extends Service {
|
|
137533
|
-
constructor(
|
|
137533
|
+
constructor(logger251, bridgeService, haClient, haRegistry, bridgeStorage, mappingStorage, identityStorage, lockCredentialStorage, settingsStorage, backupService, props) {
|
|
137534
137534
|
super("WebApi");
|
|
137535
137535
|
this.bridgeService = bridgeService;
|
|
137536
137536
|
this.haClient = haClient;
|
|
@@ -137542,8 +137542,8 @@ var WebApi = class extends Service {
|
|
|
137542
137542
|
this.settingsStorage = settingsStorage;
|
|
137543
137543
|
this.backupService = backupService;
|
|
137544
137544
|
this.props = props;
|
|
137545
|
-
this.logger =
|
|
137546
|
-
this.log =
|
|
137545
|
+
this.logger = logger251;
|
|
137546
|
+
this.log = logger251.get(this);
|
|
137547
137547
|
this.accessLogger = accessLogger(this.log.createChild("Access Log"));
|
|
137548
137548
|
this.startTime = Date.now();
|
|
137549
137549
|
this.wsApi = new WebSocketApi(
|
|
@@ -138734,10 +138734,10 @@ function isTransientConnectError(reason) {
|
|
|
138734
138734
|
return msg.includes("socket hang up") || msg.includes("tls") || msg.includes("TLS");
|
|
138735
138735
|
}
|
|
138736
138736
|
var HomeAssistantClient = class extends Service {
|
|
138737
|
-
constructor(
|
|
138737
|
+
constructor(logger251, options) {
|
|
138738
138738
|
super("HomeAssistantClient");
|
|
138739
138739
|
this.options = options;
|
|
138740
|
-
this.log =
|
|
138740
|
+
this.log = logger251.get(this);
|
|
138741
138741
|
}
|
|
138742
138742
|
options;
|
|
138743
138743
|
static Options = /* @__PURE__ */ Symbol.for("HomeAssistantClientProps");
|
|
@@ -156524,8 +156524,8 @@ var PluginManager = class {
|
|
|
156524
156524
|
this.storageDir = storageDir;
|
|
156525
156525
|
this.homeAssistant = homeAssistant;
|
|
156526
156526
|
}
|
|
156527
|
-
setRegistry(
|
|
156528
|
-
this.registry =
|
|
156527
|
+
setRegistry(registry3) {
|
|
156528
|
+
this.registry = registry3;
|
|
156529
156529
|
}
|
|
156530
156530
|
/**
|
|
156531
156531
|
* Load and register a built-in plugin instance.
|
|
@@ -157335,11 +157335,11 @@ var AUTO_FORCE_SYNC_INTERVAL_MS = 9e4;
|
|
|
157335
157335
|
var SHUTDOWN_SESSION_CLOSE_TIMEOUT_MS = 2500;
|
|
157336
157336
|
var MDNS_ADDRESS_CHECK_INTERVAL_MS = 6e4;
|
|
157337
157337
|
var Bridge = class {
|
|
157338
|
-
constructor(env,
|
|
157338
|
+
constructor(env, logger251, dataProvider, endpointManager, serverOptions) {
|
|
157339
157339
|
this.dataProvider = dataProvider;
|
|
157340
157340
|
this.endpointManager = endpointManager;
|
|
157341
157341
|
this.serverOptions = serverOptions;
|
|
157342
|
-
this.log =
|
|
157342
|
+
this.log = logger251.get(`Bridge / ${dataProvider.id}`);
|
|
157343
157343
|
this.server = new BridgeServerNode(
|
|
157344
157344
|
env,
|
|
157345
157345
|
this.dataProvider,
|
|
@@ -158471,9 +158471,9 @@ function resolveBatteryPercent(state) {
|
|
|
158471
158471
|
return BATTERY_ENUM_PERCENT[state.toLowerCase()] ?? null;
|
|
158472
158472
|
}
|
|
158473
158473
|
var EntityStateProvider = class extends Service {
|
|
158474
|
-
constructor(
|
|
158474
|
+
constructor(registry3) {
|
|
158475
158475
|
super("EntityStateProvider");
|
|
158476
|
-
this.registry =
|
|
158476
|
+
this.registry = registry3;
|
|
158477
158477
|
}
|
|
158478
158478
|
registry;
|
|
158479
158479
|
/**
|
|
@@ -160391,11 +160391,11 @@ function createEndpointId2(entityId, customName) {
|
|
|
160391
160391
|
const baseName = customName || entityId;
|
|
160392
160392
|
return baseName.replace(/\./g, "_").replace(/\s+/g, "_");
|
|
160393
160393
|
}
|
|
160394
|
-
function buildEntityPayload(
|
|
160395
|
-
const state =
|
|
160394
|
+
function buildEntityPayload(registry3, entityId) {
|
|
160395
|
+
const state = registry3.initialState(entityId);
|
|
160396
160396
|
if (!state) return void 0;
|
|
160397
|
-
const entity =
|
|
160398
|
-
const deviceRegistry =
|
|
160397
|
+
const entity = registry3.entity(entityId);
|
|
160398
|
+
const deviceRegistry = registry3.deviceOf(entityId);
|
|
160399
160399
|
return {
|
|
160400
160400
|
entity_id: entityId,
|
|
160401
160401
|
state,
|
|
@@ -160410,8 +160410,8 @@ var ComposedAirPurifierEndpoint = class _ComposedAirPurifierEndpoint extends End
|
|
|
160410
160410
|
lastStates = /* @__PURE__ */ new Map();
|
|
160411
160411
|
debouncedUpdates = /* @__PURE__ */ new Map();
|
|
160412
160412
|
static async create(config11) {
|
|
160413
|
-
const { registry:
|
|
160414
|
-
const primaryPayload = buildEntityPayload(
|
|
160413
|
+
const { registry: registry3, primaryEntityId } = config11;
|
|
160414
|
+
const primaryPayload = buildEntityPayload(registry3, primaryEntityId);
|
|
160415
160415
|
if (!primaryPayload) return void 0;
|
|
160416
160416
|
const airPurifierAttributes = primaryPayload.state.attributes;
|
|
160417
160417
|
const supportedFeatures = airPurifierAttributes.supported_features ?? 0;
|
|
@@ -160499,7 +160499,7 @@ var ComposedAirPurifierEndpoint = class _ComposedAirPurifierEndpoint extends End
|
|
|
160499
160499
|
let tempSub;
|
|
160500
160500
|
if (config11.temperatureEntityId) {
|
|
160501
160501
|
const tempPayload = buildEntityPayload(
|
|
160502
|
-
|
|
160502
|
+
registry3,
|
|
160503
160503
|
config11.temperatureEntityId
|
|
160504
160504
|
);
|
|
160505
160505
|
if (tempPayload) {
|
|
@@ -160514,7 +160514,7 @@ var ComposedAirPurifierEndpoint = class _ComposedAirPurifierEndpoint extends End
|
|
|
160514
160514
|
}
|
|
160515
160515
|
let humSub;
|
|
160516
160516
|
if (config11.humidityEntityId) {
|
|
160517
|
-
const humPayload = buildEntityPayload(
|
|
160517
|
+
const humPayload = buildEntityPayload(registry3, config11.humidityEntityId);
|
|
160518
160518
|
if (humPayload) {
|
|
160519
160519
|
humSub = new Endpoint(
|
|
160520
160520
|
HumiditySubType.set({
|
|
@@ -161968,14 +161968,14 @@ function createEndpointId3(entityId, customName) {
|
|
|
161968
161968
|
const baseName = customName || entityId;
|
|
161969
161969
|
return baseName.replace(/\./g, "_").replace(/\s+/g, "_");
|
|
161970
161970
|
}
|
|
161971
|
-
function buildEntityPayload2(
|
|
161972
|
-
const state =
|
|
161971
|
+
function buildEntityPayload2(registry3, entityId) {
|
|
161972
|
+
const state = registry3.initialState(entityId);
|
|
161973
161973
|
if (!state) return void 0;
|
|
161974
161974
|
return {
|
|
161975
161975
|
entity_id: entityId,
|
|
161976
161976
|
state,
|
|
161977
|
-
registry:
|
|
161978
|
-
deviceRegistry:
|
|
161977
|
+
registry: registry3.entity(entityId),
|
|
161978
|
+
deviceRegistry: registry3.deviceOf(entityId)
|
|
161979
161979
|
};
|
|
161980
161980
|
}
|
|
161981
161981
|
var ComposedClimateFanEndpoint = class _ComposedClimateFanEndpoint extends Endpoint {
|
|
@@ -161985,8 +161985,8 @@ var ComposedClimateFanEndpoint = class _ComposedClimateFanEndpoint extends Endpo
|
|
|
161985
161985
|
lastStates = /* @__PURE__ */ new Map();
|
|
161986
161986
|
debouncedUpdates = /* @__PURE__ */ new Map();
|
|
161987
161987
|
static async create(config11) {
|
|
161988
|
-
const { registry:
|
|
161989
|
-
const payload = buildEntityPayload2(
|
|
161988
|
+
const { registry: registry3, primaryEntityId } = config11;
|
|
161989
|
+
const payload = buildEntityPayload2(registry3, primaryEntityId);
|
|
161990
161990
|
if (!payload) return void 0;
|
|
161991
161991
|
const endpointId = config11.endpointId ?? createEndpointId3(primaryEntityId, config11.customName);
|
|
161992
161992
|
const mapping = config11.mapping ?? {
|
|
@@ -162244,11 +162244,11 @@ function createEndpointId4(entityId, customName) {
|
|
|
162244
162244
|
const baseName = customName || entityId;
|
|
162245
162245
|
return baseName.replace(/\./g, "_").replace(/\s+/g, "_");
|
|
162246
162246
|
}
|
|
162247
|
-
function buildEntityPayload3(
|
|
162248
|
-
const state =
|
|
162247
|
+
function buildEntityPayload3(registry3, entityId) {
|
|
162248
|
+
const state = registry3.initialStateIncludingUnfiltered(entityId);
|
|
162249
162249
|
if (!state) return void 0;
|
|
162250
|
-
const entity =
|
|
162251
|
-
const deviceRegistry =
|
|
162250
|
+
const entity = registry3.entityIncludingUnfiltered(entityId);
|
|
162251
|
+
const deviceRegistry = registry3.deviceOfIncludingUnfiltered(entityId);
|
|
162252
162252
|
return {
|
|
162253
162253
|
entity_id: entityId,
|
|
162254
162254
|
state,
|
|
@@ -162263,8 +162263,8 @@ var ComposedSensorEndpoint = class _ComposedSensorEndpoint extends Endpoint {
|
|
|
162263
162263
|
lastStates = /* @__PURE__ */ new Map();
|
|
162264
162264
|
debouncedUpdates = /* @__PURE__ */ new Map();
|
|
162265
162265
|
static async create(config11) {
|
|
162266
|
-
const { registry:
|
|
162267
|
-
const primaryPayload = buildEntityPayload3(
|
|
162266
|
+
const { registry: registry3, primaryEntityId } = config11;
|
|
162267
|
+
const primaryPayload = buildEntityPayload3(registry3, primaryEntityId);
|
|
162268
162268
|
if (!primaryPayload) return void 0;
|
|
162269
162269
|
let parentType = BridgedNodeEndpoint.with(
|
|
162270
162270
|
BasicInformationServer2,
|
|
@@ -162308,7 +162308,7 @@ var ComposedSensorEndpoint = class _ComposedSensorEndpoint extends Endpoint {
|
|
|
162308
162308
|
parts.push(tempSub);
|
|
162309
162309
|
let humSub;
|
|
162310
162310
|
if (config11.humidityEntityId) {
|
|
162311
|
-
const humPayload = buildEntityPayload3(
|
|
162311
|
+
const humPayload = buildEntityPayload3(registry3, config11.humidityEntityId);
|
|
162312
162312
|
if (humPayload) {
|
|
162313
162313
|
humSub = new Endpoint(
|
|
162314
162314
|
HumiditySubType2.set({
|
|
@@ -162322,7 +162322,7 @@ var ComposedSensorEndpoint = class _ComposedSensorEndpoint extends Endpoint {
|
|
|
162322
162322
|
let pressSub;
|
|
162323
162323
|
if (config11.pressureEntityId) {
|
|
162324
162324
|
const pressPayload = buildEntityPayload3(
|
|
162325
|
-
|
|
162325
|
+
registry3,
|
|
162326
162326
|
config11.pressureEntityId
|
|
162327
162327
|
);
|
|
162328
162328
|
if (pressPayload) {
|
|
@@ -169774,8 +169774,8 @@ var VacuumIdentifyServer = class extends IdentifyServer2 {
|
|
|
169774
169774
|
#findIdentifyButton(homeAssistant) {
|
|
169775
169775
|
const deviceId = homeAssistant.entity.registry?.device_id;
|
|
169776
169776
|
if (!deviceId) return void 0;
|
|
169777
|
-
const
|
|
169778
|
-
for (const entity of Object.values(
|
|
169777
|
+
const registry3 = this.env.get(HomeAssistantRegistry);
|
|
169778
|
+
for (const entity of Object.values(registry3.entities)) {
|
|
169779
169779
|
if (entity.device_id !== deviceId) continue;
|
|
169780
169780
|
if (!entity.entity_id.startsWith("button.")) continue;
|
|
169781
169781
|
const uniqueId = entity.unique_id ?? "";
|
|
@@ -172178,11 +172178,11 @@ function createEndpointId5(entityId, customName) {
|
|
|
172178
172178
|
const baseName = customName || entityId;
|
|
172179
172179
|
return baseName.replace(/\./g, "_").replace(/\s+/g, "_");
|
|
172180
172180
|
}
|
|
172181
|
-
function buildEntityPayload4(
|
|
172182
|
-
const state =
|
|
172181
|
+
function buildEntityPayload4(registry3, entityId) {
|
|
172182
|
+
const state = registry3.initialStateIncludingUnfiltered(entityId);
|
|
172183
172183
|
if (!state) return void 0;
|
|
172184
|
-
const entity =
|
|
172185
|
-
const deviceRegistry =
|
|
172184
|
+
const entity = registry3.entityIncludingUnfiltered(entityId);
|
|
172185
|
+
const deviceRegistry = registry3.deviceOfIncludingUnfiltered(entityId);
|
|
172186
172186
|
return {
|
|
172187
172187
|
entity_id: entityId,
|
|
172188
172188
|
state,
|
|
@@ -172198,8 +172198,8 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
172198
172198
|
lastMappedStates = /* @__PURE__ */ new Map();
|
|
172199
172199
|
debouncedUpdates = /* @__PURE__ */ new Map();
|
|
172200
172200
|
static async create(config11) {
|
|
172201
|
-
const { registry:
|
|
172202
|
-
const primaryPayload = buildEntityPayload4(
|
|
172201
|
+
const { registry: registry3, primaryEntityId, composedEntities } = config11;
|
|
172202
|
+
const primaryPayload = buildEntityPayload4(registry3, primaryEntityId);
|
|
172203
172203
|
if (!primaryPayload) return void 0;
|
|
172204
172204
|
let parentType = BridgedNodeEndpoint.with(
|
|
172205
172205
|
BasicInformationServer2,
|
|
@@ -172241,7 +172241,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
172241
172241
|
primarySubPayload,
|
|
172242
172242
|
primaryMapping,
|
|
172243
172243
|
config11.areaName,
|
|
172244
|
-
{ vacuumOnOff:
|
|
172244
|
+
{ vacuumOnOff: registry3.isVacuumOnOffEnabled() }
|
|
172245
172245
|
);
|
|
172246
172246
|
if (!primaryType) {
|
|
172247
172247
|
logger242.warn(
|
|
@@ -172257,7 +172257,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
172257
172257
|
for (let i = 0; i < composedEntities.length; i++) {
|
|
172258
172258
|
const sub = composedEntities[i];
|
|
172259
172259
|
if (!sub.entityId) continue;
|
|
172260
|
-
const subPayload = buildEntityPayload4(
|
|
172260
|
+
const subPayload = buildEntityPayload4(registry3, sub.entityId);
|
|
172261
172261
|
if (!subPayload) {
|
|
172262
172262
|
logger242.warn(
|
|
172263
172263
|
`Cannot find state for composed sub-entity ${sub.entityId}, it does not exist in Home Assistant (removed or renamed?)`
|
|
@@ -172419,32 +172419,32 @@ function asStandaloneEndpointType(type) {
|
|
|
172419
172419
|
// src/matter/endpoints/legacy/legacy-endpoint.ts
|
|
172420
172420
|
var logger243 = Logger.get("LegacyEndpoint");
|
|
172421
172421
|
var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
172422
|
-
static async create(
|
|
172423
|
-
const deviceRegistry =
|
|
172424
|
-
let state =
|
|
172425
|
-
const entity =
|
|
172422
|
+
static async create(registry3, entityId, mapping, pluginDomainMappings, standalone = false, endpointId, identityAnchor) {
|
|
172423
|
+
const deviceRegistry = registry3.deviceOf(entityId);
|
|
172424
|
+
let state = registry3.initialState(entityId);
|
|
172425
|
+
const entity = registry3.entity(entityId);
|
|
172426
172426
|
if (!state) {
|
|
172427
172427
|
return;
|
|
172428
172428
|
}
|
|
172429
|
-
if (
|
|
172429
|
+
if (registry3.isAutoBatteryMappingEnabled() && registry3.isBatteryEntityUsed(entityId)) {
|
|
172430
172430
|
logger243.debug(
|
|
172431
172431
|
`Skipping ${entityId} - already auto-assigned as battery to another device`
|
|
172432
172432
|
);
|
|
172433
172433
|
return;
|
|
172434
172434
|
}
|
|
172435
|
-
if (
|
|
172435
|
+
if (registry3.isAutoHumidityMappingEnabled() && registry3.isHumidityEntityUsed(entityId)) {
|
|
172436
172436
|
logger243.debug(
|
|
172437
172437
|
`Skipping ${entityId} - already auto-assigned as humidity to a temperature sensor`
|
|
172438
172438
|
);
|
|
172439
172439
|
return;
|
|
172440
172440
|
}
|
|
172441
|
-
if (
|
|
172441
|
+
if (registry3.isAutoPressureMappingEnabled() && registry3.isPressureEntityUsed(entityId)) {
|
|
172442
172442
|
logger243.debug(
|
|
172443
172443
|
`Skipping ${entityId} - already auto-assigned as pressure to a temperature sensor`
|
|
172444
172444
|
);
|
|
172445
172445
|
return;
|
|
172446
172446
|
}
|
|
172447
|
-
if (
|
|
172447
|
+
if (registry3.isAutoComposedDevicesEnabled() && registry3.isComposedSubEntityUsed(entityId)) {
|
|
172448
172448
|
logger243.debug(
|
|
172449
172449
|
`Skipping ${entityId} - already consumed by a composed device`
|
|
172450
172450
|
);
|
|
@@ -172452,10 +172452,10 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172452
172452
|
}
|
|
172453
172453
|
let effectiveMapping = mapping;
|
|
172454
172454
|
if (entity.device_id) {
|
|
172455
|
-
if (
|
|
172455
|
+
if (registry3.isAutoHumidityMappingEnabled()) {
|
|
172456
172456
|
const attrs = state.attributes;
|
|
172457
172457
|
if (!mapping?.humidityEntity && entityId.startsWith("sensor.") && attrs.device_class === SensorDeviceClass.temperature) {
|
|
172458
|
-
const humidityEntityId =
|
|
172458
|
+
const humidityEntityId = registry3.findHumidityEntityForDevice(
|
|
172459
172459
|
entity.device_id
|
|
172460
172460
|
);
|
|
172461
172461
|
if (humidityEntityId && humidityEntityId !== entityId) {
|
|
@@ -172464,17 +172464,17 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172464
172464
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
172465
172465
|
humidityEntity: humidityEntityId
|
|
172466
172466
|
};
|
|
172467
|
-
|
|
172467
|
+
registry3.markHumidityEntityUsed(humidityEntityId);
|
|
172468
172468
|
logger243.debug(
|
|
172469
172469
|
`Auto-assigned humidity ${humidityEntityId} to ${entityId}`
|
|
172470
172470
|
);
|
|
172471
172471
|
}
|
|
172472
172472
|
}
|
|
172473
172473
|
}
|
|
172474
|
-
if (
|
|
172474
|
+
if (registry3.isAutoPressureMappingEnabled()) {
|
|
172475
172475
|
const attrs = state.attributes;
|
|
172476
172476
|
if (!mapping?.pressureEntity && entityId.startsWith("sensor.") && attrs.device_class === SensorDeviceClass.temperature) {
|
|
172477
|
-
const pressureEntityId =
|
|
172477
|
+
const pressureEntityId = registry3.findPressureEntityForDevice(
|
|
172478
172478
|
entity.device_id
|
|
172479
172479
|
);
|
|
172480
172480
|
if (pressureEntityId && pressureEntityId !== entityId) {
|
|
@@ -172483,7 +172483,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172483
172483
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
172484
172484
|
pressureEntity: pressureEntityId
|
|
172485
172485
|
};
|
|
172486
|
-
|
|
172486
|
+
registry3.markPressureEntityUsed(pressureEntityId);
|
|
172487
172487
|
logger243.debug(
|
|
172488
172488
|
`Auto-assigned pressure ${pressureEntityId} to ${entityId}`
|
|
172489
172489
|
);
|
|
@@ -172491,8 +172491,8 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172491
172491
|
}
|
|
172492
172492
|
}
|
|
172493
172493
|
const isVacuum = entityId.startsWith("vacuum.");
|
|
172494
|
-
if ((
|
|
172495
|
-
const batteryEntityId =
|
|
172494
|
+
if ((registry3.isAutoBatteryMappingEnabled() || isVacuum) && !mapping?.batteryEntity && !mapping?.disableBatteryMapping) {
|
|
172495
|
+
const batteryEntityId = registry3.findBatteryEntityForDevice(
|
|
172496
172496
|
entity.device_id
|
|
172497
172497
|
);
|
|
172498
172498
|
if (batteryEntityId && batteryEntityId !== entityId) {
|
|
@@ -172501,7 +172501,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172501
172501
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
172502
172502
|
batteryEntity: batteryEntityId
|
|
172503
172503
|
};
|
|
172504
|
-
|
|
172504
|
+
registry3.markBatteryEntityUsed(batteryEntityId);
|
|
172505
172505
|
logger243.debug(
|
|
172506
172506
|
`Auto-assigned battery ${batteryEntityId} to ${entityId}`
|
|
172507
172507
|
);
|
|
@@ -172509,8 +172509,8 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172509
172509
|
}
|
|
172510
172510
|
const alarmDeviceClass = state.attributes.device_class;
|
|
172511
172511
|
const isSmokeCoAlarm = mapping?.matterDeviceType === "smoke_co_alarm" || entityId.startsWith("binary_sensor.") && (alarmDeviceClass === "smoke" || alarmDeviceClass === "carbon_monoxide" || alarmDeviceClass === "gas");
|
|
172512
|
-
if (
|
|
172513
|
-
const faultEntityId =
|
|
172512
|
+
if (registry3.isAutoBatteryMappingEnabled() && !mapping?.faultEntity && isSmokeCoAlarm) {
|
|
172513
|
+
const faultEntityId = registry3.findProblemEntityForDevice(
|
|
172514
172514
|
entity.device_id
|
|
172515
172515
|
);
|
|
172516
172516
|
if (faultEntityId && faultEntityId !== entityId) {
|
|
@@ -172525,7 +172525,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172525
172525
|
if (!mapping?.powerEntity) {
|
|
172526
172526
|
const domain = entityId.split(".")[0];
|
|
172527
172527
|
if (domain === "switch") {
|
|
172528
|
-
const powerEntityId =
|
|
172528
|
+
const powerEntityId = registry3.findPowerEntityForDevice(
|
|
172529
172529
|
entity.device_id
|
|
172530
172530
|
);
|
|
172531
172531
|
if (powerEntityId && powerEntityId !== entityId) {
|
|
@@ -172534,7 +172534,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172534
172534
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
172535
172535
|
powerEntity: powerEntityId
|
|
172536
172536
|
};
|
|
172537
|
-
|
|
172537
|
+
registry3.markPowerEntityUsed(powerEntityId);
|
|
172538
172538
|
logger243.debug(`Auto-assigned power ${powerEntityId} to ${entityId}`);
|
|
172539
172539
|
}
|
|
172540
172540
|
}
|
|
@@ -172542,7 +172542,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172542
172542
|
if (!mapping?.energyEntity) {
|
|
172543
172543
|
const domain = entityId.split(".")[0];
|
|
172544
172544
|
if (domain === "switch") {
|
|
172545
|
-
const energyEntityId =
|
|
172545
|
+
const energyEntityId = registry3.findEnergyEntityForDevice(
|
|
172546
172546
|
entity.device_id
|
|
172547
172547
|
);
|
|
172548
172548
|
if (energyEntityId && energyEntityId !== entityId) {
|
|
@@ -172551,7 +172551,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172551
172551
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
172552
172552
|
energyEntity: energyEntityId
|
|
172553
172553
|
};
|
|
172554
|
-
|
|
172554
|
+
registry3.markEnergyEntityUsed(energyEntityId);
|
|
172555
172555
|
logger243.debug(
|
|
172556
172556
|
`Auto-assigned energy ${energyEntityId} to ${entityId}`
|
|
172557
172557
|
);
|
|
@@ -172559,7 +172559,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172559
172559
|
}
|
|
172560
172560
|
}
|
|
172561
172561
|
if (entityId.startsWith("vacuum.")) {
|
|
172562
|
-
const vacuumEntities =
|
|
172562
|
+
const vacuumEntities = registry3.findVacuumSelectEntities(
|
|
172563
172563
|
entity.device_id
|
|
172564
172564
|
);
|
|
172565
172565
|
if (!effectiveMapping?.cleaningModeEntity && vacuumEntities.cleaningModeEntity) {
|
|
@@ -172603,7 +172603,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172603
172603
|
);
|
|
172604
172604
|
}
|
|
172605
172605
|
const supportedFeatures = state.attributes.supported_features ?? 0;
|
|
172606
|
-
const cleanAreaRooms = await
|
|
172606
|
+
const cleanAreaRooms = await registry3.resolveCleanAreaRooms(
|
|
172607
172607
|
entityId,
|
|
172608
172608
|
supportedFeatures
|
|
172609
172609
|
);
|
|
@@ -172619,7 +172619,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172619
172619
|
}
|
|
172620
172620
|
const vacAttrs = state.attributes;
|
|
172621
172621
|
if (cleanAreaRooms.length === 0 && !vacAttrs.rooms && !vacAttrs.segments && !vacAttrs.room_mapping) {
|
|
172622
|
-
const valetudoRooms =
|
|
172622
|
+
const valetudoRooms = registry3.findValetudoMapSegments(
|
|
172623
172623
|
entity.device_id
|
|
172624
172624
|
);
|
|
172625
172625
|
if (valetudoRooms.length > 0) {
|
|
@@ -172638,7 +172638,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172638
172638
|
`Auto-detected ${valetudoRooms.length} Valetudo segments for ${entityId}`
|
|
172639
172639
|
);
|
|
172640
172640
|
} else {
|
|
172641
|
-
const roborockRooms = await
|
|
172641
|
+
const roborockRooms = await registry3.resolveRoborockRooms(entityId);
|
|
172642
172642
|
if (roborockRooms.length > 0) {
|
|
172643
172643
|
const roomsObj = {};
|
|
172644
172644
|
for (const r of roborockRooms) {
|
|
@@ -172664,10 +172664,10 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172664
172664
|
`Composed mappings are not supported in server mode, exposing ${entityId} as a flat standalone endpoint`
|
|
172665
172665
|
);
|
|
172666
172666
|
}
|
|
172667
|
-
if (!standalone &&
|
|
172668
|
-
const composedAreaName =
|
|
172667
|
+
if (!standalone && registry3.isAutoComposedDevicesEnabled() && effectiveMapping?.composedEntities && effectiveMapping.composedEntities.length > 0) {
|
|
172668
|
+
const composedAreaName = registry3.getAreaName(entityId);
|
|
172669
172669
|
const composed = await UserComposedEndpoint.create({
|
|
172670
|
-
registry:
|
|
172670
|
+
registry: registry3,
|
|
172671
172671
|
primaryEntityId: entityId,
|
|
172672
172672
|
mapping: effectiveMapping,
|
|
172673
172673
|
composedEntities: effectiveMapping.composedEntities,
|
|
@@ -172683,12 +172683,12 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172683
172683
|
`User composed device creation failed for ${entityId}, falling back to standalone`
|
|
172684
172684
|
);
|
|
172685
172685
|
}
|
|
172686
|
-
if (!standalone &&
|
|
172686
|
+
if (!standalone && registry3.isAutoComposedDevicesEnabled()) {
|
|
172687
172687
|
const attrs = state.attributes;
|
|
172688
172688
|
if (entityId.startsWith("sensor.") && attrs.device_class === SensorDeviceClass.temperature && (effectiveMapping?.humidityEntity || effectiveMapping?.pressureEntity)) {
|
|
172689
|
-
const composedAreaName =
|
|
172689
|
+
const composedAreaName = registry3.getAreaName(entityId);
|
|
172690
172690
|
const composed = await ComposedSensorEndpoint.create({
|
|
172691
|
-
registry:
|
|
172691
|
+
registry: registry3,
|
|
172692
172692
|
primaryEntityId: entityId,
|
|
172693
172693
|
humidityEntityId: effectiveMapping?.humidityEntity,
|
|
172694
172694
|
pressureEntityId: effectiveMapping?.pressureEntity,
|
|
@@ -172704,12 +172704,12 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172704
172704
|
}
|
|
172705
172705
|
const resolvedMatterType = mapping?.matterDeviceType ?? (entityId.startsWith("fan.") ? "fan" : void 0);
|
|
172706
172706
|
if (resolvedMatterType === "air_purifier") {
|
|
172707
|
-
const temperatureEntityId = effectiveMapping?.temperatureEntity || (entity.device_id ?
|
|
172708
|
-
const humidityEntityId = effectiveMapping?.humidityEntity || (entity.device_id ?
|
|
172707
|
+
const temperatureEntityId = effectiveMapping?.temperatureEntity || (entity.device_id ? registry3.findTemperatureEntityForDevice(entity.device_id) : void 0);
|
|
172708
|
+
const humidityEntityId = effectiveMapping?.humidityEntity || (entity.device_id ? registry3.findHumidityEntityForDevice(entity.device_id) : void 0);
|
|
172709
172709
|
if (temperatureEntityId || humidityEntityId) {
|
|
172710
|
-
const composedAreaName =
|
|
172710
|
+
const composedAreaName = registry3.getAreaName(entityId);
|
|
172711
172711
|
const composed = await ComposedAirPurifierEndpoint.create({
|
|
172712
|
-
registry:
|
|
172712
|
+
registry: registry3,
|
|
172713
172713
|
primaryEntityId: entityId,
|
|
172714
172714
|
temperatureEntityId,
|
|
172715
172715
|
humidityEntityId,
|
|
@@ -172731,9 +172731,9 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172731
172731
|
if (!standalone && entityId.startsWith("climate.") && effectiveMapping?.climateExposeFan === true) {
|
|
172732
172732
|
const climateFeatures = state.attributes.supported_features ?? 0;
|
|
172733
172733
|
if ((climateFeatures & ClimateDeviceFeature.FAN_MODE) !== 0) {
|
|
172734
|
-
const composedAreaName =
|
|
172734
|
+
const composedAreaName = registry3.getAreaName(entityId);
|
|
172735
172735
|
const composed = await ComposedClimateFanEndpoint.create({
|
|
172736
|
-
registry:
|
|
172736
|
+
registry: registry3,
|
|
172737
172737
|
primaryEntityId: entityId,
|
|
172738
172738
|
mapping: effectiveMapping,
|
|
172739
172739
|
customName: effectiveMapping?.customName,
|
|
@@ -172758,7 +172758,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172758
172758
|
let cleaningModeOptions;
|
|
172759
172759
|
if (entityId.startsWith("vacuum.")) {
|
|
172760
172760
|
if (effectiveMapping?.cleaningModeEntity) {
|
|
172761
|
-
const cmState =
|
|
172761
|
+
const cmState = registry3.initialState(
|
|
172762
172762
|
effectiveMapping.cleaningModeEntity
|
|
172763
172763
|
);
|
|
172764
172764
|
cleaningModeOptions = cmState?.attributes?.options;
|
|
@@ -172772,13 +172772,13 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172772
172772
|
];
|
|
172773
172773
|
}
|
|
172774
172774
|
}
|
|
172775
|
-
const areaName =
|
|
172775
|
+
const areaName = registry3.getAreaName(entityId);
|
|
172776
172776
|
let type = createLegacyEndpointType(
|
|
172777
172777
|
payload,
|
|
172778
172778
|
effectiveMapping,
|
|
172779
172779
|
areaName,
|
|
172780
172780
|
{
|
|
172781
|
-
vacuumOnOff:
|
|
172781
|
+
vacuumOnOff: registry3.isVacuumOnOffEnabled(),
|
|
172782
172782
|
cleaningModeOptions,
|
|
172783
172783
|
pluginDomainMappings
|
|
172784
172784
|
},
|
|
@@ -172957,18 +172957,186 @@ var CameraAvStreamServer = class extends Base4 {
|
|
|
172957
172957
|
})(CameraAvStreamServer || (CameraAvStreamServer = {}));
|
|
172958
172958
|
|
|
172959
172959
|
// src/plugins/builtin/camera/webrtc-provider-server.ts
|
|
172960
|
+
init_esm();
|
|
172960
172961
|
init_esm7();
|
|
172961
172962
|
init_esm3();
|
|
172963
|
+
|
|
172964
|
+
// src/plugins/builtin/camera/requestor-client.ts
|
|
172965
|
+
init_esm();
|
|
172966
|
+
init_esm4();
|
|
172967
|
+
var logger244 = Logger.get("CameraWebRtcRequestor");
|
|
172968
|
+
var registry2 = /* @__PURE__ */ new Map();
|
|
172969
|
+
var pendingDeliveries = /* @__PURE__ */ new Map();
|
|
172970
|
+
var invokeTransport = defaultInvoke;
|
|
172971
|
+
function registerRequestor(sessionId, registration) {
|
|
172972
|
+
registry2.set(sessionId, registration);
|
|
172973
|
+
}
|
|
172974
|
+
function unregisterRequestor(sessionId) {
|
|
172975
|
+
registry2.delete(sessionId);
|
|
172976
|
+
const timer = pendingDeliveries.get(sessionId);
|
|
172977
|
+
if (timer) {
|
|
172978
|
+
clearTimeout(timer);
|
|
172979
|
+
pendingDeliveries.delete(sessionId);
|
|
172980
|
+
}
|
|
172981
|
+
}
|
|
172982
|
+
function unregisterAllRequestors() {
|
|
172983
|
+
for (const id of [...registry2.keys()]) unregisterRequestor(id);
|
|
172984
|
+
for (const timer of pendingDeliveries.values()) clearTimeout(timer);
|
|
172985
|
+
pendingDeliveries.clear();
|
|
172986
|
+
}
|
|
172987
|
+
function deliverAnswerDeferred(sessionId, sdp, onGiveUp) {
|
|
172988
|
+
const prior = pendingDeliveries.get(sessionId);
|
|
172989
|
+
if (prior) clearTimeout(prior);
|
|
172990
|
+
const owner = registry2.get(sessionId);
|
|
172991
|
+
const timer = setTimeout(() => {
|
|
172992
|
+
void (async () => {
|
|
172993
|
+
try {
|
|
172994
|
+
for (const delayMs of [0, 250, 500]) {
|
|
172995
|
+
if (delayMs > 0) await new Promise((r) => setTimeout(r, delayMs));
|
|
172996
|
+
if (registry2.get(sessionId) !== owner || pendingDeliveries.get(sessionId) !== timer) {
|
|
172997
|
+
return;
|
|
172998
|
+
}
|
|
172999
|
+
if (await sendAnswer(sessionId, sdp)) {
|
|
173000
|
+
logger244.info(`answer delivered for session ${sessionId}`);
|
|
173001
|
+
return;
|
|
173002
|
+
}
|
|
173003
|
+
}
|
|
173004
|
+
if (registry2.get(sessionId) !== owner || pendingDeliveries.get(sessionId) !== timer) {
|
|
173005
|
+
return;
|
|
173006
|
+
}
|
|
173007
|
+
logger244.info(
|
|
173008
|
+
`answer delivery failed for session ${sessionId}, giving up`
|
|
173009
|
+
);
|
|
173010
|
+
await onGiveUp();
|
|
173011
|
+
} catch (err) {
|
|
173012
|
+
logger244.info(
|
|
173013
|
+
`answer delivery for session ${sessionId} threw: ${errText(err)}`
|
|
173014
|
+
);
|
|
173015
|
+
} finally {
|
|
173016
|
+
if (pendingDeliveries.get(sessionId) === timer) {
|
|
173017
|
+
pendingDeliveries.delete(sessionId);
|
|
173018
|
+
}
|
|
173019
|
+
}
|
|
173020
|
+
})();
|
|
173021
|
+
}, 0);
|
|
173022
|
+
timer.unref?.();
|
|
173023
|
+
pendingDeliveries.set(sessionId, timer);
|
|
173024
|
+
}
|
|
173025
|
+
function hasRequestor(sessionId) {
|
|
173026
|
+
return registry2.has(sessionId);
|
|
173027
|
+
}
|
|
173028
|
+
function sendAnswer(sessionId, sdp) {
|
|
173029
|
+
return invokeRequestor(sessionId, "answer", {
|
|
173030
|
+
webRtcSessionId: sessionId,
|
|
173031
|
+
sdp
|
|
173032
|
+
});
|
|
173033
|
+
}
|
|
173034
|
+
async function invokeRequestor(sessionId, command, fields) {
|
|
173035
|
+
const registration = registry2.get(sessionId);
|
|
173036
|
+
if (!registration) {
|
|
173037
|
+
logger244.info(`requestor ${command}: no session ${sessionId} registered`);
|
|
173038
|
+
return false;
|
|
173039
|
+
}
|
|
173040
|
+
if (registration.session.isClosed) {
|
|
173041
|
+
logger244.info(`requestor ${command}: session ${sessionId} already closed`);
|
|
173042
|
+
return false;
|
|
173043
|
+
}
|
|
173044
|
+
const request = {
|
|
173045
|
+
endpoint: registration.requestorEndpoint,
|
|
173046
|
+
cluster: WebRtcTransportRequestor3.Cluster,
|
|
173047
|
+
command,
|
|
173048
|
+
fields
|
|
173049
|
+
};
|
|
173050
|
+
try {
|
|
173051
|
+
return await invokeTransport({ registration, request });
|
|
173052
|
+
} catch (err) {
|
|
173053
|
+
logger244.info(
|
|
173054
|
+
`requestor ${command} failed for session ${sessionId}: ${errText(err)}`
|
|
173055
|
+
);
|
|
173056
|
+
return false;
|
|
173057
|
+
}
|
|
173058
|
+
}
|
|
173059
|
+
async function defaultInvoke({
|
|
173060
|
+
registration,
|
|
173061
|
+
request
|
|
173062
|
+
}) {
|
|
173063
|
+
const { session, env } = registration;
|
|
173064
|
+
const exchangeManager = env.get(ExchangeManager);
|
|
173065
|
+
const exchangeProvider = new DedicatedChannelExchangeProvider(
|
|
173066
|
+
exchangeManager,
|
|
173067
|
+
session
|
|
173068
|
+
);
|
|
173069
|
+
const client = new ClientInteraction({ environment: env, exchangeProvider });
|
|
173070
|
+
try {
|
|
173071
|
+
const result = client.invoke(
|
|
173072
|
+
Invoke({
|
|
173073
|
+
commands: [
|
|
173074
|
+
{
|
|
173075
|
+
endpoint: request.endpoint,
|
|
173076
|
+
cluster: request.cluster,
|
|
173077
|
+
command: request.command,
|
|
173078
|
+
// biome-ignore lint/suspicious/noExplicitAny: fields typed per command by caller
|
|
173079
|
+
fields: request.fields
|
|
173080
|
+
}
|
|
173081
|
+
]
|
|
173082
|
+
})
|
|
173083
|
+
);
|
|
173084
|
+
for await (const chunk of result) {
|
|
173085
|
+
for (const entry of chunk) {
|
|
173086
|
+
if (entry.kind === "cmd-status") {
|
|
173087
|
+
if (entry.status !== Status2.Success) {
|
|
173088
|
+
logger244.info(
|
|
173089
|
+
`requestor ${request.command} status ${entry.status} for session ${String(request.fields.webRtcSessionId)}`
|
|
173090
|
+
);
|
|
173091
|
+
return false;
|
|
173092
|
+
}
|
|
173093
|
+
return true;
|
|
173094
|
+
}
|
|
173095
|
+
}
|
|
173096
|
+
}
|
|
173097
|
+
return true;
|
|
173098
|
+
} finally {
|
|
173099
|
+
await client.close().catch(() => {
|
|
173100
|
+
});
|
|
173101
|
+
}
|
|
173102
|
+
}
|
|
173103
|
+
function errText(err) {
|
|
173104
|
+
return err instanceof Error ? err.message : String(err);
|
|
173105
|
+
}
|
|
173106
|
+
|
|
173107
|
+
// src/plugins/builtin/camera/webrtc-provider-server.ts
|
|
173108
|
+
var logger245 = Logger.get("CameraWebRtc");
|
|
173109
|
+
var nextGlobalSessionId = 0;
|
|
173110
|
+
function mintSessionId() {
|
|
173111
|
+
for (let i = 0; i <= 65534; i++) {
|
|
173112
|
+
const id = nextGlobalSessionId;
|
|
173113
|
+
nextGlobalSessionId = nextGlobalSessionId >= 65534 ? 0 : nextGlobalSessionId + 1;
|
|
173114
|
+
if (!hasRequestor(id)) return id;
|
|
173115
|
+
}
|
|
173116
|
+
return nextGlobalSessionId;
|
|
173117
|
+
}
|
|
172962
173118
|
var CameraWebRtcProviderServer = class extends WebRtcTransportProviderServer {
|
|
172963
173119
|
solicitOffer(request) {
|
|
172964
|
-
const id =
|
|
173120
|
+
const id = mintSessionId();
|
|
172965
173121
|
this.trackSession(id, request.streamUsage, request.originatingEndpointId);
|
|
172966
|
-
|
|
172967
|
-
|
|
173122
|
+
logger245.info(
|
|
173123
|
+
`solicitOffer session=${id} (${this.state.entityId}), deferred offer`
|
|
173124
|
+
);
|
|
173125
|
+
void this.state.bridge.startSession(id, this.state.entityId, {
|
|
173126
|
+
iceServers: request.iceServers,
|
|
173127
|
+
iceTransportPolicy: request.iceTransportPolicy
|
|
173128
|
+
}).catch(
|
|
173129
|
+
(err) => logger245.info(
|
|
173130
|
+
`solicitOffer startSession failed for ${this.state.entityId}: ${errText2(err)}`
|
|
173131
|
+
)
|
|
173132
|
+
);
|
|
172968
173133
|
return { webRtcSessionId: id, deferredOffer: true };
|
|
172969
173134
|
}
|
|
172970
173135
|
async provideOffer(request) {
|
|
172971
|
-
const id = request.webRtcSessionId ??
|
|
173136
|
+
const id = request.webRtcSessionId ?? mintSessionId();
|
|
173137
|
+
logger245.info(
|
|
173138
|
+
`provideOffer entry: entityId=${this.state.entityId} session=${id} (sdp ${request.sdp.length} chars)`
|
|
173139
|
+
);
|
|
172972
173140
|
if (request.webRtcSessionId == null) {
|
|
172973
173141
|
this.trackSession(
|
|
172974
173142
|
id,
|
|
@@ -172976,37 +173144,96 @@ var CameraWebRtcProviderServer = class extends WebRtcTransportProviderServer {
|
|
|
172976
173144
|
request.originatingEndpointId ?? EndpointNumber(0)
|
|
172977
173145
|
);
|
|
172978
173146
|
}
|
|
172979
|
-
const
|
|
172980
|
-
|
|
172981
|
-
|
|
172982
|
-
|
|
173147
|
+
const requestorEndpoint = request.originatingEndpointId ?? EndpointNumber(0);
|
|
173148
|
+
const session = this.context.session;
|
|
173149
|
+
if (session) {
|
|
173150
|
+
registerRequestor(id, {
|
|
173151
|
+
session,
|
|
173152
|
+
requestorEndpoint,
|
|
173153
|
+
env: this.env
|
|
173154
|
+
});
|
|
173155
|
+
}
|
|
173156
|
+
let answerSdp;
|
|
173157
|
+
try {
|
|
173158
|
+
answerSdp = await this.state.bridge.acceptControllerOffer(
|
|
173159
|
+
id,
|
|
173160
|
+
this.state.entityId,
|
|
173161
|
+
request.sdp,
|
|
173162
|
+
{
|
|
173163
|
+
iceServers: request.iceServers,
|
|
173164
|
+
iceTransportPolicy: request.iceTransportPolicy
|
|
173165
|
+
}
|
|
173166
|
+
);
|
|
173167
|
+
} catch (err) {
|
|
173168
|
+
const message = errText2(err);
|
|
173169
|
+
logger245.info(
|
|
173170
|
+
`provideOffer failed for ${this.state.entityId} session=${id}: ${message}`
|
|
173171
|
+
);
|
|
173172
|
+
unregisterRequestor(id);
|
|
173173
|
+
this.state.currentSessions = this.state.currentSessions.filter(
|
|
173174
|
+
(s) => s.id !== id
|
|
173175
|
+
);
|
|
173176
|
+
throw new StatusResponseError(
|
|
173177
|
+
`WebRTC offer failed: ${message}`,
|
|
173178
|
+
StatusCode.Failure
|
|
173179
|
+
);
|
|
173180
|
+
}
|
|
173181
|
+
logger245.info(
|
|
173182
|
+
`provideOffer answer computed for ${this.state.entityId} session=${id} (${answerSdp.length} chars); delivering via requestor`
|
|
172983
173183
|
);
|
|
172984
|
-
|
|
173184
|
+
const bridge = this.state.bridge;
|
|
173185
|
+
const state = this.state;
|
|
173186
|
+
deliverAnswerDeferred(id, answerSdp, async () => {
|
|
173187
|
+
await bridge.endSession(id).catch(() => {
|
|
173188
|
+
});
|
|
173189
|
+
unregisterRequestor(id);
|
|
173190
|
+
try {
|
|
173191
|
+
state.currentSessions = state.currentSessions.filter(
|
|
173192
|
+
(s) => s.id !== id
|
|
173193
|
+
);
|
|
173194
|
+
} catch {
|
|
173195
|
+
}
|
|
173196
|
+
});
|
|
172985
173197
|
return { webRtcSessionId: id };
|
|
172986
173198
|
}
|
|
172987
173199
|
provideAnswer(request) {
|
|
173200
|
+
logger245.info(
|
|
173201
|
+
`provideAnswer session=${request.webRtcSessionId} (sdp ${request.sdp.length} chars, ${this.state.entityId})`
|
|
173202
|
+
);
|
|
172988
173203
|
return this.state.bridge.acceptControllerAnswer(
|
|
172989
173204
|
request.webRtcSessionId,
|
|
172990
173205
|
request.sdp
|
|
172991
173206
|
);
|
|
172992
173207
|
}
|
|
172993
173208
|
async provideIceCandidates(request) {
|
|
173209
|
+
logger245.info(
|
|
173210
|
+
`provideIceCandidates session=${request.webRtcSessionId}: ${request.iceCandidates.length} candidate(s) (${this.state.entityId})`
|
|
173211
|
+
);
|
|
172994
173212
|
for (const c of request.iceCandidates) {
|
|
172995
173213
|
await this.state.bridge.addControllerIceCandidate(
|
|
172996
173214
|
request.webRtcSessionId,
|
|
172997
173215
|
c.candidate,
|
|
172998
|
-
c.sdpMid
|
|
173216
|
+
c.sdpMid,
|
|
173217
|
+
c.sdpmLineIndex
|
|
172999
173218
|
);
|
|
173000
173219
|
}
|
|
173001
173220
|
}
|
|
173002
173221
|
async endSession(request) {
|
|
173222
|
+
logger245.info(
|
|
173223
|
+
`endSession session=${request.webRtcSessionId} (${this.state.entityId})`
|
|
173224
|
+
);
|
|
173003
173225
|
await this.state.bridge.endSession(request.webRtcSessionId);
|
|
173226
|
+
unregisterRequestor(request.webRtcSessionId);
|
|
173004
173227
|
this.state.currentSessions = this.state.currentSessions.filter(
|
|
173005
173228
|
(s) => s.id !== request.webRtcSessionId
|
|
173006
173229
|
);
|
|
173007
173230
|
}
|
|
173008
173231
|
trackSession(id, streamUsage, peerEndpointId) {
|
|
173009
173232
|
const session = this.context.session;
|
|
173233
|
+
const fabricIndex = session?.associatedFabric?.fabricIndex;
|
|
173234
|
+
if (fabricIndex == null) {
|
|
173235
|
+
return;
|
|
173236
|
+
}
|
|
173010
173237
|
this.state.currentSessions = [
|
|
173011
173238
|
...this.state.currentSessions,
|
|
173012
173239
|
{
|
|
@@ -173015,16 +173242,18 @@ var CameraWebRtcProviderServer = class extends WebRtcTransportProviderServer {
|
|
|
173015
173242
|
peerEndpointId,
|
|
173016
173243
|
streamUsage,
|
|
173017
173244
|
metadataEnabled: false,
|
|
173018
|
-
fabricIndex
|
|
173245
|
+
fabricIndex
|
|
173019
173246
|
}
|
|
173020
173247
|
];
|
|
173021
173248
|
}
|
|
173022
173249
|
};
|
|
173250
|
+
function errText2(err) {
|
|
173251
|
+
return err instanceof Error ? err.message : String(err);
|
|
173252
|
+
}
|
|
173023
173253
|
((CameraWebRtcProviderServer2) => {
|
|
173024
173254
|
class State extends WebRtcTransportProviderServer.State {
|
|
173025
173255
|
bridge;
|
|
173026
173256
|
entityId;
|
|
173027
|
-
nextSessionId = 1;
|
|
173028
173257
|
}
|
|
173029
173258
|
CameraWebRtcProviderServer2.State = State;
|
|
173030
173259
|
})(CameraWebRtcProviderServer || (CameraWebRtcProviderServer = {}));
|
|
@@ -173043,8 +173272,7 @@ function createCameraEndpointType(bridge, entityId, sensor = defaultSensorParams
|
|
|
173043
173272
|
webRtcTransportProvider: {
|
|
173044
173273
|
bridge,
|
|
173045
173274
|
entityId,
|
|
173046
|
-
currentSessions: []
|
|
173047
|
-
nextSessionId: 1
|
|
173275
|
+
currentSessions: []
|
|
173048
173276
|
},
|
|
173049
173277
|
cameraAvStreamManagement: {
|
|
173050
173278
|
bridge,
|
|
@@ -173106,128 +173334,232 @@ function createCameraEndpointType(bridge, entityId, sensor = defaultSensorParams
|
|
|
173106
173334
|
}
|
|
173107
173335
|
|
|
173108
173336
|
// src/plugins/builtin/camera/webrtc-bridge.ts
|
|
173337
|
+
init_esm();
|
|
173109
173338
|
import {
|
|
173110
173339
|
createConnection as createConnection3,
|
|
173111
173340
|
createLongLivedTokenAuth as createLongLivedTokenAuth2
|
|
173112
173341
|
} from "home-assistant-js-websocket";
|
|
173113
173342
|
import { RTCPeerConnection } from "werift";
|
|
173343
|
+
var logger246 = Logger.get("CameraWebRtc");
|
|
173344
|
+
var DEFAULT_HA_WEBRTC_TIMEOUT_MS = 15e3;
|
|
173345
|
+
var haWebRtcTimeoutMs = DEFAULT_HA_WEBRTC_TIMEOUT_MS;
|
|
173114
173346
|
var WebRtcBridge = class {
|
|
173115
|
-
constructor(config11) {
|
|
173347
|
+
constructor(config11, deps = {}) {
|
|
173116
173348
|
this.config = config11;
|
|
173349
|
+
this.deps = deps;
|
|
173117
173350
|
}
|
|
173118
173351
|
config;
|
|
173352
|
+
deps;
|
|
173119
173353
|
connection;
|
|
173120
173354
|
sessions = /* @__PURE__ */ new Map();
|
|
173121
173355
|
async ha() {
|
|
173122
173356
|
if (this.connection) return this.connection;
|
|
173123
|
-
|
|
173124
|
-
this.config
|
|
173125
|
-
|
|
173126
|
-
|
|
173127
|
-
|
|
173357
|
+
if (this.deps.connect) {
|
|
173358
|
+
this.connection = await this.deps.connect(this.config);
|
|
173359
|
+
} else {
|
|
173360
|
+
const auth = createLongLivedTokenAuth2(
|
|
173361
|
+
this.config.haUrl,
|
|
173362
|
+
this.config.haToken
|
|
173363
|
+
);
|
|
173364
|
+
this.connection = await createConnection3({ auth });
|
|
173365
|
+
}
|
|
173128
173366
|
return this.connection;
|
|
173129
173367
|
}
|
|
173130
173368
|
// We offer to the controller; it answers. Pulls HA media first, then forwards.
|
|
173131
|
-
async startSession(matterSessionId, entityId) {
|
|
173369
|
+
async startSession(matterSessionId, entityId, ice) {
|
|
173132
173370
|
const haPeer = new RTCPeerConnection();
|
|
173133
|
-
const controllerPeer = new RTCPeerConnection(
|
|
173134
|
-
|
|
173135
|
-
|
|
173136
|
-
|
|
173137
|
-
|
|
173371
|
+
const controllerPeer = new RTCPeerConnection(
|
|
173372
|
+
this.controllerConfig(entityId, ice)
|
|
173373
|
+
);
|
|
173374
|
+
this.wireStateLogging(haPeer, "haPeer", entityId);
|
|
173375
|
+
this.wireStateLogging(controllerPeer, "controllerPeer", entityId);
|
|
173376
|
+
const senders = /* @__PURE__ */ new Map();
|
|
173377
|
+
senders.set(
|
|
173378
|
+
"video",
|
|
173379
|
+
controllerPeer.addTransceiver("video", { direction: "sendonly" })
|
|
173380
|
+
);
|
|
173381
|
+
this.forwardHaTracks(haPeer, senders, entityId);
|
|
173382
|
+
await this.closeExistingPeers(matterSessionId);
|
|
173383
|
+
this.sessions.set(matterSessionId, { entityId, haPeer, controllerPeer });
|
|
173384
|
+
try {
|
|
173385
|
+
haPeer.addTransceiver("video", { direction: "recvonly" });
|
|
173386
|
+
haPeer.addTransceiver("audio", { direction: "recvonly" });
|
|
173387
|
+
const haOffer = await haPeer.createOffer();
|
|
173388
|
+
await haPeer.setLocalDescription(haOffer);
|
|
173389
|
+
const haOfferSdp = this.localSdp(haPeer);
|
|
173390
|
+
logger246.info(`HA offer sent for ${entityId} (${haOfferSdp.length} chars)`);
|
|
173391
|
+
const { answer, sessionId, unsubscribe } = await this.requestHaWebRtc(
|
|
173392
|
+
entityId,
|
|
173393
|
+
haOfferSdp,
|
|
173394
|
+
haPeer
|
|
173138
173395
|
);
|
|
173139
|
-
|
|
173140
|
-
|
|
173141
|
-
|
|
173142
|
-
|
|
173143
|
-
|
|
173144
|
-
|
|
173145
|
-
|
|
173146
|
-
|
|
173147
|
-
|
|
173148
|
-
|
|
173149
|
-
|
|
173150
|
-
|
|
173151
|
-
|
|
173152
|
-
|
|
173153
|
-
|
|
173154
|
-
|
|
173155
|
-
|
|
173156
|
-
|
|
173157
|
-
|
|
173158
|
-
|
|
173159
|
-
|
|
173160
|
-
|
|
173161
|
-
|
|
173162
|
-
|
|
173396
|
+
const session = this.sessions.get(matterSessionId);
|
|
173397
|
+
if (session) {
|
|
173398
|
+
session.haSessionId = sessionId;
|
|
173399
|
+
session.haUnsubscribe = unsubscribe;
|
|
173400
|
+
}
|
|
173401
|
+
await haPeer.setRemoteDescription({ type: "answer", sdp: answer });
|
|
173402
|
+
const iceCandidates = [];
|
|
173403
|
+
controllerPeer.onIceCandidate.subscribe((c) => {
|
|
173404
|
+
if (c?.candidate)
|
|
173405
|
+
iceCandidates.push({
|
|
173406
|
+
candidate: c.candidate,
|
|
173407
|
+
sdpMid: c.sdpMid ?? null
|
|
173408
|
+
});
|
|
173409
|
+
});
|
|
173410
|
+
const controllerOffer = await controllerPeer.createOffer();
|
|
173411
|
+
await controllerPeer.setLocalDescription(controllerOffer);
|
|
173412
|
+
const sdp = this.localSdp(controllerPeer);
|
|
173413
|
+
logger246.info(
|
|
173414
|
+
`controller offer created for ${entityId} (${sdp.length} chars)`
|
|
173415
|
+
);
|
|
173416
|
+
return { sdp, iceCandidates };
|
|
173417
|
+
} catch (err) {
|
|
173418
|
+
logger246.info(`startSession failed for ${entityId}: ${errText3(err)}`);
|
|
173419
|
+
await this.endSession(matterSessionId);
|
|
173420
|
+
throw err;
|
|
173421
|
+
}
|
|
173163
173422
|
}
|
|
173164
173423
|
// ProvideOffer flow: controller sent its offer. Pull HA media, answer it.
|
|
173165
173424
|
// Returning the answer to the controller is the unverified Requestor path.
|
|
173166
|
-
async acceptControllerOffer(matterSessionId, entityId, controllerOfferSdp) {
|
|
173425
|
+
async acceptControllerOffer(matterSessionId, entityId, controllerOfferSdp, ice) {
|
|
173167
173426
|
const haPeer = new RTCPeerConnection();
|
|
173168
|
-
const controllerPeer = new RTCPeerConnection(
|
|
173169
|
-
|
|
173170
|
-
|
|
173171
|
-
|
|
173172
|
-
|
|
173173
|
-
|
|
173174
|
-
|
|
173427
|
+
const controllerPeer = new RTCPeerConnection(
|
|
173428
|
+
this.controllerConfig(entityId, ice)
|
|
173429
|
+
);
|
|
173430
|
+
this.wireStateLogging(haPeer, "haPeer", entityId);
|
|
173431
|
+
this.wireStateLogging(controllerPeer, "controllerPeer", entityId);
|
|
173432
|
+
const senders = /* @__PURE__ */ new Map();
|
|
173433
|
+
for (const kind of offerKinds(controllerOfferSdp)) {
|
|
173434
|
+
senders.set(
|
|
173435
|
+
kind,
|
|
173436
|
+
controllerPeer.addTransceiver(kind, { direction: "sendonly" })
|
|
173437
|
+
);
|
|
173438
|
+
}
|
|
173439
|
+
this.forwardHaTracks(haPeer, senders, entityId);
|
|
173440
|
+
await this.closeExistingPeers(matterSessionId);
|
|
173175
173441
|
this.sessions.set(matterSessionId, { entityId, haPeer, controllerPeer });
|
|
173176
|
-
|
|
173177
|
-
|
|
173178
|
-
|
|
173179
|
-
|
|
173180
|
-
|
|
173181
|
-
|
|
173182
|
-
|
|
173183
|
-
|
|
173184
|
-
|
|
173185
|
-
|
|
173186
|
-
|
|
173187
|
-
|
|
173188
|
-
|
|
173442
|
+
try {
|
|
173443
|
+
haPeer.addTransceiver("video", { direction: "recvonly" });
|
|
173444
|
+
haPeer.addTransceiver("audio", { direction: "recvonly" });
|
|
173445
|
+
const haOffer = await haPeer.createOffer();
|
|
173446
|
+
await haPeer.setLocalDescription(haOffer);
|
|
173447
|
+
const haOfferSdp = this.localSdp(haPeer);
|
|
173448
|
+
logger246.info(`HA offer sent for ${entityId} (${haOfferSdp.length} chars)`);
|
|
173449
|
+
const { answer, sessionId, unsubscribe } = await this.requestHaWebRtc(
|
|
173450
|
+
entityId,
|
|
173451
|
+
haOfferSdp,
|
|
173452
|
+
haPeer
|
|
173453
|
+
);
|
|
173454
|
+
const session = this.sessions.get(matterSessionId);
|
|
173455
|
+
if (session) {
|
|
173456
|
+
session.haSessionId = sessionId;
|
|
173457
|
+
session.haUnsubscribe = unsubscribe;
|
|
173458
|
+
}
|
|
173459
|
+
await haPeer.setRemoteDescription({ type: "answer", sdp: answer });
|
|
173460
|
+
await controllerPeer.setRemoteDescription({
|
|
173461
|
+
type: "offer",
|
|
173462
|
+
sdp: controllerOfferSdp
|
|
173463
|
+
});
|
|
173464
|
+
const controllerAnswer = await controllerPeer.createAnswer();
|
|
173465
|
+
await controllerPeer.setLocalDescription(controllerAnswer);
|
|
173466
|
+
const answerSdp = this.localSdp(controllerPeer);
|
|
173467
|
+
logger246.info(
|
|
173468
|
+
`controller answer created for ${entityId} (${answerSdp.length} chars)`
|
|
173469
|
+
);
|
|
173470
|
+
return answerSdp;
|
|
173471
|
+
} catch (err) {
|
|
173472
|
+
logger246.info(
|
|
173473
|
+
`acceptControllerOffer failed for ${entityId}: ${errText3(err)}`
|
|
173474
|
+
);
|
|
173475
|
+
await this.endSession(matterSessionId);
|
|
173476
|
+
throw err;
|
|
173477
|
+
}
|
|
173189
173478
|
}
|
|
173190
173479
|
/** Apply the Matter controller's SDP answer to the controller peer. */
|
|
173191
173480
|
async acceptControllerAnswer(matterSessionId, sdp) {
|
|
173192
173481
|
const session = this.sessions.get(matterSessionId);
|
|
173193
173482
|
if (!session) return;
|
|
173483
|
+
logger246.debug(`controller answer applied for ${session.entityId}`);
|
|
173194
173484
|
await session.controllerPeer.setRemoteDescription({ type: "answer", sdp });
|
|
173195
173485
|
}
|
|
173196
173486
|
/** Add a remote ICE candidate from the Matter controller. */
|
|
173197
|
-
async addControllerIceCandidate(matterSessionId, candidate, sdpMid) {
|
|
173487
|
+
async addControllerIceCandidate(matterSessionId, candidate, sdpMid, sdpMLineIndex) {
|
|
173198
173488
|
const session = this.sessions.get(matterSessionId);
|
|
173199
173489
|
if (!session) return;
|
|
173490
|
+
logger246.debug(
|
|
173491
|
+
`controller ICE candidate for ${session.entityId}: ${candidate}`
|
|
173492
|
+
);
|
|
173200
173493
|
await session.controllerPeer.addIceCandidate({
|
|
173201
173494
|
candidate,
|
|
173202
|
-
sdpMid: sdpMid ?? void 0
|
|
173495
|
+
sdpMid: sdpMid ?? void 0,
|
|
173496
|
+
sdpMLineIndex: sdpMLineIndex ?? void 0
|
|
173497
|
+
});
|
|
173498
|
+
}
|
|
173499
|
+
// Close the peers of a session we are about to overwrite. Leaves no map
|
|
173500
|
+
// entry; the caller replaces it with fresh peers under the same id.
|
|
173501
|
+
async closeExistingPeers(matterSessionId) {
|
|
173502
|
+
const prior = this.sessions.get(matterSessionId);
|
|
173503
|
+
if (!prior) return;
|
|
173504
|
+
logger246.info(
|
|
173505
|
+
`replacing session ${matterSessionId} (${prior.entityId}), closing prior peers`
|
|
173506
|
+
);
|
|
173507
|
+
if (prior.haUnsubscribe) {
|
|
173508
|
+
await Promise.resolve(prior.haUnsubscribe()).catch(
|
|
173509
|
+
(err) => logger246.debug(`HA unsubscribe failed: ${errText3(err)}`)
|
|
173510
|
+
);
|
|
173511
|
+
}
|
|
173512
|
+
await prior.haPeer.close().catch(() => {
|
|
173513
|
+
});
|
|
173514
|
+
await prior.controllerPeer.close().catch(() => {
|
|
173515
|
+
});
|
|
173516
|
+
await this.stopHaStream(prior).catch(() => {
|
|
173203
173517
|
});
|
|
173204
173518
|
}
|
|
173205
173519
|
async endSession(matterSessionId) {
|
|
173206
173520
|
const session = this.sessions.get(matterSessionId);
|
|
173207
173521
|
if (!session) return;
|
|
173522
|
+
logger246.info(`ending session ${matterSessionId} (${session.entityId})`);
|
|
173208
173523
|
this.sessions.delete(matterSessionId);
|
|
173209
|
-
|
|
173210
|
-
|
|
173211
|
-
|
|
173212
|
-
|
|
173213
|
-
const conn = await this.ha();
|
|
173214
|
-
await conn.sendMessagePromise({
|
|
173215
|
-
type: "camera/webrtc/candidate",
|
|
173216
|
-
entity_id: session.entityId,
|
|
173217
|
-
session_id: session.haSessionId,
|
|
173218
|
-
candidate: { candidate: "" }
|
|
173219
|
-
});
|
|
173220
|
-
} catch {
|
|
173221
|
-
}
|
|
173524
|
+
if (session.haUnsubscribe) {
|
|
173525
|
+
await Promise.resolve(session.haUnsubscribe()).catch(
|
|
173526
|
+
(err) => logger246.debug(`HA unsubscribe failed: ${errText3(err)}`)
|
|
173527
|
+
);
|
|
173222
173528
|
}
|
|
173529
|
+
await session.haPeer.close().catch(() => {
|
|
173530
|
+
});
|
|
173531
|
+
await session.controllerPeer.close().catch(() => {
|
|
173532
|
+
});
|
|
173533
|
+
await this.stopHaStream(session).catch(() => {
|
|
173534
|
+
});
|
|
173535
|
+
}
|
|
173536
|
+
// Tell HA to stop the stream if we tracked an HA session id. Best effort.
|
|
173537
|
+
async stopHaStream(session) {
|
|
173538
|
+
if (!session.haSessionId) return;
|
|
173539
|
+
const conn = await this.ha();
|
|
173540
|
+
await conn.sendMessagePromise({
|
|
173541
|
+
type: "camera/webrtc/candidate",
|
|
173542
|
+
entity_id: session.entityId,
|
|
173543
|
+
session_id: session.haSessionId,
|
|
173544
|
+
candidate: { candidate: "" }
|
|
173545
|
+
});
|
|
173223
173546
|
}
|
|
173224
173547
|
// Grab a still JPEG via HA's camera proxy (for CaptureSnapshot).
|
|
173225
173548
|
async snapshot(entityId) {
|
|
173226
173549
|
const url2 = `${this.config.haUrl}/api/camera_proxy/${entityId}`;
|
|
173227
|
-
|
|
173228
|
-
|
|
173229
|
-
|
|
173550
|
+
let res;
|
|
173551
|
+
try {
|
|
173552
|
+
res = await fetch(url2, {
|
|
173553
|
+
headers: { Authorization: `Bearer ${this.config.haToken}` }
|
|
173554
|
+
});
|
|
173555
|
+
} catch (err) {
|
|
173556
|
+
logger246.info(`snapshot fetch failed for ${entityId}: ${errText3(err)}`);
|
|
173557
|
+
throw err;
|
|
173558
|
+
}
|
|
173230
173559
|
if (!res.ok) {
|
|
173560
|
+
logger246.info(
|
|
173561
|
+
`snapshot fetch failed for ${entityId}: camera_proxy ${res.status}`
|
|
173562
|
+
);
|
|
173231
173563
|
throw new Error(`HA camera_proxy ${entityId}: ${res.status}`);
|
|
173232
173564
|
}
|
|
173233
173565
|
return new Uint8Array(await res.arrayBuffer());
|
|
@@ -173239,29 +173571,157 @@ var WebRtcBridge = class {
|
|
|
173239
173571
|
this.connection?.close();
|
|
173240
173572
|
this.connection = void 0;
|
|
173241
173573
|
}
|
|
173242
|
-
//
|
|
173243
|
-
|
|
173574
|
+
// Forward every track HA sends into the matching pre-added controller sender.
|
|
173575
|
+
forwardHaTracks(haPeer, senders, entityId) {
|
|
173576
|
+
haPeer.onTrack.subscribe((track) => {
|
|
173577
|
+
logger246.info(`onTrack ${track.kind} from HA (${entityId})`);
|
|
173578
|
+
const transceiver = senders.get(track.kind);
|
|
173579
|
+
if (!transceiver) {
|
|
173580
|
+
logger246.info(
|
|
173581
|
+
`no controller transceiver for ${track.kind} (${entityId})`
|
|
173582
|
+
);
|
|
173583
|
+
return;
|
|
173584
|
+
}
|
|
173585
|
+
let firstLogged = false;
|
|
173586
|
+
track.onReceiveRtp.subscribe((rtp) => {
|
|
173587
|
+
if (!firstLogged) {
|
|
173588
|
+
firstLogged = true;
|
|
173589
|
+
logger246.info(`first RTP forwarded for ${track.kind} (${entityId})`);
|
|
173590
|
+
}
|
|
173591
|
+
transceiver.sender.sendRtp(rtp);
|
|
173592
|
+
});
|
|
173593
|
+
});
|
|
173594
|
+
}
|
|
173595
|
+
// Log connection/ice state transitions (these events fire on change only).
|
|
173596
|
+
wireStateLogging(peer, label, entityId) {
|
|
173597
|
+
peer.connectionStateChange.subscribe(
|
|
173598
|
+
(s) => logger246.info(`${label} connectionState=${s} (${entityId})`)
|
|
173599
|
+
);
|
|
173600
|
+
peer.iceConnectionStateChange.subscribe(
|
|
173601
|
+
(s) => logger246.info(`${label} iceConnectionState=${s} (${entityId})`)
|
|
173602
|
+
);
|
|
173603
|
+
}
|
|
173604
|
+
// Map the Matter ICE struct onto werift's config. Only the controller peer
|
|
173605
|
+
// uses controller-supplied servers; the HA peer keeps werift defaults.
|
|
173606
|
+
controllerConfig(entityId, ice) {
|
|
173607
|
+
const iceServers = (ice?.iceServers ?? []).flatMap(
|
|
173608
|
+
(s) => (s.urLs ?? []).map((url2) => ({
|
|
173609
|
+
urls: url2,
|
|
173610
|
+
username: s.username,
|
|
173611
|
+
credential: s.credential
|
|
173612
|
+
}))
|
|
173613
|
+
);
|
|
173614
|
+
if (iceServers.length === 0) {
|
|
173615
|
+
logger246.info(`controller peer using default ICE servers (${entityId})`);
|
|
173616
|
+
return void 0;
|
|
173617
|
+
}
|
|
173618
|
+
const policy = ice?.iceTransportPolicy === "relay" || ice?.iceTransportPolicy === "all" ? ice.iceTransportPolicy : void 0;
|
|
173619
|
+
logger246.info(
|
|
173620
|
+
`controller peer using ${iceServers.length} controller ICE server(s)${policy ? ` policy=${policy}` : ""} (${entityId})`
|
|
173621
|
+
);
|
|
173622
|
+
return policy ? { iceServers, iceTransportPolicy: policy } : { iceServers };
|
|
173623
|
+
}
|
|
173624
|
+
localSdp(peer) {
|
|
173625
|
+
const local = peer.localDescription;
|
|
173626
|
+
if (!local) throw new Error("no local description");
|
|
173627
|
+
return local.sdp;
|
|
173628
|
+
}
|
|
173629
|
+
// Feed an HA trickle-ICE candidate into the HA peer.
|
|
173630
|
+
feedHaCandidate(entityId, haPeer, candidate) {
|
|
173631
|
+
const value = candidate?.candidate;
|
|
173632
|
+
if (!value) return;
|
|
173633
|
+
logger246.debug(`HA ICE candidate for ${entityId}: ${value}`);
|
|
173634
|
+
void haPeer.addIceCandidate({
|
|
173635
|
+
candidate: value,
|
|
173636
|
+
sdpMid: candidate?.sdpMid ?? void 0,
|
|
173637
|
+
sdpMLineIndex: candidate?.sdpMLineIndex ?? void 0
|
|
173638
|
+
}).catch(
|
|
173639
|
+
(e) => logger246.debug(
|
|
173640
|
+
`HA addIceCandidate failed for ${entityId}: ${errText3(e)}`
|
|
173641
|
+
)
|
|
173642
|
+
);
|
|
173643
|
+
}
|
|
173644
|
+
// Offer to HA's WebRTC and resolve on the first answer. Rejects on an error
|
|
173645
|
+
// reply or after a timeout; keeps the subscription open past the answer so HA
|
|
173646
|
+
// trickle candidates keep flowing into the HA peer until the session ends.
|
|
173647
|
+
async requestHaWebRtc(entityId, offerSdp, haPeer) {
|
|
173244
173648
|
const conn = await this.ha();
|
|
173245
|
-
|
|
173649
|
+
let unsubscribe = () => {
|
|
173650
|
+
};
|
|
173651
|
+
let sessionId;
|
|
173652
|
+
const answer = await new Promise((resolve11, reject) => {
|
|
173246
173653
|
let settled = false;
|
|
173654
|
+
let rejected = false;
|
|
173655
|
+
let timer;
|
|
173656
|
+
const settle = (fn) => {
|
|
173657
|
+
if (settled) return;
|
|
173658
|
+
settled = true;
|
|
173659
|
+
clearTimeout(timer);
|
|
173660
|
+
fn();
|
|
173661
|
+
};
|
|
173662
|
+
const fail = (err) => settle(() => {
|
|
173663
|
+
rejected = true;
|
|
173664
|
+
unsubscribe();
|
|
173665
|
+
reject(err);
|
|
173666
|
+
});
|
|
173667
|
+
timer = setTimeout(() => {
|
|
173668
|
+
logger246.info(
|
|
173669
|
+
`HA WebRTC timed out after ${haWebRtcTimeoutMs}ms for ${entityId}`
|
|
173670
|
+
);
|
|
173671
|
+
fail(
|
|
173672
|
+
new Error(`HA WebRTC request timed out after ${haWebRtcTimeoutMs}ms`)
|
|
173673
|
+
);
|
|
173674
|
+
}, haWebRtcTimeoutMs);
|
|
173247
173675
|
conn.subscribeMessage(
|
|
173248
173676
|
(msg) => {
|
|
173249
|
-
|
|
173250
|
-
|
|
173251
|
-
|
|
173252
|
-
|
|
173253
|
-
|
|
173254
|
-
|
|
173255
|
-
|
|
173677
|
+
switch (msg.type) {
|
|
173678
|
+
case "session":
|
|
173679
|
+
if (msg.session_id) sessionId = msg.session_id;
|
|
173680
|
+
break;
|
|
173681
|
+
case "answer":
|
|
173682
|
+
if (msg.answer) {
|
|
173683
|
+
if (msg.session_id) sessionId = msg.session_id;
|
|
173684
|
+
const ans = msg.answer;
|
|
173685
|
+
settle(() => {
|
|
173686
|
+
logger246.info(
|
|
173687
|
+
`HA answer received for ${entityId} (${ans.length} chars)`
|
|
173688
|
+
);
|
|
173689
|
+
resolve11(ans);
|
|
173690
|
+
});
|
|
173691
|
+
}
|
|
173692
|
+
break;
|
|
173693
|
+
case "error": {
|
|
173694
|
+
const detail = msg.message ?? msg.code ?? "unknown error";
|
|
173695
|
+
logger246.info(`HA WebRTC error for ${entityId}: ${detail}`);
|
|
173696
|
+
fail(new Error(`HA WebRTC error: ${detail}`));
|
|
173697
|
+
break;
|
|
173256
173698
|
}
|
|
173257
|
-
|
|
173699
|
+
case "candidate":
|
|
173700
|
+
this.feedHaCandidate(entityId, haPeer, msg.candidate);
|
|
173701
|
+
break;
|
|
173258
173702
|
}
|
|
173259
173703
|
},
|
|
173260
173704
|
{ type: "camera/webrtc/offer", entity_id: entityId, offer: offerSdp }
|
|
173261
|
-
).
|
|
173705
|
+
).then((unsub) => {
|
|
173706
|
+
unsubscribe = unsub;
|
|
173707
|
+
if (rejected) unsub();
|
|
173708
|
+
}).catch((err) => {
|
|
173709
|
+
fail(err instanceof Error ? err : new Error(String(err)));
|
|
173710
|
+
});
|
|
173262
173711
|
});
|
|
173712
|
+
return { answer, sessionId, unsubscribe };
|
|
173263
173713
|
}
|
|
173264
173714
|
};
|
|
173715
|
+
function offerKinds(sdp) {
|
|
173716
|
+
const kinds = [];
|
|
173717
|
+
for (const m of sdp.matchAll(/^m=(video|audio)/gm)) {
|
|
173718
|
+
kinds.push(m[1]);
|
|
173719
|
+
}
|
|
173720
|
+
return kinds;
|
|
173721
|
+
}
|
|
173722
|
+
function errText3(err) {
|
|
173723
|
+
return err instanceof Error ? err.message : String(err);
|
|
173724
|
+
}
|
|
173265
173725
|
|
|
173266
173726
|
// src/plugins/builtin/camera/camera-plugin.ts
|
|
173267
173727
|
var CONFIG_KEY = "config";
|
|
@@ -173394,6 +173854,7 @@ var CameraPlugin = class {
|
|
|
173394
173854
|
await this.bridge?.close().catch(() => {
|
|
173395
173855
|
});
|
|
173396
173856
|
this.bridge = void 0;
|
|
173857
|
+
unregisterAllRequestors();
|
|
173397
173858
|
}
|
|
173398
173859
|
};
|
|
173399
173860
|
|
|
@@ -173407,7 +173868,7 @@ import {
|
|
|
173407
173868
|
getCollection
|
|
173408
173869
|
} from "home-assistant-js-websocket";
|
|
173409
173870
|
import { atLeastHaVersion } from "home-assistant-js-websocket/dist/util.js";
|
|
173410
|
-
var
|
|
173871
|
+
var logger247 = Logger.get("SubscribeEntities");
|
|
173411
173872
|
function processEvent(store, updates) {
|
|
173412
173873
|
const state = { ...store.state };
|
|
173413
173874
|
if (updates.a) {
|
|
@@ -173433,7 +173894,7 @@ function processEvent(store, updates) {
|
|
|
173433
173894
|
for (const entityId in updates.c) {
|
|
173434
173895
|
let entityState = state[entityId];
|
|
173435
173896
|
if (!entityState) {
|
|
173436
|
-
|
|
173897
|
+
logger247.warn("Received state update for unknown entity", entityId);
|
|
173437
173898
|
continue;
|
|
173438
173899
|
}
|
|
173439
173900
|
entityState = { ...entityState };
|
|
@@ -173522,7 +173983,7 @@ var subscribeEntities = (conn, onChange, entityIds) => {
|
|
|
173522
173983
|
// src/services/bridges/entity-isolation-service.ts
|
|
173523
173984
|
init_esm();
|
|
173524
173985
|
init_diagnostic_event_bus();
|
|
173525
|
-
var
|
|
173986
|
+
var logger248 = Logger.get("EntityIsolation");
|
|
173526
173987
|
var EntityIsolationServiceImpl = class {
|
|
173527
173988
|
isolatedEntities = /* @__PURE__ */ new Map();
|
|
173528
173989
|
isolationCallbacks = /* @__PURE__ */ new Map();
|
|
@@ -173587,13 +174048,13 @@ var EntityIsolationServiceImpl = class {
|
|
|
173587
174048
|
}
|
|
173588
174049
|
const parsed = this.parseEndpointPath(msg);
|
|
173589
174050
|
if (!parsed) {
|
|
173590
|
-
|
|
174051
|
+
logger248.warn("Could not parse entity from error:", msg);
|
|
173591
174052
|
return false;
|
|
173592
174053
|
}
|
|
173593
174054
|
const { bridgeId, entityName } = parsed;
|
|
173594
174055
|
const callback = this.isolationCallbacks.get(bridgeId);
|
|
173595
174056
|
if (!callback) {
|
|
173596
|
-
|
|
174057
|
+
logger248.warn(
|
|
173597
174058
|
`No isolation callback registered for bridge ${bridgeId}, entity: ${entityName}`
|
|
173598
174059
|
);
|
|
173599
174060
|
return false;
|
|
@@ -173608,7 +174069,7 @@ var EntityIsolationServiceImpl = class {
|
|
|
173608
174069
|
reason,
|
|
173609
174070
|
failedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
173610
174071
|
});
|
|
173611
|
-
|
|
174072
|
+
logger248.warn(
|
|
173612
174073
|
`Isolating entity "${entityName}" from bridge ${bridgeId} due to: ${reason}`
|
|
173613
174074
|
);
|
|
173614
174075
|
diagnosticEventBus.emit("entity_error", `Entity isolated: ${entityName}`, {
|
|
@@ -173620,7 +174081,7 @@ var EntityIsolationServiceImpl = class {
|
|
|
173620
174081
|
await callback(entityName);
|
|
173621
174082
|
return true;
|
|
173622
174083
|
} catch (e) {
|
|
173623
|
-
|
|
174084
|
+
logger248.error(`Failed to isolate entity ${entityName}:`, e);
|
|
173624
174085
|
return false;
|
|
173625
174086
|
}
|
|
173626
174087
|
}
|
|
@@ -173653,10 +174114,10 @@ var EntityIsolationService = new EntityIsolationServiceImpl();
|
|
|
173653
174114
|
var MAX_ENTITY_ID_LENGTH = 150;
|
|
173654
174115
|
var ENDPOINT_REMOVAL_GRACE_MS = 6e4;
|
|
173655
174116
|
var BridgeEndpointManager = class extends Service {
|
|
173656
|
-
constructor(client,
|
|
174117
|
+
constructor(client, registry3, mappingStorage, identityStorage, bridgeId, log, pluginManager, pluginRegistry, pluginInstaller) {
|
|
173657
174118
|
super("BridgeEndpointManager");
|
|
173658
174119
|
this.client = client;
|
|
173659
|
-
this.registry =
|
|
174120
|
+
this.registry = registry3;
|
|
173660
174121
|
this.mappingStorage = mappingStorage;
|
|
173661
174122
|
this.identityStorage = identityStorage;
|
|
173662
174123
|
this.bridgeId = bridgeId;
|
|
@@ -174367,8 +174828,8 @@ init_send_ha_message();
|
|
|
174367
174828
|
import { callService as callService2 } from "home-assistant-js-websocket";
|
|
174368
174829
|
import { keys as keys2, pickBy, values as values3 } from "lodash-es";
|
|
174369
174830
|
var BridgeRegistry = class _BridgeRegistry {
|
|
174370
|
-
constructor(
|
|
174371
|
-
this.registry =
|
|
174831
|
+
constructor(registry3, dataProvider, client) {
|
|
174832
|
+
this.registry = registry3;
|
|
174372
174833
|
this.dataProvider = dataProvider;
|
|
174373
174834
|
this.client = client;
|
|
174374
174835
|
this.refresh();
|
|
@@ -175138,11 +175599,11 @@ function makeWarmStartState(state, now = (/* @__PURE__ */ new Date()).toISOStrin
|
|
|
175138
175599
|
return { ...state, last_updated: now };
|
|
175139
175600
|
}
|
|
175140
175601
|
var ServerModeBridge = class {
|
|
175141
|
-
constructor(
|
|
175602
|
+
constructor(logger251, dataProvider, endpointManager, server) {
|
|
175142
175603
|
this.dataProvider = dataProvider;
|
|
175143
175604
|
this.endpointManager = endpointManager;
|
|
175144
175605
|
this.server = server;
|
|
175145
|
-
this.log =
|
|
175606
|
+
this.log = logger251.get(`ServerModeBridge / ${dataProvider.id}`);
|
|
175146
175607
|
}
|
|
175147
175608
|
dataProvider;
|
|
175148
175609
|
endpointManager;
|
|
@@ -176172,12 +176633,12 @@ function ServerModeVacuumDevice(homeAssistantEntity, includeOnOff = false, clean
|
|
|
176172
176633
|
}
|
|
176173
176634
|
|
|
176174
176635
|
// src/matter/endpoints/server-mode-vacuum-endpoint.ts
|
|
176175
|
-
var
|
|
176636
|
+
var logger249 = Logger.get("ServerModeVacuumEndpoint");
|
|
176176
176637
|
var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEndpoint {
|
|
176177
|
-
static async create(
|
|
176178
|
-
const deviceRegistry =
|
|
176179
|
-
let state =
|
|
176180
|
-
const entity =
|
|
176638
|
+
static async create(registry3, entityId, mapping, endpointId) {
|
|
176639
|
+
const deviceRegistry = registry3.deviceOf(entityId);
|
|
176640
|
+
let state = registry3.initialState(entityId);
|
|
176641
|
+
const entity = registry3.entity(entityId);
|
|
176181
176642
|
if (!state) {
|
|
176182
176643
|
return void 0;
|
|
176183
176644
|
}
|
|
@@ -176185,12 +176646,12 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
176185
176646
|
if (mapping?.disableBatteryMapping && mapping.batteryEntity) {
|
|
176186
176647
|
effectiveMapping = { ...mapping, batteryEntity: void 0 };
|
|
176187
176648
|
}
|
|
176188
|
-
|
|
176649
|
+
logger249.info(
|
|
176189
176650
|
`${entityId}: device_id=${entity.device_id}, manualBattery=${mapping?.batteryEntity ?? "none"}`
|
|
176190
176651
|
);
|
|
176191
176652
|
if (entity.device_id) {
|
|
176192
176653
|
if (!mapping?.batteryEntity && !mapping?.disableBatteryMapping) {
|
|
176193
|
-
const batteryEntityId =
|
|
176654
|
+
const batteryEntityId = registry3.findBatteryEntityForDevice(
|
|
176194
176655
|
entity.device_id
|
|
176195
176656
|
);
|
|
176196
176657
|
if (batteryEntityId && batteryEntityId !== entityId) {
|
|
@@ -176199,22 +176660,22 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
176199
176660
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
176200
176661
|
batteryEntity: batteryEntityId
|
|
176201
176662
|
};
|
|
176202
|
-
|
|
176203
|
-
|
|
176663
|
+
registry3.markBatteryEntityUsed(batteryEntityId);
|
|
176664
|
+
logger249.info(`${entityId}: Auto-assigned battery ${batteryEntityId}`);
|
|
176204
176665
|
} else {
|
|
176205
176666
|
const attrs = state.attributes;
|
|
176206
176667
|
if (attrs.battery_level != null || attrs.battery != null) {
|
|
176207
|
-
|
|
176668
|
+
logger249.info(
|
|
176208
176669
|
`${entityId}: No battery entity found, using battery attribute from vacuum state`
|
|
176209
176670
|
);
|
|
176210
176671
|
} else {
|
|
176211
|
-
|
|
176672
|
+
logger249.warn(
|
|
176212
176673
|
`${entityId}: No battery entity found for device ${entity.device_id}`
|
|
176213
176674
|
);
|
|
176214
176675
|
}
|
|
176215
176676
|
}
|
|
176216
176677
|
}
|
|
176217
|
-
const vacuumEntities =
|
|
176678
|
+
const vacuumEntities = registry3.findVacuumSelectEntities(
|
|
176218
176679
|
entity.device_id
|
|
176219
176680
|
);
|
|
176220
176681
|
if (!effectiveMapping?.cleaningModeEntity && vacuumEntities.cleaningModeEntity) {
|
|
@@ -176223,7 +176684,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
176223
176684
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
176224
176685
|
cleaningModeEntity: vacuumEntities.cleaningModeEntity
|
|
176225
176686
|
};
|
|
176226
|
-
|
|
176687
|
+
logger249.info(
|
|
176227
176688
|
`${entityId}: Auto-assigned cleaningMode ${vacuumEntities.cleaningModeEntity}`
|
|
176228
176689
|
);
|
|
176229
176690
|
}
|
|
@@ -176233,7 +176694,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
176233
176694
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
176234
176695
|
suctionLevelEntity: vacuumEntities.suctionLevelEntity
|
|
176235
176696
|
};
|
|
176236
|
-
|
|
176697
|
+
logger249.info(
|
|
176237
176698
|
`${entityId}: Auto-assigned suctionLevel ${vacuumEntities.suctionLevelEntity}`
|
|
176238
176699
|
);
|
|
176239
176700
|
}
|
|
@@ -176243,7 +176704,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
176243
176704
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
176244
176705
|
mopIntensityEntity: vacuumEntities.mopIntensityEntity
|
|
176245
176706
|
};
|
|
176246
|
-
|
|
176707
|
+
logger249.info(
|
|
176247
176708
|
`${entityId}: Auto-assigned mopIntensity ${vacuumEntities.mopIntensityEntity}`
|
|
176248
176709
|
);
|
|
176249
176710
|
}
|
|
@@ -176253,12 +176714,12 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
176253
176714
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
176254
176715
|
currentRoomEntity: vacuumEntities.currentRoomEntity
|
|
176255
176716
|
};
|
|
176256
|
-
|
|
176717
|
+
logger249.info(
|
|
176257
176718
|
`${entityId}: Auto-assigned currentRoom ${vacuumEntities.currentRoomEntity}`
|
|
176258
176719
|
);
|
|
176259
176720
|
}
|
|
176260
176721
|
const supportedFeatures = state.attributes.supported_features ?? 0;
|
|
176261
|
-
const cleanAreaRooms = await
|
|
176722
|
+
const cleanAreaRooms = await registry3.resolveCleanAreaRooms(
|
|
176262
176723
|
entityId,
|
|
176263
176724
|
supportedFeatures
|
|
176264
176725
|
);
|
|
@@ -176268,13 +176729,13 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
176268
176729
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
176269
176730
|
cleanAreaRooms
|
|
176270
176731
|
};
|
|
176271
|
-
|
|
176732
|
+
logger249.info(
|
|
176272
176733
|
`${entityId}: Using ${cleanAreaRooms.length} HA areas via CLEAN_AREA`
|
|
176273
176734
|
);
|
|
176274
176735
|
}
|
|
176275
176736
|
const vacAttrs = state.attributes;
|
|
176276
176737
|
if (cleanAreaRooms.length === 0 && !vacAttrs.rooms && !vacAttrs.segments && !vacAttrs.room_mapping) {
|
|
176277
|
-
const valetudoRooms =
|
|
176738
|
+
const valetudoRooms = registry3.findValetudoMapSegments(
|
|
176278
176739
|
entity.device_id
|
|
176279
176740
|
);
|
|
176280
176741
|
if (valetudoRooms.length > 0) {
|
|
@@ -176289,11 +176750,11 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
176289
176750
|
rooms: roomsObj
|
|
176290
176751
|
}
|
|
176291
176752
|
};
|
|
176292
|
-
|
|
176753
|
+
logger249.info(
|
|
176293
176754
|
`${entityId}: Auto-detected ${valetudoRooms.length} Valetudo segments`
|
|
176294
176755
|
);
|
|
176295
176756
|
} else {
|
|
176296
|
-
const roborockRooms = await
|
|
176757
|
+
const roborockRooms = await registry3.resolveRoborockRooms(entityId);
|
|
176297
176758
|
if (roborockRooms.length > 0) {
|
|
176298
176759
|
const roomsObj = {};
|
|
176299
176760
|
for (const r of roborockRooms) {
|
|
@@ -176306,14 +176767,14 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
176306
176767
|
rooms: roomsObj
|
|
176307
176768
|
}
|
|
176308
176769
|
};
|
|
176309
|
-
|
|
176770
|
+
logger249.info(
|
|
176310
176771
|
`${entityId}: Auto-detected ${roborockRooms.length} Roborock rooms`
|
|
176311
176772
|
);
|
|
176312
176773
|
}
|
|
176313
176774
|
}
|
|
176314
176775
|
}
|
|
176315
176776
|
} else {
|
|
176316
|
-
|
|
176777
|
+
logger249.warn(`${entityId}: No device_id, cannot auto-assign battery`);
|
|
176317
176778
|
}
|
|
176318
176779
|
const payload = {
|
|
176319
176780
|
entity_id: entityId,
|
|
@@ -176324,7 +176785,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
176324
176785
|
const vacAttrsForClean = state.attributes;
|
|
176325
176786
|
let cleaningModeOptions;
|
|
176326
176787
|
if (effectiveMapping?.cleaningModeEntity) {
|
|
176327
|
-
const cmState =
|
|
176788
|
+
const cmState = registry3.initialState(
|
|
176328
176789
|
effectiveMapping.cleaningModeEntity
|
|
176329
176790
|
);
|
|
176330
176791
|
cleaningModeOptions = cmState?.attributes?.options;
|
|
@@ -176344,7 +176805,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
176344
176805
|
customName,
|
|
176345
176806
|
mapping: effectiveMapping
|
|
176346
176807
|
},
|
|
176347
|
-
|
|
176808
|
+
registry3.isServerModeVacuumOnOffEnabled(),
|
|
176348
176809
|
cleaningModeOptions
|
|
176349
176810
|
);
|
|
176350
176811
|
if (!endpointType) {
|
|
@@ -176386,11 +176847,11 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
176386
176847
|
}
|
|
176387
176848
|
if (mappedChanged) {
|
|
176388
176849
|
this.pendingMappedChange = true;
|
|
176389
|
-
|
|
176850
|
+
logger249.debug(
|
|
176390
176851
|
`Mapped entity change detected for ${this.entityId}, forcing update`
|
|
176391
176852
|
);
|
|
176392
176853
|
}
|
|
176393
|
-
|
|
176854
|
+
logger249.debug(
|
|
176394
176855
|
`State update received for ${this.entityId}: state=${state.state}`
|
|
176395
176856
|
);
|
|
176396
176857
|
this.lastState = state;
|
|
@@ -176430,11 +176891,11 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
176430
176891
|
// src/services/bridges/server-mode-endpoint-manager.ts
|
|
176431
176892
|
var MAX_SERVER_MODE_DEVICES = 10;
|
|
176432
176893
|
var ServerModeEndpointManager = class extends Service {
|
|
176433
|
-
constructor(serverNode, client,
|
|
176894
|
+
constructor(serverNode, client, registry3, mappingStorage, identityStorage, dataProvider, log) {
|
|
176434
176895
|
super("ServerModeEndpointManager");
|
|
176435
176896
|
this.serverNode = serverNode;
|
|
176436
176897
|
this.client = client;
|
|
176437
|
-
this.registry =
|
|
176898
|
+
this.registry = registry3;
|
|
176438
176899
|
this.mappingStorage = mappingStorage;
|
|
176439
176900
|
this.identityStorage = identityStorage;
|
|
176440
176901
|
this.dataProvider = dataProvider;
|
|
@@ -176968,10 +177429,10 @@ var BridgeEnvironmentFactory = class extends BridgeFactory {
|
|
|
176968
177429
|
// src/core/ioc/app-environment.ts
|
|
176969
177430
|
var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
176970
177431
|
constructor(rootEnv, options) {
|
|
176971
|
-
const
|
|
177432
|
+
const logger251 = rootEnv.get(LoggerService);
|
|
176972
177433
|
super({
|
|
176973
177434
|
id: "App",
|
|
176974
|
-
log:
|
|
177435
|
+
log: logger251.get("AppContainer"),
|
|
176975
177436
|
parent: rootEnv
|
|
176976
177437
|
});
|
|
176977
177438
|
this.options = options;
|
|
@@ -176985,8 +177446,8 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
176985
177446
|
}
|
|
176986
177447
|
construction;
|
|
176987
177448
|
async init() {
|
|
176988
|
-
const
|
|
176989
|
-
this.set(LoggerService,
|
|
177449
|
+
const logger251 = this.get(LoggerService);
|
|
177450
|
+
this.set(LoggerService, logger251);
|
|
176990
177451
|
this.set(AppStorage, new AppStorage(await this.load(StorageService)));
|
|
176991
177452
|
this.set(BridgeStorage, new BridgeStorage(await this.load(AppStorage)));
|
|
176992
177453
|
this.set(
|
|
@@ -177007,7 +177468,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
177007
177468
|
);
|
|
177008
177469
|
this.set(
|
|
177009
177470
|
HomeAssistantClient,
|
|
177010
|
-
new HomeAssistantClient(
|
|
177471
|
+
new HomeAssistantClient(logger251, this.options.homeAssistant)
|
|
177011
177472
|
);
|
|
177012
177473
|
this.set(
|
|
177013
177474
|
HomeAssistantConfig,
|
|
@@ -177015,7 +177476,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
177015
177476
|
);
|
|
177016
177477
|
this.set(
|
|
177017
177478
|
HomeAssistantActions,
|
|
177018
|
-
new HomeAssistantActions(
|
|
177479
|
+
new HomeAssistantActions(logger251, await this.load(HomeAssistantClient))
|
|
177019
177480
|
);
|
|
177020
177481
|
this.set(
|
|
177021
177482
|
HomeAssistantRegistry,
|
|
@@ -177051,7 +177512,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
177051
177512
|
this.set(
|
|
177052
177513
|
WebApi,
|
|
177053
177514
|
new WebApi(
|
|
177054
|
-
|
|
177515
|
+
logger251,
|
|
177055
177516
|
await this.load(BridgeService),
|
|
177056
177517
|
await this.load(HomeAssistantClient),
|
|
177057
177518
|
await this.load(HomeAssistantRegistry),
|
|
@@ -177072,7 +177533,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
177072
177533
|
|
|
177073
177534
|
// src/matter/patches/patch-level-control-tlv.ts
|
|
177074
177535
|
init_esm();
|
|
177075
|
-
var
|
|
177536
|
+
var logger250 = Logger.get("PatchLevelControlTlv");
|
|
177076
177537
|
var optionalFieldModels = /* @__PURE__ */ new WeakSet();
|
|
177077
177538
|
var fieldModelMandatoryGetterPatched = false;
|
|
177078
177539
|
function patchLevelControlTlv() {
|
|
@@ -177128,11 +177589,11 @@ function patchLevelControlTlv() {
|
|
|
177128
177589
|
patched++;
|
|
177129
177590
|
}
|
|
177130
177591
|
if (patched > 0) {
|
|
177131
|
-
|
|
177592
|
+
logger250.info(
|
|
177132
177593
|
`Patched ${patched} LevelControl TLV schema(s): transitionTime is now optional (Google Home compatibility)`
|
|
177133
177594
|
);
|
|
177134
177595
|
} else {
|
|
177135
|
-
|
|
177596
|
+
logger250.warn(
|
|
177136
177597
|
"Failed to patch LevelControl TLV schemas, field definitions not found. Google Home brightness adjustment may not work.",
|
|
177137
177598
|
{
|
|
177138
177599
|
moveToLevel: describeFields(
|