@camstack/addon-provider-bosch 0.1.53 → 0.1.54

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,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.54] - 2026-11-12
11
+
12
+ ### Changed
13
+
14
+ - A new Bosch SHC gateway is named "Bosch SHC", and a new HomeCom gateway "Bosch HomeCom" plus its device type.
15
+
10
16
  ## [0.1.53] - 2026-11-12
11
17
 
12
18
  ### Changed
@@ -1,4 +1,4 @@
1
- import { et as errMsg } from "./bosch-instances-y_A00js_.mjs";
1
+ import { nt as errMsg } from "./bosch-instances-DMzZSMxW.mjs";
2
2
  import { randomBytes } from "node:crypto";
3
3
  //#region src/shared/sign-in-redirects.ts
4
4
  /** The addresses each vendor sends the browser to after a sign-in; no browser can open them. Kept free of imports so the form schema can name them. */
@@ -1,4 +1,4 @@
1
- const require_bosch_instances = require("./bosch-instances-dqTG9no9.js");
1
+ const require_bosch_instances = require("./bosch-instances-DkTzZrlR.js");
2
2
  let node_crypto = require("node:crypto");
3
3
  //#region src/shared/sign-in-redirects.ts
4
4
  /** The addresses each vendor sends the browser to after a sign-in; no browser can open them. Kept free of imports so the form schema can name them. */
@@ -44097,6 +44097,51 @@ function macroOnly(macro) {
44097
44097
  };
44098
44098
  }
44099
44099
  }
44100
+ var EventVocabularyKindSchema = _enum([
44101
+ "press",
44102
+ "long-press",
44103
+ "long-press-start",
44104
+ "release",
44105
+ "repeat",
44106
+ "double-press",
44107
+ "other"
44108
+ ]);
44109
+ /** The part of the device an event comes from: a button, a channel. */
44110
+ var EventVocabularySourceSchema = object({
44111
+ id: string().min(1),
44112
+ label: string().min(1)
44113
+ });
44114
+ /** One scalar field of an event's `data`, by dotted path. */
44115
+ var EventVocabularyFieldSchema = object({
44116
+ path: string().min(1),
44117
+ kind: _enum([
44118
+ "string",
44119
+ "number",
44120
+ "boolean",
44121
+ "enum"
44122
+ ]),
44123
+ enumValues: array(string()).optional(),
44124
+ label: string().min(1).optional()
44125
+ });
44126
+ var EventVocabularyEntrySchema = object({
44127
+ /** The native token, verbatim. */
44128
+ id: string().min(1),
44129
+ source: EventVocabularySourceSchema.optional(),
44130
+ label: string().min(1),
44131
+ description: string().optional(),
44132
+ kind: EventVocabularyKindSchema.optional(),
44133
+ payload: array(EventVocabularyFieldSchema).optional()
44134
+ });
44135
+ /**
44136
+ * The vocabulary of a source that declares tokens and nothing else: one
44137
+ * entry per token, labelled with the token itself.
44138
+ */
44139
+ function plainEventVocabulary(eventTypes) {
44140
+ return [...new Set(eventTypes)].filter((eventType) => eventType !== "").map((eventType) => ({
44141
+ id: eventType,
44142
+ label: eventType
44143
+ }));
44144
+ }
44100
44145
  Math.PI / 180;
44101
44146
  /**
44102
44147
  * WHEN something happens, as data (D983) — the one time vocabulary of the
@@ -44304,6 +44349,33 @@ var ScheduleLeafSchema = object({
44304
44349
  /** @deprecated legacy cron — new schedules use `at`. */
44305
44350
  cron: string().min(1).max(120).optional()
44306
44351
  }).refine((leaf) => leaf.at === void 0 !== (leaf.cron === void 0), { message: "a schedule names exactly one of `at` (a time spec) and `cron` (legacy)" }).refine((leaf) => leaf.days === void 0 || leaf.at !== void 0, { message: "`days` goes with `at`; a cron expression carries its own days" });
44352
+ /**
44353
+ * One payload predicate of a `device-fired` row: the value at `path` inside
44354
+ * the fire's `data` (dotted) equals `equals`. Compared strictly, no coercion.
44355
+ */
44356
+ var DeviceFiredMatchSchema = object({
44357
+ path: string().min(1).max(120),
44358
+ equals: union([
44359
+ string(),
44360
+ number$1(),
44361
+ boolean()
44362
+ ])
44363
+ });
44364
+ /**
44365
+ * "fires": one device of the `event-emitter` capability reported an event
44366
+ * (D1045). Every list is an OR, the lists together an AND; an absent list does
44367
+ * not narrow. `eventIds` are the device's own tokens, `sourceIds` the parts of
44368
+ * the device (a button), `kinds` the shared press kinds of its vocabulary.
44369
+ */
44370
+ var DeviceFiredLeafSchema = object({
44371
+ kind: literal("device-fired"),
44372
+ ...eventLeafId,
44373
+ deviceId: number$1().int().nonnegative(),
44374
+ eventIds: array(string().min(1)).min(1).max(64).optional(),
44375
+ sourceIds: array(string().min(1)).min(1).max(64).optional(),
44376
+ kinds: array(EventVocabularyKindSchema).min(1).optional(),
44377
+ match: array(DeviceFiredMatchSchema).min(1).max(8).optional()
44378
+ });
44307
44379
  var ManualLeafSchema = object({
44308
44380
  kind: literal("manual"),
44309
44381
  ...eventLeafId
@@ -44445,6 +44517,7 @@ var AutomationWhenSchema = lazy(() => discriminatedUnion("kind", [
44445
44517
  }),
44446
44518
  DeviceBecomesLeafSchema,
44447
44519
  DeviceEventLeafSchema,
44520
+ DeviceFiredLeafSchema,
44448
44521
  ScheduleLeafSchema,
44449
44522
  ManualLeafSchema,
44450
44523
  IntervalLeafSchema,
@@ -44459,6 +44532,7 @@ var AutomationWhenSchema = lazy(() => discriminatedUnion("kind", [
44459
44532
  var EVENT_KINDS = new Set([
44460
44533
  "device-becomes",
44461
44534
  "device-event",
44535
+ "device-fired",
44462
44536
  "schedule",
44463
44537
  "manual",
44464
44538
  "interval",
@@ -44539,6 +44613,7 @@ function hasEmptyContainer(node) {
44539
44613
  var LEAF_WORDS = {
44540
44614
  "device-becomes": "a device value that becomes",
44541
44615
  "device-event": "a device event",
44616
+ "device-fired": "a device firing an event",
44542
44617
  schedule: "a schedule",
44543
44618
  manual: "a manual run",
44544
44619
  interval: "an interval",
@@ -45182,6 +45257,16 @@ var BECOMES_DESCRIPTIONS = {
45182
45257
  from: "the value before the change, empty when it is not known",
45183
45258
  to: "the value it changed to"
45184
45259
  };
45260
+ /**
45261
+ * A fire's payload is offered too, as `data.<path>` (`{{vars.data.channel}}`):
45262
+ * those names depend on the device, so they are not in this list.
45263
+ */
45264
+ var FIRED_DESCRIPTIONS = {
45265
+ deviceId: "the device that fired",
45266
+ eventType: "the event, as the device names it",
45267
+ sourceId: "the part of the device that fired (a button), empty when it names none",
45268
+ eventKind: "the kind of press (press, long-press …), empty when the device declares none"
45269
+ };
45185
45270
  function describe$1(descriptions) {
45186
45271
  return Object.entries(descriptions).map(([name, description]) => ({
45187
45272
  name,
@@ -45190,12 +45275,74 @@ function describe$1(descriptions) {
45190
45275
  }
45191
45276
  describe$1(DETECTION_DESCRIPTIONS);
45192
45277
  describe$1(STATIONARY_DESCRIPTIONS);
45278
+ describe$1(FIRED_DESCRIPTIONS).map((v) => v.name === "deviceId" ? {
45279
+ ...v,
45280
+ hintKey: "firedDeviceId"
45281
+ } : v);
45193
45282
  describe$1(BECOMES_DESCRIPTIONS).map((v) => v.name === "deviceId" ? {
45194
45283
  ...v,
45195
45284
  hintKey: "becomesDeviceId"
45196
45285
  } : v);
45197
45286
  new Set(Object.values(COCO_TO_MACRO.mapping));
45198
45287
  /**
45288
+ * Generic stateless event emitter. Installed on a `DeviceType.EventEmitter`
45289
+ * device. Carries the device's EXACT declared event vocabulary verbatim
45290
+ * (NO normalization). Two shapes:
45291
+ * - structured source (HA `event.*` entity) → `vocabulary` is the fixed
45292
+ * declared set (e.g. press_short, press_long, …).
45293
+ * - generic/legacy source (HA bus events, e.g. zha_event) → `vocabulary`
45294
+ * is [] (open) and `lastEvent.data` carries the complex payload.
45295
+ * `vocabulary` (D1044) names each event for a person and types it for a
45296
+ * rule; `eventTypes` is its list of native tokens, kept for older readers.
45297
+ * A fire names the part of the device it came from in `sourceId` when the
45298
+ * vocabulary declares sources (a remote's buttons).
45299
+ * `seq` is monotonic so two identical events still produce distinct slice writes.
45300
+ */
45301
+ var EventFireSchema = object({
45302
+ deviceId: number$1(),
45303
+ eventType: string(),
45304
+ sourceId: string().optional(),
45305
+ data: record(string(), unknown()).nullable(),
45306
+ timestamp: number$1().meta(readingMeta("none")),
45307
+ seq: number$1().meta(readingMeta("count"))
45308
+ });
45309
+ var EventEmitterStatusSchema = object({
45310
+ eventTypes: array(string()),
45311
+ /**
45312
+ * Required of a provider by the type. A status written before the field
45313
+ * existed still parses, as an empty vocabulary: read it through
45314
+ * `readEventVocabulary`, which then answers with the plain tokens.
45315
+ */
45316
+ vocabulary: array(EventVocabularyEntrySchema).default([]),
45317
+ lastEvent: EventFireSchema.nullable(),
45318
+ eventCountSinceStart: number$1().meta(readingMeta("count"))
45319
+ });
45320
+ var eventEmitterCapability = {
45321
+ name: "event-emitter",
45322
+ scope: "device",
45323
+ deviceNative: true,
45324
+ mode: "singleton",
45325
+ deviceTypes: [DeviceType.EventEmitter],
45326
+ methods: {},
45327
+ events: { onEvent: { data: EventFireSchema } },
45328
+ status: {
45329
+ schema: EventEmitterStatusSchema,
45330
+ kind: "push"
45331
+ },
45332
+ runtimeState: EventEmitterStatusSchema,
45333
+ /**
45334
+ * Runtime-state durability: **session** — `eventCountSinceStart` names its own scope.
45335
+ *
45336
+ * See `RuntimeStateDurability`. Enforced by
45337
+ * `scripts/check-runtime-state-durability.ts`.
45338
+ */
45339
+ durability: "session",
45340
+ /**
45341
+ * History (D850): none — `eventCountSinceStart` resets with the addon; events live in ledgers.
45342
+ */
45343
+ history: "none"
45344
+ };
45345
+ /**
45199
45346
  * Schedulers (D983) — an entity that performs actions over the day.
45200
45347
  *
45201
45348
  * A scheduler has profiles; a profile has weekdays and a timeline of POINTS.
@@ -45453,6 +45600,7 @@ var AutomationConditionTraceNodeSchema = object({
45453
45600
  "triggered-by",
45454
45601
  "device-becomes",
45455
45602
  "device-event",
45603
+ "device-fired",
45456
45604
  "schedule",
45457
45605
  "interval",
45458
45606
  "manual",
@@ -56661,109 +56809,6 @@ var enumSensorCapability = {
56661
56809
  * whether persisting is worth a SQLite commit. */
56662
56810
  volatileStateFields: ["lastFetchedAt", "timestamp"]
56663
56811
  };
56664
- var EventVocabularyKindSchema = _enum([
56665
- "press",
56666
- "long-press",
56667
- "long-press-start",
56668
- "release",
56669
- "repeat",
56670
- "double-press",
56671
- "other"
56672
- ]);
56673
- /** The part of the device an event comes from: a button, a channel. */
56674
- var EventVocabularySourceSchema = object({
56675
- id: string().min(1),
56676
- label: string().min(1)
56677
- });
56678
- /** One scalar field of an event's `data`, by dotted path. */
56679
- var EventVocabularyFieldSchema = object({
56680
- path: string().min(1),
56681
- kind: _enum([
56682
- "string",
56683
- "number",
56684
- "boolean",
56685
- "enum"
56686
- ]),
56687
- enumValues: array(string()).optional(),
56688
- label: string().min(1).optional()
56689
- });
56690
- var EventVocabularyEntrySchema = object({
56691
- /** The native token, verbatim. */
56692
- id: string().min(1),
56693
- source: EventVocabularySourceSchema.optional(),
56694
- label: string().min(1),
56695
- description: string().optional(),
56696
- kind: EventVocabularyKindSchema.optional(),
56697
- payload: array(EventVocabularyFieldSchema).optional()
56698
- });
56699
- /**
56700
- * The vocabulary of a source that declares tokens and nothing else: one
56701
- * entry per token, labelled with the token itself.
56702
- */
56703
- function plainEventVocabulary(eventTypes) {
56704
- return [...new Set(eventTypes)].filter((eventType) => eventType !== "").map((eventType) => ({
56705
- id: eventType,
56706
- label: eventType
56707
- }));
56708
- }
56709
- /**
56710
- * Generic stateless event emitter. Installed on a `DeviceType.EventEmitter`
56711
- * device. Carries the device's EXACT declared event vocabulary verbatim
56712
- * (NO normalization). Two shapes:
56713
- * - structured source (HA `event.*` entity) → `vocabulary` is the fixed
56714
- * declared set (e.g. press_short, press_long, …).
56715
- * - generic/legacy source (HA bus events, e.g. zha_event) → `vocabulary`
56716
- * is [] (open) and `lastEvent.data` carries the complex payload.
56717
- * `vocabulary` (D1044) names each event for a person and types it for a
56718
- * rule; `eventTypes` is its list of native tokens, kept for older readers.
56719
- * A fire names the part of the device it came from in `sourceId` when the
56720
- * vocabulary declares sources (a remote's buttons).
56721
- * `seq` is monotonic so two identical events still produce distinct slice writes.
56722
- */
56723
- var EventFireSchema = object({
56724
- deviceId: number$1(),
56725
- eventType: string(),
56726
- sourceId: string().optional(),
56727
- data: record(string(), unknown()).nullable(),
56728
- timestamp: number$1().meta(readingMeta("none")),
56729
- seq: number$1().meta(readingMeta("count"))
56730
- });
56731
- var EventEmitterStatusSchema = object({
56732
- eventTypes: array(string()),
56733
- /**
56734
- * Required of a provider by the type. A status written before the field
56735
- * existed still parses, as an empty vocabulary: read it through
56736
- * `readEventVocabulary`, which then answers with the plain tokens.
56737
- */
56738
- vocabulary: array(EventVocabularyEntrySchema).default([]),
56739
- lastEvent: EventFireSchema.nullable(),
56740
- eventCountSinceStart: number$1().meta(readingMeta("count"))
56741
- });
56742
- var eventEmitterCapability = {
56743
- name: "event-emitter",
56744
- scope: "device",
56745
- deviceNative: true,
56746
- mode: "singleton",
56747
- deviceTypes: [DeviceType.EventEmitter],
56748
- methods: {},
56749
- events: { onEvent: { data: EventFireSchema } },
56750
- status: {
56751
- schema: EventEmitterStatusSchema,
56752
- kind: "push"
56753
- },
56754
- runtimeState: EventEmitterStatusSchema,
56755
- /**
56756
- * Runtime-state durability: **session** — `eventCountSinceStart` names its own scope.
56757
- *
56758
- * See `RuntimeStateDurability`. Enforced by
56759
- * `scripts/check-runtime-state-durability.ts`.
56760
- */
56761
- durability: "session",
56762
- /**
56763
- * History (D850): none — `eventCountSinceStart` resets with the addon; events live in ledgers.
56764
- */
56765
- history: "none"
56766
- };
56767
56812
  var IdentitySchema = object({
56768
56813
  id: string(),
56769
56814
  name: string(),
@@ -59366,6 +59411,12 @@ var IntegrationLiteSchema = object({
59366
59411
  var AvailableIntegrationTypeSchema = object({
59367
59412
  addonId: string(),
59368
59413
  name: string(),
59414
+ /**
59415
+ * Product name a new integration is prefilled from (`<label> - Home`).
59416
+ * Absent: the client uses `name`. Set when the catalog title is not the
59417
+ * product (Bosch SHC, MQTT).
59418
+ */
59419
+ providerLabel: string().optional(),
59369
59420
  description: string(),
59370
59421
  iconUrl: string().nullable(),
59371
59422
  color: string(),
@@ -103091,6 +103142,38 @@ function ingestReading(input) {
103091
103142
  value: converted
103092
103143
  };
103093
103144
  }
103145
+ /**
103146
+ * Names chosen when an integration or a Gateway device is created.
103147
+ * A stored name is never rewritten from these helpers.
103148
+ */
103149
+ var HOME_SUFFIX = "Home";
103150
+ function collapse(value) {
103151
+ return value.trim().replace(/\s+/g, " ");
103152
+ }
103153
+ /** "KLF-200" → "KLF200". A hyphen between words ("Home Hub") stays. */
103154
+ function compactModelToken(value) {
103155
+ return value.replace(/([A-Za-z])-(\d)/g, "$1$2");
103156
+ }
103157
+ /** Prefill for a new integration: "<provider> - Home". The operator can edit it. */
103158
+ function defaultIntegrationName(providerLabel) {
103159
+ const label = collapse(providerLabel);
103160
+ if (label.length === 0) return HOME_SUFFIX;
103161
+ return `${label} - ${HOME_SUFFIX}`;
103162
+ }
103163
+ /**
103164
+ * A Gateway device: "<Brand> <Model>". An unknown model is the brand alone
103165
+ * (the caller passes the brand-level fallback it already has, e.g. "Velux KLF-200").
103166
+ */
103167
+ function gatewayDeviceName(brand, model) {
103168
+ const brandPart = compactModelToken(collapse(brand));
103169
+ const raw = collapse(model ?? "");
103170
+ if (raw.length === 0) return brandPart;
103171
+ const modelPart = compactModelToken(raw);
103172
+ const prefix = `${brandPart.toLowerCase()} `;
103173
+ if (modelPart.toLowerCase() === brandPart.toLowerCase()) return brandPart;
103174
+ if (modelPart.toLowerCase().startsWith(prefix)) return modelPart;
103175
+ return `${brandPart} ${modelPart}`;
103176
+ }
103094
103177
  String.raw`(?<=^|["'(\s>,\[{])`;
103095
103178
  var MB = 1024 * 1024;
103096
103179
  1024 * MB, 3072 * MB;
@@ -103199,4 +103282,4 @@ function keepBodyKeys(provider, keys) {
103199
103282
  };
103200
103283
  }
103201
103284
  //#endregion
103202
- export { DeviceType as $, temperatureSensorCapability as A, rowsDepsOver as B, plainEventVocabulary as C, runningFromDishwasherOperation as D, registerPowerSwitch as E, defineCustomActions as F, literal as G, _null as H, defineEntryKind as I, record as J, number$1 as K, entryBody as L, RecordIntegrationInstances as M, createEvent as N, runningStateCapability as O, customAction as P, DeviceRole as Q, isSecretMarker as R, numericSensorCapability as S, quantityFromUnit as T, array as U, _enum as V, boolean as W, union as X, string as Y, unknown as Z, heatPumpControlCapability as _, BaseDevice as a, ingestReading as b, RUNNING_STATE_COLD as c, climateControlCapability as d, errMsg as et, consumablesCapability as f, eventEmitterCapability as g, enumSensorCapability as h, testBoschInstance as i, waterHeaterCapability as j, switchCapability as k, batteryCapability as l, dishwasherCapability as m, boschRowsPorts as n, BaseDeviceProvider as o, deviceAdoptionCapability as p, object as q, keepBodyKeys as r, DishwasherOperationStateSchema as s, boschRowsMigration as t, EventCategory as tt, binaryCapability as u, heatPumpStatusCapability as v, powerMeterCapability as w, integrationInstancesCapability as x, heatingValveCapability as y, isSecretMarkerLike as z };
103285
+ export { unknown as $, runningStateCapability as A, isSecretMarker as B, integrationInstancesCapability as C, quantityFromUnit as D, powerMeterCapability as E, createEvent as F, array as G, rowsDepsOver as H, customAction as I, number$1 as J, boolean as K, defineCustomActions as L, temperatureSensorCapability as M, waterHeaterCapability as N, registerPowerSwitch as O, RecordIntegrationInstances as P, union as Q, defineEntryKind as R, ingestReading as S, plainEventVocabulary as T, _enum as U, isSecretMarkerLike as V, _null as W, record as X, object as Y, string as Z, eventEmitterCapability as _, BaseDevice as a, heatPumpStatusCapability as b, RUNNING_STATE_COLD as c, climateControlCapability as d, DeviceRole as et, consumablesCapability as f, enumSensorCapability as g, dishwasherCapability as h, testBoschInstance as i, switchCapability as j, runningFromDishwasherOperation as k, batteryCapability as l, deviceAdoptionCapability as m, boschRowsPorts as n, errMsg as nt, BaseDeviceProvider as o, defaultIntegrationName as p, literal as q, keepBodyKeys as r, EventCategory as rt, DishwasherOperationStateSchema as s, boschRowsMigration as t, DeviceType as tt, binaryCapability as u, gatewayDeviceName as v, numericSensorCapability as w, heatingValveCapability as x, heatPumpControlCapability as y, entryBody as z };
@@ -44097,6 +44097,51 @@ function macroOnly(macro) {
44097
44097
  };
44098
44098
  }
44099
44099
  }
44100
+ var EventVocabularyKindSchema = _enum([
44101
+ "press",
44102
+ "long-press",
44103
+ "long-press-start",
44104
+ "release",
44105
+ "repeat",
44106
+ "double-press",
44107
+ "other"
44108
+ ]);
44109
+ /** The part of the device an event comes from: a button, a channel. */
44110
+ var EventVocabularySourceSchema = object({
44111
+ id: string().min(1),
44112
+ label: string().min(1)
44113
+ });
44114
+ /** One scalar field of an event's `data`, by dotted path. */
44115
+ var EventVocabularyFieldSchema = object({
44116
+ path: string().min(1),
44117
+ kind: _enum([
44118
+ "string",
44119
+ "number",
44120
+ "boolean",
44121
+ "enum"
44122
+ ]),
44123
+ enumValues: array(string()).optional(),
44124
+ label: string().min(1).optional()
44125
+ });
44126
+ var EventVocabularyEntrySchema = object({
44127
+ /** The native token, verbatim. */
44128
+ id: string().min(1),
44129
+ source: EventVocabularySourceSchema.optional(),
44130
+ label: string().min(1),
44131
+ description: string().optional(),
44132
+ kind: EventVocabularyKindSchema.optional(),
44133
+ payload: array(EventVocabularyFieldSchema).optional()
44134
+ });
44135
+ /**
44136
+ * The vocabulary of a source that declares tokens and nothing else: one
44137
+ * entry per token, labelled with the token itself.
44138
+ */
44139
+ function plainEventVocabulary(eventTypes) {
44140
+ return [...new Set(eventTypes)].filter((eventType) => eventType !== "").map((eventType) => ({
44141
+ id: eventType,
44142
+ label: eventType
44143
+ }));
44144
+ }
44100
44145
  Math.PI / 180;
44101
44146
  /**
44102
44147
  * WHEN something happens, as data (D983) — the one time vocabulary of the
@@ -44304,6 +44349,33 @@ var ScheduleLeafSchema = object({
44304
44349
  /** @deprecated legacy cron — new schedules use `at`. */
44305
44350
  cron: string().min(1).max(120).optional()
44306
44351
  }).refine((leaf) => leaf.at === void 0 !== (leaf.cron === void 0), { message: "a schedule names exactly one of `at` (a time spec) and `cron` (legacy)" }).refine((leaf) => leaf.days === void 0 || leaf.at !== void 0, { message: "`days` goes with `at`; a cron expression carries its own days" });
44352
+ /**
44353
+ * One payload predicate of a `device-fired` row: the value at `path` inside
44354
+ * the fire's `data` (dotted) equals `equals`. Compared strictly, no coercion.
44355
+ */
44356
+ var DeviceFiredMatchSchema = object({
44357
+ path: string().min(1).max(120),
44358
+ equals: union([
44359
+ string(),
44360
+ number$1(),
44361
+ boolean()
44362
+ ])
44363
+ });
44364
+ /**
44365
+ * "fires": one device of the `event-emitter` capability reported an event
44366
+ * (D1045). Every list is an OR, the lists together an AND; an absent list does
44367
+ * not narrow. `eventIds` are the device's own tokens, `sourceIds` the parts of
44368
+ * the device (a button), `kinds` the shared press kinds of its vocabulary.
44369
+ */
44370
+ var DeviceFiredLeafSchema = object({
44371
+ kind: literal("device-fired"),
44372
+ ...eventLeafId,
44373
+ deviceId: number$1().int().nonnegative(),
44374
+ eventIds: array(string().min(1)).min(1).max(64).optional(),
44375
+ sourceIds: array(string().min(1)).min(1).max(64).optional(),
44376
+ kinds: array(EventVocabularyKindSchema).min(1).optional(),
44377
+ match: array(DeviceFiredMatchSchema).min(1).max(8).optional()
44378
+ });
44307
44379
  var ManualLeafSchema = object({
44308
44380
  kind: literal("manual"),
44309
44381
  ...eventLeafId
@@ -44445,6 +44517,7 @@ var AutomationWhenSchema = lazy(() => discriminatedUnion("kind", [
44445
44517
  }),
44446
44518
  DeviceBecomesLeafSchema,
44447
44519
  DeviceEventLeafSchema,
44520
+ DeviceFiredLeafSchema,
44448
44521
  ScheduleLeafSchema,
44449
44522
  ManualLeafSchema,
44450
44523
  IntervalLeafSchema,
@@ -44459,6 +44532,7 @@ var AutomationWhenSchema = lazy(() => discriminatedUnion("kind", [
44459
44532
  var EVENT_KINDS = new Set([
44460
44533
  "device-becomes",
44461
44534
  "device-event",
44535
+ "device-fired",
44462
44536
  "schedule",
44463
44537
  "manual",
44464
44538
  "interval",
@@ -44539,6 +44613,7 @@ function hasEmptyContainer(node) {
44539
44613
  var LEAF_WORDS = {
44540
44614
  "device-becomes": "a device value that becomes",
44541
44615
  "device-event": "a device event",
44616
+ "device-fired": "a device firing an event",
44542
44617
  schedule: "a schedule",
44543
44618
  manual: "a manual run",
44544
44619
  interval: "an interval",
@@ -45182,6 +45257,16 @@ var BECOMES_DESCRIPTIONS = {
45182
45257
  from: "the value before the change, empty when it is not known",
45183
45258
  to: "the value it changed to"
45184
45259
  };
45260
+ /**
45261
+ * A fire's payload is offered too, as `data.<path>` (`{{vars.data.channel}}`):
45262
+ * those names depend on the device, so they are not in this list.
45263
+ */
45264
+ var FIRED_DESCRIPTIONS = {
45265
+ deviceId: "the device that fired",
45266
+ eventType: "the event, as the device names it",
45267
+ sourceId: "the part of the device that fired (a button), empty when it names none",
45268
+ eventKind: "the kind of press (press, long-press …), empty when the device declares none"
45269
+ };
45185
45270
  function describe$1(descriptions) {
45186
45271
  return Object.entries(descriptions).map(([name, description]) => ({
45187
45272
  name,
@@ -45190,12 +45275,74 @@ function describe$1(descriptions) {
45190
45275
  }
45191
45276
  describe$1(DETECTION_DESCRIPTIONS);
45192
45277
  describe$1(STATIONARY_DESCRIPTIONS);
45278
+ describe$1(FIRED_DESCRIPTIONS).map((v) => v.name === "deviceId" ? {
45279
+ ...v,
45280
+ hintKey: "firedDeviceId"
45281
+ } : v);
45193
45282
  describe$1(BECOMES_DESCRIPTIONS).map((v) => v.name === "deviceId" ? {
45194
45283
  ...v,
45195
45284
  hintKey: "becomesDeviceId"
45196
45285
  } : v);
45197
45286
  new Set(Object.values(COCO_TO_MACRO.mapping));
45198
45287
  /**
45288
+ * Generic stateless event emitter. Installed on a `DeviceType.EventEmitter`
45289
+ * device. Carries the device's EXACT declared event vocabulary verbatim
45290
+ * (NO normalization). Two shapes:
45291
+ * - structured source (HA `event.*` entity) → `vocabulary` is the fixed
45292
+ * declared set (e.g. press_short, press_long, …).
45293
+ * - generic/legacy source (HA bus events, e.g. zha_event) → `vocabulary`
45294
+ * is [] (open) and `lastEvent.data` carries the complex payload.
45295
+ * `vocabulary` (D1044) names each event for a person and types it for a
45296
+ * rule; `eventTypes` is its list of native tokens, kept for older readers.
45297
+ * A fire names the part of the device it came from in `sourceId` when the
45298
+ * vocabulary declares sources (a remote's buttons).
45299
+ * `seq` is monotonic so two identical events still produce distinct slice writes.
45300
+ */
45301
+ var EventFireSchema = object({
45302
+ deviceId: number$1(),
45303
+ eventType: string(),
45304
+ sourceId: string().optional(),
45305
+ data: record(string(), unknown()).nullable(),
45306
+ timestamp: number$1().meta(readingMeta("none")),
45307
+ seq: number$1().meta(readingMeta("count"))
45308
+ });
45309
+ var EventEmitterStatusSchema = object({
45310
+ eventTypes: array(string()),
45311
+ /**
45312
+ * Required of a provider by the type. A status written before the field
45313
+ * existed still parses, as an empty vocabulary: read it through
45314
+ * `readEventVocabulary`, which then answers with the plain tokens.
45315
+ */
45316
+ vocabulary: array(EventVocabularyEntrySchema).default([]),
45317
+ lastEvent: EventFireSchema.nullable(),
45318
+ eventCountSinceStart: number$1().meta(readingMeta("count"))
45319
+ });
45320
+ var eventEmitterCapability = {
45321
+ name: "event-emitter",
45322
+ scope: "device",
45323
+ deviceNative: true,
45324
+ mode: "singleton",
45325
+ deviceTypes: [DeviceType.EventEmitter],
45326
+ methods: {},
45327
+ events: { onEvent: { data: EventFireSchema } },
45328
+ status: {
45329
+ schema: EventEmitterStatusSchema,
45330
+ kind: "push"
45331
+ },
45332
+ runtimeState: EventEmitterStatusSchema,
45333
+ /**
45334
+ * Runtime-state durability: **session** — `eventCountSinceStart` names its own scope.
45335
+ *
45336
+ * See `RuntimeStateDurability`. Enforced by
45337
+ * `scripts/check-runtime-state-durability.ts`.
45338
+ */
45339
+ durability: "session",
45340
+ /**
45341
+ * History (D850): none — `eventCountSinceStart` resets with the addon; events live in ledgers.
45342
+ */
45343
+ history: "none"
45344
+ };
45345
+ /**
45199
45346
  * Schedulers (D983) — an entity that performs actions over the day.
45200
45347
  *
45201
45348
  * A scheduler has profiles; a profile has weekdays and a timeline of POINTS.
@@ -45453,6 +45600,7 @@ var AutomationConditionTraceNodeSchema = object({
45453
45600
  "triggered-by",
45454
45601
  "device-becomes",
45455
45602
  "device-event",
45603
+ "device-fired",
45456
45604
  "schedule",
45457
45605
  "interval",
45458
45606
  "manual",
@@ -56661,109 +56809,6 @@ var enumSensorCapability = {
56661
56809
  * whether persisting is worth a SQLite commit. */
56662
56810
  volatileStateFields: ["lastFetchedAt", "timestamp"]
56663
56811
  };
56664
- var EventVocabularyKindSchema = _enum([
56665
- "press",
56666
- "long-press",
56667
- "long-press-start",
56668
- "release",
56669
- "repeat",
56670
- "double-press",
56671
- "other"
56672
- ]);
56673
- /** The part of the device an event comes from: a button, a channel. */
56674
- var EventVocabularySourceSchema = object({
56675
- id: string().min(1),
56676
- label: string().min(1)
56677
- });
56678
- /** One scalar field of an event's `data`, by dotted path. */
56679
- var EventVocabularyFieldSchema = object({
56680
- path: string().min(1),
56681
- kind: _enum([
56682
- "string",
56683
- "number",
56684
- "boolean",
56685
- "enum"
56686
- ]),
56687
- enumValues: array(string()).optional(),
56688
- label: string().min(1).optional()
56689
- });
56690
- var EventVocabularyEntrySchema = object({
56691
- /** The native token, verbatim. */
56692
- id: string().min(1),
56693
- source: EventVocabularySourceSchema.optional(),
56694
- label: string().min(1),
56695
- description: string().optional(),
56696
- kind: EventVocabularyKindSchema.optional(),
56697
- payload: array(EventVocabularyFieldSchema).optional()
56698
- });
56699
- /**
56700
- * The vocabulary of a source that declares tokens and nothing else: one
56701
- * entry per token, labelled with the token itself.
56702
- */
56703
- function plainEventVocabulary(eventTypes) {
56704
- return [...new Set(eventTypes)].filter((eventType) => eventType !== "").map((eventType) => ({
56705
- id: eventType,
56706
- label: eventType
56707
- }));
56708
- }
56709
- /**
56710
- * Generic stateless event emitter. Installed on a `DeviceType.EventEmitter`
56711
- * device. Carries the device's EXACT declared event vocabulary verbatim
56712
- * (NO normalization). Two shapes:
56713
- * - structured source (HA `event.*` entity) → `vocabulary` is the fixed
56714
- * declared set (e.g. press_short, press_long, …).
56715
- * - generic/legacy source (HA bus events, e.g. zha_event) → `vocabulary`
56716
- * is [] (open) and `lastEvent.data` carries the complex payload.
56717
- * `vocabulary` (D1044) names each event for a person and types it for a
56718
- * rule; `eventTypes` is its list of native tokens, kept for older readers.
56719
- * A fire names the part of the device it came from in `sourceId` when the
56720
- * vocabulary declares sources (a remote's buttons).
56721
- * `seq` is monotonic so two identical events still produce distinct slice writes.
56722
- */
56723
- var EventFireSchema = object({
56724
- deviceId: number$1(),
56725
- eventType: string(),
56726
- sourceId: string().optional(),
56727
- data: record(string(), unknown()).nullable(),
56728
- timestamp: number$1().meta(readingMeta("none")),
56729
- seq: number$1().meta(readingMeta("count"))
56730
- });
56731
- var EventEmitterStatusSchema = object({
56732
- eventTypes: array(string()),
56733
- /**
56734
- * Required of a provider by the type. A status written before the field
56735
- * existed still parses, as an empty vocabulary: read it through
56736
- * `readEventVocabulary`, which then answers with the plain tokens.
56737
- */
56738
- vocabulary: array(EventVocabularyEntrySchema).default([]),
56739
- lastEvent: EventFireSchema.nullable(),
56740
- eventCountSinceStart: number$1().meta(readingMeta("count"))
56741
- });
56742
- var eventEmitterCapability = {
56743
- name: "event-emitter",
56744
- scope: "device",
56745
- deviceNative: true,
56746
- mode: "singleton",
56747
- deviceTypes: [DeviceType.EventEmitter],
56748
- methods: {},
56749
- events: { onEvent: { data: EventFireSchema } },
56750
- status: {
56751
- schema: EventEmitterStatusSchema,
56752
- kind: "push"
56753
- },
56754
- runtimeState: EventEmitterStatusSchema,
56755
- /**
56756
- * Runtime-state durability: **session** — `eventCountSinceStart` names its own scope.
56757
- *
56758
- * See `RuntimeStateDurability`. Enforced by
56759
- * `scripts/check-runtime-state-durability.ts`.
56760
- */
56761
- durability: "session",
56762
- /**
56763
- * History (D850): none — `eventCountSinceStart` resets with the addon; events live in ledgers.
56764
- */
56765
- history: "none"
56766
- };
56767
56812
  var IdentitySchema = object({
56768
56813
  id: string(),
56769
56814
  name: string(),
@@ -59366,6 +59411,12 @@ var IntegrationLiteSchema = object({
59366
59411
  var AvailableIntegrationTypeSchema = object({
59367
59412
  addonId: string(),
59368
59413
  name: string(),
59414
+ /**
59415
+ * Product name a new integration is prefilled from (`<label> - Home`).
59416
+ * Absent: the client uses `name`. Set when the catalog title is not the
59417
+ * product (Bosch SHC, MQTT).
59418
+ */
59419
+ providerLabel: string().optional(),
59369
59420
  description: string(),
59370
59421
  iconUrl: string().nullable(),
59371
59422
  color: string(),
@@ -103091,6 +103142,38 @@ function ingestReading(input) {
103091
103142
  value: converted
103092
103143
  };
103093
103144
  }
103145
+ /**
103146
+ * Names chosen when an integration or a Gateway device is created.
103147
+ * A stored name is never rewritten from these helpers.
103148
+ */
103149
+ var HOME_SUFFIX = "Home";
103150
+ function collapse(value) {
103151
+ return value.trim().replace(/\s+/g, " ");
103152
+ }
103153
+ /** "KLF-200" → "KLF200". A hyphen between words ("Home Hub") stays. */
103154
+ function compactModelToken(value) {
103155
+ return value.replace(/([A-Za-z])-(\d)/g, "$1$2");
103156
+ }
103157
+ /** Prefill for a new integration: "<provider> - Home". The operator can edit it. */
103158
+ function defaultIntegrationName(providerLabel) {
103159
+ const label = collapse(providerLabel);
103160
+ if (label.length === 0) return HOME_SUFFIX;
103161
+ return `${label} - ${HOME_SUFFIX}`;
103162
+ }
103163
+ /**
103164
+ * A Gateway device: "<Brand> <Model>". An unknown model is the brand alone
103165
+ * (the caller passes the brand-level fallback it already has, e.g. "Velux KLF-200").
103166
+ */
103167
+ function gatewayDeviceName(brand, model) {
103168
+ const brandPart = compactModelToken(collapse(brand));
103169
+ const raw = collapse(model ?? "");
103170
+ if (raw.length === 0) return brandPart;
103171
+ const modelPart = compactModelToken(raw);
103172
+ const prefix = `${brandPart.toLowerCase()} `;
103173
+ if (modelPart.toLowerCase() === brandPart.toLowerCase()) return brandPart;
103174
+ if (modelPart.toLowerCase().startsWith(prefix)) return modelPart;
103175
+ return `${brandPart} ${modelPart}`;
103176
+ }
103094
103177
  String.raw`(?<=^|["'(\s>,\[{])`;
103095
103178
  var MB = 1024 * 1024;
103096
103179
  1024 * MB, 3072 * MB;
@@ -103319,6 +103402,12 @@ Object.defineProperty(exports, "customAction", {
103319
103402
  return customAction;
103320
103403
  }
103321
103404
  });
103405
+ Object.defineProperty(exports, "defaultIntegrationName", {
103406
+ enumerable: true,
103407
+ get: function() {
103408
+ return defaultIntegrationName;
103409
+ }
103410
+ });
103322
103411
  Object.defineProperty(exports, "defineCustomActions", {
103323
103412
  enumerable: true,
103324
103413
  get: function() {
@@ -103367,6 +103456,12 @@ Object.defineProperty(exports, "eventEmitterCapability", {
103367
103456
  return eventEmitterCapability;
103368
103457
  }
103369
103458
  });
103459
+ Object.defineProperty(exports, "gatewayDeviceName", {
103460
+ enumerable: true,
103461
+ get: function() {
103462
+ return gatewayDeviceName;
103463
+ }
103464
+ });
103370
103465
  Object.defineProperty(exports, "heatPumpControlCapability", {
103371
103466
  enumerable: true,
103372
103467
  get: function() {
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_bosch_instances = require("../bosch-instances-dqTG9no9.js");
3
- const require_account_integration_offline = require("../account-integration-offline-C-KJYRdX.js");
2
+ const require_bosch_instances = require("../bosch-instances-DkTzZrlR.js");
3
+ const require_account_integration_offline = require("../account-integration-offline-DK6CYsvB.js");
4
4
  let node_crypto = require("node:crypto");
5
5
  let node_tls = require("node:tls");
6
6
  let node_zlib = require("node:zlib");
@@ -1,5 +1,5 @@
1
- import { $ as DeviceType, B as rowsDepsOver, C as plainEventVocabulary, D as runningFromDishwasherOperation, F as defineCustomActions, G as literal, I as defineEntryKind, J as record, L as entryBody, M as RecordIntegrationInstances, N as createEvent, O as runningStateCapability, P as customAction, Q as DeviceRole, R as isSecretMarker, S as numericSensorCapability, T as quantityFromUnit, U as array, V as _enum, X as union, Y as string, Z as unknown, a as BaseDevice, b as ingestReading, c as RUNNING_STATE_COLD, et as errMsg, f as consumablesCapability, g as eventEmitterCapability, h as enumSensorCapability, i as testBoschInstance, m as dishwasherCapability, n as boschRowsPorts, o as BaseDeviceProvider, p as deviceAdoptionCapability, q as object, r as keepBodyKeys, s as DishwasherOperationStateSchema, t as boschRowsMigration, tt as EventCategory, u as binaryCapability, w as powerMeterCapability, x as integrationInstancesCapability, z as isSecretMarkerLike } from "../bosch-instances-y_A00js_.mjs";
2
- import { a as loginFailureForAttempt, c as HOME_CONNECT_REDIRECT_URI, i as createSignInAttemptStore, n as cascadeRemoveDevicesForIntegration, o as parseOAuthCallback, r as buildSignInGuideFields, t as setIntegrationDevicesOnline } from "../account-integration-offline-KQcJ_VVK.mjs";
1
+ import { $ as unknown, A as runningStateCapability, B as isSecretMarker, C as integrationInstancesCapability, D as quantityFromUnit, E as powerMeterCapability, F as createEvent, G as array, H as rowsDepsOver, I as customAction, L as defineCustomActions, P as RecordIntegrationInstances, Q as union, R as defineEntryKind, S as ingestReading, T as plainEventVocabulary, U as _enum, V as isSecretMarkerLike, X as record, Y as object, Z as string, _ as eventEmitterCapability, a as BaseDevice, c as RUNNING_STATE_COLD, et as DeviceRole, f as consumablesCapability, g as enumSensorCapability, h as dishwasherCapability, i as testBoschInstance, k as runningFromDishwasherOperation, m as deviceAdoptionCapability, n as boschRowsPorts, nt as errMsg, o as BaseDeviceProvider, q as literal, r as keepBodyKeys, rt as EventCategory, s as DishwasherOperationStateSchema, t as boschRowsMigration, tt as DeviceType, u as binaryCapability, w as numericSensorCapability, z as entryBody } from "../bosch-instances-DMzZSMxW.mjs";
2
+ import { a as loginFailureForAttempt, c as HOME_CONNECT_REDIRECT_URI, i as createSignInAttemptStore, n as cascadeRemoveDevicesForIntegration, o as parseOAuthCallback, r as buildSignInGuideFields, t as setIntegrationDevicesOnline } from "../account-integration-offline-C9glrBvy.mjs";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  import { connect } from "node:tls";
5
5
  import { inflateRawSync } from "node:zlib";
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_bosch_instances = require("../bosch-instances-dqTG9no9.js");
3
- const require_account_integration_offline = require("../account-integration-offline-C-KJYRdX.js");
2
+ const require_bosch_instances = require("../bosch-instances-DkTzZrlR.js");
3
+ const require_account_integration_offline = require("../account-integration-offline-DK6CYsvB.js");
4
4
  let node_crypto = require("node:crypto");
5
5
  let node_child_process = require("node:child_process");
6
6
  let node_fs = require("node:fs");
@@ -2471,7 +2471,7 @@ var HOMECOM_GATEWAY_NATIVE_ID = "gateway:0";
2471
2471
  function gatewayDiscoverable(snapshot) {
2472
2472
  return {
2473
2473
  nativeId: HOMECOM_GATEWAY_NATIVE_ID,
2474
- name: snapshot.gateway.name.length > 0 ? snapshot.gateway.name : "HomeCom gateway",
2474
+ name: require_bosch_instances.gatewayDeviceName("Bosch HomeCom", snapshot.deviceType),
2475
2475
  kind: "gateway"
2476
2476
  };
2477
2477
  }
@@ -1,5 +1,5 @@
1
- import { $ as DeviceType, B as rowsDepsOver, E as registerPowerSwitch, F as defineCustomActions, G as literal, H as _null, I as defineEntryKind, J as record, K as number, L as entryBody, M as RecordIntegrationInstances, P as customAction, Q as DeviceRole, U as array, V as _enum, W as boolean, X as union, Y as string, _ as heatPumpControlCapability, a as BaseDevice, d as climateControlCapability, et as errMsg, i as testBoschInstance, j as waterHeaterCapability, n as boschRowsPorts, o as BaseDeviceProvider, p as deviceAdoptionCapability, q as object, r as keepBodyKeys, t as boschRowsMigration, tt as EventCategory, v as heatPumpStatusCapability, x as integrationInstancesCapability } from "../bosch-instances-y_A00js_.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-KQcJ_VVK.mjs";
1
+ import { C as integrationInstancesCapability, G as array, H as rowsDepsOver, I as customAction, J as number, K as boolean, L as defineCustomActions, N as waterHeaterCapability, O as registerPowerSwitch, P as RecordIntegrationInstances, Q as union, R as defineEntryKind, U as _enum, W as _null, X as record, Y as object, Z as string, a as BaseDevice, b as heatPumpStatusCapability, d as climateControlCapability, et as DeviceRole, i as testBoschInstance, m as deviceAdoptionCapability, n as boschRowsPorts, nt as errMsg, o as BaseDeviceProvider, q as literal, r as keepBodyKeys, rt as EventCategory, t as boschRowsMigration, tt as DeviceType, v as gatewayDeviceName, y as heatPumpControlCapability, z as entryBody } from "../bosch-instances-DMzZSMxW.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-C9glrBvy.mjs";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  import { spawn } from "node:child_process";
5
5
  import { existsSync } from "node:fs";
@@ -2470,7 +2470,7 @@ var HOMECOM_GATEWAY_NATIVE_ID = "gateway:0";
2470
2470
  function gatewayDiscoverable(snapshot) {
2471
2471
  return {
2472
2472
  nativeId: HOMECOM_GATEWAY_NATIVE_ID,
2473
- name: snapshot.gateway.name.length > 0 ? snapshot.gateway.name : "HomeCom gateway",
2473
+ name: gatewayDeviceName("Bosch HomeCom", snapshot.deviceType),
2474
2474
  kind: "gateway"
2475
2475
  };
2476
2476
  }
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-dqTG9no9.js");
5
+ const require_bosch_instances = require("../bosch-instances-DkTzZrlR.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");
@@ -638,7 +638,7 @@ function shcDiscoveryCandidates(proposals) {
638
638
  return proposals.map((found) => ({
639
639
  stableId: `bosch-shc:${found.id}`,
640
640
  type: require_bosch_instances.DeviceType.Gateway,
641
- suggestedName: found.name,
641
+ suggestedName: require_bosch_instances.defaultIntegrationName("Bosch SHC"),
642
642
  prefilledConfig: { host: found.host },
643
643
  setupIntegration: true
644
644
  }));
@@ -895,7 +895,7 @@ function buildShcCandidates(input) {
895
895
  const gatewayAdopted = input.adopted.get(gatewayId) ?? null;
896
896
  const out = [{
897
897
  childNativeId: gatewayId,
898
- name: input.integrationName,
898
+ name: require_bosch_instances.gatewayDeviceName("Bosch", "SHC"),
899
899
  type: require_bosch_instances.DeviceType.Gateway,
900
900
  status: "online",
901
901
  metadata: {
@@ -1376,7 +1376,7 @@ function buildShcAdoptionProvider(deps) {
1376
1376
  let failures = 0;
1377
1377
  for (const shcDeviceId of childNativeIds) try {
1378
1378
  if (shcDeviceId === shcGatewayNativeId(integrationId)) {
1379
- const name = perCandidate?.[shcDeviceId]?.name ?? integrationName(integrationId) ?? "Bosch SHC";
1379
+ const name = perCandidate?.[shcDeviceId]?.name ?? require_bosch_instances.gatewayDeviceName("Bosch", "SHC");
1380
1380
  const { deviceId } = await adoptDevice({
1381
1381
  shcDeviceId,
1382
1382
  integrationId,
@@ -1,4 +1,4 @@
1
- import { $ as DeviceType, A as temperatureSensorCapability, B as rowsDepsOver, E as registerPowerSwitch, F as defineCustomActions, G as literal, I as defineEntryKind, K as number, L as entryBody, M as RecordIntegrationInstances, P as customAction, Q as DeviceRole, U as array, V as _enum, Y as string, a as BaseDevice, d as climateControlCapability, et as errMsg, i as testBoschInstance, k as switchCapability, l as batteryCapability, n as boschRowsPorts, o as BaseDeviceProvider, p as deviceAdoptionCapability, q as object, r as keepBodyKeys, t as boschRowsMigration, tt as EventCategory, x as integrationInstancesCapability, y as heatingValveCapability } from "../bosch-instances-y_A00js_.mjs";
1
+ import { C as integrationInstancesCapability, G as array, H as rowsDepsOver, I as customAction, J as number, L as defineCustomActions, M as temperatureSensorCapability, O as registerPowerSwitch, P as RecordIntegrationInstances, R as defineEntryKind, U as _enum, Y as object, Z as string, a as BaseDevice, d as climateControlCapability, et as DeviceRole, i as testBoschInstance, j as switchCapability, l as batteryCapability, m as deviceAdoptionCapability, n as boschRowsPorts, nt as errMsg, o as BaseDeviceProvider, p as defaultIntegrationName, q as literal, r as keepBodyKeys, rt as EventCategory, t as boschRowsMigration, tt as DeviceType, v as gatewayDeviceName, x as heatingValveCapability, z as entryBody } from "../bosch-instances-DMzZSMxW.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { request } from "node:https";
@@ -639,7 +639,7 @@ function shcDiscoveryCandidates(proposals) {
639
639
  return proposals.map((found) => ({
640
640
  stableId: `bosch-shc:${found.id}`,
641
641
  type: DeviceType.Gateway,
642
- suggestedName: found.name,
642
+ suggestedName: defaultIntegrationName("Bosch SHC"),
643
643
  prefilledConfig: { host: found.host },
644
644
  setupIntegration: true
645
645
  }));
@@ -896,7 +896,7 @@ function buildShcCandidates(input) {
896
896
  const gatewayAdopted = input.adopted.get(gatewayId) ?? null;
897
897
  const out = [{
898
898
  childNativeId: gatewayId,
899
- name: input.integrationName,
899
+ name: gatewayDeviceName("Bosch", "SHC"),
900
900
  type: DeviceType.Gateway,
901
901
  status: "online",
902
902
  metadata: {
@@ -1377,7 +1377,7 @@ function buildShcAdoptionProvider(deps) {
1377
1377
  let failures = 0;
1378
1378
  for (const shcDeviceId of childNativeIds) try {
1379
1379
  if (shcDeviceId === shcGatewayNativeId(integrationId)) {
1380
- const name = perCandidate?.[shcDeviceId]?.name ?? integrationName(integrationId) ?? "Bosch SHC";
1380
+ const name = perCandidate?.[shcDeviceId]?.name ?? gatewayDeviceName("Bosch", "SHC");
1381
1381
  const { deviceId } = await adoptDevice({
1382
1382
  shcDeviceId,
1383
1383
  integrationId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-bosch",
3
- "version": "0.1.53",
3
+ "version": "0.1.54",
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",
@@ -39,6 +39,7 @@
39
39
  "integrationRole": "devices",
40
40
  "category": "providers",
41
41
  "name": "Bosch Smart Home",
42
+ "providerLabel": "Bosch SHC",
42
43
  "version": "0.1.0",
43
44
  "description": "Adopt Bosch Smart Home Controller (SHC) devices via account onboarding — scaffold",
44
45
  "entry": "./dist/shc/addon.js",
@@ -141,7 +142,7 @@
141
142
  }
142
143
  ],
143
144
  "requires": {
144
- "server": ">=1.2.842"
145
+ "server": ">=1.2.846"
145
146
  }
146
147
  },
147
148
  "files": [