@riddix/hamh 2.1.0-alpha.848 → 2.1.0-alpha.850
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
|
@@ -136608,7 +136608,20 @@ var PluginRegistry = class {
|
|
|
136608
136608
|
}
|
|
136609
136609
|
};
|
|
136610
136610
|
|
|
136611
|
+
// src/plugins/types.ts
|
|
136612
|
+
var SECRET_UNCHANGED = "__unchanged__";
|
|
136613
|
+
|
|
136611
136614
|
// src/api/plugin-api.ts
|
|
136615
|
+
function redactSecrets(config11, schema6) {
|
|
136616
|
+
if (!schema6) return config11;
|
|
136617
|
+
const out = { ...config11 };
|
|
136618
|
+
for (const [key, prop] of Object.entries(schema6.properties)) {
|
|
136619
|
+
if (prop.secret && out[key] != null && out[key] !== "") {
|
|
136620
|
+
out[key] = SECRET_UNCHANGED;
|
|
136621
|
+
}
|
|
136622
|
+
}
|
|
136623
|
+
return out;
|
|
136624
|
+
}
|
|
136612
136625
|
var MAX_UPLOAD_BYTES = 50 * 1024 * 1024;
|
|
136613
136626
|
var BLOCKED_PREFIXES = [
|
|
136614
136627
|
"/bin",
|
|
@@ -136647,7 +136660,10 @@ function pluginApi(bridgeService, storageLocation) {
|
|
|
136647
136660
|
version: meta.version,
|
|
136648
136661
|
source: meta.source,
|
|
136649
136662
|
enabled: meta.enabled,
|
|
136650
|
-
config:
|
|
136663
|
+
config: redactSecrets(
|
|
136664
|
+
meta.config,
|
|
136665
|
+
bridge.getPluginConfigSchema?.(meta.name)
|
|
136666
|
+
),
|
|
136651
136667
|
circuitBreaker: info.circuitBreakers[meta.name],
|
|
136652
136668
|
devices: info.devices.filter((d) => d.pluginName === meta.name).map((d) => ({
|
|
136653
136669
|
id: d.device.id,
|
|
@@ -156746,6 +156762,9 @@ var PluginManager = class {
|
|
|
156746
156762
|
} else if (this.runner.getState(name).failures === 0) {
|
|
156747
156763
|
instance.started = true;
|
|
156748
156764
|
}
|
|
156765
|
+
if (instance.plugin.getCurrentConfig) {
|
|
156766
|
+
instance.metadata.config = instance.plugin.getCurrentConfig();
|
|
156767
|
+
}
|
|
156749
156768
|
}
|
|
156750
156769
|
}
|
|
156751
156770
|
/**
|
|
@@ -156846,6 +156865,17 @@ var PluginManager = class {
|
|
|
156846
156865
|
async updateConfig(pluginName, config11) {
|
|
156847
156866
|
const instance = this.instances.get(pluginName);
|
|
156848
156867
|
if (!instance) return false;
|
|
156868
|
+
config11 = { ...config11 };
|
|
156869
|
+
const schema6 = instance.plugin.getConfigSchema?.();
|
|
156870
|
+
if (schema6) {
|
|
156871
|
+
for (const [key, prop] of Object.entries(schema6.properties)) {
|
|
156872
|
+
if (prop.secret && config11[key] === SECRET_UNCHANGED) {
|
|
156873
|
+
const stored = instance.metadata.config[key];
|
|
156874
|
+
if (stored == null) delete config11[key];
|
|
156875
|
+
else config11[key] = stored;
|
|
156876
|
+
}
|
|
156877
|
+
}
|
|
156878
|
+
}
|
|
156849
156879
|
instance.metadata.config = config11;
|
|
156850
156880
|
this.registry?.updateConfig(pluginName, config11);
|
|
156851
156881
|
if (instance.plugin.onConfigChanged) {
|
|
@@ -161085,7 +161115,7 @@ function thermostatPreInitialize(self) {
|
|
|
161085
161115
|
);
|
|
161086
161116
|
self.state.thermostatRunningState = runningStateAllOff;
|
|
161087
161117
|
if (self.features.autoMode) {
|
|
161088
|
-
self.state.minSetpointDeadBand =
|
|
161118
|
+
self.state.minSetpointDeadBand = 0;
|
|
161089
161119
|
} else {
|
|
161090
161120
|
if (self.state.minSetpointDeadBand !== void 0)
|
|
161091
161121
|
self.state.minSetpointDeadBand = void 0;
|
|
@@ -161782,24 +161812,25 @@ function applyClimateFreezeForKeepModeOnIdle(computed, entity, entityId, keepMod
|
|
|
161782
161812
|
}
|
|
161783
161813
|
return computed;
|
|
161784
161814
|
}
|
|
161815
|
+
function isTemperatureRangeActive(entity) {
|
|
161816
|
+
const hasFeature = testBit(
|
|
161817
|
+
entity.attributes.supported_features ?? 0,
|
|
161818
|
+
ClimateDeviceFeature.TARGET_TEMPERATURE_RANGE
|
|
161819
|
+
);
|
|
161820
|
+
const currentMode = entity.state;
|
|
161821
|
+
const isRangeMode = currentMode === ClimateHvacMode.heat_cool || currentMode === ClimateHvacMode.auto;
|
|
161822
|
+
return hasFeature && isRangeMode;
|
|
161823
|
+
}
|
|
161785
161824
|
var config5 = {
|
|
161786
|
-
|
|
161787
|
-
// In heat or cool mode, HA expects a single "temperature" value.
|
|
161788
|
-
// We must check BOTH the feature flag AND the current HVAC mode.
|
|
161789
|
-
supportsTemperatureRange: (entity) => {
|
|
161790
|
-
const hasFeature = testBit(
|
|
161791
|
-
entity.attributes.supported_features ?? 0,
|
|
161792
|
-
ClimateDeviceFeature.TARGET_TEMPERATURE_RANGE
|
|
161793
|
-
);
|
|
161794
|
-
const currentMode = entity.state;
|
|
161795
|
-
const isRangeMode = currentMode === ClimateHvacMode.heat_cool || currentMode === ClimateHvacMode.auto;
|
|
161796
|
-
return hasFeature && isRangeMode;
|
|
161797
|
-
},
|
|
161825
|
+
supportsTemperatureRange: isTemperatureRangeActive,
|
|
161798
161826
|
getMinTemperature: (entity, agent) => getTemp(agent, entity, "min_temp"),
|
|
161799
161827
|
getMaxTemperature: (entity, agent) => getTemp(agent, entity, "max_temp"),
|
|
161800
161828
|
getCurrentTemperature: (entity, agent) => getTemp(agent, entity, "current_temperature"),
|
|
161801
|
-
|
|
161802
|
-
|
|
161829
|
+
// Outside range mode the range attributes are stale: an integration can park
|
|
161830
|
+
// target_temp_low/high while the mode it actually runs on is "temperature".
|
|
161831
|
+
// Reading them then reports the parked value as the setpoint (#435).
|
|
161832
|
+
getTargetHeatingTemperature: (entity, agent) => isTemperatureRangeActive(entity) ? getTemp(agent, entity, "target_temp_low") ?? getTemp(agent, entity, "target_temperature") ?? getTemp(agent, entity, "temperature") : getTemp(agent, entity, "temperature") ?? getTemp(agent, entity, "target_temperature") ?? getTemp(agent, entity, "target_temp_low"),
|
|
161833
|
+
getTargetCoolingTemperature: (entity, agent) => isTemperatureRangeActive(entity) ? getTemp(agent, entity, "target_temp_high") ?? getTemp(agent, entity, "target_temperature") ?? getTemp(agent, entity, "temperature") : getTemp(agent, entity, "temperature") ?? getTemp(agent, entity, "target_temperature") ?? getTemp(agent, entity, "target_temp_high"),
|
|
161803
161834
|
getSystemMode: (entity, agent) => {
|
|
161804
161835
|
const homeAssistant = agent.get(HomeAssistantEntityBehavior);
|
|
161805
161836
|
const computed = computeSystemMode(entity, agent);
|
|
@@ -161991,13 +162022,16 @@ function ClimateDevice(homeAssistantEntity, includeBasicInformation = true) {
|
|
|
161991
162022
|
const rawMaxLimit = toMatterTemp(attributes9.max_temp) ?? 5e3;
|
|
161992
162023
|
const minLimit = Math.min(rawMinLimit, rawMaxLimit);
|
|
161993
162024
|
const maxLimit = Math.max(rawMinLimit, rawMaxLimit);
|
|
162025
|
+
const rangeActive = isTemperatureRangeActive(
|
|
162026
|
+
homeAssistantEntity.entity.state
|
|
162027
|
+
);
|
|
161994
162028
|
const initialState = {
|
|
161995
162029
|
// Pass actual current_temperature for initial state.
|
|
161996
162030
|
// If unavailable (null/undefined), update() will fall back to the
|
|
161997
162031
|
// target setpoint so controllers don't display 0°C.
|
|
161998
162032
|
localTemperature: toMatterTemp(attributes9.current_temperature),
|
|
161999
|
-
occupiedHeatingSetpoint: toMatterTemp(attributes9.target_temp_low) ?? toMatterTemp(attributes9.temperature) ?? 2e3,
|
|
162000
|
-
occupiedCoolingSetpoint: toMatterTemp(attributes9.target_temp_high) ?? toMatterTemp(attributes9.temperature) ?? 2400,
|
|
162033
|
+
occupiedHeatingSetpoint: rangeActive ? toMatterTemp(attributes9.target_temp_low) ?? toMatterTemp(attributes9.temperature) ?? 2e3 : toMatterTemp(attributes9.temperature) ?? toMatterTemp(attributes9.target_temp_low) ?? 2e3,
|
|
162034
|
+
occupiedCoolingSetpoint: rangeActive ? toMatterTemp(attributes9.target_temp_high) ?? toMatterTemp(attributes9.temperature) ?? 2400 : toMatterTemp(attributes9.temperature) ?? toMatterTemp(attributes9.target_temp_high) ?? 2400,
|
|
162001
162035
|
// Use HA's actual min/max limits, fall back to wide range (0-50°C) if not
|
|
162002
162036
|
// provided. Ordered above so min <= max always holds.
|
|
162003
162037
|
minHeatSetpointLimit: minLimit,
|
|
@@ -173985,6 +174019,9 @@ var CameraPlugin = class {
|
|
|
173985
174019
|
async onShutdown() {
|
|
173986
174020
|
await this.teardown();
|
|
173987
174021
|
}
|
|
174022
|
+
getCurrentConfig() {
|
|
174023
|
+
return { ...this.config };
|
|
174024
|
+
}
|
|
173988
174025
|
getConfigSchema() {
|
|
173989
174026
|
return {
|
|
173990
174027
|
title: "Camera",
|
|
@@ -174000,7 +174037,8 @@ var CameraPlugin = class {
|
|
|
174000
174037
|
type: "string",
|
|
174001
174038
|
title: "Long-lived access token",
|
|
174002
174039
|
description: "Leave empty to use the bridge's Home Assistant connection.",
|
|
174003
|
-
required: false
|
|
174040
|
+
required: false,
|
|
174041
|
+
secret: true
|
|
174004
174042
|
},
|
|
174005
174043
|
cameras: {
|
|
174006
174044
|
type: "string",
|
|
@@ -174243,7 +174281,7 @@ var EntityIsolationServiceImpl = class {
|
|
|
174243
174281
|
* Returns: { bridgeId: "ed5b4f8d...", entityName: "Küchenlicht" }
|
|
174244
174282
|
*/
|
|
174245
174283
|
parseEndpointPath(errorMessage) {
|
|
174246
|
-
const match = errorMessage.match(/([a-f0-9]{32})\.aggregator\.([
|
|
174284
|
+
const match = errorMessage.match(/([a-f0-9]{32})\.aggregator\.([^.\s>]+)/i);
|
|
174247
174285
|
if (match) {
|
|
174248
174286
|
return {
|
|
174249
174287
|
bridgeId: match[1],
|
|
@@ -174271,6 +174309,9 @@ var EntityIsolationServiceImpl = class {
|
|
|
174271
174309
|
if (msg.includes("Endpoint storage inaccessible")) {
|
|
174272
174310
|
return "Endpoint storage inaccessible";
|
|
174273
174311
|
}
|
|
174312
|
+
if (msg.includes("Error initializing part")) {
|
|
174313
|
+
return "Endpoint construction failure";
|
|
174314
|
+
}
|
|
174274
174315
|
if (msg.includes("aggregator.")) {
|
|
174275
174316
|
return "Runtime error in endpoint";
|
|
174276
174317
|
}
|
|
@@ -177900,7 +177941,7 @@ function formatPatchError(action, error) {
|
|
|
177900
177941
|
return `${action}:${error instanceof Error ? error.message : String(error)}`;
|
|
177901
177942
|
}
|
|
177902
177943
|
|
|
177903
|
-
// src/commands/start/start-
|
|
177944
|
+
// src/commands/start/start-error-matchers.ts
|
|
177904
177945
|
function extractErrorMessage(error) {
|
|
177905
177946
|
if (error instanceof Error) return error.message;
|
|
177906
177947
|
if (typeof error === "object" && error !== null) {
|
|
@@ -177913,14 +177954,17 @@ function extractErrorMessage(error) {
|
|
|
177913
177954
|
}
|
|
177914
177955
|
return String(error);
|
|
177915
177956
|
}
|
|
177957
|
+
var AGGREGATOR_PATH_RE = /[0-9a-f]{32}\.aggregator\b/i;
|
|
177916
177958
|
function shouldSuppressError(error) {
|
|
177917
177959
|
const msg = extractErrorMessage(error);
|
|
177918
|
-
return msg.includes("Connection lost") || msg.includes("Endpoint storage inaccessible") || msg.includes("Invalid intervalMs") || msg.includes("generalDiagnostics") || msg.includes("Behaviors have errors") || msg.includes("TransactionDestroyedError") || msg.includes("DestroyedDependencyError") || msg.includes("UninitializedDependencyError") || msg.includes("mutex-closed") || msg.includes("not a node and is not owned") || msg.includes("aggregator.");
|
|
177960
|
+
return msg.includes("Connection lost") || msg.includes("Endpoint storage inaccessible") || msg.includes("Invalid intervalMs") || msg.includes("generalDiagnostics") || msg.includes("Behaviors have errors") || msg.includes("TransactionDestroyedError") || msg.includes("DestroyedDependencyError") || msg.includes("UninitializedDependencyError") || msg.includes("mutex-closed") || msg.includes("not a node and is not owned") || msg.includes("aggregator.") || AGGREGATOR_PATH_RE.test(msg);
|
|
177919
177961
|
}
|
|
177920
177962
|
function isIsolatableError(error) {
|
|
177921
177963
|
const msg = error instanceof Error ? error.message : String(error);
|
|
177922
|
-
return msg.includes("Invalid intervalMs") || msg.includes("Behaviors have errors") || msg.includes("TransactionDestroyedError") || msg.includes("DestroyedDependencyError") || msg.includes("UninitializedDependencyError") || msg.includes("Endpoint storage inaccessible") || msg.includes("aggregator.");
|
|
177964
|
+
return msg.includes("Invalid intervalMs") || msg.includes("Behaviors have errors") || msg.includes("TransactionDestroyedError") || msg.includes("DestroyedDependencyError") || msg.includes("UninitializedDependencyError") || msg.includes("Endpoint storage inaccessible") || msg.includes("aggregator.") || AGGREGATOR_PATH_RE.test(msg);
|
|
177923
177965
|
}
|
|
177966
|
+
|
|
177967
|
+
// src/commands/start/start-handler.ts
|
|
177924
177968
|
process.on("uncaughtException", (error) => {
|
|
177925
177969
|
if (shouldSuppressError(error)) {
|
|
177926
177970
|
return;
|