@camstack/addon-provider-velux 0.2.143 → 0.2.144

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.
Files changed (3) hide show
  1. package/dist/addon.js +193 -117
  2. package/dist/addon.mjs +193 -117
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -5431,7 +5431,7 @@ var ZodIssueCode = {
5431
5431
  var ZodFirstPartyTypeKind;
5432
5432
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5433
5433
  //#endregion
5434
- //#region ../types/dist/sleep-DJFUfKvA.mjs
5434
+ //#region ../types/dist/sleep-CUp20JkO.mjs
5435
5435
  /**
5436
5436
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5437
5437
  * window to float samples (D455).
@@ -8323,7 +8323,11 @@ var ContributionSectionSchema = object({
8323
8323
  literal(4)
8324
8324
  ]).optional(),
8325
8325
  tab: string().optional(),
8326
- location: _enum(["settings", "top-tab"]).optional(),
8326
+ location: _enum([
8327
+ "settings",
8328
+ "top-tab",
8329
+ "hero"
8330
+ ]).optional(),
8327
8331
  order: number().optional(),
8328
8332
  fields: array(any())
8329
8333
  });
@@ -13270,7 +13274,11 @@ var ConfigSectionWithValuesSchema = object({
13270
13274
  literal(4)
13271
13275
  ]).optional(),
13272
13276
  tab: string().optional(),
13273
- location: _enum(["settings", "top-tab"]).optional(),
13277
+ location: _enum([
13278
+ "settings",
13279
+ "top-tab",
13280
+ "hero"
13281
+ ]).optional(),
13274
13282
  order: number().optional(),
13275
13283
  fields: array(any())
13276
13284
  });
@@ -17150,6 +17158,52 @@ var TierStatusSchema = object({
17150
17158
  countedAt: number().nullable()
17151
17159
  });
17152
17160
  /** Operator/diagnostic view: rows per tier, last runs, refusals and drops since boot. */
17161
+ /**
17162
+ * Why a series is orphan. `device-gone`: its device is absent from the
17163
+ * successful device listings (the departure clock). `undeclared`: its `cap:`
17164
+ * key is declared by no capability any more (a field a cap removed).
17165
+ */
17166
+ var DeviceHistoryOrphanReasonSchema = _enum(["device-gone", "undeclared"]);
17167
+ /** Rows held per stored tier. */
17168
+ var TierRowsSchema = object({
17169
+ raw: number().int(),
17170
+ "5m": number().int(),
17171
+ "1h": number().int(),
17172
+ "1d": number().int()
17173
+ });
17174
+ var OrphanSeriesSchema = object({
17175
+ seriesId: number().int(),
17176
+ deviceId: number().int(),
17177
+ key: string(),
17178
+ scope: string(),
17179
+ /** The metric's display name; `null` when its metric row is gone too. */
17180
+ displayName: string().nullable(),
17181
+ reason: DeviceHistoryOrphanReasonSchema,
17182
+ /** `device-gone`: since when the device has been absent; `null` otherwise. */
17183
+ missingSince: number().nullable(),
17184
+ firstTs: number(),
17185
+ lastTs: number(),
17186
+ rows: TierRowsSchema
17187
+ });
17188
+ var DeviceHistoryOrphanDeleteRefusalSchema = _enum([
17189
+ "not-found",
17190
+ "not-orphan",
17191
+ "failed"
17192
+ ]);
17193
+ var OrphanDeleteEntrySchema = discriminatedUnion("ok", [object({
17194
+ seriesId: number().int(),
17195
+ ok: literal(true),
17196
+ deleted: TierRowsSchema
17197
+ }), object({
17198
+ seriesId: number().int(),
17199
+ ok: literal(false),
17200
+ reason: DeviceHistoryOrphanDeleteRefusalSchema
17201
+ })]);
17202
+ var OrphanListSchema = object({
17203
+ series: array(OrphanSeriesSchema).readonly(),
17204
+ /** More orphans exist than {@link DEVICE_HISTORY_ORPHAN_LIST_MAX}. */
17205
+ truncated: boolean()
17206
+ });
17153
17207
  var DeviceHistoryStatusSchema = object({
17154
17208
  startedAt: number(),
17155
17209
  /** The store is declared, series loaded and the first reconcile has answered. */
@@ -17247,7 +17301,10 @@ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly())
17247
17301
  }), object({ enabled: boolean() }), {
17248
17302
  kind: "mutation",
17249
17303
  auth: "admin"
17250
- }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" });
17304
+ }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" }), method(object({}), OrphanListSchema, { auth: "admin" }), method(object({ seriesIds: array(number().int()).min(1).max(50) }), object({ results: array(OrphanDeleteEntrySchema).readonly() }), {
17305
+ kind: "mutation",
17306
+ auth: "admin"
17307
+ });
17251
17308
  var DeviceCaStatusSchema = discriminatedUnion("state", [
17252
17309
  object({ state: literal("absent") }),
17253
17310
  object({
@@ -55203,17 +55260,69 @@ var connectivityCapability = {
55203
55260
  volatileStateFields: ["lastChangedAt"]
55204
55261
  };
55205
55262
  /**
55206
- * Generic device-consumables capability — surfaces a device's
55207
- * maintenance items (vacuum filters/brushes, replaceable cartridges,
55208
- * descaling cycles, …) with their remaining life and an optional
55209
- * "Replaced" reset action. Device-agnostic: any provider that knows its
55210
- * device tracks consumables can register it; the cap declares no
55211
- * vocabulary of its own — the provider names each item verbatim.
55263
+ * Generic device-consumables capability — the ONE place a device reports what
55264
+ * it uses up or fills: wear parts (vacuum filters/brushes, cartridges,
55265
+ * descaling cycles), supplies it draws from (a vacuum's clean-water tank and
55266
+ * detergent, a dishwasher's salt and rinse aid) and waste it collects (a dirty
55267
+ * water tank, a dust bin). Each item carries its remaining life or fill and an
55268
+ * optional "Replaced" reset action. Device-agnostic: any provider that knows
55269
+ * its device tracks consumables registers it; the provider names each item
55270
+ * verbatim and says which `kind` it is.
55271
+ *
55272
+ * The admin UI renders it as ONE collapsible section directly under the
55273
+ * device page's hero card (`placement: 'hero'`), for every device bound to
55274
+ * this cap — never drawn by a device type's hero card itself (D915).
55212
55275
  *
55213
55276
  * Like `childLayout`, the cap is INERT until a provider sets items: no
55214
55277
  * provider populates it by guessing (no HA inference). The UI renders a
55215
55278
  * "No consumables reported" placeholder when `items` is empty.
55216
55279
  */
55280
+ /**
55281
+ * What an item IS, which decides which direction is bad:
55282
+ * - `wear` — a part that wears out (a brush, a filter); low life is bad.
55283
+ * - `supply` — something the device draws from (clean water, detergent,
55284
+ * salt, rinse aid); low or empty is bad.
55285
+ * - `waste` — something the device fills (dirty water, a dust bin); full is
55286
+ * bad.
55287
+ * Absent = `wear`.
55288
+ */
55289
+ var ConsumableKindSchema = _enum([
55290
+ "wear",
55291
+ "supply",
55292
+ "waste"
55293
+ ]);
55294
+ /**
55295
+ * What an item LOOKS like, which decides how a client draws it — independent
55296
+ * of `kind`, which decides which direction is bad:
55297
+ * - `part` — a part that wears (a brush, a filter, a mop pad): a wear bar,
55298
+ * remaining time and a reset.
55299
+ * - `tank` — a container of liquid (clean water, dirty water): a fill gauge.
55300
+ * - `product` — something bought and refilled (detergent, salt, rinse aid):
55301
+ * a stepped level and "refill".
55302
+ * - `bin` — a container that collects waste (a dust bin): a fill gauge
55303
+ * that warns when full.
55304
+ * Absent = derived from the kind ({@link consumableFormOf}).
55305
+ */
55306
+ var ConsumableFormSchema = _enum([
55307
+ "part",
55308
+ "tank",
55309
+ "product",
55310
+ "bin"
55311
+ ]);
55312
+ /** The provider's own discrete verdict on an item. */
55313
+ var ConsumableStatusSchema = _enum([
55314
+ "ok",
55315
+ "low",
55316
+ "empty",
55317
+ "full",
55318
+ "replace"
55319
+ ]);
55320
+ _enum([
55321
+ "ok",
55322
+ "low",
55323
+ "empty",
55324
+ "full"
55325
+ ]);
55217
55326
  /** Units a remaining-life counter is reported in. Closed: the panel renders
55218
55327
  * each. */
55219
55328
  var ConsumableRemainingUnitSchema = _enum([
@@ -55228,18 +55337,23 @@ var ConsumableRemainingSchema = object({
55228
55337
  unit: ConsumableRemainingUnitSchema
55229
55338
  });
55230
55339
  /** A single consumable item. Either a continuous `level` (remaining
55231
- * life %) or a discrete `status` may be known — both may be null when a
55232
- * provider only knows the item exists. `level` and `status` are not
55233
- * mutually exclusive; a provider may report both. */
55340
+ * life %, or fill % for a `supply` / `waste` item) or a discrete `status`
55341
+ * may be known — both may be null when a provider only knows the item
55342
+ * exists. `level` and `status` are not mutually exclusive; a provider may
55343
+ * report both. */
55234
55344
  var ConsumableItemSchema = object({
55235
55345
  /** Stable id, e.g. 'main-brush'. */
55236
55346
  key: string().min(1),
55237
55347
  /** Display name. */
55238
55348
  label: string().min(1),
55239
- /** Remaining life % when known (0..100). */
55349
+ /** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
55240
55350
  level: number().min(0).max(100).nullable(),
55241
- /** Discrete state when known (binary mode). */
55242
- status: _enum(["ok", "replace"]).nullable(),
55351
+ /** The provider's discrete verdict when known (binary mode). */
55352
+ status: ConsumableStatusSchema.nullable(),
55353
+ /** What the item is — decides whether low or full is bad. Absent = `wear`. */
55354
+ kind: ConsumableKindSchema.optional(),
55355
+ /** How the item is drawn (part, tank, product, bin). Absent = derived from `kind`. */
55356
+ form: ConsumableFormSchema.optional(),
55243
55357
  /** Ms epoch of the last replace, when known. */
55244
55358
  lastResetAt: number().nullable(),
55245
55359
  /** Whether `reset()` is meaningful for this item. */
@@ -55262,7 +55376,7 @@ var consumablesCapability = {
55262
55376
  kind: "widget",
55263
55377
  widgetId: "host/consumables-panel",
55264
55378
  tab: "consumables",
55265
- topTab: true,
55379
+ placement: "hero",
55266
55380
  label: "Consumables",
55267
55381
  order: 5
55268
55382
  } },
@@ -55323,9 +55437,37 @@ reset: method(object({
55323
55437
  */
55324
55438
  durability: "restored",
55325
55439
  /**
55326
- * History (D850): none — `items` is an array keyed by runtime ids; a history path never enters it.
55440
+ * History (D850, D917): one series per (item field, item `key`) — the item key
55441
+ * is the series scope, the item `label` names it. A vacuum tank's fill, a
55442
+ * brush's remaining life and a dishwasher's salt are each recorded the moment
55443
+ * their provider reports them; an item that appears later gets its series.
55327
55444
  */
55328
- history: "none",
55445
+ history: {
55446
+ fields: {},
55447
+ items: {
55448
+ path: "items",
55449
+ key: "key",
55450
+ label: "label",
55451
+ fields: {
55452
+ level: {
55453
+ kind: "gauge",
55454
+ unit: "%",
55455
+ deadband: 2,
55456
+ displayName: "Level"
55457
+ },
55458
+ status: {
55459
+ kind: "enum",
55460
+ displayName: "Status"
55461
+ },
55462
+ "remaining.value": {
55463
+ kind: "gauge",
55464
+ unitFrom: "remaining.unit",
55465
+ deadband: 1,
55466
+ displayName: "Remaining"
55467
+ }
55468
+ }
55469
+ }
55470
+ },
55329
55471
  /** Clocks, not content: a re-read that changed no item costs no commit. */
55330
55472
  volatileStateFields: ["lastChangedAt", "lastFetchedAt"]
55331
55473
  };
@@ -55740,8 +55882,9 @@ onStatusChanged: { data: object({
55740
55882
  volatileStateFields: ["lastChangedAt"]
55741
55883
  };
55742
55884
  /**
55743
- * Smart-dishwasher cap — program lifecycle, door / remote-start gates,
55744
- * consumable levels (salt, rinse aid) and common program options.
55885
+ * Smart-dishwasher cap — program lifecycle, door / remote-start gates and
55886
+ * common program options. Salt and rinse aid are NOT here: they are items of
55887
+ * the device's `consumables` cap, like every other device's (D915).
55745
55888
  *
55746
55889
  * Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
55747
55890
  * by any integration that exposes the same program / option surface.
@@ -55789,11 +55932,6 @@ var DishwasherAvailabilitySchema = _enum([
55789
55932
  "offline",
55790
55933
  "description-missing"
55791
55934
  ]);
55792
- var DishwasherConsumableLevelSchema = _enum([
55793
- "ok",
55794
- "low",
55795
- "empty"
55796
- ]);
55797
55935
  var DishwasherStatusSchema = object({
55798
55936
  availability: DishwasherAvailabilitySchema,
55799
55937
  /** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
@@ -55826,8 +55964,6 @@ var DishwasherStatusSchema = object({
55826
55964
  powerOn: boolean().nullable(),
55827
55965
  /** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
55828
55966
  powerState: string().nullable(),
55829
- saltLevel: DishwasherConsumableLevelSchema.nullable(),
55830
- rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
55831
55967
  /**
55832
55968
  * True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
55833
55969
  * combined care-and-filter reminder raised); false when every such reminder reads clear; null
@@ -64643,60 +64779,17 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
64643
64779
  auth: "admin",
64644
64780
  access: "delete"
64645
64781
  });
64646
- /**
64647
- * Robot-vacuum cap. Models HA `vacuum.*` entities — anything with a
64648
- * cleaning lifecycle plus a return-to-base / locate surface and an
64649
- * optional fan-speed selector.
64650
- *
64651
- * State follows HA's canonical vacuum lifecycle: `idle` / `cleaning` /
64652
- * `paused` / `returning` / `docked` / `error`. `batteryLevel`
64653
- * (0..100) is nullable — some vacuums don't report a battery
64654
- * percentage. `fanSpeed` is the current speed token (provider-verbatim,
64655
- * e.g. `'standard'` / `'turbo'`) and `availableFanSpeeds` lists the
64656
- * tokens the hardware accepts so the UI renders only supported choices.
64657
- *
64658
- * The `setFanSpeed` method takes the bare `speed` token — the provider
64659
- * validates it against the vacuum's own list. `locate` triggers the
64660
- * find-me chirp; `returnToBase` sends it home.
64661
- *
64662
- * Consumable / waste tanks: `cleanWater` / `dirtyWater` / `detergent` /
64663
- * `dustBin` each carry a nullable `{ level (0..100 %), status ('ok' |
64664
- * 'low' | 'full') }` reading. Native providers (e.g. Dreame, Roborock)
64665
- * SHOULD populate whichever tanks the hardware has — leave a field `null`
64666
- * only when the device has no such tank at all, and use a `TankStatus`
64667
- * with both inner fields `null` when the tank exists but its level is
64668
- * currently unknown. HA `vacuum.*` entities expose no per-tank telemetry,
64669
- * so the HA provider leaves all four `null`.
64670
- */
64671
- var VacuumStateSchema = _enum([
64672
- "idle",
64673
- "cleaning",
64674
- "paused",
64675
- "returning",
64676
- "docked",
64677
- "drying",
64678
- "error"
64679
- ]);
64680
- /**
64681
- * One consumable / waste tank on a robot vacuum (clean-water, dirty-water,
64682
- * detergent or dust-bin). A tank can report a numeric fill `level` (0..100),
64683
- * a discrete `status` (binary-style hardware), or both. Both `null` means the
64684
- * level is currently unknown; the OWNING field being `null` means the
64685
- * hardware has no such tank at all.
64686
- */
64687
- var TankStatusSchema = object({
64688
- /** Numeric fill 0..100 when the hardware reports a percentage; null otherwise. */
64689
- level: number().min(0).max(100).nullable(),
64690
- /** Discrete state when the hardware is binary-mode; null otherwise. */
64691
- status: _enum([
64692
- "ok",
64693
- "low",
64694
- "full"
64695
- ]).nullable()
64696
- });
64697
64782
  var VacuumControlStatusSchema = object({
64698
64783
  /** Lifecycle state of the vacuum. */
64699
- state: VacuumStateSchema,
64784
+ state: _enum([
64785
+ "idle",
64786
+ "cleaning",
64787
+ "paused",
64788
+ "returning",
64789
+ "docked",
64790
+ "drying",
64791
+ "error"
64792
+ ]),
64700
64793
  /** 0..100 battery percentage. Null when the device has no battery
64701
64794
  * reading. */
64702
64795
  batteryLevel: number().min(0).max(100).nullable(),
@@ -64705,14 +64798,6 @@ var VacuumControlStatusSchema = object({
64705
64798
  fanSpeed: string().nullable(),
64706
64799
  /** Speed tokens the hardware accepts — drives the UI selector. */
64707
64800
  availableFanSpeeds: array(string()),
64708
- /** Clean-water (mop) tank. Null when the hardware has no clean-water tank. */
64709
- cleanWater: TankStatusSchema.nullable(),
64710
- /** Dirty-water (recovery) tank. Null when the hardware has no dirty-water tank. */
64711
- dirtyWater: TankStatusSchema.nullable(),
64712
- /** Detergent tank. Null when the hardware has no detergent tank. */
64713
- detergent: TankStatusSchema.nullable(),
64714
- /** Dust bin. Null when the hardware has no dust bin. */
64715
- dustBin: TankStatusSchema.nullable(),
64716
64801
  /** 0..100 cleaning-completion percentage of the current task, or null. */
64717
64802
  progressPercent: number().min(0).max(100).nullable(),
64718
64803
  /** Current error code (0 / null = no error). */
@@ -64774,35 +64859,14 @@ var vacuumControlCapability = {
64774
64859
  */
64775
64860
  durability: "session",
64776
64861
  /**
64777
- * History (D850): recorded series. Tank levels are fixed-object paths (`cleanWater.level`, ...).
64862
+ * History (D850): recorded series. The tanks moved to `consumables` (D915), whose
64863
+ * items are keyed by runtime ids and record no history.
64778
64864
  */
64779
- history: { fields: {
64780
- batteryLevel: {
64781
- kind: "gauge",
64782
- unit: "%",
64783
- deadband: 2
64784
- },
64785
- "cleanWater.level": {
64786
- kind: "gauge",
64787
- unit: "%",
64788
- deadband: 2
64789
- },
64790
- "dirtyWater.level": {
64791
- kind: "gauge",
64792
- unit: "%",
64793
- deadband: 2
64794
- },
64795
- "detergent.level": {
64796
- kind: "gauge",
64797
- unit: "%",
64798
- deadband: 2
64799
- },
64800
- "dustBin.level": {
64801
- kind: "gauge",
64802
- unit: "%",
64803
- deadband: 2
64804
- }
64805
- } }
64865
+ history: { fields: { batteryLevel: {
64866
+ kind: "gauge",
64867
+ unit: "%",
64868
+ deadband: 2
64869
+ } } }
64806
64870
  };
64807
64871
  var ValveStatusSchema = object({
64808
64872
  /** Lifecycle state of the valve. */
@@ -69196,6 +69260,12 @@ Object.freeze({
69196
69260
  addonId: null,
69197
69261
  access: "create"
69198
69262
  },
69263
+ "deviceHistory.deleteOrphanSeries": {
69264
+ capName: "device-history",
69265
+ capScope: "system",
69266
+ addonId: null,
69267
+ access: "delete"
69268
+ },
69199
69269
  "deviceHistory.getDeviceEnabled": {
69200
69270
  capName: "device-history",
69201
69271
  capScope: "system",
@@ -69214,6 +69284,12 @@ Object.freeze({
69214
69284
  addonId: null,
69215
69285
  access: "view"
69216
69286
  },
69287
+ "deviceHistory.listOrphanSeries": {
69288
+ capName: "device-history",
69289
+ capScope: "system",
69290
+ addonId: null,
69291
+ access: "view"
69292
+ },
69217
69293
  "deviceHistory.listSeries": {
69218
69294
  capName: "device-history",
69219
69295
  capScope: "system",
@@ -79219,7 +79295,7 @@ var STATE_SUMMARY_VARS = [
79219
79295
  ([...RULE_TEXT], [...COMBINED_ALARM]),
79220
79296
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
79221
79297
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
79222
- ([...RULE_TEXT], [...CONSUMABLE]),
79298
+ ([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
79223
79299
  ([...RULE_TEXT], [...TANK]),
79224
79300
  [...RULE_TEXT],
79225
79301
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
package/dist/addon.mjs CHANGED
@@ -5430,7 +5430,7 @@ var ZodIssueCode = {
5430
5430
  var ZodFirstPartyTypeKind;
5431
5431
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5432
5432
  //#endregion
5433
- //#region ../types/dist/sleep-DJFUfKvA.mjs
5433
+ //#region ../types/dist/sleep-CUp20JkO.mjs
5434
5434
  /**
5435
5435
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5436
5436
  * window to float samples (D455).
@@ -8322,7 +8322,11 @@ var ContributionSectionSchema = object({
8322
8322
  literal(4)
8323
8323
  ]).optional(),
8324
8324
  tab: string().optional(),
8325
- location: _enum(["settings", "top-tab"]).optional(),
8325
+ location: _enum([
8326
+ "settings",
8327
+ "top-tab",
8328
+ "hero"
8329
+ ]).optional(),
8326
8330
  order: number().optional(),
8327
8331
  fields: array(any())
8328
8332
  });
@@ -13269,7 +13273,11 @@ var ConfigSectionWithValuesSchema = object({
13269
13273
  literal(4)
13270
13274
  ]).optional(),
13271
13275
  tab: string().optional(),
13272
- location: _enum(["settings", "top-tab"]).optional(),
13276
+ location: _enum([
13277
+ "settings",
13278
+ "top-tab",
13279
+ "hero"
13280
+ ]).optional(),
13273
13281
  order: number().optional(),
13274
13282
  fields: array(any())
13275
13283
  });
@@ -17149,6 +17157,52 @@ var TierStatusSchema = object({
17149
17157
  countedAt: number().nullable()
17150
17158
  });
17151
17159
  /** Operator/diagnostic view: rows per tier, last runs, refusals and drops since boot. */
17160
+ /**
17161
+ * Why a series is orphan. `device-gone`: its device is absent from the
17162
+ * successful device listings (the departure clock). `undeclared`: its `cap:`
17163
+ * key is declared by no capability any more (a field a cap removed).
17164
+ */
17165
+ var DeviceHistoryOrphanReasonSchema = _enum(["device-gone", "undeclared"]);
17166
+ /** Rows held per stored tier. */
17167
+ var TierRowsSchema = object({
17168
+ raw: number().int(),
17169
+ "5m": number().int(),
17170
+ "1h": number().int(),
17171
+ "1d": number().int()
17172
+ });
17173
+ var OrphanSeriesSchema = object({
17174
+ seriesId: number().int(),
17175
+ deviceId: number().int(),
17176
+ key: string(),
17177
+ scope: string(),
17178
+ /** The metric's display name; `null` when its metric row is gone too. */
17179
+ displayName: string().nullable(),
17180
+ reason: DeviceHistoryOrphanReasonSchema,
17181
+ /** `device-gone`: since when the device has been absent; `null` otherwise. */
17182
+ missingSince: number().nullable(),
17183
+ firstTs: number(),
17184
+ lastTs: number(),
17185
+ rows: TierRowsSchema
17186
+ });
17187
+ var DeviceHistoryOrphanDeleteRefusalSchema = _enum([
17188
+ "not-found",
17189
+ "not-orphan",
17190
+ "failed"
17191
+ ]);
17192
+ var OrphanDeleteEntrySchema = discriminatedUnion("ok", [object({
17193
+ seriesId: number().int(),
17194
+ ok: literal(true),
17195
+ deleted: TierRowsSchema
17196
+ }), object({
17197
+ seriesId: number().int(),
17198
+ ok: literal(false),
17199
+ reason: DeviceHistoryOrphanDeleteRefusalSchema
17200
+ })]);
17201
+ var OrphanListSchema = object({
17202
+ series: array(OrphanSeriesSchema).readonly(),
17203
+ /** More orphans exist than {@link DEVICE_HISTORY_ORPHAN_LIST_MAX}. */
17204
+ truncated: boolean()
17205
+ });
17152
17206
  var DeviceHistoryStatusSchema = object({
17153
17207
  startedAt: number(),
17154
17208
  /** The store is declared, series loaded and the first reconcile has answered. */
@@ -17246,7 +17300,10 @@ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly())
17246
17300
  }), object({ enabled: boolean() }), {
17247
17301
  kind: "mutation",
17248
17302
  auth: "admin"
17249
- }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" });
17303
+ }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" }), method(object({}), OrphanListSchema, { auth: "admin" }), method(object({ seriesIds: array(number().int()).min(1).max(50) }), object({ results: array(OrphanDeleteEntrySchema).readonly() }), {
17304
+ kind: "mutation",
17305
+ auth: "admin"
17306
+ });
17250
17307
  var DeviceCaStatusSchema = discriminatedUnion("state", [
17251
17308
  object({ state: literal("absent") }),
17252
17309
  object({
@@ -55202,17 +55259,69 @@ var connectivityCapability = {
55202
55259
  volatileStateFields: ["lastChangedAt"]
55203
55260
  };
55204
55261
  /**
55205
- * Generic device-consumables capability — surfaces a device's
55206
- * maintenance items (vacuum filters/brushes, replaceable cartridges,
55207
- * descaling cycles, …) with their remaining life and an optional
55208
- * "Replaced" reset action. Device-agnostic: any provider that knows its
55209
- * device tracks consumables can register it; the cap declares no
55210
- * vocabulary of its own — the provider names each item verbatim.
55262
+ * Generic device-consumables capability — the ONE place a device reports what
55263
+ * it uses up or fills: wear parts (vacuum filters/brushes, cartridges,
55264
+ * descaling cycles), supplies it draws from (a vacuum's clean-water tank and
55265
+ * detergent, a dishwasher's salt and rinse aid) and waste it collects (a dirty
55266
+ * water tank, a dust bin). Each item carries its remaining life or fill and an
55267
+ * optional "Replaced" reset action. Device-agnostic: any provider that knows
55268
+ * its device tracks consumables registers it; the provider names each item
55269
+ * verbatim and says which `kind` it is.
55270
+ *
55271
+ * The admin UI renders it as ONE collapsible section directly under the
55272
+ * device page's hero card (`placement: 'hero'`), for every device bound to
55273
+ * this cap — never drawn by a device type's hero card itself (D915).
55211
55274
  *
55212
55275
  * Like `childLayout`, the cap is INERT until a provider sets items: no
55213
55276
  * provider populates it by guessing (no HA inference). The UI renders a
55214
55277
  * "No consumables reported" placeholder when `items` is empty.
55215
55278
  */
55279
+ /**
55280
+ * What an item IS, which decides which direction is bad:
55281
+ * - `wear` — a part that wears out (a brush, a filter); low life is bad.
55282
+ * - `supply` — something the device draws from (clean water, detergent,
55283
+ * salt, rinse aid); low or empty is bad.
55284
+ * - `waste` — something the device fills (dirty water, a dust bin); full is
55285
+ * bad.
55286
+ * Absent = `wear`.
55287
+ */
55288
+ var ConsumableKindSchema = _enum([
55289
+ "wear",
55290
+ "supply",
55291
+ "waste"
55292
+ ]);
55293
+ /**
55294
+ * What an item LOOKS like, which decides how a client draws it — independent
55295
+ * of `kind`, which decides which direction is bad:
55296
+ * - `part` — a part that wears (a brush, a filter, a mop pad): a wear bar,
55297
+ * remaining time and a reset.
55298
+ * - `tank` — a container of liquid (clean water, dirty water): a fill gauge.
55299
+ * - `product` — something bought and refilled (detergent, salt, rinse aid):
55300
+ * a stepped level and "refill".
55301
+ * - `bin` — a container that collects waste (a dust bin): a fill gauge
55302
+ * that warns when full.
55303
+ * Absent = derived from the kind ({@link consumableFormOf}).
55304
+ */
55305
+ var ConsumableFormSchema = _enum([
55306
+ "part",
55307
+ "tank",
55308
+ "product",
55309
+ "bin"
55310
+ ]);
55311
+ /** The provider's own discrete verdict on an item. */
55312
+ var ConsumableStatusSchema = _enum([
55313
+ "ok",
55314
+ "low",
55315
+ "empty",
55316
+ "full",
55317
+ "replace"
55318
+ ]);
55319
+ _enum([
55320
+ "ok",
55321
+ "low",
55322
+ "empty",
55323
+ "full"
55324
+ ]);
55216
55325
  /** Units a remaining-life counter is reported in. Closed: the panel renders
55217
55326
  * each. */
55218
55327
  var ConsumableRemainingUnitSchema = _enum([
@@ -55227,18 +55336,23 @@ var ConsumableRemainingSchema = object({
55227
55336
  unit: ConsumableRemainingUnitSchema
55228
55337
  });
55229
55338
  /** A single consumable item. Either a continuous `level` (remaining
55230
- * life %) or a discrete `status` may be known — both may be null when a
55231
- * provider only knows the item exists. `level` and `status` are not
55232
- * mutually exclusive; a provider may report both. */
55339
+ * life %, or fill % for a `supply` / `waste` item) or a discrete `status`
55340
+ * may be known — both may be null when a provider only knows the item
55341
+ * exists. `level` and `status` are not mutually exclusive; a provider may
55342
+ * report both. */
55233
55343
  var ConsumableItemSchema = object({
55234
55344
  /** Stable id, e.g. 'main-brush'. */
55235
55345
  key: string().min(1),
55236
55346
  /** Display name. */
55237
55347
  label: string().min(1),
55238
- /** Remaining life % when known (0..100). */
55348
+ /** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
55239
55349
  level: number().min(0).max(100).nullable(),
55240
- /** Discrete state when known (binary mode). */
55241
- status: _enum(["ok", "replace"]).nullable(),
55350
+ /** The provider's discrete verdict when known (binary mode). */
55351
+ status: ConsumableStatusSchema.nullable(),
55352
+ /** What the item is — decides whether low or full is bad. Absent = `wear`. */
55353
+ kind: ConsumableKindSchema.optional(),
55354
+ /** How the item is drawn (part, tank, product, bin). Absent = derived from `kind`. */
55355
+ form: ConsumableFormSchema.optional(),
55242
55356
  /** Ms epoch of the last replace, when known. */
55243
55357
  lastResetAt: number().nullable(),
55244
55358
  /** Whether `reset()` is meaningful for this item. */
@@ -55261,7 +55375,7 @@ var consumablesCapability = {
55261
55375
  kind: "widget",
55262
55376
  widgetId: "host/consumables-panel",
55263
55377
  tab: "consumables",
55264
- topTab: true,
55378
+ placement: "hero",
55265
55379
  label: "Consumables",
55266
55380
  order: 5
55267
55381
  } },
@@ -55322,9 +55436,37 @@ reset: method(object({
55322
55436
  */
55323
55437
  durability: "restored",
55324
55438
  /**
55325
- * History (D850): none — `items` is an array keyed by runtime ids; a history path never enters it.
55439
+ * History (D850, D917): one series per (item field, item `key`) — the item key
55440
+ * is the series scope, the item `label` names it. A vacuum tank's fill, a
55441
+ * brush's remaining life and a dishwasher's salt are each recorded the moment
55442
+ * their provider reports them; an item that appears later gets its series.
55326
55443
  */
55327
- history: "none",
55444
+ history: {
55445
+ fields: {},
55446
+ items: {
55447
+ path: "items",
55448
+ key: "key",
55449
+ label: "label",
55450
+ fields: {
55451
+ level: {
55452
+ kind: "gauge",
55453
+ unit: "%",
55454
+ deadband: 2,
55455
+ displayName: "Level"
55456
+ },
55457
+ status: {
55458
+ kind: "enum",
55459
+ displayName: "Status"
55460
+ },
55461
+ "remaining.value": {
55462
+ kind: "gauge",
55463
+ unitFrom: "remaining.unit",
55464
+ deadband: 1,
55465
+ displayName: "Remaining"
55466
+ }
55467
+ }
55468
+ }
55469
+ },
55328
55470
  /** Clocks, not content: a re-read that changed no item costs no commit. */
55329
55471
  volatileStateFields: ["lastChangedAt", "lastFetchedAt"]
55330
55472
  };
@@ -55739,8 +55881,9 @@ onStatusChanged: { data: object({
55739
55881
  volatileStateFields: ["lastChangedAt"]
55740
55882
  };
55741
55883
  /**
55742
- * Smart-dishwasher cap — program lifecycle, door / remote-start gates,
55743
- * consumable levels (salt, rinse aid) and common program options.
55884
+ * Smart-dishwasher cap — program lifecycle, door / remote-start gates and
55885
+ * common program options. Salt and rinse aid are NOT here: they are items of
55886
+ * the device's `consumables` cap, like every other device's (D915).
55744
55887
  *
55745
55888
  * Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
55746
55889
  * by any integration that exposes the same program / option surface.
@@ -55788,11 +55931,6 @@ var DishwasherAvailabilitySchema = _enum([
55788
55931
  "offline",
55789
55932
  "description-missing"
55790
55933
  ]);
55791
- var DishwasherConsumableLevelSchema = _enum([
55792
- "ok",
55793
- "low",
55794
- "empty"
55795
- ]);
55796
55934
  var DishwasherStatusSchema = object({
55797
55935
  availability: DishwasherAvailabilitySchema,
55798
55936
  /** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
@@ -55825,8 +55963,6 @@ var DishwasherStatusSchema = object({
55825
55963
  powerOn: boolean().nullable(),
55826
55964
  /** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
55827
55965
  powerState: string().nullable(),
55828
- saltLevel: DishwasherConsumableLevelSchema.nullable(),
55829
- rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
55830
55966
  /**
55831
55967
  * True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
55832
55968
  * combined care-and-filter reminder raised); false when every such reminder reads clear; null
@@ -64642,60 +64778,17 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
64642
64778
  auth: "admin",
64643
64779
  access: "delete"
64644
64780
  });
64645
- /**
64646
- * Robot-vacuum cap. Models HA `vacuum.*` entities — anything with a
64647
- * cleaning lifecycle plus a return-to-base / locate surface and an
64648
- * optional fan-speed selector.
64649
- *
64650
- * State follows HA's canonical vacuum lifecycle: `idle` / `cleaning` /
64651
- * `paused` / `returning` / `docked` / `error`. `batteryLevel`
64652
- * (0..100) is nullable — some vacuums don't report a battery
64653
- * percentage. `fanSpeed` is the current speed token (provider-verbatim,
64654
- * e.g. `'standard'` / `'turbo'`) and `availableFanSpeeds` lists the
64655
- * tokens the hardware accepts so the UI renders only supported choices.
64656
- *
64657
- * The `setFanSpeed` method takes the bare `speed` token — the provider
64658
- * validates it against the vacuum's own list. `locate` triggers the
64659
- * find-me chirp; `returnToBase` sends it home.
64660
- *
64661
- * Consumable / waste tanks: `cleanWater` / `dirtyWater` / `detergent` /
64662
- * `dustBin` each carry a nullable `{ level (0..100 %), status ('ok' |
64663
- * 'low' | 'full') }` reading. Native providers (e.g. Dreame, Roborock)
64664
- * SHOULD populate whichever tanks the hardware has — leave a field `null`
64665
- * only when the device has no such tank at all, and use a `TankStatus`
64666
- * with both inner fields `null` when the tank exists but its level is
64667
- * currently unknown. HA `vacuum.*` entities expose no per-tank telemetry,
64668
- * so the HA provider leaves all four `null`.
64669
- */
64670
- var VacuumStateSchema = _enum([
64671
- "idle",
64672
- "cleaning",
64673
- "paused",
64674
- "returning",
64675
- "docked",
64676
- "drying",
64677
- "error"
64678
- ]);
64679
- /**
64680
- * One consumable / waste tank on a robot vacuum (clean-water, dirty-water,
64681
- * detergent or dust-bin). A tank can report a numeric fill `level` (0..100),
64682
- * a discrete `status` (binary-style hardware), or both. Both `null` means the
64683
- * level is currently unknown; the OWNING field being `null` means the
64684
- * hardware has no such tank at all.
64685
- */
64686
- var TankStatusSchema = object({
64687
- /** Numeric fill 0..100 when the hardware reports a percentage; null otherwise. */
64688
- level: number().min(0).max(100).nullable(),
64689
- /** Discrete state when the hardware is binary-mode; null otherwise. */
64690
- status: _enum([
64691
- "ok",
64692
- "low",
64693
- "full"
64694
- ]).nullable()
64695
- });
64696
64781
  var VacuumControlStatusSchema = object({
64697
64782
  /** Lifecycle state of the vacuum. */
64698
- state: VacuumStateSchema,
64783
+ state: _enum([
64784
+ "idle",
64785
+ "cleaning",
64786
+ "paused",
64787
+ "returning",
64788
+ "docked",
64789
+ "drying",
64790
+ "error"
64791
+ ]),
64699
64792
  /** 0..100 battery percentage. Null when the device has no battery
64700
64793
  * reading. */
64701
64794
  batteryLevel: number().min(0).max(100).nullable(),
@@ -64704,14 +64797,6 @@ var VacuumControlStatusSchema = object({
64704
64797
  fanSpeed: string().nullable(),
64705
64798
  /** Speed tokens the hardware accepts — drives the UI selector. */
64706
64799
  availableFanSpeeds: array(string()),
64707
- /** Clean-water (mop) tank. Null when the hardware has no clean-water tank. */
64708
- cleanWater: TankStatusSchema.nullable(),
64709
- /** Dirty-water (recovery) tank. Null when the hardware has no dirty-water tank. */
64710
- dirtyWater: TankStatusSchema.nullable(),
64711
- /** Detergent tank. Null when the hardware has no detergent tank. */
64712
- detergent: TankStatusSchema.nullable(),
64713
- /** Dust bin. Null when the hardware has no dust bin. */
64714
- dustBin: TankStatusSchema.nullable(),
64715
64800
  /** 0..100 cleaning-completion percentage of the current task, or null. */
64716
64801
  progressPercent: number().min(0).max(100).nullable(),
64717
64802
  /** Current error code (0 / null = no error). */
@@ -64773,35 +64858,14 @@ var vacuumControlCapability = {
64773
64858
  */
64774
64859
  durability: "session",
64775
64860
  /**
64776
- * History (D850): recorded series. Tank levels are fixed-object paths (`cleanWater.level`, ...).
64861
+ * History (D850): recorded series. The tanks moved to `consumables` (D915), whose
64862
+ * items are keyed by runtime ids and record no history.
64777
64863
  */
64778
- history: { fields: {
64779
- batteryLevel: {
64780
- kind: "gauge",
64781
- unit: "%",
64782
- deadband: 2
64783
- },
64784
- "cleanWater.level": {
64785
- kind: "gauge",
64786
- unit: "%",
64787
- deadband: 2
64788
- },
64789
- "dirtyWater.level": {
64790
- kind: "gauge",
64791
- unit: "%",
64792
- deadband: 2
64793
- },
64794
- "detergent.level": {
64795
- kind: "gauge",
64796
- unit: "%",
64797
- deadband: 2
64798
- },
64799
- "dustBin.level": {
64800
- kind: "gauge",
64801
- unit: "%",
64802
- deadband: 2
64803
- }
64804
- } }
64864
+ history: { fields: { batteryLevel: {
64865
+ kind: "gauge",
64866
+ unit: "%",
64867
+ deadband: 2
64868
+ } } }
64805
64869
  };
64806
64870
  var ValveStatusSchema = object({
64807
64871
  /** Lifecycle state of the valve. */
@@ -69195,6 +69259,12 @@ Object.freeze({
69195
69259
  addonId: null,
69196
69260
  access: "create"
69197
69261
  },
69262
+ "deviceHistory.deleteOrphanSeries": {
69263
+ capName: "device-history",
69264
+ capScope: "system",
69265
+ addonId: null,
69266
+ access: "delete"
69267
+ },
69198
69268
  "deviceHistory.getDeviceEnabled": {
69199
69269
  capName: "device-history",
69200
69270
  capScope: "system",
@@ -69213,6 +69283,12 @@ Object.freeze({
69213
69283
  addonId: null,
69214
69284
  access: "view"
69215
69285
  },
69286
+ "deviceHistory.listOrphanSeries": {
69287
+ capName: "device-history",
69288
+ capScope: "system",
69289
+ addonId: null,
69290
+ access: "view"
69291
+ },
69216
69292
  "deviceHistory.listSeries": {
69217
69293
  capName: "device-history",
69218
69294
  capScope: "system",
@@ -79218,7 +79294,7 @@ var STATE_SUMMARY_VARS = [
79218
79294
  ([...RULE_TEXT], [...COMBINED_ALARM]),
79219
79295
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
79220
79296
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
79221
- ([...RULE_TEXT], [...CONSUMABLE]),
79297
+ ([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
79222
79298
  ([...RULE_TEXT], [...TANK]),
79223
79299
  [...RULE_TEXT],
79224
79300
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-velux",
3
- "version": "0.2.143",
3
+ "version": "0.2.144",
4
4
  "description": "Velux KLF-200 device-provider addon for CamStack — local-gateway window + shutter covers (positional, no tilt)",
5
5
  "keywords": [
6
6
  "camstack",