@camstack/addon-provider-bosch 0.1.46 → 0.1.48

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.
@@ -1,5 +1,5 @@
1
- import { A as RecordIntegrationInstances, B as array, F as entryBody, G as string, H as number, M as customAction, N as defineCustomActions, P as defineEntryKind, R as rowsDepsOver, U as object, V as literal, X as errMsg, Y as DeviceType, Z as EventCategory, _ as heatPumpControlCapability, a as BaseDevice, d as climateControlCapability, i as testBoschInstance, k as waterHeaterCapability, n as boschRowsPorts, o as BaseDeviceProvider, p as deviceAdoptionCapability, r as keepBodyKeys, t as boschRowsMigration, v as heatPumpStatusCapability, x as integrationInstancesCapability, z as _enum } from "../bosch-instances-DkUo6BfT.mjs";
2
- import { a as loginFailureForAttempt, i as createSignInAttemptStore, n as cascadeRemoveDevicesForIntegration, o as parseOAuthCallback, r as buildSignInGuideFields, s as HOMECOM_REDIRECT_URI, t as setIntegrationDevicesOnline } from "../account-integration-offline-BGH1q3tj.mjs";
1
+ import { A as RecordIntegrationInstances, B as array, F as entryBody, G as string, H as number, M as customAction, N as defineCustomActions, P as defineEntryKind, R as rowsDepsOver, U as object, V as literal, X as errMsg, Y as DeviceType, Z as EventCategory, _ as heatPumpControlCapability, a as BaseDevice, d as climateControlCapability, i as testBoschInstance, k as waterHeaterCapability, n as boschRowsPorts, o as BaseDeviceProvider, p as deviceAdoptionCapability, r as keepBodyKeys, t as boschRowsMigration, v as heatPumpStatusCapability, x as integrationInstancesCapability, z as _enum } from "../bosch-instances-t9x1fGVW.mjs";
2
+ import { a as loginFailureForAttempt, i as createSignInAttemptStore, n as cascadeRemoveDevicesForIntegration, o as parseOAuthCallback, r as buildSignInGuideFields, s as HOMECOM_REDIRECT_URI, t as setIntegrationDevicesOnline } from "../account-integration-offline-DLCUxCxS.mjs";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  //#region src/homecom/config.ts
5
5
  var HOMECOM_BRANDS = ["bosch", "buderus"];
@@ -1806,6 +1806,129 @@ function buildHomeComGatewayPersister(deps) {
1806
1806
  return (integrationId, gatewayId) => patch(integrationId, { gatewayId });
1807
1807
  }
1808
1808
  //#endregion
1809
+ //#region src/homecom/homecom-gateway.ts
1810
+ /** Stable id of one HomeCom device. Adoption matches an existing row on this. */
1811
+ function homeComStableId(integrationId, nativeId) {
1812
+ return `homecom:${integrationId}:${nativeId}`;
1813
+ }
1814
+ /** The hot-water child of a heat pump. A boiler's own row keeps its longer name. */
1815
+ var HOMECOM_HOT_WATER_CHILD_NAME = "Hot water";
1816
+ var HomeComConnectionResolver = class {
1817
+ #surfaces = /* @__PURE__ */ new Map();
1818
+ set(integrationId, surface) {
1819
+ if (surface === null) {
1820
+ this.#surfaces.delete(integrationId);
1821
+ return;
1822
+ }
1823
+ this.#surfaces.set(integrationId, surface);
1824
+ }
1825
+ has(integrationId) {
1826
+ return this.#surfaces.has(integrationId);
1827
+ }
1828
+ list() {
1829
+ return Array.from(this.#surfaces.keys()).map((id) => ({ id }));
1830
+ }
1831
+ discoverables(integrationId) {
1832
+ return this.#surfaces.get(integrationId)?.discoverables ?? [];
1833
+ }
1834
+ getClient(integrationId) {
1835
+ return this.#surfaces.get(integrationId)?.client ?? null;
1836
+ }
1837
+ getSnapshot(integrationId) {
1838
+ return this.#surfaces.get(integrationId)?.snapshot ?? null;
1839
+ }
1840
+ updateSnapshot(integrationId, snapshot) {
1841
+ const existing = this.#surfaces.get(integrationId);
1842
+ if (!existing) return;
1843
+ this.#surfaces.set(integrationId, {
1844
+ ...existing,
1845
+ snapshot,
1846
+ discoverables: buildDiscoverables(snapshot)
1847
+ });
1848
+ }
1849
+ clear() {
1850
+ this.#surfaces.clear();
1851
+ }
1852
+ };
1853
+ var BOILER_DHW_NAME = "Domestic hot water";
1854
+ function circuitDiscoverable(circuit) {
1855
+ return {
1856
+ nativeId: `hc:${circuit.id}`,
1857
+ name: circuit.name,
1858
+ kind: "heating-circuit",
1859
+ circuitId: circuit.id
1860
+ };
1861
+ }
1862
+ function dhwDiscoverable(name) {
1863
+ return {
1864
+ nativeId: "dhw:0",
1865
+ name,
1866
+ kind: "dhw"
1867
+ };
1868
+ }
1869
+ /**
1870
+ * A gateway with a heat pump is one pick. A boiler still offers each circuit
1871
+ * and the hot-water row on its own.
1872
+ */
1873
+ function buildDiscoverables(snapshot) {
1874
+ const circuits = snapshot.circuits.map(circuitDiscoverable);
1875
+ if (snapshot.heatPump !== void 0) return [{
1876
+ nativeId: "hp:0",
1877
+ name: "Heat pump",
1878
+ kind: "heat-pump",
1879
+ children: [...circuits, ...snapshot.dhw === null ? [] : [dhwDiscoverable(HOMECOM_HOT_WATER_CHILD_NAME)]]
1880
+ }];
1881
+ return [...circuits, ...snapshot.dhw === null ? [] : [dhwDiscoverable(BOILER_DHW_NAME)]];
1882
+ }
1883
+ var homeComConnections = new HomeComConnectionResolver();
1884
+ //#endregion
1885
+ //#region src/homecom/homecom-adoption-plan.ts
1886
+ function createOf(device, parentNativeId) {
1887
+ return {
1888
+ nativeId: device.nativeId,
1889
+ name: device.name,
1890
+ kind: device.kind,
1891
+ circuitId: device.circuitId,
1892
+ parentNativeId
1893
+ };
1894
+ }
1895
+ /**
1896
+ * The devices one pick creates. A heat pump also creates its children, except
1897
+ * a circuit or hot-water row that already exists: a top-level one is reported
1898
+ * so the caller can log why it stayed there, and any existing row is not
1899
+ * created again.
1900
+ */
1901
+ function planHomeComAdoption(device, integrationId, adopted) {
1902
+ const root = createOf(device, null);
1903
+ if (device.kind !== "heat-pump") return {
1904
+ create: [root],
1905
+ stayedTopLevel: [],
1906
+ alreadyPresent: []
1907
+ };
1908
+ const byStableId = new Map(adopted.map((row) => [row.stableId, row]));
1909
+ const create = [root];
1910
+ const stayedTopLevel = [];
1911
+ const alreadyPresent = [];
1912
+ for (const child of device.children ?? []) {
1913
+ const existing = byStableId.get(homeComStableId(integrationId, child.nativeId));
1914
+ if (existing === void 0) {
1915
+ create.push(createOf(child, device.nativeId));
1916
+ continue;
1917
+ }
1918
+ const skip = {
1919
+ nativeId: child.nativeId,
1920
+ deviceId: existing.id
1921
+ };
1922
+ if (existing.parentDeviceId === null) stayedTopLevel.push(skip);
1923
+ else alreadyPresent.push(skip);
1924
+ }
1925
+ return {
1926
+ create,
1927
+ stayedTopLevel,
1928
+ alreadyPresent
1929
+ };
1930
+ }
1931
+ //#endregion
1809
1932
  //#region src/homecom/homecom-discovery.ts
1810
1933
  function buildHomeComCandidates(input) {
1811
1934
  const out = [];
@@ -1825,6 +1948,9 @@ function buildHomeComCandidates(input) {
1825
1948
  }
1826
1949
  return out;
1827
1950
  }
1951
+ function homeComDeviceType(kind) {
1952
+ return shapeOf(kind).type;
1953
+ }
1828
1954
  function shapeOf(kind) {
1829
1955
  switch (kind) {
1830
1956
  case "heating-circuit": return {
@@ -1848,6 +1974,62 @@ var DEVICES_FILTER = {
1848
1974
  label: "Devices",
1849
1975
  isDefault: true
1850
1976
  };
1977
+ var STAYED_TOP_LEVEL = "HomeCom device stayed top-level: it was already adopted, so it was not created again under the heat pump";
1978
+ var ALREADY_PRESENT = "HomeCom device was not created again: a device with this stable id already exists";
1979
+ async function adoptOne(input) {
1980
+ const { dev, integrationId, name, known, adoptDevice, logger, logOnce } = input;
1981
+ const plan = planHomeComAdoption(dev, integrationId, known);
1982
+ for (const skip of plan.stayedTopLevel) logOnce(skip.deviceId, STAYED_TOP_LEVEL);
1983
+ for (const skip of plan.alreadyPresent) logOnce(skip.deviceId, ALREADY_PRESENT);
1984
+ const root = plan.create[0];
1985
+ if (root === void 0) return { ok: false };
1986
+ let parentDeviceId;
1987
+ try {
1988
+ parentDeviceId = (await adoptDevice({
1989
+ nativeId: root.nativeId,
1990
+ integrationId,
1991
+ type: homeComDeviceType(root.kind),
1992
+ name,
1993
+ kind: root.kind,
1994
+ ...root.circuitId === void 0 ? {} : { circuitId: root.circuitId },
1995
+ parentDeviceId: null
1996
+ })).deviceId;
1997
+ } catch (err) {
1998
+ logger.warn("homecom adopt failed", { meta: {
1999
+ nativeId: root.nativeId,
2000
+ integrationId,
2001
+ error: errMsg(err)
2002
+ } });
2003
+ return { ok: false };
2004
+ }
2005
+ const accessoryDeviceIds = [];
2006
+ for (const child of plan.create.slice(1)) try {
2007
+ const created = await adoptDevice({
2008
+ nativeId: child.nativeId,
2009
+ integrationId,
2010
+ type: homeComDeviceType(child.kind),
2011
+ name: child.name,
2012
+ kind: child.kind,
2013
+ ...child.circuitId === void 0 ? {} : { circuitId: child.circuitId },
2014
+ parentDeviceId
2015
+ });
2016
+ accessoryDeviceIds.push(created.deviceId);
2017
+ } catch (err) {
2018
+ logger.warn("homecom adopt child failed", {
2019
+ tags: { deviceId: parentDeviceId },
2020
+ meta: {
2021
+ nativeId: child.nativeId,
2022
+ integrationId,
2023
+ error: errMsg(err)
2024
+ }
2025
+ });
2026
+ }
2027
+ return {
2028
+ ok: true,
2029
+ parentDeviceId,
2030
+ accessoryDeviceIds
2031
+ };
2032
+ }
1851
2033
  async function adoptedMapForIntegration(integrationId, listAdopted) {
1852
2034
  const all = await listAdopted();
1853
2035
  const map = /* @__PURE__ */ new Map();
@@ -1859,6 +2041,12 @@ async function adoptedMapForIntegration(integrationId, listAdopted) {
1859
2041
  }
1860
2042
  function buildHomeComAdoptionProvider(deps) {
1861
2043
  const { registry, hasIntegration, listIntegrations, listAdopted, adoptDevice, removeDevice, findDeviceConfig, logger } = deps;
2044
+ const logged = /* @__PURE__ */ new Set();
2045
+ const logOnce = (deviceId, message) => {
2046
+ if (logged.has(deviceId)) return;
2047
+ logged.add(deviceId);
2048
+ logger.info(message, { tags: { deviceId } });
2049
+ };
1862
2050
  async function allCandidatesForIntegration(integrationId) {
1863
2051
  return buildHomeComCandidates({
1864
2052
  devices: registry.discoverables(integrationId),
@@ -1913,48 +2101,36 @@ function buildHomeComAdoptionProvider(deps) {
1913
2101
  adopt: async ({ integrationId, childNativeIds, perCandidate }) => {
1914
2102
  if (!registry.has(integrationId)) throw new Error(`homecom adopt: integration ${integrationId} not connected`);
1915
2103
  const devices = registry.discoverables(integrationId);
2104
+ const known = await listAdopted();
1916
2105
  const adopted = [];
1917
2106
  let failures = 0;
1918
- for (const nativeId of childNativeIds) try {
2107
+ for (const nativeId of childNativeIds) {
1919
2108
  const dev = devices.find((d) => d.nativeId === nativeId);
1920
2109
  if (!dev) {
1921
2110
  failures++;
1922
2111
  continue;
1923
2112
  }
1924
- const candidate = buildHomeComCandidates({
1925
- devices: [dev],
1926
- adopted: /* @__PURE__ */ new Map()
1927
- })[0];
1928
- if (!candidate) {
2113
+ const outcome = await adoptOne({
2114
+ dev,
2115
+ integrationId,
2116
+ name: perCandidate?.[nativeId]?.name ?? dev.name,
2117
+ known,
2118
+ adoptDevice,
2119
+ logger,
2120
+ logOnce
2121
+ });
2122
+ if (!outcome.ok) {
1929
2123
  failures++;
1930
2124
  continue;
1931
2125
  }
1932
- const name = perCandidate?.[nativeId]?.name ?? dev.name;
1933
- const { deviceId } = await adoptDevice({
1934
- nativeId,
1935
- integrationId,
1936
- type: candidate.type,
1937
- name,
1938
- kind: dev.kind,
1939
- circuitId: dev.circuitId
1940
- });
1941
2126
  adopted.push({
1942
2127
  childNativeId: nativeId,
1943
- parentDeviceId: deviceId
2128
+ parentDeviceId: outcome.parentDeviceId,
2129
+ accessoryDeviceIds: outcome.accessoryDeviceIds
1944
2130
  });
1945
- } catch (err) {
1946
- logger.warn("homecom adopt failed", { meta: {
1947
- nativeId,
1948
- integrationId,
1949
- error: errMsg(err)
1950
- } });
1951
- failures++;
1952
2131
  }
1953
2132
  if (adopted.length === 0 && failures > 0) throw new Error(`homecom adopt: all ${failures} adopt(s) failed`);
1954
- return { adopted: adopted.map((a) => ({
1955
- ...a,
1956
- accessoryDeviceIds: []
1957
- })) };
2133
+ return { adopted };
1958
2134
  },
1959
2135
  release: async ({ camDeviceId }) => {
1960
2136
  await removeDevice(camDeviceId);
@@ -1974,66 +2150,6 @@ function buildHomeComAdoptionProvider(deps) {
1974
2150
  };
1975
2151
  }
1976
2152
  //#endregion
1977
- //#region src/homecom/homecom-gateway.ts
1978
- var HomeComConnectionResolver = class {
1979
- #surfaces = /* @__PURE__ */ new Map();
1980
- set(integrationId, surface) {
1981
- if (surface === null) {
1982
- this.#surfaces.delete(integrationId);
1983
- return;
1984
- }
1985
- this.#surfaces.set(integrationId, surface);
1986
- }
1987
- has(integrationId) {
1988
- return this.#surfaces.has(integrationId);
1989
- }
1990
- list() {
1991
- return Array.from(this.#surfaces.keys()).map((id) => ({ id }));
1992
- }
1993
- discoverables(integrationId) {
1994
- return this.#surfaces.get(integrationId)?.discoverables ?? [];
1995
- }
1996
- getClient(integrationId) {
1997
- return this.#surfaces.get(integrationId)?.client ?? null;
1998
- }
1999
- getSnapshot(integrationId) {
2000
- return this.#surfaces.get(integrationId)?.snapshot ?? null;
2001
- }
2002
- updateSnapshot(integrationId, snapshot) {
2003
- const existing = this.#surfaces.get(integrationId);
2004
- if (!existing) return;
2005
- this.#surfaces.set(integrationId, {
2006
- ...existing,
2007
- snapshot,
2008
- discoverables: buildDiscoverables(snapshot)
2009
- });
2010
- }
2011
- clear() {
2012
- this.#surfaces.clear();
2013
- }
2014
- };
2015
- function buildDiscoverables(snapshot) {
2016
- const out = [];
2017
- for (const circuit of snapshot.circuits) out.push({
2018
- nativeId: `hc:${circuit.id}`,
2019
- name: circuit.name,
2020
- kind: "heating-circuit",
2021
- circuitId: circuit.id
2022
- });
2023
- if (snapshot.dhw) out.push({
2024
- nativeId: "dhw:0",
2025
- name: "Domestic hot water",
2026
- kind: "dhw"
2027
- });
2028
- if (snapshot.heatPump !== void 0) out.push({
2029
- nativeId: "hp:0",
2030
- name: "Heat pump",
2031
- kind: "heat-pump"
2032
- });
2033
- return out;
2034
- }
2035
- var homeComConnections = new HomeComConnectionResolver();
2036
- //#endregion
2037
2153
  //#region src/homecom/homecom-integration-manager.ts
2038
2154
  var HomeComIntegrationManager = class {
2039
2155
  #id;
@@ -2932,7 +3048,7 @@ var BoschHomeComProviderAddon = class extends BaseDeviceProvider {
2932
3048
  if (typeof integrationId !== "string" || integrationId.length === 0) throw new Error("homecom generateStableId: brokerId required");
2933
3049
  const nativeId = config?.["nativeId"];
2934
3050
  if (typeof nativeId !== "string" || nativeId.length === 0) throw new Error("homecom generateStableId: nativeId required");
2935
- return `homecom:${integrationId}:${nativeId}`;
3051
+ return homeComStableId(integrationId, nativeId);
2936
3052
  }
2937
3053
  async reconcileIntegrations() {
2938
3054
  const reg = this.requireClients();
@@ -2994,12 +3110,14 @@ var BoschHomeComProviderAddon = class extends BaseDeviceProvider {
2994
3110
  const config = await devices.loadConfig(d.id).catch(() => ({}));
2995
3111
  out.push({
2996
3112
  id: d.id,
3113
+ stableId: d.stableId,
3114
+ parentDeviceId: d.parentDeviceId,
2997
3115
  config
2998
3116
  });
2999
3117
  }
3000
3118
  return out;
3001
3119
  },
3002
- adoptDevice: async ({ nativeId, integrationId, type, name, kind, circuitId }) => {
3120
+ adoptDevice: async ({ nativeId, integrationId, type, name, kind, circuitId, parentDeviceId }) => {
3003
3121
  const devices = this.ctx.kernel.devices;
3004
3122
  if (!devices) throw new Error("homecom adopt: devices unavailable");
3005
3123
  const config = {
@@ -3013,7 +3131,7 @@ var BoschHomeComProviderAddon = class extends BaseDeviceProvider {
3013
3131
  const stableId = this.generateStableId(type, config);
3014
3132
  const DeviceClass = this.deviceClasses[type];
3015
3133
  if (!DeviceClass) throw new Error(`homecom adopt: unsupported type ${type}`);
3016
- return { deviceId: (await devices.create(stableId, DeviceClass, config, null, {
3134
+ return { deviceId: (await devices.create(stableId, DeviceClass, config, parentDeviceId, {
3017
3135
  type,
3018
3136
  name,
3019
3137
  integrationId
package/dist/shc/addon.js CHANGED
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region \0rolldown/runtime.js
3
3
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
4
4
  //#endregion
5
- const require_bosch_instances = require("../bosch-instances-BD-Valeo.js");
5
+ const require_bosch_instances = require("../bosch-instances-CRvxRbDk.js");
6
6
  let node_crypto = require("node:crypto");
7
7
  let node_https = require("node:https");
8
8
  let node_child_process = require("node:child_process");
@@ -1,4 +1,4 @@
1
- import { A as RecordIntegrationInstances, B as array, D as switchCapability, F as entryBody, G as string, H as number, M as customAction, N as defineCustomActions, O as temperatureSensorCapability, P as defineEntryKind, R as rowsDepsOver, U as object, V as literal, X as errMsg, Y as DeviceType, Z as EventCategory, a as BaseDevice, d as climateControlCapability, i as testBoschInstance, l as batteryCapability, n as boschRowsPorts, o as BaseDeviceProvider, p as deviceAdoptionCapability, r as keepBodyKeys, t as boschRowsMigration, x as integrationInstancesCapability, y as heatingValveCapability, z as _enum } from "../bosch-instances-DkUo6BfT.mjs";
1
+ import { A as RecordIntegrationInstances, B as array, D as switchCapability, F as entryBody, G as string, H as number, M as customAction, N as defineCustomActions, O as temperatureSensorCapability, P as defineEntryKind, R as rowsDepsOver, U as object, V as literal, X as errMsg, Y as DeviceType, Z as EventCategory, a as BaseDevice, d as climateControlCapability, i as testBoschInstance, l as batteryCapability, n as boschRowsPorts, o as BaseDeviceProvider, p as deviceAdoptionCapability, r as keepBodyKeys, t as boschRowsMigration, x as integrationInstancesCapability, y as heatingValveCapability, z as _enum } from "../bosch-instances-t9x1fGVW.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { request } from "node:https";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-bosch",
3
- "version": "0.1.46",
3
+ "version": "0.1.48",
4
4
  "description": "Bosch smart-home device-provider addons for CamStack — SHC, Home Connect, and HomeCom cloud integrations (scaffold)",
5
5
  "keywords": [
6
6
  "camstack",
@@ -138,7 +138,7 @@
138
138
  }
139
139
  ],
140
140
  "requires": {
141
- "server": ">=1.2.822"
141
+ "server": ">=1.2.827"
142
142
  }
143
143
  },
144
144
  "files": [