@camstack/addon-provider-ecowitt 0.2.142 → 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 -123
  2. package/dist/addon.mjs +193 -123
  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({
@@ -48074,7 +48131,6 @@ var RecommendationReasonSchema = discriminatedUnion("kind", [
48074
48131
  modelId: string()
48075
48132
  }),
48076
48133
  object({ kind: literal("cpu-device") }),
48077
- object({ kind: literal("coral-untouched") }),
48078
48134
  object({ kind: literal("device-disabled") }),
48079
48135
  object({ kind: literal("device-unavailable") }),
48080
48136
  object({ kind: literal("node-offline") }),
@@ -48172,11 +48228,6 @@ var AutoTuneWarningSchema = discriminatedUnion("kind", [
48172
48228
  kind: literal("detector-store-unreadable"),
48173
48229
  error: string()
48174
48230
  }),
48175
- object({
48176
- kind: literal("coral-enabled"),
48177
- nodeId: string(),
48178
- deviceKey: string()
48179
- }),
48180
48231
  object({
48181
48232
  kind: literal("custom-pin-kept"),
48182
48233
  nodeId: string(),
@@ -55212,17 +55263,69 @@ var connectivityCapability = {
55212
55263
  volatileStateFields: ["lastChangedAt"]
55213
55264
  };
55214
55265
  /**
55215
- * Generic device-consumables capability — surfaces a device's
55216
- * maintenance items (vacuum filters/brushes, replaceable cartridges,
55217
- * descaling cycles, …) with their remaining life and an optional
55218
- * "Replaced" reset action. Device-agnostic: any provider that knows its
55219
- * device tracks consumables can register it; the cap declares no
55220
- * 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).
55221
55278
  *
55222
55279
  * Like `childLayout`, the cap is INERT until a provider sets items: no
55223
55280
  * provider populates it by guessing (no HA inference). The UI renders a
55224
55281
  * "No consumables reported" placeholder when `items` is empty.
55225
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
+ ]);
55226
55329
  /** Units a remaining-life counter is reported in. Closed: the panel renders
55227
55330
  * each. */
55228
55331
  var ConsumableRemainingUnitSchema = _enum([
@@ -55237,18 +55340,23 @@ var ConsumableRemainingSchema = object({
55237
55340
  unit: ConsumableRemainingUnitSchema
55238
55341
  });
55239
55342
  /** A single consumable item. Either a continuous `level` (remaining
55240
- * life %) or a discrete `status` may be known — both may be null when a
55241
- * provider only knows the item exists. `level` and `status` are not
55242
- * 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. */
55243
55347
  var ConsumableItemSchema = object({
55244
55348
  /** Stable id, e.g. 'main-brush'. */
55245
55349
  key: string().min(1),
55246
55350
  /** Display name. */
55247
55351
  label: string().min(1),
55248
- /** Remaining life % when known (0..100). */
55352
+ /** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
55249
55353
  level: number().min(0).max(100).nullable(),
55250
- /** Discrete state when known (binary mode). */
55251
- 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(),
55252
55360
  /** Ms epoch of the last replace, when known. */
55253
55361
  lastResetAt: number().nullable(),
55254
55362
  /** Whether `reset()` is meaningful for this item. */
@@ -55271,7 +55379,7 @@ var consumablesCapability = {
55271
55379
  kind: "widget",
55272
55380
  widgetId: "host/consumables-panel",
55273
55381
  tab: "consumables",
55274
- topTab: true,
55382
+ placement: "hero",
55275
55383
  label: "Consumables",
55276
55384
  order: 5
55277
55385
  } },
@@ -55332,9 +55440,37 @@ reset: method(object({
55332
55440
  */
55333
55441
  durability: "restored",
55334
55442
  /**
55335
- * 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.
55336
55447
  */
55337
- 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
+ },
55338
55474
  /** Clocks, not content: a re-read that changed no item costs no commit. */
55339
55475
  volatileStateFields: ["lastChangedAt", "lastFetchedAt"]
55340
55476
  };
@@ -55749,8 +55885,9 @@ onStatusChanged: { data: object({
55749
55885
  volatileStateFields: ["lastChangedAt"]
55750
55886
  };
55751
55887
  /**
55752
- * Smart-dishwasher cap — program lifecycle, door / remote-start gates,
55753
- * 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).
55754
55891
  *
55755
55892
  * Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
55756
55893
  * by any integration that exposes the same program / option surface.
@@ -55798,11 +55935,6 @@ var DishwasherAvailabilitySchema = _enum([
55798
55935
  "offline",
55799
55936
  "description-missing"
55800
55937
  ]);
55801
- var DishwasherConsumableLevelSchema = _enum([
55802
- "ok",
55803
- "low",
55804
- "empty"
55805
- ]);
55806
55938
  var DishwasherStatusSchema = object({
55807
55939
  availability: DishwasherAvailabilitySchema,
55808
55940
  /** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
@@ -55835,8 +55967,6 @@ var DishwasherStatusSchema = object({
55835
55967
  powerOn: boolean().nullable(),
55836
55968
  /** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
55837
55969
  powerState: string().nullable(),
55838
- saltLevel: DishwasherConsumableLevelSchema.nullable(),
55839
- rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
55840
55970
  /**
55841
55971
  * True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
55842
55972
  * combined care-and-filter reminder raised); false when every such reminder reads clear; null
@@ -64652,60 +64782,17 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
64652
64782
  auth: "admin",
64653
64783
  access: "delete"
64654
64784
  });
64655
- /**
64656
- * Robot-vacuum cap. Models HA `vacuum.*` entities — anything with a
64657
- * cleaning lifecycle plus a return-to-base / locate surface and an
64658
- * optional fan-speed selector.
64659
- *
64660
- * State follows HA's canonical vacuum lifecycle: `idle` / `cleaning` /
64661
- * `paused` / `returning` / `docked` / `error`. `batteryLevel`
64662
- * (0..100) is nullable — some vacuums don't report a battery
64663
- * percentage. `fanSpeed` is the current speed token (provider-verbatim,
64664
- * e.g. `'standard'` / `'turbo'`) and `availableFanSpeeds` lists the
64665
- * tokens the hardware accepts so the UI renders only supported choices.
64666
- *
64667
- * The `setFanSpeed` method takes the bare `speed` token — the provider
64668
- * validates it against the vacuum's own list. `locate` triggers the
64669
- * find-me chirp; `returnToBase` sends it home.
64670
- *
64671
- * Consumable / waste tanks: `cleanWater` / `dirtyWater` / `detergent` /
64672
- * `dustBin` each carry a nullable `{ level (0..100 %), status ('ok' |
64673
- * 'low' | 'full') }` reading. Native providers (e.g. Dreame, Roborock)
64674
- * SHOULD populate whichever tanks the hardware has — leave a field `null`
64675
- * only when the device has no such tank at all, and use a `TankStatus`
64676
- * with both inner fields `null` when the tank exists but its level is
64677
- * currently unknown. HA `vacuum.*` entities expose no per-tank telemetry,
64678
- * so the HA provider leaves all four `null`.
64679
- */
64680
- var VacuumStateSchema = _enum([
64681
- "idle",
64682
- "cleaning",
64683
- "paused",
64684
- "returning",
64685
- "docked",
64686
- "drying",
64687
- "error"
64688
- ]);
64689
- /**
64690
- * One consumable / waste tank on a robot vacuum (clean-water, dirty-water,
64691
- * detergent or dust-bin). A tank can report a numeric fill `level` (0..100),
64692
- * a discrete `status` (binary-style hardware), or both. Both `null` means the
64693
- * level is currently unknown; the OWNING field being `null` means the
64694
- * hardware has no such tank at all.
64695
- */
64696
- var TankStatusSchema = object({
64697
- /** Numeric fill 0..100 when the hardware reports a percentage; null otherwise. */
64698
- level: number().min(0).max(100).nullable(),
64699
- /** Discrete state when the hardware is binary-mode; null otherwise. */
64700
- status: _enum([
64701
- "ok",
64702
- "low",
64703
- "full"
64704
- ]).nullable()
64705
- });
64706
64785
  var VacuumControlStatusSchema = object({
64707
64786
  /** Lifecycle state of the vacuum. */
64708
- state: VacuumStateSchema,
64787
+ state: _enum([
64788
+ "idle",
64789
+ "cleaning",
64790
+ "paused",
64791
+ "returning",
64792
+ "docked",
64793
+ "drying",
64794
+ "error"
64795
+ ]),
64709
64796
  /** 0..100 battery percentage. Null when the device has no battery
64710
64797
  * reading. */
64711
64798
  batteryLevel: number().min(0).max(100).nullable(),
@@ -64714,14 +64801,6 @@ var VacuumControlStatusSchema = object({
64714
64801
  fanSpeed: string().nullable(),
64715
64802
  /** Speed tokens the hardware accepts — drives the UI selector. */
64716
64803
  availableFanSpeeds: array(string()),
64717
- /** Clean-water (mop) tank. Null when the hardware has no clean-water tank. */
64718
- cleanWater: TankStatusSchema.nullable(),
64719
- /** Dirty-water (recovery) tank. Null when the hardware has no dirty-water tank. */
64720
- dirtyWater: TankStatusSchema.nullable(),
64721
- /** Detergent tank. Null when the hardware has no detergent tank. */
64722
- detergent: TankStatusSchema.nullable(),
64723
- /** Dust bin. Null when the hardware has no dust bin. */
64724
- dustBin: TankStatusSchema.nullable(),
64725
64804
  /** 0..100 cleaning-completion percentage of the current task, or null. */
64726
64805
  progressPercent: number().min(0).max(100).nullable(),
64727
64806
  /** Current error code (0 / null = no error). */
@@ -64783,35 +64862,14 @@ var vacuumControlCapability = {
64783
64862
  */
64784
64863
  durability: "session",
64785
64864
  /**
64786
- * 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.
64787
64867
  */
64788
- history: { fields: {
64789
- batteryLevel: {
64790
- kind: "gauge",
64791
- unit: "%",
64792
- deadband: 2
64793
- },
64794
- "cleanWater.level": {
64795
- kind: "gauge",
64796
- unit: "%",
64797
- deadband: 2
64798
- },
64799
- "dirtyWater.level": {
64800
- kind: "gauge",
64801
- unit: "%",
64802
- deadband: 2
64803
- },
64804
- "detergent.level": {
64805
- kind: "gauge",
64806
- unit: "%",
64807
- deadband: 2
64808
- },
64809
- "dustBin.level": {
64810
- kind: "gauge",
64811
- unit: "%",
64812
- deadband: 2
64813
- }
64814
- } }
64868
+ history: { fields: { batteryLevel: {
64869
+ kind: "gauge",
64870
+ unit: "%",
64871
+ deadband: 2
64872
+ } } }
64815
64873
  };
64816
64874
  var ValveStatusSchema = object({
64817
64875
  /** Lifecycle state of the valve. */
@@ -69205,6 +69263,12 @@ Object.freeze({
69205
69263
  addonId: null,
69206
69264
  access: "create"
69207
69265
  },
69266
+ "deviceHistory.deleteOrphanSeries": {
69267
+ capName: "device-history",
69268
+ capScope: "system",
69269
+ addonId: null,
69270
+ access: "delete"
69271
+ },
69208
69272
  "deviceHistory.getDeviceEnabled": {
69209
69273
  capName: "device-history",
69210
69274
  capScope: "system",
@@ -69223,6 +69287,12 @@ Object.freeze({
69223
69287
  addonId: null,
69224
69288
  access: "view"
69225
69289
  },
69290
+ "deviceHistory.listOrphanSeries": {
69291
+ capName: "device-history",
69292
+ capScope: "system",
69293
+ addonId: null,
69294
+ access: "view"
69295
+ },
69226
69296
  "deviceHistory.listSeries": {
69227
69297
  capName: "device-history",
69228
69298
  capScope: "system",
@@ -79228,7 +79298,7 @@ var STATE_SUMMARY_VARS = [
79228
79298
  ([...RULE_TEXT], [...COMBINED_ALARM]),
79229
79299
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
79230
79300
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
79231
- ([...RULE_TEXT], [...CONSUMABLE]),
79301
+ ([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
79232
79302
  ([...RULE_TEXT], [...TANK]),
79233
79303
  [...RULE_TEXT],
79234
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({
@@ -48073,7 +48130,6 @@ var RecommendationReasonSchema = discriminatedUnion("kind", [
48073
48130
  modelId: string()
48074
48131
  }),
48075
48132
  object({ kind: literal("cpu-device") }),
48076
- object({ kind: literal("coral-untouched") }),
48077
48133
  object({ kind: literal("device-disabled") }),
48078
48134
  object({ kind: literal("device-unavailable") }),
48079
48135
  object({ kind: literal("node-offline") }),
@@ -48171,11 +48227,6 @@ var AutoTuneWarningSchema = discriminatedUnion("kind", [
48171
48227
  kind: literal("detector-store-unreadable"),
48172
48228
  error: string()
48173
48229
  }),
48174
- object({
48175
- kind: literal("coral-enabled"),
48176
- nodeId: string(),
48177
- deviceKey: string()
48178
- }),
48179
48230
  object({
48180
48231
  kind: literal("custom-pin-kept"),
48181
48232
  nodeId: string(),
@@ -55211,17 +55262,69 @@ var connectivityCapability = {
55211
55262
  volatileStateFields: ["lastChangedAt"]
55212
55263
  };
55213
55264
  /**
55214
- * Generic device-consumables capability — surfaces a device's
55215
- * maintenance items (vacuum filters/brushes, replaceable cartridges,
55216
- * descaling cycles, …) with their remaining life and an optional
55217
- * "Replaced" reset action. Device-agnostic: any provider that knows its
55218
- * device tracks consumables can register it; the cap declares no
55219
- * 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).
55220
55277
  *
55221
55278
  * Like `childLayout`, the cap is INERT until a provider sets items: no
55222
55279
  * provider populates it by guessing (no HA inference). The UI renders a
55223
55280
  * "No consumables reported" placeholder when `items` is empty.
55224
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
+ ]);
55225
55328
  /** Units a remaining-life counter is reported in. Closed: the panel renders
55226
55329
  * each. */
55227
55330
  var ConsumableRemainingUnitSchema = _enum([
@@ -55236,18 +55339,23 @@ var ConsumableRemainingSchema = object({
55236
55339
  unit: ConsumableRemainingUnitSchema
55237
55340
  });
55238
55341
  /** A single consumable item. Either a continuous `level` (remaining
55239
- * life %) or a discrete `status` may be known — both may be null when a
55240
- * provider only knows the item exists. `level` and `status` are not
55241
- * 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. */
55242
55346
  var ConsumableItemSchema = object({
55243
55347
  /** Stable id, e.g. 'main-brush'. */
55244
55348
  key: string().min(1),
55245
55349
  /** Display name. */
55246
55350
  label: string().min(1),
55247
- /** Remaining life % when known (0..100). */
55351
+ /** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
55248
55352
  level: number().min(0).max(100).nullable(),
55249
- /** Discrete state when known (binary mode). */
55250
- 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(),
55251
55359
  /** Ms epoch of the last replace, when known. */
55252
55360
  lastResetAt: number().nullable(),
55253
55361
  /** Whether `reset()` is meaningful for this item. */
@@ -55270,7 +55378,7 @@ var consumablesCapability = {
55270
55378
  kind: "widget",
55271
55379
  widgetId: "host/consumables-panel",
55272
55380
  tab: "consumables",
55273
- topTab: true,
55381
+ placement: "hero",
55274
55382
  label: "Consumables",
55275
55383
  order: 5
55276
55384
  } },
@@ -55331,9 +55439,37 @@ reset: method(object({
55331
55439
  */
55332
55440
  durability: "restored",
55333
55441
  /**
55334
- * 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.
55335
55446
  */
55336
- 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
+ },
55337
55473
  /** Clocks, not content: a re-read that changed no item costs no commit. */
55338
55474
  volatileStateFields: ["lastChangedAt", "lastFetchedAt"]
55339
55475
  };
@@ -55748,8 +55884,9 @@ onStatusChanged: { data: object({
55748
55884
  volatileStateFields: ["lastChangedAt"]
55749
55885
  };
55750
55886
  /**
55751
- * Smart-dishwasher cap — program lifecycle, door / remote-start gates,
55752
- * 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).
55753
55890
  *
55754
55891
  * Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
55755
55892
  * by any integration that exposes the same program / option surface.
@@ -55797,11 +55934,6 @@ var DishwasherAvailabilitySchema = _enum([
55797
55934
  "offline",
55798
55935
  "description-missing"
55799
55936
  ]);
55800
- var DishwasherConsumableLevelSchema = _enum([
55801
- "ok",
55802
- "low",
55803
- "empty"
55804
- ]);
55805
55937
  var DishwasherStatusSchema = object({
55806
55938
  availability: DishwasherAvailabilitySchema,
55807
55939
  /** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
@@ -55834,8 +55966,6 @@ var DishwasherStatusSchema = object({
55834
55966
  powerOn: boolean().nullable(),
55835
55967
  /** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
55836
55968
  powerState: string().nullable(),
55837
- saltLevel: DishwasherConsumableLevelSchema.nullable(),
55838
- rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
55839
55969
  /**
55840
55970
  * True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
55841
55971
  * combined care-and-filter reminder raised); false when every such reminder reads clear; null
@@ -64651,60 +64781,17 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
64651
64781
  auth: "admin",
64652
64782
  access: "delete"
64653
64783
  });
64654
- /**
64655
- * Robot-vacuum cap. Models HA `vacuum.*` entities — anything with a
64656
- * cleaning lifecycle plus a return-to-base / locate surface and an
64657
- * optional fan-speed selector.
64658
- *
64659
- * State follows HA's canonical vacuum lifecycle: `idle` / `cleaning` /
64660
- * `paused` / `returning` / `docked` / `error`. `batteryLevel`
64661
- * (0..100) is nullable — some vacuums don't report a battery
64662
- * percentage. `fanSpeed` is the current speed token (provider-verbatim,
64663
- * e.g. `'standard'` / `'turbo'`) and `availableFanSpeeds` lists the
64664
- * tokens the hardware accepts so the UI renders only supported choices.
64665
- *
64666
- * The `setFanSpeed` method takes the bare `speed` token — the provider
64667
- * validates it against the vacuum's own list. `locate` triggers the
64668
- * find-me chirp; `returnToBase` sends it home.
64669
- *
64670
- * Consumable / waste tanks: `cleanWater` / `dirtyWater` / `detergent` /
64671
- * `dustBin` each carry a nullable `{ level (0..100 %), status ('ok' |
64672
- * 'low' | 'full') }` reading. Native providers (e.g. Dreame, Roborock)
64673
- * SHOULD populate whichever tanks the hardware has — leave a field `null`
64674
- * only when the device has no such tank at all, and use a `TankStatus`
64675
- * with both inner fields `null` when the tank exists but its level is
64676
- * currently unknown. HA `vacuum.*` entities expose no per-tank telemetry,
64677
- * so the HA provider leaves all four `null`.
64678
- */
64679
- var VacuumStateSchema = _enum([
64680
- "idle",
64681
- "cleaning",
64682
- "paused",
64683
- "returning",
64684
- "docked",
64685
- "drying",
64686
- "error"
64687
- ]);
64688
- /**
64689
- * One consumable / waste tank on a robot vacuum (clean-water, dirty-water,
64690
- * detergent or dust-bin). A tank can report a numeric fill `level` (0..100),
64691
- * a discrete `status` (binary-style hardware), or both. Both `null` means the
64692
- * level is currently unknown; the OWNING field being `null` means the
64693
- * hardware has no such tank at all.
64694
- */
64695
- var TankStatusSchema = object({
64696
- /** Numeric fill 0..100 when the hardware reports a percentage; null otherwise. */
64697
- level: number().min(0).max(100).nullable(),
64698
- /** Discrete state when the hardware is binary-mode; null otherwise. */
64699
- status: _enum([
64700
- "ok",
64701
- "low",
64702
- "full"
64703
- ]).nullable()
64704
- });
64705
64784
  var VacuumControlStatusSchema = object({
64706
64785
  /** Lifecycle state of the vacuum. */
64707
- state: VacuumStateSchema,
64786
+ state: _enum([
64787
+ "idle",
64788
+ "cleaning",
64789
+ "paused",
64790
+ "returning",
64791
+ "docked",
64792
+ "drying",
64793
+ "error"
64794
+ ]),
64708
64795
  /** 0..100 battery percentage. Null when the device has no battery
64709
64796
  * reading. */
64710
64797
  batteryLevel: number().min(0).max(100).nullable(),
@@ -64713,14 +64800,6 @@ var VacuumControlStatusSchema = object({
64713
64800
  fanSpeed: string().nullable(),
64714
64801
  /** Speed tokens the hardware accepts — drives the UI selector. */
64715
64802
  availableFanSpeeds: array(string()),
64716
- /** Clean-water (mop) tank. Null when the hardware has no clean-water tank. */
64717
- cleanWater: TankStatusSchema.nullable(),
64718
- /** Dirty-water (recovery) tank. Null when the hardware has no dirty-water tank. */
64719
- dirtyWater: TankStatusSchema.nullable(),
64720
- /** Detergent tank. Null when the hardware has no detergent tank. */
64721
- detergent: TankStatusSchema.nullable(),
64722
- /** Dust bin. Null when the hardware has no dust bin. */
64723
- dustBin: TankStatusSchema.nullable(),
64724
64803
  /** 0..100 cleaning-completion percentage of the current task, or null. */
64725
64804
  progressPercent: number().min(0).max(100).nullable(),
64726
64805
  /** Current error code (0 / null = no error). */
@@ -64782,35 +64861,14 @@ var vacuumControlCapability = {
64782
64861
  */
64783
64862
  durability: "session",
64784
64863
  /**
64785
- * 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.
64786
64866
  */
64787
- history: { fields: {
64788
- batteryLevel: {
64789
- kind: "gauge",
64790
- unit: "%",
64791
- deadband: 2
64792
- },
64793
- "cleanWater.level": {
64794
- kind: "gauge",
64795
- unit: "%",
64796
- deadband: 2
64797
- },
64798
- "dirtyWater.level": {
64799
- kind: "gauge",
64800
- unit: "%",
64801
- deadband: 2
64802
- },
64803
- "detergent.level": {
64804
- kind: "gauge",
64805
- unit: "%",
64806
- deadband: 2
64807
- },
64808
- "dustBin.level": {
64809
- kind: "gauge",
64810
- unit: "%",
64811
- deadband: 2
64812
- }
64813
- } }
64867
+ history: { fields: { batteryLevel: {
64868
+ kind: "gauge",
64869
+ unit: "%",
64870
+ deadband: 2
64871
+ } } }
64814
64872
  };
64815
64873
  var ValveStatusSchema = object({
64816
64874
  /** Lifecycle state of the valve. */
@@ -69204,6 +69262,12 @@ Object.freeze({
69204
69262
  addonId: null,
69205
69263
  access: "create"
69206
69264
  },
69265
+ "deviceHistory.deleteOrphanSeries": {
69266
+ capName: "device-history",
69267
+ capScope: "system",
69268
+ addonId: null,
69269
+ access: "delete"
69270
+ },
69207
69271
  "deviceHistory.getDeviceEnabled": {
69208
69272
  capName: "device-history",
69209
69273
  capScope: "system",
@@ -69222,6 +69286,12 @@ Object.freeze({
69222
69286
  addonId: null,
69223
69287
  access: "view"
69224
69288
  },
69289
+ "deviceHistory.listOrphanSeries": {
69290
+ capName: "device-history",
69291
+ capScope: "system",
69292
+ addonId: null,
69293
+ access: "view"
69294
+ },
69225
69295
  "deviceHistory.listSeries": {
69226
69296
  capName: "device-history",
69227
69297
  capScope: "system",
@@ -79227,7 +79297,7 @@ var STATE_SUMMARY_VARS = [
79227
79297
  ([...RULE_TEXT], [...COMBINED_ALARM]),
79228
79298
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
79229
79299
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
79230
- ([...RULE_TEXT], [...CONSUMABLE]),
79300
+ ([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
79231
79301
  ([...RULE_TEXT], [...TANK]),
79232
79302
  [...RULE_TEXT],
79233
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.142",
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",