@riddix/hamh 2.0.54 → 2.0.55
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 +16 -5
- package/dist/backend/cli.js +1174 -613
- package/dist/frontend/assets/{index-CGD-E6t7.js → index-CgudGWST.js} +152 -152
- package/dist/frontend/index.html +1 -1
- package/package.json +4 -4
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(logger255) {
|
|
1771
|
+
this.#logger = logger255;
|
|
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, logger255, 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 = logger255;
|
|
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 logger255 = Logger.get(this.#subject.constructor.name);
|
|
5691
|
+
logger255.error(...args);
|
|
5692
5692
|
}
|
|
5693
5693
|
#createErrorHandler(name) {
|
|
5694
5694
|
return (e) => {
|
|
@@ -64126,8 +64126,8 @@ var init_NodeSession = __esm({
|
|
|
64126
64126
|
return session?.type === SessionType.Unicast;
|
|
64127
64127
|
}
|
|
64128
64128
|
NodeSession2.is = is;
|
|
64129
|
-
function logNew(
|
|
64130
|
-
|
|
64129
|
+
function logNew(logger255, operation, session, messenger, fabric, peerNodeId) {
|
|
64130
|
+
logger255.info(
|
|
64131
64131
|
session.via,
|
|
64132
64132
|
`${operation} session with`,
|
|
64133
64133
|
Diagnostic.strong(PeerAddress({ fabricIndex: fabric.fabricIndex, nodeId: peerNodeId }).toString()),
|
|
@@ -118041,11 +118041,11 @@ var init_Api = __esm({
|
|
|
118041
118041
|
}
|
|
118042
118042
|
Api2.resourceFor = resourceFor;
|
|
118043
118043
|
function log(level, facility, id, ...message) {
|
|
118044
|
-
let
|
|
118045
|
-
if (!
|
|
118046
|
-
loggers.set(facility,
|
|
118044
|
+
let logger255 = loggers.get(facility);
|
|
118045
|
+
if (!logger255) {
|
|
118046
|
+
loggers.set(facility, logger255 = Logger.get(facility));
|
|
118047
118047
|
}
|
|
118048
|
-
|
|
118048
|
+
logger255[level](Diagnostic.via(id || "(anon)"), message);
|
|
118049
118049
|
}
|
|
118050
118050
|
Api2.log = log;
|
|
118051
118051
|
function logRequest(facility, id, method, target) {
|
|
@@ -132383,6 +132383,14 @@ var init_bridge_config_schema = __esm({
|
|
|
132383
132383
|
maximum: 5e3,
|
|
132384
132384
|
default: 0
|
|
132385
132385
|
},
|
|
132386
|
+
fanSliderDebounceMs: {
|
|
132387
|
+
title: "Fan Slider Debounce (ms)",
|
|
132388
|
+
description: "Wait this long after the last inbound fan-speed write before sending it to Home Assistant. Controllers stream percentSetting while the user is still dragging - one Google Home drag was measured emitting nine writes in eight seconds - and on IR or UART bridged air conditioners every write is a device frame that makes the unit beep. 0 (the default) sends every write immediately, matching previous behaviour. Try 1000-2000 ms for bridged ACs. A per-entity override on a single fan or climate wins over this flag.",
|
|
132389
|
+
type: "number",
|
|
132390
|
+
minimum: 0,
|
|
132391
|
+
maximum: 1e4,
|
|
132392
|
+
default: 0
|
|
132393
|
+
},
|
|
132386
132394
|
fastSessionRecovery: {
|
|
132387
132395
|
title: "Fast Session Recovery (Google offline workaround)",
|
|
132388
132396
|
description: "When a controller drops all subscriptions, clean up the dead session and re-announce after 5 seconds instead of 60. Opt-in for Google Home users whose devices go offline after a cancelled subscription (#386). It shortens the offline window but cannot stop the controller from rejecting the subscription. Default off.",
|
|
@@ -132763,6 +132771,14 @@ var init_esm7 = __esm({
|
|
|
132763
132771
|
}
|
|
132764
132772
|
});
|
|
132765
132773
|
|
|
132774
|
+
// ../../node_modules/.pnpm/@matter+main@0.17.9/node_modules/@matter/main/dist/esm/protocol.js
|
|
132775
|
+
var init_protocol3 = __esm({
|
|
132776
|
+
"../../node_modules/.pnpm/@matter+main@0.17.9/node_modules/@matter/main/dist/esm/protocol.js"() {
|
|
132777
|
+
init_nodejs();
|
|
132778
|
+
init_esm4();
|
|
132779
|
+
}
|
|
132780
|
+
});
|
|
132781
|
+
|
|
132766
132782
|
// src/utils/debounce-context.ts
|
|
132767
132783
|
import debounce from "debounce";
|
|
132768
132784
|
var DebounceContext;
|
|
@@ -132842,7 +132858,7 @@ async function withRetry(fn, options = {}) {
|
|
|
132842
132858
|
return await fn();
|
|
132843
132859
|
} catch (error) {
|
|
132844
132860
|
lastError = error;
|
|
132845
|
-
if (attempt === opts.maxAttempts) {
|
|
132861
|
+
if (attempt === opts.maxAttempts || options.shouldRetry?.(error) === false) {
|
|
132846
132862
|
break;
|
|
132847
132863
|
}
|
|
132848
132864
|
const delayMs = Math.min(
|
|
@@ -132906,6 +132922,12 @@ var init_retry = __esm({
|
|
|
132906
132922
|
get isOpen() {
|
|
132907
132923
|
return this.state === "open";
|
|
132908
132924
|
}
|
|
132925
|
+
// Open AND still inside the reset window. Callers that pre-check
|
|
132926
|
+
// availability must use this, not isOpen, or the half-open probe never
|
|
132927
|
+
// happens and the breaker stays latched forever (#446).
|
|
132928
|
+
get isBlocking() {
|
|
132929
|
+
return this.state === "open" && Date.now() - this.lastFailureTime < this.resetTimeoutMs;
|
|
132930
|
+
}
|
|
132909
132931
|
reset() {
|
|
132910
132932
|
this.failures = 0;
|
|
132911
132933
|
this.state = "closed";
|
|
@@ -132942,8 +132964,7 @@ var init_send_ha_message = __esm({
|
|
|
132942
132964
|
});
|
|
132943
132965
|
|
|
132944
132966
|
// src/services/home-assistant/home-assistant-actions.ts
|
|
132945
|
-
|
|
132946
|
-
var defaultConfig, HomeAssistantActions;
|
|
132967
|
+
var TARGET_FAILURE_THRESHOLD, defaultConfig, HomeAssistantActions;
|
|
132947
132968
|
var init_home_assistant_actions = __esm({
|
|
132948
132969
|
"src/services/home-assistant/home-assistant-actions.ts"() {
|
|
132949
132970
|
"use strict";
|
|
@@ -132952,6 +132973,7 @@ var init_home_assistant_actions = __esm({
|
|
|
132952
132973
|
init_retry();
|
|
132953
132974
|
init_send_ha_message();
|
|
132954
132975
|
init_diagnostic_event_bus();
|
|
132976
|
+
TARGET_FAILURE_THRESHOLD = 3;
|
|
132955
132977
|
defaultConfig = {
|
|
132956
132978
|
retryAttempts: 3,
|
|
132957
132979
|
retryBaseDelayMs: 100,
|
|
@@ -132960,10 +132982,10 @@ var init_home_assistant_actions = __esm({
|
|
|
132960
132982
|
circuitBreakerResetMs: 3e4
|
|
132961
132983
|
};
|
|
132962
132984
|
HomeAssistantActions = class extends Service {
|
|
132963
|
-
constructor(
|
|
132985
|
+
constructor(logger255, client, config8) {
|
|
132964
132986
|
super("HomeAssistantActions");
|
|
132965
132987
|
this.client = client;
|
|
132966
|
-
this.log =
|
|
132988
|
+
this.log = logger255.get(this);
|
|
132967
132989
|
this.config = { ...defaultConfig, ...config8 };
|
|
132968
132990
|
this.circuitBreaker = new CircuitBreaker(
|
|
132969
132991
|
this.config.circuitBreakerThreshold,
|
|
@@ -132971,6 +132993,13 @@ var init_home_assistant_actions = __esm({
|
|
|
132971
132993
|
);
|
|
132972
132994
|
}
|
|
132973
132995
|
client;
|
|
132996
|
+
// #446: a Matter command must not report success while HA cannot take the
|
|
132997
|
+
// call. Only the transport counts here: the breaker is app-wide, so ten
|
|
132998
|
+
// failures from one broken entity would otherwise make every device on
|
|
132999
|
+
// every bridge fail.
|
|
133000
|
+
get available() {
|
|
133001
|
+
return this.client.haRunning;
|
|
133002
|
+
}
|
|
132974
133003
|
log;
|
|
132975
133004
|
debounceContext = new DebounceContext(
|
|
132976
133005
|
this.processAction.bind(this)
|
|
@@ -132979,6 +133008,27 @@ var init_home_assistant_actions = __esm({
|
|
|
132979
133008
|
config;
|
|
132980
133009
|
consecutiveFailures = 0;
|
|
132981
133010
|
lastSuccessTime = Date.now();
|
|
133011
|
+
// Per entity, not app wide: the shared breaker would let one broken entity
|
|
133012
|
+
// make every device on every bridge fail (#446).
|
|
133013
|
+
targetFailures = /* @__PURE__ */ new Map();
|
|
133014
|
+
// A target that just failed repeatedly is reported as unavailable, so the
|
|
133015
|
+
// controller sees the failure on that device instead of a false success.
|
|
133016
|
+
isTargetBlocked(entityId) {
|
|
133017
|
+
const entry = this.targetFailures.get(entityId);
|
|
133018
|
+
return entry != null && Date.now() < entry.blockedUntil;
|
|
133019
|
+
}
|
|
133020
|
+
recordTargetResult(entityId, failed) {
|
|
133021
|
+
if (!entityId) return;
|
|
133022
|
+
if (!failed) {
|
|
133023
|
+
this.targetFailures.delete(entityId);
|
|
133024
|
+
return;
|
|
133025
|
+
}
|
|
133026
|
+
const count = (this.targetFailures.get(entityId)?.count ?? 0) + 1;
|
|
133027
|
+
this.targetFailures.set(entityId, {
|
|
133028
|
+
count,
|
|
133029
|
+
blockedUntil: count >= TARGET_FAILURE_THRESHOLD ? Date.now() + this.config.circuitBreakerResetMs : 0
|
|
133030
|
+
});
|
|
133031
|
+
}
|
|
132982
133032
|
processAction(_key, calls) {
|
|
132983
133033
|
const skipTarget = calls[0].target === false;
|
|
132984
133034
|
const entity_id = skipTarget ? void 0 : calls[0].target || calls[0].entityId;
|
|
@@ -132986,7 +133036,9 @@ var init_home_assistant_actions = __esm({
|
|
|
132986
133036
|
const data = Object.assign({}, ...calls.map((c) => c.data));
|
|
132987
133037
|
const [domain, actionName] = action.split(".");
|
|
132988
133038
|
const target = entity_id ? { entity_id } : {};
|
|
132989
|
-
|
|
133039
|
+
const origin = calls[0].entityId;
|
|
133040
|
+
this.callAction(domain, actionName, data, target, false).then(() => this.recordTargetResult(origin, false)).catch((error) => {
|
|
133041
|
+
this.recordTargetResult(origin, true);
|
|
132990
133042
|
const errorMsg = this.formatError(error);
|
|
132991
133043
|
this.log.error(
|
|
132992
133044
|
`Failed to call action '${action}' for entity '${entity_id ?? "(no target)"}': ${errorMsg}`
|
|
@@ -133022,13 +133074,17 @@ var init_home_assistant_actions = __esm({
|
|
|
133022
133074
|
const result = await this.circuitBreaker.execute(
|
|
133023
133075
|
() => withRetry(
|
|
133024
133076
|
async () => {
|
|
133025
|
-
const res = await
|
|
133077
|
+
const res = await sendHaMessage(
|
|
133026
133078
|
this.client.connection,
|
|
133027
|
-
|
|
133028
|
-
|
|
133029
|
-
|
|
133030
|
-
|
|
133031
|
-
|
|
133079
|
+
{
|
|
133080
|
+
type: "call_service",
|
|
133081
|
+
domain,
|
|
133082
|
+
service: action,
|
|
133083
|
+
service_data: data,
|
|
133084
|
+
target,
|
|
133085
|
+
return_response: returnResponse
|
|
133086
|
+
},
|
|
133087
|
+
this.client.messageTimeoutMs
|
|
133032
133088
|
);
|
|
133033
133089
|
return res;
|
|
133034
133090
|
},
|
|
@@ -133036,6 +133092,9 @@ var init_home_assistant_actions = __esm({
|
|
|
133036
133092
|
maxAttempts: this.config.retryAttempts,
|
|
133037
133093
|
baseDelayMs: this.config.retryBaseDelayMs,
|
|
133038
133094
|
maxDelayMs: this.config.retryMaxDelayMs,
|
|
133095
|
+
// A timeout does not mean HA ignored the call, it may have run it.
|
|
133096
|
+
// Repeating a button press or a script would be worse than failing.
|
|
133097
|
+
shouldRetry: (error) => !(error instanceof Error && error.message.includes("timed out")),
|
|
133039
133098
|
onRetry: (attempt, error, delayMs) => {
|
|
133040
133099
|
const errorMsg = this.formatError(error);
|
|
133041
133100
|
this.log.warn(
|
|
@@ -133109,6 +133168,14 @@ var init_home_assistant_actions = __esm({
|
|
|
133109
133168
|
}
|
|
133110
133169
|
});
|
|
133111
133170
|
|
|
133171
|
+
// ../../node_modules/.pnpm/@matter+main@0.17.9/node_modules/@matter/main/dist/esm/types.js
|
|
133172
|
+
var init_types2 = __esm({
|
|
133173
|
+
"../../node_modules/.pnpm/@matter+main@0.17.9/node_modules/@matter/main/dist/esm/types.js"() {
|
|
133174
|
+
init_nodejs();
|
|
133175
|
+
init_esm3();
|
|
133176
|
+
}
|
|
133177
|
+
});
|
|
133178
|
+
|
|
133112
133179
|
// src/utils/async-observable.ts
|
|
133113
133180
|
var AsyncObservable2;
|
|
133114
133181
|
var init_async_observable = __esm({
|
|
@@ -133119,6 +133186,17 @@ var init_async_observable = __esm({
|
|
|
133119
133186
|
}
|
|
133120
133187
|
});
|
|
133121
133188
|
|
|
133189
|
+
// src/utils/transaction-is-offline.ts
|
|
133190
|
+
function transactionIsOffline(context) {
|
|
133191
|
+
return !context || hasLocalActor(context);
|
|
133192
|
+
}
|
|
133193
|
+
var init_transaction_is_offline = __esm({
|
|
133194
|
+
"src/utils/transaction-is-offline.ts"() {
|
|
133195
|
+
"use strict";
|
|
133196
|
+
init_protocol3();
|
|
133197
|
+
}
|
|
133198
|
+
});
|
|
133199
|
+
|
|
133122
133200
|
// src/matter/behaviors/home-assistant-entity-behavior.ts
|
|
133123
133201
|
var home_assistant_entity_behavior_exports = {};
|
|
133124
133202
|
__export(home_assistant_entity_behavior_exports, {
|
|
@@ -133130,8 +133208,10 @@ var init_home_assistant_entity_behavior = __esm({
|
|
|
133130
133208
|
"use strict";
|
|
133131
133209
|
init_dist();
|
|
133132
133210
|
init_esm7();
|
|
133211
|
+
init_types2();
|
|
133133
133212
|
init_home_assistant_actions();
|
|
133134
133213
|
init_async_observable();
|
|
133214
|
+
init_transaction_is_offline();
|
|
133135
133215
|
HomeAssistantEntityBehavior = class extends Behavior {
|
|
133136
133216
|
static id = ClusterId2.homeAssistantEntity;
|
|
133137
133217
|
get entityId() {
|
|
@@ -133146,7 +133226,24 @@ var init_home_assistant_entity_behavior = __esm({
|
|
|
133146
133226
|
get isAvailable() {
|
|
133147
133227
|
return this.entity.state.state !== "unavailable" && this.entity.state.state !== "unknown";
|
|
133148
133228
|
}
|
|
133229
|
+
// #446: fail the command instead of telling the controller it worked while
|
|
133230
|
+
// the call never reaches HA. `=== false` on purpose: test stubs do not
|
|
133231
|
+
// define `available`, and undefined must read as "no opinion".
|
|
133232
|
+
// ponytail: commands only. Attribute writes that fan and thermostat handle
|
|
133233
|
+
// in reactors run as a local actor, so they still go through and rely on HA
|
|
133234
|
+
// state to correct them. Plumb it there too if that shows up in reports.
|
|
133235
|
+
assertAvailable() {
|
|
133236
|
+
const actions = this.env.get(HomeAssistantActions);
|
|
133237
|
+
const blocked = actions.available === false || actions.isTargetBlocked?.(this.entityId) === true;
|
|
133238
|
+
if (blocked && !transactionIsOffline(this.context)) {
|
|
133239
|
+
throw new StatusResponseError(
|
|
133240
|
+
"Home Assistant is not reachable",
|
|
133241
|
+
StatusCode.Failure
|
|
133242
|
+
);
|
|
133243
|
+
}
|
|
133244
|
+
}
|
|
133149
133245
|
callAction(action) {
|
|
133246
|
+
this.assertAvailable();
|
|
133150
133247
|
const actions = this.env.get(HomeAssistantActions);
|
|
133151
133248
|
actions.call(action, this.entityId);
|
|
133152
133249
|
}
|
|
@@ -133309,10 +133406,10 @@ var DiagnosticService = class {
|
|
|
133309
133406
|
};
|
|
133310
133407
|
|
|
133311
133408
|
// src/api/access-log.ts
|
|
133312
|
-
function accessLogger(
|
|
133409
|
+
function accessLogger(logger255) {
|
|
133313
133410
|
return (req, res, next) => {
|
|
133314
133411
|
res.on("finish", () => {
|
|
133315
|
-
|
|
133412
|
+
logger255.debug(
|
|
133316
133413
|
`${req.method} ${decodeURI(req.originalUrl)} ${res.statusCode} ${res.statusMessage} from ${req.socket.remoteAddress}`
|
|
133317
133414
|
);
|
|
133318
133415
|
});
|
|
@@ -133593,6 +133690,7 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
|
|
|
133593
133690
|
valetudoIdentifier: config8.valetudoIdentifier,
|
|
133594
133691
|
coverSwapOpenClose: config8.coverSwapOpenClose,
|
|
133595
133692
|
coverSliderDebounceMs: config8.coverSliderDebounceMs,
|
|
133693
|
+
fanSliderDebounceMs: config8.fanSliderDebounceMs,
|
|
133596
133694
|
disableClimateOnOff: config8.disableClimateOnOff,
|
|
133597
133695
|
disableClimateFanControl: config8.disableClimateFanControl,
|
|
133598
133696
|
climateAutoMode: config8.climateAutoMode,
|
|
@@ -133762,6 +133860,7 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
|
|
|
133762
133860
|
valetudoIdentifier: config8.valetudoIdentifier,
|
|
133763
133861
|
coverSwapOpenClose: config8.coverSwapOpenClose,
|
|
133764
133862
|
coverSliderDebounceMs: config8.coverSliderDebounceMs,
|
|
133863
|
+
fanSliderDebounceMs: config8.fanSliderDebounceMs,
|
|
133765
133864
|
disableClimateOnOff: config8.disableClimateOnOff,
|
|
133766
133865
|
disableClimateFanControl: config8.disableClimateFanControl,
|
|
133767
133866
|
climateAutoMode: config8.climateAutoMode,
|
|
@@ -134644,6 +134743,7 @@ function entityMappingApi(mappingStorage, identityStorage) {
|
|
|
134644
134743
|
selectSwitchOnOption: body.selectSwitchOnOption,
|
|
134645
134744
|
selectSwitchOffOption: body.selectSwitchOffOption,
|
|
134646
134745
|
coverSliderDebounceMs: body.coverSliderDebounceMs,
|
|
134746
|
+
fanSliderDebounceMs: body.fanSliderDebounceMs,
|
|
134647
134747
|
updateThrottleMs: body.updateThrottleMs,
|
|
134648
134748
|
disableClimateOnOff: body.disableClimateOnOff,
|
|
134649
134749
|
disableClimateFanControl: body.disableClimateFanControl,
|
|
@@ -135142,6 +135242,7 @@ function configToProfileEntry(config8) {
|
|
|
135142
135242
|
valetudoIdentifier: config8.valetudoIdentifier,
|
|
135143
135243
|
coverSwapOpenClose: config8.coverSwapOpenClose,
|
|
135144
135244
|
coverSliderDebounceMs: config8.coverSliderDebounceMs,
|
|
135245
|
+
fanSliderDebounceMs: config8.fanSliderDebounceMs,
|
|
135145
135246
|
disableClimateOnOff: config8.disableClimateOnOff,
|
|
135146
135247
|
disableClimateFanControl: config8.disableClimateFanControl,
|
|
135147
135248
|
climateKeepModeOnIdle: config8.climateKeepModeOnIdle,
|
|
@@ -135287,6 +135388,7 @@ function mappingProfileApi(mappingStorage) {
|
|
|
135287
135388
|
valetudoIdentifier: entry.valetudoIdentifier,
|
|
135288
135389
|
coverSwapOpenClose: entry.coverSwapOpenClose,
|
|
135289
135390
|
coverSliderDebounceMs: entry.coverSliderDebounceMs,
|
|
135391
|
+
fanSliderDebounceMs: entry.fanSliderDebounceMs,
|
|
135290
135392
|
disableClimateOnOff: entry.disableClimateOnOff,
|
|
135291
135393
|
disableClimateFanControl: entry.disableClimateFanControl,
|
|
135292
135394
|
climateKeepModeOnIdle: entry.climateKeepModeOnIdle,
|
|
@@ -138045,7 +138147,7 @@ var WebSocketApi = class {
|
|
|
138045
138147
|
|
|
138046
138148
|
// src/api/web-api.ts
|
|
138047
138149
|
var WebApi = class extends Service {
|
|
138048
|
-
constructor(
|
|
138150
|
+
constructor(logger255, bridgeService, haClient, haRegistry, bridgeStorage, mappingStorage, identityStorage, lockCredentialStorage, settingsStorage, backupService, props) {
|
|
138049
138151
|
super("WebApi");
|
|
138050
138152
|
this.bridgeService = bridgeService;
|
|
138051
138153
|
this.haClient = haClient;
|
|
@@ -138057,8 +138159,8 @@ var WebApi = class extends Service {
|
|
|
138057
138159
|
this.settingsStorage = settingsStorage;
|
|
138058
138160
|
this.backupService = backupService;
|
|
138059
138161
|
this.props = props;
|
|
138060
|
-
this.logger =
|
|
138061
|
-
this.log =
|
|
138162
|
+
this.logger = logger255;
|
|
138163
|
+
this.log = logger255.get(this);
|
|
138062
138164
|
this.accessLogger = accessLogger(this.log.createChild("Access Log"));
|
|
138063
138165
|
this.startTime = Date.now();
|
|
138064
138166
|
this.wsApi = new WebSocketApi(
|
|
@@ -138479,12 +138581,9 @@ var BetterLogger = class _BetterLogger extends Logger {
|
|
|
138479
138581
|
// src/core/app/mdns.ts
|
|
138480
138582
|
init_esm();
|
|
138481
138583
|
init_esm7();
|
|
138584
|
+
init_protocol3();
|
|
138482
138585
|
import * as os5 from "node:os";
|
|
138483
138586
|
|
|
138484
|
-
// ../../node_modules/.pnpm/@matter+main@0.17.9/node_modules/@matter/main/dist/esm/protocol.js
|
|
138485
|
-
init_nodejs();
|
|
138486
|
-
init_esm4();
|
|
138487
|
-
|
|
138488
138587
|
// src/core/app/filtered-network.ts
|
|
138489
138588
|
init_esm6();
|
|
138490
138589
|
function filterAdvertisedIpv6(ipV6) {
|
|
@@ -139234,6 +139333,7 @@ init_home_assistant_actions();
|
|
|
139234
139333
|
// src/services/home-assistant/home-assistant-client.ts
|
|
139235
139334
|
init_service();
|
|
139236
139335
|
init_retry();
|
|
139336
|
+
init_send_ha_message();
|
|
139237
139337
|
import {
|
|
139238
139338
|
createConnection as createConnection2,
|
|
139239
139339
|
createLongLivedTokenAuth,
|
|
@@ -139259,30 +139359,92 @@ function isTransientConnectError(reason) {
|
|
|
139259
139359
|
return msg.includes("socket hang up") || msg.includes("tls") || msg.includes("TLS");
|
|
139260
139360
|
}
|
|
139261
139361
|
var HomeAssistantClient = class extends Service {
|
|
139262
|
-
constructor(
|
|
139362
|
+
constructor(logger255, options) {
|
|
139263
139363
|
super("HomeAssistantClient");
|
|
139264
139364
|
this.options = options;
|
|
139265
|
-
this.log =
|
|
139365
|
+
this.log = logger255.get(this);
|
|
139266
139366
|
}
|
|
139267
139367
|
options;
|
|
139268
139368
|
static Options = /* @__PURE__ */ Symbol.for("HomeAssistantClientProps");
|
|
139269
139369
|
_connection;
|
|
139270
139370
|
log;
|
|
139371
|
+
_haRunning = false;
|
|
139372
|
+
_runningSince = 0;
|
|
139373
|
+
runningPollGeneration = 0;
|
|
139271
139374
|
get connection() {
|
|
139272
139375
|
return this._connection;
|
|
139273
139376
|
}
|
|
139377
|
+
// False during HA's own startup and after any WS drop, true only once
|
|
139378
|
+
// getConfig reports RUNNING again. Endpoint managers use this to not trust
|
|
139379
|
+
// partial registry snapshots (#438).
|
|
139380
|
+
get haRunning() {
|
|
139381
|
+
return this._haRunning;
|
|
139382
|
+
}
|
|
139383
|
+
// When HA last reached RUNNING. The removal grace has to outlast HA's own
|
|
139384
|
+
// start, so it counts from here, not from wall time (#438).
|
|
139385
|
+
get runningSince() {
|
|
139386
|
+
return this._runningSince;
|
|
139387
|
+
}
|
|
139274
139388
|
get baseUrl() {
|
|
139275
139389
|
return this.options.url;
|
|
139276
139390
|
}
|
|
139277
139391
|
get accessToken() {
|
|
139278
139392
|
return this.options.accessToken;
|
|
139279
139393
|
}
|
|
139394
|
+
get messageTimeoutMs() {
|
|
139395
|
+
return this.options.messageTimeoutMs;
|
|
139396
|
+
}
|
|
139280
139397
|
async initialize() {
|
|
139281
139398
|
this._connection = await this.createConnection(this.options);
|
|
139399
|
+
this.watchRunningState(this._connection);
|
|
139400
|
+
this.setRunning(this._connection.connected ?? true);
|
|
139401
|
+
}
|
|
139402
|
+
setRunning(running) {
|
|
139403
|
+
if (running && !this._haRunning) {
|
|
139404
|
+
this._runningSince = Date.now();
|
|
139405
|
+
}
|
|
139406
|
+
this._haRunning = running;
|
|
139282
139407
|
}
|
|
139283
139408
|
async dispose() {
|
|
139409
|
+
this.runningPollGeneration++;
|
|
139284
139410
|
this.connection?.close();
|
|
139285
139411
|
}
|
|
139412
|
+
// The websocket library reconnects on its own after a drop and nothing
|
|
139413
|
+
// re-checks HA's lifecycle state, so a core restart resumed registry reads
|
|
139414
|
+
// mid-boot (#438). Force false on every drop and only flip back once a
|
|
139415
|
+
// fresh getConfig poll sees RUNNING. The generation counter kills stale
|
|
139416
|
+
// polls from an older reconnect.
|
|
139417
|
+
watchRunningState(connection) {
|
|
139418
|
+
connection.addEventListener("disconnected", () => {
|
|
139419
|
+
this.runningPollGeneration++;
|
|
139420
|
+
this.setRunning(false);
|
|
139421
|
+
});
|
|
139422
|
+
connection.addEventListener("ready", () => {
|
|
139423
|
+
const generation = ++this.runningPollGeneration;
|
|
139424
|
+
this.setRunning(false);
|
|
139425
|
+
this.confirmRunning(connection, generation).catch((e) => {
|
|
139426
|
+
this.log.warnCtx("HA running state check failed", {
|
|
139427
|
+
reason: e instanceof Error ? e.message : String(e)
|
|
139428
|
+
});
|
|
139429
|
+
});
|
|
139430
|
+
});
|
|
139431
|
+
}
|
|
139432
|
+
async confirmRunning(connection, generation) {
|
|
139433
|
+
while (this.runningPollGeneration === generation) {
|
|
139434
|
+
const config8 = await sendHaMessage(
|
|
139435
|
+
connection,
|
|
139436
|
+
{ type: "get_config" },
|
|
139437
|
+
this.options.messageTimeoutMs
|
|
139438
|
+
).catch(() => void 0);
|
|
139439
|
+
if (this.runningPollGeneration !== generation) return;
|
|
139440
|
+
if (config8?.state === "RUNNING") {
|
|
139441
|
+
this.setRunning(true);
|
|
139442
|
+
this.log.infoCtx("Home Assistant is up and running again", {});
|
|
139443
|
+
return;
|
|
139444
|
+
}
|
|
139445
|
+
await new Promise((resolve11) => setTimeout(resolve11, 5e3));
|
|
139446
|
+
}
|
|
139447
|
+
}
|
|
139286
139448
|
async createConnection(props) {
|
|
139287
139449
|
const maxConnectAttempts = 60;
|
|
139288
139450
|
for (let attempt = 1; attempt <= maxConnectAttempts; attempt++) {
|
|
@@ -139466,6 +139628,16 @@ var HomeAssistantRegistry = class extends Service {
|
|
|
139466
139628
|
options;
|
|
139467
139629
|
autoRefresh;
|
|
139468
139630
|
lastRegistryFingerprint = "";
|
|
139631
|
+
// Bumped on every successful reload, even an unchanged one. Endpoint
|
|
139632
|
+
// removal requires a bump between stamp and delete, so a stale cached
|
|
139633
|
+
// snapshot can never confirm a removal (#438).
|
|
139634
|
+
_snapshotGeneration = 0;
|
|
139635
|
+
get snapshotGeneration() {
|
|
139636
|
+
return this._snapshotGeneration;
|
|
139637
|
+
}
|
|
139638
|
+
// Last HA uptime stamp the auto-refresh saw, so a restart between ticks
|
|
139639
|
+
// still drives one reconcile (#438).
|
|
139640
|
+
lastRunningSince = 0;
|
|
139469
139641
|
_devices = {};
|
|
139470
139642
|
get devices() {
|
|
139471
139643
|
return this._devices;
|
|
@@ -139509,8 +139681,11 @@ var HomeAssistantRegistry = class extends Service {
|
|
|
139509
139681
|
}
|
|
139510
139682
|
refreshing = true;
|
|
139511
139683
|
try {
|
|
139684
|
+
const runningSince = this.client.runningSince;
|
|
139685
|
+
const restarted = runningSince !== this.lastRunningSince;
|
|
139512
139686
|
const changed = await this.reload();
|
|
139513
|
-
|
|
139687
|
+
this.lastRunningSince = runningSince;
|
|
139688
|
+
if (changed || restarted) {
|
|
139514
139689
|
await onRefresh();
|
|
139515
139690
|
}
|
|
139516
139691
|
} catch (e) {
|
|
@@ -139573,6 +139748,7 @@ var HomeAssistantRegistry = class extends Service {
|
|
|
139573
139748
|
});
|
|
139574
139749
|
}
|
|
139575
139750
|
async runRegistryQueries() {
|
|
139751
|
+
const trustedAtStart = this.client.haRunning;
|
|
139576
139752
|
const connection = this.client.connection;
|
|
139577
139753
|
const timeoutMs = this.options.messageTimeoutMs;
|
|
139578
139754
|
const [entityRegistry, statesList, deviceRegistry, labels, areas] = await Promise.all([
|
|
@@ -139612,6 +139788,12 @@ var HomeAssistantRegistry = class extends Service {
|
|
|
139612
139788
|
for (const a of areas) hash2.update(`${a.area_id}\0${a.name}
|
|
139613
139789
|
`);
|
|
139614
139790
|
const fingerprint = hash2.digest("hex");
|
|
139791
|
+
if (!trustedAtStart || !this.client.haRunning) {
|
|
139792
|
+
logger183.debug("Discarding registry snapshot, HA was not running");
|
|
139793
|
+
this.lastRegistryFingerprint = "";
|
|
139794
|
+
return false;
|
|
139795
|
+
}
|
|
139796
|
+
this._snapshotGeneration++;
|
|
139615
139797
|
this._states = keyBy(statesList, "entity_id");
|
|
139616
139798
|
if (fingerprint === this.lastRegistryFingerprint) {
|
|
139617
139799
|
logger183.debug("Registry unchanged, skipping full refresh");
|
|
@@ -140103,6 +140285,7 @@ var EntityMappingStorage = class extends Service {
|
|
|
140103
140285
|
selectSwitchOnOption: request.selectSwitchOnOption || void 0,
|
|
140104
140286
|
selectSwitchOffOption: request.selectSwitchOffOption || void 0,
|
|
140105
140287
|
coverSliderDebounceMs: sanitizeDebounceMs(request.coverSliderDebounceMs),
|
|
140288
|
+
fanSliderDebounceMs: sanitizeDebounceMs(request.fanSliderDebounceMs),
|
|
140106
140289
|
updateThrottleMs: sanitizeThrottleMs(request.updateThrottleMs),
|
|
140107
140290
|
disableClimateOnOff: request.disableClimateOnOff || void 0,
|
|
140108
140291
|
disableClimateFanControl: request.disableClimateFanControl || void 0,
|
|
@@ -140112,7 +140295,7 @@ var EntityMappingStorage = class extends Service {
|
|
|
140112
140295
|
composedEntities: request.composedEntities?.filter((e) => e.entityId?.trim()) ?? void 0,
|
|
140113
140296
|
disableMomentaryFlip: request.disableMomentaryFlip || void 0
|
|
140114
140297
|
};
|
|
140115
|
-
if (!config8.matterDeviceType && !config8.customName && !config8.customProductName && !config8.customVendorName && !config8.customSerialNumber && config8.customVendorId === void 0 && config8.disabled !== true && !config8.filterLifeEntity && !config8.cleaningModeEntity && !config8.temperatureEntity && !config8.humidityEntity && !config8.batteryEntity && !config8.disableBatteryMapping && !config8.chargingStateEntity && !config8.roomEntities && !config8.disableLockPin && !config8.lockUsercodeService && config8.lockUsercodeSlot === void 0 && config8.lockPinMinLength === void 0 && config8.lockPinMaxLength === void 0 && !config8.powerEntity && !config8.energyEntity && !config8.meterSerialNumber && !config8.pointOfDelivery && !config8.voltageEntity && !config8.currentEntity && !config8.batteryPowerEntity && !config8.batteryEnergyEntity && !config8.chargingSwitchEntity && !config8.currentLimitEntity && !config8.pressureEntity && !config8.suctionLevelEntity && !config8.mopIntensityEntity && (!config8.customServiceAreas || config8.customServiceAreas.length === 0) && (!config8.customFanSpeedTags || Object.keys(config8.customFanSpeedTags).length === 0) && (!config8.fanWindPresets || (config8.fanWindPresets.natural?.length ?? 0) === 0 && (config8.fanWindPresets.sleep?.length ?? 0) === 0) && !config8.fanRestoreSpeedOnPowerOn && !config8.currentRoomEntity && !config8.cleanedAreaEntity && !config8.vacuumAscendingRoomOrder && !config8.vacuumRoomSwitches && !config8.disableCustomAreaRoomModes && !config8.valetudoIdentifier && !config8.coverSwapOpenClose && !config8.coverExposeAsDimmableLight && !config8.selectExposeAsSwitch && !config8.selectSwitchOnOption && !config8.selectSwitchOffOption && !config8.coverSliderDebounceMs && !config8.updateThrottleMs && !config8.disableClimateOnOff && !config8.disableClimateFanControl && !config8.climateKeepModeOnIdle && !config8.climateExposeFan && !config8.climateAutoMode && (!config8.composedEntities || config8.composedEntities.length === 0) && !config8.disableMomentaryFlip) {
|
|
140298
|
+
if (!config8.matterDeviceType && !config8.customName && !config8.customProductName && !config8.customVendorName && !config8.customSerialNumber && config8.customVendorId === void 0 && config8.disabled !== true && !config8.filterLifeEntity && !config8.cleaningModeEntity && !config8.temperatureEntity && !config8.humidityEntity && !config8.batteryEntity && !config8.disableBatteryMapping && !config8.chargingStateEntity && !config8.roomEntities && !config8.disableLockPin && !config8.lockUsercodeService && config8.lockUsercodeSlot === void 0 && config8.lockPinMinLength === void 0 && config8.lockPinMaxLength === void 0 && !config8.powerEntity && !config8.energyEntity && !config8.meterSerialNumber && !config8.pointOfDelivery && !config8.voltageEntity && !config8.currentEntity && !config8.batteryPowerEntity && !config8.batteryEnergyEntity && !config8.chargingSwitchEntity && !config8.currentLimitEntity && !config8.pressureEntity && !config8.suctionLevelEntity && !config8.mopIntensityEntity && (!config8.customServiceAreas || config8.customServiceAreas.length === 0) && (!config8.customFanSpeedTags || Object.keys(config8.customFanSpeedTags).length === 0) && (!config8.fanWindPresets || (config8.fanWindPresets.natural?.length ?? 0) === 0 && (config8.fanWindPresets.sleep?.length ?? 0) === 0) && !config8.fanRestoreSpeedOnPowerOn && !config8.currentRoomEntity && !config8.cleanedAreaEntity && !config8.vacuumAscendingRoomOrder && !config8.vacuumRoomSwitches && !config8.disableCustomAreaRoomModes && !config8.valetudoIdentifier && !config8.coverSwapOpenClose && !config8.coverExposeAsDimmableLight && !config8.selectExposeAsSwitch && !config8.selectSwitchOnOption && !config8.selectSwitchOffOption && !config8.coverSliderDebounceMs && !config8.fanSliderDebounceMs && !config8.updateThrottleMs && !config8.disableClimateOnOff && !config8.disableClimateFanControl && !config8.climateKeepModeOnIdle && !config8.climateExposeFan && !config8.climateAutoMode && (!config8.composedEntities || config8.composedEntities.length === 0) && !config8.disableMomentaryFlip) {
|
|
140116
140299
|
bridgeMap.delete(request.entityId);
|
|
140117
140300
|
} else {
|
|
140118
140301
|
bridgeMap.set(request.entityId, config8);
|
|
@@ -155038,9 +155221,8 @@ var WindowCoveringDevice = WindowCoveringDeviceDefinition;
|
|
|
155038
155221
|
init_nodejs();
|
|
155039
155222
|
init_esm5();
|
|
155040
155223
|
|
|
155041
|
-
//
|
|
155042
|
-
|
|
155043
|
-
init_esm3();
|
|
155224
|
+
// src/matter/endpoints/server-mode-server-node.ts
|
|
155225
|
+
init_types2();
|
|
155044
155226
|
|
|
155045
155227
|
// src/utils/sanitize-matter-string.ts
|
|
155046
155228
|
function sanitizeMatterString(value) {
|
|
@@ -155224,6 +155406,9 @@ import * as path12 from "node:path";
|
|
|
155224
155406
|
// src/plugins/plugin-device-factory.ts
|
|
155225
155407
|
init_esm();
|
|
155226
155408
|
|
|
155409
|
+
// src/matter/behaviors/identify-server.ts
|
|
155410
|
+
init_esm();
|
|
155411
|
+
|
|
155227
155412
|
// ../../node_modules/.pnpm/@matter+main@0.17.9/node_modules/@matter/main/dist/esm/behaviors.js
|
|
155228
155413
|
init_nodejs();
|
|
155229
155414
|
|
|
@@ -156419,14 +156604,138 @@ init_wi_fi_network_diagnostics2();
|
|
|
156419
156604
|
init_ClientBehavior();
|
|
156420
156605
|
var WiFiNetworkManagementClientConstructor = ClientBehavior(WiFiNetworkManagement3);
|
|
156421
156606
|
|
|
156607
|
+
// ../../node_modules/.pnpm/@matter+main@0.17.9/node_modules/@matter/main/dist/esm/clusters.js
|
|
156608
|
+
init_nodejs();
|
|
156609
|
+
|
|
156610
|
+
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/index.js
|
|
156611
|
+
init_access_control();
|
|
156612
|
+
init_actions();
|
|
156613
|
+
init_administrator_commissioning();
|
|
156614
|
+
|
|
156615
|
+
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/alarm-base.js
|
|
156616
|
+
init_ClusterType();
|
|
156617
|
+
init_esm2();
|
|
156618
|
+
var AlarmBase3 = ClusterType(AlarmBase2);
|
|
156619
|
+
|
|
156620
|
+
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/index.js
|
|
156621
|
+
init_basic_information();
|
|
156622
|
+
init_binding();
|
|
156623
|
+
init_bridged_device_basic_information();
|
|
156624
|
+
init_commissioner_control();
|
|
156625
|
+
|
|
156626
|
+
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/concentration-measurement.js
|
|
156627
|
+
init_ClusterType();
|
|
156628
|
+
init_esm2();
|
|
156629
|
+
var ConcentrationMeasurement3 = ClusterType(ConcentrationMeasurement2);
|
|
156630
|
+
|
|
156631
|
+
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/index.js
|
|
156632
|
+
init_descriptor();
|
|
156633
|
+
init_diagnostic_logs();
|
|
156634
|
+
init_ethernet_network_diagnostics();
|
|
156635
|
+
init_general_commissioning();
|
|
156636
|
+
init_general_diagnostics();
|
|
156637
|
+
init_group_key_management();
|
|
156638
|
+
init_groupcast();
|
|
156639
|
+
init_icd_management();
|
|
156640
|
+
init_identify();
|
|
156641
|
+
|
|
156642
|
+
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/label.js
|
|
156643
|
+
init_ClusterType();
|
|
156644
|
+
init_esm2();
|
|
156645
|
+
var Label3 = ClusterType(Label2);
|
|
156646
|
+
|
|
156647
|
+
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/index.js
|
|
156648
|
+
init_localization_configuration();
|
|
156649
|
+
init_network_commissioning();
|
|
156650
|
+
init_operational_credentials();
|
|
156651
|
+
init_ota_software_update_provider();
|
|
156652
|
+
init_ota_software_update_requestor();
|
|
156653
|
+
init_power_source();
|
|
156654
|
+
init_power_source_configuration();
|
|
156655
|
+
|
|
156656
|
+
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/resource-monitoring.js
|
|
156657
|
+
init_ClusterType();
|
|
156658
|
+
init_esm2();
|
|
156659
|
+
var ResourceMonitoring3 = ClusterType(ResourceMonitoring2);
|
|
156660
|
+
|
|
156661
|
+
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/index.js
|
|
156662
|
+
init_software_diagnostics();
|
|
156663
|
+
init_thread_network_diagnostics();
|
|
156664
|
+
init_time_format_localization();
|
|
156665
|
+
init_time_synchronization();
|
|
156666
|
+
init_tls_certificate_management();
|
|
156667
|
+
init_tls_client_management();
|
|
156668
|
+
init_unit_localization();
|
|
156669
|
+
|
|
156670
|
+
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/web-rtc-transport-definitions.js
|
|
156671
|
+
init_ClusterType();
|
|
156672
|
+
init_esm2();
|
|
156673
|
+
var WebRtcTransportDefinitions3 = ClusterType(WebRtcTransportDefinitions2);
|
|
156674
|
+
|
|
156675
|
+
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/index.js
|
|
156676
|
+
init_wi_fi_network_diagnostics();
|
|
156677
|
+
|
|
156422
156678
|
// src/matter/behaviors/identify-server.ts
|
|
156679
|
+
init_home_assistant_entity_behavior();
|
|
156680
|
+
var logger198 = Logger.get("IdentifyServer");
|
|
156681
|
+
var IDENTIFY_BUTTON_SUFFIXES = ["_identify", "_locate", "_find_me"];
|
|
156423
156682
|
var IdentifyServer2 = class extends IdentifyServer {
|
|
156683
|
+
identify(request) {
|
|
156684
|
+
if (request.identifyTime > 0) {
|
|
156685
|
+
this.identifyInHomeAssistant("identify");
|
|
156686
|
+
}
|
|
156687
|
+
return super.identify(request);
|
|
156688
|
+
}
|
|
156689
|
+
triggerEffect(effect) {
|
|
156690
|
+
if (effect.effectIdentifier !== Identify3.EffectIdentifier.StopEffect && effect.effectIdentifier !== Identify3.EffectIdentifier.FinishEffect) {
|
|
156691
|
+
this.identifyInHomeAssistant("triggerEffect");
|
|
156692
|
+
}
|
|
156693
|
+
return super.triggerEffect(effect);
|
|
156694
|
+
}
|
|
156695
|
+
identifyInHomeAssistant(source) {
|
|
156696
|
+
if (!this.agent.has(HomeAssistantEntityBehavior)) return;
|
|
156697
|
+
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
156698
|
+
const target = this.findIdentifyEntity(homeAssistant);
|
|
156699
|
+
if (!target) {
|
|
156700
|
+
logger198.debug(
|
|
156701
|
+
`${source} for ${homeAssistant.entityId}, no identify entity on this device`
|
|
156702
|
+
);
|
|
156703
|
+
return;
|
|
156704
|
+
}
|
|
156705
|
+
logger198.info(
|
|
156706
|
+
`${source} \u2192 button.press ${target} for ${homeAssistant.entityId}`
|
|
156707
|
+
);
|
|
156708
|
+
homeAssistant.callAction({ action: "button.press", target });
|
|
156709
|
+
}
|
|
156710
|
+
// Searches the FULL registry: an identify button rarely matches the bridge
|
|
156711
|
+
// filter, same reason the battery and problem lookups do it.
|
|
156712
|
+
findIdentifyEntity(homeAssistant) {
|
|
156713
|
+
const deviceId = homeAssistant.entity.registry?.device_id;
|
|
156714
|
+
if (!deviceId) return void 0;
|
|
156715
|
+
const registry3 = this.env.maybeGet(HomeAssistantRegistry);
|
|
156716
|
+
if (!registry3) return void 0;
|
|
156717
|
+
let byName;
|
|
156718
|
+
for (const entity of Object.values(registry3.entities)) {
|
|
156719
|
+
if (entity.device_id !== deviceId) continue;
|
|
156720
|
+
if (entity.disabled_by != null) continue;
|
|
156721
|
+
if (!entity.entity_id.startsWith("button.")) continue;
|
|
156722
|
+
const deviceClass = registry3.states[entity.entity_id]?.attributes?.device_class;
|
|
156723
|
+
if (deviceClass === "identify") return entity.entity_id;
|
|
156724
|
+
const uniqueId = entity.unique_id ?? "";
|
|
156725
|
+
if (byName == null && IDENTIFY_BUTTON_SUFFIXES.some(
|
|
156726
|
+
(s) => entity.entity_id.endsWith(s) || uniqueId.endsWith(s)
|
|
156727
|
+
)) {
|
|
156728
|
+
byName = entity.entity_id;
|
|
156729
|
+
}
|
|
156730
|
+
}
|
|
156731
|
+
return byName;
|
|
156732
|
+
}
|
|
156424
156733
|
};
|
|
156425
156734
|
|
|
156426
156735
|
// src/matter/endpoints/validate-endpoint-type.ts
|
|
156427
156736
|
init_esm();
|
|
156428
156737
|
init_esm7();
|
|
156429
|
-
var
|
|
156738
|
+
var logger199 = Logger.get("EndpointValidation");
|
|
156430
156739
|
function toCamelCase(name) {
|
|
156431
156740
|
return name.charAt(0).toLowerCase() + name.slice(1);
|
|
156432
156741
|
}
|
|
@@ -156456,12 +156765,12 @@ function validateEndpointType(endpointType, entityId) {
|
|
|
156456
156765
|
}
|
|
156457
156766
|
const prefix = entityId ? `[${entityId}] ` : "";
|
|
156458
156767
|
if (missingMandatory.length > 0) {
|
|
156459
|
-
|
|
156768
|
+
logger199.warn(
|
|
156460
156769
|
`${prefix}${deviceTypeModel.name} (0x${endpointType.deviceType.toString(16)}): missing mandatory clusters: ${missingMandatory.join(", ")}`
|
|
156461
156770
|
);
|
|
156462
156771
|
}
|
|
156463
156772
|
if (availableOptional.length > 0) {
|
|
156464
|
-
|
|
156773
|
+
logger199.debug(
|
|
156465
156774
|
`${prefix}${deviceTypeModel.name} (0x${endpointType.deviceType.toString(16)}): optional clusters not used: ${availableOptional.join(", ")}`
|
|
156466
156775
|
);
|
|
156467
156776
|
}
|
|
@@ -156585,7 +156894,7 @@ var BridgeDataProvider = class extends Service {
|
|
|
156585
156894
|
|
|
156586
156895
|
// src/utils/apply-patch-state.ts
|
|
156587
156896
|
init_esm();
|
|
156588
|
-
var
|
|
156897
|
+
var logger200 = Logger.get("ApplyPatchState");
|
|
156589
156898
|
function applyPatchState(state, patch, options) {
|
|
156590
156899
|
return applyPatch(state, patch, options?.force);
|
|
156591
156900
|
}
|
|
@@ -156612,23 +156921,23 @@ function applyPatch(state, patch, force = false) {
|
|
|
156612
156921
|
if (errorMessage.includes(
|
|
156613
156922
|
"Endpoint storage inaccessible because endpoint is not a node and is not owned by another endpoint"
|
|
156614
156923
|
)) {
|
|
156615
|
-
|
|
156924
|
+
logger200.debug(
|
|
156616
156925
|
`Suppressed endpoint storage error, patch not applied: ${JSON.stringify(actualPatch)}`
|
|
156617
156926
|
);
|
|
156618
156927
|
return actualPatch;
|
|
156619
156928
|
}
|
|
156620
156929
|
if (errorMessage.includes("synchronous-transaction-conflict")) {
|
|
156621
|
-
|
|
156930
|
+
logger200.warn(
|
|
156622
156931
|
`Transaction conflict, state update DROPPED: ${JSON.stringify(actualPatch)}`
|
|
156623
156932
|
);
|
|
156624
156933
|
return actualPatch;
|
|
156625
156934
|
}
|
|
156626
156935
|
failedKeys.push(key);
|
|
156627
|
-
|
|
156936
|
+
logger200.warn(`Failed to set property '${key}': ${errorMessage}`);
|
|
156628
156937
|
}
|
|
156629
156938
|
}
|
|
156630
156939
|
if (failedKeys.length > 0) {
|
|
156631
|
-
|
|
156940
|
+
logger200.warn(
|
|
156632
156941
|
`${failedKeys.length} properties failed to update: [${failedKeys.join(", ")}]`
|
|
156633
156942
|
);
|
|
156634
156943
|
}
|
|
@@ -156698,7 +157007,7 @@ function truncate(maxLength, value) {
|
|
|
156698
157007
|
}
|
|
156699
157008
|
|
|
156700
157009
|
// src/plugins/plugin-device-factory.ts
|
|
156701
|
-
var
|
|
157010
|
+
var logger201 = Logger.get("PluginDeviceFactory");
|
|
156702
157011
|
var deviceTypeMap = {
|
|
156703
157012
|
on_off_light: () => OnOffLightDevice.with(
|
|
156704
157013
|
IdentifyServer2,
|
|
@@ -156804,7 +157113,7 @@ var deviceTypeMap = {
|
|
|
156804
157113
|
function createPluginEndpointType(deviceType) {
|
|
156805
157114
|
const factory = deviceTypeMap[deviceType];
|
|
156806
157115
|
if (!factory) {
|
|
156807
|
-
|
|
157116
|
+
logger201.warn(`Unsupported plugin device type: "${deviceType}"`);
|
|
156808
157117
|
return void 0;
|
|
156809
157118
|
}
|
|
156810
157119
|
const endpoint = factory();
|
|
@@ -156817,7 +157126,7 @@ function getSupportedPluginDeviceTypes() {
|
|
|
156817
157126
|
|
|
156818
157127
|
// src/plugins/safe-plugin-runner.ts
|
|
156819
157128
|
init_esm();
|
|
156820
|
-
var
|
|
157129
|
+
var logger202 = Logger.get("SafePluginRunner");
|
|
156821
157130
|
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
156822
157131
|
var CIRCUIT_BREAKER_THRESHOLD = 3;
|
|
156823
157132
|
var SafePluginRunner = class {
|
|
@@ -156850,7 +157159,7 @@ var SafePluginRunner = class {
|
|
|
156850
157159
|
async run(pluginName, operation, fn, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
156851
157160
|
const state = this.getState(pluginName);
|
|
156852
157161
|
if (state.disabled) {
|
|
156853
|
-
|
|
157162
|
+
logger202.debug(
|
|
156854
157163
|
`Plugin "${pluginName}" is disabled (circuit breaker open), skipping ${operation}`
|
|
156855
157164
|
);
|
|
156856
157165
|
return void 0;
|
|
@@ -156868,13 +157177,13 @@ var SafePluginRunner = class {
|
|
|
156868
157177
|
timeout.clear();
|
|
156869
157178
|
state.failures++;
|
|
156870
157179
|
state.lastError = error instanceof Error ? error.message : String(error);
|
|
156871
|
-
|
|
157180
|
+
logger202.error(
|
|
156872
157181
|
`Plugin "${pluginName}" failed during ${operation} (failure ${state.failures}/${CIRCUIT_BREAKER_THRESHOLD}): ${state.lastError}`
|
|
156873
157182
|
);
|
|
156874
157183
|
if (state.failures >= CIRCUIT_BREAKER_THRESHOLD) {
|
|
156875
157184
|
state.disabled = true;
|
|
156876
157185
|
state.disabledAt = Date.now();
|
|
156877
|
-
|
|
157186
|
+
logger202.error(
|
|
156878
157187
|
`Plugin "${pluginName}" DISABLED after ${CIRCUIT_BREAKER_THRESHOLD} consecutive failures. Last error: ${state.lastError}`
|
|
156879
157188
|
);
|
|
156880
157189
|
}
|
|
@@ -156897,7 +157206,7 @@ var SafePluginRunner = class {
|
|
|
156897
157206
|
return result;
|
|
156898
157207
|
} catch (error) {
|
|
156899
157208
|
timeout.clear();
|
|
156900
|
-
|
|
157209
|
+
logger202.error(
|
|
156901
157210
|
`Plugin "${pluginName}" failed during ${operation}: ${error instanceof Error ? error.message : String(error)}`
|
|
156902
157211
|
);
|
|
156903
157212
|
return void 0;
|
|
@@ -156918,13 +157227,13 @@ var SafePluginRunner = class {
|
|
|
156918
157227
|
} catch (error) {
|
|
156919
157228
|
state.failures++;
|
|
156920
157229
|
state.lastError = error instanceof Error ? error.message : String(error);
|
|
156921
|
-
|
|
157230
|
+
logger202.error(
|
|
156922
157231
|
`Plugin "${pluginName}" failed during ${operation} (sync, failure ${state.failures}/${CIRCUIT_BREAKER_THRESHOLD}): ${state.lastError}`
|
|
156923
157232
|
);
|
|
156924
157233
|
if (state.failures >= CIRCUIT_BREAKER_THRESHOLD) {
|
|
156925
157234
|
state.disabled = true;
|
|
156926
157235
|
state.disabledAt = Date.now();
|
|
156927
|
-
|
|
157236
|
+
logger202.error(
|
|
156928
157237
|
`Plugin "${pluginName}" DISABLED after ${CIRCUIT_BREAKER_THRESHOLD} consecutive failures.`
|
|
156929
157238
|
);
|
|
156930
157239
|
}
|
|
@@ -156950,7 +157259,7 @@ var SafePluginRunner = class {
|
|
|
156950
157259
|
};
|
|
156951
157260
|
|
|
156952
157261
|
// src/plugins/plugin-manager.ts
|
|
156953
|
-
var
|
|
157262
|
+
var logger203 = Logger.get("PluginManager");
|
|
156954
157263
|
var PLUGIN_API_VERSION = 1;
|
|
156955
157264
|
var MAX_PLUGIN_DEVICE_ID_LENGTH = 100;
|
|
156956
157265
|
var LEGACY_ENABLED_KEY = "__enabled";
|
|
@@ -157045,7 +157354,7 @@ var PluginManager = class {
|
|
|
157045
157354
|
throw new Error(`Plugin at ${packagePath} package.json missing "main"`);
|
|
157046
157355
|
}
|
|
157047
157356
|
if (manifest.hamhPluginApiVersion != null && manifest.hamhPluginApiVersion !== PLUGIN_API_VERSION) {
|
|
157048
|
-
|
|
157357
|
+
logger203.warn(
|
|
157049
157358
|
`Plugin "${manifest.name}" declares API version ${manifest.hamhPluginApiVersion}, current is ${PLUGIN_API_VERSION}. It may not work correctly.`
|
|
157050
157359
|
);
|
|
157051
157360
|
}
|
|
@@ -157076,7 +157385,7 @@ var PluginManager = class {
|
|
|
157076
157385
|
};
|
|
157077
157386
|
await this.register(plugin, metadata);
|
|
157078
157387
|
} catch (e) {
|
|
157079
|
-
|
|
157388
|
+
logger203.error(`Failed to load external plugin from ${packagePath}:`, e);
|
|
157080
157389
|
throw e;
|
|
157081
157390
|
}
|
|
157082
157391
|
}
|
|
@@ -157101,7 +157410,7 @@ var PluginManager = class {
|
|
|
157101
157410
|
}
|
|
157102
157411
|
if (enabled === false) {
|
|
157103
157412
|
metadata.enabled = false;
|
|
157104
|
-
|
|
157413
|
+
logger203.info(`Plugin "${plugin.name}" stays disabled (persisted)`);
|
|
157105
157414
|
}
|
|
157106
157415
|
const devices = /* @__PURE__ */ new Map();
|
|
157107
157416
|
const pluginLogger = Logger.get(`Plugin:${plugin.name}`);
|
|
@@ -157140,7 +157449,7 @@ var PluginManager = class {
|
|
|
157140
157449
|
}
|
|
157141
157450
|
devices.delete(deviceId);
|
|
157142
157451
|
await this.onDeviceUnregistered?.(plugin.name, deviceId, {
|
|
157143
|
-
keepIdentity:
|
|
157452
|
+
keepIdentity: true
|
|
157144
157453
|
});
|
|
157145
157454
|
pluginLogger.debug(`Unregistered device: ${deviceId}`);
|
|
157146
157455
|
},
|
|
@@ -157189,7 +157498,7 @@ var PluginManager = class {
|
|
|
157189
157498
|
}),
|
|
157190
157499
|
suspending: false
|
|
157191
157500
|
});
|
|
157192
|
-
|
|
157501
|
+
logger203.info(
|
|
157193
157502
|
`Registered plugin: ${plugin.name} v${plugin.version} (${metadata.source})`
|
|
157194
157503
|
);
|
|
157195
157504
|
}
|
|
@@ -157214,13 +157523,13 @@ var PluginManager = class {
|
|
|
157214
157523
|
async startPlugin(name, instance) {
|
|
157215
157524
|
if (!instance.metadata.enabled) return;
|
|
157216
157525
|
if (this.runner.isDisabled(name)) {
|
|
157217
|
-
|
|
157526
|
+
logger203.warn(
|
|
157218
157527
|
`Plugin "${name}" is disabled (circuit breaker), skipping start`
|
|
157219
157528
|
);
|
|
157220
157529
|
instance.metadata.enabled = false;
|
|
157221
157530
|
return;
|
|
157222
157531
|
}
|
|
157223
|
-
|
|
157532
|
+
logger203.info(`Starting plugin: ${name}`);
|
|
157224
157533
|
const epoch = ++instance.epoch;
|
|
157225
157534
|
await this.runner.run(
|
|
157226
157535
|
name,
|
|
@@ -157279,7 +157588,7 @@ var PluginManager = class {
|
|
|
157279
157588
|
storage2.flush();
|
|
157280
157589
|
}
|
|
157281
157590
|
instance.started = false;
|
|
157282
|
-
|
|
157591
|
+
logger203.info(`Plugin "${name}" shut down`);
|
|
157283
157592
|
});
|
|
157284
157593
|
}
|
|
157285
157594
|
this.instances.clear();
|
|
@@ -157375,13 +157684,13 @@ var PluginManager = class {
|
|
|
157375
157684
|
instance.metadata.config = pending;
|
|
157376
157685
|
instance.pendingConfig = void 0;
|
|
157377
157686
|
} catch (e) {
|
|
157378
|
-
|
|
157687
|
+
logger203.warn(
|
|
157379
157688
|
`Failed to persist the parked config for "${pluginName}", it stays parked:`,
|
|
157380
157689
|
e
|
|
157381
157690
|
);
|
|
157382
157691
|
}
|
|
157383
157692
|
}
|
|
157384
|
-
|
|
157693
|
+
logger203.info(`Starting plugin: ${pluginName}`);
|
|
157385
157694
|
const epoch = ++instance.epoch;
|
|
157386
157695
|
await this.runner.run(
|
|
157387
157696
|
pluginName,
|
|
@@ -157414,7 +157723,7 @@ var PluginManager = class {
|
|
|
157414
157723
|
return JSON.parse(fs10.readFileSync(this.stateFile, "utf-8"));
|
|
157415
157724
|
}
|
|
157416
157725
|
} catch (e) {
|
|
157417
|
-
|
|
157726
|
+
logger203.warn(`Failed to read the plugin state file:`, e);
|
|
157418
157727
|
}
|
|
157419
157728
|
return {};
|
|
157420
157729
|
}
|
|
@@ -157425,7 +157734,7 @@ var PluginManager = class {
|
|
|
157425
157734
|
fs10.mkdirSync(path12.dirname(this.stateFile), { recursive: true });
|
|
157426
157735
|
fs10.writeFileSync(this.stateFile, JSON.stringify(state, null, 2));
|
|
157427
157736
|
} catch (e) {
|
|
157428
|
-
|
|
157737
|
+
logger203.warn(
|
|
157429
157738
|
`Failed to persist enabled=${enabled} for "${pluginName}":`,
|
|
157430
157739
|
e
|
|
157431
157740
|
);
|
|
@@ -157459,7 +157768,7 @@ var PluginManager = class {
|
|
|
157459
157768
|
if (instance.plugin.onConfigChanged) {
|
|
157460
157769
|
if (!instance.metadata.enabled) {
|
|
157461
157770
|
instance.pendingConfig = config8;
|
|
157462
|
-
|
|
157771
|
+
logger203.info(
|
|
157463
157772
|
`Plugin "${pluginName}" is disabled, the config applies on enable`
|
|
157464
157773
|
);
|
|
157465
157774
|
} else {
|
|
@@ -157479,6 +157788,7 @@ var PluginManager = class {
|
|
|
157479
157788
|
init_dist();
|
|
157480
157789
|
init_esm7();
|
|
157481
157790
|
import * as os9 from "node:os";
|
|
157791
|
+
init_protocol3();
|
|
157482
157792
|
|
|
157483
157793
|
// src/utils/json/create-bridge-server-config.ts
|
|
157484
157794
|
import crypto5 from "node:crypto";
|
|
@@ -157735,6 +158045,7 @@ var SecondaryNetworkInterfaceEndpointDefinition = MutableEndpoint({
|
|
|
157735
158045
|
Object.freeze(SecondaryNetworkInterfaceEndpointDefinition);
|
|
157736
158046
|
|
|
157737
158047
|
// src/utils/json/create-bridge-server-config.ts
|
|
158048
|
+
init_types2();
|
|
157738
158049
|
function createBridgeServerConfig(data, options) {
|
|
157739
158050
|
return {
|
|
157740
158051
|
type: ServerNode.RootEndpoint,
|
|
@@ -157831,6 +158142,7 @@ async function runMdnsAddressWatchTick(deps) {
|
|
|
157831
158142
|
}
|
|
157832
158143
|
|
|
157833
158144
|
// src/utils/ensure-commissioning-config.ts
|
|
158145
|
+
init_protocol3();
|
|
157834
158146
|
var ServerNodeConfigProvider = class extends CommissioningConfigProvider {
|
|
157835
158147
|
#node;
|
|
157836
158148
|
constructor(node) {
|
|
@@ -157878,6 +158190,10 @@ function deadSessionTimeoutMs(flags2) {
|
|
|
157878
158190
|
return flags2?.fastSessionRecovery ? FAST_DEAD_SESSION_TIMEOUT_MS : DEAD_SESSION_TIMEOUT_MS;
|
|
157879
158191
|
}
|
|
157880
158192
|
var STALE_SESSION_QUIET_WINDOW_MS = 5 * 60 * 1e3;
|
|
158193
|
+
var PRIMING_GRACE_MS = 3e4;
|
|
158194
|
+
function replacedSessionTimeoutMs(flags2) {
|
|
158195
|
+
return Math.max(deadSessionTimeoutMs(flags2), PRIMING_GRACE_MS);
|
|
158196
|
+
}
|
|
157881
158197
|
function staleSessionQuietWindowMs(flags2) {
|
|
157882
158198
|
return flags2?.fastSessionRecovery ? 0 : STALE_SESSION_QUIET_WINDOW_MS;
|
|
157883
158199
|
}
|
|
@@ -158024,11 +158340,11 @@ var AUTO_FORCE_SYNC_INTERVAL_MS = 9e4;
|
|
|
158024
158340
|
var SHUTDOWN_SESSION_CLOSE_TIMEOUT_MS = 2500;
|
|
158025
158341
|
var MDNS_ADDRESS_CHECK_INTERVAL_MS = 6e4;
|
|
158026
158342
|
var Bridge = class {
|
|
158027
|
-
constructor(env,
|
|
158343
|
+
constructor(env, logger255, dataProvider, endpointManager, serverOptions) {
|
|
158028
158344
|
this.dataProvider = dataProvider;
|
|
158029
158345
|
this.endpointManager = endpointManager;
|
|
158030
158346
|
this.serverOptions = serverOptions;
|
|
158031
|
-
this.log =
|
|
158347
|
+
this.log = logger255.get(`Bridge / ${dataProvider.id}`);
|
|
158032
158348
|
this.server = new BridgeServerNode(
|
|
158033
158349
|
env,
|
|
158034
158350
|
this.dataProvider,
|
|
@@ -158486,12 +158802,18 @@ ${e?.toString()}`);
|
|
|
158486
158802
|
for (const s of [...sessionManager.sessions]) {
|
|
158487
158803
|
if (s !== newSession && !s.isClosing && s.peerNodeId === newSession.peerNodeId && s.fabric?.fabricIndex === newSession.fabric?.fabricIndex && s.subscriptions.size === 0) {
|
|
158488
158804
|
this.log.info(
|
|
158489
|
-
`
|
|
158805
|
+
`Session ${s.id} (peer ${s.peerNodeId}, 0 subs) replaced by session ${newSession.id}, closing it once it goes quiet`
|
|
158806
|
+
);
|
|
158807
|
+
const staleId = s.id;
|
|
158808
|
+
const armed = this.staleSessionTimers.get(staleId);
|
|
158809
|
+
if (armed) clearTimeout(armed);
|
|
158810
|
+
this.staleSessionTimers.set(
|
|
158811
|
+
staleId,
|
|
158812
|
+
setTimeout(() => {
|
|
158813
|
+
this.staleSessionTimers.delete(staleId);
|
|
158814
|
+
this.closeStaleSession(staleId, PRIMING_GRACE_MS);
|
|
158815
|
+
}, replacedSessionTimeoutMs(this.dataProvider.featureFlags))
|
|
158490
158816
|
);
|
|
158491
|
-
s.initiateForceClose({
|
|
158492
|
-
cause: new Error("stale session replaced by new session")
|
|
158493
|
-
}).catch(() => {
|
|
158494
|
-
});
|
|
158495
158817
|
}
|
|
158496
158818
|
}
|
|
158497
158819
|
const quietWindowMs = staleSessionQuietWindowMs(
|
|
@@ -158527,6 +158849,11 @@ ${e?.toString()}`);
|
|
|
158527
158849
|
};
|
|
158528
158850
|
this.sessionDeletedHandler = (session) => {
|
|
158529
158851
|
this.sessionStartedAt.delete(session.id);
|
|
158852
|
+
const armed = this.staleSessionTimers.get(session.id);
|
|
158853
|
+
if (armed) {
|
|
158854
|
+
clearTimeout(armed);
|
|
158855
|
+
this.staleSessionTimers.delete(session.id);
|
|
158856
|
+
}
|
|
158530
158857
|
const sessions = [...sessionManager.sessions];
|
|
158531
158858
|
this.log.warn(
|
|
158532
158859
|
`Session closed: id=${session.id} peer=${session.peerNodeId} | remaining sessions=${sessions.length}`
|
|
@@ -158625,7 +158952,7 @@ ${e?.toString()}`);
|
|
|
158625
158952
|
);
|
|
158626
158953
|
});
|
|
158627
158954
|
}
|
|
158628
|
-
closeStaleSession(sessionId) {
|
|
158955
|
+
closeStaleSession(sessionId, minQuietMs = 0) {
|
|
158629
158956
|
try {
|
|
158630
158957
|
const sessionManager = this.server.env.get(SessionManager);
|
|
158631
158958
|
for (const s of [...sessionManager.sessions]) {
|
|
@@ -158635,7 +158962,10 @@ ${e?.toString()}`);
|
|
|
158635
158962
|
const idleSec = Math.round((Date.now() - s.timestamp) / 1e3);
|
|
158636
158963
|
if (!staleSessionShouldClose(
|
|
158637
158964
|
s,
|
|
158638
|
-
|
|
158965
|
+
Math.max(
|
|
158966
|
+
staleSessionQuietWindowMs(this.dataProvider.featureFlags),
|
|
158967
|
+
minQuietMs
|
|
158968
|
+
)
|
|
158639
158969
|
)) {
|
|
158640
158970
|
this.log.info(
|
|
158641
158971
|
`Keeping session ${s.id} (peer ${s.peerNodeId}, 0 subs, last traffic ${idleSec}s ago)`
|
|
@@ -158644,7 +158974,7 @@ ${e?.toString()}`);
|
|
|
158644
158974
|
sessionId,
|
|
158645
158975
|
setTimeout(() => {
|
|
158646
158976
|
this.staleSessionTimers.delete(sessionId);
|
|
158647
|
-
this.closeStaleSession(sessionId);
|
|
158977
|
+
this.closeStaleSession(sessionId, minQuietMs);
|
|
158648
158978
|
}, deadSessionTimeoutMs(this.dataProvider.featureFlags))
|
|
158649
158979
|
);
|
|
158650
158980
|
break;
|
|
@@ -158673,6 +159003,9 @@ ${e?.toString()}`);
|
|
|
158673
159003
|
if (s.isClosing || s.subscriptions.size > 0) {
|
|
158674
159004
|
continue;
|
|
158675
159005
|
}
|
|
159006
|
+
if (this.staleSessionTimers.has(s.id)) {
|
|
159007
|
+
continue;
|
|
159008
|
+
}
|
|
158676
159009
|
const idleSec = Math.round((Date.now() - s.timestamp) / 1e3);
|
|
158677
159010
|
if (!staleSessionShouldClose(
|
|
158678
159011
|
s,
|
|
@@ -159315,77 +159648,6 @@ var EntityStateProvider = class extends Service {
|
|
|
159315
159648
|
}
|
|
159316
159649
|
};
|
|
159317
159650
|
|
|
159318
|
-
// ../../node_modules/.pnpm/@matter+main@0.17.9/node_modules/@matter/main/dist/esm/clusters.js
|
|
159319
|
-
init_nodejs();
|
|
159320
|
-
|
|
159321
|
-
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/index.js
|
|
159322
|
-
init_access_control();
|
|
159323
|
-
init_actions();
|
|
159324
|
-
init_administrator_commissioning();
|
|
159325
|
-
|
|
159326
|
-
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/alarm-base.js
|
|
159327
|
-
init_ClusterType();
|
|
159328
|
-
init_esm2();
|
|
159329
|
-
var AlarmBase3 = ClusterType(AlarmBase2);
|
|
159330
|
-
|
|
159331
|
-
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/index.js
|
|
159332
|
-
init_basic_information();
|
|
159333
|
-
init_binding();
|
|
159334
|
-
init_bridged_device_basic_information();
|
|
159335
|
-
init_commissioner_control();
|
|
159336
|
-
|
|
159337
|
-
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/concentration-measurement.js
|
|
159338
|
-
init_ClusterType();
|
|
159339
|
-
init_esm2();
|
|
159340
|
-
var ConcentrationMeasurement3 = ClusterType(ConcentrationMeasurement2);
|
|
159341
|
-
|
|
159342
|
-
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/index.js
|
|
159343
|
-
init_descriptor();
|
|
159344
|
-
init_diagnostic_logs();
|
|
159345
|
-
init_ethernet_network_diagnostics();
|
|
159346
|
-
init_general_commissioning();
|
|
159347
|
-
init_general_diagnostics();
|
|
159348
|
-
init_group_key_management();
|
|
159349
|
-
init_groupcast();
|
|
159350
|
-
init_icd_management();
|
|
159351
|
-
init_identify();
|
|
159352
|
-
|
|
159353
|
-
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/label.js
|
|
159354
|
-
init_ClusterType();
|
|
159355
|
-
init_esm2();
|
|
159356
|
-
var Label3 = ClusterType(Label2);
|
|
159357
|
-
|
|
159358
|
-
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/index.js
|
|
159359
|
-
init_localization_configuration();
|
|
159360
|
-
init_network_commissioning();
|
|
159361
|
-
init_operational_credentials();
|
|
159362
|
-
init_ota_software_update_provider();
|
|
159363
|
-
init_ota_software_update_requestor();
|
|
159364
|
-
init_power_source();
|
|
159365
|
-
init_power_source_configuration();
|
|
159366
|
-
|
|
159367
|
-
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/resource-monitoring.js
|
|
159368
|
-
init_ClusterType();
|
|
159369
|
-
init_esm2();
|
|
159370
|
-
var ResourceMonitoring3 = ClusterType(ResourceMonitoring2);
|
|
159371
|
-
|
|
159372
|
-
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/index.js
|
|
159373
|
-
init_software_diagnostics();
|
|
159374
|
-
init_thread_network_diagnostics();
|
|
159375
|
-
init_time_format_localization();
|
|
159376
|
-
init_time_synchronization();
|
|
159377
|
-
init_tls_certificate_management();
|
|
159378
|
-
init_tls_client_management();
|
|
159379
|
-
init_unit_localization();
|
|
159380
|
-
|
|
159381
|
-
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/web-rtc-transport-definitions.js
|
|
159382
|
-
init_ClusterType();
|
|
159383
|
-
init_esm2();
|
|
159384
|
-
var WebRtcTransportDefinitions3 = ClusterType(WebRtcTransportDefinitions2);
|
|
159385
|
-
|
|
159386
|
-
// ../../node_modules/.pnpm/@matter+types@0.17.9/node_modules/@matter/types/dist/esm/clusters/index.js
|
|
159387
|
-
init_wi_fi_network_diagnostics();
|
|
159388
|
-
|
|
159389
159651
|
// src/utils/converters/fan-mode.ts
|
|
159390
159652
|
var FanMode = class _FanMode {
|
|
159391
159653
|
constructor(mode, sequence) {
|
|
@@ -159574,7 +159836,7 @@ init_esm();
|
|
|
159574
159836
|
init_esm7();
|
|
159575
159837
|
import crypto6 from "node:crypto";
|
|
159576
159838
|
init_home_assistant_entity_behavior();
|
|
159577
|
-
var
|
|
159839
|
+
var logger204 = Logger.get("BasicInformationServer");
|
|
159578
159840
|
var appliedUniqueIds = /* @__PURE__ */ new Map();
|
|
159579
159841
|
var BasicInformationServer2 = class extends BridgedDeviceBasicInformationServer {
|
|
159580
159842
|
async initialize() {
|
|
@@ -159620,7 +159882,7 @@ var BasicInformationServer2 = class extends BridgedDeviceBasicInformationServer
|
|
|
159620
159882
|
// records keyed on it can be shed (#385).
|
|
159621
159883
|
uniqueId: this.frozenUniqueId(anchor)
|
|
159622
159884
|
});
|
|
159623
|
-
|
|
159885
|
+
logger204.debug(
|
|
159624
159886
|
`[${entity.entity_id}] basicInfo vendor=${this.state.vendorName} product=${this.state.productName} label=${this.state.productLabel} serial=${this.state.serialNumber} node=${this.state.nodeLabel} uniqueId=${this.state.uniqueId}`
|
|
159625
159887
|
);
|
|
159626
159888
|
}
|
|
@@ -159650,7 +159912,7 @@ function isValidVendorId(value) {
|
|
|
159650
159912
|
// src/matter/behaviors/electrical-energy-measurement-server.ts
|
|
159651
159913
|
init_esm();
|
|
159652
159914
|
init_home_assistant_entity_behavior();
|
|
159653
|
-
var
|
|
159915
|
+
var logger205 = Logger.get("ElectricalEnergyMeasurementServer");
|
|
159654
159916
|
var FeaturedBase = ElectricalEnergyMeasurementServer.with("CumulativeEnergy", "ImportedEnergy");
|
|
159655
159917
|
var ElectricalEnergyMeasurementServerBase = class extends FeaturedBase {
|
|
159656
159918
|
async initialize() {
|
|
@@ -159659,7 +159921,7 @@ var ElectricalEnergyMeasurementServerBase = class extends FeaturedBase {
|
|
|
159659
159921
|
const entityId = homeAssistant.entityId;
|
|
159660
159922
|
const energyEntity = homeAssistant.state.mapping?.energyEntity;
|
|
159661
159923
|
if (energyEntity) {
|
|
159662
|
-
|
|
159924
|
+
logger205.debug(
|
|
159663
159925
|
`[${entityId}] ElectricalEnergyMeasurement using mapped energy entity: ${energyEntity}`
|
|
159664
159926
|
);
|
|
159665
159927
|
}
|
|
@@ -159715,7 +159977,7 @@ var HaElectricalEnergyMeasurementServer = ElectricalEnergyMeasurementServerBase.
|
|
|
159715
159977
|
// src/matter/behaviors/electrical-power-measurement-server.ts
|
|
159716
159978
|
init_esm();
|
|
159717
159979
|
init_home_assistant_entity_behavior();
|
|
159718
|
-
var
|
|
159980
|
+
var logger206 = Logger.get("ElectricalPowerMeasurementServer");
|
|
159719
159981
|
var FeaturedBase2 = ElectricalPowerMeasurementServer.with("AlternatingCurrent");
|
|
159720
159982
|
var ElectricalPowerMeasurementServerBase = class extends FeaturedBase2 {
|
|
159721
159983
|
async initialize() {
|
|
@@ -159724,7 +159986,7 @@ var ElectricalPowerMeasurementServerBase = class extends FeaturedBase2 {
|
|
|
159724
159986
|
const entityId = homeAssistant.entityId;
|
|
159725
159987
|
const powerEntity = homeAssistant.state.mapping?.powerEntity;
|
|
159726
159988
|
if (powerEntity) {
|
|
159727
|
-
|
|
159989
|
+
logger206.debug(
|
|
159728
159990
|
`[${entityId}] ElectricalPowerMeasurement using mapped power entity: ${powerEntity}`
|
|
159729
159991
|
);
|
|
159730
159992
|
}
|
|
@@ -159863,7 +160125,7 @@ init_home_assistant_entity_behavior();
|
|
|
159863
160125
|
// src/matter/behaviors/humidity-measurement-server.ts
|
|
159864
160126
|
init_esm();
|
|
159865
160127
|
init_home_assistant_entity_behavior();
|
|
159866
|
-
var
|
|
160128
|
+
var logger207 = Logger.get("HumidityMeasurementServer");
|
|
159867
160129
|
var HumidityMeasurementServerBase = class extends RelativeHumidityMeasurementServer {
|
|
159868
160130
|
async initialize() {
|
|
159869
160131
|
await super.initialize();
|
|
@@ -159876,7 +160138,7 @@ var HumidityMeasurementServerBase = class extends RelativeHumidityMeasurementSer
|
|
|
159876
160138
|
return;
|
|
159877
160139
|
}
|
|
159878
160140
|
const humidity = this.getHumidity(this.state.config, entity.state);
|
|
159879
|
-
|
|
160141
|
+
logger207.debug(
|
|
159880
160142
|
`Humidity ${entity.state.entity_id} raw=${entity.state.state} measuredValue=${humidity}`
|
|
159881
160143
|
);
|
|
159882
160144
|
applyPatchState(this.state, {
|
|
@@ -159906,7 +160168,7 @@ function HumidityMeasurementServer(config8) {
|
|
|
159906
160168
|
// src/matter/behaviors/power-source-server.ts
|
|
159907
160169
|
init_esm();
|
|
159908
160170
|
init_home_assistant_entity_behavior();
|
|
159909
|
-
var
|
|
160171
|
+
var logger208 = Logger.get("PowerSourceServer");
|
|
159910
160172
|
var FeaturedBase3 = PowerSourceServer.with("Battery", "Rechargeable");
|
|
159911
160173
|
var PowerSourceServerBase = class extends FeaturedBase3 {
|
|
159912
160174
|
async initialize() {
|
|
@@ -159918,17 +160180,17 @@ var PowerSourceServerBase = class extends FeaturedBase3 {
|
|
|
159918
160180
|
applyPatchState(this.state, {
|
|
159919
160181
|
endpointList: [endpointNumber]
|
|
159920
160182
|
});
|
|
159921
|
-
|
|
160183
|
+
logger208.debug(
|
|
159922
160184
|
`[${entityId}] PowerSource initialized with endpointList=[${endpointNumber}]`
|
|
159923
160185
|
);
|
|
159924
160186
|
} else {
|
|
159925
|
-
|
|
160187
|
+
logger208.warn(
|
|
159926
160188
|
`[${entityId}] PowerSource endpoint number is null during initialize - endpointList will be empty!`
|
|
159927
160189
|
);
|
|
159928
160190
|
}
|
|
159929
160191
|
const batteryEntity = homeAssistant.state.mapping?.batteryEntity;
|
|
159930
160192
|
if (batteryEntity) {
|
|
159931
|
-
|
|
160193
|
+
logger208.debug(
|
|
159932
160194
|
`[${entityId}] PowerSource using mapped battery entity: ${batteryEntity}`
|
|
159933
160195
|
);
|
|
159934
160196
|
}
|
|
@@ -160143,6 +160405,7 @@ init_dist();
|
|
|
160143
160405
|
|
|
160144
160406
|
// src/matter/behaviors/fan-control-server.ts
|
|
160145
160407
|
init_esm();
|
|
160408
|
+
init_home_assistant_actions();
|
|
160146
160409
|
|
|
160147
160410
|
// src/utils/converters/fan-mode-order.ts
|
|
160148
160411
|
var SPEED_RANK = {
|
|
@@ -160181,26 +160444,36 @@ var SPEED_RANK = {
|
|
|
160181
160444
|
boost: 7,
|
|
160182
160445
|
jet: 7
|
|
160183
160446
|
};
|
|
160184
|
-
function
|
|
160185
|
-
|
|
160186
|
-
|
|
160187
|
-
|
|
160188
|
-
|
|
160447
|
+
function speedTokenKey(token) {
|
|
160448
|
+
return token.toLowerCase().replace(/[ _-]/g, "");
|
|
160449
|
+
}
|
|
160450
|
+
function speedNumericValue(token) {
|
|
160451
|
+
const key = speedTokenKey(token).replace(/%$/, "");
|
|
160189
160452
|
const level = key.match(/^level(\d+)$/);
|
|
160190
160453
|
if (level) {
|
|
160191
160454
|
return Number(level[1]);
|
|
160192
160455
|
}
|
|
160193
|
-
|
|
160194
|
-
|
|
160195
|
-
|
|
160196
|
-
return
|
|
160456
|
+
return /^\d+$/.test(key) ? Number(key) : void 0;
|
|
160457
|
+
}
|
|
160458
|
+
function rankOf(token) {
|
|
160459
|
+
return SPEED_RANK[speedTokenKey(token)];
|
|
160460
|
+
}
|
|
160461
|
+
function sortByRank(presets, ranks) {
|
|
160462
|
+
return presets.map((value, index) => ({ value, index, rank: ranks[index] })).sort((a, b) => a.rank - b.rank || a.index - b.index).map((entry) => entry.value);
|
|
160197
160463
|
}
|
|
160198
160464
|
function toAscendingSpeedPresets(presets) {
|
|
160465
|
+
const numerics = presets.map(speedNumericValue);
|
|
160466
|
+
if (numerics.every((value) => value !== void 0)) {
|
|
160467
|
+
return sortByRank(presets, numerics);
|
|
160468
|
+
}
|
|
160469
|
+
if (numerics.some((value) => value !== void 0)) {
|
|
160470
|
+
return presets.slice();
|
|
160471
|
+
}
|
|
160199
160472
|
const ranks = presets.map(rankOf);
|
|
160200
160473
|
if (ranks.some((rank) => rank === void 0)) {
|
|
160201
160474
|
return presets.slice();
|
|
160202
160475
|
}
|
|
160203
|
-
return presets
|
|
160476
|
+
return sortByRank(presets, ranks);
|
|
160204
160477
|
}
|
|
160205
160478
|
function percentToPresetIndex(percentage, count) {
|
|
160206
160479
|
if (count <= 0) {
|
|
@@ -160238,12 +160511,8 @@ var FanSpeed = class _FanSpeed {
|
|
|
160238
160511
|
}
|
|
160239
160512
|
};
|
|
160240
160513
|
|
|
160241
|
-
// src/utils/transaction-is-offline.ts
|
|
160242
|
-
function transactionIsOffline(context) {
|
|
160243
|
-
return !context || hasLocalActor(context);
|
|
160244
|
-
}
|
|
160245
|
-
|
|
160246
160514
|
// src/matter/behaviors/fan-control-server.ts
|
|
160515
|
+
init_transaction_is_offline();
|
|
160247
160516
|
init_home_assistant_entity_behavior();
|
|
160248
160517
|
|
|
160249
160518
|
// src/matter/behaviors/on-off-server.ts
|
|
@@ -160297,7 +160566,7 @@ function notifyLightTurnedOff(entityId, haLastChanged) {
|
|
|
160297
160566
|
sweepLastTurnOff(now);
|
|
160298
160567
|
lastTurnOffTimestamps.set(entityId, { ts: now, haLastChanged });
|
|
160299
160568
|
}
|
|
160300
|
-
var
|
|
160569
|
+
var logger209 = Logger.get("LevelControlServer");
|
|
160301
160570
|
var FeaturedBase5 = LevelControlServer.with("OnOff", "Lighting");
|
|
160302
160571
|
var LevelControlServerBase = class extends FeaturedBase5 {
|
|
160303
160572
|
pendingTransitionTime;
|
|
@@ -160315,7 +160584,7 @@ var LevelControlServerBase = class extends FeaturedBase5 {
|
|
|
160315
160584
|
try {
|
|
160316
160585
|
await super.initialize();
|
|
160317
160586
|
} catch (error) {
|
|
160318
|
-
|
|
160587
|
+
logger209.error("super.initialize() failed:", error);
|
|
160319
160588
|
throw error;
|
|
160320
160589
|
}
|
|
160321
160590
|
const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
|
|
@@ -160433,7 +160702,7 @@ var LevelControlServerBase = class extends FeaturedBase5 {
|
|
|
160433
160702
|
expectedLevel: remembered,
|
|
160434
160703
|
timestamp: now2
|
|
160435
160704
|
});
|
|
160436
|
-
|
|
160705
|
+
logger209.debug(
|
|
160437
160706
|
`[${entityId}] Storing level ${level} without calling HA - moveToLevel arrived ${sinceTurnOff}ms after a Matter off while still off (#434)`
|
|
160438
160707
|
);
|
|
160439
160708
|
return;
|
|
@@ -160444,7 +160713,7 @@ var LevelControlServerBase = class extends FeaturedBase5 {
|
|
|
160444
160713
|
const lastTurnOn = lastTurnOnTimestamps.get(entityId);
|
|
160445
160714
|
const timeSinceTurnOn = lastTurnOn ? Date.now() - lastTurnOn : Infinity;
|
|
160446
160715
|
if (level >= this.maxLevel && timeSinceTurnOn < 200) {
|
|
160447
|
-
|
|
160716
|
+
logger209.debug(
|
|
160448
160717
|
`[${entityId}] Ignoring moveToLevel(${level}) - Alexa brightness reset detected (${timeSinceTurnOn}ms after turn-on)`
|
|
160449
160718
|
);
|
|
160450
160719
|
return;
|
|
@@ -160490,7 +160759,7 @@ function LevelControlServer2(config8) {
|
|
|
160490
160759
|
}
|
|
160491
160760
|
|
|
160492
160761
|
// src/matter/behaviors/on-off-server.ts
|
|
160493
|
-
var
|
|
160762
|
+
var logger210 = Logger.get("OnOffServer");
|
|
160494
160763
|
var optimisticOnOffState = /* @__PURE__ */ new Map();
|
|
160495
160764
|
var OPTIMISTIC_TIMEOUT_MS2 = 3e3;
|
|
160496
160765
|
function sweepOptimisticOnOff(now) {
|
|
@@ -160554,7 +160823,7 @@ var OnOffServerBase = class extends OnOffServer {
|
|
|
160554
160823
|
if (!action) {
|
|
160555
160824
|
return;
|
|
160556
160825
|
}
|
|
160557
|
-
|
|
160826
|
+
logger210.info(`[${homeAssistant.entityId}] Turning ON -> ${action.action}`);
|
|
160558
160827
|
notifyLightTurnedOn(homeAssistant.entityId);
|
|
160559
160828
|
if (!skipMomentaryFlip) {
|
|
160560
160829
|
const now = Date.now();
|
|
@@ -160585,7 +160854,7 @@ var OnOffServerBase = class extends OnOffServer {
|
|
|
160585
160854
|
if (!action) {
|
|
160586
160855
|
return;
|
|
160587
160856
|
}
|
|
160588
|
-
|
|
160857
|
+
logger210.info(`[${homeAssistant.entityId}] Turning OFF -> ${action.action}`);
|
|
160589
160858
|
const now = Date.now();
|
|
160590
160859
|
sweepOptimisticOnOff(now);
|
|
160591
160860
|
optimisticOnOffState.set(homeAssistant.entityId, {
|
|
@@ -160619,10 +160888,26 @@ function setOptimisticOnOff(entityId, expectedOnOff) {
|
|
|
160619
160888
|
}
|
|
160620
160889
|
|
|
160621
160890
|
// src/matter/behaviors/fan-control-server.ts
|
|
160622
|
-
var
|
|
160891
|
+
var logger211 = Logger.get("FanControlServer");
|
|
160623
160892
|
var defaultStepSize = 33.33;
|
|
160624
160893
|
var minSpeedMax = 3;
|
|
160625
160894
|
var maxSpeedMax = 100;
|
|
160895
|
+
var fanDebounce = /* @__PURE__ */ new WeakMap();
|
|
160896
|
+
function getFanDebounce(endpoint) {
|
|
160897
|
+
let st = fanDebounce.get(endpoint);
|
|
160898
|
+
if (!st) {
|
|
160899
|
+
st = { timer: null, pending: null };
|
|
160900
|
+
fanDebounce.set(endpoint, st);
|
|
160901
|
+
}
|
|
160902
|
+
return st;
|
|
160903
|
+
}
|
|
160904
|
+
function clearFanDebounce(st) {
|
|
160905
|
+
if (st.timer) {
|
|
160906
|
+
clearTimeout(st.timer);
|
|
160907
|
+
st.timer = null;
|
|
160908
|
+
}
|
|
160909
|
+
st.pending = null;
|
|
160910
|
+
}
|
|
160626
160911
|
var FeaturedBase6 = FanControlServer.with(
|
|
160627
160912
|
"Step",
|
|
160628
160913
|
"MultiSpeed",
|
|
@@ -160653,6 +160938,14 @@ var FanControlServerBase = class extends FeaturedBase6 {
|
|
|
160653
160938
|
auto: this.lastIsAutoMode
|
|
160654
160939
|
};
|
|
160655
160940
|
}
|
|
160941
|
+
async [Symbol.asyncDispose]() {
|
|
160942
|
+
const st = fanDebounce.get(this.endpoint);
|
|
160943
|
+
if (st) {
|
|
160944
|
+
clearFanDebounce(st);
|
|
160945
|
+
fanDebounce.delete(this.endpoint);
|
|
160946
|
+
}
|
|
160947
|
+
await super[Symbol.asyncDispose]();
|
|
160948
|
+
}
|
|
160656
160949
|
async initialize() {
|
|
160657
160950
|
if (this.state.fanModeSequence == null) {
|
|
160658
160951
|
this.state.fanModeSequence = this.features.auto ? FanControl3.FanModeSequence.OffLowMedHighAuto : FanControl3.FanModeSequence.OffLowMedHigh;
|
|
@@ -160814,7 +161107,7 @@ var FanControlServerBase = class extends FeaturedBase6 {
|
|
|
160814
161107
|
if (!homeAssistant.isAvailable) {
|
|
160815
161108
|
return;
|
|
160816
161109
|
}
|
|
160817
|
-
this.
|
|
161110
|
+
this.syncOnOffFromSpeed(percentSetting !== 0);
|
|
160818
161111
|
if (percentSetting === 0) {
|
|
160819
161112
|
homeAssistant.callAction(this.state.config.turnOff(void 0, this.agent));
|
|
160820
161113
|
} else {
|
|
@@ -160859,7 +161152,7 @@ var FanControlServerBase = class extends FeaturedBase6 {
|
|
|
160859
161152
|
}
|
|
160860
161153
|
const targetFanMode = FanMode.create(fanMode, this.state.fanModeSequence);
|
|
160861
161154
|
if (targetFanMode.mode === FanControl3.FanMode.Auto) {
|
|
160862
|
-
this.
|
|
161155
|
+
this.syncOnOffFromSpeed(true);
|
|
160863
161156
|
homeAssistant.callAction(
|
|
160864
161157
|
this.state.config.setAutoMode(void 0, this.agent)
|
|
160865
161158
|
);
|
|
@@ -160879,6 +161172,53 @@ var FanControlServerBase = class extends FeaturedBase6 {
|
|
|
160879
161172
|
this.applyPercentageAction(percentage);
|
|
160880
161173
|
});
|
|
160881
161174
|
}
|
|
161175
|
+
// Per-entity override wins over the per-bridge flag; both must be > 0 to
|
|
161176
|
+
// count. Mirrors WindowCoveringServerBase.resolveDebounceOverride.
|
|
161177
|
+
resolveFanDebounceMs(homeAssistant) {
|
|
161178
|
+
const fromEntity = homeAssistant.state.mapping?.fanSliderDebounceMs;
|
|
161179
|
+
if (typeof fromEntity === "number" && fromEntity > 0) {
|
|
161180
|
+
return fromEntity;
|
|
161181
|
+
}
|
|
161182
|
+
const fromBridge = this.env.get(BridgeDataProvider).featureFlags?.fanSliderDebounceMs;
|
|
161183
|
+
if (typeof fromBridge === "number" && fromBridge > 0) {
|
|
161184
|
+
return fromBridge;
|
|
161185
|
+
}
|
|
161186
|
+
return null;
|
|
161187
|
+
}
|
|
161188
|
+
// Send a speed-derived action, or park it in the debounce window so only the
|
|
161189
|
+
// last write of a burst reaches HA. Cluster state was already updated per
|
|
161190
|
+
// write, so the controller sees immediate feedback either way. With no
|
|
161191
|
+
// window configured this is a plain callAction, the historic path.
|
|
161192
|
+
dispatchSpeedAction(homeAssistant, action) {
|
|
161193
|
+
const debounceMs = this.resolveFanDebounceMs(homeAssistant);
|
|
161194
|
+
if (debounceMs == null) {
|
|
161195
|
+
homeAssistant.callAction(action);
|
|
161196
|
+
return;
|
|
161197
|
+
}
|
|
161198
|
+
homeAssistant.assertAvailable();
|
|
161199
|
+
const entityId = homeAssistant.entityId;
|
|
161200
|
+
const actions = this.env.get(HomeAssistantActions);
|
|
161201
|
+
const st = getFanDebounce(this.endpoint);
|
|
161202
|
+
st.pending = { action, entityId, actions };
|
|
161203
|
+
if (st.timer) {
|
|
161204
|
+
clearTimeout(st.timer);
|
|
161205
|
+
}
|
|
161206
|
+
st.timer = setTimeout(() => {
|
|
161207
|
+
st.timer = null;
|
|
161208
|
+
const pending = st.pending;
|
|
161209
|
+
st.pending = null;
|
|
161210
|
+
if (pending) {
|
|
161211
|
+
pending.actions.call(pending.action, pending.entityId);
|
|
161212
|
+
}
|
|
161213
|
+
}, debounceMs);
|
|
161214
|
+
}
|
|
161215
|
+
// Devices whose fan cannot stop (air conditioners) opt out of driving OnOff
|
|
161216
|
+
// from speed: speed zero is a speed change, not a power change (#442).
|
|
161217
|
+
syncOnOffFromSpeed(on) {
|
|
161218
|
+
if (this.state.config.syncOnOffWithSpeed !== false) {
|
|
161219
|
+
this.syncOnOff(on);
|
|
161220
|
+
}
|
|
161221
|
+
}
|
|
160882
161222
|
applyPercentageAction(percentage) {
|
|
160883
161223
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
160884
161224
|
if (!homeAssistant.isAvailable) {
|
|
@@ -160888,7 +161228,7 @@ var FanControlServerBase = class extends FeaturedBase6 {
|
|
|
160888
161228
|
const wasOff = homeAssistant.entity.state?.state === "off" || this.agent.has(OnOffBehavior) && !this.agent.get(OnOffBehavior).state.onOff;
|
|
160889
161229
|
const remembered = this.remembered();
|
|
160890
161230
|
if (wasOff) {
|
|
160891
|
-
|
|
161231
|
+
logger211.debug(
|
|
160892
161232
|
`[${homeAssistant.entityId}] power-on write ${percentage}%: restore flag=${restoreOnPowerOn}, last speed=${remembered.percent}`
|
|
160893
161233
|
);
|
|
160894
161234
|
}
|
|
@@ -160911,9 +161251,12 @@ var FanControlServerBase = class extends FeaturedBase6 {
|
|
|
160911
161251
|
homeAssistant.entity.state,
|
|
160912
161252
|
this.agent
|
|
160913
161253
|
);
|
|
160914
|
-
this.
|
|
161254
|
+
this.syncOnOffFromSpeed(percentage !== 0);
|
|
160915
161255
|
if (percentage === 0) {
|
|
160916
|
-
|
|
161256
|
+
this.dispatchSpeedAction(
|
|
161257
|
+
homeAssistant,
|
|
161258
|
+
config8.turnOff(void 0, this.agent)
|
|
161259
|
+
);
|
|
160917
161260
|
} else if (supportsPercentage) {
|
|
160918
161261
|
const stepSize = config8.getStepSize(
|
|
160919
161262
|
homeAssistant.entity.state,
|
|
@@ -160924,7 +161267,10 @@ var FanControlServerBase = class extends FeaturedBase6 {
|
|
|
160924
161267
|
stepSize ?? 1,
|
|
160925
161268
|
Math.min(100, roundedPercentage)
|
|
160926
161269
|
);
|
|
160927
|
-
|
|
161270
|
+
this.dispatchSpeedAction(
|
|
161271
|
+
homeAssistant,
|
|
161272
|
+
config8.turnOn(clampedPercentage, this.agent)
|
|
161273
|
+
);
|
|
160928
161274
|
this.rememberSpeed(clampedPercentage);
|
|
160929
161275
|
} else {
|
|
160930
161276
|
const presetModes = config8.getPresetModes(homeAssistant.entity.state, this.agent) ?? [];
|
|
@@ -160937,7 +161283,8 @@ var FanControlServerBase = class extends FeaturedBase6 {
|
|
|
160937
161283
|
speedPresets.length
|
|
160938
161284
|
);
|
|
160939
161285
|
const targetPreset = speedPresets[presetIndex];
|
|
160940
|
-
|
|
161286
|
+
this.dispatchSpeedAction(
|
|
161287
|
+
homeAssistant,
|
|
160941
161288
|
config8.setPresetMode(targetPreset, this.agent)
|
|
160942
161289
|
);
|
|
160943
161290
|
this.rememberSpeed(percentage);
|
|
@@ -161074,7 +161421,7 @@ var FanControlServerBase = class extends FeaturedBase6 {
|
|
|
161074
161421
|
const entityId = this.agent.get(HomeAssistantEntityBehavior).entity.entity_id;
|
|
161075
161422
|
setOptimisticOnOff(entityId, on);
|
|
161076
161423
|
} catch (e) {
|
|
161077
|
-
|
|
161424
|
+
logger211.debug(
|
|
161078
161425
|
`syncOnOff(${on}) failed: ${e instanceof Error ? e.message : String(e)}`
|
|
161079
161426
|
);
|
|
161080
161427
|
}
|
|
@@ -161217,7 +161564,7 @@ var FanOnOffServer = OnOffServer2({
|
|
|
161217
161564
|
});
|
|
161218
161565
|
|
|
161219
161566
|
// src/matter/endpoints/composed/composed-air-purifier-endpoint.ts
|
|
161220
|
-
var
|
|
161567
|
+
var logger212 = Logger.get("ComposedAirPurifierEndpoint");
|
|
161221
161568
|
var temperatureConfig = {
|
|
161222
161569
|
getValue(entity, agent) {
|
|
161223
161570
|
const fallbackUnit = agent.env.get(HomeAssistantConfig).unitSystem.temperature;
|
|
@@ -161435,7 +161782,7 @@ var ComposedAirPurifierEndpoint = class _ComposedAirPurifierEndpoint extends End
|
|
|
161435
161782
|
config8.powerEntityId ? "+Pwr" : "",
|
|
161436
161783
|
config8.energyEntityId ? "+Nrg" : ""
|
|
161437
161784
|
].filter(Boolean).join("");
|
|
161438
|
-
|
|
161785
|
+
logger212.info(
|
|
161439
161786
|
`Created composed air purifier ${primaryEntityId}: ${clusterLabels}`
|
|
161440
161787
|
);
|
|
161441
161788
|
return endpoint;
|
|
@@ -161608,6 +161955,19 @@ function rockSettingToSwingMode(setting) {
|
|
|
161608
161955
|
}
|
|
161609
161956
|
return "off";
|
|
161610
161957
|
}
|
|
161958
|
+
function climateFanOffMode(fanModes) {
|
|
161959
|
+
const modes = fanModes ?? [];
|
|
161960
|
+
const declaredOff = modes.find(
|
|
161961
|
+
(mode) => ["off", "none", "stop"].includes(mode.trim().toLowerCase())
|
|
161962
|
+
);
|
|
161963
|
+
if (declaredOff) {
|
|
161964
|
+
return declaredOff;
|
|
161965
|
+
}
|
|
161966
|
+
const speeds = toAscendingSpeedPresets(
|
|
161967
|
+
modes.filter((mode) => mode.toLowerCase() !== "auto")
|
|
161968
|
+
);
|
|
161969
|
+
return speeds[0] ?? "off";
|
|
161970
|
+
}
|
|
161611
161971
|
var climateFanControlConfig = {
|
|
161612
161972
|
getPercentage: () => void 0,
|
|
161613
161973
|
getStepSize: () => void 0,
|
|
@@ -161623,16 +161983,33 @@ var climateFanControlConfig = {
|
|
|
161623
161983
|
return attributes4(entity).fan_mode ?? void 0;
|
|
161624
161984
|
},
|
|
161625
161985
|
supportsPercentage: () => false,
|
|
161986
|
+
// An AC's fan cannot stop while the compressor runs, so speed zero must not
|
|
161987
|
+
// report the unit as powered off. Without this the Matter OnOff cluster flips
|
|
161988
|
+
// false at zero, the controller shows the AC off, HA reports it still on, and
|
|
161989
|
+
// the tile flaps back. Power stays with the OnOff cluster's own commands.
|
|
161990
|
+
syncOnOffWithSpeed: false,
|
|
161626
161991
|
isOscillating: (entity) => attributes4(entity).swing_mode?.toLowerCase() !== "off" && attributes4(entity).swing_mode != null,
|
|
161627
161992
|
supportsOscillation: (entity) => (attributes4(entity).swing_modes?.length ?? 0) > 0,
|
|
161628
161993
|
getRockSetting: (entity) => swingModeToRockSetting(attributes4(entity).swing_mode),
|
|
161629
161994
|
// Climate devices don't typically support wind modes
|
|
161630
161995
|
getWindMode: () => void 0,
|
|
161631
161996
|
supportsWind: () => false,
|
|
161632
|
-
|
|
161633
|
-
|
|
161634
|
-
|
|
161635
|
-
|
|
161997
|
+
// A controller writing percentSetting 0 lands here. An air conditioner's fan
|
|
161998
|
+
// cannot stop independently of the compressor, and HA climate entities almost
|
|
161999
|
+
// never declare an "off" fan mode - sending the literal "off" just fails the
|
|
162000
|
+
// service call, so the slider's bottom position silently does nothing.
|
|
162001
|
+
// Clamp to the slowest real speed instead, unless the entity genuinely offers
|
|
162002
|
+
// an off-like mode, in which case use its own spelling (HA fan mode names are
|
|
162003
|
+
// case-sensitive). Power stays with the OnOff cluster, which is where a
|
|
162004
|
+
// controller's actual "off" belongs.
|
|
162005
|
+
turnOff: (_, agent) => {
|
|
162006
|
+
const entityState = agent.get(HomeAssistantEntityBehavior).state.entity.state;
|
|
162007
|
+
const fanMode = climateFanOffMode(attributes4(entityState).fan_modes);
|
|
162008
|
+
return {
|
|
162009
|
+
action: "climate.set_fan_mode",
|
|
162010
|
+
data: { fan_mode: fanMode }
|
|
162011
|
+
};
|
|
162012
|
+
},
|
|
161636
162013
|
turnOn: () => ({
|
|
161637
162014
|
action: "climate.set_fan_mode",
|
|
161638
162015
|
data: { fan_mode: "on" }
|
|
@@ -161721,11 +162098,16 @@ var humidityConfig2 = {
|
|
|
161721
162098
|
var ClimateHumidityMeasurementServer = HumidityMeasurementServer(humidityConfig2);
|
|
161722
162099
|
|
|
161723
162100
|
// src/matter/endpoints/legacy/climate/behaviors/climate-on-off-server.ts
|
|
162101
|
+
init_esm();
|
|
161724
162102
|
init_home_assistant_entity_behavior();
|
|
162103
|
+
var logger213 = Logger.get("ClimateOnOffServer");
|
|
161725
162104
|
var ClimateOnOffServer = OnOffServer2({
|
|
161726
162105
|
turnOn: (_value, agent) => {
|
|
161727
162106
|
const entity = agent.get(HomeAssistantEntityBehavior).entity;
|
|
161728
|
-
if (entity.state.state !== "off") {
|
|
162107
|
+
if (entity.state.state !== "off" && agent.get(OnOffServer).state.onOff) {
|
|
162108
|
+
logger213.debug(
|
|
162109
|
+
`[${entity.entity_id}] Skipping redundant OnOff.on(), cached state "${entity.state.state}"`
|
|
162110
|
+
);
|
|
161729
162111
|
return void 0;
|
|
161730
162112
|
}
|
|
161731
162113
|
return { action: "climate.turn_on" };
|
|
@@ -161757,7 +162139,8 @@ init_home_assistant_entity_behavior();
|
|
|
161757
162139
|
// src/matter/behaviors/thermostat-server.ts
|
|
161758
162140
|
init_esm();
|
|
161759
162141
|
init_home_assistant_entity_behavior();
|
|
161760
|
-
|
|
162142
|
+
init_transaction_is_offline();
|
|
162143
|
+
var logger214 = Logger.get("ThermostatServer");
|
|
161761
162144
|
var SystemMode = Thermostat3.SystemMode;
|
|
161762
162145
|
var RunningMode = Thermostat3.ThermostatRunningMode;
|
|
161763
162146
|
var nudgingSetpoints = /* @__PURE__ */ new Set();
|
|
@@ -161836,7 +162219,7 @@ function clearInactiveSetpointState(self, scope) {
|
|
|
161836
162219
|
}
|
|
161837
162220
|
function thermostatPreInitialize(self) {
|
|
161838
162221
|
const currentLocal = self.state.localTemperature;
|
|
161839
|
-
|
|
162222
|
+
logger214.debug(
|
|
161840
162223
|
`initialize: features - heating=${self.features.heating}, cooling=${self.features.cooling}`
|
|
161841
162224
|
);
|
|
161842
162225
|
const localValue = typeof currentLocal === "number" && !Number.isNaN(currentLocal) ? currentLocal : currentLocal === null ? null : 2100;
|
|
@@ -161883,7 +162266,7 @@ function thermostatPreInitialize(self) {
|
|
|
161883
162266
|
} else {
|
|
161884
162267
|
clearInactiveSetpointState(self, "Cool");
|
|
161885
162268
|
}
|
|
161886
|
-
|
|
162269
|
+
logger214.debug(
|
|
161887
162270
|
`initialize: after force-set - local=${self.state.localTemperature}`
|
|
161888
162271
|
);
|
|
161889
162272
|
self.state.thermostatRunningState = runningStateAllOff;
|
|
@@ -161976,7 +162359,7 @@ var ThermostatServerBase = class extends FullFeaturedBase {
|
|
|
161976
162359
|
maxCoolLimit,
|
|
161977
162360
|
"cool"
|
|
161978
162361
|
);
|
|
161979
|
-
|
|
162362
|
+
logger214.debug(
|
|
161980
162363
|
`update: limits heat=[${minHeatLimit}, ${maxHeatLimit}], cool=[${minCoolLimit}, ${maxCoolLimit}], systemMode=${systemMode}, runningMode=${runningMode}`
|
|
161981
162364
|
);
|
|
161982
162365
|
let controlSequence = config8.getControlSequence(entity.state, this.agent);
|
|
@@ -162049,18 +162432,18 @@ var ThermostatServerBase = class extends FullFeaturedBase {
|
|
|
162049
162432
|
*/
|
|
162050
162433
|
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: Called via thermostatPostInitialize + prototype copy
|
|
162051
162434
|
heatingSetpointChanging(value, _oldValue, context) {
|
|
162052
|
-
|
|
162435
|
+
logger214.debug(
|
|
162053
162436
|
`heatingSetpointChanging: value=${value}, oldValue=${_oldValue}, isOffline=${transactionIsOffline(context)}`
|
|
162054
162437
|
);
|
|
162055
162438
|
if (transactionIsOffline(context)) {
|
|
162056
|
-
|
|
162439
|
+
logger214.debug(
|
|
162057
162440
|
"heatingSetpointChanging: skipping - transaction is offline"
|
|
162058
162441
|
);
|
|
162059
162442
|
return;
|
|
162060
162443
|
}
|
|
162061
162444
|
const next = Temperature.celsius(value / 100);
|
|
162062
162445
|
if (!next) {
|
|
162063
|
-
|
|
162446
|
+
logger214.debug("heatingSetpointChanging: skipping - invalid temperature");
|
|
162064
162447
|
return;
|
|
162065
162448
|
}
|
|
162066
162449
|
this.agent.asLocalActor(() => {
|
|
@@ -162071,7 +162454,7 @@ var ThermostatServerBase = class extends FullFeaturedBase {
|
|
|
162071
162454
|
this.agent
|
|
162072
162455
|
);
|
|
162073
162456
|
const currentMode2 = this.state.systemMode;
|
|
162074
|
-
|
|
162457
|
+
logger214.debug(
|
|
162075
162458
|
`heatingSetpointChanging: supportsRange=${supportsRange}, systemMode=${currentMode2}, features.heating=${this.features.heating}, features.cooling=${this.features.cooling}`
|
|
162076
162459
|
);
|
|
162077
162460
|
if (!supportsRange) {
|
|
@@ -162081,12 +162464,12 @@ var ThermostatServerBase = class extends FullFeaturedBase {
|
|
|
162081
162464
|
const isOff = currentMode2 === Thermostat3.SystemMode.Off;
|
|
162082
162465
|
if (isOff && this.features.heating) {
|
|
162083
162466
|
if (nudgingSetpoints.has(homeAssistant.entityId)) {
|
|
162084
|
-
|
|
162467
|
+
logger214.debug(
|
|
162085
162468
|
`heatingSetpointChanging: skipping auto-resume - nudge write in progress`
|
|
162086
162469
|
);
|
|
162087
162470
|
return;
|
|
162088
162471
|
}
|
|
162089
|
-
|
|
162472
|
+
logger214.info(
|
|
162090
162473
|
`heatingSetpointChanging: auto-resume - switching to Heat (was Off)`
|
|
162091
162474
|
);
|
|
162092
162475
|
const modeAction = config8.setSystemMode(
|
|
@@ -162095,17 +162478,17 @@ var ThermostatServerBase = class extends FullFeaturedBase {
|
|
|
162095
162478
|
);
|
|
162096
162479
|
homeAssistant.callAction(modeAction);
|
|
162097
162480
|
} else if (!isAutoMode && !isHeatingMode) {
|
|
162098
|
-
|
|
162481
|
+
logger214.debug(
|
|
162099
162482
|
`heatingSetpointChanging: skipping - not in heating/auto mode (mode=${currentMode2}, haMode=${haHvacMode})`
|
|
162100
162483
|
);
|
|
162101
162484
|
return;
|
|
162102
162485
|
}
|
|
162103
|
-
|
|
162486
|
+
logger214.debug(
|
|
162104
162487
|
`heatingSetpointChanging: proceeding - isAutoMode=${isAutoMode}, isHeatingMode=${isHeatingMode}, isOff=${isOff}, haMode=${haHvacMode}`
|
|
162105
162488
|
);
|
|
162106
162489
|
}
|
|
162107
162490
|
const coolingSetpoint = this.features.cooling ? this.state.occupiedCoolingSetpoint : value;
|
|
162108
|
-
|
|
162491
|
+
logger214.debug(
|
|
162109
162492
|
`heatingSetpointChanging: calling setTemperature with heat=${next.celsius(true)}, cool=${coolingSetpoint}`
|
|
162110
162493
|
);
|
|
162111
162494
|
this.setTemperature(
|
|
@@ -162144,12 +162527,12 @@ var ThermostatServerBase = class extends FullFeaturedBase {
|
|
|
162144
162527
|
const isOff = currentMode2 === Thermostat3.SystemMode.Off;
|
|
162145
162528
|
if (isOff && !this.features.heating && this.features.cooling) {
|
|
162146
162529
|
if (nudgingSetpoints.has(homeAssistant.entityId)) {
|
|
162147
|
-
|
|
162530
|
+
logger214.debug(
|
|
162148
162531
|
`coolingSetpointChanging: skipping auto-resume - nudge write in progress`
|
|
162149
162532
|
);
|
|
162150
162533
|
return;
|
|
162151
162534
|
}
|
|
162152
|
-
|
|
162535
|
+
logger214.info(
|
|
162153
162536
|
`coolingSetpointChanging: auto-resume - switching to Cool (was Off)`
|
|
162154
162537
|
);
|
|
162155
162538
|
const modeAction = config8.setSystemMode(
|
|
@@ -162158,12 +162541,12 @@ var ThermostatServerBase = class extends FullFeaturedBase {
|
|
|
162158
162541
|
);
|
|
162159
162542
|
homeAssistant.callAction(modeAction);
|
|
162160
162543
|
} else if (!isAutoMode && !isCoolingMode) {
|
|
162161
|
-
|
|
162544
|
+
logger214.debug(
|
|
162162
162545
|
`coolingSetpointChanging: skipping - not in cooling/auto mode (mode=${currentMode2}, haMode=${haHvacMode})`
|
|
162163
162546
|
);
|
|
162164
162547
|
return;
|
|
162165
162548
|
}
|
|
162166
|
-
|
|
162549
|
+
logger214.debug(
|
|
162167
162550
|
`coolingSetpointChanging: proceeding - isAutoMode=${isAutoMode}, isCoolingMode=${isCoolingMode}, isOff=${isOff}, haMode=${haHvacMode}`
|
|
162168
162551
|
);
|
|
162169
162552
|
}
|
|
@@ -162277,7 +162660,7 @@ var ThermostatServerBase = class extends FullFeaturedBase {
|
|
|
162277
162660
|
const effectiveMax = max ?? 5e3;
|
|
162278
162661
|
if (value == null || Number.isNaN(value)) {
|
|
162279
162662
|
const defaultValue = type === "heat" ? 2e3 : 2400;
|
|
162280
|
-
|
|
162663
|
+
logger214.debug(
|
|
162281
162664
|
`${type} setpoint is undefined, using default: ${defaultValue}`
|
|
162282
162665
|
);
|
|
162283
162666
|
return Math.max(effectiveMin, Math.min(effectiveMax, defaultValue));
|
|
@@ -162855,7 +163238,7 @@ function ClimateDevice(homeAssistantEntity, includeBasicInformation = true) {
|
|
|
162855
163238
|
}
|
|
162856
163239
|
|
|
162857
163240
|
// src/matter/endpoints/composed/composed-climate-fan-endpoint.ts
|
|
162858
|
-
var
|
|
163241
|
+
var logger215 = Logger.get("ComposedClimateFanEndpoint");
|
|
162859
163242
|
function createEndpointId3(entityId, customName) {
|
|
162860
163243
|
const baseName = customName || entityId;
|
|
162861
163244
|
return baseName.replace(/\./g, "_").replace(/\s+/g, "_");
|
|
@@ -162893,7 +163276,7 @@ var ComposedClimateFanEndpoint = class _ComposedClimateFanEndpoint extends Endpo
|
|
|
162893
163276
|
climateSub = new Endpoint(climateType, { id: `${endpointId}_climate` });
|
|
162894
163277
|
} catch (error) {
|
|
162895
163278
|
const message = error instanceof Error ? error.message : String(error);
|
|
162896
|
-
|
|
163279
|
+
logger215.warn(
|
|
162897
163280
|
`Companion fan: climate sub build failed for ${primaryEntityId}: ${message}`
|
|
162898
163281
|
);
|
|
162899
163282
|
return void 0;
|
|
@@ -162937,7 +163320,7 @@ var ComposedClimateFanEndpoint = class _ComposedClimateFanEndpoint extends Endpo
|
|
|
162937
163320
|
endpointId,
|
|
162938
163321
|
[climateSub, fanSub]
|
|
162939
163322
|
);
|
|
162940
|
-
|
|
163323
|
+
logger215.info(`Created composed climate+fan endpoint ${primaryEntityId}`);
|
|
162941
163324
|
return endpoint;
|
|
162942
163325
|
}
|
|
162943
163326
|
constructor(type, entityId, id, parts) {
|
|
@@ -163032,7 +163415,7 @@ init_home_assistant_entity_behavior();
|
|
|
163032
163415
|
// src/matter/behaviors/pressure-measurement-server.ts
|
|
163033
163416
|
init_esm();
|
|
163034
163417
|
init_home_assistant_entity_behavior();
|
|
163035
|
-
var
|
|
163418
|
+
var logger216 = Logger.get("PressureMeasurementServer");
|
|
163036
163419
|
var MIN_PRESSURE = 300;
|
|
163037
163420
|
var MAX_PRESSURE = 1100;
|
|
163038
163421
|
var PressureMeasurementServerBase = class extends PressureMeasurementServer {
|
|
@@ -163060,7 +163443,7 @@ var PressureMeasurementServerBase = class extends PressureMeasurementServer {
|
|
|
163060
163443
|
}
|
|
163061
163444
|
const rounded = Math.round(value);
|
|
163062
163445
|
if (rounded < MIN_PRESSURE || rounded > MAX_PRESSURE) {
|
|
163063
|
-
|
|
163446
|
+
logger216.warn(
|
|
163064
163447
|
`Pressure value ${rounded} (raw: ${value}) for ${entity.entity_id} is outside valid range [${MIN_PRESSURE}-${MAX_PRESSURE}], ignoring`
|
|
163065
163448
|
);
|
|
163066
163449
|
return null;
|
|
@@ -163079,7 +163462,7 @@ function PressureMeasurementServer2(config8) {
|
|
|
163079
163462
|
}
|
|
163080
163463
|
|
|
163081
163464
|
// src/matter/endpoints/composed/composed-sensor-endpoint.ts
|
|
163082
|
-
var
|
|
163465
|
+
var logger217 = Logger.get("ComposedSensorEndpoint");
|
|
163083
163466
|
var temperatureConfig2 = {
|
|
163084
163467
|
getValue(entity, agent) {
|
|
163085
163468
|
const fallbackUnit = agent.env.get(HomeAssistantConfig).unitSystem.temperature;
|
|
@@ -163257,7 +163640,7 @@ var ComposedSensorEndpoint = class _ComposedSensorEndpoint extends Endpoint {
|
|
|
163257
163640
|
if (config8.pressureEntityId && pressSub) {
|
|
163258
163641
|
endpoint.subEndpoints.set(config8.pressureEntityId, pressSub);
|
|
163259
163642
|
}
|
|
163260
|
-
|
|
163643
|
+
logger217.info(
|
|
163261
163644
|
`Created composed sensor ${primaryEntityId} with ${parts.length} sub-endpoint(s): T${humSub ? "+H" : ""}${pressSub ? "+P" : ""}${config8.batteryEntityId ? "+Bat" : ""}${config8.powerEntityId ? "+Pwr" : ""}${config8.energyEntityId ? "+Nrg" : ""}`
|
|
163262
163645
|
);
|
|
163263
163646
|
return endpoint;
|
|
@@ -163394,7 +163777,7 @@ init_home_assistant_entity_behavior();
|
|
|
163394
163777
|
// src/matter/behaviors/mode-select-server.ts
|
|
163395
163778
|
init_esm();
|
|
163396
163779
|
init_home_assistant_entity_behavior();
|
|
163397
|
-
var
|
|
163780
|
+
var logger218 = Logger.get("ModeSelectServer");
|
|
163398
163781
|
function buildSupportedModes(options) {
|
|
163399
163782
|
return options.map((label, index) => ({
|
|
163400
163783
|
label: label.length > 64 ? label.substring(0, 64) : label,
|
|
@@ -163431,13 +163814,13 @@ var ModeSelectServerBase = class extends ModeSelectServer {
|
|
|
163431
163814
|
const options = config8.getOptions(homeAssistant.entity);
|
|
163432
163815
|
const { newMode } = request;
|
|
163433
163816
|
if (newMode < 0 || newMode >= options.length) {
|
|
163434
|
-
|
|
163817
|
+
logger218.warn(
|
|
163435
163818
|
`[${homeAssistant.entityId}] Invalid mode ${newMode}, options: [${options.join(", ")}]`
|
|
163436
163819
|
);
|
|
163437
163820
|
return;
|
|
163438
163821
|
}
|
|
163439
163822
|
const option = options[newMode];
|
|
163440
|
-
|
|
163823
|
+
logger218.info(
|
|
163441
163824
|
`[${homeAssistant.entityId}] changeToMode(${newMode}) -> "${option}"`
|
|
163442
163825
|
);
|
|
163443
163826
|
applyPatchState(this.state, { currentMode: newMode });
|
|
@@ -163988,7 +164371,7 @@ var CoAlarmWithBatteryType = SmokeCoAlarmDevice.with(
|
|
|
163988
164371
|
);
|
|
163989
164372
|
|
|
163990
164373
|
// src/matter/endpoints/legacy/binary-sensor/index.ts
|
|
163991
|
-
var
|
|
164374
|
+
var logger219 = Logger.get("BinarySensorDevice");
|
|
163992
164375
|
var deviceClasses = {
|
|
163993
164376
|
[BinarySensorDeviceClass.CarbonMonoxide]: CoAlarmType,
|
|
163994
164377
|
[BinarySensorDeviceClass.Gas]: CoAlarmType,
|
|
@@ -164039,11 +164422,11 @@ function BinarySensorDevice(homeAssistantEntity) {
|
|
|
164039
164422
|
const originalTypeName = type.name;
|
|
164040
164423
|
if (hasBattery && batteryTypes.has(type)) {
|
|
164041
164424
|
type = batteryTypes.get(type);
|
|
164042
|
-
|
|
164425
|
+
logger219.info(
|
|
164043
164426
|
`[${entityId}] Using battery variant: ${originalTypeName} -> ${type.name}, batteryAttr=${hasBatteryAttr}, batteryEntity=${homeAssistantEntity.mapping?.batteryEntity ?? "none"}`
|
|
164044
164427
|
);
|
|
164045
164428
|
} else if (hasBattery) {
|
|
164046
|
-
|
|
164429
|
+
logger219.warn(
|
|
164047
164430
|
`[${entityId}] Has battery but no variant available for ${originalTypeName}`
|
|
164048
164431
|
);
|
|
164049
164432
|
}
|
|
@@ -164130,7 +164513,7 @@ init_home_assistant_entity_behavior();
|
|
|
164130
164513
|
init_esm();
|
|
164131
164514
|
init_home_assistant_actions();
|
|
164132
164515
|
init_home_assistant_entity_behavior();
|
|
164133
|
-
var
|
|
164516
|
+
var logger220 = Logger.get("WindowCoveringServer");
|
|
164134
164517
|
var MovementStatus = WindowCovering3.MovementStatus;
|
|
164135
164518
|
var FeaturedBase7 = WindowCoveringServer.with(
|
|
164136
164519
|
"Lift",
|
|
@@ -164341,7 +164724,7 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
|
|
|
164341
164724
|
}
|
|
164342
164725
|
return existing100ths ?? current100ths;
|
|
164343
164726
|
};
|
|
164344
|
-
|
|
164727
|
+
logger220.debug(
|
|
164345
164728
|
`Cover update for ${entity.entity_id}: state=${state.state}, lift=${currentLift}%, tilt=${currentTilt}%, ha=${MovementStatus[movementStatus]}, effective=${MovementStatus[globalStatus]}`
|
|
164346
164729
|
);
|
|
164347
164730
|
const overrideType = config8.getCoverType?.(state, this.agent);
|
|
@@ -164386,9 +164769,9 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
|
|
|
164386
164769
|
);
|
|
164387
164770
|
if (Object.keys(appliedPatch).length > 0) {
|
|
164388
164771
|
const hasOperationalChange = "operationalStatus" in appliedPatch;
|
|
164389
|
-
const log = hasOperationalChange ?
|
|
164772
|
+
const log = hasOperationalChange ? logger220.info : logger220.debug;
|
|
164390
164773
|
log.call(
|
|
164391
|
-
|
|
164774
|
+
logger220,
|
|
164392
164775
|
`Cover ${entity.entity_id} state changed: ${JSON.stringify(appliedPatch)}`
|
|
164393
164776
|
);
|
|
164394
164777
|
}
|
|
@@ -164497,7 +164880,7 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
|
|
|
164497
164880
|
}
|
|
164498
164881
|
});
|
|
164499
164882
|
} catch (error) {
|
|
164500
|
-
|
|
164883
|
+
logger220.debug(
|
|
164501
164884
|
`Optimistic ${axis} timeout write failed (endpoint may be closing): ${error}`
|
|
164502
164885
|
);
|
|
164503
164886
|
}
|
|
@@ -164507,12 +164890,32 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
|
|
|
164507
164890
|
optimistic[axis] = { status: status3, startedAt, timer, expectedRestEnd };
|
|
164508
164891
|
this.writeOperationalStatus({ [axis]: status3 });
|
|
164509
164892
|
}
|
|
164893
|
+
// matter.js runs handleMovement as a worker, so a throw in there cannot fail
|
|
164894
|
+
// the command. The commands that start movement check up front instead, and
|
|
164895
|
+
// the HA call is deferred past the debounce anyway, outside the transaction
|
|
164896
|
+
// where a rollback could not undo the optimistic target (#446).
|
|
164897
|
+
async upOrOpen() {
|
|
164898
|
+
this.agent.get(HomeAssistantEntityBehavior).assertAvailable();
|
|
164899
|
+
return super.upOrOpen();
|
|
164900
|
+
}
|
|
164901
|
+
async downOrClose() {
|
|
164902
|
+
this.agent.get(HomeAssistantEntityBehavior).assertAvailable();
|
|
164903
|
+
return super.downOrClose();
|
|
164904
|
+
}
|
|
164905
|
+
async goToLiftPercentage(request) {
|
|
164906
|
+
this.agent.get(HomeAssistantEntityBehavior).assertAvailable();
|
|
164907
|
+
return super.goToLiftPercentage(request);
|
|
164908
|
+
}
|
|
164909
|
+
async goToTiltPercentage(request) {
|
|
164910
|
+
this.agent.get(HomeAssistantEntityBehavior).assertAvailable();
|
|
164911
|
+
return super.goToTiltPercentage(request);
|
|
164912
|
+
}
|
|
164510
164913
|
async handleMovement(type, _, direction, targetPercent100ths) {
|
|
164511
164914
|
const currentLift = this.state.currentPositionLiftPercent100ths ?? 0;
|
|
164512
164915
|
const currentTilt = this.state.currentPositionTiltPercent100ths ?? 0;
|
|
164513
164916
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
164514
164917
|
const flags2 = this.state.config.getDiagnosticFlags?.(this.agent);
|
|
164515
|
-
|
|
164918
|
+
logger220.info(
|
|
164516
164919
|
`handleMovement ${homeAssistant.entityId}: type=${MovementType[type]}, direction=${MovementDirection[direction]}, target=${targetPercent100ths}, currentLift=${currentLift}, currentTilt=${currentTilt}${flags2 ? `, ${flags2}` : ""}`
|
|
164517
164920
|
);
|
|
164518
164921
|
if (type === MovementType.Lift) {
|
|
@@ -164531,7 +164934,7 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
|
|
|
164531
164934
|
}
|
|
164532
164935
|
} else if (type === MovementType.Tilt) {
|
|
164533
164936
|
if (targetPercent100ths == null && this.lastLiftMovementDirection === direction && Date.now() - this.lastLiftMovementMs < 50) {
|
|
164534
|
-
|
|
164937
|
+
logger220.info(
|
|
164535
164938
|
`Skipping tilt ${MovementDirection[direction]}, lift already moving in same direction`
|
|
164536
164939
|
);
|
|
164537
164940
|
return;
|
|
@@ -164576,7 +164979,7 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
|
|
|
164576
164979
|
} else {
|
|
164577
164980
|
this.startOptimisticMovement("lift", MovementStatus.Opening, end);
|
|
164578
164981
|
}
|
|
164579
|
-
|
|
164982
|
+
logger220.info(
|
|
164580
164983
|
`handleLiftOpen ${homeAssistant.entityId}: calling action=${action.action}, atRest=${atRest}, ${this.state.config.getDiagnosticFlags?.(this.agent) ?? ""}`
|
|
164581
164984
|
);
|
|
164582
164985
|
homeAssistant.callAction(action);
|
|
@@ -164592,7 +164995,7 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
|
|
|
164592
164995
|
} else {
|
|
164593
164996
|
this.startOptimisticMovement("lift", MovementStatus.Closing, end);
|
|
164594
164997
|
}
|
|
164595
|
-
|
|
164998
|
+
logger220.info(
|
|
164596
164999
|
`handleLiftClose ${homeAssistant.entityId}: calling action=${action.action}, atRest=${atRest}, ${this.state.config.getDiagnosticFlags?.(this.agent) ?? ""}`
|
|
164597
165000
|
);
|
|
164598
165001
|
homeAssistant.callAction(action);
|
|
@@ -164622,7 +165025,7 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
|
|
|
164622
165025
|
const isFirstInSequence = timeSinceLastCommand > _WindowCoveringServerBase.COMMAND_SEQUENCE_THRESHOLD_MS;
|
|
164623
165026
|
const overrideMs = this.resolveDebounceOverride(homeAssistant);
|
|
164624
165027
|
const debounceMs = overrideMs != null ? overrideMs : isFirstInSequence ? _WindowCoveringServerBase.DEBOUNCE_INITIAL_MS : _WindowCoveringServerBase.DEBOUNCE_SUBSEQUENT_MS;
|
|
164625
|
-
|
|
165028
|
+
logger220.debug(
|
|
164626
165029
|
`Lift command: target=${targetPosition}%, debounce=${debounceMs}ms (${overrideMs != null ? "override" : isFirstInSequence ? "initial" : "subsequent"})`
|
|
164627
165030
|
);
|
|
164628
165031
|
if (st.liftTimer) {
|
|
@@ -164654,7 +165057,7 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
|
|
|
164654
165057
|
this.startOptimisticMovement("tilt", MovementStatus.Opening, end);
|
|
164655
165058
|
}
|
|
164656
165059
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
164657
|
-
|
|
165060
|
+
logger220.info(
|
|
164658
165061
|
`handleTiltOpen ${homeAssistant.entityId}: calling action=${action.action}, atRest=${atRest}, ${this.state.config.getDiagnosticFlags?.(this.agent) ?? ""}`
|
|
164659
165062
|
);
|
|
164660
165063
|
homeAssistant.callAction(action);
|
|
@@ -164672,7 +165075,7 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
|
|
|
164672
165075
|
this.startOptimisticMovement("tilt", MovementStatus.Closing, end);
|
|
164673
165076
|
}
|
|
164674
165077
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
164675
|
-
|
|
165078
|
+
logger220.info(
|
|
164676
165079
|
`handleTiltClose ${homeAssistant.entityId}: calling action=${action.action}, atRest=${atRest}, ${this.state.config.getDiagnosticFlags?.(this.agent) ?? ""}`
|
|
164677
165080
|
);
|
|
164678
165081
|
homeAssistant.callAction(action);
|
|
@@ -164702,7 +165105,7 @@ var WindowCoveringServerBase = class _WindowCoveringServerBase extends FeaturedB
|
|
|
164702
165105
|
const isFirstInSequence = timeSinceLastCommand > _WindowCoveringServerBase.COMMAND_SEQUENCE_THRESHOLD_MS;
|
|
164703
165106
|
const overrideMs = this.resolveDebounceOverride(homeAssistant);
|
|
164704
165107
|
const debounceMs = overrideMs != null ? overrideMs : isFirstInSequence ? _WindowCoveringServerBase.DEBOUNCE_INITIAL_MS : _WindowCoveringServerBase.DEBOUNCE_SUBSEQUENT_MS;
|
|
164705
|
-
|
|
165108
|
+
logger220.debug(
|
|
164706
165109
|
`Tilt command: target=${targetPosition}%, debounce=${debounceMs}ms (${overrideMs != null ? "override" : isFirstInSequence ? "initial" : "subsequent"})`
|
|
164707
165110
|
);
|
|
164708
165111
|
if (st.tiltTimer) {
|
|
@@ -164754,7 +165157,7 @@ function adjustPositionForWriting(position, flags2, matterSemantics) {
|
|
|
164754
165157
|
}
|
|
164755
165158
|
|
|
164756
165159
|
// src/matter/endpoints/legacy/cover/behaviors/cover-window-covering-server.ts
|
|
164757
|
-
var
|
|
165160
|
+
var logger221 = Logger.get("CoverWindowCoveringServer");
|
|
164758
165161
|
var attributes6 = (entity) => entity.attributes;
|
|
164759
165162
|
var DEVICE_CLASS_TO_MATTER_TYPE = {
|
|
164760
165163
|
curtain: {
|
|
@@ -164826,7 +165229,7 @@ var adjustPositionForReading2 = (position, agent) => {
|
|
|
164826
165229
|
const { featureFlags } = agent.env.get(BridgeDataProvider);
|
|
164827
165230
|
const matterSem = usesMatterSemantics(agent);
|
|
164828
165231
|
const result = adjustPositionForReading(position, featureFlags, matterSem);
|
|
164829
|
-
|
|
165232
|
+
logger221.debug(`adjustPositionForReading: HA=${position}%, result=${result}%`);
|
|
164830
165233
|
return result;
|
|
164831
165234
|
};
|
|
164832
165235
|
var adjustPositionForWriting2 = (position, agent) => {
|
|
@@ -165051,14 +165454,14 @@ var CoverAsDimmableLightWithBatteryType = DimmableLightDevice.with(
|
|
|
165051
165454
|
);
|
|
165052
165455
|
|
|
165053
165456
|
// src/matter/endpoints/legacy/cover/index.ts
|
|
165054
|
-
var
|
|
165457
|
+
var logger222 = Logger.get("CoverDevice");
|
|
165055
165458
|
var CoverDeviceType = (supportedFeatures, hasBattery, entityId) => {
|
|
165056
165459
|
const features = /* @__PURE__ */ new Set();
|
|
165057
165460
|
if (testBit(supportedFeatures, CoverSupportedFeatures.support_open)) {
|
|
165058
165461
|
features.add("Lift");
|
|
165059
165462
|
features.add("PositionAwareLift");
|
|
165060
165463
|
} else {
|
|
165061
|
-
|
|
165464
|
+
logger222.warn(
|
|
165062
165465
|
`[${entityId}] Cover has no support_open feature (supported_features=${supportedFeatures}), adding Lift anyway`
|
|
165063
165466
|
);
|
|
165064
165467
|
features.add("Lift");
|
|
@@ -165073,7 +165476,7 @@ var CoverDeviceType = (supportedFeatures, hasBattery, entityId) => {
|
|
|
165073
165476
|
features.add("PositionAwareTilt");
|
|
165074
165477
|
}
|
|
165075
165478
|
}
|
|
165076
|
-
|
|
165479
|
+
logger222.info(
|
|
165077
165480
|
`[${entityId}] Creating WindowCovering with features: [${[...features].join(", ")}], supported_features=${supportedFeatures}`
|
|
165078
165481
|
);
|
|
165079
165482
|
const baseBehaviors2 = [
|
|
@@ -165097,16 +165500,16 @@ function CoverDevice(homeAssistantEntity) {
|
|
|
165097
165500
|
const hasBatteryEntity = !!homeAssistantEntity.mapping?.batteryEntity;
|
|
165098
165501
|
const hasBattery = hasBatteryAttr || hasBatteryEntity;
|
|
165099
165502
|
if (hasBattery) {
|
|
165100
|
-
|
|
165503
|
+
logger222.info(
|
|
165101
165504
|
`[${entityId}] Creating cover with PowerSource cluster, batteryAttr=${hasBatteryAttr}, batteryEntity=${homeAssistantEntity.mapping?.batteryEntity ?? "none"}`
|
|
165102
165505
|
);
|
|
165103
165506
|
} else {
|
|
165104
|
-
|
|
165507
|
+
logger222.debug(
|
|
165105
165508
|
`[${entityId}] Creating cover without battery (batteryAttr=${hasBatteryAttr}, batteryEntity=${homeAssistantEntity.mapping?.batteryEntity ?? "none"})`
|
|
165106
165509
|
);
|
|
165107
165510
|
}
|
|
165108
165511
|
if (homeAssistantEntity.mapping?.coverExposeAsDimmableLight) {
|
|
165109
|
-
|
|
165512
|
+
logger222.info(`[${entityId}] Exposing cover as a Dimmable Light (#372)`);
|
|
165110
165513
|
const type = hasBattery ? CoverAsDimmableLightWithBatteryType : CoverAsDimmableLightType;
|
|
165111
165514
|
return type.set({ homeAssistantEntity });
|
|
165112
165515
|
}
|
|
@@ -165221,7 +165624,7 @@ function DishwasherEndpoint(homeAssistantEntity) {
|
|
|
165221
165624
|
// src/matter/behaviors/generic-switch-server.ts
|
|
165222
165625
|
init_esm();
|
|
165223
165626
|
init_home_assistant_entity_behavior();
|
|
165224
|
-
var
|
|
165627
|
+
var logger223 = Logger.get("GenericSwitchServer");
|
|
165225
165628
|
var SimpleBase = SwitchServer.with(
|
|
165226
165629
|
"MomentarySwitch",
|
|
165227
165630
|
"MomentarySwitchRelease",
|
|
@@ -165263,7 +165666,7 @@ var HaGenericSwitchServerBase = class extends SimpleBase {
|
|
|
165263
165666
|
await super.initialize();
|
|
165264
165667
|
const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
|
|
165265
165668
|
const entityId = homeAssistant.entityId;
|
|
165266
|
-
|
|
165669
|
+
logger223.debug(`[${entityId}] GenericSwitch initialized (simple)`);
|
|
165267
165670
|
this.reactTo(homeAssistant.onChange, this.handleEventChange);
|
|
165268
165671
|
}
|
|
165269
165672
|
handleEventChange() {
|
|
@@ -165274,7 +165677,7 @@ var HaGenericSwitchServerBase = class extends SimpleBase {
|
|
|
165274
165677
|
const eventType = attrs.event_type;
|
|
165275
165678
|
if (!eventType) return;
|
|
165276
165679
|
const entityId = homeAssistant.entityId;
|
|
165277
|
-
|
|
165680
|
+
logger223.debug(`[${entityId}] Event fired: ${eventType}`);
|
|
165278
165681
|
this.triggerPress(eventType);
|
|
165279
165682
|
}
|
|
165280
165683
|
triggerPress(eventType) {
|
|
@@ -165320,7 +165723,7 @@ var HaGenericSwitchServerMultiBase = class extends FullBase {
|
|
|
165320
165723
|
await super.initialize();
|
|
165321
165724
|
const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
|
|
165322
165725
|
const entityId = homeAssistant.entityId;
|
|
165323
|
-
|
|
165726
|
+
logger223.debug(`[${entityId}] GenericSwitch initialized (multi)`);
|
|
165324
165727
|
this.reactTo(homeAssistant.onChange, this.handleEventChange);
|
|
165325
165728
|
}
|
|
165326
165729
|
handleEventChange() {
|
|
@@ -165331,7 +165734,7 @@ var HaGenericSwitchServerMultiBase = class extends FullBase {
|
|
|
165331
165734
|
const eventType = attrs.event_type;
|
|
165332
165735
|
if (!eventType) return;
|
|
165333
165736
|
const entityId = homeAssistant.entityId;
|
|
165334
|
-
|
|
165737
|
+
logger223.debug(`[${entityId}] Event fired: ${eventType}`);
|
|
165335
165738
|
this.triggerPress(eventType);
|
|
165336
165739
|
}
|
|
165337
165740
|
triggerPress(eventType) {
|
|
@@ -165708,7 +166111,7 @@ init_nodejs();
|
|
|
165708
166111
|
init_home_assistant_entity_behavior();
|
|
165709
166112
|
var OperationalState4 = RvcOperationalState4.OperationalState;
|
|
165710
166113
|
var ErrorState = RvcOperationalState4.ErrorState;
|
|
165711
|
-
var
|
|
166114
|
+
var logger224 = Logger.get("RvcOperationalStateServer");
|
|
165712
166115
|
var activeStates = /* @__PURE__ */ new Set([
|
|
165713
166116
|
OperationalState4.Running,
|
|
165714
166117
|
OperationalState4.SeekingCharger
|
|
@@ -165760,7 +166163,7 @@ var RvcOperationalStateServerBase = class extends RvcOperationalStateServer {
|
|
|
165760
166163
|
{ force: true }
|
|
165761
166164
|
);
|
|
165762
166165
|
if (activeStates.has(previousState) && !activeStates.has(newState)) {
|
|
165763
|
-
|
|
166166
|
+
logger224.info(
|
|
165764
166167
|
`Operation completed: ${OperationalState4[previousState]} -> ${OperationalState4[newState]}`
|
|
165765
166168
|
);
|
|
165766
166169
|
try {
|
|
@@ -165773,7 +166176,7 @@ var RvcOperationalStateServerBase = class extends RvcOperationalStateServer {
|
|
|
165773
166176
|
this.context
|
|
165774
166177
|
);
|
|
165775
166178
|
} catch (e) {
|
|
165776
|
-
|
|
166179
|
+
logger224.debug("Failed to emit operationCompletion event:", e);
|
|
165777
166180
|
}
|
|
165778
166181
|
}
|
|
165779
166182
|
}
|
|
@@ -165808,7 +166211,7 @@ var RvcOperationalStateServerBase = class extends RvcOperationalStateServer {
|
|
|
165808
166211
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
165809
166212
|
homeAssistant.callAction(goHomeAction(void 0, this.agent));
|
|
165810
166213
|
} else {
|
|
165811
|
-
|
|
166214
|
+
logger224.warn("GoHome command received but no goHome action configured");
|
|
165812
166215
|
}
|
|
165813
166216
|
return {
|
|
165814
166217
|
commandResponseState: {
|
|
@@ -165828,7 +166231,7 @@ function RvcOperationalStateServer2(config8) {
|
|
|
165828
166231
|
}
|
|
165829
166232
|
|
|
165830
166233
|
// src/matter/endpoints/legacy/lawn-mower/behaviors/lawn-mower-rvc-operational-state-server.ts
|
|
165831
|
-
var
|
|
166234
|
+
var logger225 = Logger.get("LawnMowerRvcOperationalStateServer");
|
|
165832
166235
|
function mapLawnMowerOperationalState(entity) {
|
|
165833
166236
|
const state = entity.state;
|
|
165834
166237
|
switch (state) {
|
|
@@ -165844,7 +166247,7 @@ function mapLawnMowerOperationalState(entity) {
|
|
|
165844
166247
|
case "unavailable":
|
|
165845
166248
|
return RvcOperationalState4.OperationalState.Error;
|
|
165846
166249
|
default:
|
|
165847
|
-
|
|
166250
|
+
logger225.info(`Unknown lawn_mower state "${state}", treating as Stopped`);
|
|
165848
166251
|
return RvcOperationalState4.OperationalState.Stopped;
|
|
165849
166252
|
}
|
|
165850
166253
|
}
|
|
@@ -165898,7 +166301,7 @@ function inferCleanedAreaProgress(cleanedSqm, orderedAreas) {
|
|
|
165898
166301
|
}
|
|
165899
166302
|
|
|
165900
166303
|
// src/matter/behaviors/rvc-run-mode-server.ts
|
|
165901
|
-
var
|
|
166304
|
+
var logger226 = Logger.get("RvcRunModeServer");
|
|
165902
166305
|
var ROOM_MODE_BASE = 100;
|
|
165903
166306
|
function isRoomMode(mode) {
|
|
165904
166307
|
return mode >= ROOM_MODE_BASE;
|
|
@@ -166024,7 +166427,7 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
|
|
|
166024
166427
|
const s = getSession(this.endpoint);
|
|
166025
166428
|
if (s.loggedShortCircuits.has(reason)) return;
|
|
166026
166429
|
s.loggedShortCircuits.add(reason);
|
|
166027
|
-
|
|
166430
|
+
logger226.info(message);
|
|
166028
166431
|
}
|
|
166029
166432
|
/**
|
|
166030
166433
|
* Read the currentRoomEntity sensor and update currentArea + progress
|
|
@@ -166081,7 +166484,7 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
|
|
|
166081
166484
|
}
|
|
166082
166485
|
}
|
|
166083
166486
|
if (matchedAreaId === null) {
|
|
166084
|
-
|
|
166487
|
+
logger226.info(
|
|
166085
166488
|
`currentRoom sensor: no match for "${roomName}" (segmentId=${segmentId}), activeAreas=[${s.activeAreas.join(", ")}], supportedAreas=[${serviceArea.state.supportedAreas.map((a) => `${a.areaId}:${a.areaInfo.locationInfo?.locationName}`).join(", ")}]`
|
|
166086
166489
|
);
|
|
166087
166490
|
return;
|
|
@@ -166091,14 +166494,14 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
|
|
|
166091
166494
|
s.completedAreas.add(s.lastCurrentArea);
|
|
166092
166495
|
}
|
|
166093
166496
|
s.lastCurrentArea = matchedAreaId;
|
|
166094
|
-
|
|
166497
|
+
logger226.info(
|
|
166095
166498
|
`currentRoom sensor: transition to area ${matchedAreaId} ("${roomName}"), completed: [${[...s.completedAreas].join(", ")}]`
|
|
166096
166499
|
);
|
|
166097
166500
|
this.trySetCurrentArea(matchedAreaId);
|
|
166098
166501
|
} catch (e) {
|
|
166099
166502
|
const msg = e instanceof Error ? e.message : String(e);
|
|
166100
166503
|
if (!msg.includes("No provider for") && !msg.includes("not supported")) {
|
|
166101
|
-
|
|
166504
|
+
logger226.warn(`currentRoom sensor update failed: ${msg}`);
|
|
166102
166505
|
}
|
|
166103
166506
|
}
|
|
166104
166507
|
}
|
|
@@ -166178,7 +166581,7 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
|
|
|
166178
166581
|
cleaned,
|
|
166179
166582
|
ordered
|
|
166180
166583
|
);
|
|
166181
|
-
|
|
166584
|
+
logger226.debug(
|
|
166182
166585
|
`cleanedArea: raw=${raw} baseline=${s.cleanedAreaBaseline} cleaned=${cleaned} sizes=[${ordered.map((o) => `${o.areaId}:${o.sizeSqm}`).join(",")}] -> current=${currentArea} completed=[${completed.join(",")}]`
|
|
166183
166586
|
);
|
|
166184
166587
|
for (const id of completed) {
|
|
@@ -166192,7 +166595,7 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
|
|
|
166192
166595
|
} catch (e) {
|
|
166193
166596
|
const msg = e instanceof Error ? e.message : String(e);
|
|
166194
166597
|
if (!msg.includes("No provider for") && !msg.includes("not supported")) {
|
|
166195
|
-
|
|
166598
|
+
logger226.warn(`cleanedArea room update failed: ${msg}`);
|
|
166196
166599
|
}
|
|
166197
166600
|
}
|
|
166198
166601
|
}
|
|
@@ -166207,7 +166610,7 @@ var RvcRunModeServerBase = class extends RvcRunModeServer {
|
|
|
166207
166610
|
const serviceArea = this.agent.get(ServiceAreaBehavior);
|
|
166208
166611
|
if (serviceArea.state.currentArea !== areaId) {
|
|
166209
166612
|
serviceArea.state.currentArea = areaId;
|
|
166210
|
-
|
|
166613
|
+
logger226.debug(`currentArea set to ${areaId}`);
|
|
166211
166614
|
}
|
|
166212
166615
|
this.updateProgress(serviceArea, areaId);
|
|
166213
166616
|
} catch {
|
|
@@ -166490,7 +166893,7 @@ init_nodejs();
|
|
|
166490
166893
|
|
|
166491
166894
|
// src/matter/behaviors/color-control-server.ts
|
|
166492
166895
|
init_home_assistant_entity_behavior();
|
|
166493
|
-
var
|
|
166896
|
+
var logger227 = Logger.get("ColorControlServer");
|
|
166494
166897
|
var optimisticColorState = /* @__PURE__ */ new Map();
|
|
166495
166898
|
var OPTIMISTIC_TIMEOUT_MS3 = 3e3;
|
|
166496
166899
|
var OPTIMISTIC_TOLERANCE2 = 5;
|
|
@@ -166529,7 +166932,7 @@ var ColorControlServerBase = class extends FeaturedBase8 {
|
|
|
166529
166932
|
if (this.state.startUpColorTemperatureMireds == null) {
|
|
166530
166933
|
this.state.startUpColorTemperatureMireds = defaultMireds;
|
|
166531
166934
|
}
|
|
166532
|
-
|
|
166935
|
+
logger227.debug(
|
|
166533
166936
|
`initialize: set ColorTemperature defaults - min=${this.state.colorTempPhysicalMinMireds}, max=${this.state.colorTempPhysicalMaxMireds}, current=${this.state.colorTemperatureMireds}`
|
|
166534
166937
|
);
|
|
166535
166938
|
}
|
|
@@ -167083,8 +167486,9 @@ init_home_assistant_entity_behavior();
|
|
|
167083
167486
|
|
|
167084
167487
|
// src/matter/behaviors/lock-server.ts
|
|
167085
167488
|
init_esm();
|
|
167489
|
+
init_types2();
|
|
167086
167490
|
init_home_assistant_entity_behavior();
|
|
167087
|
-
var
|
|
167491
|
+
var logger228 = Logger.get("LockServer");
|
|
167088
167492
|
var SUPPORTED_SLOT = 1;
|
|
167089
167493
|
function normalizeSupportedIndex(index) {
|
|
167090
167494
|
if (index === 0 || index === SUPPORTED_SLOT) {
|
|
@@ -167425,7 +167829,7 @@ var LockServerWithPinBase = class extends PinCredentialBase {
|
|
|
167425
167829
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
167426
167830
|
const action = this.state.config.lock(void 0, this.agent);
|
|
167427
167831
|
const hasPinProvided = !!request.pinCode;
|
|
167428
|
-
|
|
167832
|
+
logger228.debug(
|
|
167429
167833
|
`lockDoor called for ${homeAssistant.entityId}, PIN provided: ${hasPinProvided}`
|
|
167430
167834
|
);
|
|
167431
167835
|
if (request.pinCode) {
|
|
@@ -167438,12 +167842,12 @@ var LockServerWithPinBase = class extends PinCredentialBase {
|
|
|
167438
167842
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
167439
167843
|
const action = this.state.config.unlock(void 0, this.agent);
|
|
167440
167844
|
const hasPinProvided = !!request.pinCode;
|
|
167441
|
-
|
|
167845
|
+
logger228.debug(
|
|
167442
167846
|
`unlockDoor called for ${homeAssistant.entityId}, PIN provided: ${hasPinProvided}, requirePin: ${this.state.requirePinForRemoteOperation}`
|
|
167443
167847
|
);
|
|
167444
167848
|
if (this.state.requirePinForRemoteOperation) {
|
|
167445
167849
|
if (!request.pinCode) {
|
|
167446
|
-
|
|
167850
|
+
logger228.info(
|
|
167447
167851
|
`unlockDoor REJECTED for ${homeAssistant.entityId} - no PIN provided`
|
|
167448
167852
|
);
|
|
167449
167853
|
throw new StatusResponseError(
|
|
@@ -167453,12 +167857,12 @@ var LockServerWithPinBase = class extends PinCredentialBase {
|
|
|
167453
167857
|
}
|
|
167454
167858
|
const providedPin = new TextDecoder().decode(request.pinCode);
|
|
167455
167859
|
if (!verifyStoredPinHelper(this.env, homeAssistant.entityId, providedPin)) {
|
|
167456
|
-
|
|
167860
|
+
logger228.info(
|
|
167457
167861
|
`unlockDoor REJECTED for ${homeAssistant.entityId} - invalid PIN`
|
|
167458
167862
|
);
|
|
167459
167863
|
throw new StatusResponseError("Invalid PIN code", StatusCode.Failure);
|
|
167460
167864
|
}
|
|
167461
|
-
|
|
167865
|
+
logger228.debug(`unlockDoor PIN verified for ${homeAssistant.entityId}`);
|
|
167462
167866
|
action.data = { ...action.data, code: providedPin };
|
|
167463
167867
|
}
|
|
167464
167868
|
homeAssistant.callAction(action);
|
|
@@ -167600,7 +168004,7 @@ var LockServerWithPinAndUnboltBase = class extends PinCredentialUnboltBase {
|
|
|
167600
168004
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
167601
168005
|
const action = this.state.config.lock(void 0, this.agent);
|
|
167602
168006
|
const hasPinProvided = !!request.pinCode;
|
|
167603
|
-
|
|
168007
|
+
logger228.debug(
|
|
167604
168008
|
`lockDoor called for ${homeAssistant.entityId}, PIN provided: ${hasPinProvided}`
|
|
167605
168009
|
);
|
|
167606
168010
|
if (request.pinCode) {
|
|
@@ -167614,12 +168018,12 @@ var LockServerWithPinAndUnboltBase = class extends PinCredentialUnboltBase {
|
|
|
167614
168018
|
const unlatchConfig = this.state.config.unlatch;
|
|
167615
168019
|
const action = unlatchConfig ? unlatchConfig(void 0, this.agent) : this.state.config.unlock(void 0, this.agent);
|
|
167616
168020
|
const hasPinProvided = !!request.pinCode;
|
|
167617
|
-
|
|
168021
|
+
logger228.debug(
|
|
167618
168022
|
`unlockDoor called for ${homeAssistant.entityId}, PIN provided: ${hasPinProvided}, requirePin: ${this.state.requirePinForRemoteOperation}, usingUnlatch: ${!!unlatchConfig}`
|
|
167619
168023
|
);
|
|
167620
168024
|
if (this.state.requirePinForRemoteOperation) {
|
|
167621
168025
|
if (!request.pinCode) {
|
|
167622
|
-
|
|
168026
|
+
logger228.info(
|
|
167623
168027
|
`unlockDoor REJECTED for ${homeAssistant.entityId} - no PIN provided`
|
|
167624
168028
|
);
|
|
167625
168029
|
throw new StatusResponseError(
|
|
@@ -167629,12 +168033,12 @@ var LockServerWithPinAndUnboltBase = class extends PinCredentialUnboltBase {
|
|
|
167629
168033
|
}
|
|
167630
168034
|
const providedPin = new TextDecoder().decode(request.pinCode);
|
|
167631
168035
|
if (!verifyStoredPinHelper(this.env, homeAssistant.entityId, providedPin)) {
|
|
167632
|
-
|
|
168036
|
+
logger228.info(
|
|
167633
168037
|
`unlockDoor REJECTED for ${homeAssistant.entityId} - invalid PIN`
|
|
167634
168038
|
);
|
|
167635
168039
|
throw new StatusResponseError("Invalid PIN code", StatusCode.Failure);
|
|
167636
168040
|
}
|
|
167637
|
-
|
|
168041
|
+
logger228.debug(`unlockDoor PIN verified for ${homeAssistant.entityId}`);
|
|
167638
168042
|
action.data = { ...action.data, code: providedPin };
|
|
167639
168043
|
}
|
|
167640
168044
|
homeAssistant.callAction(action);
|
|
@@ -167643,12 +168047,12 @@ var LockServerWithPinAndUnboltBase = class extends PinCredentialUnboltBase {
|
|
|
167643
168047
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
167644
168048
|
const action = this.state.config.unlock(void 0, this.agent);
|
|
167645
168049
|
const hasPinProvided = !!request.pinCode;
|
|
167646
|
-
|
|
168050
|
+
logger228.debug(
|
|
167647
168051
|
`unboltDoor called for ${homeAssistant.entityId}, PIN provided: ${hasPinProvided}, requirePin: ${this.state.requirePinForRemoteOperation}`
|
|
167648
168052
|
);
|
|
167649
168053
|
if (this.state.requirePinForRemoteOperation) {
|
|
167650
168054
|
if (!request.pinCode) {
|
|
167651
|
-
|
|
168055
|
+
logger228.info(
|
|
167652
168056
|
`unboltDoor REJECTED for ${homeAssistant.entityId} - no PIN provided`
|
|
167653
168057
|
);
|
|
167654
168058
|
throw new StatusResponseError(
|
|
@@ -167658,12 +168062,12 @@ var LockServerWithPinAndUnboltBase = class extends PinCredentialUnboltBase {
|
|
|
167658
168062
|
}
|
|
167659
168063
|
const providedPin = new TextDecoder().decode(request.pinCode);
|
|
167660
168064
|
if (!verifyStoredPinHelper(this.env, homeAssistant.entityId, providedPin)) {
|
|
167661
|
-
|
|
168065
|
+
logger228.info(
|
|
167662
168066
|
`unboltDoor REJECTED for ${homeAssistant.entityId} - invalid PIN`
|
|
167663
168067
|
);
|
|
167664
168068
|
throw new StatusResponseError("Invalid PIN code", StatusCode.Failure);
|
|
167665
168069
|
}
|
|
167666
|
-
|
|
168070
|
+
logger228.debug(`unboltDoor PIN verified for ${homeAssistant.entityId}`);
|
|
167667
168071
|
action.data = { ...action.data, code: providedPin };
|
|
167668
168072
|
}
|
|
167669
168073
|
homeAssistant.callAction(action);
|
|
@@ -167802,7 +168206,7 @@ init_home_assistant_entity_behavior();
|
|
|
167802
168206
|
init_dist();
|
|
167803
168207
|
init_esm();
|
|
167804
168208
|
init_home_assistant_entity_behavior();
|
|
167805
|
-
var
|
|
168209
|
+
var logger229 = Logger.get("MediaPlayerKeypadInputServer");
|
|
167806
168210
|
var MediaPlayerKeypadInputServer = class extends KeypadInputServer {
|
|
167807
168211
|
sendKey(request) {
|
|
167808
168212
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
@@ -167813,12 +168217,12 @@ var MediaPlayerKeypadInputServer = class extends KeypadInputServer {
|
|
|
167813
168217
|
const features = attributes9.supported_features ?? 0;
|
|
167814
168218
|
const action = this.mapKeyToAction(request.keyCode, features);
|
|
167815
168219
|
if (!action) {
|
|
167816
|
-
|
|
168220
|
+
logger229.debug(
|
|
167817
168221
|
`Unsupported key code ${request.keyCode} for ${homeAssistant.entityId}`
|
|
167818
168222
|
);
|
|
167819
168223
|
return { status: KeypadInput3.Status.UnsupportedKey };
|
|
167820
168224
|
}
|
|
167821
|
-
|
|
168225
|
+
logger229.debug(
|
|
167822
168226
|
`sendKey(${request.keyCode}) \u2192 ${action} for ${homeAssistant.entityId}`
|
|
167823
168227
|
);
|
|
167824
168228
|
homeAssistant.callAction({ action });
|
|
@@ -168097,7 +168501,7 @@ init_home_assistant_entity_behavior();
|
|
|
168097
168501
|
// src/matter/behaviors/speaker-level-control-server.ts
|
|
168098
168502
|
init_esm();
|
|
168099
168503
|
init_home_assistant_entity_behavior();
|
|
168100
|
-
var
|
|
168504
|
+
var logger230 = Logger.get("SpeakerLevelControlServer");
|
|
168101
168505
|
var optimisticLevelState2 = /* @__PURE__ */ new Map();
|
|
168102
168506
|
var OPTIMISTIC_TIMEOUT_MS4 = 3e3;
|
|
168103
168507
|
var OPTIMISTIC_TOLERANCE3 = 5;
|
|
@@ -168140,7 +168544,7 @@ var SpeakerLevelControlServerBase = class extends FeaturedBase9 {
|
|
|
168140
168544
|
currentLevel = Math.min(Math.max(minLevel, currentLevel), maxLevel);
|
|
168141
168545
|
}
|
|
168142
168546
|
const entityId = this.agent.get(HomeAssistantEntityBehavior).entity.entity_id;
|
|
168143
|
-
|
|
168547
|
+
logger230.debug(
|
|
168144
168548
|
`[${entityId}] Volume update: HA=${currentLevelPercent != null ? Math.round(currentLevelPercent * 100) : "null"}% -> currentLevel=${currentLevel}`
|
|
168145
168549
|
);
|
|
168146
168550
|
const optimistic = optimisticLevelState2.get(entity.entity_id);
|
|
@@ -168188,7 +168592,7 @@ var SpeakerLevelControlServerBase = class extends FeaturedBase9 {
|
|
|
168188
168592
|
const config8 = this.state.config;
|
|
168189
168593
|
const entityId = homeAssistant.entity.entity_id;
|
|
168190
168594
|
const levelPercent = level / 254;
|
|
168191
|
-
|
|
168595
|
+
logger230.debug(
|
|
168192
168596
|
`[${entityId}] Volume command: level=${level} -> HA volume_level=${levelPercent}`
|
|
168193
168597
|
);
|
|
168194
168598
|
const current = config8.getValuePercent(
|
|
@@ -169075,6 +169479,7 @@ var ElectricalUtilityMeterType = ElectricalUtilityMeterDevice.with(
|
|
|
169075
169479
|
|
|
169076
169480
|
// src/matter/endpoints/legacy/sensor/devices/energy-evse.ts
|
|
169077
169481
|
init_esm();
|
|
169482
|
+
init_types2();
|
|
169078
169483
|
init_home_assistant_actions();
|
|
169079
169484
|
init_home_assistant_entity_behavior();
|
|
169080
169485
|
|
|
@@ -169132,7 +169537,7 @@ function mapEvseStatus(rawState, chargingSwitchOn) {
|
|
|
169132
169537
|
}
|
|
169133
169538
|
|
|
169134
169539
|
// src/matter/endpoints/legacy/sensor/devices/energy-evse.ts
|
|
169135
|
-
var
|
|
169540
|
+
var logger231 = Logger.get("EnergyEvse");
|
|
169136
169541
|
var MIN_CHARGE_CURRENT_MA = 6e3;
|
|
169137
169542
|
var MAX_CHARGE_CURRENT_MA = 32e3;
|
|
169138
169543
|
var CIRCUIT_CAPACITY_MA = 32e3;
|
|
@@ -169216,7 +169621,7 @@ var EvseStatusServer = class _EvseStatusServer extends EnergyEvseServer {
|
|
|
169216
169621
|
dispatched = true;
|
|
169217
169622
|
}
|
|
169218
169623
|
if (!dispatched) {
|
|
169219
|
-
|
|
169624
|
+
logger231.debug(
|
|
169220
169625
|
`enableCharging ignored for ${homeAssistant.entityId}: no charging switch or current limit mapped`
|
|
169221
169626
|
);
|
|
169222
169627
|
return;
|
|
@@ -169256,7 +169661,7 @@ var EvseStatusServer = class _EvseStatusServer extends EnergyEvseServer {
|
|
|
169256
169661
|
chargingEnabledUntil: null
|
|
169257
169662
|
});
|
|
169258
169663
|
} catch (error) {
|
|
169259
|
-
|
|
169664
|
+
logger231.debug(
|
|
169260
169665
|
`EVSE charge-window expiry write failed (endpoint may be closing): ${error}`
|
|
169261
169666
|
);
|
|
169262
169667
|
} finally {
|
|
@@ -169287,7 +169692,7 @@ var EvseStatusServer = class _EvseStatusServer extends EnergyEvseServer {
|
|
|
169287
169692
|
chargingEnabledUntil: null
|
|
169288
169693
|
});
|
|
169289
169694
|
} else {
|
|
169290
|
-
|
|
169695
|
+
logger231.debug(
|
|
169291
169696
|
`disable ignored for ${homeAssistant.entityId}: no charging switch mapped`
|
|
169292
169697
|
);
|
|
169293
169698
|
}
|
|
@@ -170092,7 +170497,7 @@ var TvocConcentrationMeasurementServer = class extends TvocConcentrationMeasurem
|
|
|
170092
170497
|
};
|
|
170093
170498
|
|
|
170094
170499
|
// src/matter/endpoints/legacy/sensor/devices/tvoc-sensor.ts
|
|
170095
|
-
var
|
|
170500
|
+
var logger232 = Logger.get("TvocSensor");
|
|
170096
170501
|
function airQualityFromUgm3(value) {
|
|
170097
170502
|
if (value <= 300) return AirQuality3.AirQualityEnum.Good;
|
|
170098
170503
|
if (value <= 1e3) return AirQuality3.AirQualityEnum.Fair;
|
|
@@ -170133,17 +170538,17 @@ var TvocAirQualityServer = class extends TvocAirQualityServerBase {
|
|
|
170133
170538
|
const attributes9 = entity.state.attributes;
|
|
170134
170539
|
const deviceClass = attributes9.device_class;
|
|
170135
170540
|
let airQuality = AirQuality3.AirQualityEnum.Unknown;
|
|
170136
|
-
|
|
170541
|
+
logger232.debug(
|
|
170137
170542
|
`[${entity.entity_id}] TVOC update: state="${state}", device_class="${deviceClass}"`
|
|
170138
170543
|
);
|
|
170139
170544
|
if (state != null && !Number.isNaN(+state)) {
|
|
170140
170545
|
const value = +state;
|
|
170141
170546
|
airQuality = deviceClass === SensorDeviceClass.volatile_organic_compounds ? airQualityFromUgm3(value) : airQualityFromPpb(value);
|
|
170142
|
-
|
|
170547
|
+
logger232.debug(
|
|
170143
170548
|
`[${entity.entity_id}] TVOC value=${value} (${deviceClass}) -> airQuality=${AirQuality3.AirQualityEnum[airQuality]}`
|
|
170144
170549
|
);
|
|
170145
170550
|
} else {
|
|
170146
|
-
|
|
170551
|
+
logger232.warn(
|
|
170147
170552
|
`[${entity.entity_id}] TVOC state not a valid number: "${state}"`
|
|
170148
170553
|
);
|
|
170149
170554
|
}
|
|
@@ -170160,6 +170565,7 @@ var TvocSensorType = AirQualitySensorDevice.with(
|
|
|
170160
170565
|
|
|
170161
170566
|
// src/matter/endpoints/legacy/sensor/index.ts
|
|
170162
170567
|
init_dist();
|
|
170568
|
+
init_types2();
|
|
170163
170569
|
init_diagnostic_event_bus();
|
|
170164
170570
|
|
|
170165
170571
|
// src/matter/behaviors/carbon-dioxide-concentration-measurement-server.ts
|
|
@@ -170357,7 +170763,7 @@ init_home_assistant_entity_behavior();
|
|
|
170357
170763
|
// src/matter/behaviors/pm25-concentration-measurement-server.ts
|
|
170358
170764
|
init_esm();
|
|
170359
170765
|
init_home_assistant_entity_behavior();
|
|
170360
|
-
var
|
|
170766
|
+
var logger233 = Logger.get("Pm25ConcentrationMeasurementServer");
|
|
170361
170767
|
var Pm25ConcentrationMeasurementServerBase = Pm25ConcentrationMeasurementServer.with(
|
|
170362
170768
|
ConcentrationMeasurement3.Feature.NumericMeasurement
|
|
170363
170769
|
);
|
|
@@ -170381,11 +170787,11 @@ var Pm25ConcentrationMeasurementServer2 = class extends Pm25ConcentrationMeasure
|
|
|
170381
170787
|
if (this.state.measurementMedium === void 0) {
|
|
170382
170788
|
this.state.measurementMedium = ConcentrationMeasurement3.MeasurementMedium.Air;
|
|
170383
170789
|
}
|
|
170384
|
-
|
|
170790
|
+
logger233.debug(
|
|
170385
170791
|
"Pm25ConcentrationMeasurementServer: before super.initialize()"
|
|
170386
170792
|
);
|
|
170387
170793
|
await super.initialize();
|
|
170388
|
-
|
|
170794
|
+
logger233.debug(
|
|
170389
170795
|
"Pm25ConcentrationMeasurementServer: after super.initialize()"
|
|
170390
170796
|
);
|
|
170391
170797
|
const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
|
|
@@ -170408,7 +170814,7 @@ var Pm25ConcentrationMeasurementServer2 = class extends Pm25ConcentrationMeasure
|
|
|
170408
170814
|
};
|
|
170409
170815
|
|
|
170410
170816
|
// src/matter/endpoints/legacy/sensor/devices/pm25-sensor.ts
|
|
170411
|
-
var
|
|
170817
|
+
var logger234 = Logger.get("Pm25AirQualityServer");
|
|
170412
170818
|
var Pm25AirQualityServerBase = AirQualityServer.with(
|
|
170413
170819
|
AirQuality3.Feature.Fair,
|
|
170414
170820
|
AirQuality3.Feature.Moderate,
|
|
@@ -170420,9 +170826,9 @@ var Pm25AirQualityServer = class extends Pm25AirQualityServerBase {
|
|
|
170420
170826
|
if (this.state.airQuality === void 0) {
|
|
170421
170827
|
this.state.airQuality = AirQuality3.AirQualityEnum.Unknown;
|
|
170422
170828
|
}
|
|
170423
|
-
|
|
170829
|
+
logger234.debug("Pm25AirQualityServer: before super.initialize()");
|
|
170424
170830
|
await super.initialize();
|
|
170425
|
-
|
|
170831
|
+
logger234.debug("Pm25AirQualityServer: after super.initialize()");
|
|
170426
170832
|
const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
|
|
170427
170833
|
this.update(homeAssistant.entity);
|
|
170428
170834
|
this.reactTo(homeAssistant.onChange, this.update, { offline: true });
|
|
@@ -170847,56 +171253,25 @@ init_home_assistant_entity_behavior();
|
|
|
170847
171253
|
init_dist();
|
|
170848
171254
|
init_esm();
|
|
170849
171255
|
init_home_assistant_entity_behavior();
|
|
170850
|
-
var
|
|
170851
|
-
var IDENTIFY_BUTTON_SUFFIXES = ["_identify", "_locate", "_find_me"];
|
|
171256
|
+
var logger235 = Logger.get("VacuumIdentifyServer");
|
|
170852
171257
|
var VacuumIdentifyServer = class extends IdentifyServer2 {
|
|
170853
|
-
|
|
170854
|
-
this.#locate("triggerEffect");
|
|
170855
|
-
return super.triggerEffect(effect);
|
|
170856
|
-
}
|
|
170857
|
-
identify(request) {
|
|
170858
|
-
if (request.identifyTime > 0) {
|
|
170859
|
-
this.#locate("identify");
|
|
170860
|
-
}
|
|
170861
|
-
return super.identify(request);
|
|
170862
|
-
}
|
|
170863
|
-
#locate(source) {
|
|
171258
|
+
identifyInHomeAssistant(source) {
|
|
170864
171259
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
170865
171260
|
const features = homeAssistant.entity.state.attributes.supported_features ?? 0;
|
|
170866
171261
|
if (testBit(features, VacuumDeviceFeature.LOCATE)) {
|
|
170867
|
-
|
|
171262
|
+
logger235.info(`${source} \u2192 vacuum.locate for ${homeAssistant.entityId}`);
|
|
170868
171263
|
homeAssistant.callAction({ action: "vacuum.locate" });
|
|
170869
171264
|
return;
|
|
170870
171265
|
}
|
|
170871
|
-
|
|
170872
|
-
|
|
170873
|
-
logger233.info(
|
|
170874
|
-
`${source} \u2192 button.press ${sibling} for ${homeAssistant.entityId}`
|
|
170875
|
-
);
|
|
170876
|
-
homeAssistant.callAction({ action: "button.press", target: sibling });
|
|
171266
|
+
if (this.findIdentifyEntity(homeAssistant)) {
|
|
171267
|
+
super.identifyInHomeAssistant(source);
|
|
170877
171268
|
return;
|
|
170878
171269
|
}
|
|
170879
|
-
|
|
171270
|
+
logger235.warn(
|
|
170880
171271
|
`${source} for ${homeAssistant.entityId}, LOCATE not in supported_features (${features}), trying vacuum.locate anyway`
|
|
170881
171272
|
);
|
|
170882
171273
|
homeAssistant.callAction({ action: "vacuum.locate" });
|
|
170883
171274
|
}
|
|
170884
|
-
#findIdentifyButton(homeAssistant) {
|
|
170885
|
-
const deviceId = homeAssistant.entity.registry?.device_id;
|
|
170886
|
-
if (!deviceId) return void 0;
|
|
170887
|
-
const registry3 = this.env.get(HomeAssistantRegistry);
|
|
170888
|
-
for (const entity of Object.values(registry3.entities)) {
|
|
170889
|
-
if (entity.device_id !== deviceId) continue;
|
|
170890
|
-
if (!entity.entity_id.startsWith("button.")) continue;
|
|
170891
|
-
const uniqueId = entity.unique_id ?? "";
|
|
170892
|
-
if (IDENTIFY_BUTTON_SUFFIXES.some(
|
|
170893
|
-
(s) => entity.entity_id.endsWith(s) || uniqueId.endsWith(s)
|
|
170894
|
-
)) {
|
|
170895
|
-
return entity.entity_id;
|
|
170896
|
-
}
|
|
170897
|
-
}
|
|
170898
|
-
return void 0;
|
|
170899
|
-
}
|
|
170900
171275
|
};
|
|
170901
171276
|
|
|
170902
171277
|
// src/matter/endpoints/legacy/vacuum/behaviors/vacuum-rvc-run-mode-server.ts
|
|
@@ -171076,7 +171451,7 @@ init_esm();
|
|
|
171076
171451
|
// src/matter/behaviors/service-area-server.ts
|
|
171077
171452
|
init_esm();
|
|
171078
171453
|
init_home_assistant_entity_behavior();
|
|
171079
|
-
var
|
|
171454
|
+
var logger236 = Logger.get("ServiceAreaServer");
|
|
171080
171455
|
function orderSelection(areas, agent) {
|
|
171081
171456
|
try {
|
|
171082
171457
|
const ascending = agent?.get(HomeAssistantEntityBehavior).state.mapping?.vacuumAscendingRoomOrder === true;
|
|
@@ -171091,7 +171466,7 @@ var ServiceAreaWithProgress = ServiceAreaBehavior.with(
|
|
|
171091
171466
|
var ServiceAreaServerBase = class extends ServiceAreaWithProgress {
|
|
171092
171467
|
selectAreas(request) {
|
|
171093
171468
|
const { newAreas } = request;
|
|
171094
|
-
|
|
171469
|
+
logger236.info(
|
|
171095
171470
|
`ServiceArea selectAreas called with: ${JSON.stringify(newAreas)}`
|
|
171096
171471
|
);
|
|
171097
171472
|
const uniqueAreas = orderSelection([...new Set(newAreas)], this.agent);
|
|
@@ -171100,7 +171475,7 @@ var ServiceAreaServerBase = class extends ServiceAreaWithProgress {
|
|
|
171100
171475
|
(id) => !supportedAreaIds.includes(id)
|
|
171101
171476
|
);
|
|
171102
171477
|
if (invalidAreas.length > 0) {
|
|
171103
|
-
|
|
171478
|
+
logger236.warn(`Invalid area IDs requested: ${invalidAreas.join(", ")}`);
|
|
171104
171479
|
return {
|
|
171105
171480
|
status: ServiceArea3.SelectAreasStatus.UnsupportedArea,
|
|
171106
171481
|
statusText: `Invalid area IDs: ${invalidAreas.join(", ")}`
|
|
@@ -171112,7 +171487,7 @@ var ServiceAreaServerBase = class extends ServiceAreaWithProgress {
|
|
|
171112
171487
|
status: ServiceArea3.OperationalStatus.Pending
|
|
171113
171488
|
}));
|
|
171114
171489
|
this.state.currentArea = null;
|
|
171115
|
-
|
|
171490
|
+
logger236.info(
|
|
171116
171491
|
`ServiceArea: Stored ${uniqueAreas.length} areas for cleaning: ${uniqueAreas.join(", ")}`
|
|
171117
171492
|
);
|
|
171118
171493
|
return {
|
|
@@ -171133,7 +171508,7 @@ var ServiceAreaServerBase = class extends ServiceAreaWithProgress {
|
|
|
171133
171508
|
ServiceAreaServerBase2.State = State;
|
|
171134
171509
|
})(ServiceAreaServerBase || (ServiceAreaServerBase = {}));
|
|
171135
171510
|
function ServiceAreaServer2(initialState) {
|
|
171136
|
-
|
|
171511
|
+
logger236.info(
|
|
171137
171512
|
`Creating ServiceAreaServer with ${initialState.supportedAreas.length} areas`
|
|
171138
171513
|
);
|
|
171139
171514
|
return ServiceAreaServerBase.set({
|
|
@@ -171150,7 +171525,7 @@ var ServiceAreaWithMapsAndProgress = ServiceAreaBehavior.with(
|
|
|
171150
171525
|
var ServiceAreaServerWithMapsBase = class extends ServiceAreaWithMapsAndProgress {
|
|
171151
171526
|
selectAreas(request) {
|
|
171152
171527
|
const { newAreas } = request;
|
|
171153
|
-
|
|
171528
|
+
logger236.info(
|
|
171154
171529
|
`ServiceArea selectAreas called with: ${JSON.stringify(newAreas)}`
|
|
171155
171530
|
);
|
|
171156
171531
|
const uniqueAreas = orderSelection([...new Set(newAreas)], this.agent);
|
|
@@ -171159,7 +171534,7 @@ var ServiceAreaServerWithMapsBase = class extends ServiceAreaWithMapsAndProgress
|
|
|
171159
171534
|
(id) => !supportedAreaIds.includes(id)
|
|
171160
171535
|
);
|
|
171161
171536
|
if (invalidAreas.length > 0) {
|
|
171162
|
-
|
|
171537
|
+
logger236.warn(`Invalid area IDs requested: ${invalidAreas.join(", ")}`);
|
|
171163
171538
|
return {
|
|
171164
171539
|
status: ServiceArea3.SelectAreasStatus.UnsupportedArea,
|
|
171165
171540
|
statusText: `Invalid area IDs: ${invalidAreas.join(", ")}`
|
|
@@ -171171,7 +171546,7 @@ var ServiceAreaServerWithMapsBase = class extends ServiceAreaWithMapsAndProgress
|
|
|
171171
171546
|
status: ServiceArea3.OperationalStatus.Pending
|
|
171172
171547
|
}));
|
|
171173
171548
|
this.state.currentArea = null;
|
|
171174
|
-
|
|
171549
|
+
logger236.info(
|
|
171175
171550
|
`ServiceArea: Stored ${uniqueAreas.length} areas for cleaning: ${uniqueAreas.join(", ")}`
|
|
171176
171551
|
);
|
|
171177
171552
|
return {
|
|
@@ -171192,14 +171567,14 @@ var ServiceAreaServerWithMapsBase = class extends ServiceAreaWithMapsAndProgress
|
|
|
171192
171567
|
ServiceAreaServerWithMapsBase2.State = State;
|
|
171193
171568
|
})(ServiceAreaServerWithMapsBase || (ServiceAreaServerWithMapsBase = {}));
|
|
171194
171569
|
function ServiceAreaServerWithMaps(initialState) {
|
|
171195
|
-
|
|
171570
|
+
logger236.info(
|
|
171196
171571
|
`Creating ServiceAreaServer with Maps: ${initialState.supportedAreas.length} areas, ${initialState.supportedMaps.length} maps`
|
|
171197
171572
|
);
|
|
171198
171573
|
for (const map of initialState.supportedMaps) {
|
|
171199
171574
|
const areaCount = initialState.supportedAreas.filter(
|
|
171200
171575
|
(a) => a.mapId === map.mapId
|
|
171201
171576
|
).length;
|
|
171202
|
-
|
|
171577
|
+
logger236.info(` Map ${map.mapId}: "${map.name}" (${areaCount} areas)`);
|
|
171203
171578
|
}
|
|
171204
171579
|
return ServiceAreaServerWithMapsBase.set({
|
|
171205
171580
|
supportedAreas: initialState.supportedAreas,
|
|
@@ -171211,7 +171586,7 @@ function ServiceAreaServerWithMaps(initialState) {
|
|
|
171211
171586
|
}
|
|
171212
171587
|
|
|
171213
171588
|
// src/matter/endpoints/legacy/vacuum/behaviors/vacuum-service-area-server.ts
|
|
171214
|
-
var
|
|
171589
|
+
var logger237 = Logger.get("VacuumServiceAreaServer");
|
|
171215
171590
|
function toAreaId(roomId) {
|
|
171216
171591
|
if (typeof roomId === "number") {
|
|
171217
171592
|
return roomId;
|
|
@@ -171290,13 +171665,13 @@ function createVacuumServiceAreaServer(attributes9, roomEntities, includeUnnamed
|
|
|
171290
171665
|
let rooms;
|
|
171291
171666
|
if (roomEntities && roomEntities.length > 0) {
|
|
171292
171667
|
rooms = buttonEntitiesToRooms(roomEntities, attributes9);
|
|
171293
|
-
|
|
171668
|
+
logger237.info(
|
|
171294
171669
|
`Using ${rooms.length} button entities as rooms: ${rooms.map((r) => r.name).join(", ")}`
|
|
171295
171670
|
);
|
|
171296
171671
|
} else {
|
|
171297
171672
|
rooms = parseVacuumRooms(attributes9, includeUnnamedRooms);
|
|
171298
171673
|
if (rooms.length > 0) {
|
|
171299
|
-
|
|
171674
|
+
logger237.info(
|
|
171300
171675
|
`Using ${rooms.length} rooms from attributes: ${rooms.map((r) => r.name).join(", ")}`
|
|
171301
171676
|
);
|
|
171302
171677
|
}
|
|
@@ -171350,7 +171725,7 @@ function createCustomServiceAreaServer(customAreas) {
|
|
|
171350
171725
|
landmarkInfo: null
|
|
171351
171726
|
}
|
|
171352
171727
|
}));
|
|
171353
|
-
|
|
171728
|
+
logger237.info(
|
|
171354
171729
|
`Using ${customAreas.length} custom service areas: ${customAreas.map((a) => a.name).join(", ")}`
|
|
171355
171730
|
);
|
|
171356
171731
|
return ServiceAreaServer2({
|
|
@@ -171372,7 +171747,7 @@ function createCleanAreaServiceAreaServer(cleanAreaRooms) {
|
|
|
171372
171747
|
landmarkInfo: null
|
|
171373
171748
|
}
|
|
171374
171749
|
}));
|
|
171375
|
-
|
|
171750
|
+
logger237.info(
|
|
171376
171751
|
`Using ${cleanAreaRooms.length} HA areas via CLEAN_AREA: ${cleanAreaRooms.map((r) => r.name).join(", ")}`
|
|
171377
171752
|
);
|
|
171378
171753
|
return ServiceAreaServer2({
|
|
@@ -171408,11 +171783,11 @@ function getVacuumServiceAreas(attributes9, mapping) {
|
|
|
171408
171783
|
}
|
|
171409
171784
|
|
|
171410
171785
|
// src/matter/endpoints/legacy/vacuum/behaviors/vacuum-rvc-run-mode-server.ts
|
|
171411
|
-
var
|
|
171786
|
+
var logger238 = Logger.get("VacuumRvcRunModeServer");
|
|
171412
171787
|
function buildValetudoSegmentAction(vacuumEntityId, segmentIds, valetudoIdentifier) {
|
|
171413
171788
|
const identifier = valetudoIdentifier || vacuumEntityId.replace(/^vacuum\.valetudo_/, "");
|
|
171414
171789
|
const topic = `valetudo/${identifier}/MapSegmentationCapability/clean/set`;
|
|
171415
|
-
|
|
171790
|
+
logger238.info(
|
|
171416
171791
|
`Valetudo: mqtt.publish to ${topic}, segments: ${segmentIds.join(", ")}`
|
|
171417
171792
|
);
|
|
171418
171793
|
return {
|
|
@@ -171517,14 +171892,14 @@ function mergeBatchData(areas) {
|
|
|
171517
171892
|
function handleCustomServiceAreas(selectedAreas, customAreas, session) {
|
|
171518
171893
|
const matched = selectedAreas.map((areaId) => ({ areaId, area: customAreas[areaId - 1] })).filter((m) => !!m.area);
|
|
171519
171894
|
if (matched.length === 0) {
|
|
171520
|
-
|
|
171895
|
+
logger238.warn(
|
|
171521
171896
|
`Custom service areas: no match for selected IDs ${selectedAreas.join(", ")}`
|
|
171522
171897
|
);
|
|
171523
171898
|
return { action: "vacuum.start" };
|
|
171524
171899
|
}
|
|
171525
171900
|
const batchArea = matched.find(({ area }) => area.batchDispatch === true);
|
|
171526
171901
|
if (batchArea) {
|
|
171527
|
-
|
|
171902
|
+
logger238.info(
|
|
171528
171903
|
`Custom service areas (batch): single call for ${matched.length} room(s): ${matched.map(({ area }) => area.name).join(", ")}`
|
|
171529
171904
|
);
|
|
171530
171905
|
session.pendingDispatches = [];
|
|
@@ -171545,7 +171920,7 @@ function handleCustomServiceAreas(selectedAreas, customAreas, session) {
|
|
|
171545
171920
|
}
|
|
171546
171921
|
};
|
|
171547
171922
|
}
|
|
171548
|
-
|
|
171923
|
+
logger238.info(
|
|
171549
171924
|
`Custom service areas: ${matched.length} room(s) queued: ${matched.map(({ area }) => `${area.service} (${area.name})`).join(", ")}`
|
|
171550
171925
|
);
|
|
171551
171926
|
session.pendingDispatches = matched.slice(1).map(({ areaId, area }) => ({
|
|
@@ -171603,7 +171978,7 @@ function dispatchRoomClean(attributes9, mapping, entityId, selectedAreas, seam)
|
|
|
171603
171978
|
if (cleanAreaRooms && cleanAreaRooms.length > 0) {
|
|
171604
171979
|
const haAreaIds = resolveCleanAreaIds(selectedAreas, cleanAreaRooms);
|
|
171605
171980
|
if (haAreaIds.length > 0) {
|
|
171606
|
-
|
|
171981
|
+
logger238.info(`CLEAN_AREA: cleaning HA areas: ${haAreaIds.join(", ")}`);
|
|
171607
171982
|
return {
|
|
171608
171983
|
action: {
|
|
171609
171984
|
action: "vacuum.clean_area",
|
|
@@ -171623,7 +171998,7 @@ function dispatchRoomClean(attributes9, mapping, entityId, selectedAreas, seam)
|
|
|
171623
171998
|
}
|
|
171624
171999
|
}
|
|
171625
172000
|
if (matched.length > 0) {
|
|
171626
|
-
|
|
172001
|
+
logger238.info(
|
|
171627
172002
|
`Roborock: ${matched.length} room button(s) queued: ${matched.map((m) => m.entityId).join(", ")}`
|
|
171628
172003
|
);
|
|
171629
172004
|
return {
|
|
@@ -171658,12 +172033,12 @@ function dispatchRoomClean(attributes9, mapping, entityId, selectedAreas, seam)
|
|
|
171658
172033
|
}
|
|
171659
172034
|
}
|
|
171660
172035
|
if (roomIds.length > 0) {
|
|
171661
|
-
|
|
172036
|
+
logger238.info(`Starting cleaning with selected areas: ${roomIds.join(", ")}`);
|
|
171662
172037
|
if (isDreameVacuum(attributes9)) {
|
|
171663
172038
|
if (targetMapName) {
|
|
171664
172039
|
const vacName = entityId.replace("vacuum.", "");
|
|
171665
172040
|
const selectedMapEntity = `select.${vacName}_selected_map`;
|
|
171666
|
-
|
|
172041
|
+
logger238.info(
|
|
171667
172042
|
`Dreame multi-floor: switching to map "${targetMapName}" via ${selectedMapEntity}`
|
|
171668
172043
|
);
|
|
171669
172044
|
seam.callAction({
|
|
@@ -171691,7 +172066,7 @@ function dispatchRoomClean(attributes9, mapping, entityId, selectedAreas, seam)
|
|
|
171691
172066
|
}
|
|
171692
172067
|
if (isEcovacsVacuum(attributes9)) {
|
|
171693
172068
|
const roomIdStr = roomIds.join(",");
|
|
171694
|
-
|
|
172069
|
+
logger238.info(`Ecovacs vacuum: Using spot_area for rooms: ${roomIdStr}`);
|
|
171695
172070
|
return {
|
|
171696
172071
|
action: {
|
|
171697
172072
|
action: "vacuum.send_command",
|
|
@@ -171703,7 +172078,7 @@ function dispatchRoomClean(attributes9, mapping, entityId, selectedAreas, seam)
|
|
|
171703
172078
|
pending: []
|
|
171704
172079
|
};
|
|
171705
172080
|
}
|
|
171706
|
-
|
|
172081
|
+
logger238.warn(
|
|
171707
172082
|
`Room cleaning via send_command not supported for this vacuum type. Rooms: ${roomIds.join(", ")}. Falling back to vacuum.start`
|
|
171708
172083
|
);
|
|
171709
172084
|
}
|
|
@@ -171712,7 +172087,7 @@ function dispatchRoomClean(attributes9, mapping, entityId, selectedAreas, seam)
|
|
|
171712
172087
|
var vacuumRvcRunModeConfig = {
|
|
171713
172088
|
getCurrentMode: (entity) => {
|
|
171714
172089
|
const isCleaning = vacuumIsCleaning(entity.state);
|
|
171715
|
-
|
|
172090
|
+
logger238.debug(
|
|
171716
172091
|
`Vacuum state: "${entity.state}", isCleaning: ${isCleaning}, currentMode: ${isCleaning ? "Cleaning" : "Idle"}`
|
|
171717
172092
|
);
|
|
171718
172093
|
return isCleaning ? 1 /* Cleaning */ : 0 /* Idle */;
|
|
@@ -171751,7 +172126,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
171751
172126
|
}
|
|
171752
172127
|
} catch {
|
|
171753
172128
|
}
|
|
171754
|
-
|
|
172129
|
+
logger238.info("Starting regular cleaning (no areas selected)");
|
|
171755
172130
|
return { action: "vacuum.start" };
|
|
171756
172131
|
},
|
|
171757
172132
|
returnToBase: () => ({ action: "vacuum.return_to_base" }),
|
|
@@ -171766,7 +172141,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
171766
172141
|
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
171767
172142
|
const entity = homeAssistant.entity;
|
|
171768
172143
|
const attributes9 = entity.state.attributes;
|
|
171769
|
-
|
|
172144
|
+
logger238.info(`cleanRoom called: roomMode=${roomMode}`);
|
|
171770
172145
|
const cleanAreaRooms = homeAssistant.state.mapping?.cleanAreaRooms;
|
|
171771
172146
|
if (cleanAreaRooms && cleanAreaRooms.length > 0) {
|
|
171772
172147
|
const sorted = [...cleanAreaRooms].sort(
|
|
@@ -171775,7 +172150,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
171775
172150
|
const areaIndex = roomMode - ROOM_MODE_BASE2 - 1;
|
|
171776
172151
|
if (areaIndex >= 0 && areaIndex < sorted.length) {
|
|
171777
172152
|
const area = sorted[areaIndex];
|
|
171778
|
-
|
|
172153
|
+
logger238.info(
|
|
171779
172154
|
`cleanRoom: CLEAN_AREA "${area.name}" \u2192 vacuum.clean_area(${area.haAreaId})`
|
|
171780
172155
|
);
|
|
171781
172156
|
return {
|
|
@@ -171792,7 +172167,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
171792
172167
|
const areaIndex = roomMode - ROOM_MODE_BASE2 - 1;
|
|
171793
172168
|
if (areaIndex >= 0 && areaIndex < sorted.length) {
|
|
171794
172169
|
const area = sorted[areaIndex];
|
|
171795
|
-
|
|
172170
|
+
logger238.info(
|
|
171796
172171
|
`cleanRoom: custom service area "${area.name}" \u2192 ${area.service}`
|
|
171797
172172
|
);
|
|
171798
172173
|
return {
|
|
@@ -171813,7 +172188,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
171813
172188
|
}
|
|
171814
172189
|
const rooms = parseVacuumRooms(attributes9);
|
|
171815
172190
|
const numericIdFromMode = getRoomIdFromMode(roomMode);
|
|
171816
|
-
|
|
172191
|
+
logger238.info(
|
|
171817
172192
|
`cleanRoom: numericIdFromMode=${numericIdFromMode}, available rooms: ${JSON.stringify(rooms.map((r) => ({ id: r.id, name: r.name, modeValue: getRoomModeValue(r) })))}`
|
|
171818
172193
|
);
|
|
171819
172194
|
const room = rooms.find((r) => getRoomModeValue(r) === roomMode);
|
|
@@ -171823,7 +172198,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
171823
172198
|
if (room.mapName) {
|
|
171824
172199
|
const vacuumName = vacuumEntityId.replace("vacuum.", "");
|
|
171825
172200
|
const selectedMapEntity = `select.${vacuumName}_selected_map`;
|
|
171826
|
-
|
|
172201
|
+
logger238.info(
|
|
171827
172202
|
`Dreame multi-floor: switching to map "${room.mapName}" via ${selectedMapEntity}`
|
|
171828
172203
|
);
|
|
171829
172204
|
homeAssistant.callAction({
|
|
@@ -171832,7 +172207,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
171832
172207
|
data: { option: room.mapName }
|
|
171833
172208
|
});
|
|
171834
172209
|
}
|
|
171835
|
-
|
|
172210
|
+
logger238.debug(
|
|
171836
172211
|
`Dreame vacuum detected, using dreame_vacuum.vacuum_clean_segment for room ${room.name} (commandId: ${commandId3}, id: ${room.id})`
|
|
171837
172212
|
);
|
|
171838
172213
|
return {
|
|
@@ -171843,7 +172218,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
171843
172218
|
};
|
|
171844
172219
|
}
|
|
171845
172220
|
if (isRoborockVacuum(attributes9) || isXiaomiMiotVacuum(attributes9)) {
|
|
171846
|
-
|
|
172221
|
+
logger238.debug(
|
|
171847
172222
|
`Using vacuum.send_command with app_segment_clean for room ${room.name} (commandId: ${commandId3}, id: ${room.id})`
|
|
171848
172223
|
);
|
|
171849
172224
|
return {
|
|
@@ -171856,7 +172231,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
171856
172231
|
}
|
|
171857
172232
|
if (isEcovacsVacuum(attributes9)) {
|
|
171858
172233
|
const roomIdStr = String(commandId3);
|
|
171859
|
-
|
|
172234
|
+
logger238.info(
|
|
171860
172235
|
`Ecovacs vacuum: Using spot_area for room ${room.name} (id: ${roomIdStr})`
|
|
171861
172236
|
);
|
|
171862
172237
|
return {
|
|
@@ -171871,7 +172246,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
171871
172246
|
}
|
|
171872
172247
|
};
|
|
171873
172248
|
}
|
|
171874
|
-
|
|
172249
|
+
logger238.warn(
|
|
171875
172250
|
`Room cleaning via send_command not supported for this vacuum type. Room: ${room.name} (id=${commandId3}). Falling back to vacuum.start`
|
|
171876
172251
|
);
|
|
171877
172252
|
}
|
|
@@ -171888,20 +172263,20 @@ function createVacuumRvcRunModeServer(attributes9, includeUnnamedRooms = false,
|
|
|
171888
172263
|
customAreas,
|
|
171889
172264
|
disableRoomModes
|
|
171890
172265
|
);
|
|
171891
|
-
|
|
172266
|
+
logger238.info(
|
|
171892
172267
|
`Creating VacuumRvcRunModeServer with ${rooms.length} rooms, ${supportedModes2.length} total modes`
|
|
171893
172268
|
);
|
|
171894
172269
|
if (rooms.length > 0) {
|
|
171895
|
-
|
|
172270
|
+
logger238.info(`Rooms found: ${rooms.map((r) => r.name).join(", ")}`);
|
|
171896
172271
|
}
|
|
171897
172272
|
if (filteredCount > 0) {
|
|
171898
172273
|
const filtered = allRooms.filter((r) => !rooms.some((x) => x.id === r.id));
|
|
171899
|
-
|
|
172274
|
+
logger238.info(
|
|
171900
172275
|
`Filtered out ${filteredCount} unnamed room(s): ${filtered.map((r) => r.name).join(", ")}`
|
|
171901
172276
|
);
|
|
171902
172277
|
}
|
|
171903
172278
|
if (allRooms.length === 0) {
|
|
171904
|
-
|
|
172279
|
+
logger238.debug(
|
|
171905
172280
|
`No rooms found. Attributes: rooms=${JSON.stringify(attributes9.rooms)}, segments=${JSON.stringify(attributes9.segments)}, room_list=${attributes9.room_list}`
|
|
171906
172281
|
);
|
|
171907
172282
|
}
|
|
@@ -171935,7 +172310,7 @@ function createCleanAreaRvcRunModeServer(cleanAreaRooms) {
|
|
|
171935
172310
|
modeTags: [{ value: RvcRunMode3.ModeTag.Cleaning }]
|
|
171936
172311
|
});
|
|
171937
172312
|
}
|
|
171938
|
-
|
|
172313
|
+
logger238.info(
|
|
171939
172314
|
`Creating CLEAN_AREA RvcRunModeServer with ${cleanAreaRooms.length} HA areas, ${modes.length} total modes`
|
|
171940
172315
|
);
|
|
171941
172316
|
return RvcRunModeServer2(vacuumRvcRunModeConfig, {
|
|
@@ -172025,7 +172400,7 @@ init_nodejs();
|
|
|
172025
172400
|
|
|
172026
172401
|
// src/matter/behaviors/rvc-clean-mode-server.ts
|
|
172027
172402
|
init_home_assistant_entity_behavior();
|
|
172028
|
-
var
|
|
172403
|
+
var logger239 = Logger.get("RvcCleanModeServerBase");
|
|
172029
172404
|
var RvcCleanModeServerBase = class _RvcCleanModeServerBase extends RvcCleanModeServer {
|
|
172030
172405
|
// Pending mode from a recent changeToMode command.
|
|
172031
172406
|
// Prevents stale HA state (from a different entity like select.xxx)
|
|
@@ -172072,14 +172447,14 @@ var RvcCleanModeServerBase = class _RvcCleanModeServerBase extends RvcCleanModeS
|
|
|
172072
172447
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
172073
172448
|
const { newMode } = request;
|
|
172074
172449
|
if (newMode !== this.state.currentMode && !this.state.supportedModes.some((m) => m.mode === newMode)) {
|
|
172075
|
-
|
|
172450
|
+
logger239.warn(`changeToMode(${newMode}) rejected: unsupported mode`);
|
|
172076
172451
|
return {
|
|
172077
172452
|
status: ModeBase3.ModeChangeStatus.UnsupportedMode,
|
|
172078
172453
|
statusText: `Unsupported mode: ${newMode}`
|
|
172079
172454
|
};
|
|
172080
172455
|
}
|
|
172081
172456
|
const modeLabel = this.state.supportedModes.find((m) => m.mode === newMode);
|
|
172082
|
-
|
|
172457
|
+
logger239.info(
|
|
172083
172458
|
`changeToMode(${newMode}) "${modeLabel?.label ?? "unknown"}" for ${homeAssistant.entityId}`
|
|
172084
172459
|
);
|
|
172085
172460
|
this.pendingMode = newMode;
|
|
@@ -172087,7 +172462,7 @@ var RvcCleanModeServerBase = class _RvcCleanModeServerBase extends RvcCleanModeS
|
|
|
172087
172462
|
this.state.currentMode = newMode;
|
|
172088
172463
|
const action = this.state.config.setCleanMode(newMode, this.agent);
|
|
172089
172464
|
if (action) {
|
|
172090
|
-
|
|
172465
|
+
logger239.info(
|
|
172091
172466
|
`changeToMode: dispatching action ${action.action} \u2192 ${action.target ?? homeAssistant.entityId}`
|
|
172092
172467
|
);
|
|
172093
172468
|
homeAssistant.callAction(action);
|
|
@@ -172120,7 +172495,7 @@ function RvcCleanModeServer2(config8, initialState) {
|
|
|
172120
172495
|
}
|
|
172121
172496
|
|
|
172122
172497
|
// src/matter/endpoints/legacy/vacuum/behaviors/vacuum-rvc-clean-mode-server.ts
|
|
172123
|
-
var
|
|
172498
|
+
var logger240 = Logger.get("VacuumRvcCleanModeServer");
|
|
172124
172499
|
var MODE_VACUUM = 0;
|
|
172125
172500
|
var MODE_VACUUM_AND_MOP = 1;
|
|
172126
172501
|
var MODE_MOP = 2;
|
|
@@ -172390,7 +172765,7 @@ function findMatchingCleanOption(ct, availableOptions) {
|
|
|
172390
172765
|
const match = availableOptions.find((o) => classifyCleanOption(o) === type);
|
|
172391
172766
|
if (match) return match;
|
|
172392
172767
|
}
|
|
172393
|
-
|
|
172768
|
+
logger240.warn(
|
|
172394
172769
|
`No match for ${CLEAN_TYPE_LABELS[ct]} in [${availableOptions.join(", ")}]`
|
|
172395
172770
|
);
|
|
172396
172771
|
return availableOptions[0];
|
|
@@ -172399,7 +172774,7 @@ function buildCleaningModeAction(targetCleanType, agent) {
|
|
|
172399
172774
|
const selectEntityId = getCleaningModeSelectEntity(agent);
|
|
172400
172775
|
const { options } = readSelectEntity(selectEntityId, agent);
|
|
172401
172776
|
const optionToUse = findMatchingCleanOption(targetCleanType, options);
|
|
172402
|
-
|
|
172777
|
+
logger240.info(
|
|
172403
172778
|
`Switching cleaning mode to: ${optionToUse} via ${selectEntityId}`
|
|
172404
172779
|
);
|
|
172405
172780
|
return {
|
|
@@ -172488,7 +172863,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
172488
172863
|
}
|
|
172489
172864
|
}
|
|
172490
172865
|
if (speedMode !== void 0) {
|
|
172491
|
-
|
|
172866
|
+
logger240.debug(
|
|
172492
172867
|
`Current mode: Vacuum + fan_speed="${speedState}" -> mode ${speedMode}`
|
|
172493
172868
|
);
|
|
172494
172869
|
return speedMode;
|
|
@@ -172509,7 +172884,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
172509
172884
|
}
|
|
172510
172885
|
}
|
|
172511
172886
|
if (mopMode !== void 0) {
|
|
172512
|
-
|
|
172887
|
+
logger240.debug(
|
|
172513
172888
|
`Current mode: Mop + intensity="${state}" -> mode ${mopMode}`
|
|
172514
172889
|
);
|
|
172515
172890
|
return mopMode;
|
|
@@ -172527,14 +172902,14 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
172527
172902
|
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
172528
172903
|
const vacuumEntityId = homeAssistant.entityId;
|
|
172529
172904
|
const mapping = homeAssistant.state.mapping;
|
|
172530
|
-
|
|
172905
|
+
logger240.info(
|
|
172531
172906
|
`setCleanMode(${mode}) for ${vacuumEntityId}, suctionEntity=${mapping?.suctionLevelEntity ?? "none"}, mopEntity=${mapping?.mopIntensityEntity ?? "none"}, fanSpeedList=${JSON.stringify(fanSpeedList ?? [])}, mopIntensityList=${JSON.stringify(mopIntensityList ?? [])}, customTags=${JSON.stringify(customFanSpeedTags ?? {})}`
|
|
172532
172907
|
);
|
|
172533
172908
|
if (mopIntensityList && mopIntensityList.length > 0 && isMopIntensityMode(mode)) {
|
|
172534
172909
|
const mopIndex = mode - MOP_INTENSITY_MODE_BASE;
|
|
172535
172910
|
const mopName = mopIntensityList[mopIndex];
|
|
172536
172911
|
if (!mopName) {
|
|
172537
|
-
|
|
172912
|
+
logger240.warn(`Invalid mop intensity mode index: ${mopIndex}`);
|
|
172538
172913
|
return void 0;
|
|
172539
172914
|
}
|
|
172540
172915
|
if (hasCleanTypes) {
|
|
@@ -172547,18 +172922,18 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
172547
172922
|
mapping.mopIntensityEntity,
|
|
172548
172923
|
agent
|
|
172549
172924
|
);
|
|
172550
|
-
|
|
172925
|
+
logger240.info(
|
|
172551
172926
|
`Mop intensity entity ${mapping.mopIntensityEntity}: current="${state}", options=${JSON.stringify(options ?? [])}`
|
|
172552
172927
|
);
|
|
172553
172928
|
let option = matchMopIntensityOption(mopName, options);
|
|
172554
172929
|
if (!option && options && mopIndex < options.length) {
|
|
172555
172930
|
option = options[mopIndex];
|
|
172556
|
-
|
|
172931
|
+
logger240.info(
|
|
172557
172932
|
`Positional match for mop "${mopName}" -> "${option}" (index ${mopIndex})`
|
|
172558
172933
|
);
|
|
172559
172934
|
}
|
|
172560
172935
|
if (option) {
|
|
172561
|
-
|
|
172936
|
+
logger240.info(
|
|
172562
172937
|
`Setting mop intensity to: ${option} via ${mapping.mopIntensityEntity}`
|
|
172563
172938
|
);
|
|
172564
172939
|
return {
|
|
@@ -172567,11 +172942,11 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
172567
172942
|
target: mapping.mopIntensityEntity
|
|
172568
172943
|
};
|
|
172569
172944
|
}
|
|
172570
|
-
|
|
172945
|
+
logger240.warn(
|
|
172571
172946
|
`No match for mop intensity "${mopName}" in options: [${(options ?? []).join(", ")}]`
|
|
172572
172947
|
);
|
|
172573
172948
|
} else {
|
|
172574
|
-
|
|
172949
|
+
logger240.warn(
|
|
172575
172950
|
`Mop intensity mode ${mode} requested but no mopIntensityEntity configured`
|
|
172576
172951
|
);
|
|
172577
172952
|
}
|
|
@@ -172581,7 +172956,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
172581
172956
|
const fanSpeedIndex = mode - FAN_SPEED_MODE_BASE;
|
|
172582
172957
|
const fanSpeedName = fanSpeedList[fanSpeedIndex];
|
|
172583
172958
|
if (!fanSpeedName) {
|
|
172584
|
-
|
|
172959
|
+
logger240.warn(`Invalid fan speed mode index: ${fanSpeedIndex}`);
|
|
172585
172960
|
return void 0;
|
|
172586
172961
|
}
|
|
172587
172962
|
if (mapping?.suctionLevelEntity) {
|
|
@@ -172594,7 +172969,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
172594
172969
|
mapping.suctionLevelEntity,
|
|
172595
172970
|
agent
|
|
172596
172971
|
);
|
|
172597
|
-
|
|
172972
|
+
logger240.info(
|
|
172598
172973
|
`Suction entity ${mapping.suctionLevelEntity}: current="${state}", options=${JSON.stringify(options ?? [])}`
|
|
172599
172974
|
);
|
|
172600
172975
|
let option = matchFanSpeedOption(
|
|
@@ -172604,12 +172979,12 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
172604
172979
|
);
|
|
172605
172980
|
if (!option && options && fanSpeedIndex < options.length) {
|
|
172606
172981
|
option = options[fanSpeedIndex];
|
|
172607
|
-
|
|
172982
|
+
logger240.info(
|
|
172608
172983
|
`Positional match for fan "${fanSpeedName}" -> "${option}" (index ${fanSpeedIndex})`
|
|
172609
172984
|
);
|
|
172610
172985
|
}
|
|
172611
172986
|
if (option) {
|
|
172612
|
-
|
|
172987
|
+
logger240.info(
|
|
172613
172988
|
`Setting suction to: ${option} via ${mapping.suctionLevelEntity}`
|
|
172614
172989
|
);
|
|
172615
172990
|
return {
|
|
@@ -172618,7 +172993,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
172618
172993
|
target: mapping.suctionLevelEntity
|
|
172619
172994
|
};
|
|
172620
172995
|
}
|
|
172621
|
-
|
|
172996
|
+
logger240.warn(
|
|
172622
172997
|
`No match for fan speed "${fanSpeedName}" in suction options: [${(options ?? []).join(", ")}]`
|
|
172623
172998
|
);
|
|
172624
172999
|
return void 0;
|
|
@@ -172628,7 +173003,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
172628
173003
|
buildCleaningModeAction(0 /* Sweeping */, agent)
|
|
172629
173004
|
);
|
|
172630
173005
|
}
|
|
172631
|
-
|
|
173006
|
+
logger240.info(
|
|
172632
173007
|
`Setting fan speed to: ${fanSpeedName} via vacuum.set_fan_speed`
|
|
172633
173008
|
);
|
|
172634
173009
|
return {
|
|
@@ -172638,7 +173013,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
172638
173013
|
};
|
|
172639
173014
|
}
|
|
172640
173015
|
if (!hasCleanTypes) {
|
|
172641
|
-
|
|
173016
|
+
logger240.debug(
|
|
172642
173017
|
`Ignoring cleaning type change (mode=${mode}): no cleaning mode entity`
|
|
172643
173018
|
);
|
|
172644
173019
|
return void 0;
|
|
@@ -172650,7 +173025,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
172650
173025
|
agent
|
|
172651
173026
|
);
|
|
172652
173027
|
const optionToUse = findMatchingCleanOption(cleanType, availableOptions);
|
|
172653
|
-
|
|
173028
|
+
logger240.info(
|
|
172654
173029
|
`Setting cleaning mode to: ${optionToUse} (mode=${mode}) via ${selectEntityId}`
|
|
172655
173030
|
);
|
|
172656
173031
|
return {
|
|
@@ -172668,10 +173043,10 @@ function createVacuumRvcCleanModeServer(_attributes, fanSpeedList, mopIntensityL
|
|
|
172668
173043
|
cleaningModeOptions,
|
|
172669
173044
|
customFanSpeedTags
|
|
172670
173045
|
);
|
|
172671
|
-
|
|
173046
|
+
logger240.info(
|
|
172672
173047
|
`Creating VacuumRvcCleanModeServer with ${supportedModes2.length} modes (fanSpeedList=${JSON.stringify(fanSpeedList ?? [])}, mopIntensityList=${JSON.stringify(mopIntensityList ?? [])}, cleaningModeOptions=${JSON.stringify(cleaningModeOptions ?? [])}, customTags=${JSON.stringify(customFanSpeedTags ?? {})})`
|
|
172673
173048
|
);
|
|
172674
|
-
|
|
173049
|
+
logger240.info(
|
|
172675
173050
|
`Modes: ${supportedModes2.map((m) => `${m.mode}:${m.label}[${m.modeTags.map((t) => t.value).join(",")}]`).join(", ")}`
|
|
172676
173051
|
);
|
|
172677
173052
|
const initialState = {
|
|
@@ -172734,7 +173109,7 @@ function resolveMopIntensityList(mopIntensityEntity) {
|
|
|
172734
173109
|
init_dist();
|
|
172735
173110
|
init_esm();
|
|
172736
173111
|
init_home_assistant_entity_behavior();
|
|
172737
|
-
var
|
|
173112
|
+
var logger241 = Logger.get("VacuumRvcOperationalStateServer");
|
|
172738
173113
|
function batteryFromAttributes(attrs) {
|
|
172739
173114
|
const raw = attrs.battery_level ?? attrs.battery;
|
|
172740
173115
|
if (raw == null) return null;
|
|
@@ -172785,16 +173160,16 @@ function mapVacuumOperationalState(entity, batteryPercent = batteryFromAttribute
|
|
|
172785
173160
|
operationalState = RvcOperationalState4.OperationalState.Error;
|
|
172786
173161
|
} else {
|
|
172787
173162
|
if (state.toLowerCase().includes("clean")) {
|
|
172788
|
-
|
|
173163
|
+
logger241.info(
|
|
172789
173164
|
`Unknown vacuum state "${state}" contains 'clean', treating as Running`
|
|
172790
173165
|
);
|
|
172791
173166
|
operationalState = RvcOperationalState4.OperationalState.Running;
|
|
172792
173167
|
} else {
|
|
172793
|
-
|
|
173168
|
+
logger241.info(`Unknown vacuum state "${state}", treating as Stopped`);
|
|
172794
173169
|
operationalState = RvcOperationalState4.OperationalState.Stopped;
|
|
172795
173170
|
}
|
|
172796
173171
|
}
|
|
172797
|
-
|
|
173172
|
+
logger241.debug(
|
|
172798
173173
|
`Vacuum operationalState: "${state}" -> ${RvcOperationalState4.OperationalState[operationalState]}`
|
|
172799
173174
|
);
|
|
172800
173175
|
return operationalState;
|
|
@@ -172823,7 +173198,7 @@ var VacuumRvcOperationalStateServer = RvcOperationalStateServer2({
|
|
|
172823
173198
|
});
|
|
172824
173199
|
|
|
172825
173200
|
// src/matter/endpoints/legacy/vacuum/index.ts
|
|
172826
|
-
var
|
|
173201
|
+
var logger242 = Logger.get("VacuumDevice");
|
|
172827
173202
|
var VacuumEndpointType = RoboticVacuumCleanerDevice.with(
|
|
172828
173203
|
BasicInformationServer2,
|
|
172829
173204
|
VacuumIdentifyServer,
|
|
@@ -172837,7 +173212,7 @@ function VacuumDevice(homeAssistantEntity, includeOnOff = false, cleaningModeOpt
|
|
|
172837
173212
|
const entityId = homeAssistantEntity.entity.entity_id;
|
|
172838
173213
|
const attributes9 = homeAssistantEntity.entity.state.attributes;
|
|
172839
173214
|
const customAreas = homeAssistantEntity.mapping?.customServiceAreas;
|
|
172840
|
-
|
|
173215
|
+
logger242.info(
|
|
172841
173216
|
`Creating vacuum endpoint for ${entityId}, mapping: ${JSON.stringify(homeAssistantEntity.mapping ?? "none")}`
|
|
172842
173217
|
);
|
|
172843
173218
|
const cleanAreaRooms = homeAssistantEntity.mapping?.cleanAreaRooms;
|
|
@@ -172850,32 +173225,32 @@ function VacuumDevice(homeAssistantEntity, includeOnOff = false, cleaningModeOpt
|
|
|
172850
173225
|
)
|
|
172851
173226
|
).set({ homeAssistantEntity });
|
|
172852
173227
|
if (includeOnOff) {
|
|
172853
|
-
|
|
173228
|
+
logger242.info(`${entityId}: Adding OnOff cluster (vacuumOnOff flag enabled)`);
|
|
172854
173229
|
device = device.with(VacuumOnOffServer);
|
|
172855
173230
|
}
|
|
172856
173231
|
device = device.with(VacuumPowerSourceServer);
|
|
172857
173232
|
const roomEntities = homeAssistantEntity.mapping?.roomEntities;
|
|
172858
173233
|
const rooms = parseVacuumRooms(attributes9);
|
|
172859
|
-
|
|
173234
|
+
logger242.info(
|
|
172860
173235
|
`${entityId}: customAreas=${customAreas?.length ?? 0}, roomEntities=${JSON.stringify(roomEntities ?? [])}, parsedRooms=${rooms.length}, cleanAreaRooms=${cleanAreaRooms?.length ?? 0}`
|
|
172861
173236
|
);
|
|
172862
173237
|
if (cleanAreaRooms && cleanAreaRooms.length > 0) {
|
|
172863
|
-
|
|
173238
|
+
logger242.info(
|
|
172864
173239
|
`${entityId}: Adding ServiceArea (${cleanAreaRooms.length} HA areas via CLEAN_AREA)`
|
|
172865
173240
|
);
|
|
172866
173241
|
device = device.with(createCleanAreaServiceAreaServer(cleanAreaRooms));
|
|
172867
173242
|
} else if (customAreas && customAreas.length > 0) {
|
|
172868
|
-
|
|
173243
|
+
logger242.info(
|
|
172869
173244
|
`${entityId}: Adding ServiceArea (${customAreas.length} custom areas)`
|
|
172870
173245
|
);
|
|
172871
173246
|
device = device.with(createCustomServiceAreaServer(customAreas));
|
|
172872
173247
|
} else if (rooms.length > 0 || roomEntities && roomEntities.length > 0) {
|
|
172873
|
-
|
|
173248
|
+
logger242.info(`${entityId}: Adding ServiceArea (${rooms.length} rooms)`);
|
|
172874
173249
|
device = device.with(
|
|
172875
173250
|
createVacuumServiceAreaServer(attributes9, roomEntities)
|
|
172876
173251
|
);
|
|
172877
173252
|
} else {
|
|
172878
|
-
|
|
173253
|
+
logger242.info(`${entityId}: Adding ServiceArea (default single-area)`);
|
|
172879
173254
|
device = device.with(createDefaultServiceAreaServer());
|
|
172880
173255
|
}
|
|
172881
173256
|
const fanSpeedList = resolveFanSpeedList(
|
|
@@ -172886,7 +173261,7 @@ function VacuumDevice(homeAssistantEntity, includeOnOff = false, cleaningModeOpt
|
|
|
172886
173261
|
homeAssistantEntity.mapping?.mopIntensityEntity
|
|
172887
173262
|
);
|
|
172888
173263
|
if (cleaningModeOptions || fanSpeedList || mopIntensityList) {
|
|
172889
|
-
|
|
173264
|
+
logger242.info(
|
|
172890
173265
|
`${entityId}: Adding RvcCleanMode (multi-mode, cleaningModeOptions=${JSON.stringify(cleaningModeOptions ?? [])}, fanSpeedList=${JSON.stringify(fanSpeedList ?? [])}, mopIntensityList=${JSON.stringify(mopIntensityList ?? [])})`
|
|
172891
173266
|
);
|
|
172892
173267
|
device = device.with(
|
|
@@ -172899,7 +173274,7 @@ function VacuumDevice(homeAssistantEntity, includeOnOff = false, cleaningModeOpt
|
|
|
172899
173274
|
)
|
|
172900
173275
|
);
|
|
172901
173276
|
} else {
|
|
172902
|
-
|
|
173277
|
+
logger242.info(`${entityId}: Adding RvcCleanMode (default single-mode)`);
|
|
172903
173278
|
device = device.with(createDefaultRvcCleanModeServer());
|
|
172904
173279
|
}
|
|
172905
173280
|
return device;
|
|
@@ -173065,7 +173440,7 @@ var WaterHeaterThermostatServer = ThermostatServer2(
|
|
|
173065
173440
|
);
|
|
173066
173441
|
|
|
173067
173442
|
// src/matter/endpoints/legacy/water-heater/index.ts
|
|
173068
|
-
var
|
|
173443
|
+
var logger243 = Logger.get("WaterHeaterDevice");
|
|
173069
173444
|
var WaterHeaterDeviceType = ThermostatDevice.with(
|
|
173070
173445
|
BasicInformationServer2,
|
|
173071
173446
|
IdentifyServer2,
|
|
@@ -173081,7 +173456,7 @@ function toMatterTemp2(value) {
|
|
|
173081
173456
|
}
|
|
173082
173457
|
function WaterHeaterDevice2(homeAssistantEntity) {
|
|
173083
173458
|
const attributes9 = homeAssistantEntity.entity.state.attributes;
|
|
173084
|
-
|
|
173459
|
+
logger243.debug(
|
|
173085
173460
|
`Creating device for ${homeAssistantEntity.entity.entity_id}, min_temp=${attributes9.min_temp}, max_temp=${attributes9.max_temp}`
|
|
173086
173461
|
);
|
|
173087
173462
|
const minLimit = toMatterTemp2(attributes9.min_temp) ?? 0;
|
|
@@ -173167,6 +173542,7 @@ var WaterHeaterBoostMemoryBehavior = class extends Behavior {
|
|
|
173167
173542
|
// src/matter/endpoints/legacy/water-heater/behaviors/water-heater-management-server.ts
|
|
173168
173543
|
init_dist();
|
|
173169
173544
|
init_esm();
|
|
173545
|
+
init_types2();
|
|
173170
173546
|
init_home_assistant_entity_behavior();
|
|
173171
173547
|
|
|
173172
173548
|
// src/matter/endpoints/legacy/water-heater/water-heater-modes.ts
|
|
@@ -173323,7 +173699,7 @@ function activeHeatSource(attributes9) {
|
|
|
173323
173699
|
}
|
|
173324
173700
|
|
|
173325
173701
|
// src/matter/endpoints/legacy/water-heater/behaviors/water-heater-management-server.ts
|
|
173326
|
-
var
|
|
173702
|
+
var logger244 = Logger.get("WaterHeaterManagementServer");
|
|
173327
173703
|
var MAX_TIMER_MS2 = 2147483647;
|
|
173328
173704
|
var boostSessions = /* @__PURE__ */ new WeakMap();
|
|
173329
173705
|
function clearBoostTimer(endpoint) {
|
|
@@ -173569,7 +173945,7 @@ var WaterHeaterManagementServerBase = class _WaterHeaterManagementServerBase ext
|
|
|
173569
173945
|
armBoostTimer(durationSeconds) {
|
|
173570
173946
|
const delay = durationSeconds * 1e3;
|
|
173571
173947
|
if (!Number.isFinite(delay) || delay <= 0 || delay > MAX_TIMER_MS2) {
|
|
173572
|
-
|
|
173948
|
+
logger244.debug(
|
|
173573
173949
|
`Boost duration ${durationSeconds}s outside the timer range, boost stays active until CancelBoost`
|
|
173574
173950
|
);
|
|
173575
173951
|
return;
|
|
@@ -173583,7 +173959,7 @@ var WaterHeaterManagementServerBase = class _WaterHeaterManagementServerBase ext
|
|
|
173583
173959
|
agent.get(_WaterHeaterManagementServerBase).endBoost({ restoreMode: true });
|
|
173584
173960
|
});
|
|
173585
173961
|
} catch (error) {
|
|
173586
|
-
|
|
173962
|
+
logger244.debug(
|
|
173587
173963
|
`Boost expiry failed (endpoint may be closing): ${error}`
|
|
173588
173964
|
);
|
|
173589
173965
|
}
|
|
@@ -173686,13 +174062,13 @@ function WaterHeaterModeServer2(mapping, initialMode) {
|
|
|
173686
174062
|
}
|
|
173687
174063
|
|
|
173688
174064
|
// src/matter/endpoints/legacy/water-heater/water-heater-management-device.ts
|
|
173689
|
-
var
|
|
174065
|
+
var logger245 = Logger.get("WaterHeaterManagementDevice");
|
|
173690
174066
|
function WaterHeaterManagementDevice(homeAssistantEntity) {
|
|
173691
174067
|
const entityState = homeAssistantEntity.entity.state;
|
|
173692
174068
|
const attributes9 = entityState.attributes;
|
|
173693
174069
|
const modeMapping = buildModeMapping(attributes9);
|
|
173694
174070
|
const initialMode = currentMode(modeMapping, entityState.state, attributes9);
|
|
173695
|
-
|
|
174071
|
+
logger245.debug(
|
|
173696
174072
|
`Creating Matter 1.4 water heater for ${homeAssistantEntity.entity.entity_id}, modes=[${modeMapping.supportedModes.map((m) => `${m.mode}:${m.label}`).join(", ")}], boostMode=${modeMapping.boostOperationMode ?? "none"}`
|
|
173697
174073
|
);
|
|
173698
174074
|
const minLimit = toMatterTemp2(attributes9.min_temp) ?? 0;
|
|
@@ -173963,7 +174339,7 @@ var matterDeviceTypeFactories = {
|
|
|
173963
174339
|
};
|
|
173964
174340
|
|
|
173965
174341
|
// src/matter/endpoints/composed/user-composed-endpoint.ts
|
|
173966
|
-
var
|
|
174342
|
+
var logger246 = Logger.get("UserComposedEndpoint");
|
|
173967
174343
|
function stripBasicInformation(type) {
|
|
173968
174344
|
const behaviors = { ...type.behaviors };
|
|
173969
174345
|
delete behaviors.bridgedDeviceBasicInformation;
|
|
@@ -174039,7 +174415,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
174039
174415
|
{ vacuumOnOff: registry3.isVacuumOnOffEnabled() }
|
|
174040
174416
|
);
|
|
174041
174417
|
if (!primaryType) {
|
|
174042
|
-
|
|
174418
|
+
logger246.warn(
|
|
174043
174419
|
`Cannot create endpoint type for primary entity ${primaryEntityId}`
|
|
174044
174420
|
);
|
|
174045
174421
|
return void 0;
|
|
@@ -174054,7 +174430,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
174054
174430
|
if (!sub.entityId) continue;
|
|
174055
174431
|
const subPayload = buildEntityPayload4(registry3, sub.entityId);
|
|
174056
174432
|
if (!subPayload) {
|
|
174057
|
-
|
|
174433
|
+
logger246.warn(
|
|
174058
174434
|
`Cannot find state for composed sub-entity ${sub.entityId}, it does not exist in Home Assistant (removed or renamed?)`
|
|
174059
174435
|
);
|
|
174060
174436
|
continue;
|
|
@@ -174069,7 +174445,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
174069
174445
|
config8.areaName
|
|
174070
174446
|
);
|
|
174071
174447
|
if (!subType) {
|
|
174072
|
-
|
|
174448
|
+
logger246.warn(
|
|
174073
174449
|
`Cannot create endpoint type for composed sub-entity ${sub.entityId}`
|
|
174074
174450
|
);
|
|
174075
174451
|
continue;
|
|
@@ -174082,7 +174458,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
174082
174458
|
mappedIds.push(sub.entityId);
|
|
174083
174459
|
}
|
|
174084
174460
|
if (parts.length < 2) {
|
|
174085
|
-
|
|
174461
|
+
logger246.warn(
|
|
174086
174462
|
`User composed device ${primaryEntityId}: only ${parts.length} sub-endpoint(s), need at least 2 (primary + one sub-entity). Falling back to standalone.`
|
|
174087
174463
|
);
|
|
174088
174464
|
return void 0;
|
|
@@ -174106,7 +174482,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
174106
174482
|
const labels = parts.map(
|
|
174107
174483
|
(_, i) => i === 0 ? primaryEntityId.split(".")[0] : composedEntities[i - 1]?.entityId?.split(".")[0] ?? "?"
|
|
174108
174484
|
).join("+");
|
|
174109
|
-
|
|
174485
|
+
logger246.info(
|
|
174110
174486
|
`Created user composed device ${primaryEntityId}: ${parts.length} sub-endpoint(s) [${labels}]`
|
|
174111
174487
|
);
|
|
174112
174488
|
return endpoint;
|
|
@@ -174212,7 +174588,7 @@ function asStandaloneEndpointType(type) {
|
|
|
174212
174588
|
}
|
|
174213
174589
|
|
|
174214
174590
|
// src/matter/endpoints/legacy/legacy-endpoint.ts
|
|
174215
|
-
var
|
|
174591
|
+
var logger247 = Logger.get("LegacyEndpoint");
|
|
174216
174592
|
var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
174217
174593
|
constructor(type, entityId, customName, mappedEntityIds, throttleMs, endpointId, vacuumEffective) {
|
|
174218
174594
|
super(type, entityId, customName, mappedEntityIds, endpointId);
|
|
@@ -174228,25 +174604,25 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174228
174604
|
return;
|
|
174229
174605
|
}
|
|
174230
174606
|
if (registry3.isAutoBatteryMappingEnabled() && registry3.isBatteryEntityUsed(entityId)) {
|
|
174231
|
-
|
|
174607
|
+
logger247.debug(
|
|
174232
174608
|
`Skipping ${entityId} - already auto-assigned as battery to another device`
|
|
174233
174609
|
);
|
|
174234
174610
|
return;
|
|
174235
174611
|
}
|
|
174236
174612
|
if (registry3.isAutoHumidityMappingEnabled() && registry3.isHumidityEntityUsed(entityId)) {
|
|
174237
|
-
|
|
174613
|
+
logger247.debug(
|
|
174238
174614
|
`Skipping ${entityId} - already auto-assigned as humidity to a temperature sensor`
|
|
174239
174615
|
);
|
|
174240
174616
|
return;
|
|
174241
174617
|
}
|
|
174242
174618
|
if (registry3.isAutoPressureMappingEnabled() && registry3.isPressureEntityUsed(entityId)) {
|
|
174243
|
-
|
|
174619
|
+
logger247.debug(
|
|
174244
174620
|
`Skipping ${entityId} - already auto-assigned as pressure to a temperature sensor`
|
|
174245
174621
|
);
|
|
174246
174622
|
return;
|
|
174247
174623
|
}
|
|
174248
174624
|
if (registry3.isAutoComposedDevicesEnabled() && registry3.isComposedSubEntityUsed(entityId)) {
|
|
174249
|
-
|
|
174625
|
+
logger247.debug(
|
|
174250
174626
|
`Skipping ${entityId} - already consumed by a composed device`
|
|
174251
174627
|
);
|
|
174252
174628
|
return;
|
|
@@ -174266,7 +174642,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174266
174642
|
humidityEntity: humidityEntityId
|
|
174267
174643
|
};
|
|
174268
174644
|
registry3.markHumidityEntityUsed(humidityEntityId);
|
|
174269
|
-
|
|
174645
|
+
logger247.debug(
|
|
174270
174646
|
`Auto-assigned humidity ${humidityEntityId} to ${entityId}`
|
|
174271
174647
|
);
|
|
174272
174648
|
}
|
|
@@ -174285,7 +174661,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174285
174661
|
pressureEntity: pressureEntityId
|
|
174286
174662
|
};
|
|
174287
174663
|
registry3.markPressureEntityUsed(pressureEntityId);
|
|
174288
|
-
|
|
174664
|
+
logger247.debug(
|
|
174289
174665
|
`Auto-assigned pressure ${pressureEntityId} to ${entityId}`
|
|
174290
174666
|
);
|
|
174291
174667
|
}
|
|
@@ -174303,7 +174679,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174303
174679
|
batteryEntity: batteryEntityId
|
|
174304
174680
|
};
|
|
174305
174681
|
registry3.markBatteryEntityUsed(batteryEntityId);
|
|
174306
|
-
|
|
174682
|
+
logger247.debug(
|
|
174307
174683
|
`Auto-assigned battery ${batteryEntityId} to ${entityId}`
|
|
174308
174684
|
);
|
|
174309
174685
|
}
|
|
@@ -174320,7 +174696,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174320
174696
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
174321
174697
|
faultEntity: faultEntityId
|
|
174322
174698
|
};
|
|
174323
|
-
|
|
174699
|
+
logger247.debug(`Auto-assigned fault ${faultEntityId} to ${entityId}`);
|
|
174324
174700
|
}
|
|
174325
174701
|
}
|
|
174326
174702
|
if (!mapping?.powerEntity) {
|
|
@@ -174336,7 +174712,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174336
174712
|
powerEntity: powerEntityId
|
|
174337
174713
|
};
|
|
174338
174714
|
registry3.markPowerEntityUsed(powerEntityId);
|
|
174339
|
-
|
|
174715
|
+
logger247.debug(`Auto-assigned power ${powerEntityId} to ${entityId}`);
|
|
174340
174716
|
}
|
|
174341
174717
|
}
|
|
174342
174718
|
}
|
|
@@ -174353,7 +174729,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174353
174729
|
energyEntity: energyEntityId
|
|
174354
174730
|
};
|
|
174355
174731
|
registry3.markEnergyEntityUsed(energyEntityId);
|
|
174356
|
-
|
|
174732
|
+
logger247.debug(
|
|
174357
174733
|
`Auto-assigned energy ${energyEntityId} to ${entityId}`
|
|
174358
174734
|
);
|
|
174359
174735
|
}
|
|
@@ -174369,7 +174745,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174369
174745
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
174370
174746
|
cleaningModeEntity: vacuumEntities.cleaningModeEntity
|
|
174371
174747
|
};
|
|
174372
|
-
|
|
174748
|
+
logger247.info(
|
|
174373
174749
|
`Auto-assigned cleaningMode ${vacuumEntities.cleaningModeEntity} to ${entityId}`
|
|
174374
174750
|
);
|
|
174375
174751
|
}
|
|
@@ -174379,7 +174755,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174379
174755
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
174380
174756
|
suctionLevelEntity: vacuumEntities.suctionLevelEntity
|
|
174381
174757
|
};
|
|
174382
|
-
|
|
174758
|
+
logger247.info(
|
|
174383
174759
|
`Auto-assigned suctionLevel ${vacuumEntities.suctionLevelEntity} to ${entityId}`
|
|
174384
174760
|
);
|
|
174385
174761
|
}
|
|
@@ -174389,7 +174765,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174389
174765
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
174390
174766
|
mopIntensityEntity: vacuumEntities.mopIntensityEntity
|
|
174391
174767
|
};
|
|
174392
|
-
|
|
174768
|
+
logger247.info(
|
|
174393
174769
|
`Auto-assigned mopIntensity ${vacuumEntities.mopIntensityEntity} to ${entityId}`
|
|
174394
174770
|
);
|
|
174395
174771
|
}
|
|
@@ -174399,7 +174775,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174399
174775
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
174400
174776
|
currentRoomEntity: vacuumEntities.currentRoomEntity
|
|
174401
174777
|
};
|
|
174402
|
-
|
|
174778
|
+
logger247.info(
|
|
174403
174779
|
`Auto-assigned currentRoom ${vacuumEntities.currentRoomEntity} to ${entityId}`
|
|
174404
174780
|
);
|
|
174405
174781
|
}
|
|
@@ -174414,7 +174790,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174414
174790
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
174415
174791
|
cleanAreaRooms
|
|
174416
174792
|
};
|
|
174417
|
-
|
|
174793
|
+
logger247.info(
|
|
174418
174794
|
`Using ${cleanAreaRooms.length} HA areas via CLEAN_AREA for ${entityId}`
|
|
174419
174795
|
);
|
|
174420
174796
|
}
|
|
@@ -174435,7 +174811,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174435
174811
|
rooms: roomsObj
|
|
174436
174812
|
}
|
|
174437
174813
|
};
|
|
174438
|
-
|
|
174814
|
+
logger247.debug(
|
|
174439
174815
|
`Auto-detected ${valetudoRooms.length} Valetudo segments for ${entityId}`
|
|
174440
174816
|
);
|
|
174441
174817
|
} else {
|
|
@@ -174452,7 +174828,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174452
174828
|
rooms: roomsObj
|
|
174453
174829
|
}
|
|
174454
174830
|
};
|
|
174455
|
-
|
|
174831
|
+
logger247.debug(
|
|
174456
174832
|
`Auto-detected ${roborockRooms.length} Roborock rooms for ${entityId}`
|
|
174457
174833
|
);
|
|
174458
174834
|
}
|
|
@@ -174461,7 +174837,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174461
174837
|
}
|
|
174462
174838
|
}
|
|
174463
174839
|
if (standalone && ((effectiveMapping?.composedEntities?.length ?? 0) > 0 || effectiveMapping?.climateExposeFan === true)) {
|
|
174464
|
-
|
|
174840
|
+
logger247.warn(
|
|
174465
174841
|
`Composed mappings are not supported in server mode, exposing ${entityId} as a flat standalone endpoint`
|
|
174466
174842
|
);
|
|
174467
174843
|
}
|
|
@@ -174480,7 +174856,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174480
174856
|
if (composed) {
|
|
174481
174857
|
return composed;
|
|
174482
174858
|
}
|
|
174483
|
-
|
|
174859
|
+
logger247.warn(
|
|
174484
174860
|
`User composed device creation failed for ${entityId}, falling back to standalone`
|
|
174485
174861
|
);
|
|
174486
174862
|
}
|
|
@@ -174545,7 +174921,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174545
174921
|
if (composed) {
|
|
174546
174922
|
return composed;
|
|
174547
174923
|
}
|
|
174548
|
-
|
|
174924
|
+
logger247.warn(
|
|
174549
174925
|
`Companion fan creation failed for ${entityId}, falling back to standalone`
|
|
174550
174926
|
);
|
|
174551
174927
|
}
|
|
@@ -174623,11 +174999,11 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
174623
174999
|
}
|
|
174624
175000
|
if (mappedChanged) {
|
|
174625
175001
|
this.pendingMappedChange = true;
|
|
174626
|
-
|
|
175002
|
+
logger247.debug(
|
|
174627
175003
|
`Mapped entity change detected for ${this.entityId}, forcing update`
|
|
174628
175004
|
);
|
|
174629
175005
|
}
|
|
174630
|
-
|
|
175006
|
+
logger247.debug(
|
|
174631
175007
|
`State update received for ${this.entityId}: state=${state.state}`
|
|
174632
175008
|
);
|
|
174633
175009
|
this.lastState = state;
|
|
@@ -174848,12 +175224,14 @@ var CameraAvStreamServer = class extends Base4 {
|
|
|
174848
175224
|
// src/plugins/builtin/camera/webrtc-provider-server.ts
|
|
174849
175225
|
init_esm();
|
|
174850
175226
|
init_esm7();
|
|
175227
|
+
init_types2();
|
|
174851
175228
|
init_esm3();
|
|
174852
175229
|
|
|
174853
175230
|
// src/plugins/builtin/camera/requestor-client.ts
|
|
174854
175231
|
init_esm();
|
|
175232
|
+
init_types2();
|
|
174855
175233
|
init_esm4();
|
|
174856
|
-
var
|
|
175234
|
+
var logger248 = Logger.get("CameraWebRtcRequestor");
|
|
174857
175235
|
var registry2 = /* @__PURE__ */ new Map();
|
|
174858
175236
|
var pendingDeliveries = /* @__PURE__ */ new Map();
|
|
174859
175237
|
var invokeTransport = defaultInvoke;
|
|
@@ -174887,19 +175265,19 @@ function deliverAnswerDeferred(sessionId, sdp, onGiveUp) {
|
|
|
174887
175265
|
return;
|
|
174888
175266
|
}
|
|
174889
175267
|
if (await sendAnswer(sessionId, sdp)) {
|
|
174890
|
-
|
|
175268
|
+
logger248.info(`answer delivered for session ${sessionId}`);
|
|
174891
175269
|
return;
|
|
174892
175270
|
}
|
|
174893
175271
|
}
|
|
174894
175272
|
if (registry2.get(sessionId) !== owner || pendingDeliveries.get(sessionId) !== timer) {
|
|
174895
175273
|
return;
|
|
174896
175274
|
}
|
|
174897
|
-
|
|
175275
|
+
logger248.info(
|
|
174898
175276
|
`answer delivery failed for session ${sessionId}, giving up`
|
|
174899
175277
|
);
|
|
174900
175278
|
await onGiveUp();
|
|
174901
175279
|
} catch (err) {
|
|
174902
|
-
|
|
175280
|
+
logger248.info(
|
|
174903
175281
|
`answer delivery for session ${sessionId} threw: ${errText(err)}`
|
|
174904
175282
|
);
|
|
174905
175283
|
} finally {
|
|
@@ -174924,11 +175302,11 @@ function sendAnswer(sessionId, sdp) {
|
|
|
174924
175302
|
async function invokeRequestor(sessionId, command, fields) {
|
|
174925
175303
|
const registration = registry2.get(sessionId);
|
|
174926
175304
|
if (!registration) {
|
|
174927
|
-
|
|
175305
|
+
logger248.info(`requestor ${command}: no session ${sessionId} registered`);
|
|
174928
175306
|
return false;
|
|
174929
175307
|
}
|
|
174930
175308
|
if (registration.session.isClosed) {
|
|
174931
|
-
|
|
175309
|
+
logger248.info(`requestor ${command}: session ${sessionId} already closed`);
|
|
174932
175310
|
return false;
|
|
174933
175311
|
}
|
|
174934
175312
|
const request = {
|
|
@@ -174940,7 +175318,7 @@ async function invokeRequestor(sessionId, command, fields) {
|
|
|
174940
175318
|
try {
|
|
174941
175319
|
return await invokeTransport({ registration, request });
|
|
174942
175320
|
} catch (err) {
|
|
174943
|
-
|
|
175321
|
+
logger248.info(
|
|
174944
175322
|
`requestor ${command} failed for session ${sessionId}: ${errText(err)}`
|
|
174945
175323
|
);
|
|
174946
175324
|
return false;
|
|
@@ -174975,7 +175353,7 @@ async function defaultInvoke({
|
|
|
174975
175353
|
for (const entry of chunk) {
|
|
174976
175354
|
if (entry.kind === "cmd-status") {
|
|
174977
175355
|
if (entry.status !== Status2.Success) {
|
|
174978
|
-
|
|
175356
|
+
logger248.info(
|
|
174979
175357
|
`requestor ${request.command} status ${entry.status} for session ${String(request.fields.webRtcSessionId)}`
|
|
174980
175358
|
);
|
|
174981
175359
|
return false;
|
|
@@ -174995,7 +175373,7 @@ function errText(err) {
|
|
|
174995
175373
|
}
|
|
174996
175374
|
|
|
174997
175375
|
// src/plugins/builtin/camera/webrtc-provider-server.ts
|
|
174998
|
-
var
|
|
175376
|
+
var logger249 = Logger.get("CameraWebRtc");
|
|
174999
175377
|
var nextGlobalSessionId = 0;
|
|
175000
175378
|
function mintSessionId() {
|
|
175001
175379
|
for (let i = 0; i <= 65534; i++) {
|
|
@@ -175009,14 +175387,14 @@ var CameraWebRtcProviderServer = class extends WebRtcTransportProviderServer {
|
|
|
175009
175387
|
solicitOffer(request) {
|
|
175010
175388
|
const id = mintSessionId();
|
|
175011
175389
|
this.trackSession(id, request.streamUsage, request.originatingEndpointId);
|
|
175012
|
-
|
|
175390
|
+
logger249.info(
|
|
175013
175391
|
`solicitOffer session=${id} (${this.state.entityId}), deferred offer`
|
|
175014
175392
|
);
|
|
175015
175393
|
void this.state.bridge.startSession(id, this.state.entityId, {
|
|
175016
175394
|
iceServers: request.iceServers,
|
|
175017
175395
|
iceTransportPolicy: request.iceTransportPolicy
|
|
175018
175396
|
}).catch(
|
|
175019
|
-
(err) =>
|
|
175397
|
+
(err) => logger249.info(
|
|
175020
175398
|
`solicitOffer startSession failed for ${this.state.entityId}: ${errText2(err)}`
|
|
175021
175399
|
)
|
|
175022
175400
|
);
|
|
@@ -175024,7 +175402,7 @@ var CameraWebRtcProviderServer = class extends WebRtcTransportProviderServer {
|
|
|
175024
175402
|
}
|
|
175025
175403
|
async provideOffer(request) {
|
|
175026
175404
|
const id = request.webRtcSessionId ?? mintSessionId();
|
|
175027
|
-
|
|
175405
|
+
logger249.info(
|
|
175028
175406
|
`provideOffer entry: entityId=${this.state.entityId} session=${id} (sdp ${request.sdp.length} chars)`
|
|
175029
175407
|
);
|
|
175030
175408
|
if (request.webRtcSessionId == null) {
|
|
@@ -175058,7 +175436,7 @@ var CameraWebRtcProviderServer = class extends WebRtcTransportProviderServer {
|
|
|
175058
175436
|
);
|
|
175059
175437
|
} catch (err) {
|
|
175060
175438
|
const message = errText2(err);
|
|
175061
|
-
|
|
175439
|
+
logger249.info(
|
|
175062
175440
|
`provideOffer failed for ${this.state.entityId} session=${id}: ${message}`
|
|
175063
175441
|
);
|
|
175064
175442
|
unregisterRequestor(id);
|
|
@@ -175070,7 +175448,7 @@ var CameraWebRtcProviderServer = class extends WebRtcTransportProviderServer {
|
|
|
175070
175448
|
StatusCode.Failure
|
|
175071
175449
|
);
|
|
175072
175450
|
}
|
|
175073
|
-
|
|
175451
|
+
logger249.info(
|
|
175074
175452
|
`provideOffer answer computed for ${this.state.entityId} session=${id} (${answerSdp.length} chars); delivering via requestor`
|
|
175075
175453
|
);
|
|
175076
175454
|
const bridge = this.state.bridge;
|
|
@@ -175089,7 +175467,7 @@ var CameraWebRtcProviderServer = class extends WebRtcTransportProviderServer {
|
|
|
175089
175467
|
return { webRtcSessionId: id };
|
|
175090
175468
|
}
|
|
175091
175469
|
provideAnswer(request) {
|
|
175092
|
-
|
|
175470
|
+
logger249.info(
|
|
175093
175471
|
`provideAnswer session=${request.webRtcSessionId} (sdp ${request.sdp.length} chars, ${this.state.entityId})`
|
|
175094
175472
|
);
|
|
175095
175473
|
return this.state.bridge.acceptControllerAnswer(
|
|
@@ -175098,7 +175476,7 @@ var CameraWebRtcProviderServer = class extends WebRtcTransportProviderServer {
|
|
|
175098
175476
|
);
|
|
175099
175477
|
}
|
|
175100
175478
|
async provideIceCandidates(request) {
|
|
175101
|
-
|
|
175479
|
+
logger249.info(
|
|
175102
175480
|
`provideIceCandidates session=${request.webRtcSessionId}: ${request.iceCandidates.length} candidate(s) (${this.state.entityId})`
|
|
175103
175481
|
);
|
|
175104
175482
|
for (const c of request.iceCandidates) {
|
|
@@ -175111,7 +175489,7 @@ var CameraWebRtcProviderServer = class extends WebRtcTransportProviderServer {
|
|
|
175111
175489
|
}
|
|
175112
175490
|
}
|
|
175113
175491
|
async endSession(request) {
|
|
175114
|
-
|
|
175492
|
+
logger249.info(
|
|
175115
175493
|
`endSession session=${request.webRtcSessionId} (${this.state.entityId})`
|
|
175116
175494
|
);
|
|
175117
175495
|
await this.state.bridge.endSession(request.webRtcSessionId);
|
|
@@ -175232,7 +175610,7 @@ import {
|
|
|
175232
175610
|
createLongLivedTokenAuth as createLongLivedTokenAuth2
|
|
175233
175611
|
} from "home-assistant-js-websocket";
|
|
175234
175612
|
import { RTCPeerConnection } from "werift";
|
|
175235
|
-
var
|
|
175613
|
+
var logger250 = Logger.get("CameraWebRtc");
|
|
175236
175614
|
var DEFAULT_HA_WEBRTC_TIMEOUT_MS = 15e3;
|
|
175237
175615
|
var haWebRtcTimeoutMs = DEFAULT_HA_WEBRTC_TIMEOUT_MS;
|
|
175238
175616
|
var WebRtcBridge = class {
|
|
@@ -175279,7 +175657,7 @@ var WebRtcBridge = class {
|
|
|
175279
175657
|
const haOffer = await haPeer.createOffer();
|
|
175280
175658
|
await haPeer.setLocalDescription(haOffer);
|
|
175281
175659
|
const haOfferSdp = this.localSdp(haPeer);
|
|
175282
|
-
|
|
175660
|
+
logger250.info(`HA offer sent for ${entityId} (${haOfferSdp.length} chars)`);
|
|
175283
175661
|
const { answer, sessionId, unsubscribe } = await this.requestHaWebRtc(
|
|
175284
175662
|
entityId,
|
|
175285
175663
|
haOfferSdp,
|
|
@@ -175302,12 +175680,12 @@ var WebRtcBridge = class {
|
|
|
175302
175680
|
const controllerOffer = await controllerPeer.createOffer();
|
|
175303
175681
|
await controllerPeer.setLocalDescription(controllerOffer);
|
|
175304
175682
|
const sdp = this.localSdp(controllerPeer);
|
|
175305
|
-
|
|
175683
|
+
logger250.info(
|
|
175306
175684
|
`controller offer created for ${entityId} (${sdp.length} chars)`
|
|
175307
175685
|
);
|
|
175308
175686
|
return { sdp, iceCandidates };
|
|
175309
175687
|
} catch (err) {
|
|
175310
|
-
|
|
175688
|
+
logger250.info(`startSession failed for ${entityId}: ${errText3(err)}`);
|
|
175311
175689
|
await this.endSession(matterSessionId);
|
|
175312
175690
|
throw err;
|
|
175313
175691
|
}
|
|
@@ -175337,7 +175715,7 @@ var WebRtcBridge = class {
|
|
|
175337
175715
|
const haOffer = await haPeer.createOffer();
|
|
175338
175716
|
await haPeer.setLocalDescription(haOffer);
|
|
175339
175717
|
const haOfferSdp = this.localSdp(haPeer);
|
|
175340
|
-
|
|
175718
|
+
logger250.info(`HA offer sent for ${entityId} (${haOfferSdp.length} chars)`);
|
|
175341
175719
|
const { answer, sessionId, unsubscribe } = await this.requestHaWebRtc(
|
|
175342
175720
|
entityId,
|
|
175343
175721
|
haOfferSdp,
|
|
@@ -175356,12 +175734,12 @@ var WebRtcBridge = class {
|
|
|
175356
175734
|
const controllerAnswer = await controllerPeer.createAnswer();
|
|
175357
175735
|
await controllerPeer.setLocalDescription(controllerAnswer);
|
|
175358
175736
|
const answerSdp = this.localSdp(controllerPeer);
|
|
175359
|
-
|
|
175737
|
+
logger250.info(
|
|
175360
175738
|
`controller answer created for ${entityId} (${answerSdp.length} chars)`
|
|
175361
175739
|
);
|
|
175362
175740
|
return answerSdp;
|
|
175363
175741
|
} catch (err) {
|
|
175364
|
-
|
|
175742
|
+
logger250.info(
|
|
175365
175743
|
`acceptControllerOffer failed for ${entityId}: ${errText3(err)}`
|
|
175366
175744
|
);
|
|
175367
175745
|
await this.endSession(matterSessionId);
|
|
@@ -175372,14 +175750,14 @@ var WebRtcBridge = class {
|
|
|
175372
175750
|
async acceptControllerAnswer(matterSessionId, sdp) {
|
|
175373
175751
|
const session = this.sessions.get(matterSessionId);
|
|
175374
175752
|
if (!session) return;
|
|
175375
|
-
|
|
175753
|
+
logger250.debug(`controller answer applied for ${session.entityId}`);
|
|
175376
175754
|
await session.controllerPeer.setRemoteDescription({ type: "answer", sdp });
|
|
175377
175755
|
}
|
|
175378
175756
|
/** Add a remote ICE candidate from the Matter controller. */
|
|
175379
175757
|
async addControllerIceCandidate(matterSessionId, candidate, sdpMid, sdpMLineIndex) {
|
|
175380
175758
|
const session = this.sessions.get(matterSessionId);
|
|
175381
175759
|
if (!session) return;
|
|
175382
|
-
|
|
175760
|
+
logger250.debug(
|
|
175383
175761
|
`controller ICE candidate for ${session.entityId}: ${candidate}`
|
|
175384
175762
|
);
|
|
175385
175763
|
await session.controllerPeer.addIceCandidate({
|
|
@@ -175393,12 +175771,12 @@ var WebRtcBridge = class {
|
|
|
175393
175771
|
async closeExistingPeers(matterSessionId) {
|
|
175394
175772
|
const prior = this.sessions.get(matterSessionId);
|
|
175395
175773
|
if (!prior) return;
|
|
175396
|
-
|
|
175774
|
+
logger250.info(
|
|
175397
175775
|
`replacing session ${matterSessionId} (${prior.entityId}), closing prior peers`
|
|
175398
175776
|
);
|
|
175399
175777
|
if (prior.haUnsubscribe) {
|
|
175400
175778
|
await Promise.resolve(prior.haUnsubscribe()).catch(
|
|
175401
|
-
(err) =>
|
|
175779
|
+
(err) => logger250.debug(`HA unsubscribe failed: ${errText3(err)}`)
|
|
175402
175780
|
);
|
|
175403
175781
|
}
|
|
175404
175782
|
await prior.haPeer.close().catch(() => {
|
|
@@ -175411,11 +175789,11 @@ var WebRtcBridge = class {
|
|
|
175411
175789
|
async endSession(matterSessionId) {
|
|
175412
175790
|
const session = this.sessions.get(matterSessionId);
|
|
175413
175791
|
if (!session) return;
|
|
175414
|
-
|
|
175792
|
+
logger250.info(`ending session ${matterSessionId} (${session.entityId})`);
|
|
175415
175793
|
this.sessions.delete(matterSessionId);
|
|
175416
175794
|
if (session.haUnsubscribe) {
|
|
175417
175795
|
await Promise.resolve(session.haUnsubscribe()).catch(
|
|
175418
|
-
(err) =>
|
|
175796
|
+
(err) => logger250.debug(`HA unsubscribe failed: ${errText3(err)}`)
|
|
175419
175797
|
);
|
|
175420
175798
|
}
|
|
175421
175799
|
await session.haPeer.close().catch(() => {
|
|
@@ -175445,11 +175823,11 @@ var WebRtcBridge = class {
|
|
|
175445
175823
|
headers: { Authorization: `Bearer ${this.config.haToken}` }
|
|
175446
175824
|
});
|
|
175447
175825
|
} catch (err) {
|
|
175448
|
-
|
|
175826
|
+
logger250.info(`snapshot fetch failed for ${entityId}: ${errText3(err)}`);
|
|
175449
175827
|
throw err;
|
|
175450
175828
|
}
|
|
175451
175829
|
if (!res.ok) {
|
|
175452
|
-
|
|
175830
|
+
logger250.info(
|
|
175453
175831
|
`snapshot fetch failed for ${entityId}: camera_proxy ${res.status}`
|
|
175454
175832
|
);
|
|
175455
175833
|
throw new Error(`HA camera_proxy ${entityId}: ${res.status}`);
|
|
@@ -175466,10 +175844,10 @@ var WebRtcBridge = class {
|
|
|
175466
175844
|
// Forward every track HA sends into the matching pre-added controller sender.
|
|
175467
175845
|
forwardHaTracks(haPeer, senders, entityId) {
|
|
175468
175846
|
haPeer.onTrack.subscribe((track) => {
|
|
175469
|
-
|
|
175847
|
+
logger250.info(`onTrack ${track.kind} from HA (${entityId})`);
|
|
175470
175848
|
const transceiver = senders.get(track.kind);
|
|
175471
175849
|
if (!transceiver) {
|
|
175472
|
-
|
|
175850
|
+
logger250.info(
|
|
175473
175851
|
`no controller transceiver for ${track.kind} (${entityId})`
|
|
175474
175852
|
);
|
|
175475
175853
|
return;
|
|
@@ -175478,7 +175856,7 @@ var WebRtcBridge = class {
|
|
|
175478
175856
|
track.onReceiveRtp.subscribe((rtp) => {
|
|
175479
175857
|
if (!firstLogged) {
|
|
175480
175858
|
firstLogged = true;
|
|
175481
|
-
|
|
175859
|
+
logger250.info(`first RTP forwarded for ${track.kind} (${entityId})`);
|
|
175482
175860
|
}
|
|
175483
175861
|
transceiver.sender.sendRtp(rtp);
|
|
175484
175862
|
});
|
|
@@ -175487,10 +175865,10 @@ var WebRtcBridge = class {
|
|
|
175487
175865
|
// Log connection/ice state transitions (these events fire on change only).
|
|
175488
175866
|
wireStateLogging(peer, label, entityId) {
|
|
175489
175867
|
peer.connectionStateChange.subscribe(
|
|
175490
|
-
(s) =>
|
|
175868
|
+
(s) => logger250.info(`${label} connectionState=${s} (${entityId})`)
|
|
175491
175869
|
);
|
|
175492
175870
|
peer.iceConnectionStateChange.subscribe(
|
|
175493
|
-
(s) =>
|
|
175871
|
+
(s) => logger250.info(`${label} iceConnectionState=${s} (${entityId})`)
|
|
175494
175872
|
);
|
|
175495
175873
|
}
|
|
175496
175874
|
// Map the Matter ICE struct onto werift's config. Only the controller peer
|
|
@@ -175504,11 +175882,11 @@ var WebRtcBridge = class {
|
|
|
175504
175882
|
}))
|
|
175505
175883
|
);
|
|
175506
175884
|
if (iceServers.length === 0) {
|
|
175507
|
-
|
|
175885
|
+
logger250.info(`controller peer using default ICE servers (${entityId})`);
|
|
175508
175886
|
return void 0;
|
|
175509
175887
|
}
|
|
175510
175888
|
const policy = ice?.iceTransportPolicy === "relay" || ice?.iceTransportPolicy === "all" ? ice.iceTransportPolicy : void 0;
|
|
175511
|
-
|
|
175889
|
+
logger250.info(
|
|
175512
175890
|
`controller peer using ${iceServers.length} controller ICE server(s)${policy ? ` policy=${policy}` : ""} (${entityId})`
|
|
175513
175891
|
);
|
|
175514
175892
|
return policy ? { iceServers, iceTransportPolicy: policy } : { iceServers };
|
|
@@ -175522,13 +175900,13 @@ var WebRtcBridge = class {
|
|
|
175522
175900
|
feedHaCandidate(entityId, haPeer, candidate) {
|
|
175523
175901
|
const value = candidate?.candidate;
|
|
175524
175902
|
if (!value) return;
|
|
175525
|
-
|
|
175903
|
+
logger250.debug(`HA ICE candidate for ${entityId}: ${value}`);
|
|
175526
175904
|
void haPeer.addIceCandidate({
|
|
175527
175905
|
candidate: value,
|
|
175528
175906
|
sdpMid: candidate?.sdpMid ?? void 0,
|
|
175529
175907
|
sdpMLineIndex: candidate?.sdpMLineIndex ?? void 0
|
|
175530
175908
|
}).catch(
|
|
175531
|
-
(e) =>
|
|
175909
|
+
(e) => logger250.debug(
|
|
175532
175910
|
`HA addIceCandidate failed for ${entityId}: ${errText3(e)}`
|
|
175533
175911
|
)
|
|
175534
175912
|
);
|
|
@@ -175557,7 +175935,7 @@ var WebRtcBridge = class {
|
|
|
175557
175935
|
reject(err);
|
|
175558
175936
|
});
|
|
175559
175937
|
timer = setTimeout(() => {
|
|
175560
|
-
|
|
175938
|
+
logger250.info(
|
|
175561
175939
|
`HA WebRTC timed out after ${haWebRtcTimeoutMs}ms for ${entityId}`
|
|
175562
175940
|
);
|
|
175563
175941
|
fail(
|
|
@@ -175575,7 +175953,7 @@ var WebRtcBridge = class {
|
|
|
175575
175953
|
if (msg.session_id) sessionId = msg.session_id;
|
|
175576
175954
|
const ans = msg.answer;
|
|
175577
175955
|
settle(() => {
|
|
175578
|
-
|
|
175956
|
+
logger250.info(
|
|
175579
175957
|
`HA answer received for ${entityId} (${ans.length} chars)`
|
|
175580
175958
|
);
|
|
175581
175959
|
resolve11(ans);
|
|
@@ -175584,7 +175962,7 @@ var WebRtcBridge = class {
|
|
|
175584
175962
|
break;
|
|
175585
175963
|
case "error": {
|
|
175586
175964
|
const detail = msg.message ?? msg.code ?? "unknown error";
|
|
175587
|
-
|
|
175965
|
+
logger250.info(`HA WebRTC error for ${entityId}: ${detail}`);
|
|
175588
175966
|
fail(new Error(`HA WebRTC error: ${detail}`));
|
|
175589
175967
|
break;
|
|
175590
175968
|
}
|
|
@@ -175758,7 +176136,7 @@ var CameraPlugin = class {
|
|
|
175758
176136
|
// src/plugins/builtin/security/security-plugin.ts
|
|
175759
176137
|
init_esm();
|
|
175760
176138
|
import {
|
|
175761
|
-
callService
|
|
176139
|
+
callService,
|
|
175762
176140
|
createConnection as createConnection4,
|
|
175763
176141
|
createLongLivedTokenAuth as createLongLivedTokenAuth3
|
|
175764
176142
|
} from "home-assistant-js-websocket";
|
|
@@ -176610,7 +176988,7 @@ var SecurityPlugin = class {
|
|
|
176610
176988
|
let timer;
|
|
176611
176989
|
try {
|
|
176612
176990
|
await Promise.race([
|
|
176613
|
-
|
|
176991
|
+
callService(connection, domain, service, void 0, {
|
|
176614
176992
|
entity_id: entityId
|
|
176615
176993
|
}),
|
|
176616
176994
|
new Promise((_, reject) => {
|
|
@@ -176741,7 +177119,7 @@ import {
|
|
|
176741
177119
|
getCollection
|
|
176742
177120
|
} from "home-assistant-js-websocket";
|
|
176743
177121
|
import { atLeastHaVersion } from "home-assistant-js-websocket/dist/util.js";
|
|
176744
|
-
var
|
|
177122
|
+
var logger251 = Logger.get("SubscribeEntities");
|
|
176745
177123
|
function processEvent(store, updates) {
|
|
176746
177124
|
const state = { ...store.state };
|
|
176747
177125
|
if (updates.a) {
|
|
@@ -176767,7 +177145,7 @@ function processEvent(store, updates) {
|
|
|
176767
177145
|
for (const entityId in updates.c) {
|
|
176768
177146
|
let entityState = state[entityId];
|
|
176769
177147
|
if (!entityState) {
|
|
176770
|
-
|
|
177148
|
+
logger251.warn("Received state update for unknown entity", entityId);
|
|
176771
177149
|
continue;
|
|
176772
177150
|
}
|
|
176773
177151
|
entityState = { ...entityState };
|
|
@@ -176856,7 +177234,7 @@ var subscribeEntities = (conn, onChange, entityIds) => {
|
|
|
176856
177234
|
// src/services/bridges/entity-isolation-service.ts
|
|
176857
177235
|
init_esm();
|
|
176858
177236
|
init_diagnostic_event_bus();
|
|
176859
|
-
var
|
|
177237
|
+
var logger252 = Logger.get("EntityIsolation");
|
|
176860
177238
|
var EntityIsolationServiceImpl = class {
|
|
176861
177239
|
isolatedEntities = /* @__PURE__ */ new Map();
|
|
176862
177240
|
isolationCallbacks = /* @__PURE__ */ new Map();
|
|
@@ -176924,13 +177302,13 @@ var EntityIsolationServiceImpl = class {
|
|
|
176924
177302
|
}
|
|
176925
177303
|
const parsed = this.parseEndpointPath(msg);
|
|
176926
177304
|
if (!parsed) {
|
|
176927
|
-
|
|
177305
|
+
logger252.warn("Could not parse entity from error:", msg);
|
|
176928
177306
|
return false;
|
|
176929
177307
|
}
|
|
176930
177308
|
const { bridgeId, entityName } = parsed;
|
|
176931
177309
|
const callback = this.isolationCallbacks.get(bridgeId);
|
|
176932
177310
|
if (!callback) {
|
|
176933
|
-
|
|
177311
|
+
logger252.warn(
|
|
176934
177312
|
`No isolation callback registered for bridge ${bridgeId}, entity: ${entityName}`
|
|
176935
177313
|
);
|
|
176936
177314
|
return false;
|
|
@@ -176945,7 +177323,7 @@ var EntityIsolationServiceImpl = class {
|
|
|
176945
177323
|
reason,
|
|
176946
177324
|
failedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
176947
177325
|
});
|
|
176948
|
-
|
|
177326
|
+
logger252.warn(
|
|
176949
177327
|
`Isolating entity "${entityName}" from bridge ${bridgeId} due to: ${reason}`
|
|
176950
177328
|
);
|
|
176951
177329
|
diagnosticEventBus.emit("entity_error", `Entity isolated: ${entityName}`, {
|
|
@@ -176957,7 +177335,7 @@ var EntityIsolationServiceImpl = class {
|
|
|
176957
177335
|
await callback(entityName);
|
|
176958
177336
|
return true;
|
|
176959
177337
|
} catch (e) {
|
|
176960
|
-
|
|
177338
|
+
logger252.error(`Failed to isolate entity ${entityName}:`, e);
|
|
176961
177339
|
return false;
|
|
176962
177340
|
}
|
|
176963
177341
|
}
|
|
@@ -176988,7 +177366,13 @@ var EntityIsolationService = new EntityIsolationServiceImpl();
|
|
|
176988
177366
|
|
|
176989
177367
|
// src/services/bridges/bridge-endpoint-manager.ts
|
|
176990
177368
|
var MAX_ENTITY_ID_LENGTH = 150;
|
|
176991
|
-
var ENDPOINT_REMOVAL_GRACE_MS =
|
|
177369
|
+
var ENDPOINT_REMOVAL_GRACE_MS = 3e5;
|
|
177370
|
+
function isEntityPart(p) {
|
|
177371
|
+
return typeof p.updateStates === "function";
|
|
177372
|
+
}
|
|
177373
|
+
function hasEntityIdentity(p) {
|
|
177374
|
+
return typeof p.entityId === "string";
|
|
177375
|
+
}
|
|
176992
177376
|
var BridgeEndpointManager = class extends Service {
|
|
176993
177377
|
constructor(client, registry3, mappingStorage, identityStorage, bridgeId, log, pluginManager, pluginRegistry, pluginInstaller) {
|
|
176994
177378
|
super("BridgeEndpointManager");
|
|
@@ -177026,11 +177410,15 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177026
177410
|
root;
|
|
177027
177411
|
entityIds = [];
|
|
177028
177412
|
unsubscribe;
|
|
177413
|
+
observingRequested = false;
|
|
177029
177414
|
_failedEntities = [];
|
|
177030
177415
|
mappingFingerprints = /* @__PURE__ */ new Map();
|
|
177031
|
-
// entityId -> first
|
|
177416
|
+
// entityId -> first absence stamp (grace window)
|
|
177032
177417
|
pendingRemovals = /* @__PURE__ */ new Map();
|
|
177033
177418
|
removalRecheckTimer = null;
|
|
177419
|
+
// Bumped on every stop, so a refresh that was already running cannot arm a
|
|
177420
|
+
// timer on a bridge that has since stopped (#438).
|
|
177421
|
+
lifecycle = 0;
|
|
177034
177422
|
pluginEndpoints = /* @__PURE__ */ new Map();
|
|
177035
177423
|
pluginStateUpdating = /* @__PURE__ */ new Set();
|
|
177036
177424
|
pluginListeners = /* @__PURE__ */ new Map();
|
|
@@ -177063,11 +177451,36 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177063
177451
|
);
|
|
177064
177452
|
return;
|
|
177065
177453
|
}
|
|
177454
|
+
const supplied = device.endpointType;
|
|
177066
177455
|
const initialState = {};
|
|
177067
177456
|
for (const cluster2 of device.clusters) {
|
|
177457
|
+
if (cluster2.clusterId === "pluginDevice" && supplied.behaviors?.pluginDevice == null && supplied.behaviors?.bridgedDeviceBasicInformation == null) {
|
|
177458
|
+
this.log.warn(
|
|
177459
|
+
`Plugin "${pluginName}": device "${device.id}" declares a "pluginDevice" cluster without owning that behavior, ignoring it`
|
|
177460
|
+
);
|
|
177461
|
+
continue;
|
|
177462
|
+
}
|
|
177068
177463
|
initialState[cluster2.clusterId] = cluster2.attributes;
|
|
177069
177464
|
}
|
|
177070
|
-
const
|
|
177465
|
+
const hasOwnIdentity = supplied.behaviors?.bridgedDeviceBasicInformation != null;
|
|
177466
|
+
const ownsPluginDevice = supplied.behaviors?.pluginDevice != null;
|
|
177467
|
+
const mutable = typeof supplied.with === "function" && typeof supplied.set === "function";
|
|
177468
|
+
if (!mutable && Object.keys(initialState).length > 0) {
|
|
177469
|
+
this.log.warn(
|
|
177470
|
+
`Plugin "${pluginName}": endpointType for device "${device.id}" cannot take its cluster config, skipping it`
|
|
177471
|
+
);
|
|
177472
|
+
return;
|
|
177473
|
+
}
|
|
177474
|
+
if (!hasOwnIdentity && (!mutable || ownsPluginDevice)) {
|
|
177475
|
+
this.log.warn(
|
|
177476
|
+
`Plugin "${pluginName}": device "${device.id}" mounts without BridgedDeviceBasicInformation, controllers may not show it`
|
|
177477
|
+
);
|
|
177478
|
+
}
|
|
177479
|
+
let base = device.endpointType;
|
|
177480
|
+
if (mutable && !hasOwnIdentity && !ownsPluginDevice) {
|
|
177481
|
+
base = base.with(PluginBasicInformationServer, PluginDeviceBehavior);
|
|
177482
|
+
initialState.pluginDevice = { device, pluginName };
|
|
177483
|
+
}
|
|
177071
177484
|
endpoint = new Endpoint(
|
|
177072
177485
|
Object.keys(initialState).length > 0 ? base.set(initialState) : base,
|
|
177073
177486
|
{ id: `plugin_${device.id}` }
|
|
@@ -177236,9 +177649,9 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177236
177649
|
await this.pluginManager.shutdownAll("Bridge stopping");
|
|
177237
177650
|
for (const [id, endpoint] of this.pluginEndpoints) {
|
|
177238
177651
|
try {
|
|
177239
|
-
await endpoint.
|
|
177652
|
+
await endpoint.close();
|
|
177240
177653
|
} catch (e) {
|
|
177241
|
-
this.log.warn(`Failed to
|
|
177654
|
+
this.log.warn(`Failed to close plugin endpoint ${id}:`, e);
|
|
177242
177655
|
}
|
|
177243
177656
|
}
|
|
177244
177657
|
this.pluginEndpoints.clear();
|
|
@@ -177278,7 +177691,7 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177278
177691
|
* Called by EntityIsolationService when a runtime error is detected.
|
|
177279
177692
|
*/
|
|
177280
177693
|
async isolateEntity(entityName) {
|
|
177281
|
-
const endpoints = this.root.parts.
|
|
177694
|
+
const endpoints = [...this.root.parts].filter(hasEntityIdentity);
|
|
177282
177695
|
const endpoint = endpoints.find(
|
|
177283
177696
|
(e) => !(e instanceof VacuumAreaSwitchEndpoint) && (e.id === entityName || e.entityId === entityName)
|
|
177284
177697
|
) ?? endpoints.find((e) => e.id === entityName);
|
|
@@ -177287,9 +177700,9 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177287
177700
|
`Isolating entity ${endpoint.entityId} due to runtime error`
|
|
177288
177701
|
);
|
|
177289
177702
|
try {
|
|
177290
|
-
await endpoint.
|
|
177703
|
+
await endpoint.close();
|
|
177291
177704
|
} catch (e) {
|
|
177292
|
-
this.log.error(`Failed to
|
|
177705
|
+
this.log.error(`Failed to close isolated endpoint:`, e);
|
|
177293
177706
|
}
|
|
177294
177707
|
this.pendingRemovals.delete(endpoint.entityId);
|
|
177295
177708
|
this.mappingFingerprints.delete(endpoint.entityId);
|
|
@@ -177298,7 +177711,7 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177298
177711
|
if (!(sw instanceof VacuumAreaSwitchEndpoint)) continue;
|
|
177299
177712
|
if (sw.vacuumEndpointId !== endpoint.id) continue;
|
|
177300
177713
|
try {
|
|
177301
|
-
await sw.
|
|
177714
|
+
await sw.close();
|
|
177302
177715
|
} catch (e) {
|
|
177303
177716
|
this.log.warn(`Failed to remove area switch ${sw.id}:`, e);
|
|
177304
177717
|
}
|
|
@@ -177315,11 +177728,13 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177315
177728
|
this.removalRecheckTimer = null;
|
|
177316
177729
|
}
|
|
177317
177730
|
if (this.pendingRemovals.size === 0) return;
|
|
177731
|
+
const lifecycle = this.lifecycle;
|
|
177318
177732
|
this.removalRecheckTimer = setTimeout(() => {
|
|
177319
177733
|
this.removalRecheckTimer = null;
|
|
177320
|
-
this.refreshDevices().catch(
|
|
177321
|
-
|
|
177322
|
-
|
|
177734
|
+
this.refreshDevices().catch((e) => {
|
|
177735
|
+
this.log.warn("Endpoint removal recheck failed:", e);
|
|
177736
|
+
if (lifecycle === this.lifecycle) this.scheduleRemovalRecheck();
|
|
177737
|
+
});
|
|
177323
177738
|
}, ENDPOINT_REMOVAL_GRACE_MS + 5e3);
|
|
177324
177739
|
}
|
|
177325
177740
|
getPluginDomainMappings() {
|
|
@@ -177358,7 +177773,8 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177358
177773
|
}
|
|
177359
177774
|
}
|
|
177360
177775
|
async startObserving() {
|
|
177361
|
-
this.
|
|
177776
|
+
this.clearSubscription();
|
|
177777
|
+
this.observingRequested = true;
|
|
177362
177778
|
if (!this.entityIds.length) {
|
|
177363
177779
|
return;
|
|
177364
177780
|
}
|
|
@@ -177382,14 +177798,32 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177382
177798
|
}
|
|
177383
177799
|
return [...ids];
|
|
177384
177800
|
}
|
|
177385
|
-
|
|
177801
|
+
clearSubscription() {
|
|
177386
177802
|
this.unsubscribe?.();
|
|
177387
177803
|
this.unsubscribe = void 0;
|
|
177388
177804
|
}
|
|
177805
|
+
stopObserving() {
|
|
177806
|
+
this.observingRequested = false;
|
|
177807
|
+
this.lifecycle++;
|
|
177808
|
+
this.clearSubscription();
|
|
177809
|
+
if (this.removalRecheckTimer) {
|
|
177810
|
+
clearTimeout(this.removalRecheckTimer);
|
|
177811
|
+
this.removalRecheckTimer = null;
|
|
177812
|
+
}
|
|
177813
|
+
}
|
|
177389
177814
|
async refreshDevices() {
|
|
177390
177815
|
this.registry.refresh();
|
|
177816
|
+
const lifecycle = this.lifecycle;
|
|
177817
|
+
const endpoints = [...this.root.parts].filter(hasEntityIdentity).filter((p) => !(p instanceof VacuumAreaSwitchEndpoint));
|
|
177818
|
+
const fullEntities = this.registry.fullEntities;
|
|
177819
|
+
if (!this.client.haRunning || Object.keys(fullEntities).length === 0) {
|
|
177820
|
+
this.pendingRemovals.clear();
|
|
177821
|
+
this.log.warn(
|
|
177822
|
+
`HA not running or registry empty, deferring reconcile of ${endpoints.length} endpoints`
|
|
177823
|
+
);
|
|
177824
|
+
return;
|
|
177825
|
+
}
|
|
177391
177826
|
this._failedEntities = [];
|
|
177392
|
-
const endpoints = this.root.parts.map((p) => p).filter((p) => !(p instanceof VacuumAreaSwitchEndpoint));
|
|
177393
177827
|
this.entityIds = this.registry.entityIds;
|
|
177394
177828
|
if (this.registry.isAutoComposedDevicesEnabled()) {
|
|
177395
177829
|
for (const eid of this.entityIds) {
|
|
@@ -177441,7 +177875,6 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177441
177875
|
this.mappingFingerprints.set(entityId, fp);
|
|
177442
177876
|
}
|
|
177443
177877
|
}
|
|
177444
|
-
const fullEntities = this.registry.fullEntities;
|
|
177445
177878
|
stampIdentityPresence(
|
|
177446
177879
|
this.identityStorage,
|
|
177447
177880
|
this.bridgeId,
|
|
@@ -177490,13 +177923,16 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177490
177923
|
this.pendingRemovals.delete(endpoint.entityId);
|
|
177491
177924
|
}
|
|
177492
177925
|
if (!present) {
|
|
177493
|
-
const
|
|
177494
|
-
if (
|
|
177495
|
-
this.pendingRemovals.set(endpoint.entityId,
|
|
177926
|
+
const entry = this.pendingRemovals.get(endpoint.entityId);
|
|
177927
|
+
if (entry == null) {
|
|
177928
|
+
this.pendingRemovals.set(endpoint.entityId, {
|
|
177929
|
+
since: now,
|
|
177930
|
+
generation: this.registry.snapshotGeneration
|
|
177931
|
+
});
|
|
177496
177932
|
existingEndpoints.push(endpoint);
|
|
177497
177933
|
continue;
|
|
177498
177934
|
}
|
|
177499
|
-
if (now - since < ENDPOINT_REMOVAL_GRACE_MS) {
|
|
177935
|
+
if (now - entry.since < ENDPOINT_REMOVAL_GRACE_MS || now - this.client.runningSince < ENDPOINT_REMOVAL_GRACE_MS || this.registry.snapshotGeneration <= entry.generation) {
|
|
177500
177936
|
existingEndpoints.push(endpoint);
|
|
177501
177937
|
continue;
|
|
177502
177938
|
}
|
|
@@ -177512,13 +177948,13 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177512
177948
|
this.pendingRemovals.delete(endpoint.entityId);
|
|
177513
177949
|
} else if (this.registry.isAutoComposedDevicesEnabled() && this.registry.isComposedSubEntityUsed(endpoint.entityId)) {
|
|
177514
177950
|
this.log.info(
|
|
177515
|
-
`
|
|
177951
|
+
`Removing standalone endpoint ${endpoint.entityId}, consumed by composed device`
|
|
177516
177952
|
);
|
|
177517
177953
|
try {
|
|
177518
|
-
await endpoint.
|
|
177954
|
+
await endpoint.close();
|
|
177519
177955
|
} catch (e) {
|
|
177520
177956
|
this.log.warn(
|
|
177521
|
-
`Failed to
|
|
177957
|
+
`Failed to remove composed sub-entity endpoint ${endpoint.entityId}:`,
|
|
177522
177958
|
e
|
|
177523
177959
|
);
|
|
177524
177960
|
}
|
|
@@ -177551,7 +177987,9 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177551
177987
|
}
|
|
177552
177988
|
}
|
|
177553
177989
|
}
|
|
177554
|
-
this.
|
|
177990
|
+
if (lifecycle === this.lifecycle) {
|
|
177991
|
+
this.scheduleRemovalRecheck();
|
|
177992
|
+
}
|
|
177555
177993
|
let memoryLimitReached = false;
|
|
177556
177994
|
for (const entityId of this.entityIds) {
|
|
177557
177995
|
if (!memoryLimitReached && isHeapUnderPressure()) {
|
|
@@ -177625,7 +178063,7 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177625
178063
|
}
|
|
177626
178064
|
}
|
|
177627
178065
|
await this.reconcileAreaSwitches();
|
|
177628
|
-
if (this.
|
|
178066
|
+
if (this.observingRequested) {
|
|
177629
178067
|
this.startObserving();
|
|
177630
178068
|
}
|
|
177631
178069
|
}
|
|
@@ -177757,10 +178195,10 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177757
178195
|
this.pendingStates = void 0;
|
|
177758
178196
|
this.pendingChanged = void 0;
|
|
177759
178197
|
if (queued) {
|
|
177760
|
-
|
|
178198
|
+
this.updateStates(
|
|
177761
178199
|
queued,
|
|
177762
178200
|
queuedChanged === void 0 ? null : queuedChanged
|
|
177763
|
-
);
|
|
178201
|
+
).catch((e) => this.log.warn("Queued state update failed:", e));
|
|
177764
178202
|
}
|
|
177765
178203
|
});
|
|
177766
178204
|
return this.updateInFlight;
|
|
@@ -177768,9 +178206,9 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177768
178206
|
async runUpdateStates(states, changed) {
|
|
177769
178207
|
const startMs = performance.now();
|
|
177770
178208
|
this.registry.mergeExternalStates(states);
|
|
177771
|
-
const allEndpoints = this.root.parts.
|
|
178209
|
+
const allEndpoints = [...this.root.parts].filter(isEntityPart);
|
|
177772
178210
|
const endpoints = changed === null ? allEndpoints : allEndpoints.filter(
|
|
177773
|
-
(e) => changed.has(e.entityId) || e.mappedEntityIds.some((id) => changed.has(id))
|
|
178211
|
+
(e) => changed.has(e.entityId) || (e.mappedEntityIds ?? []).some((id) => changed.has(id))
|
|
177774
178212
|
);
|
|
177775
178213
|
if (endpoints.length === 0) return;
|
|
177776
178214
|
const results = await Promise.allSettled(
|
|
@@ -177850,7 +178288,7 @@ var BridgeEndpointManager = class extends Service {
|
|
|
177850
178288
|
init_dist();
|
|
177851
178289
|
init_esm();
|
|
177852
178290
|
init_send_ha_message();
|
|
177853
|
-
import { callService as
|
|
178291
|
+
import { callService as callService2 } from "home-assistant-js-websocket";
|
|
177854
178292
|
import { keys as keys2, pickBy, values as values3 } from "lodash-es";
|
|
177855
178293
|
var BridgeRegistry = class _BridgeRegistry {
|
|
177856
178294
|
constructor(registry3, dataProvider, client) {
|
|
@@ -177899,6 +178337,10 @@ var BridgeRegistry = class _BridgeRegistry {
|
|
|
177899
178337
|
get fullEntities() {
|
|
177900
178338
|
return this.registry.entities;
|
|
177901
178339
|
}
|
|
178340
|
+
// Successful-reload counter, see HomeAssistantRegistry (#438).
|
|
178341
|
+
get snapshotGeneration() {
|
|
178342
|
+
return this.registry.snapshotGeneration;
|
|
178343
|
+
}
|
|
177902
178344
|
// composed sub-entities may sit outside the bridge filter (#408), so these
|
|
177903
178345
|
// fall back to the full HA registry. keep them separate from the strict
|
|
177904
178346
|
// accessors above, every other caller must stay filtered.
|
|
@@ -178236,7 +178678,7 @@ var BridgeRegistry = class _BridgeRegistry {
|
|
|
178236
178678
|
async resolveRoborockRooms(entityId) {
|
|
178237
178679
|
if (!this.client) return [];
|
|
178238
178680
|
try {
|
|
178239
|
-
const raw = await
|
|
178681
|
+
const raw = await callService2(
|
|
178240
178682
|
this.client.connection,
|
|
178241
178683
|
"roborock",
|
|
178242
178684
|
"get_maps",
|
|
@@ -178615,6 +179057,7 @@ function hashAreaId(areaId) {
|
|
|
178615
179057
|
init_dist();
|
|
178616
179058
|
init_esm7();
|
|
178617
179059
|
import * as os10 from "node:os";
|
|
179060
|
+
init_protocol3();
|
|
178618
179061
|
init_diagnostic_event_bus();
|
|
178619
179062
|
var imWrapMarker2 = /* @__PURE__ */ Symbol("hamh.wedgeImWrap");
|
|
178620
179063
|
var commandMessageTypes2 = [
|
|
@@ -178630,11 +179073,11 @@ function makeWarmStartState(state, now = (/* @__PURE__ */ new Date()).toISOStrin
|
|
|
178630
179073
|
return { ...state, last_updated: now };
|
|
178631
179074
|
}
|
|
178632
179075
|
var ServerModeBridge = class {
|
|
178633
|
-
constructor(
|
|
179076
|
+
constructor(logger255, dataProvider, endpointManager, server) {
|
|
178634
179077
|
this.dataProvider = dataProvider;
|
|
178635
179078
|
this.endpointManager = endpointManager;
|
|
178636
179079
|
this.server = server;
|
|
178637
|
-
this.log =
|
|
179080
|
+
this.log = logger255.get(`ServerModeBridge / ${dataProvider.id}`);
|
|
178638
179081
|
}
|
|
178639
179082
|
dataProvider;
|
|
178640
179083
|
endpointManager;
|
|
@@ -179014,12 +179457,18 @@ ${e?.toString()}`);
|
|
|
179014
179457
|
for (const s of [...sessionManager.sessions]) {
|
|
179015
179458
|
if (s !== newSession && !s.isClosing && s.peerNodeId === newSession.peerNodeId && s.fabric?.fabricIndex === newSession.fabric?.fabricIndex && s.subscriptions.size === 0) {
|
|
179016
179459
|
this.log.info(
|
|
179017
|
-
`
|
|
179460
|
+
`Session ${s.id} (peer ${s.peerNodeId}, 0 subs) replaced by session ${newSession.id}, closing it once it goes quiet`
|
|
179461
|
+
);
|
|
179462
|
+
const staleId = s.id;
|
|
179463
|
+
const armed = this.staleSessionTimers.get(staleId);
|
|
179464
|
+
if (armed) clearTimeout(armed);
|
|
179465
|
+
this.staleSessionTimers.set(
|
|
179466
|
+
staleId,
|
|
179467
|
+
setTimeout(() => {
|
|
179468
|
+
this.staleSessionTimers.delete(staleId);
|
|
179469
|
+
this.closeStaleSession(staleId, PRIMING_GRACE_MS);
|
|
179470
|
+
}, replacedSessionTimeoutMs(this.dataProvider.featureFlags))
|
|
179018
179471
|
);
|
|
179019
|
-
s.initiateForceClose({
|
|
179020
|
-
cause: new Error("stale session replaced by new session")
|
|
179021
|
-
}).catch(() => {
|
|
179022
|
-
});
|
|
179023
179472
|
}
|
|
179024
179473
|
}
|
|
179025
179474
|
const quietWindowMs = staleSessionQuietWindowMs(
|
|
@@ -179055,6 +179504,11 @@ ${e?.toString()}`);
|
|
|
179055
179504
|
};
|
|
179056
179505
|
this.sessionDeletedHandler = (session) => {
|
|
179057
179506
|
this.sessionStartedAt.delete(session.id);
|
|
179507
|
+
const armed = this.staleSessionTimers.get(session.id);
|
|
179508
|
+
if (armed) {
|
|
179509
|
+
clearTimeout(armed);
|
|
179510
|
+
this.staleSessionTimers.delete(session.id);
|
|
179511
|
+
}
|
|
179058
179512
|
const sessions = [...sessionManager.sessions];
|
|
179059
179513
|
this.log.warn(
|
|
179060
179514
|
`Session closed: id=${session.id} peer=${session.peerNodeId} | remaining sessions=${sessions.length}`
|
|
@@ -179163,7 +179617,7 @@ ${e?.toString()}`);
|
|
|
179163
179617
|
);
|
|
179164
179618
|
});
|
|
179165
179619
|
}
|
|
179166
|
-
closeStaleSession(sessionId) {
|
|
179620
|
+
closeStaleSession(sessionId, minQuietMs = 0) {
|
|
179167
179621
|
try {
|
|
179168
179622
|
const sessionManager = this.server.env.get(SessionManager);
|
|
179169
179623
|
for (const s of [...sessionManager.sessions]) {
|
|
@@ -179173,7 +179627,10 @@ ${e?.toString()}`);
|
|
|
179173
179627
|
const idleSec = Math.round((Date.now() - s.timestamp) / 1e3);
|
|
179174
179628
|
if (!staleSessionShouldClose(
|
|
179175
179629
|
s,
|
|
179176
|
-
|
|
179630
|
+
Math.max(
|
|
179631
|
+
staleSessionQuietWindowMs(this.dataProvider.featureFlags),
|
|
179632
|
+
minQuietMs
|
|
179633
|
+
)
|
|
179177
179634
|
)) {
|
|
179178
179635
|
this.log.info(
|
|
179179
179636
|
`Keeping session ${s.id} (peer ${s.peerNodeId}, 0 subs, last traffic ${idleSec}s ago)`
|
|
@@ -179182,7 +179639,7 @@ ${e?.toString()}`);
|
|
|
179182
179639
|
sessionId,
|
|
179183
179640
|
setTimeout(() => {
|
|
179184
179641
|
this.staleSessionTimers.delete(sessionId);
|
|
179185
|
-
this.closeStaleSession(sessionId);
|
|
179642
|
+
this.closeStaleSession(sessionId, minQuietMs);
|
|
179186
179643
|
}, deadSessionTimeoutMs(this.dataProvider.featureFlags))
|
|
179187
179644
|
);
|
|
179188
179645
|
break;
|
|
@@ -179211,6 +179668,9 @@ ${e?.toString()}`);
|
|
|
179211
179668
|
if (s.isClosing || s.subscriptions.size > 0) {
|
|
179212
179669
|
continue;
|
|
179213
179670
|
}
|
|
179671
|
+
if (this.staleSessionTimers.has(s.id)) {
|
|
179672
|
+
continue;
|
|
179673
|
+
}
|
|
179214
179674
|
const idleSec = Math.round((Date.now() - s.timestamp) / 1e3);
|
|
179215
179675
|
if (!staleSessionShouldClose(
|
|
179216
179676
|
s,
|
|
@@ -179776,7 +180236,7 @@ function ServerModeVacuumDevice(homeAssistantEntity, includeOnOff = false, clean
|
|
|
179776
180236
|
}
|
|
179777
180237
|
|
|
179778
180238
|
// src/matter/endpoints/server-mode-vacuum-endpoint.ts
|
|
179779
|
-
var
|
|
180239
|
+
var logger253 = Logger.get("ServerModeVacuumEndpoint");
|
|
179780
180240
|
var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEndpoint {
|
|
179781
180241
|
static async create(registry3, entityId, mapping, endpointId) {
|
|
179782
180242
|
const deviceRegistry = registry3.deviceOf(entityId);
|
|
@@ -179789,7 +180249,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179789
180249
|
if (mapping?.disableBatteryMapping && mapping.batteryEntity) {
|
|
179790
180250
|
effectiveMapping = { ...mapping, batteryEntity: void 0 };
|
|
179791
180251
|
}
|
|
179792
|
-
|
|
180252
|
+
logger253.info(
|
|
179793
180253
|
`${entityId}: device_id=${entity.device_id}, manualBattery=${mapping?.batteryEntity ?? "none"}`
|
|
179794
180254
|
);
|
|
179795
180255
|
if (entity.device_id) {
|
|
@@ -179804,15 +180264,15 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179804
180264
|
batteryEntity: batteryEntityId
|
|
179805
180265
|
};
|
|
179806
180266
|
registry3.markBatteryEntityUsed(batteryEntityId);
|
|
179807
|
-
|
|
180267
|
+
logger253.info(`${entityId}: Auto-assigned battery ${batteryEntityId}`);
|
|
179808
180268
|
} else {
|
|
179809
180269
|
const attrs = state.attributes;
|
|
179810
180270
|
if (attrs.battery_level != null || attrs.battery != null) {
|
|
179811
|
-
|
|
180271
|
+
logger253.info(
|
|
179812
180272
|
`${entityId}: No battery entity found, using battery attribute from vacuum state`
|
|
179813
180273
|
);
|
|
179814
180274
|
} else {
|
|
179815
|
-
|
|
180275
|
+
logger253.warn(
|
|
179816
180276
|
`${entityId}: No battery entity found for device ${entity.device_id}`
|
|
179817
180277
|
);
|
|
179818
180278
|
}
|
|
@@ -179827,7 +180287,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179827
180287
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
179828
180288
|
cleaningModeEntity: vacuumEntities.cleaningModeEntity
|
|
179829
180289
|
};
|
|
179830
|
-
|
|
180290
|
+
logger253.info(
|
|
179831
180291
|
`${entityId}: Auto-assigned cleaningMode ${vacuumEntities.cleaningModeEntity}`
|
|
179832
180292
|
);
|
|
179833
180293
|
}
|
|
@@ -179837,7 +180297,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179837
180297
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
179838
180298
|
suctionLevelEntity: vacuumEntities.suctionLevelEntity
|
|
179839
180299
|
};
|
|
179840
|
-
|
|
180300
|
+
logger253.info(
|
|
179841
180301
|
`${entityId}: Auto-assigned suctionLevel ${vacuumEntities.suctionLevelEntity}`
|
|
179842
180302
|
);
|
|
179843
180303
|
}
|
|
@@ -179847,7 +180307,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179847
180307
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
179848
180308
|
mopIntensityEntity: vacuumEntities.mopIntensityEntity
|
|
179849
180309
|
};
|
|
179850
|
-
|
|
180310
|
+
logger253.info(
|
|
179851
180311
|
`${entityId}: Auto-assigned mopIntensity ${vacuumEntities.mopIntensityEntity}`
|
|
179852
180312
|
);
|
|
179853
180313
|
}
|
|
@@ -179857,7 +180317,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179857
180317
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
179858
180318
|
currentRoomEntity: vacuumEntities.currentRoomEntity
|
|
179859
180319
|
};
|
|
179860
|
-
|
|
180320
|
+
logger253.info(
|
|
179861
180321
|
`${entityId}: Auto-assigned currentRoom ${vacuumEntities.currentRoomEntity}`
|
|
179862
180322
|
);
|
|
179863
180323
|
}
|
|
@@ -179872,7 +180332,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179872
180332
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
179873
180333
|
cleanAreaRooms
|
|
179874
180334
|
};
|
|
179875
|
-
|
|
180335
|
+
logger253.info(
|
|
179876
180336
|
`${entityId}: Using ${cleanAreaRooms.length} HA areas via CLEAN_AREA`
|
|
179877
180337
|
);
|
|
179878
180338
|
}
|
|
@@ -179893,7 +180353,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179893
180353
|
rooms: roomsObj
|
|
179894
180354
|
}
|
|
179895
180355
|
};
|
|
179896
|
-
|
|
180356
|
+
logger253.info(
|
|
179897
180357
|
`${entityId}: Auto-detected ${valetudoRooms.length} Valetudo segments`
|
|
179898
180358
|
);
|
|
179899
180359
|
} else {
|
|
@@ -179910,14 +180370,14 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179910
180370
|
rooms: roomsObj
|
|
179911
180371
|
}
|
|
179912
180372
|
};
|
|
179913
|
-
|
|
180373
|
+
logger253.info(
|
|
179914
180374
|
`${entityId}: Auto-detected ${roborockRooms.length} Roborock rooms`
|
|
179915
180375
|
);
|
|
179916
180376
|
}
|
|
179917
180377
|
}
|
|
179918
180378
|
}
|
|
179919
180379
|
} else {
|
|
179920
|
-
|
|
180380
|
+
logger253.warn(`${entityId}: No device_id, cannot auto-assign battery`);
|
|
179921
180381
|
}
|
|
179922
180382
|
const payload = {
|
|
179923
180383
|
entity_id: entityId,
|
|
@@ -179990,11 +180450,11 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
179990
180450
|
}
|
|
179991
180451
|
if (mappedChanged) {
|
|
179992
180452
|
this.pendingMappedChange = true;
|
|
179993
|
-
|
|
180453
|
+
logger253.debug(
|
|
179994
180454
|
`Mapped entity change detected for ${this.entityId}, forcing update`
|
|
179995
180455
|
);
|
|
179996
180456
|
}
|
|
179997
|
-
|
|
180457
|
+
logger253.debug(
|
|
179998
180458
|
`State update received for ${this.entityId}: state=${state.state}`
|
|
179999
180459
|
);
|
|
180000
180460
|
this.lastState = state;
|
|
@@ -180057,8 +180517,20 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
180057
180517
|
log;
|
|
180058
180518
|
entityIds = [];
|
|
180059
180519
|
unsubscribe;
|
|
180520
|
+
observingRequested = false;
|
|
180060
180521
|
_failedEntities = [];
|
|
180061
180522
|
endpoints = /* @__PURE__ */ new Map();
|
|
180523
|
+
// Same grace as the aggregator manager: server mode deleted on the FIRST
|
|
180524
|
+
// refresh an entity was absent, so one partial HA snapshot re-minted the
|
|
180525
|
+
// device (#438).
|
|
180526
|
+
pendingRemovals = /* @__PURE__ */ new Map();
|
|
180527
|
+
removalRecheckTimer = null;
|
|
180528
|
+
// endpoint id -> entity that closed but may come back (disable). Its number
|
|
180529
|
+
// is still parked, so nobody else may mount on that id (#438).
|
|
180530
|
+
parkedEndpointIds = /* @__PURE__ */ new Map();
|
|
180531
|
+
// Bumped on every stop, so a refresh that was already running cannot arm a
|
|
180532
|
+
// timer on a bridge that has since stopped.
|
|
180533
|
+
lifecycle = 0;
|
|
180062
180534
|
get failedEntities() {
|
|
180063
180535
|
return this._failedEntities;
|
|
180064
180536
|
}
|
|
@@ -180076,6 +180548,11 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
180076
180548
|
}
|
|
180077
180549
|
async dispose() {
|
|
180078
180550
|
this.stopObserving();
|
|
180551
|
+
if (this.removalRecheckTimer) {
|
|
180552
|
+
clearTimeout(this.removalRecheckTimer);
|
|
180553
|
+
this.removalRecheckTimer = null;
|
|
180554
|
+
}
|
|
180555
|
+
this.pendingRemovals.clear();
|
|
180079
180556
|
for (const [entityId, entry] of this.endpoints) {
|
|
180080
180557
|
try {
|
|
180081
180558
|
await entry.endpoint.close();
|
|
@@ -180089,7 +180566,8 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
180089
180566
|
this.endpoints.clear();
|
|
180090
180567
|
}
|
|
180091
180568
|
async startObserving() {
|
|
180092
|
-
this.
|
|
180569
|
+
this.clearSubscription();
|
|
180570
|
+
this.observingRequested = true;
|
|
180093
180571
|
if (!this.entityIds.length) {
|
|
180094
180572
|
return;
|
|
180095
180573
|
}
|
|
@@ -180109,10 +180587,19 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
180109
180587
|
}
|
|
180110
180588
|
return [...ids];
|
|
180111
180589
|
}
|
|
180112
|
-
|
|
180590
|
+
clearSubscription() {
|
|
180113
180591
|
this.unsubscribe?.();
|
|
180114
180592
|
this.unsubscribe = void 0;
|
|
180115
180593
|
}
|
|
180594
|
+
stopObserving() {
|
|
180595
|
+
this.observingRequested = false;
|
|
180596
|
+
this.lifecycle++;
|
|
180597
|
+
this.clearSubscription();
|
|
180598
|
+
if (this.removalRecheckTimer) {
|
|
180599
|
+
clearTimeout(this.removalRecheckTimer);
|
|
180600
|
+
this.removalRecheckTimer = null;
|
|
180601
|
+
}
|
|
180602
|
+
}
|
|
180116
180603
|
/** Primary first (the entity the first include matcher tests true for). */
|
|
180117
180604
|
orderEntityIds(ids) {
|
|
180118
180605
|
const firstMatcher = this.dataProvider.filter?.include?.[0];
|
|
@@ -180135,6 +180622,44 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
180135
180622
|
this.endpoints.delete(entityId);
|
|
180136
180623
|
}
|
|
180137
180624
|
}
|
|
180625
|
+
// Absence-driven removals wait out the grace window AND a fresh successful
|
|
180626
|
+
// HA reload, so restarts and stale snapshots never erase numbers (#438).
|
|
180627
|
+
// Returns the ids whose absence is confirmed, ready for removeEndpoints.
|
|
180628
|
+
removableAfterGrace(entityIds) {
|
|
180629
|
+
const now = Date.now();
|
|
180630
|
+
const generation = this.registry.snapshotGeneration;
|
|
180631
|
+
const ready = [];
|
|
180632
|
+
for (const entityId of entityIds) {
|
|
180633
|
+
const entry = this.pendingRemovals.get(entityId);
|
|
180634
|
+
if (entry == null) {
|
|
180635
|
+
this.pendingRemovals.set(entityId, { since: now, generation });
|
|
180636
|
+
continue;
|
|
180637
|
+
}
|
|
180638
|
+
if (now - entry.since < ENDPOINT_REMOVAL_GRACE_MS || now - this.client.runningSince < ENDPOINT_REMOVAL_GRACE_MS || generation <= entry.generation) {
|
|
180639
|
+
continue;
|
|
180640
|
+
}
|
|
180641
|
+
ready.push(entityId);
|
|
180642
|
+
this.pendingRemovals.delete(entityId);
|
|
180643
|
+
}
|
|
180644
|
+
return ready;
|
|
180645
|
+
}
|
|
180646
|
+
// refreshDevices only runs on registry-fingerprint changes, which may not
|
|
180647
|
+
// recur, so drive held removals to completion ourselves after the grace.
|
|
180648
|
+
scheduleRemovalRecheck() {
|
|
180649
|
+
if (this.removalRecheckTimer) {
|
|
180650
|
+
clearTimeout(this.removalRecheckTimer);
|
|
180651
|
+
this.removalRecheckTimer = null;
|
|
180652
|
+
}
|
|
180653
|
+
if (this.pendingRemovals.size === 0) return;
|
|
180654
|
+
const lifecycle = this.lifecycle;
|
|
180655
|
+
this.removalRecheckTimer = setTimeout(() => {
|
|
180656
|
+
this.removalRecheckTimer = null;
|
|
180657
|
+
this.refreshDevices().catch((e) => {
|
|
180658
|
+
this.log.warn("Endpoint removal recheck failed:", e);
|
|
180659
|
+
if (lifecycle === this.lifecycle) this.scheduleRemovalRecheck();
|
|
180660
|
+
});
|
|
180661
|
+
}, ENDPOINT_REMOVAL_GRACE_MS + 5e3);
|
|
180662
|
+
}
|
|
180138
180663
|
// Like removeEndpoints but close() keeps the persisted number pre-allocated,
|
|
180139
180664
|
// so a same-id recreate reuses it. Used on rename and same-id recreates (#404).
|
|
180140
180665
|
async closeEndpoint(entityId) {
|
|
@@ -180144,29 +180669,40 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
180144
180669
|
await entry.endpoint.close();
|
|
180145
180670
|
} catch (e) {
|
|
180146
180671
|
this.log.warn(`Failed to close endpoint ${entityId}:`, e);
|
|
180672
|
+
return;
|
|
180147
180673
|
}
|
|
180148
180674
|
this.serverNode.forgetDevice(entry.endpoint);
|
|
180149
180675
|
this.endpoints.delete(entityId);
|
|
180150
180676
|
}
|
|
180151
180677
|
async refreshDevices() {
|
|
180152
180678
|
this.registry.refresh();
|
|
180153
|
-
|
|
180154
|
-
this.entityIds = this.registry.entityIds;
|
|
180679
|
+
const lifecycle = this.lifecycle;
|
|
180155
180680
|
const fullEntities = this.registry.fullEntities;
|
|
180156
|
-
stampIdentityPresence(
|
|
180157
|
-
this.identityStorage,
|
|
180158
|
-
this.dataProvider.id,
|
|
180159
|
-
buildPresentIdentityKeys(fullEntities)
|
|
180160
|
-
);
|
|
180161
|
-
stampMappingPresence(
|
|
180162
|
-
this.mappingStorage,
|
|
180163
|
-
this.dataProvider.id,
|
|
180164
|
-
buildPresentEntityIds(fullEntities)
|
|
180165
|
-
);
|
|
180166
180681
|
try {
|
|
180682
|
+
if (!this.client.haRunning || Object.keys(fullEntities).length === 0) {
|
|
180683
|
+
this.pendingRemovals.clear();
|
|
180684
|
+
this.log.warn(
|
|
180685
|
+
"HA not running or registry empty, deferring server mode reconcile"
|
|
180686
|
+
);
|
|
180687
|
+
return;
|
|
180688
|
+
}
|
|
180689
|
+
this._failedEntities = [];
|
|
180690
|
+
this.entityIds = this.registry.entityIds;
|
|
180691
|
+
stampIdentityPresence(
|
|
180692
|
+
this.identityStorage,
|
|
180693
|
+
this.dataProvider.id,
|
|
180694
|
+
buildPresentIdentityKeys(fullEntities)
|
|
180695
|
+
);
|
|
180696
|
+
stampMappingPresence(
|
|
180697
|
+
this.mappingStorage,
|
|
180698
|
+
this.dataProvider.id,
|
|
180699
|
+
buildPresentEntityIds(fullEntities)
|
|
180700
|
+
);
|
|
180167
180701
|
if (this.entityIds.length === 0) {
|
|
180168
180702
|
this.log.warn("Server mode bridge has no entities configured");
|
|
180169
|
-
await this.removeEndpoints(
|
|
180703
|
+
await this.removeEndpoints(
|
|
180704
|
+
this.removableAfterGrace([...this.endpoints.keys()])
|
|
180705
|
+
);
|
|
180170
180706
|
this._failedEntities.push({
|
|
180171
180707
|
entityId: this.dataProvider.filter?.include?.[0]?.value ?? "(no entity configured)",
|
|
180172
180708
|
reason: "No Home Assistant entity matched this bridge's filter. Check for typos or renamed/removed entities."
|
|
@@ -180212,19 +180748,35 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
180212
180748
|
endpointIdToEntity.set(resolved.endpointId, entityId);
|
|
180213
180749
|
}
|
|
180214
180750
|
const keep = new Set(orderedIds);
|
|
180751
|
+
for (const id of keep) {
|
|
180752
|
+
this.pendingRemovals.delete(id);
|
|
180753
|
+
}
|
|
180215
180754
|
const removed = [...this.endpoints.keys()].filter((id) => !keep.has(id));
|
|
180216
|
-
let structureChanged = removed.length > 0;
|
|
180217
180755
|
const genuinelyRemoved = [];
|
|
180218
180756
|
for (const oldId of removed) {
|
|
180219
180757
|
const entry = this.endpoints.get(oldId);
|
|
180220
180758
|
const claimant = entry ? endpointIdToEntity.get(entry.endpoint.id) : void 0;
|
|
180221
180759
|
if (entry && claimant != null && claimant !== oldId) {
|
|
180222
180760
|
await this.closeEndpoint(oldId);
|
|
180761
|
+
this.pendingRemovals.delete(oldId);
|
|
180223
180762
|
} else {
|
|
180224
180763
|
genuinelyRemoved.push(oldId);
|
|
180225
180764
|
}
|
|
180226
180765
|
}
|
|
180227
|
-
|
|
180766
|
+
const confirmedRemoved = this.removableAfterGrace(genuinelyRemoved);
|
|
180767
|
+
let structureChanged = removed.length > genuinelyRemoved.length || confirmedRemoved.length > 0;
|
|
180768
|
+
await this.removeEndpoints(confirmedRemoved);
|
|
180769
|
+
for (const entityId of orderedIds) {
|
|
180770
|
+
const mapping = this.getEntityMapping(entityId);
|
|
180771
|
+
if (!mapping?.disabled) continue;
|
|
180772
|
+
for (const [id, owner] of this.parkedEndpointIds) {
|
|
180773
|
+
if (owner === entityId) this.parkedEndpointIds.delete(id);
|
|
180774
|
+
}
|
|
180775
|
+
this.parkedEndpointIds.set(
|
|
180776
|
+
this.endpoints.get(entityId)?.endpoint.id ?? resolvedByEntity.get(entityId)?.endpointId ?? createEndpointId(entityId, mapping.customName),
|
|
180777
|
+
entityId
|
|
180778
|
+
);
|
|
180779
|
+
}
|
|
180228
180780
|
for (const entityId of orderedIds) {
|
|
180229
180781
|
const mapping = this.getEntityMapping(entityId);
|
|
180230
180782
|
if (mapping?.disabled) {
|
|
@@ -180232,7 +180784,7 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
180232
180784
|
`Entity in server mode bridge is disabled: ${entityId}`
|
|
180233
180785
|
);
|
|
180234
180786
|
if (this.endpoints.has(entityId)) {
|
|
180235
|
-
await this.
|
|
180787
|
+
await this.closeEndpoint(entityId);
|
|
180236
180788
|
structureChanged = true;
|
|
180237
180789
|
}
|
|
180238
180790
|
this._failedEntities.push({
|
|
@@ -180271,10 +180823,11 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
180271
180823
|
const collision = [...this.endpoints.entries()].find(
|
|
180272
180824
|
([, entry]) => entry.endpoint.id === endpointId
|
|
180273
180825
|
);
|
|
180274
|
-
|
|
180826
|
+
const parkedBy = this.parkedEndpointIds.get(endpointId);
|
|
180827
|
+
if (collision || parkedBy != null && parkedBy !== entityId) {
|
|
180275
180828
|
this._failedEntities.push({
|
|
180276
180829
|
entityId,
|
|
180277
|
-
reason: `Endpoint id collides with ${collision[0]}. Set distinct custom names.`
|
|
180830
|
+
reason: `Endpoint id collides with ${collision?.[0] ?? parkedBy}. Set distinct custom names.`
|
|
180278
180831
|
});
|
|
180279
180832
|
continue;
|
|
180280
180833
|
}
|
|
@@ -180312,6 +180865,11 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
180312
180865
|
}
|
|
180313
180866
|
await this.serverNode.addDevice(endpoint);
|
|
180314
180867
|
this.endpoints.set(entityId, { endpoint, fingerprint });
|
|
180868
|
+
for (const [id, owner] of this.parkedEndpointIds) {
|
|
180869
|
+
if (id === endpointId || owner === entityId) {
|
|
180870
|
+
this.parkedEndpointIds.delete(id);
|
|
180871
|
+
}
|
|
180872
|
+
}
|
|
180315
180873
|
structureChanged = true;
|
|
180316
180874
|
this.log.info(`Server mode: Added device ${entityId}`);
|
|
180317
180875
|
} catch (e) {
|
|
@@ -180331,7 +180889,10 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
180331
180889
|
}
|
|
180332
180890
|
}
|
|
180333
180891
|
} finally {
|
|
180334
|
-
if (this.
|
|
180892
|
+
if (lifecycle === this.lifecycle) {
|
|
180893
|
+
this.scheduleRemovalRecheck();
|
|
180894
|
+
}
|
|
180895
|
+
if (this.observingRequested) {
|
|
180335
180896
|
this.startObserving();
|
|
180336
180897
|
}
|
|
180337
180898
|
}
|
|
@@ -180572,10 +181133,10 @@ var BridgeEnvironmentFactory = class extends BridgeFactory {
|
|
|
180572
181133
|
// src/core/ioc/app-environment.ts
|
|
180573
181134
|
var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
180574
181135
|
constructor(rootEnv, options) {
|
|
180575
|
-
const
|
|
181136
|
+
const logger255 = rootEnv.get(LoggerService);
|
|
180576
181137
|
super({
|
|
180577
181138
|
id: "App",
|
|
180578
|
-
log:
|
|
181139
|
+
log: logger255.get("AppContainer"),
|
|
180579
181140
|
parent: rootEnv
|
|
180580
181141
|
});
|
|
180581
181142
|
this.options = options;
|
|
@@ -180589,8 +181150,8 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
180589
181150
|
}
|
|
180590
181151
|
construction;
|
|
180591
181152
|
async init() {
|
|
180592
|
-
const
|
|
180593
|
-
this.set(LoggerService,
|
|
181153
|
+
const logger255 = this.get(LoggerService);
|
|
181154
|
+
this.set(LoggerService, logger255);
|
|
180594
181155
|
this.set(AppStorage, new AppStorage(await this.load(StorageService)));
|
|
180595
181156
|
this.set(BridgeStorage, new BridgeStorage(await this.load(AppStorage)));
|
|
180596
181157
|
this.set(
|
|
@@ -180611,7 +181172,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
180611
181172
|
);
|
|
180612
181173
|
this.set(
|
|
180613
181174
|
HomeAssistantClient,
|
|
180614
|
-
new HomeAssistantClient(
|
|
181175
|
+
new HomeAssistantClient(logger255, this.options.homeAssistant)
|
|
180615
181176
|
);
|
|
180616
181177
|
this.set(
|
|
180617
181178
|
HomeAssistantConfig,
|
|
@@ -180619,7 +181180,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
180619
181180
|
);
|
|
180620
181181
|
this.set(
|
|
180621
181182
|
HomeAssistantActions,
|
|
180622
|
-
new HomeAssistantActions(
|
|
181183
|
+
new HomeAssistantActions(logger255, await this.load(HomeAssistantClient))
|
|
180623
181184
|
);
|
|
180624
181185
|
this.set(
|
|
180625
181186
|
HomeAssistantRegistry,
|
|
@@ -180655,7 +181216,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
180655
181216
|
this.set(
|
|
180656
181217
|
WebApi,
|
|
180657
181218
|
new WebApi(
|
|
180658
|
-
|
|
181219
|
+
logger255,
|
|
180659
181220
|
await this.load(BridgeService),
|
|
180660
181221
|
await this.load(HomeAssistantClient),
|
|
180661
181222
|
await this.load(HomeAssistantRegistry),
|
|
@@ -180676,7 +181237,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
180676
181237
|
|
|
180677
181238
|
// src/matter/patches/patch-level-control-tlv.ts
|
|
180678
181239
|
init_esm();
|
|
180679
|
-
var
|
|
181240
|
+
var logger254 = Logger.get("PatchLevelControlTlv");
|
|
180680
181241
|
var optionalFieldModels = /* @__PURE__ */ new WeakSet();
|
|
180681
181242
|
var fieldModelMandatoryGetterPatched = false;
|
|
180682
181243
|
function patchLevelControlTlv() {
|
|
@@ -180732,11 +181293,11 @@ function patchLevelControlTlv() {
|
|
|
180732
181293
|
patched++;
|
|
180733
181294
|
}
|
|
180734
181295
|
if (patched > 0) {
|
|
180735
|
-
|
|
181296
|
+
logger254.info(
|
|
180736
181297
|
`Patched ${patched} LevelControl TLV schema(s): transitionTime is now optional (Google Home compatibility)`
|
|
180737
181298
|
);
|
|
180738
181299
|
} else {
|
|
180739
|
-
|
|
181300
|
+
logger254.warn(
|
|
180740
181301
|
"Failed to patch LevelControl TLV schemas, field definitions not found. Google Home brightness adjustment may not work.",
|
|
180741
181302
|
{
|
|
180742
181303
|
moveToLevel: describeFields(
|
|
@@ -182478,6 +183039,7 @@ export {
|
|
|
182478
183039
|
@matter/main/dist/esm/version.js:
|
|
182479
183040
|
@matter/main/dist/esm/index.js:
|
|
182480
183041
|
@matter/main/dist/esm/protocol.js:
|
|
183042
|
+
@matter/main/dist/esm/types.js:
|
|
182481
183043
|
@matter/types/dist/esm/clusters/fan-control.js:
|
|
182482
183044
|
@matter/node/dist/esm/behaviors/fan-control/FanControlBehavior.js:
|
|
182483
183045
|
@matter/node/dist/esm/behaviors/fan-control/FanControlServer.js:
|
|
@@ -182908,7 +183470,6 @@ export {
|
|
|
182908
183470
|
@matter/node/dist/esm/devices/index.js:
|
|
182909
183471
|
@matter/main/dist/esm/devices.js:
|
|
182910
183472
|
@matter/main/dist/esm/node.js:
|
|
182911
|
-
@matter/main/dist/esm/types.js:
|
|
182912
183473
|
@matter/node/dist/esm/behaviors/account-login/index.js:
|
|
182913
183474
|
@matter/node/dist/esm/behaviors/actions/ActionsClient.js:
|
|
182914
183475
|
@matter/node/dist/esm/behaviors/actions/index.js:
|
|
@@ -183133,6 +183694,13 @@ export {
|
|
|
183133
183694
|
@matter/node/dist/esm/behaviors/zone-management/index.js:
|
|
183134
183695
|
@matter/node/dist/esm/behaviors/index.js:
|
|
183135
183696
|
@matter/main/dist/esm/behaviors.js:
|
|
183697
|
+
@matter/types/dist/esm/clusters/alarm-base.js:
|
|
183698
|
+
@matter/types/dist/esm/clusters/concentration-measurement.js:
|
|
183699
|
+
@matter/types/dist/esm/clusters/label.js:
|
|
183700
|
+
@matter/types/dist/esm/clusters/resource-monitoring.js:
|
|
183701
|
+
@matter/types/dist/esm/clusters/web-rtc-transport-definitions.js:
|
|
183702
|
+
@matter/types/dist/esm/clusters/index.js:
|
|
183703
|
+
@matter/main/dist/esm/clusters.js:
|
|
183136
183704
|
@matter/node/dist/esm/endpoints/base.js:
|
|
183137
183705
|
@matter/node/dist/esm/endpoints/bridged-node.js:
|
|
183138
183706
|
@matter/node/dist/esm/endpoints/device-energy-management.js:
|
|
@@ -183144,13 +183712,6 @@ export {
|
|
|
183144
183712
|
@matter/node/dist/esm/endpoints/secondary-network-interface.js:
|
|
183145
183713
|
@matter/node/dist/esm/endpoints/index.js:
|
|
183146
183714
|
@matter/main/dist/esm/endpoints.js:
|
|
183147
|
-
@matter/types/dist/esm/clusters/alarm-base.js:
|
|
183148
|
-
@matter/types/dist/esm/clusters/concentration-measurement.js:
|
|
183149
|
-
@matter/types/dist/esm/clusters/label.js:
|
|
183150
|
-
@matter/types/dist/esm/clusters/resource-monitoring.js:
|
|
183151
|
-
@matter/types/dist/esm/clusters/web-rtc-transport-definitions.js:
|
|
183152
|
-
@matter/types/dist/esm/clusters/index.js:
|
|
183153
|
-
@matter/main/dist/esm/clusters.js:
|
|
183154
183715
|
@matter/main/dist/esm/model.js:
|
|
183155
183716
|
@matter/main/dist/esm/forwards/clusters/level-control.js:
|
|
183156
183717
|
@matter/main/dist/esm/forwards/behaviors/boolean-state.js:
|