@riddix/hamh 2.1.0-alpha.836 → 2.1.0-alpha.838
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/backend/cli.js
CHANGED
|
@@ -1767,8 +1767,8 @@ var init_Cancelable = __esm({
|
|
|
1767
1767
|
};
|
|
1768
1768
|
return result;
|
|
1769
1769
|
}
|
|
1770
|
-
static set logger(
|
|
1771
|
-
this.#logger =
|
|
1770
|
+
static set logger(logger248) {
|
|
1771
|
+
this.#logger = logger248;
|
|
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, logger248, 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 = logger248;
|
|
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 logger248 = Logger.get(this.#subject.constructor.name);
|
|
5691
|
+
logger248.error(...args);
|
|
5692
5692
|
}
|
|
5693
5693
|
#createErrorHandler(name) {
|
|
5694
5694
|
return (e) => {
|
|
@@ -64070,8 +64070,8 @@ var init_NodeSession = __esm({
|
|
|
64070
64070
|
return session?.type === SessionType.Unicast;
|
|
64071
64071
|
}
|
|
64072
64072
|
NodeSession2.is = is;
|
|
64073
|
-
function logNew(
|
|
64074
|
-
|
|
64073
|
+
function logNew(logger248, operation, session, messenger, fabric, peerNodeId) {
|
|
64074
|
+
logger248.info(
|
|
64075
64075
|
session.via,
|
|
64076
64076
|
`${operation} session with`,
|
|
64077
64077
|
Diagnostic.strong(PeerAddress({ fabricIndex: fabric.fabricIndex, nodeId: peerNodeId }).toString()),
|
|
@@ -117714,11 +117714,11 @@ var init_Api = __esm({
|
|
|
117714
117714
|
}
|
|
117715
117715
|
Api2.resourceFor = resourceFor;
|
|
117716
117716
|
function log(level, facility, id, ...message) {
|
|
117717
|
-
let
|
|
117718
|
-
if (!
|
|
117719
|
-
loggers.set(facility,
|
|
117717
|
+
let logger248 = loggers.get(facility);
|
|
117718
|
+
if (!logger248) {
|
|
117719
|
+
loggers.set(facility, logger248 = Logger.get(facility));
|
|
117720
117720
|
}
|
|
117721
|
-
|
|
117721
|
+
logger248[level](Diagnostic.via(id || "(anon)"), message);
|
|
117722
117722
|
}
|
|
117723
117723
|
Api2.log = log;
|
|
117724
117724
|
function logRequest(facility, id, method, target) {
|
|
@@ -131221,6 +131221,13 @@ var init_controller_compat = __esm({
|
|
|
131221
131221
|
aqara: "yes",
|
|
131222
131222
|
note: "Aqara lists battery storage; others show battery inside a device."
|
|
131223
131223
|
},
|
|
131224
|
+
1292: {
|
|
131225
|
+
apple: "no",
|
|
131226
|
+
google: "no",
|
|
131227
|
+
alexa: "no",
|
|
131228
|
+
aqara: "yes",
|
|
131229
|
+
note: "HA and Aqara render EnergyEvse; SmartThings announced support, unconfirmed. Bridged EVSE can break Alexa device recognition, keep it off Alexa bridges."
|
|
131230
|
+
},
|
|
131224
131231
|
39: {
|
|
131225
131232
|
apple: "no",
|
|
131226
131233
|
google: "no",
|
|
@@ -132624,10 +132631,10 @@ var init_home_assistant_actions = __esm({
|
|
|
132624
132631
|
circuitBreakerResetMs: 3e4
|
|
132625
132632
|
};
|
|
132626
132633
|
HomeAssistantActions = class extends Service {
|
|
132627
|
-
constructor(
|
|
132634
|
+
constructor(logger248, client, config11) {
|
|
132628
132635
|
super("HomeAssistantActions");
|
|
132629
132636
|
this.client = client;
|
|
132630
|
-
this.log =
|
|
132637
|
+
this.log = logger248.get(this);
|
|
132631
132638
|
this.config = { ...defaultConfig, ...config11 };
|
|
132632
132639
|
this.circuitBreaker = new CircuitBreaker(
|
|
132633
132640
|
this.config.circuitBreakerThreshold,
|
|
@@ -132973,10 +132980,10 @@ var DiagnosticService = class {
|
|
|
132973
132980
|
};
|
|
132974
132981
|
|
|
132975
132982
|
// src/api/access-log.ts
|
|
132976
|
-
function accessLogger(
|
|
132983
|
+
function accessLogger(logger248) {
|
|
132977
132984
|
return (req, res, next) => {
|
|
132978
132985
|
res.on("finish", () => {
|
|
132979
|
-
|
|
132986
|
+
logger248.debug(
|
|
132980
132987
|
`${req.method} ${decodeURI(req.originalUrl)} ${res.statusCode} ${res.statusMessage} from ${req.socket.remoteAddress}`
|
|
132981
132988
|
);
|
|
132982
132989
|
});
|
|
@@ -133161,6 +133168,8 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
|
|
|
133161
133168
|
currentEntity: config11.currentEntity,
|
|
133162
133169
|
batteryPowerEntity: config11.batteryPowerEntity,
|
|
133163
133170
|
batteryEnergyEntity: config11.batteryEnergyEntity,
|
|
133171
|
+
chargingSwitchEntity: config11.chargingSwitchEntity,
|
|
133172
|
+
currentLimitEntity: config11.currentLimitEntity,
|
|
133164
133173
|
suctionLevelEntity: config11.suctionLevelEntity,
|
|
133165
133174
|
mopIntensityEntity: config11.mopIntensityEntity,
|
|
133166
133175
|
valetudoIdentifier: config11.valetudoIdentifier,
|
|
@@ -133322,6 +133331,8 @@ WARNING: ${includeIdentity ? "This backup contains sensitive Matter identity dat
|
|
|
133322
133331
|
currentEntity: config11.currentEntity,
|
|
133323
133332
|
batteryPowerEntity: config11.batteryPowerEntity,
|
|
133324
133333
|
batteryEnergyEntity: config11.batteryEnergyEntity,
|
|
133334
|
+
chargingSwitchEntity: config11.chargingSwitchEntity,
|
|
133335
|
+
currentLimitEntity: config11.currentLimitEntity,
|
|
133325
133336
|
suctionLevelEntity: config11.suctionLevelEntity,
|
|
133326
133337
|
mopIntensityEntity: config11.mopIntensityEntity,
|
|
133327
133338
|
temperatureEntity: config11.temperatureEntity,
|
|
@@ -134174,6 +134185,8 @@ function entityMappingApi(mappingStorage, identityStorage) {
|
|
|
134174
134185
|
currentEntity: body.currentEntity,
|
|
134175
134186
|
batteryPowerEntity: body.batteryPowerEntity,
|
|
134176
134187
|
batteryEnergyEntity: body.batteryEnergyEntity,
|
|
134188
|
+
chargingSwitchEntity: body.chargingSwitchEntity,
|
|
134189
|
+
currentLimitEntity: body.currentLimitEntity,
|
|
134177
134190
|
suctionLevelEntity: body.suctionLevelEntity,
|
|
134178
134191
|
mopIntensityEntity: body.mopIntensityEntity,
|
|
134179
134192
|
customServiceAreas: body.customServiceAreas,
|
|
@@ -134675,6 +134688,8 @@ function configToProfileEntry(config11) {
|
|
|
134675
134688
|
currentEntity: config11.currentEntity,
|
|
134676
134689
|
batteryPowerEntity: config11.batteryPowerEntity,
|
|
134677
134690
|
batteryEnergyEntity: config11.batteryEnergyEntity,
|
|
134691
|
+
chargingSwitchEntity: config11.chargingSwitchEntity,
|
|
134692
|
+
currentLimitEntity: config11.currentLimitEntity,
|
|
134678
134693
|
suctionLevelEntity: config11.suctionLevelEntity,
|
|
134679
134694
|
mopIntensityEntity: config11.mopIntensityEntity,
|
|
134680
134695
|
customServiceAreas: config11.customServiceAreas,
|
|
@@ -134814,6 +134829,8 @@ function mappingProfileApi(mappingStorage) {
|
|
|
134814
134829
|
currentEntity: entry.currentEntity,
|
|
134815
134830
|
batteryPowerEntity: entry.batteryPowerEntity,
|
|
134816
134831
|
batteryEnergyEntity: entry.batteryEnergyEntity,
|
|
134832
|
+
chargingSwitchEntity: entry.chargingSwitchEntity,
|
|
134833
|
+
currentLimitEntity: entry.currentLimitEntity,
|
|
134817
134834
|
suctionLevelEntity: entry.suctionLevelEntity,
|
|
134818
134835
|
mopIntensityEntity: entry.mopIntensityEntity,
|
|
134819
134836
|
customServiceAreas: entry.customServiceAreas,
|
|
@@ -135040,6 +135057,300 @@ function resolveLabelValue(value, labels) {
|
|
|
135040
135057
|
return value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
135041
135058
|
}
|
|
135042
135059
|
|
|
135060
|
+
// src/matter/endpoints/entity-endpoint.ts
|
|
135061
|
+
init_esm7();
|
|
135062
|
+
var EntityEndpoint = class extends Endpoint {
|
|
135063
|
+
constructor(type, entityId, customName, mappedEntityIds, endpointId) {
|
|
135064
|
+
super(type, { id: endpointId ?? createEndpointId(entityId, customName) });
|
|
135065
|
+
this.entityId = entityId;
|
|
135066
|
+
this.mappedEntityIds = mappedEntityIds ?? [];
|
|
135067
|
+
}
|
|
135068
|
+
entityId;
|
|
135069
|
+
mappedEntityIds;
|
|
135070
|
+
lastMappedStates = {};
|
|
135071
|
+
hasMappedEntityChanged(states) {
|
|
135072
|
+
let changed = false;
|
|
135073
|
+
for (const mappedId of this.mappedEntityIds) {
|
|
135074
|
+
const mappedState = states[mappedId];
|
|
135075
|
+
if (!mappedState) continue;
|
|
135076
|
+
const fp = mappedState.state;
|
|
135077
|
+
if (fp !== this.lastMappedStates[mappedId]) {
|
|
135078
|
+
this.lastMappedStates[mappedId] = fp;
|
|
135079
|
+
changed = true;
|
|
135080
|
+
}
|
|
135081
|
+
}
|
|
135082
|
+
return changed;
|
|
135083
|
+
}
|
|
135084
|
+
};
|
|
135085
|
+
function createEndpointId(entityId, customName) {
|
|
135086
|
+
const baseName = customName || entityId;
|
|
135087
|
+
return baseName.replace(/\./g, "_").replace(/\s+/g, "_");
|
|
135088
|
+
}
|
|
135089
|
+
function getMappedEntityIds(mapping) {
|
|
135090
|
+
if (!mapping) return [];
|
|
135091
|
+
const ids = [];
|
|
135092
|
+
if (mapping.batteryEntity && !mapping.disableBatteryMapping) {
|
|
135093
|
+
ids.push(mapping.batteryEntity);
|
|
135094
|
+
}
|
|
135095
|
+
if (mapping.faultEntity) ids.push(mapping.faultEntity);
|
|
135096
|
+
if (mapping.chargingStateEntity) ids.push(mapping.chargingStateEntity);
|
|
135097
|
+
if (mapping.temperatureEntity) ids.push(mapping.temperatureEntity);
|
|
135098
|
+
if (mapping.humidityEntity) ids.push(mapping.humidityEntity);
|
|
135099
|
+
if (mapping.pressureEntity) ids.push(mapping.pressureEntity);
|
|
135100
|
+
if (mapping.cleaningModeEntity) ids.push(mapping.cleaningModeEntity);
|
|
135101
|
+
if (mapping.suctionLevelEntity) ids.push(mapping.suctionLevelEntity);
|
|
135102
|
+
if (mapping.mopIntensityEntity) ids.push(mapping.mopIntensityEntity);
|
|
135103
|
+
if (mapping.filterLifeEntity) ids.push(mapping.filterLifeEntity);
|
|
135104
|
+
if (mapping.powerEntity) ids.push(mapping.powerEntity);
|
|
135105
|
+
if (mapping.energyEntity) ids.push(mapping.energyEntity);
|
|
135106
|
+
if (mapping.voltageEntity) ids.push(mapping.voltageEntity);
|
|
135107
|
+
if (mapping.currentEntity) ids.push(mapping.currentEntity);
|
|
135108
|
+
if (mapping.batteryPowerEntity) ids.push(mapping.batteryPowerEntity);
|
|
135109
|
+
if (mapping.batteryEnergyEntity) ids.push(mapping.batteryEnergyEntity);
|
|
135110
|
+
if (mapping.chargingSwitchEntity) ids.push(mapping.chargingSwitchEntity);
|
|
135111
|
+
if (mapping.currentLimitEntity) ids.push(mapping.currentLimitEntity);
|
|
135112
|
+
if (mapping.currentRoomEntity) ids.push(mapping.currentRoomEntity);
|
|
135113
|
+
if (mapping.cleanedAreaEntity) ids.push(mapping.cleanedAreaEntity);
|
|
135114
|
+
if (mapping.composedEntities) {
|
|
135115
|
+
for (const sub of mapping.composedEntities) {
|
|
135116
|
+
if (sub.entityId) ids.push(sub.entityId);
|
|
135117
|
+
}
|
|
135118
|
+
}
|
|
135119
|
+
return ids;
|
|
135120
|
+
}
|
|
135121
|
+
|
|
135122
|
+
// src/services/bridges/identity-resolver.ts
|
|
135123
|
+
var SEP = "\0";
|
|
135124
|
+
function identityKey(entity) {
|
|
135125
|
+
const uniqueId = entity.registry?.unique_id;
|
|
135126
|
+
const platform = entity.registry?.platform;
|
|
135127
|
+
if (!uniqueId || !platform) {
|
|
135128
|
+
return null;
|
|
135129
|
+
}
|
|
135130
|
+
const domain = entity.entity_id.split(".")[0];
|
|
135131
|
+
return platform + SEP + domain + SEP + uniqueId;
|
|
135132
|
+
}
|
|
135133
|
+
var IdentityResolver = class {
|
|
135134
|
+
constructor(identityStorage, mappingStorage) {
|
|
135135
|
+
this.identityStorage = identityStorage;
|
|
135136
|
+
this.mappingStorage = mappingStorage;
|
|
135137
|
+
}
|
|
135138
|
+
identityStorage;
|
|
135139
|
+
mappingStorage;
|
|
135140
|
+
async resolveIdentity(bridgeId, entity, mapping, opts) {
|
|
135141
|
+
const entityId = entity.entity_id;
|
|
135142
|
+
const key = identityKey(entity);
|
|
135143
|
+
if (key == null) {
|
|
135144
|
+
return {
|
|
135145
|
+
endpointId: createEndpointId(entityId, mapping?.customName),
|
|
135146
|
+
anchorEntityId: entityId,
|
|
135147
|
+
protected: false
|
|
135148
|
+
};
|
|
135149
|
+
}
|
|
135150
|
+
const existing = this.identityStorage.getIdentity(bridgeId, key);
|
|
135151
|
+
if (existing) {
|
|
135152
|
+
const renamedFrom = existing.lastEntityId !== entityId ? existing.lastEntityId ?? existing.anchorEntityId : void 0;
|
|
135153
|
+
if (opts.stableIdentity) {
|
|
135154
|
+
if (renamedFrom) {
|
|
135155
|
+
this.identityStorage.setIdentity(bridgeId, key, {
|
|
135156
|
+
...existing,
|
|
135157
|
+
lastEntityId: entityId
|
|
135158
|
+
});
|
|
135159
|
+
await this.rekeyMapping(bridgeId, renamedFrom, entityId);
|
|
135160
|
+
}
|
|
135161
|
+
return {
|
|
135162
|
+
endpointId: existing.endpointId,
|
|
135163
|
+
anchorEntityId: existing.anchorEntityId,
|
|
135164
|
+
protected: true,
|
|
135165
|
+
renamedFrom
|
|
135166
|
+
};
|
|
135167
|
+
}
|
|
135168
|
+
const liveEndpointId = createEndpointId(entityId, mapping?.customName);
|
|
135169
|
+
if (existing.endpointId !== liveEndpointId || existing.anchorEntityId !== entityId || existing.lastEntityId !== entityId) {
|
|
135170
|
+
this.identityStorage.setIdentity(bridgeId, key, {
|
|
135171
|
+
...existing,
|
|
135172
|
+
endpointId: liveEndpointId,
|
|
135173
|
+
anchorEntityId: entityId,
|
|
135174
|
+
lastEntityId: entityId
|
|
135175
|
+
});
|
|
135176
|
+
}
|
|
135177
|
+
return {
|
|
135178
|
+
endpointId: liveEndpointId,
|
|
135179
|
+
anchorEntityId: entityId,
|
|
135180
|
+
protected: false,
|
|
135181
|
+
renamedFrom
|
|
135182
|
+
};
|
|
135183
|
+
}
|
|
135184
|
+
const desired = createEndpointId(entityId, mapping?.customName);
|
|
135185
|
+
let endpointId = desired;
|
|
135186
|
+
if (opts.stableIdentity) {
|
|
135187
|
+
let n = 2;
|
|
135188
|
+
while (opts.isEndpointIdTaken(endpointId, key)) {
|
|
135189
|
+
endpointId = `${desired}_${n++}`;
|
|
135190
|
+
}
|
|
135191
|
+
}
|
|
135192
|
+
const record = {
|
|
135193
|
+
endpointId,
|
|
135194
|
+
anchorEntityId: entityId,
|
|
135195
|
+
lastEntityId: entityId,
|
|
135196
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
135197
|
+
};
|
|
135198
|
+
this.identityStorage.setIdentity(bridgeId, key, record);
|
|
135199
|
+
if (opts.stableIdentity) {
|
|
135200
|
+
return {
|
|
135201
|
+
endpointId: record.endpointId,
|
|
135202
|
+
anchorEntityId: record.anchorEntityId,
|
|
135203
|
+
protected: true
|
|
135204
|
+
};
|
|
135205
|
+
}
|
|
135206
|
+
return {
|
|
135207
|
+
endpointId: desired,
|
|
135208
|
+
anchorEntityId: entityId,
|
|
135209
|
+
protected: false
|
|
135210
|
+
};
|
|
135211
|
+
}
|
|
135212
|
+
// Carry a mapping from the old entity_id to the new one on rename. anchorEntityId
|
|
135213
|
+
// never changes, only the mapping key. Skips when no old mapping exists or a new
|
|
135214
|
+
// one already does, so a manual mapping under the new id is never clobbered.
|
|
135215
|
+
async rekeyMapping(bridgeId, oldEntityId, newEntityId) {
|
|
135216
|
+
if (oldEntityId === newEntityId) {
|
|
135217
|
+
return;
|
|
135218
|
+
}
|
|
135219
|
+
const old = this.mappingStorage.getMapping(bridgeId, oldEntityId);
|
|
135220
|
+
if (!old) {
|
|
135221
|
+
return;
|
|
135222
|
+
}
|
|
135223
|
+
if (this.mappingStorage.getMapping(bridgeId, newEntityId)) {
|
|
135224
|
+
return;
|
|
135225
|
+
}
|
|
135226
|
+
await this.mappingStorage.setMapping({
|
|
135227
|
+
...old,
|
|
135228
|
+
bridgeId,
|
|
135229
|
+
entityId: newEntityId
|
|
135230
|
+
});
|
|
135231
|
+
await this.mappingStorage.deleteMapping(bridgeId, oldEntityId);
|
|
135232
|
+
}
|
|
135233
|
+
};
|
|
135234
|
+
|
|
135235
|
+
// src/services/storage/orphan-cleanup.ts
|
|
135236
|
+
var ORPHAN_TOMBSTONE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
135237
|
+
function buildPresentIdentityKeys(entities) {
|
|
135238
|
+
const keys3 = /* @__PURE__ */ new Set();
|
|
135239
|
+
for (const entity of Object.values(entities ?? {})) {
|
|
135240
|
+
if (!entity?.entity_id) continue;
|
|
135241
|
+
const key = identityKey({ entity_id: entity.entity_id, registry: entity });
|
|
135242
|
+
if (key != null) keys3.add(key);
|
|
135243
|
+
}
|
|
135244
|
+
return keys3;
|
|
135245
|
+
}
|
|
135246
|
+
function buildPresentEntityIds(entities) {
|
|
135247
|
+
const ids = /* @__PURE__ */ new Set();
|
|
135248
|
+
for (const entity of Object.values(entities ?? {})) {
|
|
135249
|
+
if (entity?.entity_id) ids.add(entity.entity_id);
|
|
135250
|
+
}
|
|
135251
|
+
return ids;
|
|
135252
|
+
}
|
|
135253
|
+
function stampIdentityPresence(store, bridgeId, presentKeys, now = Date.now()) {
|
|
135254
|
+
const nowIso = new Date(now).toISOString();
|
|
135255
|
+
for (const key of [...store.getBridgeIdentities(bridgeId).keys()]) {
|
|
135256
|
+
if (presentKeys.has(key)) {
|
|
135257
|
+
store.clearIdentityMissing(bridgeId, key);
|
|
135258
|
+
} else {
|
|
135259
|
+
store.markIdentityMissing(bridgeId, key, nowIso);
|
|
135260
|
+
}
|
|
135261
|
+
}
|
|
135262
|
+
}
|
|
135263
|
+
function stampMappingPresence(store, bridgeId, presentEntityIds, now = Date.now()) {
|
|
135264
|
+
const nowIso = new Date(now).toISOString();
|
|
135265
|
+
const entityIds = store.getMappingsForBridge(bridgeId).map((m) => m.entityId);
|
|
135266
|
+
for (const entityId of entityIds) {
|
|
135267
|
+
if (presentEntityIds.has(entityId)) {
|
|
135268
|
+
store.clearMappingMissing(bridgeId, entityId);
|
|
135269
|
+
} else {
|
|
135270
|
+
store.markMappingMissing(bridgeId, entityId, nowIso);
|
|
135271
|
+
}
|
|
135272
|
+
}
|
|
135273
|
+
}
|
|
135274
|
+
function computeOrphanCandidates(input) {
|
|
135275
|
+
const now = input.now ?? Date.now();
|
|
135276
|
+
const candidates = [];
|
|
135277
|
+
for (const [key, record] of input.identities) {
|
|
135278
|
+
if (!record.missingSince) continue;
|
|
135279
|
+
const missingFor = now - Date.parse(record.missingSince);
|
|
135280
|
+
if (!(missingFor >= ORPHAN_TOMBSTONE_MS)) continue;
|
|
135281
|
+
if (input.presentKeys.has(key)) continue;
|
|
135282
|
+
const lastEntityId = record.lastEntityId ?? record.anchorEntityId;
|
|
135283
|
+
candidates.push({
|
|
135284
|
+
identityKey: key,
|
|
135285
|
+
lastEntityId,
|
|
135286
|
+
missingSince: record.missingSince,
|
|
135287
|
+
// Only a true orphan mapping, not one a live entity holds under a reused
|
|
135288
|
+
// entity_id (a different identity key). Guards the sweep from clobbering
|
|
135289
|
+
// that live entity's custom mapping.
|
|
135290
|
+
hasMapping: input.hasMapping(lastEntityId) && !input.presentEntityIds.has(lastEntityId),
|
|
135291
|
+
kind: "identity"
|
|
135292
|
+
});
|
|
135293
|
+
}
|
|
135294
|
+
if (input.mappings) {
|
|
135295
|
+
const linkedByIdentity = /* @__PURE__ */ new Set();
|
|
135296
|
+
for (const candidate of candidates) {
|
|
135297
|
+
if (candidate.hasMapping) linkedByIdentity.add(candidate.lastEntityId);
|
|
135298
|
+
}
|
|
135299
|
+
for (const mapping of input.mappings) {
|
|
135300
|
+
if (!mapping.missingSince) continue;
|
|
135301
|
+
const missingFor = now - Date.parse(mapping.missingSince);
|
|
135302
|
+
if (!(missingFor >= ORPHAN_TOMBSTONE_MS)) continue;
|
|
135303
|
+
if (input.presentEntityIds.has(mapping.entityId)) continue;
|
|
135304
|
+
if (linkedByIdentity.has(mapping.entityId)) continue;
|
|
135305
|
+
candidates.push({
|
|
135306
|
+
identityKey: mapping.entityId,
|
|
135307
|
+
lastEntityId: mapping.entityId,
|
|
135308
|
+
missingSince: mapping.missingSince,
|
|
135309
|
+
hasMapping: true,
|
|
135310
|
+
kind: "mapping"
|
|
135311
|
+
});
|
|
135312
|
+
}
|
|
135313
|
+
}
|
|
135314
|
+
return candidates;
|
|
135315
|
+
}
|
|
135316
|
+
async function executeOrphanCleanup(input) {
|
|
135317
|
+
const candidates = computeOrphanCandidates({
|
|
135318
|
+
bridgeId: input.bridgeId,
|
|
135319
|
+
identities: input.identities,
|
|
135320
|
+
presentKeys: input.presentKeys,
|
|
135321
|
+
presentEntityIds: input.presentEntityIds,
|
|
135322
|
+
hasMapping: (entityId) => input.getMapping(input.bridgeId, entityId) != null,
|
|
135323
|
+
mappings: input.mappings,
|
|
135324
|
+
now: input.now
|
|
135325
|
+
});
|
|
135326
|
+
const byKey = new Map(candidates.map((c) => [c.identityKey, c]));
|
|
135327
|
+
const results = [];
|
|
135328
|
+
for (const key of input.requestedKeys) {
|
|
135329
|
+
const candidate = byKey.get(key);
|
|
135330
|
+
if (!candidate) {
|
|
135331
|
+
results.push({
|
|
135332
|
+
identityKey: key,
|
|
135333
|
+
deleted: false,
|
|
135334
|
+
reason: "not a current orphan candidate"
|
|
135335
|
+
});
|
|
135336
|
+
continue;
|
|
135337
|
+
}
|
|
135338
|
+
if (candidate.kind === "mapping") {
|
|
135339
|
+
if (!input.presentEntityIds.has(candidate.lastEntityId)) {
|
|
135340
|
+
await input.deleteMapping(input.bridgeId, candidate.lastEntityId);
|
|
135341
|
+
}
|
|
135342
|
+
results.push({ identityKey: key, deleted: true });
|
|
135343
|
+
continue;
|
|
135344
|
+
}
|
|
135345
|
+
if (candidate.hasMapping && !input.presentEntityIds.has(candidate.lastEntityId)) {
|
|
135346
|
+
await input.deleteMapping(input.bridgeId, candidate.lastEntityId);
|
|
135347
|
+
}
|
|
135348
|
+
await input.deleteIdentity(input.bridgeId, key);
|
|
135349
|
+
results.push({ identityKey: key, deleted: true });
|
|
135350
|
+
}
|
|
135351
|
+
return results;
|
|
135352
|
+
}
|
|
135353
|
+
|
|
135043
135354
|
// src/utils/json/endpoint-to-json.ts
|
|
135044
135355
|
function safeClone(value, depth = 0) {
|
|
135045
135356
|
if (depth > 20 || value === null || value === void 0) return value;
|
|
@@ -135085,7 +135396,7 @@ function endpointToJson(endpoint, parentId) {
|
|
|
135085
135396
|
|
|
135086
135397
|
// src/api/matter-api.ts
|
|
135087
135398
|
var ajv = new Ajv();
|
|
135088
|
-
function matterApi(bridgeService, haRegistry, identityStorage) {
|
|
135399
|
+
function matterApi(bridgeService, haRegistry, identityStorage, mappingStorage) {
|
|
135089
135400
|
const router = express11.Router();
|
|
135090
135401
|
router.get("/", (_, res) => {
|
|
135091
135402
|
res.status(200).json({});
|
|
@@ -135188,6 +135499,64 @@ function matterApi(bridgeService, haRegistry, identityStorage) {
|
|
|
135188
135499
|
});
|
|
135189
135500
|
}
|
|
135190
135501
|
});
|
|
135502
|
+
router.get("/bridges/:bridgeId/orphans", async (req, res) => {
|
|
135503
|
+
const bridgeId = req.params.bridgeId;
|
|
135504
|
+
const bridge = bridgeService.bridges.find((b) => b.id === bridgeId);
|
|
135505
|
+
if (!bridge) {
|
|
135506
|
+
res.status(404).send("Not Found");
|
|
135507
|
+
return;
|
|
135508
|
+
}
|
|
135509
|
+
if (!haRegistry || !identityStorage) {
|
|
135510
|
+
res.status(503).json({ error: "Orphan cleanup is not available" });
|
|
135511
|
+
return;
|
|
135512
|
+
}
|
|
135513
|
+
const presentKeys = buildPresentIdentityKeys(haRegistry.entities);
|
|
135514
|
+
const presentEntityIds = buildPresentEntityIds(haRegistry.entities);
|
|
135515
|
+
const candidates = computeOrphanCandidates({
|
|
135516
|
+
bridgeId,
|
|
135517
|
+
identities: identityStorage.getBridgeIdentities(bridgeId),
|
|
135518
|
+
presentKeys,
|
|
135519
|
+
presentEntityIds,
|
|
135520
|
+
hasMapping: (entityId) => mappingStorage?.getMapping(bridgeId, entityId) != null,
|
|
135521
|
+
mappings: mappingStorage?.getMappingsForBridge(bridgeId)
|
|
135522
|
+
});
|
|
135523
|
+
res.status(200).json({ candidates });
|
|
135524
|
+
});
|
|
135525
|
+
router.post(
|
|
135526
|
+
"/bridges/:bridgeId/actions/cleanup-orphans",
|
|
135527
|
+
async (req, res) => {
|
|
135528
|
+
const bridgeId = req.params.bridgeId;
|
|
135529
|
+
const bridge = bridgeService.bridges.find((b) => b.id === bridgeId);
|
|
135530
|
+
if (!bridge) {
|
|
135531
|
+
res.status(404).send("Not Found");
|
|
135532
|
+
return;
|
|
135533
|
+
}
|
|
135534
|
+
if (!haRegistry || !identityStorage || !mappingStorage) {
|
|
135535
|
+
res.status(503).json({ error: "Orphan cleanup is not available" });
|
|
135536
|
+
return;
|
|
135537
|
+
}
|
|
135538
|
+
const body = req.body;
|
|
135539
|
+
const requestedKeys = Array.isArray(body?.identityKeys) ? body.identityKeys.filter((k) => typeof k === "string") : [];
|
|
135540
|
+
try {
|
|
135541
|
+
const results = await executeOrphanCleanup({
|
|
135542
|
+
bridgeId,
|
|
135543
|
+
requestedKeys,
|
|
135544
|
+
identities: identityStorage.getBridgeIdentities(bridgeId),
|
|
135545
|
+
presentKeys: buildPresentIdentityKeys(haRegistry.entities),
|
|
135546
|
+
presentEntityIds: buildPresentEntityIds(haRegistry.entities),
|
|
135547
|
+
getMapping: (b, e) => mappingStorage.getMapping(b, e),
|
|
135548
|
+
deleteMapping: (b, e) => mappingStorage.deleteMapping(b, e),
|
|
135549
|
+
deleteIdentity: (b, k) => identityStorage.deleteIdentity(b, k),
|
|
135550
|
+
mappings: mappingStorage.getMappingsForBridge(bridgeId)
|
|
135551
|
+
});
|
|
135552
|
+
res.status(200).json({ results });
|
|
135553
|
+
} catch (e) {
|
|
135554
|
+
res.status(500).json({
|
|
135555
|
+
error: e instanceof Error ? e.message : "Unknown error"
|
|
135556
|
+
});
|
|
135557
|
+
}
|
|
135558
|
+
}
|
|
135559
|
+
);
|
|
135191
135560
|
router.get("/bridges/:bridgeId/devices", async (req, res) => {
|
|
135192
135561
|
const bridgeId = req.params.bridgeId;
|
|
135193
135562
|
const bridge = bridgeService.bridges.find((b) => b.id === bridgeId);
|
|
@@ -137161,7 +137530,7 @@ var WebSocketApi = class {
|
|
|
137161
137530
|
|
|
137162
137531
|
// src/api/web-api.ts
|
|
137163
137532
|
var WebApi = class extends Service {
|
|
137164
|
-
constructor(
|
|
137533
|
+
constructor(logger248, bridgeService, haClient, haRegistry, bridgeStorage, mappingStorage, identityStorage, lockCredentialStorage, settingsStorage, backupService, props) {
|
|
137165
137534
|
super("WebApi");
|
|
137166
137535
|
this.bridgeService = bridgeService;
|
|
137167
137536
|
this.haClient = haClient;
|
|
@@ -137173,8 +137542,8 @@ var WebApi = class extends Service {
|
|
|
137173
137542
|
this.settingsStorage = settingsStorage;
|
|
137174
137543
|
this.backupService = backupService;
|
|
137175
137544
|
this.props = props;
|
|
137176
|
-
this.logger =
|
|
137177
|
-
this.log =
|
|
137545
|
+
this.logger = logger248;
|
|
137546
|
+
this.log = logger248.get(this);
|
|
137178
137547
|
this.accessLogger = accessLogger(this.log.createChild("Access Log"));
|
|
137179
137548
|
this.startTime = Date.now();
|
|
137180
137549
|
this.wsApi = new WebSocketApi(
|
|
@@ -137207,7 +137576,12 @@ var WebApi = class extends Service {
|
|
|
137207
137576
|
const api = express17.Router();
|
|
137208
137577
|
api.use(express17.json()).use(nocache()).use(
|
|
137209
137578
|
"/matter",
|
|
137210
|
-
matterApi(
|
|
137579
|
+
matterApi(
|
|
137580
|
+
this.bridgeService,
|
|
137581
|
+
this.haRegistry,
|
|
137582
|
+
this.identityStorage,
|
|
137583
|
+
this.mappingStorage
|
|
137584
|
+
)
|
|
137211
137585
|
).use(
|
|
137212
137586
|
"/health",
|
|
137213
137587
|
healthApi(
|
|
@@ -138360,10 +138734,10 @@ function isTransientConnectError(reason) {
|
|
|
138360
138734
|
return msg.includes("socket hang up") || msg.includes("tls") || msg.includes("TLS");
|
|
138361
138735
|
}
|
|
138362
138736
|
var HomeAssistantClient = class extends Service {
|
|
138363
|
-
constructor(
|
|
138737
|
+
constructor(logger248, options) {
|
|
138364
138738
|
super("HomeAssistantClient");
|
|
138365
138739
|
this.options = options;
|
|
138366
|
-
this.log =
|
|
138740
|
+
this.log = logger248.get(this);
|
|
138367
138741
|
}
|
|
138368
138742
|
options;
|
|
138369
138743
|
static Options = /* @__PURE__ */ Symbol.for("HomeAssistantClientProps");
|
|
@@ -139028,11 +139402,37 @@ var EntityIdentityStorage = class extends Service {
|
|
|
139028
139402
|
this.identities.delete(bridgeId);
|
|
139029
139403
|
await this.flush();
|
|
139030
139404
|
}
|
|
139405
|
+
// Drop a single identity record. Used by the manual orphan cleanup after the
|
|
139406
|
+
// 7-day tombstone; flush immediately since it is a user-initiated deletion.
|
|
139407
|
+
async deleteIdentity(bridgeId, key) {
|
|
139408
|
+
const bridgeMap = this.identities.get(bridgeId);
|
|
139409
|
+
if (bridgeMap?.delete(key)) {
|
|
139410
|
+
await this.flush();
|
|
139411
|
+
}
|
|
139412
|
+
}
|
|
139413
|
+
// Stamp the tombstone the first time a record's entity is absent from HA. Keeps
|
|
139414
|
+
// the first-seen time on later passes and no-ops once stamped, so a steady
|
|
139415
|
+
// absence does not churn the debounced persist.
|
|
139416
|
+
markIdentityMissing(bridgeId, key, nowIso) {
|
|
139417
|
+
const record = this.identities.get(bridgeId)?.get(key);
|
|
139418
|
+
if (!record || record.missingSince != null) return;
|
|
139419
|
+
record.missingSince = nowIso;
|
|
139420
|
+
this.schedulePersist();
|
|
139421
|
+
}
|
|
139422
|
+
// Clear the tombstone when the entity is present again. No-ops when there is
|
|
139423
|
+
// nothing to clear, so an all-present bridge writes nothing on refresh.
|
|
139424
|
+
clearIdentityMissing(bridgeId, key) {
|
|
139425
|
+
const record = this.identities.get(bridgeId)?.get(key);
|
|
139426
|
+
if (!record || record.missingSince == null) return;
|
|
139427
|
+
delete record.missingSince;
|
|
139428
|
+
this.schedulePersist();
|
|
139429
|
+
}
|
|
139031
139430
|
};
|
|
139032
139431
|
|
|
139033
139432
|
// src/services/storage/entity-mapping-storage.ts
|
|
139034
139433
|
init_service();
|
|
139035
139434
|
var CURRENT_VERSION2 = 1;
|
|
139435
|
+
var PERSIST_DEBOUNCE_MS2 = 500;
|
|
139036
139436
|
var EntityMappingStorage = class extends Service {
|
|
139037
139437
|
constructor(appStorage) {
|
|
139038
139438
|
super("EntityMappingStorage");
|
|
@@ -139041,10 +139441,14 @@ var EntityMappingStorage = class extends Service {
|
|
|
139041
139441
|
appStorage;
|
|
139042
139442
|
storage;
|
|
139043
139443
|
mappings = /* @__PURE__ */ new Map();
|
|
139444
|
+
persistTimer = null;
|
|
139044
139445
|
async initialize() {
|
|
139045
139446
|
this.storage = this.appStorage.createContext("entity-mappings");
|
|
139046
139447
|
await this.load();
|
|
139047
139448
|
}
|
|
139449
|
+
async dispose() {
|
|
139450
|
+
await this.flush();
|
|
139451
|
+
}
|
|
139048
139452
|
async load() {
|
|
139049
139453
|
const stored = await this.storage.get("data", {
|
|
139050
139454
|
version: CURRENT_VERSION2,
|
|
@@ -139079,6 +139483,10 @@ var EntityMappingStorage = class extends Service {
|
|
|
139079
139483
|
}
|
|
139080
139484
|
}
|
|
139081
139485
|
async persist() {
|
|
139486
|
+
if (this.persistTimer) {
|
|
139487
|
+
clearTimeout(this.persistTimer);
|
|
139488
|
+
this.persistTimer = null;
|
|
139489
|
+
}
|
|
139082
139490
|
const data = {
|
|
139083
139491
|
version: CURRENT_VERSION2,
|
|
139084
139492
|
mappings: {}
|
|
@@ -139088,6 +139496,17 @@ var EntityMappingStorage = class extends Service {
|
|
|
139088
139496
|
}
|
|
139089
139497
|
await this.storage.set("data", data);
|
|
139090
139498
|
}
|
|
139499
|
+
schedulePersist() {
|
|
139500
|
+
if (this.persistTimer) return;
|
|
139501
|
+
this.persistTimer = setTimeout(() => {
|
|
139502
|
+
this.persistTimer = null;
|
|
139503
|
+
void this.persist();
|
|
139504
|
+
}, PERSIST_DEBOUNCE_MS2);
|
|
139505
|
+
}
|
|
139506
|
+
// Flush any pending debounced write, used on dispose and by tests.
|
|
139507
|
+
async flush() {
|
|
139508
|
+
await this.persist();
|
|
139509
|
+
}
|
|
139091
139510
|
getMappingsForBridge(bridgeId) {
|
|
139092
139511
|
const bridgeMap = this.mappings.get(bridgeId);
|
|
139093
139512
|
return bridgeMap ? Array.from(bridgeMap.values()) : [];
|
|
@@ -139134,6 +139553,8 @@ var EntityMappingStorage = class extends Service {
|
|
|
139134
139553
|
currentEntity: request.currentEntity?.trim() || void 0,
|
|
139135
139554
|
batteryPowerEntity: request.batteryPowerEntity?.trim() || void 0,
|
|
139136
139555
|
batteryEnergyEntity: request.batteryEnergyEntity?.trim() || void 0,
|
|
139556
|
+
chargingSwitchEntity: request.chargingSwitchEntity?.trim() || void 0,
|
|
139557
|
+
currentLimitEntity: request.currentLimitEntity?.trim() || void 0,
|
|
139137
139558
|
pressureEntity: request.pressureEntity?.trim() || void 0,
|
|
139138
139559
|
suctionLevelEntity: request.suctionLevelEntity?.trim() || void 0,
|
|
139139
139560
|
mopIntensityEntity: request.mopIntensityEntity?.trim() || void 0,
|
|
@@ -139162,7 +139583,7 @@ var EntityMappingStorage = class extends Service {
|
|
|
139162
139583
|
composedEntities: request.composedEntities?.filter((e) => e.entityId?.trim()) ?? void 0,
|
|
139163
139584
|
disableMomentaryFlip: request.disableMomentaryFlip || void 0
|
|
139164
139585
|
};
|
|
139165
|
-
if (!config11.matterDeviceType && !config11.customName && !config11.customProductName && !config11.customVendorName && !config11.customSerialNumber && config11.customVendorId === void 0 && config11.disabled !== true && !config11.filterLifeEntity && !config11.cleaningModeEntity && !config11.temperatureEntity && !config11.humidityEntity && !config11.batteryEntity && !config11.disableBatteryMapping && !config11.chargingStateEntity && !config11.roomEntities && !config11.disableLockPin && !config11.lockUsercodeService && config11.lockUsercodeSlot === void 0 && config11.lockPinMinLength === void 0 && config11.lockPinMaxLength === void 0 && !config11.powerEntity && !config11.energyEntity && !config11.voltageEntity && !config11.currentEntity && !config11.batteryPowerEntity && !config11.batteryEnergyEntity && !config11.pressureEntity && !config11.suctionLevelEntity && !config11.mopIntensityEntity && (!config11.customServiceAreas || config11.customServiceAreas.length === 0) && (!config11.customFanSpeedTags || Object.keys(config11.customFanSpeedTags).length === 0) && (!config11.fanWindPresets || (config11.fanWindPresets.natural?.length ?? 0) === 0 && (config11.fanWindPresets.sleep?.length ?? 0) === 0) && !config11.fanRestoreSpeedOnPowerOn && !config11.currentRoomEntity && !config11.cleanedAreaEntity && !config11.disableCustomAreaRoomModes && !config11.valetudoIdentifier && !config11.coverSwapOpenClose && !config11.coverExposeAsDimmableLight && !config11.selectExposeAsSwitch && !config11.selectSwitchOnOption && !config11.selectSwitchOffOption && !config11.coverSliderDebounceMs && !config11.updateThrottleMs && !config11.disableClimateOnOff && !config11.disableClimateFanControl && !config11.climateKeepModeOnIdle && !config11.climateExposeFan && !config11.climateAutoMode && (!config11.composedEntities || config11.composedEntities.length === 0) && !config11.disableMomentaryFlip) {
|
|
139586
|
+
if (!config11.matterDeviceType && !config11.customName && !config11.customProductName && !config11.customVendorName && !config11.customSerialNumber && config11.customVendorId === void 0 && config11.disabled !== true && !config11.filterLifeEntity && !config11.cleaningModeEntity && !config11.temperatureEntity && !config11.humidityEntity && !config11.batteryEntity && !config11.disableBatteryMapping && !config11.chargingStateEntity && !config11.roomEntities && !config11.disableLockPin && !config11.lockUsercodeService && config11.lockUsercodeSlot === void 0 && config11.lockPinMinLength === void 0 && config11.lockPinMaxLength === void 0 && !config11.powerEntity && !config11.energyEntity && !config11.voltageEntity && !config11.currentEntity && !config11.batteryPowerEntity && !config11.batteryEnergyEntity && !config11.chargingSwitchEntity && !config11.currentLimitEntity && !config11.pressureEntity && !config11.suctionLevelEntity && !config11.mopIntensityEntity && (!config11.customServiceAreas || config11.customServiceAreas.length === 0) && (!config11.customFanSpeedTags || Object.keys(config11.customFanSpeedTags).length === 0) && (!config11.fanWindPresets || (config11.fanWindPresets.natural?.length ?? 0) === 0 && (config11.fanWindPresets.sleep?.length ?? 0) === 0) && !config11.fanRestoreSpeedOnPowerOn && !config11.currentRoomEntity && !config11.cleanedAreaEntity && !config11.disableCustomAreaRoomModes && !config11.valetudoIdentifier && !config11.coverSwapOpenClose && !config11.coverExposeAsDimmableLight && !config11.selectExposeAsSwitch && !config11.selectSwitchOnOption && !config11.selectSwitchOffOption && !config11.coverSliderDebounceMs && !config11.updateThrottleMs && !config11.disableClimateOnOff && !config11.disableClimateFanControl && !config11.climateKeepModeOnIdle && !config11.climateExposeFan && !config11.climateAutoMode && (!config11.composedEntities || config11.composedEntities.length === 0) && !config11.disableMomentaryFlip) {
|
|
139166
139587
|
bridgeMap.delete(request.entityId);
|
|
139167
139588
|
} else {
|
|
139168
139589
|
bridgeMap.set(request.entityId, config11);
|
|
@@ -139181,6 +139602,23 @@ var EntityMappingStorage = class extends Service {
|
|
|
139181
139602
|
this.mappings.delete(bridgeId);
|
|
139182
139603
|
await this.persist();
|
|
139183
139604
|
}
|
|
139605
|
+
// Stamp the tombstone the first time a mapping's entity is absent from HA.
|
|
139606
|
+
// Keeps the first-seen time on later passes and no-ops once stamped, so a
|
|
139607
|
+
// steady absence does not churn the debounced persist.
|
|
139608
|
+
markMappingMissing(bridgeId, entityId, nowIso) {
|
|
139609
|
+
const record = this.mappings.get(bridgeId)?.get(entityId);
|
|
139610
|
+
if (!record || record.missingSince != null) return;
|
|
139611
|
+
record.missingSince = nowIso;
|
|
139612
|
+
this.schedulePersist();
|
|
139613
|
+
}
|
|
139614
|
+
// Clear the tombstone when the entity is present again. No-ops when there is
|
|
139615
|
+
// nothing to clear, so an all-present bridge writes nothing on refresh.
|
|
139616
|
+
clearMappingMissing(bridgeId, entityId) {
|
|
139617
|
+
const record = this.mappings.get(bridgeId)?.get(entityId);
|
|
139618
|
+
if (!record || record.missingSince == null) return;
|
|
139619
|
+
delete record.missingSince;
|
|
139620
|
+
this.schedulePersist();
|
|
139621
|
+
}
|
|
139184
139622
|
};
|
|
139185
139623
|
function sanitizeVendorId(value) {
|
|
139186
139624
|
if (value === void 0 || value === null || value === "") {
|
|
@@ -149106,6 +149544,7 @@ var EnergyEvseDeviceDefinition = MutableEndpoint({
|
|
|
149106
149544
|
)
|
|
149107
149545
|
});
|
|
149108
149546
|
Object.freeze(EnergyEvseDeviceDefinition);
|
|
149547
|
+
var EnergyEvseDevice = EnergyEvseDeviceDefinition;
|
|
149109
149548
|
|
|
149110
149549
|
// ../../node_modules/.pnpm/@matter+node@0.17.7_patch_hash=34f8224b2964673272e9f22613c0cb1f8ec12758dd46b4fe303d42373451ad4c/node_modules/@matter/node/dist/esm/devices/extended-color-light.js
|
|
149111
149550
|
init_IdentifyServer();
|
|
@@ -156832,11 +157271,11 @@ var AUTO_FORCE_SYNC_INTERVAL_MS = 9e4;
|
|
|
156832
157271
|
var SHUTDOWN_SESSION_CLOSE_TIMEOUT_MS = 2500;
|
|
156833
157272
|
var MDNS_ADDRESS_CHECK_INTERVAL_MS = 6e4;
|
|
156834
157273
|
var Bridge = class {
|
|
156835
|
-
constructor(env,
|
|
157274
|
+
constructor(env, logger248, dataProvider, endpointManager, serverOptions) {
|
|
156836
157275
|
this.dataProvider = dataProvider;
|
|
156837
157276
|
this.endpointManager = endpointManager;
|
|
156838
157277
|
this.serverOptions = serverOptions;
|
|
156839
|
-
this.log =
|
|
157278
|
+
this.log = logger248.get(`Bridge / ${dataProvider.id}`);
|
|
156840
157279
|
this.server = new BridgeServerNode(
|
|
156841
157280
|
env,
|
|
156842
157281
|
this.dataProvider,
|
|
@@ -157888,66 +158327,6 @@ var AggregatorEndpoint2 = class extends Endpoint {
|
|
|
157888
158327
|
}
|
|
157889
158328
|
};
|
|
157890
158329
|
|
|
157891
|
-
// src/matter/endpoints/entity-endpoint.ts
|
|
157892
|
-
init_esm7();
|
|
157893
|
-
var EntityEndpoint = class extends Endpoint {
|
|
157894
|
-
constructor(type, entityId, customName, mappedEntityIds, endpointId) {
|
|
157895
|
-
super(type, { id: endpointId ?? createEndpointId(entityId, customName) });
|
|
157896
|
-
this.entityId = entityId;
|
|
157897
|
-
this.mappedEntityIds = mappedEntityIds ?? [];
|
|
157898
|
-
}
|
|
157899
|
-
entityId;
|
|
157900
|
-
mappedEntityIds;
|
|
157901
|
-
lastMappedStates = {};
|
|
157902
|
-
hasMappedEntityChanged(states) {
|
|
157903
|
-
let changed = false;
|
|
157904
|
-
for (const mappedId of this.mappedEntityIds) {
|
|
157905
|
-
const mappedState = states[mappedId];
|
|
157906
|
-
if (!mappedState) continue;
|
|
157907
|
-
const fp = mappedState.state;
|
|
157908
|
-
if (fp !== this.lastMappedStates[mappedId]) {
|
|
157909
|
-
this.lastMappedStates[mappedId] = fp;
|
|
157910
|
-
changed = true;
|
|
157911
|
-
}
|
|
157912
|
-
}
|
|
157913
|
-
return changed;
|
|
157914
|
-
}
|
|
157915
|
-
};
|
|
157916
|
-
function createEndpointId(entityId, customName) {
|
|
157917
|
-
const baseName = customName || entityId;
|
|
157918
|
-
return baseName.replace(/\./g, "_").replace(/\s+/g, "_");
|
|
157919
|
-
}
|
|
157920
|
-
function getMappedEntityIds(mapping) {
|
|
157921
|
-
if (!mapping) return [];
|
|
157922
|
-
const ids = [];
|
|
157923
|
-
if (mapping.batteryEntity && !mapping.disableBatteryMapping) {
|
|
157924
|
-
ids.push(mapping.batteryEntity);
|
|
157925
|
-
}
|
|
157926
|
-
if (mapping.faultEntity) ids.push(mapping.faultEntity);
|
|
157927
|
-
if (mapping.chargingStateEntity) ids.push(mapping.chargingStateEntity);
|
|
157928
|
-
if (mapping.temperatureEntity) ids.push(mapping.temperatureEntity);
|
|
157929
|
-
if (mapping.humidityEntity) ids.push(mapping.humidityEntity);
|
|
157930
|
-
if (mapping.pressureEntity) ids.push(mapping.pressureEntity);
|
|
157931
|
-
if (mapping.cleaningModeEntity) ids.push(mapping.cleaningModeEntity);
|
|
157932
|
-
if (mapping.suctionLevelEntity) ids.push(mapping.suctionLevelEntity);
|
|
157933
|
-
if (mapping.mopIntensityEntity) ids.push(mapping.mopIntensityEntity);
|
|
157934
|
-
if (mapping.filterLifeEntity) ids.push(mapping.filterLifeEntity);
|
|
157935
|
-
if (mapping.powerEntity) ids.push(mapping.powerEntity);
|
|
157936
|
-
if (mapping.energyEntity) ids.push(mapping.energyEntity);
|
|
157937
|
-
if (mapping.voltageEntity) ids.push(mapping.voltageEntity);
|
|
157938
|
-
if (mapping.currentEntity) ids.push(mapping.currentEntity);
|
|
157939
|
-
if (mapping.batteryPowerEntity) ids.push(mapping.batteryPowerEntity);
|
|
157940
|
-
if (mapping.batteryEnergyEntity) ids.push(mapping.batteryEnergyEntity);
|
|
157941
|
-
if (mapping.currentRoomEntity) ids.push(mapping.currentRoomEntity);
|
|
157942
|
-
if (mapping.cleanedAreaEntity) ids.push(mapping.cleanedAreaEntity);
|
|
157943
|
-
if (mapping.composedEntities) {
|
|
157944
|
-
for (const sub of mapping.composedEntities) {
|
|
157945
|
-
if (sub.entityId) ids.push(sub.entityId);
|
|
157946
|
-
}
|
|
157947
|
-
}
|
|
157948
|
-
return ids;
|
|
157949
|
-
}
|
|
157950
|
-
|
|
157951
158330
|
// src/matter/endpoints/legacy/legacy-endpoint.ts
|
|
157952
158331
|
init_dist();
|
|
157953
158332
|
init_esm();
|
|
@@ -167520,6 +167899,284 @@ var ElectricalMeterType = ElectricalMeterDevice.with(
|
|
|
167520
167899
|
EnergyServer
|
|
167521
167900
|
);
|
|
167522
167901
|
|
|
167902
|
+
// src/matter/endpoints/legacy/sensor/devices/energy-evse.ts
|
|
167903
|
+
init_esm();
|
|
167904
|
+
init_home_assistant_actions();
|
|
167905
|
+
init_home_assistant_entity_behavior();
|
|
167906
|
+
|
|
167907
|
+
// src/matter/endpoints/legacy/sensor/devices/evse-status.ts
|
|
167908
|
+
function mapEvseStatus(rawState, chargingSwitchOn) {
|
|
167909
|
+
const raw = rawState.toLowerCase().trim();
|
|
167910
|
+
const switchSupply = chargingSwitchOn ? EnergyEvse3.SupplyState.ChargingEnabled : EnergyEvse3.SupplyState.Disabled;
|
|
167911
|
+
if (raw === "" || raw === "unknown" || raw === "unavailable") {
|
|
167912
|
+
return {
|
|
167913
|
+
state: null,
|
|
167914
|
+
supplyState: EnergyEvse3.SupplyState.Disabled,
|
|
167915
|
+
faultState: EnergyEvse3.FaultState.NoError
|
|
167916
|
+
};
|
|
167917
|
+
}
|
|
167918
|
+
if (raw.includes("error") || raw.includes("fault")) {
|
|
167919
|
+
return {
|
|
167920
|
+
state: EnergyEvse3.State.Fault,
|
|
167921
|
+
supplyState: EnergyEvse3.SupplyState.DisabledError,
|
|
167922
|
+
faultState: EnergyEvse3.FaultState.Other
|
|
167923
|
+
};
|
|
167924
|
+
}
|
|
167925
|
+
if (raw.includes("not connected") || raw.includes("not_connected") || raw.includes("disconnected") || raw.includes("no vehicle")) {
|
|
167926
|
+
return {
|
|
167927
|
+
state: EnergyEvse3.State.NotPluggedIn,
|
|
167928
|
+
supplyState: switchSupply,
|
|
167929
|
+
faultState: EnergyEvse3.FaultState.NoError
|
|
167930
|
+
};
|
|
167931
|
+
}
|
|
167932
|
+
if (raw.includes("not charging") || raw.includes("not_charging") || raw.includes("not-charging")) {
|
|
167933
|
+
return {
|
|
167934
|
+
state: EnergyEvse3.State.PluggedInNoDemand,
|
|
167935
|
+
supplyState: switchSupply,
|
|
167936
|
+
faultState: EnergyEvse3.FaultState.NoError
|
|
167937
|
+
};
|
|
167938
|
+
}
|
|
167939
|
+
if (raw.includes("charg") && !raw.includes("discharg")) {
|
|
167940
|
+
return {
|
|
167941
|
+
state: EnergyEvse3.State.PluggedInCharging,
|
|
167942
|
+
supplyState: EnergyEvse3.SupplyState.ChargingEnabled,
|
|
167943
|
+
faultState: EnergyEvse3.FaultState.NoError
|
|
167944
|
+
};
|
|
167945
|
+
}
|
|
167946
|
+
if (raw.includes("connected") || raw.includes("ready") || raw.includes("awaiting") || raw.includes("completed") || raw.includes("sleep") || raw.includes("paused")) {
|
|
167947
|
+
return {
|
|
167948
|
+
state: EnergyEvse3.State.PluggedInNoDemand,
|
|
167949
|
+
supplyState: switchSupply,
|
|
167950
|
+
faultState: EnergyEvse3.FaultState.NoError
|
|
167951
|
+
};
|
|
167952
|
+
}
|
|
167953
|
+
return {
|
|
167954
|
+
state: null,
|
|
167955
|
+
supplyState: EnergyEvse3.SupplyState.Disabled,
|
|
167956
|
+
faultState: EnergyEvse3.FaultState.NoError
|
|
167957
|
+
};
|
|
167958
|
+
}
|
|
167959
|
+
|
|
167960
|
+
// src/matter/endpoints/legacy/sensor/devices/energy-evse.ts
|
|
167961
|
+
var logger229 = Logger.get("EnergyEvse");
|
|
167962
|
+
var MIN_CHARGE_CURRENT_MA = 6e3;
|
|
167963
|
+
var MAX_CHARGE_CURRENT_MA = 32e3;
|
|
167964
|
+
var CIRCUIT_CAPACITY_MA = 32e3;
|
|
167965
|
+
var MAX_TIMER_MS = 2147483647;
|
|
167966
|
+
function clampMa(ma) {
|
|
167967
|
+
return Math.min(CIRCUIT_CAPACITY_MA, Math.max(MIN_CHARGE_CURRENT_MA, ma));
|
|
167968
|
+
}
|
|
167969
|
+
var evseChargingTimers = /* @__PURE__ */ new WeakMap();
|
|
167970
|
+
function clearEvseChargingTimer(endpoint) {
|
|
167971
|
+
const timer = evseChargingTimers.get(endpoint);
|
|
167972
|
+
if (timer) {
|
|
167973
|
+
clearTimeout(timer);
|
|
167974
|
+
evseChargingTimers.delete(endpoint);
|
|
167975
|
+
}
|
|
167976
|
+
}
|
|
167977
|
+
var EvseStatusServer = class _EvseStatusServer extends EnergyEvseServer {
|
|
167978
|
+
async initialize() {
|
|
167979
|
+
await super.initialize();
|
|
167980
|
+
const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
|
|
167981
|
+
this.update();
|
|
167982
|
+
this.reactTo(homeAssistant.onChange, this.update, { offline: true });
|
|
167983
|
+
}
|
|
167984
|
+
async [Symbol.asyncDispose]() {
|
|
167985
|
+
clearEvseChargingTimer(this.endpoint);
|
|
167986
|
+
await super[Symbol.asyncDispose]();
|
|
167987
|
+
}
|
|
167988
|
+
chargingSwitchIsOn() {
|
|
167989
|
+
const mapping = this.agent.get(HomeAssistantEntityBehavior).state.mapping;
|
|
167990
|
+
const switchEntity = mapping?.chargingSwitchEntity;
|
|
167991
|
+
if (!switchEntity) return false;
|
|
167992
|
+
const stateProvider = this.agent.env.get(EntityStateProvider);
|
|
167993
|
+
return stateProvider.getState(switchEntity)?.state === "on";
|
|
167994
|
+
}
|
|
167995
|
+
update() {
|
|
167996
|
+
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
167997
|
+
const raw = homeAssistant.entity.state?.state ?? "";
|
|
167998
|
+
const status3 = mapEvseStatus(raw, this.chargingSwitchIsOn());
|
|
167999
|
+
const patch = {
|
|
168000
|
+
state: status3.state,
|
|
168001
|
+
supplyState: status3.supplyState,
|
|
168002
|
+
faultState: status3.faultState
|
|
168003
|
+
};
|
|
168004
|
+
const mapping = homeAssistant.state.mapping;
|
|
168005
|
+
if (mapping?.currentLimitEntity) {
|
|
168006
|
+
const stateProvider = this.agent.env.get(EntityStateProvider);
|
|
168007
|
+
const amps = stateProvider.getNumericState(mapping.currentLimitEntity);
|
|
168008
|
+
if (amps != null) {
|
|
168009
|
+
patch.maximumChargeCurrent = clampMa(Math.round(amps * 1e3));
|
|
168010
|
+
}
|
|
168011
|
+
}
|
|
168012
|
+
applyPatchState(this.state, patch);
|
|
168013
|
+
}
|
|
168014
|
+
enableCharging(request) {
|
|
168015
|
+
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
168016
|
+
const mapping = homeAssistant.state.mapping;
|
|
168017
|
+
const until = request.chargingEnabledUntil;
|
|
168018
|
+
if (until != null && until * 1e3 <= Date.now()) {
|
|
168019
|
+
this.disable();
|
|
168020
|
+
return;
|
|
168021
|
+
}
|
|
168022
|
+
clearEvseChargingTimer(this.endpoint);
|
|
168023
|
+
let dispatched = false;
|
|
168024
|
+
if (mapping?.chargingSwitchEntity) {
|
|
168025
|
+
homeAssistant.callAction({
|
|
168026
|
+
action: "switch.turn_on",
|
|
168027
|
+
target: mapping.chargingSwitchEntity
|
|
168028
|
+
});
|
|
168029
|
+
dispatched = true;
|
|
168030
|
+
}
|
|
168031
|
+
const maxCurrent = request.maximumChargeCurrent;
|
|
168032
|
+
if (mapping?.currentLimitEntity && maxCurrent != null) {
|
|
168033
|
+
const amps = Math.max(
|
|
168034
|
+
MIN_CHARGE_CURRENT_MA / 1e3,
|
|
168035
|
+
Math.floor(clampMa(Number(maxCurrent)) / 1e3)
|
|
168036
|
+
);
|
|
168037
|
+
homeAssistant.callAction({
|
|
168038
|
+
action: "number.set_value",
|
|
168039
|
+
target: mapping.currentLimitEntity,
|
|
168040
|
+
data: { value: amps }
|
|
168041
|
+
});
|
|
168042
|
+
dispatched = true;
|
|
168043
|
+
}
|
|
168044
|
+
if (!dispatched) {
|
|
168045
|
+
logger229.debug(
|
|
168046
|
+
`enableCharging ignored for ${homeAssistant.entityId}: no charging switch or current limit mapped`
|
|
168047
|
+
);
|
|
168048
|
+
return;
|
|
168049
|
+
}
|
|
168050
|
+
const patch = {
|
|
168051
|
+
supplyState: EnergyEvse3.SupplyState.ChargingEnabled,
|
|
168052
|
+
chargingEnabledUntil: until ?? null
|
|
168053
|
+
};
|
|
168054
|
+
if (request.minimumChargeCurrent != null) {
|
|
168055
|
+
patch.minimumChargeCurrent = clampMa(
|
|
168056
|
+
Number(request.minimumChargeCurrent)
|
|
168057
|
+
);
|
|
168058
|
+
}
|
|
168059
|
+
if (maxCurrent != null) {
|
|
168060
|
+
patch.maximumChargeCurrent = clampMa(Number(maxCurrent));
|
|
168061
|
+
}
|
|
168062
|
+
applyPatchState(this.state, patch);
|
|
168063
|
+
if (until != null) {
|
|
168064
|
+
const delay = until * 1e3 - Date.now();
|
|
168065
|
+
if (delay > 0 && delay <= MAX_TIMER_MS) {
|
|
168066
|
+
const endpoint = this.endpoint;
|
|
168067
|
+
const actions = this.env.get(HomeAssistantActions);
|
|
168068
|
+
const entityId = homeAssistant.entityId;
|
|
168069
|
+
const switchEntity = mapping?.chargingSwitchEntity;
|
|
168070
|
+
const timer = setTimeout(() => {
|
|
168071
|
+
void (async () => {
|
|
168072
|
+
try {
|
|
168073
|
+
if (evseChargingTimers.get(endpoint) !== timer) return;
|
|
168074
|
+
if (switchEntity) {
|
|
168075
|
+
actions.call(
|
|
168076
|
+
{ action: "switch.turn_off", target: switchEntity },
|
|
168077
|
+
entityId
|
|
168078
|
+
);
|
|
168079
|
+
}
|
|
168080
|
+
await endpoint.setStateOf(_EvseStatusServer, {
|
|
168081
|
+
supplyState: EnergyEvse3.SupplyState.Disabled,
|
|
168082
|
+
chargingEnabledUntil: null
|
|
168083
|
+
});
|
|
168084
|
+
} catch (error) {
|
|
168085
|
+
logger229.debug(
|
|
168086
|
+
`EVSE charge-window expiry write failed (endpoint may be closing): ${error}`
|
|
168087
|
+
);
|
|
168088
|
+
} finally {
|
|
168089
|
+
if (evseChargingTimers.get(endpoint) === timer) {
|
|
168090
|
+
evseChargingTimers.delete(endpoint);
|
|
168091
|
+
}
|
|
168092
|
+
}
|
|
168093
|
+
})();
|
|
168094
|
+
}, delay);
|
|
168095
|
+
timer.unref?.();
|
|
168096
|
+
evseChargingTimers.set(endpoint, timer);
|
|
168097
|
+
}
|
|
168098
|
+
}
|
|
168099
|
+
}
|
|
168100
|
+
disable() {
|
|
168101
|
+
clearEvseChargingTimer(this.endpoint);
|
|
168102
|
+
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
168103
|
+
const mapping = homeAssistant.state.mapping;
|
|
168104
|
+
if (mapping?.chargingSwitchEntity) {
|
|
168105
|
+
homeAssistant.callAction({
|
|
168106
|
+
action: "switch.turn_off",
|
|
168107
|
+
target: mapping.chargingSwitchEntity
|
|
168108
|
+
});
|
|
168109
|
+
}
|
|
168110
|
+
if (mapping?.chargingSwitchEntity || mapping?.currentLimitEntity) {
|
|
168111
|
+
applyPatchState(this.state, {
|
|
168112
|
+
supplyState: EnergyEvse3.SupplyState.Disabled,
|
|
168113
|
+
chargingEnabledUntil: null
|
|
168114
|
+
});
|
|
168115
|
+
} else {
|
|
168116
|
+
logger229.debug(
|
|
168117
|
+
`disable ignored for ${homeAssistant.entityId}: no charging switch mapped`
|
|
168118
|
+
);
|
|
168119
|
+
}
|
|
168120
|
+
}
|
|
168121
|
+
};
|
|
168122
|
+
var EvseStatusSeeded = EvseStatusServer.set({
|
|
168123
|
+
supplyState: EnergyEvse3.SupplyState.Disabled,
|
|
168124
|
+
faultState: EnergyEvse3.FaultState.NoError,
|
|
168125
|
+
circuitCapacity: CIRCUIT_CAPACITY_MA,
|
|
168126
|
+
minimumChargeCurrent: MIN_CHARGE_CURRENT_MA,
|
|
168127
|
+
maximumChargeCurrent: MAX_CHARGE_CURRENT_MA
|
|
168128
|
+
});
|
|
168129
|
+
var EvseModeSeeded = EnergyEvseModeServer.set({
|
|
168130
|
+
supportedModes: [
|
|
168131
|
+
{
|
|
168132
|
+
label: "Manual",
|
|
168133
|
+
mode: 1,
|
|
168134
|
+
modeTags: [{ value: EnergyEvseMode3.ModeTag.Manual }]
|
|
168135
|
+
}
|
|
168136
|
+
],
|
|
168137
|
+
currentMode: 1
|
|
168138
|
+
});
|
|
168139
|
+
var WiredPowerSourceBase = PowerSourceServer.with("Wired");
|
|
168140
|
+
var EvsePowerSourceServer = class extends WiredPowerSourceBase {
|
|
168141
|
+
async initialize() {
|
|
168142
|
+
await super.initialize();
|
|
168143
|
+
const endpointNumber = this.endpoint.number;
|
|
168144
|
+
if (endpointNumber != null) {
|
|
168145
|
+
applyPatchState(this.state, { endpointList: [endpointNumber] });
|
|
168146
|
+
}
|
|
168147
|
+
}
|
|
168148
|
+
};
|
|
168149
|
+
var EvsePowerSource = EvsePowerSourceServer.set({
|
|
168150
|
+
status: PowerSource3.PowerSourceStatus.Active,
|
|
168151
|
+
order: 0,
|
|
168152
|
+
description: "Mains",
|
|
168153
|
+
wiredCurrentType: PowerSource3.WiredCurrentType.Ac
|
|
168154
|
+
});
|
|
168155
|
+
var EnergyEvseBase = EnergyEvseDevice.with(
|
|
168156
|
+
BasicInformationServer2,
|
|
168157
|
+
IdentifyServer2,
|
|
168158
|
+
HomeAssistantEntityBehavior,
|
|
168159
|
+
EvseStatusSeeded,
|
|
168160
|
+
EvseModeSeeded,
|
|
168161
|
+
EvsePowerSource,
|
|
168162
|
+
// Always mount the measurement clusters; both seed safe defaults when no
|
|
168163
|
+
// power/energy entity is mapped, so the endpoint honestly carries the
|
|
168164
|
+
// ElectricalSensor device type.
|
|
168165
|
+
PowerServer,
|
|
168166
|
+
EnergyServer,
|
|
168167
|
+
DescriptorServer
|
|
168168
|
+
).set({
|
|
168169
|
+
descriptor: {
|
|
168170
|
+
deviceTypeList: [
|
|
168171
|
+
{ deviceType: DeviceTypeId(1292), revision: 2 },
|
|
168172
|
+
{ deviceType: DeviceTypeId(1296), revision: 1 }
|
|
168173
|
+
]
|
|
168174
|
+
}
|
|
168175
|
+
});
|
|
168176
|
+
function energyEvseType() {
|
|
168177
|
+
return EnergyEvseBase;
|
|
168178
|
+
}
|
|
168179
|
+
|
|
167523
168180
|
// src/matter/behaviors/flow-measurement-server.ts
|
|
167524
168181
|
init_home_assistant_entity_behavior();
|
|
167525
168182
|
var FlowMeasurementServerBase = class extends FlowMeasurementServer {
|
|
@@ -168259,7 +168916,7 @@ var TvocConcentrationMeasurementServer = class extends TvocConcentrationMeasurem
|
|
|
168259
168916
|
};
|
|
168260
168917
|
|
|
168261
168918
|
// src/matter/endpoints/legacy/sensor/devices/tvoc-sensor.ts
|
|
168262
|
-
var
|
|
168919
|
+
var logger230 = Logger.get("TvocSensor");
|
|
168263
168920
|
function airQualityFromUgm3(value) {
|
|
168264
168921
|
if (value <= 300) return AirQuality3.AirQualityEnum.Good;
|
|
168265
168922
|
if (value <= 1e3) return AirQuality3.AirQualityEnum.Fair;
|
|
@@ -168300,17 +168957,17 @@ var TvocAirQualityServer = class extends TvocAirQualityServerBase {
|
|
|
168300
168957
|
const attributes9 = entity.state.attributes;
|
|
168301
168958
|
const deviceClass = attributes9.device_class;
|
|
168302
168959
|
let airQuality = AirQuality3.AirQualityEnum.Unknown;
|
|
168303
|
-
|
|
168960
|
+
logger230.debug(
|
|
168304
168961
|
`[${entity.entity_id}] TVOC update: state="${state}", device_class="${deviceClass}"`
|
|
168305
168962
|
);
|
|
168306
168963
|
if (state != null && !Number.isNaN(+state)) {
|
|
168307
168964
|
const value = +state;
|
|
168308
168965
|
airQuality = deviceClass === SensorDeviceClass.volatile_organic_compounds ? airQualityFromUgm3(value) : airQualityFromPpb(value);
|
|
168309
|
-
|
|
168966
|
+
logger230.debug(
|
|
168310
168967
|
`[${entity.entity_id}] TVOC value=${value} (${deviceClass}) -> airQuality=${AirQuality3.AirQualityEnum[airQuality]}`
|
|
168311
168968
|
);
|
|
168312
168969
|
} else {
|
|
168313
|
-
|
|
168970
|
+
logger230.warn(
|
|
168314
168971
|
`[${entity.entity_id}] TVOC state not a valid number: "${state}"`
|
|
168315
168972
|
);
|
|
168316
168973
|
}
|
|
@@ -168524,7 +169181,7 @@ init_home_assistant_entity_behavior();
|
|
|
168524
169181
|
// src/matter/behaviors/pm25-concentration-measurement-server.ts
|
|
168525
169182
|
init_esm();
|
|
168526
169183
|
init_home_assistant_entity_behavior();
|
|
168527
|
-
var
|
|
169184
|
+
var logger231 = Logger.get("Pm25ConcentrationMeasurementServer");
|
|
168528
169185
|
var Pm25ConcentrationMeasurementServerBase = Pm25ConcentrationMeasurementServer.with(
|
|
168529
169186
|
ConcentrationMeasurement3.Feature.NumericMeasurement
|
|
168530
169187
|
);
|
|
@@ -168548,11 +169205,11 @@ var Pm25ConcentrationMeasurementServer2 = class extends Pm25ConcentrationMeasure
|
|
|
168548
169205
|
if (this.state.measurementMedium === void 0) {
|
|
168549
169206
|
this.state.measurementMedium = ConcentrationMeasurement3.MeasurementMedium.Air;
|
|
168550
169207
|
}
|
|
168551
|
-
|
|
169208
|
+
logger231.debug(
|
|
168552
169209
|
"Pm25ConcentrationMeasurementServer: before super.initialize()"
|
|
168553
169210
|
);
|
|
168554
169211
|
await super.initialize();
|
|
168555
|
-
|
|
169212
|
+
logger231.debug(
|
|
168556
169213
|
"Pm25ConcentrationMeasurementServer: after super.initialize()"
|
|
168557
169214
|
);
|
|
168558
169215
|
const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
|
|
@@ -168575,7 +169232,7 @@ var Pm25ConcentrationMeasurementServer2 = class extends Pm25ConcentrationMeasure
|
|
|
168575
169232
|
};
|
|
168576
169233
|
|
|
168577
169234
|
// src/matter/endpoints/legacy/sensor/devices/pm25-sensor.ts
|
|
168578
|
-
var
|
|
169235
|
+
var logger232 = Logger.get("Pm25AirQualityServer");
|
|
168579
169236
|
var Pm25AirQualityServerBase = AirQualityServer.with(
|
|
168580
169237
|
AirQuality3.Feature.Fair,
|
|
168581
169238
|
AirQuality3.Feature.Moderate,
|
|
@@ -168587,9 +169244,9 @@ var Pm25AirQualityServer = class extends Pm25AirQualityServerBase {
|
|
|
168587
169244
|
if (this.state.airQuality === void 0) {
|
|
168588
169245
|
this.state.airQuality = AirQuality3.AirQualityEnum.Unknown;
|
|
168589
169246
|
}
|
|
168590
|
-
|
|
169247
|
+
logger232.debug("Pm25AirQualityServer: before super.initialize()");
|
|
168591
169248
|
await super.initialize();
|
|
168592
|
-
|
|
169249
|
+
logger232.debug("Pm25AirQualityServer: after super.initialize()");
|
|
168593
169250
|
const homeAssistant = await this.agent.load(HomeAssistantEntityBehavior);
|
|
168594
169251
|
this.update(homeAssistant.entity);
|
|
168595
169252
|
this.reactTo(homeAssistant.onChange, this.update, { offline: true });
|
|
@@ -169014,7 +169671,7 @@ init_home_assistant_entity_behavior();
|
|
|
169014
169671
|
init_dist();
|
|
169015
169672
|
init_esm();
|
|
169016
169673
|
init_home_assistant_entity_behavior();
|
|
169017
|
-
var
|
|
169674
|
+
var logger233 = Logger.get("VacuumIdentifyServer");
|
|
169018
169675
|
var IDENTIFY_BUTTON_SUFFIXES = ["_identify", "_locate", "_find_me"];
|
|
169019
169676
|
var VacuumIdentifyServer = class extends IdentifyServer2 {
|
|
169020
169677
|
triggerEffect(effect) {
|
|
@@ -169031,19 +169688,19 @@ var VacuumIdentifyServer = class extends IdentifyServer2 {
|
|
|
169031
169688
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
169032
169689
|
const features3 = homeAssistant.entity.state.attributes.supported_features ?? 0;
|
|
169033
169690
|
if (testBit(features3, VacuumDeviceFeature.LOCATE)) {
|
|
169034
|
-
|
|
169691
|
+
logger233.info(`${source} \u2192 vacuum.locate for ${homeAssistant.entityId}`);
|
|
169035
169692
|
homeAssistant.callAction({ action: "vacuum.locate" });
|
|
169036
169693
|
return;
|
|
169037
169694
|
}
|
|
169038
169695
|
const sibling = this.#findIdentifyButton(homeAssistant);
|
|
169039
169696
|
if (sibling) {
|
|
169040
|
-
|
|
169697
|
+
logger233.info(
|
|
169041
169698
|
`${source} \u2192 button.press ${sibling} for ${homeAssistant.entityId}`
|
|
169042
169699
|
);
|
|
169043
169700
|
homeAssistant.callAction({ action: "button.press", target: sibling });
|
|
169044
169701
|
return;
|
|
169045
169702
|
}
|
|
169046
|
-
|
|
169703
|
+
logger233.warn(
|
|
169047
169704
|
`${source} for ${homeAssistant.entityId}, LOCATE not in supported_features (${features3}), trying vacuum.locate anyway`
|
|
169048
169705
|
);
|
|
169049
169706
|
homeAssistant.callAction({ action: "vacuum.locate" });
|
|
@@ -169242,14 +169899,14 @@ init_esm();
|
|
|
169242
169899
|
|
|
169243
169900
|
// src/matter/behaviors/service-area-server.ts
|
|
169244
169901
|
init_esm();
|
|
169245
|
-
var
|
|
169902
|
+
var logger234 = Logger.get("ServiceAreaServer");
|
|
169246
169903
|
var ServiceAreaWithProgress = ServiceAreaBehavior.with(
|
|
169247
169904
|
ServiceArea3.Feature.ProgressReporting
|
|
169248
169905
|
);
|
|
169249
169906
|
var ServiceAreaServerBase = class extends ServiceAreaWithProgress {
|
|
169250
169907
|
selectAreas(request) {
|
|
169251
169908
|
const { newAreas } = request;
|
|
169252
|
-
|
|
169909
|
+
logger234.info(
|
|
169253
169910
|
`ServiceArea selectAreas called with: ${JSON.stringify(newAreas)}`
|
|
169254
169911
|
);
|
|
169255
169912
|
const uniqueAreas = [...new Set(newAreas)];
|
|
@@ -169258,7 +169915,7 @@ var ServiceAreaServerBase = class extends ServiceAreaWithProgress {
|
|
|
169258
169915
|
(id) => !supportedAreaIds.includes(id)
|
|
169259
169916
|
);
|
|
169260
169917
|
if (invalidAreas.length > 0) {
|
|
169261
|
-
|
|
169918
|
+
logger234.warn(`Invalid area IDs requested: ${invalidAreas.join(", ")}`);
|
|
169262
169919
|
return {
|
|
169263
169920
|
status: ServiceArea3.SelectAreasStatus.UnsupportedArea,
|
|
169264
169921
|
statusText: `Invalid area IDs: ${invalidAreas.join(", ")}`
|
|
@@ -169270,7 +169927,7 @@ var ServiceAreaServerBase = class extends ServiceAreaWithProgress {
|
|
|
169270
169927
|
status: ServiceArea3.OperationalStatus.Pending
|
|
169271
169928
|
}));
|
|
169272
169929
|
this.state.currentArea = null;
|
|
169273
|
-
|
|
169930
|
+
logger234.info(
|
|
169274
169931
|
`ServiceArea: Stored ${uniqueAreas.length} areas for cleaning: ${uniqueAreas.join(", ")}`
|
|
169275
169932
|
);
|
|
169276
169933
|
return {
|
|
@@ -169291,7 +169948,7 @@ var ServiceAreaServerBase = class extends ServiceAreaWithProgress {
|
|
|
169291
169948
|
ServiceAreaServerBase2.State = State;
|
|
169292
169949
|
})(ServiceAreaServerBase || (ServiceAreaServerBase = {}));
|
|
169293
169950
|
function ServiceAreaServer2(initialState) {
|
|
169294
|
-
|
|
169951
|
+
logger234.info(
|
|
169295
169952
|
`Creating ServiceAreaServer with ${initialState.supportedAreas.length} areas`
|
|
169296
169953
|
);
|
|
169297
169954
|
return ServiceAreaServerBase.set({
|
|
@@ -169308,7 +169965,7 @@ var ServiceAreaWithMapsAndProgress = ServiceAreaBehavior.with(
|
|
|
169308
169965
|
var ServiceAreaServerWithMapsBase = class extends ServiceAreaWithMapsAndProgress {
|
|
169309
169966
|
selectAreas(request) {
|
|
169310
169967
|
const { newAreas } = request;
|
|
169311
|
-
|
|
169968
|
+
logger234.info(
|
|
169312
169969
|
`ServiceArea selectAreas called with: ${JSON.stringify(newAreas)}`
|
|
169313
169970
|
);
|
|
169314
169971
|
const uniqueAreas = [...new Set(newAreas)];
|
|
@@ -169317,7 +169974,7 @@ var ServiceAreaServerWithMapsBase = class extends ServiceAreaWithMapsAndProgress
|
|
|
169317
169974
|
(id) => !supportedAreaIds.includes(id)
|
|
169318
169975
|
);
|
|
169319
169976
|
if (invalidAreas.length > 0) {
|
|
169320
|
-
|
|
169977
|
+
logger234.warn(`Invalid area IDs requested: ${invalidAreas.join(", ")}`);
|
|
169321
169978
|
return {
|
|
169322
169979
|
status: ServiceArea3.SelectAreasStatus.UnsupportedArea,
|
|
169323
169980
|
statusText: `Invalid area IDs: ${invalidAreas.join(", ")}`
|
|
@@ -169329,7 +169986,7 @@ var ServiceAreaServerWithMapsBase = class extends ServiceAreaWithMapsAndProgress
|
|
|
169329
169986
|
status: ServiceArea3.OperationalStatus.Pending
|
|
169330
169987
|
}));
|
|
169331
169988
|
this.state.currentArea = null;
|
|
169332
|
-
|
|
169989
|
+
logger234.info(
|
|
169333
169990
|
`ServiceArea: Stored ${uniqueAreas.length} areas for cleaning: ${uniqueAreas.join(", ")}`
|
|
169334
169991
|
);
|
|
169335
169992
|
return {
|
|
@@ -169350,14 +170007,14 @@ var ServiceAreaServerWithMapsBase = class extends ServiceAreaWithMapsAndProgress
|
|
|
169350
170007
|
ServiceAreaServerWithMapsBase2.State = State;
|
|
169351
170008
|
})(ServiceAreaServerWithMapsBase || (ServiceAreaServerWithMapsBase = {}));
|
|
169352
170009
|
function ServiceAreaServerWithMaps(initialState) {
|
|
169353
|
-
|
|
170010
|
+
logger234.info(
|
|
169354
170011
|
`Creating ServiceAreaServer with Maps: ${initialState.supportedAreas.length} areas, ${initialState.supportedMaps.length} maps`
|
|
169355
170012
|
);
|
|
169356
170013
|
for (const map of initialState.supportedMaps) {
|
|
169357
170014
|
const areaCount = initialState.supportedAreas.filter(
|
|
169358
170015
|
(a) => a.mapId === map.mapId
|
|
169359
170016
|
).length;
|
|
169360
|
-
|
|
170017
|
+
logger234.info(` Map ${map.mapId}: "${map.name}" (${areaCount} areas)`);
|
|
169361
170018
|
}
|
|
169362
170019
|
return ServiceAreaServerWithMapsBase.set({
|
|
169363
170020
|
supportedAreas: initialState.supportedAreas,
|
|
@@ -169369,7 +170026,7 @@ function ServiceAreaServerWithMaps(initialState) {
|
|
|
169369
170026
|
}
|
|
169370
170027
|
|
|
169371
170028
|
// src/matter/endpoints/legacy/vacuum/behaviors/vacuum-service-area-server.ts
|
|
169372
|
-
var
|
|
170029
|
+
var logger235 = Logger.get("VacuumServiceAreaServer");
|
|
169373
170030
|
function toAreaId(roomId) {
|
|
169374
170031
|
if (typeof roomId === "number") {
|
|
169375
170032
|
return roomId;
|
|
@@ -169448,13 +170105,13 @@ function createVacuumServiceAreaServer(attributes9, roomEntities, includeUnnamed
|
|
|
169448
170105
|
let rooms;
|
|
169449
170106
|
if (roomEntities && roomEntities.length > 0) {
|
|
169450
170107
|
rooms = buttonEntitiesToRooms(roomEntities, attributes9);
|
|
169451
|
-
|
|
170108
|
+
logger235.info(
|
|
169452
170109
|
`Using ${rooms.length} button entities as rooms: ${rooms.map((r) => r.name).join(", ")}`
|
|
169453
170110
|
);
|
|
169454
170111
|
} else {
|
|
169455
170112
|
rooms = parseVacuumRooms(attributes9, includeUnnamedRooms);
|
|
169456
170113
|
if (rooms.length > 0) {
|
|
169457
|
-
|
|
170114
|
+
logger235.info(
|
|
169458
170115
|
`Using ${rooms.length} rooms from attributes: ${rooms.map((r) => r.name).join(", ")}`
|
|
169459
170116
|
);
|
|
169460
170117
|
}
|
|
@@ -169508,7 +170165,7 @@ function createCustomServiceAreaServer(customAreas) {
|
|
|
169508
170165
|
landmarkInfo: null
|
|
169509
170166
|
}
|
|
169510
170167
|
}));
|
|
169511
|
-
|
|
170168
|
+
logger235.info(
|
|
169512
170169
|
`Using ${customAreas.length} custom service areas: ${customAreas.map((a) => a.name).join(", ")}`
|
|
169513
170170
|
);
|
|
169514
170171
|
return ServiceAreaServer2({
|
|
@@ -169530,7 +170187,7 @@ function createCleanAreaServiceAreaServer(cleanAreaRooms) {
|
|
|
169530
170187
|
landmarkInfo: null
|
|
169531
170188
|
}
|
|
169532
170189
|
}));
|
|
169533
|
-
|
|
170190
|
+
logger235.info(
|
|
169534
170191
|
`Using ${cleanAreaRooms.length} HA areas via CLEAN_AREA: ${cleanAreaRooms.map((r) => r.name).join(", ")}`
|
|
169535
170192
|
);
|
|
169536
170193
|
return ServiceAreaServer2({
|
|
@@ -169541,11 +170198,11 @@ function createCleanAreaServiceAreaServer(cleanAreaRooms) {
|
|
|
169541
170198
|
}
|
|
169542
170199
|
|
|
169543
170200
|
// src/matter/endpoints/legacy/vacuum/behaviors/vacuum-rvc-run-mode-server.ts
|
|
169544
|
-
var
|
|
170201
|
+
var logger236 = Logger.get("VacuumRvcRunModeServer");
|
|
169545
170202
|
function buildValetudoSegmentAction(vacuumEntityId, segmentIds, valetudoIdentifier) {
|
|
169546
170203
|
const identifier = valetudoIdentifier || vacuumEntityId.replace(/^vacuum\.valetudo_/, "");
|
|
169547
170204
|
const topic = `valetudo/${identifier}/MapSegmentationCapability/clean/set`;
|
|
169548
|
-
|
|
170205
|
+
logger236.info(
|
|
169549
170206
|
`Valetudo: mqtt.publish to ${topic}, segments: ${segmentIds.join(", ")}`
|
|
169550
170207
|
);
|
|
169551
170208
|
return {
|
|
@@ -169650,14 +170307,14 @@ function mergeBatchData(areas) {
|
|
|
169650
170307
|
function handleCustomServiceAreas(selectedAreas, customAreas, session) {
|
|
169651
170308
|
const matched = selectedAreas.map((areaId) => ({ areaId, area: customAreas[areaId - 1] })).filter((m) => !!m.area);
|
|
169652
170309
|
if (matched.length === 0) {
|
|
169653
|
-
|
|
170310
|
+
logger236.warn(
|
|
169654
170311
|
`Custom service areas: no match for selected IDs ${selectedAreas.join(", ")}`
|
|
169655
170312
|
);
|
|
169656
170313
|
return { action: "vacuum.start" };
|
|
169657
170314
|
}
|
|
169658
170315
|
const batchArea = matched.find(({ area }) => area.batchDispatch === true);
|
|
169659
170316
|
if (batchArea) {
|
|
169660
|
-
|
|
170317
|
+
logger236.info(
|
|
169661
170318
|
`Custom service areas (batch): single call for ${matched.length} room(s): ${matched.map(({ area }) => area.name).join(", ")}`
|
|
169662
170319
|
);
|
|
169663
170320
|
session.pendingDispatches = [];
|
|
@@ -169678,7 +170335,7 @@ function handleCustomServiceAreas(selectedAreas, customAreas, session) {
|
|
|
169678
170335
|
}
|
|
169679
170336
|
};
|
|
169680
170337
|
}
|
|
169681
|
-
|
|
170338
|
+
logger236.info(
|
|
169682
170339
|
`Custom service areas: ${matched.length} room(s) queued: ${matched.map(({ area }) => `${area.service} (${area.name})`).join(", ")}`
|
|
169683
170340
|
);
|
|
169684
170341
|
session.pendingDispatches = matched.slice(1).map(({ areaId, area }) => ({
|
|
@@ -169716,7 +170373,7 @@ function vacuumIsCleaning(state) {
|
|
|
169716
170373
|
var vacuumRvcRunModeConfig = {
|
|
169717
170374
|
getCurrentMode: (entity) => {
|
|
169718
170375
|
const isCleaning = vacuumIsCleaning(entity.state);
|
|
169719
|
-
|
|
170376
|
+
logger236.debug(
|
|
169720
170377
|
`Vacuum state: "${entity.state}", isCleaning: ${isCleaning}, currentMode: ${isCleaning ? "Cleaning" : "Idle"}`
|
|
169721
170378
|
);
|
|
169722
170379
|
return isCleaning ? 1 /* Cleaning */ : 0 /* Idle */;
|
|
@@ -169750,7 +170407,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
169750
170407
|
if (cleanAreaRooms && cleanAreaRooms.length > 0) {
|
|
169751
170408
|
const haAreaIds = resolveCleanAreaIds(selectedAreas, cleanAreaRooms);
|
|
169752
170409
|
if (haAreaIds.length > 0) {
|
|
169753
|
-
|
|
170410
|
+
logger236.info(
|
|
169754
170411
|
`CLEAN_AREA: cleaning HA areas: ${haAreaIds.join(", ")}`
|
|
169755
170412
|
);
|
|
169756
170413
|
return {
|
|
@@ -169769,7 +170426,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
169769
170426
|
}
|
|
169770
170427
|
}
|
|
169771
170428
|
if (matched.length > 0) {
|
|
169772
|
-
|
|
170429
|
+
logger236.info(
|
|
169773
170430
|
`Roborock: ${matched.length} room button(s) queued: ${matched.map((m) => m.entityId).join(", ")}`
|
|
169774
170431
|
);
|
|
169775
170432
|
session.pendingDispatches = matched.slice(1).map(({ areaId, entityId }) => ({
|
|
@@ -169803,14 +170460,14 @@ var vacuumRvcRunModeConfig = {
|
|
|
169803
170460
|
}
|
|
169804
170461
|
}
|
|
169805
170462
|
if (roomIds.length > 0) {
|
|
169806
|
-
|
|
170463
|
+
logger236.info(
|
|
169807
170464
|
`Starting cleaning with selected areas: ${roomIds.join(", ")}`
|
|
169808
170465
|
);
|
|
169809
170466
|
if (isDreameVacuum(attributes9)) {
|
|
169810
170467
|
if (targetMapName) {
|
|
169811
170468
|
const vacName = vacuumEntityId.replace("vacuum.", "");
|
|
169812
170469
|
const selectedMapEntity = `select.${vacName}_selected_map`;
|
|
169813
|
-
|
|
170470
|
+
logger236.info(
|
|
169814
170471
|
`Dreame multi-floor: switching to map "${targetMapName}" via ${selectedMapEntity}`
|
|
169815
170472
|
);
|
|
169816
170473
|
homeAssistant.callAction({
|
|
@@ -169837,7 +170494,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
169837
170494
|
}
|
|
169838
170495
|
if (isEcovacsVacuum(attributes9)) {
|
|
169839
170496
|
const roomIdStr = roomIds.join(",");
|
|
169840
|
-
|
|
170497
|
+
logger236.info(
|
|
169841
170498
|
`Ecovacs vacuum: Using spot_area for rooms: ${roomIdStr}`
|
|
169842
170499
|
);
|
|
169843
170500
|
return {
|
|
@@ -169852,14 +170509,14 @@ var vacuumRvcRunModeConfig = {
|
|
|
169852
170509
|
}
|
|
169853
170510
|
};
|
|
169854
170511
|
}
|
|
169855
|
-
|
|
170512
|
+
logger236.warn(
|
|
169856
170513
|
`Room cleaning via send_command not supported for this vacuum type. Rooms: ${roomIds.join(", ")}. Falling back to vacuum.start`
|
|
169857
170514
|
);
|
|
169858
170515
|
}
|
|
169859
170516
|
}
|
|
169860
170517
|
} catch {
|
|
169861
170518
|
}
|
|
169862
|
-
|
|
170519
|
+
logger236.info("Starting regular cleaning (no areas selected)");
|
|
169863
170520
|
return { action: "vacuum.start" };
|
|
169864
170521
|
},
|
|
169865
170522
|
returnToBase: () => ({ action: "vacuum.return_to_base" }),
|
|
@@ -169874,7 +170531,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
169874
170531
|
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
169875
170532
|
const entity = homeAssistant.entity;
|
|
169876
170533
|
const attributes9 = entity.state.attributes;
|
|
169877
|
-
|
|
170534
|
+
logger236.info(`cleanRoom called: roomMode=${roomMode}`);
|
|
169878
170535
|
const cleanAreaRooms = homeAssistant.state.mapping?.cleanAreaRooms;
|
|
169879
170536
|
if (cleanAreaRooms && cleanAreaRooms.length > 0) {
|
|
169880
170537
|
const sorted = [...cleanAreaRooms].sort(
|
|
@@ -169883,7 +170540,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
169883
170540
|
const areaIndex = roomMode - ROOM_MODE_BASE2 - 1;
|
|
169884
170541
|
if (areaIndex >= 0 && areaIndex < sorted.length) {
|
|
169885
170542
|
const area = sorted[areaIndex];
|
|
169886
|
-
|
|
170543
|
+
logger236.info(
|
|
169887
170544
|
`cleanRoom: CLEAN_AREA "${area.name}" \u2192 vacuum.clean_area(${area.haAreaId})`
|
|
169888
170545
|
);
|
|
169889
170546
|
return {
|
|
@@ -169900,7 +170557,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
169900
170557
|
const areaIndex = roomMode - ROOM_MODE_BASE2 - 1;
|
|
169901
170558
|
if (areaIndex >= 0 && areaIndex < sorted.length) {
|
|
169902
170559
|
const area = sorted[areaIndex];
|
|
169903
|
-
|
|
170560
|
+
logger236.info(
|
|
169904
170561
|
`cleanRoom: custom service area "${area.name}" \u2192 ${area.service}`
|
|
169905
170562
|
);
|
|
169906
170563
|
return {
|
|
@@ -169921,7 +170578,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
169921
170578
|
}
|
|
169922
170579
|
const rooms = parseVacuumRooms(attributes9);
|
|
169923
170580
|
const numericIdFromMode = getRoomIdFromMode(roomMode);
|
|
169924
|
-
|
|
170581
|
+
logger236.info(
|
|
169925
170582
|
`cleanRoom: numericIdFromMode=${numericIdFromMode}, available rooms: ${JSON.stringify(rooms.map((r) => ({ id: r.id, name: r.name, modeValue: getRoomModeValue(r) })))}`
|
|
169926
170583
|
);
|
|
169927
170584
|
const room = rooms.find((r) => getRoomModeValue(r) === roomMode);
|
|
@@ -169931,7 +170588,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
169931
170588
|
if (room.mapName) {
|
|
169932
170589
|
const vacuumName = vacuumEntityId.replace("vacuum.", "");
|
|
169933
170590
|
const selectedMapEntity = `select.${vacuumName}_selected_map`;
|
|
169934
|
-
|
|
170591
|
+
logger236.info(
|
|
169935
170592
|
`Dreame multi-floor: switching to map "${room.mapName}" via ${selectedMapEntity}`
|
|
169936
170593
|
);
|
|
169937
170594
|
homeAssistant.callAction({
|
|
@@ -169940,7 +170597,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
169940
170597
|
data: { option: room.mapName }
|
|
169941
170598
|
});
|
|
169942
170599
|
}
|
|
169943
|
-
|
|
170600
|
+
logger236.debug(
|
|
169944
170601
|
`Dreame vacuum detected, using dreame_vacuum.vacuum_clean_segment for room ${room.name} (commandId: ${commandId3}, id: ${room.id})`
|
|
169945
170602
|
);
|
|
169946
170603
|
return {
|
|
@@ -169951,7 +170608,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
169951
170608
|
};
|
|
169952
170609
|
}
|
|
169953
170610
|
if (isRoborockVacuum(attributes9) || isXiaomiMiotVacuum(attributes9)) {
|
|
169954
|
-
|
|
170611
|
+
logger236.debug(
|
|
169955
170612
|
`Using vacuum.send_command with app_segment_clean for room ${room.name} (commandId: ${commandId3}, id: ${room.id})`
|
|
169956
170613
|
);
|
|
169957
170614
|
return {
|
|
@@ -169964,7 +170621,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
169964
170621
|
}
|
|
169965
170622
|
if (isEcovacsVacuum(attributes9)) {
|
|
169966
170623
|
const roomIdStr = String(commandId3);
|
|
169967
|
-
|
|
170624
|
+
logger236.info(
|
|
169968
170625
|
`Ecovacs vacuum: Using spot_area for room ${room.name} (id: ${roomIdStr})`
|
|
169969
170626
|
);
|
|
169970
170627
|
return {
|
|
@@ -169979,7 +170636,7 @@ var vacuumRvcRunModeConfig = {
|
|
|
169979
170636
|
}
|
|
169980
170637
|
};
|
|
169981
170638
|
}
|
|
169982
|
-
|
|
170639
|
+
logger236.warn(
|
|
169983
170640
|
`Room cleaning via send_command not supported for this vacuum type. Room: ${room.name} (id=${commandId3}). Falling back to vacuum.start`
|
|
169984
170641
|
);
|
|
169985
170642
|
}
|
|
@@ -169996,20 +170653,20 @@ function createVacuumRvcRunModeServer(attributes9, includeUnnamedRooms = false,
|
|
|
169996
170653
|
customAreas,
|
|
169997
170654
|
disableRoomModes
|
|
169998
170655
|
);
|
|
169999
|
-
|
|
170656
|
+
logger236.info(
|
|
170000
170657
|
`Creating VacuumRvcRunModeServer with ${rooms.length} rooms, ${supportedModes2.length} total modes`
|
|
170001
170658
|
);
|
|
170002
170659
|
if (rooms.length > 0) {
|
|
170003
|
-
|
|
170660
|
+
logger236.info(`Rooms found: ${rooms.map((r) => r.name).join(", ")}`);
|
|
170004
170661
|
}
|
|
170005
170662
|
if (filteredCount > 0) {
|
|
170006
170663
|
const filtered = allRooms.filter((r) => !rooms.some((x) => x.id === r.id));
|
|
170007
|
-
|
|
170664
|
+
logger236.info(
|
|
170008
170665
|
`Filtered out ${filteredCount} unnamed room(s): ${filtered.map((r) => r.name).join(", ")}`
|
|
170009
170666
|
);
|
|
170010
170667
|
}
|
|
170011
170668
|
if (allRooms.length === 0) {
|
|
170012
|
-
|
|
170669
|
+
logger236.debug(
|
|
170013
170670
|
`No rooms found. Attributes: rooms=${JSON.stringify(attributes9.rooms)}, segments=${JSON.stringify(attributes9.segments)}, room_list=${attributes9.room_list}`
|
|
170014
170671
|
);
|
|
170015
170672
|
}
|
|
@@ -170043,7 +170700,7 @@ function createCleanAreaRvcRunModeServer(cleanAreaRooms) {
|
|
|
170043
170700
|
modeTags: [{ value: RvcRunMode3.ModeTag.Cleaning }]
|
|
170044
170701
|
});
|
|
170045
170702
|
}
|
|
170046
|
-
|
|
170703
|
+
logger236.info(
|
|
170047
170704
|
`Creating CLEAN_AREA RvcRunModeServer with ${cleanAreaRooms.length} HA areas, ${modes.length} total modes`
|
|
170048
170705
|
);
|
|
170049
170706
|
return RvcRunModeServer2(vacuumRvcRunModeConfig, {
|
|
@@ -170133,7 +170790,7 @@ init_nodejs();
|
|
|
170133
170790
|
|
|
170134
170791
|
// src/matter/behaviors/rvc-clean-mode-server.ts
|
|
170135
170792
|
init_home_assistant_entity_behavior();
|
|
170136
|
-
var
|
|
170793
|
+
var logger237 = Logger.get("RvcCleanModeServerBase");
|
|
170137
170794
|
var RvcCleanModeServerBase = class _RvcCleanModeServerBase extends RvcCleanModeServer {
|
|
170138
170795
|
// Pending mode from a recent changeToMode command.
|
|
170139
170796
|
// Prevents stale HA state (from a different entity like select.xxx)
|
|
@@ -170180,14 +170837,14 @@ var RvcCleanModeServerBase = class _RvcCleanModeServerBase extends RvcCleanModeS
|
|
|
170180
170837
|
const homeAssistant = this.agent.get(HomeAssistantEntityBehavior);
|
|
170181
170838
|
const { newMode } = request;
|
|
170182
170839
|
if (newMode !== this.state.currentMode && !this.state.supportedModes.some((m) => m.mode === newMode)) {
|
|
170183
|
-
|
|
170840
|
+
logger237.warn(`changeToMode(${newMode}) rejected: unsupported mode`);
|
|
170184
170841
|
return {
|
|
170185
170842
|
status: ModeBase3.ModeChangeStatus.UnsupportedMode,
|
|
170186
170843
|
statusText: `Unsupported mode: ${newMode}`
|
|
170187
170844
|
};
|
|
170188
170845
|
}
|
|
170189
170846
|
const modeLabel = this.state.supportedModes.find((m) => m.mode === newMode);
|
|
170190
|
-
|
|
170847
|
+
logger237.info(
|
|
170191
170848
|
`changeToMode(${newMode}) "${modeLabel?.label ?? "unknown"}" for ${homeAssistant.entityId}`
|
|
170192
170849
|
);
|
|
170193
170850
|
this.pendingMode = newMode;
|
|
@@ -170195,7 +170852,7 @@ var RvcCleanModeServerBase = class _RvcCleanModeServerBase extends RvcCleanModeS
|
|
|
170195
170852
|
this.state.currentMode = newMode;
|
|
170196
170853
|
const action = this.state.config.setCleanMode(newMode, this.agent);
|
|
170197
170854
|
if (action) {
|
|
170198
|
-
|
|
170855
|
+
logger237.info(
|
|
170199
170856
|
`changeToMode: dispatching action ${action.action} \u2192 ${action.target ?? homeAssistant.entityId}`
|
|
170200
170857
|
);
|
|
170201
170858
|
homeAssistant.callAction(action);
|
|
@@ -170228,7 +170885,7 @@ function RvcCleanModeServer2(config11, initialState) {
|
|
|
170228
170885
|
}
|
|
170229
170886
|
|
|
170230
170887
|
// src/matter/endpoints/legacy/vacuum/behaviors/vacuum-rvc-clean-mode-server.ts
|
|
170231
|
-
var
|
|
170888
|
+
var logger238 = Logger.get("VacuumRvcCleanModeServer");
|
|
170232
170889
|
var MODE_VACUUM = 0;
|
|
170233
170890
|
var MODE_VACUUM_AND_MOP = 1;
|
|
170234
170891
|
var MODE_MOP = 2;
|
|
@@ -170498,7 +171155,7 @@ function findMatchingCleanOption(ct, availableOptions) {
|
|
|
170498
171155
|
const match = availableOptions.find((o) => classifyCleanOption(o) === type);
|
|
170499
171156
|
if (match) return match;
|
|
170500
171157
|
}
|
|
170501
|
-
|
|
171158
|
+
logger238.warn(
|
|
170502
171159
|
`No match for ${CLEAN_TYPE_LABELS[ct]} in [${availableOptions.join(", ")}]`
|
|
170503
171160
|
);
|
|
170504
171161
|
return availableOptions[0];
|
|
@@ -170507,7 +171164,7 @@ function buildCleaningModeAction(targetCleanType, agent) {
|
|
|
170507
171164
|
const selectEntityId = getCleaningModeSelectEntity(agent);
|
|
170508
171165
|
const { options } = readSelectEntity(selectEntityId, agent);
|
|
170509
171166
|
const optionToUse = findMatchingCleanOption(targetCleanType, options);
|
|
170510
|
-
|
|
171167
|
+
logger238.info(
|
|
170511
171168
|
`Switching cleaning mode to: ${optionToUse} via ${selectEntityId}`
|
|
170512
171169
|
);
|
|
170513
171170
|
return {
|
|
@@ -170596,7 +171253,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
170596
171253
|
}
|
|
170597
171254
|
}
|
|
170598
171255
|
if (speedMode !== void 0) {
|
|
170599
|
-
|
|
171256
|
+
logger238.debug(
|
|
170600
171257
|
`Current mode: Vacuum + fan_speed="${speedState}" -> mode ${speedMode}`
|
|
170601
171258
|
);
|
|
170602
171259
|
return speedMode;
|
|
@@ -170617,7 +171274,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
170617
171274
|
}
|
|
170618
171275
|
}
|
|
170619
171276
|
if (mopMode !== void 0) {
|
|
170620
|
-
|
|
171277
|
+
logger238.debug(
|
|
170621
171278
|
`Current mode: Mop + intensity="${state}" -> mode ${mopMode}`
|
|
170622
171279
|
);
|
|
170623
171280
|
return mopMode;
|
|
@@ -170635,14 +171292,14 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
170635
171292
|
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
170636
171293
|
const vacuumEntityId = homeAssistant.entityId;
|
|
170637
171294
|
const mapping = homeAssistant.state.mapping;
|
|
170638
|
-
|
|
171295
|
+
logger238.info(
|
|
170639
171296
|
`setCleanMode(${mode}) for ${vacuumEntityId}, suctionEntity=${mapping?.suctionLevelEntity ?? "none"}, mopEntity=${mapping?.mopIntensityEntity ?? "none"}, fanSpeedList=${JSON.stringify(fanSpeedList ?? [])}, mopIntensityList=${JSON.stringify(mopIntensityList ?? [])}, customTags=${JSON.stringify(customFanSpeedTags ?? {})}`
|
|
170640
171297
|
);
|
|
170641
171298
|
if (mopIntensityList && mopIntensityList.length > 0 && isMopIntensityMode(mode)) {
|
|
170642
171299
|
const mopIndex = mode - MOP_INTENSITY_MODE_BASE;
|
|
170643
171300
|
const mopName = mopIntensityList[mopIndex];
|
|
170644
171301
|
if (!mopName) {
|
|
170645
|
-
|
|
171302
|
+
logger238.warn(`Invalid mop intensity mode index: ${mopIndex}`);
|
|
170646
171303
|
return void 0;
|
|
170647
171304
|
}
|
|
170648
171305
|
if (hasCleanTypes) {
|
|
@@ -170655,18 +171312,18 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
170655
171312
|
mapping.mopIntensityEntity,
|
|
170656
171313
|
agent
|
|
170657
171314
|
);
|
|
170658
|
-
|
|
171315
|
+
logger238.info(
|
|
170659
171316
|
`Mop intensity entity ${mapping.mopIntensityEntity}: current="${state}", options=${JSON.stringify(options ?? [])}`
|
|
170660
171317
|
);
|
|
170661
171318
|
let option = matchMopIntensityOption(mopName, options);
|
|
170662
171319
|
if (!option && options && mopIndex < options.length) {
|
|
170663
171320
|
option = options[mopIndex];
|
|
170664
|
-
|
|
171321
|
+
logger238.info(
|
|
170665
171322
|
`Positional match for mop "${mopName}" -> "${option}" (index ${mopIndex})`
|
|
170666
171323
|
);
|
|
170667
171324
|
}
|
|
170668
171325
|
if (option) {
|
|
170669
|
-
|
|
171326
|
+
logger238.info(
|
|
170670
171327
|
`Setting mop intensity to: ${option} via ${mapping.mopIntensityEntity}`
|
|
170671
171328
|
);
|
|
170672
171329
|
return {
|
|
@@ -170675,11 +171332,11 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
170675
171332
|
target: mapping.mopIntensityEntity
|
|
170676
171333
|
};
|
|
170677
171334
|
}
|
|
170678
|
-
|
|
171335
|
+
logger238.warn(
|
|
170679
171336
|
`No match for mop intensity "${mopName}" in options: [${(options ?? []).join(", ")}]`
|
|
170680
171337
|
);
|
|
170681
171338
|
} else {
|
|
170682
|
-
|
|
171339
|
+
logger238.warn(
|
|
170683
171340
|
`Mop intensity mode ${mode} requested but no mopIntensityEntity configured`
|
|
170684
171341
|
);
|
|
170685
171342
|
}
|
|
@@ -170689,7 +171346,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
170689
171346
|
const fanSpeedIndex = mode - FAN_SPEED_MODE_BASE;
|
|
170690
171347
|
const fanSpeedName = fanSpeedList[fanSpeedIndex];
|
|
170691
171348
|
if (!fanSpeedName) {
|
|
170692
|
-
|
|
171349
|
+
logger238.warn(`Invalid fan speed mode index: ${fanSpeedIndex}`);
|
|
170693
171350
|
return void 0;
|
|
170694
171351
|
}
|
|
170695
171352
|
if (mapping?.suctionLevelEntity) {
|
|
@@ -170702,7 +171359,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
170702
171359
|
mapping.suctionLevelEntity,
|
|
170703
171360
|
agent
|
|
170704
171361
|
);
|
|
170705
|
-
|
|
171362
|
+
logger238.info(
|
|
170706
171363
|
`Suction entity ${mapping.suctionLevelEntity}: current="${state}", options=${JSON.stringify(options ?? [])}`
|
|
170707
171364
|
);
|
|
170708
171365
|
let option = matchFanSpeedOption(
|
|
@@ -170712,12 +171369,12 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
170712
171369
|
);
|
|
170713
171370
|
if (!option && options && fanSpeedIndex < options.length) {
|
|
170714
171371
|
option = options[fanSpeedIndex];
|
|
170715
|
-
|
|
171372
|
+
logger238.info(
|
|
170716
171373
|
`Positional match for fan "${fanSpeedName}" -> "${option}" (index ${fanSpeedIndex})`
|
|
170717
171374
|
);
|
|
170718
171375
|
}
|
|
170719
171376
|
if (option) {
|
|
170720
|
-
|
|
171377
|
+
logger238.info(
|
|
170721
171378
|
`Setting suction to: ${option} via ${mapping.suctionLevelEntity}`
|
|
170722
171379
|
);
|
|
170723
171380
|
return {
|
|
@@ -170726,7 +171383,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
170726
171383
|
target: mapping.suctionLevelEntity
|
|
170727
171384
|
};
|
|
170728
171385
|
}
|
|
170729
|
-
|
|
171386
|
+
logger238.warn(
|
|
170730
171387
|
`No match for fan speed "${fanSpeedName}" in suction options: [${(options ?? []).join(", ")}]`
|
|
170731
171388
|
);
|
|
170732
171389
|
return void 0;
|
|
@@ -170736,7 +171393,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
170736
171393
|
buildCleaningModeAction(0 /* Sweeping */, agent)
|
|
170737
171394
|
);
|
|
170738
171395
|
}
|
|
170739
|
-
|
|
171396
|
+
logger238.info(
|
|
170740
171397
|
`Setting fan speed to: ${fanSpeedName} via vacuum.set_fan_speed`
|
|
170741
171398
|
);
|
|
170742
171399
|
return {
|
|
@@ -170746,7 +171403,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
170746
171403
|
};
|
|
170747
171404
|
}
|
|
170748
171405
|
if (!hasCleanTypes) {
|
|
170749
|
-
|
|
171406
|
+
logger238.debug(
|
|
170750
171407
|
`Ignoring cleaning type change (mode=${mode}): no cleaning mode entity`
|
|
170751
171408
|
);
|
|
170752
171409
|
return void 0;
|
|
@@ -170758,7 +171415,7 @@ function createCleanModeConfig(fanSpeedList, mopIntensityList, cleaningModeOptio
|
|
|
170758
171415
|
agent
|
|
170759
171416
|
);
|
|
170760
171417
|
const optionToUse = findMatchingCleanOption(cleanType, availableOptions);
|
|
170761
|
-
|
|
171418
|
+
logger238.info(
|
|
170762
171419
|
`Setting cleaning mode to: ${optionToUse} (mode=${mode}) via ${selectEntityId}`
|
|
170763
171420
|
);
|
|
170764
171421
|
return {
|
|
@@ -170776,10 +171433,10 @@ function createVacuumRvcCleanModeServer(_attributes, fanSpeedList, mopIntensityL
|
|
|
170776
171433
|
cleaningModeOptions,
|
|
170777
171434
|
customFanSpeedTags
|
|
170778
171435
|
);
|
|
170779
|
-
|
|
171436
|
+
logger238.info(
|
|
170780
171437
|
`Creating VacuumRvcCleanModeServer with ${supportedModes2.length} modes (fanSpeedList=${JSON.stringify(fanSpeedList ?? [])}, mopIntensityList=${JSON.stringify(mopIntensityList ?? [])}, cleaningModeOptions=${JSON.stringify(cleaningModeOptions ?? [])}, customTags=${JSON.stringify(customFanSpeedTags ?? {})})`
|
|
170781
171438
|
);
|
|
170782
|
-
|
|
171439
|
+
logger238.info(
|
|
170783
171440
|
`Modes: ${supportedModes2.map((m) => `${m.mode}:${m.label}[${m.modeTags.map((t) => t.value).join(",")}]`).join(", ")}`
|
|
170784
171441
|
);
|
|
170785
171442
|
const initialState = {
|
|
@@ -170842,7 +171499,7 @@ function resolveMopIntensityList(mopIntensityEntity) {
|
|
|
170842
171499
|
init_dist();
|
|
170843
171500
|
init_esm();
|
|
170844
171501
|
init_home_assistant_entity_behavior();
|
|
170845
|
-
var
|
|
171502
|
+
var logger239 = Logger.get("VacuumRvcOperationalStateServer");
|
|
170846
171503
|
function batteryFromAttributes(attrs) {
|
|
170847
171504
|
const raw = attrs.battery_level ?? attrs.battery;
|
|
170848
171505
|
if (raw == null) return null;
|
|
@@ -170893,16 +171550,16 @@ function mapVacuumOperationalState(entity, batteryPercent = batteryFromAttribute
|
|
|
170893
171550
|
operationalState = RvcOperationalState4.OperationalState.Error;
|
|
170894
171551
|
} else {
|
|
170895
171552
|
if (state.toLowerCase().includes("clean")) {
|
|
170896
|
-
|
|
171553
|
+
logger239.info(
|
|
170897
171554
|
`Unknown vacuum state "${state}" contains 'clean', treating as Running`
|
|
170898
171555
|
);
|
|
170899
171556
|
operationalState = RvcOperationalState4.OperationalState.Running;
|
|
170900
171557
|
} else {
|
|
170901
|
-
|
|
171558
|
+
logger239.info(`Unknown vacuum state "${state}", treating as Stopped`);
|
|
170902
171559
|
operationalState = RvcOperationalState4.OperationalState.Stopped;
|
|
170903
171560
|
}
|
|
170904
171561
|
}
|
|
170905
|
-
|
|
171562
|
+
logger239.debug(
|
|
170906
171563
|
`Vacuum operationalState: "${state}" -> ${RvcOperationalState4.OperationalState[operationalState]}`
|
|
170907
171564
|
);
|
|
170908
171565
|
return operationalState;
|
|
@@ -170931,7 +171588,7 @@ var VacuumRvcOperationalStateServer = RvcOperationalStateServer2({
|
|
|
170931
171588
|
});
|
|
170932
171589
|
|
|
170933
171590
|
// src/matter/endpoints/legacy/vacuum/index.ts
|
|
170934
|
-
var
|
|
171591
|
+
var logger240 = Logger.get("VacuumDevice");
|
|
170935
171592
|
var VacuumEndpointType = RoboticVacuumCleanerDevice.with(
|
|
170936
171593
|
BasicInformationServer2,
|
|
170937
171594
|
VacuumIdentifyServer,
|
|
@@ -170945,7 +171602,7 @@ function VacuumDevice(homeAssistantEntity, includeOnOff = false, cleaningModeOpt
|
|
|
170945
171602
|
const entityId = homeAssistantEntity.entity.entity_id;
|
|
170946
171603
|
const attributes9 = homeAssistantEntity.entity.state.attributes;
|
|
170947
171604
|
const customAreas = homeAssistantEntity.mapping?.customServiceAreas;
|
|
170948
|
-
|
|
171605
|
+
logger240.info(
|
|
170949
171606
|
`Creating vacuum endpoint for ${entityId}, mapping: ${JSON.stringify(homeAssistantEntity.mapping ?? "none")}`
|
|
170950
171607
|
);
|
|
170951
171608
|
const cleanAreaRooms = homeAssistantEntity.mapping?.cleanAreaRooms;
|
|
@@ -170958,32 +171615,32 @@ function VacuumDevice(homeAssistantEntity, includeOnOff = false, cleaningModeOpt
|
|
|
170958
171615
|
)
|
|
170959
171616
|
).set({ homeAssistantEntity });
|
|
170960
171617
|
if (includeOnOff) {
|
|
170961
|
-
|
|
171618
|
+
logger240.info(`${entityId}: Adding OnOff cluster (vacuumOnOff flag enabled)`);
|
|
170962
171619
|
device = device.with(VacuumOnOffServer);
|
|
170963
171620
|
}
|
|
170964
171621
|
device = device.with(VacuumPowerSourceServer);
|
|
170965
171622
|
const roomEntities = homeAssistantEntity.mapping?.roomEntities;
|
|
170966
171623
|
const rooms = parseVacuumRooms(attributes9);
|
|
170967
|
-
|
|
171624
|
+
logger240.info(
|
|
170968
171625
|
`${entityId}: customAreas=${customAreas?.length ?? 0}, roomEntities=${JSON.stringify(roomEntities ?? [])}, parsedRooms=${rooms.length}, cleanAreaRooms=${cleanAreaRooms?.length ?? 0}`
|
|
170969
171626
|
);
|
|
170970
171627
|
if (cleanAreaRooms && cleanAreaRooms.length > 0) {
|
|
170971
|
-
|
|
171628
|
+
logger240.info(
|
|
170972
171629
|
`${entityId}: Adding ServiceArea (${cleanAreaRooms.length} HA areas via CLEAN_AREA)`
|
|
170973
171630
|
);
|
|
170974
171631
|
device = device.with(createCleanAreaServiceAreaServer(cleanAreaRooms));
|
|
170975
171632
|
} else if (customAreas && customAreas.length > 0) {
|
|
170976
|
-
|
|
171633
|
+
logger240.info(
|
|
170977
171634
|
`${entityId}: Adding ServiceArea (${customAreas.length} custom areas)`
|
|
170978
171635
|
);
|
|
170979
171636
|
device = device.with(createCustomServiceAreaServer(customAreas));
|
|
170980
171637
|
} else if (rooms.length > 0 || roomEntities && roomEntities.length > 0) {
|
|
170981
|
-
|
|
171638
|
+
logger240.info(`${entityId}: Adding ServiceArea (${rooms.length} rooms)`);
|
|
170982
171639
|
device = device.with(
|
|
170983
171640
|
createVacuumServiceAreaServer(attributes9, roomEntities)
|
|
170984
171641
|
);
|
|
170985
171642
|
} else {
|
|
170986
|
-
|
|
171643
|
+
logger240.info(`${entityId}: Adding ServiceArea (default single-area)`);
|
|
170987
171644
|
device = device.with(createDefaultServiceAreaServer());
|
|
170988
171645
|
}
|
|
170989
171646
|
const fanSpeedList = resolveFanSpeedList(
|
|
@@ -170994,7 +171651,7 @@ function VacuumDevice(homeAssistantEntity, includeOnOff = false, cleaningModeOpt
|
|
|
170994
171651
|
homeAssistantEntity.mapping?.mopIntensityEntity
|
|
170995
171652
|
);
|
|
170996
171653
|
if (cleaningModeOptions || fanSpeedList || mopIntensityList) {
|
|
170997
|
-
|
|
171654
|
+
logger240.info(
|
|
170998
171655
|
`${entityId}: Adding RvcCleanMode (multi-mode, cleaningModeOptions=${JSON.stringify(cleaningModeOptions ?? [])}, fanSpeedList=${JSON.stringify(fanSpeedList ?? [])}, mopIntensityList=${JSON.stringify(mopIntensityList ?? [])})`
|
|
170999
171656
|
);
|
|
171000
171657
|
device = device.with(
|
|
@@ -171007,7 +171664,7 @@ function VacuumDevice(homeAssistantEntity, includeOnOff = false, cleaningModeOpt
|
|
|
171007
171664
|
)
|
|
171008
171665
|
);
|
|
171009
171666
|
} else {
|
|
171010
|
-
|
|
171667
|
+
logger240.info(`${entityId}: Adding RvcCleanMode (default single-mode)`);
|
|
171011
171668
|
device = device.with(createDefaultRvcCleanModeServer());
|
|
171012
171669
|
}
|
|
171013
171670
|
return device;
|
|
@@ -171173,7 +171830,7 @@ var WaterHeaterThermostatServer = ThermostatServer2(
|
|
|
171173
171830
|
);
|
|
171174
171831
|
|
|
171175
171832
|
// src/matter/endpoints/legacy/water-heater/index.ts
|
|
171176
|
-
var
|
|
171833
|
+
var logger241 = Logger.get("WaterHeaterDevice");
|
|
171177
171834
|
var WaterHeaterDeviceType = ThermostatDevice.with(
|
|
171178
171835
|
BasicInformationServer2,
|
|
171179
171836
|
IdentifyServer2,
|
|
@@ -171189,7 +171846,7 @@ function toMatterTemp2(value) {
|
|
|
171189
171846
|
}
|
|
171190
171847
|
function WaterHeaterDevice(homeAssistantEntity) {
|
|
171191
171848
|
const attributes9 = homeAssistantEntity.entity.state.attributes;
|
|
171192
|
-
|
|
171849
|
+
logger241.debug(
|
|
171193
171850
|
`Creating device for ${homeAssistantEntity.entity.entity_id}, min_temp=${attributes9.min_temp}, max_temp=${attributes9.max_temp}`
|
|
171194
171851
|
);
|
|
171195
171852
|
const minLimit = toMatterTemp2(attributes9.min_temp) ?? 0;
|
|
@@ -171429,6 +172086,7 @@ var matterDeviceTypeFactories = {
|
|
|
171429
172086
|
// Legacy SolarPower alias, kept for existing mappings.
|
|
171430
172087
|
electrical_sensor: (ha) => ElectricalSensorType.set({ homeAssistantEntity: ha }),
|
|
171431
172088
|
solar_power: (ha) => ElectricalSensorType.set({ homeAssistantEntity: ha }),
|
|
172089
|
+
evse: (ha) => energyEvseType().set({ homeAssistantEntity: ha }),
|
|
171432
172090
|
contact_sensor: (ha) => ContactSensorType.set({ homeAssistantEntity: ha }),
|
|
171433
172091
|
motion_sensor: (ha) => MotionSensorType.set({ homeAssistantEntity: ha }),
|
|
171434
172092
|
occupancy_sensor: (ha) => OccupancySensorType.set({ homeAssistantEntity: ha }),
|
|
@@ -171444,7 +172102,7 @@ var matterDeviceTypeFactories = {
|
|
|
171444
172102
|
};
|
|
171445
172103
|
|
|
171446
172104
|
// src/matter/endpoints/composed/user-composed-endpoint.ts
|
|
171447
|
-
var
|
|
172105
|
+
var logger242 = Logger.get("UserComposedEndpoint");
|
|
171448
172106
|
function stripBasicInformation(type) {
|
|
171449
172107
|
const behaviors = { ...type.behaviors };
|
|
171450
172108
|
delete behaviors.bridgedDeviceBasicInformation;
|
|
@@ -171520,7 +172178,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
171520
172178
|
{ vacuumOnOff: registry2.isVacuumOnOffEnabled() }
|
|
171521
172179
|
);
|
|
171522
172180
|
if (!primaryType) {
|
|
171523
|
-
|
|
172181
|
+
logger242.warn(
|
|
171524
172182
|
`Cannot create endpoint type for primary entity ${primaryEntityId}`
|
|
171525
172183
|
);
|
|
171526
172184
|
return void 0;
|
|
@@ -171535,7 +172193,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
171535
172193
|
if (!sub.entityId) continue;
|
|
171536
172194
|
const subPayload = buildEntityPayload4(registry2, sub.entityId);
|
|
171537
172195
|
if (!subPayload) {
|
|
171538
|
-
|
|
172196
|
+
logger242.warn(
|
|
171539
172197
|
`Cannot find state for composed sub-entity ${sub.entityId}, it does not exist in Home Assistant (removed or renamed?)`
|
|
171540
172198
|
);
|
|
171541
172199
|
continue;
|
|
@@ -171550,7 +172208,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
171550
172208
|
config11.areaName
|
|
171551
172209
|
);
|
|
171552
172210
|
if (!subType) {
|
|
171553
|
-
|
|
172211
|
+
logger242.warn(
|
|
171554
172212
|
`Cannot create endpoint type for composed sub-entity ${sub.entityId}`
|
|
171555
172213
|
);
|
|
171556
172214
|
continue;
|
|
@@ -171563,7 +172221,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
171563
172221
|
mappedIds.push(sub.entityId);
|
|
171564
172222
|
}
|
|
171565
172223
|
if (parts.length < 2) {
|
|
171566
|
-
|
|
172224
|
+
logger242.warn(
|
|
171567
172225
|
`User composed device ${primaryEntityId}: only ${parts.length} sub-endpoint(s), need at least 2 (primary + one sub-entity). Falling back to standalone.`
|
|
171568
172226
|
);
|
|
171569
172227
|
return void 0;
|
|
@@ -171587,7 +172245,7 @@ var UserComposedEndpoint = class _UserComposedEndpoint extends Endpoint {
|
|
|
171587
172245
|
const labels = parts.map(
|
|
171588
172246
|
(_, i) => i === 0 ? primaryEntityId.split(".")[0] : composedEntities[i - 1]?.entityId?.split(".")[0] ?? "?"
|
|
171589
172247
|
).join("+");
|
|
171590
|
-
|
|
172248
|
+
logger242.info(
|
|
171591
172249
|
`Created user composed device ${primaryEntityId}: ${parts.length} sub-endpoint(s) [${labels}]`
|
|
171592
172250
|
);
|
|
171593
172251
|
return endpoint;
|
|
@@ -171693,7 +172351,7 @@ function asStandaloneEndpointType(type) {
|
|
|
171693
172351
|
}
|
|
171694
172352
|
|
|
171695
172353
|
// src/matter/endpoints/legacy/legacy-endpoint.ts
|
|
171696
|
-
var
|
|
172354
|
+
var logger243 = Logger.get("LegacyEndpoint");
|
|
171697
172355
|
var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
171698
172356
|
static async create(registry2, entityId, mapping, pluginDomainMappings, standalone = false, endpointId, identityAnchor) {
|
|
171699
172357
|
const deviceRegistry = registry2.deviceOf(entityId);
|
|
@@ -171703,25 +172361,25 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171703
172361
|
return;
|
|
171704
172362
|
}
|
|
171705
172363
|
if (registry2.isAutoBatteryMappingEnabled() && registry2.isBatteryEntityUsed(entityId)) {
|
|
171706
|
-
|
|
172364
|
+
logger243.debug(
|
|
171707
172365
|
`Skipping ${entityId} - already auto-assigned as battery to another device`
|
|
171708
172366
|
);
|
|
171709
172367
|
return;
|
|
171710
172368
|
}
|
|
171711
172369
|
if (registry2.isAutoHumidityMappingEnabled() && registry2.isHumidityEntityUsed(entityId)) {
|
|
171712
|
-
|
|
172370
|
+
logger243.debug(
|
|
171713
172371
|
`Skipping ${entityId} - already auto-assigned as humidity to a temperature sensor`
|
|
171714
172372
|
);
|
|
171715
172373
|
return;
|
|
171716
172374
|
}
|
|
171717
172375
|
if (registry2.isAutoPressureMappingEnabled() && registry2.isPressureEntityUsed(entityId)) {
|
|
171718
|
-
|
|
172376
|
+
logger243.debug(
|
|
171719
172377
|
`Skipping ${entityId} - already auto-assigned as pressure to a temperature sensor`
|
|
171720
172378
|
);
|
|
171721
172379
|
return;
|
|
171722
172380
|
}
|
|
171723
172381
|
if (registry2.isAutoComposedDevicesEnabled() && registry2.isComposedSubEntityUsed(entityId)) {
|
|
171724
|
-
|
|
172382
|
+
logger243.debug(
|
|
171725
172383
|
`Skipping ${entityId} - already consumed by a composed device`
|
|
171726
172384
|
);
|
|
171727
172385
|
return;
|
|
@@ -171741,7 +172399,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171741
172399
|
humidityEntity: humidityEntityId
|
|
171742
172400
|
};
|
|
171743
172401
|
registry2.markHumidityEntityUsed(humidityEntityId);
|
|
171744
|
-
|
|
172402
|
+
logger243.debug(
|
|
171745
172403
|
`Auto-assigned humidity ${humidityEntityId} to ${entityId}`
|
|
171746
172404
|
);
|
|
171747
172405
|
}
|
|
@@ -171760,7 +172418,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171760
172418
|
pressureEntity: pressureEntityId
|
|
171761
172419
|
};
|
|
171762
172420
|
registry2.markPressureEntityUsed(pressureEntityId);
|
|
171763
|
-
|
|
172421
|
+
logger243.debug(
|
|
171764
172422
|
`Auto-assigned pressure ${pressureEntityId} to ${entityId}`
|
|
171765
172423
|
);
|
|
171766
172424
|
}
|
|
@@ -171778,7 +172436,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171778
172436
|
batteryEntity: batteryEntityId
|
|
171779
172437
|
};
|
|
171780
172438
|
registry2.markBatteryEntityUsed(batteryEntityId);
|
|
171781
|
-
|
|
172439
|
+
logger243.debug(
|
|
171782
172440
|
`Auto-assigned battery ${batteryEntityId} to ${entityId}`
|
|
171783
172441
|
);
|
|
171784
172442
|
}
|
|
@@ -171795,7 +172453,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171795
172453
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
171796
172454
|
faultEntity: faultEntityId
|
|
171797
172455
|
};
|
|
171798
|
-
|
|
172456
|
+
logger243.debug(`Auto-assigned fault ${faultEntityId} to ${entityId}`);
|
|
171799
172457
|
}
|
|
171800
172458
|
}
|
|
171801
172459
|
if (!mapping?.powerEntity) {
|
|
@@ -171811,7 +172469,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171811
172469
|
powerEntity: powerEntityId
|
|
171812
172470
|
};
|
|
171813
172471
|
registry2.markPowerEntityUsed(powerEntityId);
|
|
171814
|
-
|
|
172472
|
+
logger243.debug(`Auto-assigned power ${powerEntityId} to ${entityId}`);
|
|
171815
172473
|
}
|
|
171816
172474
|
}
|
|
171817
172475
|
}
|
|
@@ -171828,7 +172486,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171828
172486
|
energyEntity: energyEntityId
|
|
171829
172487
|
};
|
|
171830
172488
|
registry2.markEnergyEntityUsed(energyEntityId);
|
|
171831
|
-
|
|
172489
|
+
logger243.debug(
|
|
171832
172490
|
`Auto-assigned energy ${energyEntityId} to ${entityId}`
|
|
171833
172491
|
);
|
|
171834
172492
|
}
|
|
@@ -171844,7 +172502,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171844
172502
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
171845
172503
|
cleaningModeEntity: vacuumEntities.cleaningModeEntity
|
|
171846
172504
|
};
|
|
171847
|
-
|
|
172505
|
+
logger243.info(
|
|
171848
172506
|
`Auto-assigned cleaningMode ${vacuumEntities.cleaningModeEntity} to ${entityId}`
|
|
171849
172507
|
);
|
|
171850
172508
|
}
|
|
@@ -171854,7 +172512,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171854
172512
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
171855
172513
|
suctionLevelEntity: vacuumEntities.suctionLevelEntity
|
|
171856
172514
|
};
|
|
171857
|
-
|
|
172515
|
+
logger243.info(
|
|
171858
172516
|
`Auto-assigned suctionLevel ${vacuumEntities.suctionLevelEntity} to ${entityId}`
|
|
171859
172517
|
);
|
|
171860
172518
|
}
|
|
@@ -171864,7 +172522,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171864
172522
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
171865
172523
|
mopIntensityEntity: vacuumEntities.mopIntensityEntity
|
|
171866
172524
|
};
|
|
171867
|
-
|
|
172525
|
+
logger243.info(
|
|
171868
172526
|
`Auto-assigned mopIntensity ${vacuumEntities.mopIntensityEntity} to ${entityId}`
|
|
171869
172527
|
);
|
|
171870
172528
|
}
|
|
@@ -171874,7 +172532,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171874
172532
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
171875
172533
|
currentRoomEntity: vacuumEntities.currentRoomEntity
|
|
171876
172534
|
};
|
|
171877
|
-
|
|
172535
|
+
logger243.info(
|
|
171878
172536
|
`Auto-assigned currentRoom ${vacuumEntities.currentRoomEntity} to ${entityId}`
|
|
171879
172537
|
);
|
|
171880
172538
|
}
|
|
@@ -171889,7 +172547,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171889
172547
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
171890
172548
|
cleanAreaRooms
|
|
171891
172549
|
};
|
|
171892
|
-
|
|
172550
|
+
logger243.info(
|
|
171893
172551
|
`Using ${cleanAreaRooms.length} HA areas via CLEAN_AREA for ${entityId}`
|
|
171894
172552
|
);
|
|
171895
172553
|
}
|
|
@@ -171910,7 +172568,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171910
172568
|
rooms: roomsObj
|
|
171911
172569
|
}
|
|
171912
172570
|
};
|
|
171913
|
-
|
|
172571
|
+
logger243.debug(
|
|
171914
172572
|
`Auto-detected ${valetudoRooms.length} Valetudo segments for ${entityId}`
|
|
171915
172573
|
);
|
|
171916
172574
|
} else {
|
|
@@ -171927,7 +172585,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171927
172585
|
rooms: roomsObj
|
|
171928
172586
|
}
|
|
171929
172587
|
};
|
|
171930
|
-
|
|
172588
|
+
logger243.debug(
|
|
171931
172589
|
`Auto-detected ${roborockRooms.length} Roborock rooms for ${entityId}`
|
|
171932
172590
|
);
|
|
171933
172591
|
}
|
|
@@ -171936,7 +172594,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171936
172594
|
}
|
|
171937
172595
|
}
|
|
171938
172596
|
if (standalone && ((effectiveMapping?.composedEntities?.length ?? 0) > 0 || effectiveMapping?.climateExposeFan === true)) {
|
|
171939
|
-
|
|
172597
|
+
logger243.warn(
|
|
171940
172598
|
`Composed mappings are not supported in server mode, exposing ${entityId} as a flat standalone endpoint`
|
|
171941
172599
|
);
|
|
171942
172600
|
}
|
|
@@ -171955,7 +172613,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
171955
172613
|
if (composed) {
|
|
171956
172614
|
return composed;
|
|
171957
172615
|
}
|
|
171958
|
-
|
|
172616
|
+
logger243.warn(
|
|
171959
172617
|
`User composed device creation failed for ${entityId}, falling back to standalone`
|
|
171960
172618
|
);
|
|
171961
172619
|
}
|
|
@@ -172020,7 +172678,7 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172020
172678
|
if (composed) {
|
|
172021
172679
|
return composed;
|
|
172022
172680
|
}
|
|
172023
|
-
|
|
172681
|
+
logger243.warn(
|
|
172024
172682
|
`Companion fan creation failed for ${entityId}, falling back to standalone`
|
|
172025
172683
|
);
|
|
172026
172684
|
}
|
|
@@ -172100,11 +172758,11 @@ var LegacyEndpoint = class _LegacyEndpoint extends EntityEndpoint {
|
|
|
172100
172758
|
}
|
|
172101
172759
|
if (mappedChanged) {
|
|
172102
172760
|
this.pendingMappedChange = true;
|
|
172103
|
-
|
|
172761
|
+
logger243.debug(
|
|
172104
172762
|
`Mapped entity change detected for ${this.entityId}, forcing update`
|
|
172105
172763
|
);
|
|
172106
172764
|
}
|
|
172107
|
-
|
|
172765
|
+
logger243.debug(
|
|
172108
172766
|
`State update received for ${this.entityId}: state=${state.state}`
|
|
172109
172767
|
);
|
|
172110
172768
|
this.lastState = state;
|
|
@@ -172683,7 +173341,7 @@ import {
|
|
|
172683
173341
|
getCollection
|
|
172684
173342
|
} from "home-assistant-js-websocket";
|
|
172685
173343
|
import { atLeastHaVersion } from "home-assistant-js-websocket/dist/util.js";
|
|
172686
|
-
var
|
|
173344
|
+
var logger244 = Logger.get("SubscribeEntities");
|
|
172687
173345
|
function processEvent(store, updates) {
|
|
172688
173346
|
const state = { ...store.state };
|
|
172689
173347
|
if (updates.a) {
|
|
@@ -172709,7 +173367,7 @@ function processEvent(store, updates) {
|
|
|
172709
173367
|
for (const entityId in updates.c) {
|
|
172710
173368
|
let entityState = state[entityId];
|
|
172711
173369
|
if (!entityState) {
|
|
172712
|
-
|
|
173370
|
+
logger244.warn("Received state update for unknown entity", entityId);
|
|
172713
173371
|
continue;
|
|
172714
173372
|
}
|
|
172715
173373
|
entityState = { ...entityState };
|
|
@@ -172798,7 +173456,7 @@ var subscribeEntities = (conn, onChange, entityIds) => {
|
|
|
172798
173456
|
// src/services/bridges/entity-isolation-service.ts
|
|
172799
173457
|
init_esm();
|
|
172800
173458
|
init_diagnostic_event_bus();
|
|
172801
|
-
var
|
|
173459
|
+
var logger245 = Logger.get("EntityIsolation");
|
|
172802
173460
|
var EntityIsolationServiceImpl = class {
|
|
172803
173461
|
isolatedEntities = /* @__PURE__ */ new Map();
|
|
172804
173462
|
isolationCallbacks = /* @__PURE__ */ new Map();
|
|
@@ -172863,13 +173521,13 @@ var EntityIsolationServiceImpl = class {
|
|
|
172863
173521
|
}
|
|
172864
173522
|
const parsed = this.parseEndpointPath(msg);
|
|
172865
173523
|
if (!parsed) {
|
|
172866
|
-
|
|
173524
|
+
logger245.warn("Could not parse entity from error:", msg);
|
|
172867
173525
|
return false;
|
|
172868
173526
|
}
|
|
172869
173527
|
const { bridgeId, entityName } = parsed;
|
|
172870
173528
|
const callback = this.isolationCallbacks.get(bridgeId);
|
|
172871
173529
|
if (!callback) {
|
|
172872
|
-
|
|
173530
|
+
logger245.warn(
|
|
172873
173531
|
`No isolation callback registered for bridge ${bridgeId}, entity: ${entityName}`
|
|
172874
173532
|
);
|
|
172875
173533
|
return false;
|
|
@@ -172884,7 +173542,7 @@ var EntityIsolationServiceImpl = class {
|
|
|
172884
173542
|
reason,
|
|
172885
173543
|
failedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
172886
173544
|
});
|
|
172887
|
-
|
|
173545
|
+
logger245.warn(
|
|
172888
173546
|
`Isolating entity "${entityName}" from bridge ${bridgeId} due to: ${reason}`
|
|
172889
173547
|
);
|
|
172890
173548
|
diagnosticEventBus.emit("entity_error", `Entity isolated: ${entityName}`, {
|
|
@@ -172896,7 +173554,7 @@ var EntityIsolationServiceImpl = class {
|
|
|
172896
173554
|
await callback(entityName);
|
|
172897
173555
|
return true;
|
|
172898
173556
|
} catch (e) {
|
|
172899
|
-
|
|
173557
|
+
logger245.error(`Failed to isolate entity ${entityName}:`, e);
|
|
172900
173558
|
return false;
|
|
172901
173559
|
}
|
|
172902
173560
|
}
|
|
@@ -172925,119 +173583,6 @@ var EntityIsolationServiceImpl = class {
|
|
|
172925
173583
|
};
|
|
172926
173584
|
var EntityIsolationService = new EntityIsolationServiceImpl();
|
|
172927
173585
|
|
|
172928
|
-
// src/services/bridges/identity-resolver.ts
|
|
172929
|
-
var SEP = "\0";
|
|
172930
|
-
function identityKey(entity) {
|
|
172931
|
-
const uniqueId = entity.registry?.unique_id;
|
|
172932
|
-
const platform = entity.registry?.platform;
|
|
172933
|
-
if (!uniqueId || !platform) {
|
|
172934
|
-
return null;
|
|
172935
|
-
}
|
|
172936
|
-
const domain = entity.entity_id.split(".")[0];
|
|
172937
|
-
return platform + SEP + domain + SEP + uniqueId;
|
|
172938
|
-
}
|
|
172939
|
-
var IdentityResolver = class {
|
|
172940
|
-
constructor(identityStorage, mappingStorage) {
|
|
172941
|
-
this.identityStorage = identityStorage;
|
|
172942
|
-
this.mappingStorage = mappingStorage;
|
|
172943
|
-
}
|
|
172944
|
-
identityStorage;
|
|
172945
|
-
mappingStorage;
|
|
172946
|
-
async resolveIdentity(bridgeId, entity, mapping, opts) {
|
|
172947
|
-
const entityId = entity.entity_id;
|
|
172948
|
-
const key = identityKey(entity);
|
|
172949
|
-
if (key == null) {
|
|
172950
|
-
return {
|
|
172951
|
-
endpointId: createEndpointId(entityId, mapping?.customName),
|
|
172952
|
-
anchorEntityId: entityId,
|
|
172953
|
-
protected: false
|
|
172954
|
-
};
|
|
172955
|
-
}
|
|
172956
|
-
const existing = this.identityStorage.getIdentity(bridgeId, key);
|
|
172957
|
-
if (existing) {
|
|
172958
|
-
const renamedFrom = existing.lastEntityId !== entityId ? existing.lastEntityId ?? existing.anchorEntityId : void 0;
|
|
172959
|
-
if (opts.stableIdentity) {
|
|
172960
|
-
if (renamedFrom) {
|
|
172961
|
-
this.identityStorage.setIdentity(bridgeId, key, {
|
|
172962
|
-
...existing,
|
|
172963
|
-
lastEntityId: entityId
|
|
172964
|
-
});
|
|
172965
|
-
await this.rekeyMapping(bridgeId, renamedFrom, entityId);
|
|
172966
|
-
}
|
|
172967
|
-
return {
|
|
172968
|
-
endpointId: existing.endpointId,
|
|
172969
|
-
anchorEntityId: existing.anchorEntityId,
|
|
172970
|
-
protected: true,
|
|
172971
|
-
renamedFrom
|
|
172972
|
-
};
|
|
172973
|
-
}
|
|
172974
|
-
const liveEndpointId = createEndpointId(entityId, mapping?.customName);
|
|
172975
|
-
if (existing.endpointId !== liveEndpointId || existing.anchorEntityId !== entityId || existing.lastEntityId !== entityId) {
|
|
172976
|
-
this.identityStorage.setIdentity(bridgeId, key, {
|
|
172977
|
-
...existing,
|
|
172978
|
-
endpointId: liveEndpointId,
|
|
172979
|
-
anchorEntityId: entityId,
|
|
172980
|
-
lastEntityId: entityId
|
|
172981
|
-
});
|
|
172982
|
-
}
|
|
172983
|
-
return {
|
|
172984
|
-
endpointId: liveEndpointId,
|
|
172985
|
-
anchorEntityId: entityId,
|
|
172986
|
-
protected: false,
|
|
172987
|
-
renamedFrom
|
|
172988
|
-
};
|
|
172989
|
-
}
|
|
172990
|
-
const desired = createEndpointId(entityId, mapping?.customName);
|
|
172991
|
-
let endpointId = desired;
|
|
172992
|
-
if (opts.stableIdentity) {
|
|
172993
|
-
let n = 2;
|
|
172994
|
-
while (opts.isEndpointIdTaken(endpointId, key)) {
|
|
172995
|
-
endpointId = `${desired}_${n++}`;
|
|
172996
|
-
}
|
|
172997
|
-
}
|
|
172998
|
-
const record = {
|
|
172999
|
-
endpointId,
|
|
173000
|
-
anchorEntityId: entityId,
|
|
173001
|
-
lastEntityId: entityId,
|
|
173002
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
173003
|
-
};
|
|
173004
|
-
this.identityStorage.setIdentity(bridgeId, key, record);
|
|
173005
|
-
if (opts.stableIdentity) {
|
|
173006
|
-
return {
|
|
173007
|
-
endpointId: record.endpointId,
|
|
173008
|
-
anchorEntityId: record.anchorEntityId,
|
|
173009
|
-
protected: true
|
|
173010
|
-
};
|
|
173011
|
-
}
|
|
173012
|
-
return {
|
|
173013
|
-
endpointId: desired,
|
|
173014
|
-
anchorEntityId: entityId,
|
|
173015
|
-
protected: false
|
|
173016
|
-
};
|
|
173017
|
-
}
|
|
173018
|
-
// Carry a mapping from the old entity_id to the new one on rename. anchorEntityId
|
|
173019
|
-
// never changes, only the mapping key. Skips when no old mapping exists or a new
|
|
173020
|
-
// one already does, so a manual mapping under the new id is never clobbered.
|
|
173021
|
-
async rekeyMapping(bridgeId, oldEntityId, newEntityId) {
|
|
173022
|
-
if (oldEntityId === newEntityId) {
|
|
173023
|
-
return;
|
|
173024
|
-
}
|
|
173025
|
-
const old = this.mappingStorage.getMapping(bridgeId, oldEntityId);
|
|
173026
|
-
if (!old) {
|
|
173027
|
-
return;
|
|
173028
|
-
}
|
|
173029
|
-
if (this.mappingStorage.getMapping(bridgeId, newEntityId)) {
|
|
173030
|
-
return;
|
|
173031
|
-
}
|
|
173032
|
-
await this.mappingStorage.setMapping({
|
|
173033
|
-
...old,
|
|
173034
|
-
bridgeId,
|
|
173035
|
-
entityId: newEntityId
|
|
173036
|
-
});
|
|
173037
|
-
await this.mappingStorage.deleteMapping(bridgeId, oldEntityId);
|
|
173038
|
-
}
|
|
173039
|
-
};
|
|
173040
|
-
|
|
173041
173586
|
// src/services/bridges/bridge-endpoint-manager.ts
|
|
173042
173587
|
var MAX_ENTITY_ID_LENGTH = 150;
|
|
173043
173588
|
var ENDPOINT_REMOVAL_GRACE_MS = 6e4;
|
|
@@ -173047,6 +173592,7 @@ var BridgeEndpointManager = class extends Service {
|
|
|
173047
173592
|
this.client = client;
|
|
173048
173593
|
this.registry = registry2;
|
|
173049
173594
|
this.mappingStorage = mappingStorage;
|
|
173595
|
+
this.identityStorage = identityStorage;
|
|
173050
173596
|
this.bridgeId = bridgeId;
|
|
173051
173597
|
this.log = log;
|
|
173052
173598
|
this.pluginManager = pluginManager;
|
|
@@ -173068,6 +173614,7 @@ var BridgeEndpointManager = class extends Service {
|
|
|
173068
173614
|
client;
|
|
173069
173615
|
registry;
|
|
173070
173616
|
mappingStorage;
|
|
173617
|
+
identityStorage;
|
|
173071
173618
|
bridgeId;
|
|
173072
173619
|
log;
|
|
173073
173620
|
pluginManager;
|
|
@@ -173465,6 +174012,17 @@ var BridgeEndpointManager = class extends Service {
|
|
|
173465
174012
|
this.mappingFingerprints.set(entityId, fp);
|
|
173466
174013
|
}
|
|
173467
174014
|
}
|
|
174015
|
+
const fullEntities = this.registry.fullEntities;
|
|
174016
|
+
stampIdentityPresence(
|
|
174017
|
+
this.identityStorage,
|
|
174018
|
+
this.bridgeId,
|
|
174019
|
+
buildPresentIdentityKeys(fullEntities)
|
|
174020
|
+
);
|
|
174021
|
+
stampMappingPresence(
|
|
174022
|
+
this.mappingStorage,
|
|
174023
|
+
this.bridgeId,
|
|
174024
|
+
buildPresentEntityIds(fullEntities)
|
|
174025
|
+
);
|
|
173468
174026
|
const existingEndpoints = [];
|
|
173469
174027
|
const now = Date.now();
|
|
173470
174028
|
for (const endpoint of endpoints) {
|
|
@@ -173784,6 +174342,11 @@ var BridgeRegistry = class _BridgeRegistry {
|
|
|
173784
174342
|
initialState(entityId) {
|
|
173785
174343
|
return this._states[entityId];
|
|
173786
174344
|
}
|
|
174345
|
+
// The complete HA entity set (unfiltered). Used by orphan tombstone stamping
|
|
174346
|
+
// so a filter change or a scope narrowing never looks like a removal.
|
|
174347
|
+
get fullEntities() {
|
|
174348
|
+
return this.registry.entities;
|
|
174349
|
+
}
|
|
173787
174350
|
// composed sub-entities may sit outside the bridge filter (#408), so these
|
|
173788
174351
|
// fall back to the full HA registry. keep them separate from the strict
|
|
173789
174352
|
// accessors above, every other caller must stay filtered.
|
|
@@ -174509,11 +175072,11 @@ function makeWarmStartState(state, now = (/* @__PURE__ */ new Date()).toISOStrin
|
|
|
174509
175072
|
return { ...state, last_updated: now };
|
|
174510
175073
|
}
|
|
174511
175074
|
var ServerModeBridge = class {
|
|
174512
|
-
constructor(
|
|
175075
|
+
constructor(logger248, dataProvider, endpointManager, server) {
|
|
174513
175076
|
this.dataProvider = dataProvider;
|
|
174514
175077
|
this.endpointManager = endpointManager;
|
|
174515
175078
|
this.server = server;
|
|
174516
|
-
this.log =
|
|
175079
|
+
this.log = logger248.get(`ServerModeBridge / ${dataProvider.id}`);
|
|
174517
175080
|
}
|
|
174518
175081
|
dataProvider;
|
|
174519
175082
|
endpointManager;
|
|
@@ -175541,7 +176104,7 @@ function ServerModeVacuumDevice(homeAssistantEntity, includeOnOff = false, clean
|
|
|
175541
176104
|
}
|
|
175542
176105
|
|
|
175543
176106
|
// src/matter/endpoints/server-mode-vacuum-endpoint.ts
|
|
175544
|
-
var
|
|
176107
|
+
var logger246 = Logger.get("ServerModeVacuumEndpoint");
|
|
175545
176108
|
var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEndpoint {
|
|
175546
176109
|
static async create(registry2, entityId, mapping, endpointId) {
|
|
175547
176110
|
const deviceRegistry = registry2.deviceOf(entityId);
|
|
@@ -175554,7 +176117,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
175554
176117
|
if (mapping?.disableBatteryMapping && mapping.batteryEntity) {
|
|
175555
176118
|
effectiveMapping = { ...mapping, batteryEntity: void 0 };
|
|
175556
176119
|
}
|
|
175557
|
-
|
|
176120
|
+
logger246.info(
|
|
175558
176121
|
`${entityId}: device_id=${entity.device_id}, manualBattery=${mapping?.batteryEntity ?? "none"}`
|
|
175559
176122
|
);
|
|
175560
176123
|
if (entity.device_id) {
|
|
@@ -175569,15 +176132,15 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
175569
176132
|
batteryEntity: batteryEntityId
|
|
175570
176133
|
};
|
|
175571
176134
|
registry2.markBatteryEntityUsed(batteryEntityId);
|
|
175572
|
-
|
|
176135
|
+
logger246.info(`${entityId}: Auto-assigned battery ${batteryEntityId}`);
|
|
175573
176136
|
} else {
|
|
175574
176137
|
const attrs = state.attributes;
|
|
175575
176138
|
if (attrs.battery_level != null || attrs.battery != null) {
|
|
175576
|
-
|
|
176139
|
+
logger246.info(
|
|
175577
176140
|
`${entityId}: No battery entity found, using battery attribute from vacuum state`
|
|
175578
176141
|
);
|
|
175579
176142
|
} else {
|
|
175580
|
-
|
|
176143
|
+
logger246.warn(
|
|
175581
176144
|
`${entityId}: No battery entity found for device ${entity.device_id}`
|
|
175582
176145
|
);
|
|
175583
176146
|
}
|
|
@@ -175592,7 +176155,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
175592
176155
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
175593
176156
|
cleaningModeEntity: vacuumEntities.cleaningModeEntity
|
|
175594
176157
|
};
|
|
175595
|
-
|
|
176158
|
+
logger246.info(
|
|
175596
176159
|
`${entityId}: Auto-assigned cleaningMode ${vacuumEntities.cleaningModeEntity}`
|
|
175597
176160
|
);
|
|
175598
176161
|
}
|
|
@@ -175602,7 +176165,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
175602
176165
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
175603
176166
|
suctionLevelEntity: vacuumEntities.suctionLevelEntity
|
|
175604
176167
|
};
|
|
175605
|
-
|
|
176168
|
+
logger246.info(
|
|
175606
176169
|
`${entityId}: Auto-assigned suctionLevel ${vacuumEntities.suctionLevelEntity}`
|
|
175607
176170
|
);
|
|
175608
176171
|
}
|
|
@@ -175612,7 +176175,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
175612
176175
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
175613
176176
|
mopIntensityEntity: vacuumEntities.mopIntensityEntity
|
|
175614
176177
|
};
|
|
175615
|
-
|
|
176178
|
+
logger246.info(
|
|
175616
176179
|
`${entityId}: Auto-assigned mopIntensity ${vacuumEntities.mopIntensityEntity}`
|
|
175617
176180
|
);
|
|
175618
176181
|
}
|
|
@@ -175622,7 +176185,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
175622
176185
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
175623
176186
|
currentRoomEntity: vacuumEntities.currentRoomEntity
|
|
175624
176187
|
};
|
|
175625
|
-
|
|
176188
|
+
logger246.info(
|
|
175626
176189
|
`${entityId}: Auto-assigned currentRoom ${vacuumEntities.currentRoomEntity}`
|
|
175627
176190
|
);
|
|
175628
176191
|
}
|
|
@@ -175637,7 +176200,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
175637
176200
|
entityId: effectiveMapping?.entityId ?? entityId,
|
|
175638
176201
|
cleanAreaRooms
|
|
175639
176202
|
};
|
|
175640
|
-
|
|
176203
|
+
logger246.info(
|
|
175641
176204
|
`${entityId}: Using ${cleanAreaRooms.length} HA areas via CLEAN_AREA`
|
|
175642
176205
|
);
|
|
175643
176206
|
}
|
|
@@ -175658,7 +176221,7 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
175658
176221
|
rooms: roomsObj
|
|
175659
176222
|
}
|
|
175660
176223
|
};
|
|
175661
|
-
|
|
176224
|
+
logger246.info(
|
|
175662
176225
|
`${entityId}: Auto-detected ${valetudoRooms.length} Valetudo segments`
|
|
175663
176226
|
);
|
|
175664
176227
|
} else {
|
|
@@ -175675,14 +176238,14 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
175675
176238
|
rooms: roomsObj
|
|
175676
176239
|
}
|
|
175677
176240
|
};
|
|
175678
|
-
|
|
176241
|
+
logger246.info(
|
|
175679
176242
|
`${entityId}: Auto-detected ${roborockRooms.length} Roborock rooms`
|
|
175680
176243
|
);
|
|
175681
176244
|
}
|
|
175682
176245
|
}
|
|
175683
176246
|
}
|
|
175684
176247
|
} else {
|
|
175685
|
-
|
|
176248
|
+
logger246.warn(`${entityId}: No device_id, cannot auto-assign battery`);
|
|
175686
176249
|
}
|
|
175687
176250
|
const payload = {
|
|
175688
176251
|
entity_id: entityId,
|
|
@@ -175755,11 +176318,11 @@ var ServerModeVacuumEndpoint = class _ServerModeVacuumEndpoint extends EntityEnd
|
|
|
175755
176318
|
}
|
|
175756
176319
|
if (mappedChanged) {
|
|
175757
176320
|
this.pendingMappedChange = true;
|
|
175758
|
-
|
|
176321
|
+
logger246.debug(
|
|
175759
176322
|
`Mapped entity change detected for ${this.entityId}, forcing update`
|
|
175760
176323
|
);
|
|
175761
176324
|
}
|
|
175762
|
-
|
|
176325
|
+
logger246.debug(
|
|
175763
176326
|
`State update received for ${this.entityId}: state=${state.state}`
|
|
175764
176327
|
);
|
|
175765
176328
|
this.lastState = state;
|
|
@@ -175805,6 +176368,7 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
175805
176368
|
this.client = client;
|
|
175806
176369
|
this.registry = registry2;
|
|
175807
176370
|
this.mappingStorage = mappingStorage;
|
|
176371
|
+
this.identityStorage = identityStorage;
|
|
175808
176372
|
this.dataProvider = dataProvider;
|
|
175809
176373
|
this.log = log;
|
|
175810
176374
|
this.identityResolver = new IdentityResolver(
|
|
@@ -175816,6 +176380,7 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
175816
176380
|
client;
|
|
175817
176381
|
registry;
|
|
175818
176382
|
mappingStorage;
|
|
176383
|
+
identityStorage;
|
|
175819
176384
|
dataProvider;
|
|
175820
176385
|
log;
|
|
175821
176386
|
entityIds = [];
|
|
@@ -175915,6 +176480,17 @@ var ServerModeEndpointManager = class extends Service {
|
|
|
175915
176480
|
this.registry.refresh();
|
|
175916
176481
|
this._failedEntities = [];
|
|
175917
176482
|
this.entityIds = this.registry.entityIds;
|
|
176483
|
+
const fullEntities = this.registry.fullEntities;
|
|
176484
|
+
stampIdentityPresence(
|
|
176485
|
+
this.identityStorage,
|
|
176486
|
+
this.dataProvider.id,
|
|
176487
|
+
buildPresentIdentityKeys(fullEntities)
|
|
176488
|
+
);
|
|
176489
|
+
stampMappingPresence(
|
|
176490
|
+
this.mappingStorage,
|
|
176491
|
+
this.dataProvider.id,
|
|
176492
|
+
buildPresentEntityIds(fullEntities)
|
|
176493
|
+
);
|
|
175918
176494
|
try {
|
|
175919
176495
|
if (this.entityIds.length === 0) {
|
|
175920
176496
|
this.log.warn("Server mode bridge has no entities configured");
|
|
@@ -176324,10 +176900,10 @@ var BridgeEnvironmentFactory = class extends BridgeFactory {
|
|
|
176324
176900
|
// src/core/ioc/app-environment.ts
|
|
176325
176901
|
var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
176326
176902
|
constructor(rootEnv, options) {
|
|
176327
|
-
const
|
|
176903
|
+
const logger248 = rootEnv.get(LoggerService);
|
|
176328
176904
|
super({
|
|
176329
176905
|
id: "App",
|
|
176330
|
-
log:
|
|
176906
|
+
log: logger248.get("AppContainer"),
|
|
176331
176907
|
parent: rootEnv
|
|
176332
176908
|
});
|
|
176333
176909
|
this.options = options;
|
|
@@ -176341,8 +176917,8 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
176341
176917
|
}
|
|
176342
176918
|
construction;
|
|
176343
176919
|
async init() {
|
|
176344
|
-
const
|
|
176345
|
-
this.set(LoggerService,
|
|
176920
|
+
const logger248 = this.get(LoggerService);
|
|
176921
|
+
this.set(LoggerService, logger248);
|
|
176346
176922
|
this.set(AppStorage, new AppStorage(await this.load(StorageService)));
|
|
176347
176923
|
this.set(BridgeStorage, new BridgeStorage(await this.load(AppStorage)));
|
|
176348
176924
|
this.set(
|
|
@@ -176363,7 +176939,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
176363
176939
|
);
|
|
176364
176940
|
this.set(
|
|
176365
176941
|
HomeAssistantClient,
|
|
176366
|
-
new HomeAssistantClient(
|
|
176942
|
+
new HomeAssistantClient(logger248, this.options.homeAssistant)
|
|
176367
176943
|
);
|
|
176368
176944
|
this.set(
|
|
176369
176945
|
HomeAssistantConfig,
|
|
@@ -176371,7 +176947,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
176371
176947
|
);
|
|
176372
176948
|
this.set(
|
|
176373
176949
|
HomeAssistantActions,
|
|
176374
|
-
new HomeAssistantActions(
|
|
176950
|
+
new HomeAssistantActions(logger248, await this.load(HomeAssistantClient))
|
|
176375
176951
|
);
|
|
176376
176952
|
this.set(
|
|
176377
176953
|
HomeAssistantRegistry,
|
|
@@ -176407,7 +176983,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
176407
176983
|
this.set(
|
|
176408
176984
|
WebApi,
|
|
176409
176985
|
new WebApi(
|
|
176410
|
-
|
|
176986
|
+
logger248,
|
|
176411
176987
|
await this.load(BridgeService),
|
|
176412
176988
|
await this.load(HomeAssistantClient),
|
|
176413
176989
|
await this.load(HomeAssistantRegistry),
|
|
@@ -176428,7 +177004,7 @@ var AppEnvironment = class _AppEnvironment extends EnvironmentBase {
|
|
|
176428
177004
|
|
|
176429
177005
|
// src/matter/patches/patch-level-control-tlv.ts
|
|
176430
177006
|
init_esm();
|
|
176431
|
-
var
|
|
177007
|
+
var logger247 = Logger.get("PatchLevelControlTlv");
|
|
176432
177008
|
var optionalFieldModels = /* @__PURE__ */ new WeakSet();
|
|
176433
177009
|
var fieldModelMandatoryGetterPatched = false;
|
|
176434
177010
|
function patchLevelControlTlv() {
|
|
@@ -176484,11 +177060,11 @@ function patchLevelControlTlv() {
|
|
|
176484
177060
|
patched++;
|
|
176485
177061
|
}
|
|
176486
177062
|
if (patched > 0) {
|
|
176487
|
-
|
|
177063
|
+
logger247.info(
|
|
176488
177064
|
`Patched ${patched} LevelControl TLV schema(s): transitionTime is now optional (Google Home compatibility)`
|
|
176489
177065
|
);
|
|
176490
177066
|
} else {
|
|
176491
|
-
|
|
177067
|
+
logger247.warn(
|
|
176492
177068
|
"Failed to patch LevelControl TLV schemas, field definitions not found. Google Home brightness adjustment may not work.",
|
|
176493
177069
|
{
|
|
176494
177070
|
moveToLevel: describeFields(
|