@riddix/hamh 2.1.0-alpha.753 → 2.1.0-alpha.755
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
|
@@ -127033,6 +127033,7 @@ function entityMappingApi(mappingStorage) {
|
|
|
127033
127033
|
humidityEntity: body.humidityEntity,
|
|
127034
127034
|
pressureEntity: body.pressureEntity,
|
|
127035
127035
|
batteryEntity: body.batteryEntity,
|
|
127036
|
+
chargingStateEntity: body.chargingStateEntity,
|
|
127036
127037
|
roomEntities: body.roomEntities,
|
|
127037
127038
|
disableLockPin: body.disableLockPin,
|
|
127038
127039
|
powerEntity: body.powerEntity,
|
|
@@ -131671,6 +131672,7 @@ var EntityMappingStorage = class extends Service {
|
|
|
131671
131672
|
temperatureEntity: request.temperatureEntity?.trim() || void 0,
|
|
131672
131673
|
humidityEntity: request.humidityEntity?.trim() || void 0,
|
|
131673
131674
|
batteryEntity: request.batteryEntity?.trim() || void 0,
|
|
131675
|
+
chargingStateEntity: request.chargingStateEntity?.trim() || void 0,
|
|
131674
131676
|
roomEntities: roomEntities.length > 0 ? roomEntities : void 0,
|
|
131675
131677
|
disableLockPin: request.disableLockPin || void 0,
|
|
131676
131678
|
powerEntity: request.powerEntity?.trim() || void 0,
|
|
@@ -131697,7 +131699,7 @@ var EntityMappingStorage = class extends Service {
|
|
|
131697
131699
|
climateAutoMode: request.climateAutoMode || void 0,
|
|
131698
131700
|
composedEntities: request.composedEntities?.filter((e) => e.entityId?.trim()) ?? void 0
|
|
131699
131701
|
};
|
|
131700
|
-
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.roomEntities && !config11.disableLockPin && !config11.powerEntity && !config11.energyEntity && !config11.pressureEntity && !config11.suctionLevelEntity && !config11.mopIntensityEntity && (!config11.customServiceAreas || config11.customServiceAreas.length === 0) && (!config11.customFanSpeedTags || Object.keys(config11.customFanSpeedTags).length === 0) && !config11.currentRoomEntity && !config11.cleanedAreaEntity && !config11.disableCustomAreaRoomModes && !config11.valetudoIdentifier && !config11.coverSwapOpenClose && !config11.coverExposeAsDimmableLight && !config11.coverSliderDebounceMs && !config11.updateThrottleMs && !config11.disableClimateOnOff && !config11.disableClimateFanControl && !config11.climateKeepModeOnIdle && !config11.climateExposeFan && !config11.climateAutoMode && (!config11.composedEntities || config11.composedEntities.length === 0)) {
|
|
131702
|
+
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.chargingStateEntity && !config11.roomEntities && !config11.disableLockPin && !config11.powerEntity && !config11.energyEntity && !config11.pressureEntity && !config11.suctionLevelEntity && !config11.mopIntensityEntity && (!config11.customServiceAreas || config11.customServiceAreas.length === 0) && (!config11.customFanSpeedTags || Object.keys(config11.customFanSpeedTags).length === 0) && !config11.currentRoomEntity && !config11.cleanedAreaEntity && !config11.disableCustomAreaRoomModes && !config11.valetudoIdentifier && !config11.coverSwapOpenClose && !config11.coverExposeAsDimmableLight && !config11.coverSliderDebounceMs && !config11.updateThrottleMs && !config11.disableClimateOnOff && !config11.disableClimateFanControl && !config11.climateKeepModeOnIdle && !config11.climateExposeFan && !config11.climateAutoMode && (!config11.composedEntities || config11.composedEntities.length === 0)) {
|
|
131701
131703
|
bridgeMap.delete(request.entityId);
|
|
131702
131704
|
} else {
|
|
131703
131705
|
bridgeMap.set(request.entityId, config11);
|
|
@@ -148434,6 +148436,7 @@ function seedExistingSessionStarts(startedAt, sessions, now = Date.now()) {
|
|
|
148434
148436
|
// src/services/bridges/bridge.ts
|
|
148435
148437
|
var AUTO_FORCE_SYNC_INTERVAL_MS = 9e4;
|
|
148436
148438
|
var DEAD_SESSION_TIMEOUT_MS = 6e4;
|
|
148439
|
+
var SHUTDOWN_SESSION_CLOSE_TIMEOUT_MS = 2500;
|
|
148437
148440
|
var Bridge = class {
|
|
148438
148441
|
constructor(env, logger234, dataProvider, endpointManager) {
|
|
148439
148442
|
this.dataProvider = dataProvider;
|
|
@@ -148683,6 +148686,7 @@ ${e?.toString()}`);
|
|
|
148683
148686
|
async runStop(code, reason) {
|
|
148684
148687
|
this.unwireSessionDiagnostics();
|
|
148685
148688
|
this.stopAutoForceSync();
|
|
148689
|
+
await this.closeActiveSessions();
|
|
148686
148690
|
await this.endpointManager.stopPlugins();
|
|
148687
148691
|
this.endpointManager.stopObserving();
|
|
148688
148692
|
try {
|
|
@@ -148713,6 +148717,7 @@ ${e?.toString()}`);
|
|
|
148713
148717
|
this.log.info(`Force sync: every ${AUTO_FORCE_SYNC_INTERVAL_MS / 1e3}s`);
|
|
148714
148718
|
}
|
|
148715
148719
|
wireSessionDiagnostics() {
|
|
148720
|
+
this.unwireSessionDiagnostics();
|
|
148716
148721
|
try {
|
|
148717
148722
|
const sessionManager = this.server.env.get(SessionManager);
|
|
148718
148723
|
seedExistingSessionStarts(this.sessionStartedAt, sessionManager.sessions);
|
|
@@ -148868,6 +148873,42 @@ ${e?.toString()}`);
|
|
|
148868
148873
|
} catch {
|
|
148869
148874
|
}
|
|
148870
148875
|
}
|
|
148876
|
+
// Close every active session on shutdown so each controller is told to drop
|
|
148877
|
+
// its CASE session instead of being left with a stale one. Mirrors the
|
|
148878
|
+
// dead-session close, but covers all sessions and waits (capped) so the
|
|
148879
|
+
// close actually reaches the peer before the server is canceled.
|
|
148880
|
+
async closeActiveSessions() {
|
|
148881
|
+
try {
|
|
148882
|
+
const sessionManager = this.server.env.get(SessionManager);
|
|
148883
|
+
const closes = [];
|
|
148884
|
+
for (const s of [...sessionManager.sessions]) {
|
|
148885
|
+
if (s.isClosing) {
|
|
148886
|
+
continue;
|
|
148887
|
+
}
|
|
148888
|
+
closes.push(
|
|
148889
|
+
s.initiateClose().catch(() => {
|
|
148890
|
+
return s.initiateForceClose({
|
|
148891
|
+
cause: new Error("graceful close failed, forcing")
|
|
148892
|
+
});
|
|
148893
|
+
})
|
|
148894
|
+
);
|
|
148895
|
+
}
|
|
148896
|
+
if (closes.length === 0) {
|
|
148897
|
+
return;
|
|
148898
|
+
}
|
|
148899
|
+
this.log.info(`Closing ${closes.length} active session(s) on shutdown`);
|
|
148900
|
+
let timer;
|
|
148901
|
+
const timeout = new Promise((resolve11) => {
|
|
148902
|
+
timer = setTimeout(resolve11, SHUTDOWN_SESSION_CLOSE_TIMEOUT_MS);
|
|
148903
|
+
});
|
|
148904
|
+
try {
|
|
148905
|
+
await Promise.race([Promise.allSettled(closes), timeout]);
|
|
148906
|
+
} finally {
|
|
148907
|
+
clearTimeout(timer);
|
|
148908
|
+
}
|
|
148909
|
+
} catch {
|
|
148910
|
+
}
|
|
148911
|
+
}
|
|
148871
148912
|
/**
|
|
148872
148913
|
* Force a fresh mDNS operational advertisement after session cleanup.
|
|
148873
148914
|
* matter.js DeviceAdvertiser only re-announces when a subscription is
|
|
@@ -149217,6 +149258,7 @@ function getMappedEntityIds(mapping) {
|
|
|
149217
149258
|
if (!mapping) return [];
|
|
149218
149259
|
const ids = [];
|
|
149219
149260
|
if (mapping.batteryEntity) ids.push(mapping.batteryEntity);
|
|
149261
|
+
if (mapping.chargingStateEntity) ids.push(mapping.chargingStateEntity);
|
|
149220
149262
|
if (mapping.temperatureEntity) ids.push(mapping.temperatureEntity);
|
|
149221
149263
|
if (mapping.humidityEntity) ids.push(mapping.humidityEntity);
|
|
149222
149264
|
if (mapping.pressureEntity) ids.push(mapping.pressureEntity);
|
|
@@ -149749,6 +149791,13 @@ var PowerSourceServerBase = class extends FeaturedBase2 {
|
|
|
149749
149791
|
} else if (isCharging2 === false) {
|
|
149750
149792
|
batChargeState = PowerSource3.BatChargeState.IsNotCharging;
|
|
149751
149793
|
}
|
|
149794
|
+
const explicitChargeState = config11.getChargeState?.(
|
|
149795
|
+
entity.state,
|
|
149796
|
+
this.agent
|
|
149797
|
+
);
|
|
149798
|
+
if (explicitChargeState != null) {
|
|
149799
|
+
batChargeState = explicitChargeState;
|
|
149800
|
+
}
|
|
149752
149801
|
applyPatchState(this.state, {
|
|
149753
149802
|
status: PowerSource3.PowerSourceStatus.Active,
|
|
149754
149803
|
batPercentRemaining,
|
|
@@ -160330,6 +160379,28 @@ function getVacuumBatteryPercent(entity, agent) {
|
|
|
160330
160379
|
const parsed = Number.parseFloat(String(raw));
|
|
160331
160380
|
return Number.isNaN(parsed) ? null : parsed;
|
|
160332
160381
|
}
|
|
160382
|
+
var CHARGING_STRINGS = {
|
|
160383
|
+
charging: "charging",
|
|
160384
|
+
go_charging: "charging",
|
|
160385
|
+
on: "charging",
|
|
160386
|
+
true: "charging",
|
|
160387
|
+
full: "full",
|
|
160388
|
+
not_charging: "not_charging",
|
|
160389
|
+
not_chargeable: "not_charging",
|
|
160390
|
+
discharging: "not_charging",
|
|
160391
|
+
off: "not_charging",
|
|
160392
|
+
false: "not_charging"
|
|
160393
|
+
};
|
|
160394
|
+
function mapChargingString(raw) {
|
|
160395
|
+
return CHARGING_STRINGS[raw.trim().toLowerCase()] ?? null;
|
|
160396
|
+
}
|
|
160397
|
+
function getVacuumChargingState(agent) {
|
|
160398
|
+
const id = agent.get(HomeAssistantEntityBehavior).state.mapping?.chargingStateEntity;
|
|
160399
|
+
if (!id) return null;
|
|
160400
|
+
const state = agent.env.get(EntityStateProvider).getState(id);
|
|
160401
|
+
if (!state) return null;
|
|
160402
|
+
return mapChargingString(state.state);
|
|
160403
|
+
}
|
|
160333
160404
|
|
|
160334
160405
|
// src/matter/endpoints/legacy/vacuum/behaviors/vacuum-power-source-server.ts
|
|
160335
160406
|
var VacuumPowerSourceServer = PowerSourceServer2({
|
|
@@ -160337,6 +160408,14 @@ var VacuumPowerSourceServer = PowerSourceServer2({
|
|
|
160337
160408
|
isCharging(entity) {
|
|
160338
160409
|
const state = entity.state;
|
|
160339
160410
|
return state === VacuumState.docked;
|
|
160411
|
+
},
|
|
160412
|
+
getChargeState(_, agent) {
|
|
160413
|
+
const signal = getVacuumChargingState(agent);
|
|
160414
|
+
if (signal === "charging") return PowerSource3.BatChargeState.IsCharging;
|
|
160415
|
+
if (signal === "full") return PowerSource3.BatChargeState.IsAtFullCharge;
|
|
160416
|
+
if (signal === "not_charging")
|
|
160417
|
+
return PowerSource3.BatChargeState.IsNotCharging;
|
|
160418
|
+
return null;
|
|
160340
160419
|
}
|
|
160341
160420
|
});
|
|
160342
160421
|
|
|
@@ -161086,7 +161165,7 @@ function isDockedCharging(entity, batteryPercent) {
|
|
|
161086
161165
|
if (batteryPercent != null) return batteryPercent < 100;
|
|
161087
161166
|
return isCharging(entity);
|
|
161088
161167
|
}
|
|
161089
|
-
function mapVacuumOperationalState(entity, batteryPercent = batteryFromAttributes(entity.attributes)) {
|
|
161168
|
+
function mapVacuumOperationalState(entity, batteryPercent = batteryFromAttributes(entity.attributes), chargingState = null) {
|
|
161090
161169
|
const state = entity.state;
|
|
161091
161170
|
const cleaningStates = [
|
|
161092
161171
|
VacuumState.cleaning,
|
|
@@ -161097,11 +161176,8 @@ function mapVacuumOperationalState(entity, batteryPercent = batteryFromAttribute
|
|
|
161097
161176
|
];
|
|
161098
161177
|
let operationalState;
|
|
161099
161178
|
if (state === VacuumState.docked) {
|
|
161100
|
-
|
|
161101
|
-
|
|
161102
|
-
} else {
|
|
161103
|
-
operationalState = RvcOperationalState4.OperationalState.Docked;
|
|
161104
|
-
}
|
|
161179
|
+
const charging = chargingState != null ? chargingState === "charging" : isDockedCharging(entity, batteryPercent);
|
|
161180
|
+
operationalState = charging ? RvcOperationalState4.OperationalState.Charging : RvcOperationalState4.OperationalState.Docked;
|
|
161105
161181
|
} else if (state === VacuumState.returning) {
|
|
161106
161182
|
operationalState = RvcOperationalState4.OperationalState.SeekingCharger;
|
|
161107
161183
|
} else if (cleaningStates.includes(state)) {
|
|
@@ -161109,11 +161185,8 @@ function mapVacuumOperationalState(entity, batteryPercent = batteryFromAttribute
|
|
|
161109
161185
|
} else if (state === VacuumState.paused) {
|
|
161110
161186
|
operationalState = RvcOperationalState4.OperationalState.Paused;
|
|
161111
161187
|
} else if (state === VacuumState.idle) {
|
|
161112
|
-
|
|
161113
|
-
|
|
161114
|
-
} else {
|
|
161115
|
-
operationalState = RvcOperationalState4.OperationalState.Stopped;
|
|
161116
|
-
}
|
|
161188
|
+
const charging = chargingState != null ? chargingState === "charging" : isCharging(entity);
|
|
161189
|
+
operationalState = charging ? RvcOperationalState4.OperationalState.Charging : RvcOperationalState4.OperationalState.Stopped;
|
|
161117
161190
|
} else if (state === VacuumState.error || state === "unavailable") {
|
|
161118
161191
|
operationalState = RvcOperationalState4.OperationalState.Error;
|
|
161119
161192
|
} else {
|
|
@@ -161136,7 +161209,8 @@ var VacuumRvcOperationalStateServer = RvcOperationalStateServer2({
|
|
|
161136
161209
|
getOperationalState(entity, agent) {
|
|
161137
161210
|
return mapVacuumOperationalState(
|
|
161138
161211
|
entity,
|
|
161139
|
-
getVacuumBatteryPercent(entity, agent)
|
|
161212
|
+
getVacuumBatteryPercent(entity, agent),
|
|
161213
|
+
getVacuumChargingState(agent)
|
|
161140
161214
|
);
|
|
161141
161215
|
},
|
|
161142
161216
|
pause: (_, agent) => {
|
|
@@ -164306,6 +164380,7 @@ init_dist();
|
|
|
164306
164380
|
init_diagnostic_event_bus();
|
|
164307
164381
|
var AUTO_FORCE_SYNC_INTERVAL_MS2 = 9e4;
|
|
164308
164382
|
var DEAD_SESSION_TIMEOUT_MS2 = 6e4;
|
|
164383
|
+
var SHUTDOWN_SESSION_CLOSE_TIMEOUT_MS2 = 2500;
|
|
164309
164384
|
function makeWarmStartState(state, now = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
164310
164385
|
return { ...state, last_updated: now };
|
|
164311
164386
|
}
|
|
@@ -164469,6 +164544,7 @@ ${e?.toString()}`);
|
|
|
164469
164544
|
this.unwireSessionDiagnostics();
|
|
164470
164545
|
this.cancelWarmStart();
|
|
164471
164546
|
this.stopAutoForceSync();
|
|
164547
|
+
await this.closeActiveSessions();
|
|
164472
164548
|
this.endpointManager.stopObserving();
|
|
164473
164549
|
try {
|
|
164474
164550
|
await this.server.cancel();
|
|
@@ -164538,6 +164614,7 @@ ${e?.toString()}`);
|
|
|
164538
164614
|
this.log.info(`Force sync: every ${AUTO_FORCE_SYNC_INTERVAL_MS2 / 1e3}s`);
|
|
164539
164615
|
}
|
|
164540
164616
|
wireSessionDiagnostics() {
|
|
164617
|
+
this.unwireSessionDiagnostics();
|
|
164541
164618
|
try {
|
|
164542
164619
|
const sessionManager = this.server.env.get(SessionManager);
|
|
164543
164620
|
this.sessionDiagHandler = (session) => {
|
|
@@ -164658,6 +164735,42 @@ ${e?.toString()}`);
|
|
|
164658
164735
|
} catch {
|
|
164659
164736
|
}
|
|
164660
164737
|
}
|
|
164738
|
+
// Close every active session on shutdown so each controller is told to drop
|
|
164739
|
+
// its CASE session instead of being left with a stale one. Mirrors the
|
|
164740
|
+
// dead-session close, but covers all sessions and waits (capped) so the
|
|
164741
|
+
// close actually reaches the peer before the server is canceled.
|
|
164742
|
+
async closeActiveSessions() {
|
|
164743
|
+
try {
|
|
164744
|
+
const sessionManager = this.server.env.get(SessionManager);
|
|
164745
|
+
const closes = [];
|
|
164746
|
+
for (const s of [...sessionManager.sessions]) {
|
|
164747
|
+
if (s.isClosing) {
|
|
164748
|
+
continue;
|
|
164749
|
+
}
|
|
164750
|
+
closes.push(
|
|
164751
|
+
s.initiateClose().catch(() => {
|
|
164752
|
+
return s.initiateForceClose({
|
|
164753
|
+
cause: new Error("graceful close failed, forcing")
|
|
164754
|
+
});
|
|
164755
|
+
})
|
|
164756
|
+
);
|
|
164757
|
+
}
|
|
164758
|
+
if (closes.length === 0) {
|
|
164759
|
+
return;
|
|
164760
|
+
}
|
|
164761
|
+
this.log.info(`Closing ${closes.length} active session(s) on shutdown`);
|
|
164762
|
+
let timer;
|
|
164763
|
+
const timeout = new Promise((resolve11) => {
|
|
164764
|
+
timer = setTimeout(resolve11, SHUTDOWN_SESSION_CLOSE_TIMEOUT_MS2);
|
|
164765
|
+
});
|
|
164766
|
+
try {
|
|
164767
|
+
await Promise.race([Promise.allSettled(closes), timeout]);
|
|
164768
|
+
} finally {
|
|
164769
|
+
clearTimeout(timer);
|
|
164770
|
+
}
|
|
164771
|
+
} catch {
|
|
164772
|
+
}
|
|
164773
|
+
}
|
|
164661
164774
|
/**
|
|
164662
164775
|
* Force a fresh mDNS operational advertisement after session cleanup.
|
|
164663
164776
|
* matter.js DeviceAdvertiser only re-announces when a subscription is
|
|
@@ -165883,6 +165996,14 @@ async function startHandler(startOptions, webUiDist) {
|
|
|
165883
165996
|
if (shuttingDown) return;
|
|
165884
165997
|
shuttingDown = true;
|
|
165885
165998
|
console.log(`Received ${signal}, shutting down gracefully...`);
|
|
165999
|
+
try {
|
|
166000
|
+
await Promise.race([
|
|
166001
|
+
bridgeService.stopAll(),
|
|
166002
|
+
new Promise((resolve11) => setTimeout(resolve11, 1e4))
|
|
166003
|
+
]);
|
|
166004
|
+
} catch (e) {
|
|
166005
|
+
console.warn("Stopping bridges during shutdown failed:", e);
|
|
166006
|
+
}
|
|
165886
166007
|
try {
|
|
165887
166008
|
await Promise.race([
|
|
165888
166009
|
backupService.createAutoBackup(),
|