@camstack/addon-provider-homematic 1.2.171 → 1.2.173

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/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.173] - 2026-10-31
11
+
12
+ ### Changed
13
+
14
+ - The CCU connection form explains why WebUI credentials are needed and prefills the username with Admin.
15
+
16
+ ## [1.2.172] - 2026-10-31
17
+
18
+ ### Changed
19
+
20
+ - The CCU network scan now finds a CCU that answers the probe with a JSON-RPC error, a WebUI username alone (empty password) now unlocks device names, and a missing-names warning is logged.
21
+
10
22
  ## [1.2.171] - 2026-10-31
11
23
 
12
24
  ### Changed
package/dist/addon.js CHANGED
@@ -117874,7 +117874,7 @@ var homematicConfigSchema = object({
117874
117874
  enableBidcosRf: boolean().default(false).describe("Enable Homematic (BidCos-RF)"),
117875
117875
  enableGroups: boolean().default(true).describe("Enable groups (heating groups / VirtualDevices)"),
117876
117876
  enableBidcosWired: boolean().default(false).describe("Enable BidCos-Wired (HM-Wired)"),
117877
- username: string().default("").describe("WebUI username (optional — enables names / rooms / sysvars)"),
117877
+ username: string().default("Admin").describe("WebUI username (optional — enables names / rooms / sysvars)"),
117878
117878
  password: string().default("").describe("WebUI password (optional)").meta({ secret: true }),
117879
117879
  callbackHost: string().default("").describe("Address the CCU calls back to for event push (this hub LAN IP)"),
117880
117880
  callbackPort: preprocess((v) => v === "" || v === null ? void 0 : v, number().int().min(1).max(65535).default(2128)).describe("Local XML-RPC callback server port"),
@@ -117895,11 +117895,12 @@ function enabledInterfaces(config) {
117895
117895
  /**
117896
117896
  * Build the `HomematicOptions` the wrapped library constructor expects
117897
117897
  * from the validated addon config. Pure: same config in → same options
117898
- * out. Credentials are only forwarded when both fields are non-empty so
117899
- * the library skips the JSON-RPC hub layer cleanly when they're absent.
117898
+ * out. Credentials are forwarded when a username is set (the password may be
117899
+ * empty on a CCU without WebUI authentication); without one the library skips
117900
+ * the JSON-RPC hub layer cleanly.
117900
117901
  */
117901
117902
  function toHomematicOptions(config) {
117902
- const hasCredentials = config.username.length > 0 && config.password.length > 0;
117903
+ const hasCredentials = config.username.length > 0;
117903
117904
  const callbackHost = config.callbackHost.length > 0 ? config.callbackHost : inferCallbackHost(config.host) ?? "";
117904
117905
  const interfaces = enabledInterfaces(config);
117905
117906
  return {
@@ -117946,6 +117947,8 @@ var homematicGatewayDeviceSchema = object({
117946
117947
  /** The adoption candidate id the device was adopted from. */
117947
117948
  nativeId: string().min(1)
117948
117949
  });
117950
+ /** Why the form asks for credentials; shown first (translated through its `labelKey`). */
117951
+ var CREDENTIALS_NOTICE = "Device and room names come from the CCU WebUI. Enter a WebUI user (Admin by default). If the WebUI has no login, leave the password empty. Without a user, devices are listed by their address.";
117949
117952
  /**
117950
117953
  * The integration form: a discovered-CCU picker (filled by the LAN scan), the
117951
117954
  * host, the interfaces, the event callback, the WebUI credentials (the password
@@ -117958,31 +117961,41 @@ function buildConnectionFormSchema() {
117958
117961
  title: "CCU connection",
117959
117962
  titleKey: "provider-homematic:connection.s_connection.title",
117960
117963
  columns: 1,
117961
- fields: [{
117962
- type: "addon-action-select",
117963
- addonId: "provider-homematic",
117964
- key: "__homematic-discovered",
117965
- writesKey: "host",
117966
- omitFromSettings: true,
117967
- label: "CCU",
117968
- labelKey: "provider-homematic:connection.s_connection.__homematic-discovered.label",
117969
- action: "discoverCcu",
117970
- mapOption: {
117971
- value: "host",
117972
- label: "name"
117964
+ fields: [
117965
+ {
117966
+ type: "info",
117967
+ key: "credentialsNotice",
117968
+ label: CREDENTIALS_NOTICE,
117969
+ labelKey: "provider-homematic:connection.s_connection.credentialsNotice.label",
117970
+ content: ""
117973
117971
  },
117974
- hideWhenFewerThan: 2,
117975
- emptyResultsMessage: "No CCU found on the network."
117976
- }, {
117977
- type: "text",
117978
- key: "host",
117979
- label: "Host / IP",
117980
- labelKey: "provider-homematic:connection.s_connection.host.label",
117981
- description: "Filled when one CCU is found. Type the address if it is not.",
117982
- descriptionKey: "provider-homematic:connection.s_connection.host.description",
117983
- required: true,
117984
- placeholder: "192.168.10.50"
117985
- }]
117972
+ {
117973
+ type: "addon-action-select",
117974
+ addonId: "provider-homematic",
117975
+ key: "__homematic-discovered",
117976
+ writesKey: "host",
117977
+ omitFromSettings: true,
117978
+ label: "CCU",
117979
+ labelKey: "provider-homematic:connection.s_connection.__homematic-discovered.label",
117980
+ action: "discoverCcu",
117981
+ mapOption: {
117982
+ value: "host",
117983
+ label: "name"
117984
+ },
117985
+ hideWhenFewerThan: 2,
117986
+ emptyResultsMessage: "No CCU found on the network."
117987
+ },
117988
+ {
117989
+ type: "text",
117990
+ key: "host",
117991
+ label: "Host / IP",
117992
+ labelKey: "provider-homematic:connection.s_connection.host.label",
117993
+ description: "Filled when one CCU is found. Type the address if it is not.",
117994
+ descriptionKey: "provider-homematic:connection.s_connection.host.description",
117995
+ required: true,
117996
+ placeholder: "192.168.10.50"
117997
+ }
117998
+ ]
117986
117999
  },
117987
118000
  {
117988
118001
  id: "interfaces",
@@ -118056,7 +118069,8 @@ function buildConnectionFormSchema() {
118056
118069
  type: "text",
118057
118070
  key: "username",
118058
118071
  label: "Username",
118059
- labelKey: "provider-homematic:connection.s_credentials.username.label"
118072
+ labelKey: "provider-homematic:connection.s_credentials.username.label",
118073
+ default: "Admin"
118060
118074
  }, {
118061
118075
  type: "password",
118062
118076
  key: "password",
@@ -120780,6 +120794,10 @@ var HOMEMATIC_DISCOVERY_MODES = [{
120780
120794
  tls: false,
120781
120795
  acceptStatus: [200]
120782
120796
  }];
120797
+ /** A JSON-RPC reply: it echoes `version` or `id`, and carries a `result` and an `error` member. */
120798
+ function isJsonRpcEnvelope(parsed) {
120799
+ return (Reflect.has(parsed, "version") || Reflect.has(parsed, "id")) && Reflect.has(parsed, "result") && Reflect.has(parsed, "error");
120800
+ }
120783
120801
  /**
120784
120802
  * Read the answer of `CCU.getAuthEnabled`, the question the WebUI asks before
120785
120803
  * it shows a login. A CCU answers a boolean; one that already requires a login
@@ -120799,7 +120817,7 @@ function parseAuthEnabledAnswer(status, text) {
120799
120817
  if (typeof error !== "object") return null;
120800
120818
  const message = Reflect.get(error, "message");
120801
120819
  const code = Reflect.get(error, "code");
120802
- return typeof message === "string" && message.toLowerCase().startsWith("access denied") || code === 401 || code === -32001 ? { authEnabled: true } : null;
120820
+ return typeof message === "string" && message.toLowerCase().startsWith("access denied") || code === 401 || code === -32001 || isJsonRpcEnvelope(parsed) ? { authEnabled: true } : null;
120803
120821
  }
120804
120822
  const result = Reflect.get(parsed, "result");
120805
120823
  if (result === true || result === "true") return { authEnabled: true };
@@ -120910,6 +120928,7 @@ var HmIntegrationManager = class {
120910
120928
  #facade = null;
120911
120929
  #status = "disconnected";
120912
120930
  #deviceCount = 0;
120931
+ #namesAvailable = true;
120913
120932
  #lastCheckedAt = null;
120914
120933
  #error = null;
120915
120934
  /** Active event-listener disposers, cleared on stop. */
@@ -120960,7 +120979,8 @@ var HmIntegrationManager = class {
120960
120979
  info: {
120961
120980
  host: this.#connection.host,
120962
120981
  tls: this.#connection.tls,
120963
- deviceCount: this.#deviceCount
120982
+ deviceCount: this.#deviceCount,
120983
+ namesAvailable: this.#namesAvailable
120964
120984
  },
120965
120985
  lastCheckedAt: this.#lastCheckedAt,
120966
120986
  error: this.#error
@@ -120983,7 +121003,20 @@ var HmIntegrationManager = class {
120983
121003
  this.#facade = facade;
120984
121004
  this.#attachListeners(facade);
120985
121005
  await facade.start();
120986
- this.#deviceCount = facade.devices().length;
121006
+ const devices = facade.devices();
121007
+ this.#deviceCount = devices.length;
121008
+ this.#namesAvailable = devices.length === 0 || devices.some((d) => (d.name ?? "").length > 0);
121009
+ if (!this.#namesAvailable) {
121010
+ const credentialsSet = this.#connection.username.length > 0;
121011
+ this.#logger.warn("HmIntegrationManager: device names unavailable — devices are listed by address", {
121012
+ tags: { integrationId: this.#id },
121013
+ meta: {
121014
+ devices: devices.length,
121015
+ credentialsSet,
121016
+ hint: credentialsSet ? "WebUI login set but the CCU returned no names; check the username (an empty password is valid on a CCU without WebUI authentication)" : "set a WebUI username (and password if the CCU has one) on the integration"
121017
+ }
121018
+ });
121019
+ }
120987
121020
  this.#lastCheckedAt = Date.now();
120988
121021
  this.#status = "connected";
120989
121022
  this.#error = null;
@@ -121530,10 +121563,6 @@ function buildHomematicConnectionTestProvider(deps) {
121530
121563
  outcome: "rejected",
121531
121564
  error: "Some of the connection settings are not valid."
121532
121565
  };
121533
- if (connection.username.length > 0 !== connection.password.length > 0) return {
121534
- outcome: "rejected",
121535
- error: "Enter both the WebUI username and password, or neither."
121536
- };
121537
121566
  const interfaces = enabledInterfaces(connection);
121538
121567
  if (interfaces.length === 0) return {
121539
121568
  outcome: "rejected",
package/dist/addon.mjs CHANGED
@@ -117875,7 +117875,7 @@ var homematicConfigSchema = object({
117875
117875
  enableBidcosRf: boolean().default(false).describe("Enable Homematic (BidCos-RF)"),
117876
117876
  enableGroups: boolean().default(true).describe("Enable groups (heating groups / VirtualDevices)"),
117877
117877
  enableBidcosWired: boolean().default(false).describe("Enable BidCos-Wired (HM-Wired)"),
117878
- username: string().default("").describe("WebUI username (optional — enables names / rooms / sysvars)"),
117878
+ username: string().default("Admin").describe("WebUI username (optional — enables names / rooms / sysvars)"),
117879
117879
  password: string().default("").describe("WebUI password (optional)").meta({ secret: true }),
117880
117880
  callbackHost: string().default("").describe("Address the CCU calls back to for event push (this hub LAN IP)"),
117881
117881
  callbackPort: preprocess((v) => v === "" || v === null ? void 0 : v, number().int().min(1).max(65535).default(2128)).describe("Local XML-RPC callback server port"),
@@ -117896,11 +117896,12 @@ function enabledInterfaces(config) {
117896
117896
  /**
117897
117897
  * Build the `HomematicOptions` the wrapped library constructor expects
117898
117898
  * from the validated addon config. Pure: same config in → same options
117899
- * out. Credentials are only forwarded when both fields are non-empty so
117900
- * the library skips the JSON-RPC hub layer cleanly when they're absent.
117899
+ * out. Credentials are forwarded when a username is set (the password may be
117900
+ * empty on a CCU without WebUI authentication); without one the library skips
117901
+ * the JSON-RPC hub layer cleanly.
117901
117902
  */
117902
117903
  function toHomematicOptions(config) {
117903
- const hasCredentials = config.username.length > 0 && config.password.length > 0;
117904
+ const hasCredentials = config.username.length > 0;
117904
117905
  const callbackHost = config.callbackHost.length > 0 ? config.callbackHost : inferCallbackHost(config.host) ?? "";
117905
117906
  const interfaces = enabledInterfaces(config);
117906
117907
  return {
@@ -117947,6 +117948,8 @@ var homematicGatewayDeviceSchema = object({
117947
117948
  /** The adoption candidate id the device was adopted from. */
117948
117949
  nativeId: string().min(1)
117949
117950
  });
117951
+ /** Why the form asks for credentials; shown first (translated through its `labelKey`). */
117952
+ var CREDENTIALS_NOTICE = "Device and room names come from the CCU WebUI. Enter a WebUI user (Admin by default). If the WebUI has no login, leave the password empty. Without a user, devices are listed by their address.";
117950
117953
  /**
117951
117954
  * The integration form: a discovered-CCU picker (filled by the LAN scan), the
117952
117955
  * host, the interfaces, the event callback, the WebUI credentials (the password
@@ -117959,31 +117962,41 @@ function buildConnectionFormSchema() {
117959
117962
  title: "CCU connection",
117960
117963
  titleKey: "provider-homematic:connection.s_connection.title",
117961
117964
  columns: 1,
117962
- fields: [{
117963
- type: "addon-action-select",
117964
- addonId: "provider-homematic",
117965
- key: "__homematic-discovered",
117966
- writesKey: "host",
117967
- omitFromSettings: true,
117968
- label: "CCU",
117969
- labelKey: "provider-homematic:connection.s_connection.__homematic-discovered.label",
117970
- action: "discoverCcu",
117971
- mapOption: {
117972
- value: "host",
117973
- label: "name"
117965
+ fields: [
117966
+ {
117967
+ type: "info",
117968
+ key: "credentialsNotice",
117969
+ label: CREDENTIALS_NOTICE,
117970
+ labelKey: "provider-homematic:connection.s_connection.credentialsNotice.label",
117971
+ content: ""
117974
117972
  },
117975
- hideWhenFewerThan: 2,
117976
- emptyResultsMessage: "No CCU found on the network."
117977
- }, {
117978
- type: "text",
117979
- key: "host",
117980
- label: "Host / IP",
117981
- labelKey: "provider-homematic:connection.s_connection.host.label",
117982
- description: "Filled when one CCU is found. Type the address if it is not.",
117983
- descriptionKey: "provider-homematic:connection.s_connection.host.description",
117984
- required: true,
117985
- placeholder: "192.168.10.50"
117986
- }]
117973
+ {
117974
+ type: "addon-action-select",
117975
+ addonId: "provider-homematic",
117976
+ key: "__homematic-discovered",
117977
+ writesKey: "host",
117978
+ omitFromSettings: true,
117979
+ label: "CCU",
117980
+ labelKey: "provider-homematic:connection.s_connection.__homematic-discovered.label",
117981
+ action: "discoverCcu",
117982
+ mapOption: {
117983
+ value: "host",
117984
+ label: "name"
117985
+ },
117986
+ hideWhenFewerThan: 2,
117987
+ emptyResultsMessage: "No CCU found on the network."
117988
+ },
117989
+ {
117990
+ type: "text",
117991
+ key: "host",
117992
+ label: "Host / IP",
117993
+ labelKey: "provider-homematic:connection.s_connection.host.label",
117994
+ description: "Filled when one CCU is found. Type the address if it is not.",
117995
+ descriptionKey: "provider-homematic:connection.s_connection.host.description",
117996
+ required: true,
117997
+ placeholder: "192.168.10.50"
117998
+ }
117999
+ ]
117987
118000
  },
117988
118001
  {
117989
118002
  id: "interfaces",
@@ -118057,7 +118070,8 @@ function buildConnectionFormSchema() {
118057
118070
  type: "text",
118058
118071
  key: "username",
118059
118072
  label: "Username",
118060
- labelKey: "provider-homematic:connection.s_credentials.username.label"
118073
+ labelKey: "provider-homematic:connection.s_credentials.username.label",
118074
+ default: "Admin"
118061
118075
  }, {
118062
118076
  type: "password",
118063
118077
  key: "password",
@@ -120781,6 +120795,10 @@ var HOMEMATIC_DISCOVERY_MODES = [{
120781
120795
  tls: false,
120782
120796
  acceptStatus: [200]
120783
120797
  }];
120798
+ /** A JSON-RPC reply: it echoes `version` or `id`, and carries a `result` and an `error` member. */
120799
+ function isJsonRpcEnvelope(parsed) {
120800
+ return (Reflect.has(parsed, "version") || Reflect.has(parsed, "id")) && Reflect.has(parsed, "result") && Reflect.has(parsed, "error");
120801
+ }
120784
120802
  /**
120785
120803
  * Read the answer of `CCU.getAuthEnabled`, the question the WebUI asks before
120786
120804
  * it shows a login. A CCU answers a boolean; one that already requires a login
@@ -120800,7 +120818,7 @@ function parseAuthEnabledAnswer(status, text) {
120800
120818
  if (typeof error !== "object") return null;
120801
120819
  const message = Reflect.get(error, "message");
120802
120820
  const code = Reflect.get(error, "code");
120803
- return typeof message === "string" && message.toLowerCase().startsWith("access denied") || code === 401 || code === -32001 ? { authEnabled: true } : null;
120821
+ return typeof message === "string" && message.toLowerCase().startsWith("access denied") || code === 401 || code === -32001 || isJsonRpcEnvelope(parsed) ? { authEnabled: true } : null;
120804
120822
  }
120805
120823
  const result = Reflect.get(parsed, "result");
120806
120824
  if (result === true || result === "true") return { authEnabled: true };
@@ -120911,6 +120929,7 @@ var HmIntegrationManager = class {
120911
120929
  #facade = null;
120912
120930
  #status = "disconnected";
120913
120931
  #deviceCount = 0;
120932
+ #namesAvailable = true;
120914
120933
  #lastCheckedAt = null;
120915
120934
  #error = null;
120916
120935
  /** Active event-listener disposers, cleared on stop. */
@@ -120961,7 +120980,8 @@ var HmIntegrationManager = class {
120961
120980
  info: {
120962
120981
  host: this.#connection.host,
120963
120982
  tls: this.#connection.tls,
120964
- deviceCount: this.#deviceCount
120983
+ deviceCount: this.#deviceCount,
120984
+ namesAvailable: this.#namesAvailable
120965
120985
  },
120966
120986
  lastCheckedAt: this.#lastCheckedAt,
120967
120987
  error: this.#error
@@ -120984,7 +121004,20 @@ var HmIntegrationManager = class {
120984
121004
  this.#facade = facade;
120985
121005
  this.#attachListeners(facade);
120986
121006
  await facade.start();
120987
- this.#deviceCount = facade.devices().length;
121007
+ const devices = facade.devices();
121008
+ this.#deviceCount = devices.length;
121009
+ this.#namesAvailable = devices.length === 0 || devices.some((d) => (d.name ?? "").length > 0);
121010
+ if (!this.#namesAvailable) {
121011
+ const credentialsSet = this.#connection.username.length > 0;
121012
+ this.#logger.warn("HmIntegrationManager: device names unavailable — devices are listed by address", {
121013
+ tags: { integrationId: this.#id },
121014
+ meta: {
121015
+ devices: devices.length,
121016
+ credentialsSet,
121017
+ hint: credentialsSet ? "WebUI login set but the CCU returned no names; check the username (an empty password is valid on a CCU without WebUI authentication)" : "set a WebUI username (and password if the CCU has one) on the integration"
121018
+ }
121019
+ });
121020
+ }
120988
121021
  this.#lastCheckedAt = Date.now();
120989
121022
  this.#status = "connected";
120990
121023
  this.#error = null;
@@ -121531,10 +121564,6 @@ function buildHomematicConnectionTestProvider(deps) {
121531
121564
  outcome: "rejected",
121532
121565
  error: "Some of the connection settings are not valid."
121533
121566
  };
121534
- if (connection.username.length > 0 !== connection.password.length > 0) return {
121535
- outcome: "rejected",
121536
- error: "Enter both the WebUI username and password, or neither."
121537
- };
121538
121567
  const interfaces = enabledInterfaces(connection);
121539
121568
  if (interfaces.length === 0) return {
121540
121569
  outcome: "rejected",
package/i18n/en.json CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "connection.s_connection.title": "CCU connection",
3
+ "connection.s_connection.credentialsNotice.label": "Device and room names come from the CCU WebUI. Enter a WebUI user (Admin by default). If the WebUI has no login, leave the password empty. Without a user, devices are listed by their address.",
3
4
  "connection.s_connection.__homematic-discovered.label": "CCU",
4
5
  "connection.s_connection.host.label": "Host / IP",
5
6
  "connection.s_connection.host.description": "Filled when one CCU is found. Type the address if it is not.",
package/i18n/it.json CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "connection.s_connection.title": "Connessione alla CCU",
3
+ "connection.s_connection.credentialsNotice.label": "I nomi di dispositivi e stanze provengono dalla WebUI della CCU. Inserisci un utente della WebUI (Admin per impostazione predefinita). Se la WebUI non richiede login, lascia vuota la password. Senza un utente, i dispositivi vengono elencati per indirizzo.",
3
4
  "connection.s_connection.__homematic-discovered.label": "CCU",
4
5
  "connection.s_connection.host.label": "Host / IP",
5
6
  "connection.s_connection.host.description": "Compilato quando viene trovata una CCU. Digita l'indirizzo se non viene trovata.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homematic",
3
- "version": "1.2.171",
3
+ "version": "1.2.173",
4
4
  "description": "Homematic / HomematicIP (CCU3 / RaspberryMatic) device-provider addon for CamStack — wraps the nodehomematic library",
5
5
  "keywords": [
6
6
  "camstack",