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