@camstack/addon-provider-tuya 0.2.142 → 0.2.143

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
@@ -6251,7 +6251,7 @@ var ZodIssueCode = {
6251
6251
  var ZodFirstPartyTypeKind;
6252
6252
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
6253
6253
  //#endregion
6254
- //#region ../types/dist/sleep-DJFUfKvA.mjs
6254
+ //#region ../types/dist/sleep-CUp20JkO.mjs
6255
6255
  /**
6256
6256
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6257
6257
  * window to float samples (D455).
@@ -9143,7 +9143,11 @@ var ContributionSectionSchema = object({
9143
9143
  literal(4)
9144
9144
  ]).optional(),
9145
9145
  tab: string().optional(),
9146
- location: _enum(["settings", "top-tab"]).optional(),
9146
+ location: _enum([
9147
+ "settings",
9148
+ "top-tab",
9149
+ "hero"
9150
+ ]).optional(),
9147
9151
  order: number().optional(),
9148
9152
  fields: array(any())
9149
9153
  });
@@ -14076,7 +14080,11 @@ var ConfigSectionWithValuesSchema = object({
14076
14080
  literal(4)
14077
14081
  ]).optional(),
14078
14082
  tab: string().optional(),
14079
- location: _enum(["settings", "top-tab"]).optional(),
14083
+ location: _enum([
14084
+ "settings",
14085
+ "top-tab",
14086
+ "hero"
14087
+ ]).optional(),
14080
14088
  order: number().optional(),
14081
14089
  fields: array(any())
14082
14090
  });
@@ -17956,6 +17964,52 @@ var TierStatusSchema = object({
17956
17964
  countedAt: number().nullable()
17957
17965
  });
17958
17966
  /** Operator/diagnostic view: rows per tier, last runs, refusals and drops since boot. */
17967
+ /**
17968
+ * Why a series is orphan. `device-gone`: its device is absent from the
17969
+ * successful device listings (the departure clock). `undeclared`: its `cap:`
17970
+ * key is declared by no capability any more (a field a cap removed).
17971
+ */
17972
+ var DeviceHistoryOrphanReasonSchema = _enum(["device-gone", "undeclared"]);
17973
+ /** Rows held per stored tier. */
17974
+ var TierRowsSchema = object({
17975
+ raw: number().int(),
17976
+ "5m": number().int(),
17977
+ "1h": number().int(),
17978
+ "1d": number().int()
17979
+ });
17980
+ var OrphanSeriesSchema = object({
17981
+ seriesId: number().int(),
17982
+ deviceId: number().int(),
17983
+ key: string(),
17984
+ scope: string(),
17985
+ /** The metric's display name; `null` when its metric row is gone too. */
17986
+ displayName: string().nullable(),
17987
+ reason: DeviceHistoryOrphanReasonSchema,
17988
+ /** `device-gone`: since when the device has been absent; `null` otherwise. */
17989
+ missingSince: number().nullable(),
17990
+ firstTs: number(),
17991
+ lastTs: number(),
17992
+ rows: TierRowsSchema
17993
+ });
17994
+ var DeviceHistoryOrphanDeleteRefusalSchema = _enum([
17995
+ "not-found",
17996
+ "not-orphan",
17997
+ "failed"
17998
+ ]);
17999
+ var OrphanDeleteEntrySchema = discriminatedUnion("ok", [object({
18000
+ seriesId: number().int(),
18001
+ ok: literal(true),
18002
+ deleted: TierRowsSchema
18003
+ }), object({
18004
+ seriesId: number().int(),
18005
+ ok: literal(false),
18006
+ reason: DeviceHistoryOrphanDeleteRefusalSchema
18007
+ })]);
18008
+ var OrphanListSchema = object({
18009
+ series: array(OrphanSeriesSchema).readonly(),
18010
+ /** More orphans exist than {@link DEVICE_HISTORY_ORPHAN_LIST_MAX}. */
18011
+ truncated: boolean()
18012
+ });
17959
18013
  var DeviceHistoryStatusSchema = object({
17960
18014
  startedAt: number(),
17961
18015
  /** The store is declared, series loaded and the first reconcile has answered. */
@@ -18053,7 +18107,10 @@ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly())
18053
18107
  }), object({ enabled: boolean() }), {
18054
18108
  kind: "mutation",
18055
18109
  auth: "admin"
18056
- }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" });
18110
+ }), 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() }), {
18111
+ kind: "mutation",
18112
+ auth: "admin"
18113
+ });
18057
18114
  var DeviceCaStatusSchema = discriminatedUnion("state", [
18058
18115
  object({ state: literal("absent") }),
18059
18116
  object({
@@ -55921,17 +55978,69 @@ var connectivityCapability = {
55921
55978
  volatileStateFields: ["lastChangedAt"]
55922
55979
  };
55923
55980
  /**
55924
- * Generic device-consumables capability — surfaces a device's
55925
- * maintenance items (vacuum filters/brushes, replaceable cartridges,
55926
- * descaling cycles, …) with their remaining life and an optional
55927
- * "Replaced" reset action. Device-agnostic: any provider that knows its
55928
- * device tracks consumables can register it; the cap declares no
55929
- * vocabulary of its own — the provider names each item verbatim.
55981
+ * Generic device-consumables capability — the ONE place a device reports what
55982
+ * it uses up or fills: wear parts (vacuum filters/brushes, cartridges,
55983
+ * descaling cycles), supplies it draws from (a vacuum's clean-water tank and
55984
+ * detergent, a dishwasher's salt and rinse aid) and waste it collects (a dirty
55985
+ * water tank, a dust bin). Each item carries its remaining life or fill and an
55986
+ * optional "Replaced" reset action. Device-agnostic: any provider that knows
55987
+ * its device tracks consumables registers it; the provider names each item
55988
+ * verbatim and says which `kind` it is.
55989
+ *
55990
+ * The admin UI renders it as ONE collapsible section directly under the
55991
+ * device page's hero card (`placement: 'hero'`), for every device bound to
55992
+ * this cap — never drawn by a device type's hero card itself (D915).
55930
55993
  *
55931
55994
  * Like `childLayout`, the cap is INERT until a provider sets items: no
55932
55995
  * provider populates it by guessing (no HA inference). The UI renders a
55933
55996
  * "No consumables reported" placeholder when `items` is empty.
55934
55997
  */
55998
+ /**
55999
+ * What an item IS, which decides which direction is bad:
56000
+ * - `wear` — a part that wears out (a brush, a filter); low life is bad.
56001
+ * - `supply` — something the device draws from (clean water, detergent,
56002
+ * salt, rinse aid); low or empty is bad.
56003
+ * - `waste` — something the device fills (dirty water, a dust bin); full is
56004
+ * bad.
56005
+ * Absent = `wear`.
56006
+ */
56007
+ var ConsumableKindSchema = _enum([
56008
+ "wear",
56009
+ "supply",
56010
+ "waste"
56011
+ ]);
56012
+ /**
56013
+ * What an item LOOKS like, which decides how a client draws it — independent
56014
+ * of `kind`, which decides which direction is bad:
56015
+ * - `part` — a part that wears (a brush, a filter, a mop pad): a wear bar,
56016
+ * remaining time and a reset.
56017
+ * - `tank` — a container of liquid (clean water, dirty water): a fill gauge.
56018
+ * - `product` — something bought and refilled (detergent, salt, rinse aid):
56019
+ * a stepped level and "refill".
56020
+ * - `bin` — a container that collects waste (a dust bin): a fill gauge
56021
+ * that warns when full.
56022
+ * Absent = derived from the kind ({@link consumableFormOf}).
56023
+ */
56024
+ var ConsumableFormSchema = _enum([
56025
+ "part",
56026
+ "tank",
56027
+ "product",
56028
+ "bin"
56029
+ ]);
56030
+ /** The provider's own discrete verdict on an item. */
56031
+ var ConsumableStatusSchema = _enum([
56032
+ "ok",
56033
+ "low",
56034
+ "empty",
56035
+ "full",
56036
+ "replace"
56037
+ ]);
56038
+ _enum([
56039
+ "ok",
56040
+ "low",
56041
+ "empty",
56042
+ "full"
56043
+ ]);
55935
56044
  /** Units a remaining-life counter is reported in. Closed: the panel renders
55936
56045
  * each. */
55937
56046
  var ConsumableRemainingUnitSchema = _enum([
@@ -55946,18 +56055,23 @@ var ConsumableRemainingSchema = object({
55946
56055
  unit: ConsumableRemainingUnitSchema
55947
56056
  });
55948
56057
  /** A single consumable item. Either a continuous `level` (remaining
55949
- * life %) or a discrete `status` may be known — both may be null when a
55950
- * provider only knows the item exists. `level` and `status` are not
55951
- * mutually exclusive; a provider may report both. */
56058
+ * life %, or fill % for a `supply` / `waste` item) or a discrete `status`
56059
+ * may be known — both may be null when a provider only knows the item
56060
+ * exists. `level` and `status` are not mutually exclusive; a provider may
56061
+ * report both. */
55952
56062
  var ConsumableItemSchema = object({
55953
56063
  /** Stable id, e.g. 'main-brush'. */
55954
56064
  key: string().min(1),
55955
56065
  /** Display name. */
55956
56066
  label: string().min(1),
55957
- /** Remaining life % when known (0..100). */
56067
+ /** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
55958
56068
  level: number().min(0).max(100).nullable(),
55959
- /** Discrete state when known (binary mode). */
55960
- status: _enum(["ok", "replace"]).nullable(),
56069
+ /** The provider's discrete verdict when known (binary mode). */
56070
+ status: ConsumableStatusSchema.nullable(),
56071
+ /** What the item is — decides whether low or full is bad. Absent = `wear`. */
56072
+ kind: ConsumableKindSchema.optional(),
56073
+ /** How the item is drawn (part, tank, product, bin). Absent = derived from `kind`. */
56074
+ form: ConsumableFormSchema.optional(),
55961
56075
  /** Ms epoch of the last replace, when known. */
55962
56076
  lastResetAt: number().nullable(),
55963
56077
  /** Whether `reset()` is meaningful for this item. */
@@ -55980,7 +56094,7 @@ var consumablesCapability = {
55980
56094
  kind: "widget",
55981
56095
  widgetId: "host/consumables-panel",
55982
56096
  tab: "consumables",
55983
- topTab: true,
56097
+ placement: "hero",
55984
56098
  label: "Consumables",
55985
56099
  order: 5
55986
56100
  } },
@@ -56041,9 +56155,37 @@ reset: method(object({
56041
56155
  */
56042
56156
  durability: "restored",
56043
56157
  /**
56044
- * History (D850): none — `items` is an array keyed by runtime ids; a history path never enters it.
56158
+ * History (D850, D917): one series per (item field, item `key`) — the item key
56159
+ * is the series scope, the item `label` names it. A vacuum tank's fill, a
56160
+ * brush's remaining life and a dishwasher's salt are each recorded the moment
56161
+ * their provider reports them; an item that appears later gets its series.
56045
56162
  */
56046
- history: "none",
56163
+ history: {
56164
+ fields: {},
56165
+ items: {
56166
+ path: "items",
56167
+ key: "key",
56168
+ label: "label",
56169
+ fields: {
56170
+ level: {
56171
+ kind: "gauge",
56172
+ unit: "%",
56173
+ deadband: 2,
56174
+ displayName: "Level"
56175
+ },
56176
+ status: {
56177
+ kind: "enum",
56178
+ displayName: "Status"
56179
+ },
56180
+ "remaining.value": {
56181
+ kind: "gauge",
56182
+ unitFrom: "remaining.unit",
56183
+ deadband: 1,
56184
+ displayName: "Remaining"
56185
+ }
56186
+ }
56187
+ }
56188
+ },
56047
56189
  /** Clocks, not content: a re-read that changed no item costs no commit. */
56048
56190
  volatileStateFields: ["lastChangedAt", "lastFetchedAt"]
56049
56191
  };
@@ -56458,8 +56600,9 @@ onStatusChanged: { data: object({
56458
56600
  volatileStateFields: ["lastChangedAt"]
56459
56601
  };
56460
56602
  /**
56461
- * Smart-dishwasher cap — program lifecycle, door / remote-start gates,
56462
- * consumable levels (salt, rinse aid) and common program options.
56603
+ * Smart-dishwasher cap — program lifecycle, door / remote-start gates and
56604
+ * common program options. Salt and rinse aid are NOT here: they are items of
56605
+ * the device's `consumables` cap, like every other device's (D915).
56463
56606
  *
56464
56607
  * Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
56465
56608
  * by any integration that exposes the same program / option surface.
@@ -56507,11 +56650,6 @@ var DishwasherAvailabilitySchema = _enum([
56507
56650
  "offline",
56508
56651
  "description-missing"
56509
56652
  ]);
56510
- var DishwasherConsumableLevelSchema = _enum([
56511
- "ok",
56512
- "low",
56513
- "empty"
56514
- ]);
56515
56653
  var DishwasherStatusSchema = object({
56516
56654
  availability: DishwasherAvailabilitySchema,
56517
56655
  /** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
@@ -56544,8 +56682,6 @@ var DishwasherStatusSchema = object({
56544
56682
  powerOn: boolean().nullable(),
56545
56683
  /** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
56546
56684
  powerState: string().nullable(),
56547
- saltLevel: DishwasherConsumableLevelSchema.nullable(),
56548
- rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
56549
56685
  /**
56550
56686
  * True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
56551
56687
  * combined care-and-filter reminder raised); false when every such reminder reads clear; null
@@ -65361,60 +65497,17 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
65361
65497
  auth: "admin",
65362
65498
  access: "delete"
65363
65499
  });
65364
- /**
65365
- * Robot-vacuum cap. Models HA `vacuum.*` entities — anything with a
65366
- * cleaning lifecycle plus a return-to-base / locate surface and an
65367
- * optional fan-speed selector.
65368
- *
65369
- * State follows HA's canonical vacuum lifecycle: `idle` / `cleaning` /
65370
- * `paused` / `returning` / `docked` / `error`. `batteryLevel`
65371
- * (0..100) is nullable — some vacuums don't report a battery
65372
- * percentage. `fanSpeed` is the current speed token (provider-verbatim,
65373
- * e.g. `'standard'` / `'turbo'`) and `availableFanSpeeds` lists the
65374
- * tokens the hardware accepts so the UI renders only supported choices.
65375
- *
65376
- * The `setFanSpeed` method takes the bare `speed` token — the provider
65377
- * validates it against the vacuum's own list. `locate` triggers the
65378
- * find-me chirp; `returnToBase` sends it home.
65379
- *
65380
- * Consumable / waste tanks: `cleanWater` / `dirtyWater` / `detergent` /
65381
- * `dustBin` each carry a nullable `{ level (0..100 %), status ('ok' |
65382
- * 'low' | 'full') }` reading. Native providers (e.g. Dreame, Roborock)
65383
- * SHOULD populate whichever tanks the hardware has — leave a field `null`
65384
- * only when the device has no such tank at all, and use a `TankStatus`
65385
- * with both inner fields `null` when the tank exists but its level is
65386
- * currently unknown. HA `vacuum.*` entities expose no per-tank telemetry,
65387
- * so the HA provider leaves all four `null`.
65388
- */
65389
- var VacuumStateSchema = _enum([
65390
- "idle",
65391
- "cleaning",
65392
- "paused",
65393
- "returning",
65394
- "docked",
65395
- "drying",
65396
- "error"
65397
- ]);
65398
- /**
65399
- * One consumable / waste tank on a robot vacuum (clean-water, dirty-water,
65400
- * detergent or dust-bin). A tank can report a numeric fill `level` (0..100),
65401
- * a discrete `status` (binary-style hardware), or both. Both `null` means the
65402
- * level is currently unknown; the OWNING field being `null` means the
65403
- * hardware has no such tank at all.
65404
- */
65405
- var TankStatusSchema = object({
65406
- /** Numeric fill 0..100 when the hardware reports a percentage; null otherwise. */
65407
- level: number().min(0).max(100).nullable(),
65408
- /** Discrete state when the hardware is binary-mode; null otherwise. */
65409
- status: _enum([
65410
- "ok",
65411
- "low",
65412
- "full"
65413
- ]).nullable()
65414
- });
65415
65500
  var VacuumControlStatusSchema = object({
65416
65501
  /** Lifecycle state of the vacuum. */
65417
- state: VacuumStateSchema,
65502
+ state: _enum([
65503
+ "idle",
65504
+ "cleaning",
65505
+ "paused",
65506
+ "returning",
65507
+ "docked",
65508
+ "drying",
65509
+ "error"
65510
+ ]),
65418
65511
  /** 0..100 battery percentage. Null when the device has no battery
65419
65512
  * reading. */
65420
65513
  batteryLevel: number().min(0).max(100).nullable(),
@@ -65423,14 +65516,6 @@ var VacuumControlStatusSchema = object({
65423
65516
  fanSpeed: string().nullable(),
65424
65517
  /** Speed tokens the hardware accepts — drives the UI selector. */
65425
65518
  availableFanSpeeds: array(string()),
65426
- /** Clean-water (mop) tank. Null when the hardware has no clean-water tank. */
65427
- cleanWater: TankStatusSchema.nullable(),
65428
- /** Dirty-water (recovery) tank. Null when the hardware has no dirty-water tank. */
65429
- dirtyWater: TankStatusSchema.nullable(),
65430
- /** Detergent tank. Null when the hardware has no detergent tank. */
65431
- detergent: TankStatusSchema.nullable(),
65432
- /** Dust bin. Null when the hardware has no dust bin. */
65433
- dustBin: TankStatusSchema.nullable(),
65434
65519
  /** 0..100 cleaning-completion percentage of the current task, or null. */
65435
65520
  progressPercent: number().min(0).max(100).nullable(),
65436
65521
  /** Current error code (0 / null = no error). */
@@ -65492,35 +65577,14 @@ var vacuumControlCapability = {
65492
65577
  */
65493
65578
  durability: "session",
65494
65579
  /**
65495
- * History (D850): recorded series. Tank levels are fixed-object paths (`cleanWater.level`, ...).
65580
+ * History (D850): recorded series. The tanks moved to `consumables` (D915), whose
65581
+ * items are keyed by runtime ids and record no history.
65496
65582
  */
65497
- history: { fields: {
65498
- batteryLevel: {
65499
- kind: "gauge",
65500
- unit: "%",
65501
- deadband: 2
65502
- },
65503
- "cleanWater.level": {
65504
- kind: "gauge",
65505
- unit: "%",
65506
- deadband: 2
65507
- },
65508
- "dirtyWater.level": {
65509
- kind: "gauge",
65510
- unit: "%",
65511
- deadband: 2
65512
- },
65513
- "detergent.level": {
65514
- kind: "gauge",
65515
- unit: "%",
65516
- deadband: 2
65517
- },
65518
- "dustBin.level": {
65519
- kind: "gauge",
65520
- unit: "%",
65521
- deadband: 2
65522
- }
65523
- } }
65583
+ history: { fields: { batteryLevel: {
65584
+ kind: "gauge",
65585
+ unit: "%",
65586
+ deadband: 2
65587
+ } } }
65524
65588
  };
65525
65589
  var ValveStatusSchema = object({
65526
65590
  /** Lifecycle state of the valve. */
@@ -69914,6 +69978,12 @@ Object.freeze({
69914
69978
  addonId: null,
69915
69979
  access: "create"
69916
69980
  },
69981
+ "deviceHistory.deleteOrphanSeries": {
69982
+ capName: "device-history",
69983
+ capScope: "system",
69984
+ addonId: null,
69985
+ access: "delete"
69986
+ },
69917
69987
  "deviceHistory.getDeviceEnabled": {
69918
69988
  capName: "device-history",
69919
69989
  capScope: "system",
@@ -69932,6 +70002,12 @@ Object.freeze({
69932
70002
  addonId: null,
69933
70003
  access: "view"
69934
70004
  },
70005
+ "deviceHistory.listOrphanSeries": {
70006
+ capName: "device-history",
70007
+ capScope: "system",
70008
+ addonId: null,
70009
+ access: "view"
70010
+ },
69935
70011
  "deviceHistory.listSeries": {
69936
70012
  capName: "device-history",
69937
70013
  capScope: "system",
@@ -79937,7 +80013,7 @@ var STATE_SUMMARY_VARS = [
79937
80013
  ([...RULE_TEXT], [...COMBINED_ALARM]),
79938
80014
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
79939
80015
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
79940
- ([...RULE_TEXT], [...CONSUMABLE]),
80016
+ ([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
79941
80017
  ([...RULE_TEXT], [...TANK]),
79942
80018
  [...RULE_TEXT],
79943
80019
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
package/dist/addon.mjs CHANGED
@@ -6250,7 +6250,7 @@ var ZodIssueCode = {
6250
6250
  var ZodFirstPartyTypeKind;
6251
6251
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
6252
6252
  //#endregion
6253
- //#region ../types/dist/sleep-DJFUfKvA.mjs
6253
+ //#region ../types/dist/sleep-CUp20JkO.mjs
6254
6254
  /**
6255
6255
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6256
6256
  * window to float samples (D455).
@@ -9142,7 +9142,11 @@ var ContributionSectionSchema = object({
9142
9142
  literal(4)
9143
9143
  ]).optional(),
9144
9144
  tab: string().optional(),
9145
- location: _enum(["settings", "top-tab"]).optional(),
9145
+ location: _enum([
9146
+ "settings",
9147
+ "top-tab",
9148
+ "hero"
9149
+ ]).optional(),
9146
9150
  order: number().optional(),
9147
9151
  fields: array(any())
9148
9152
  });
@@ -14075,7 +14079,11 @@ var ConfigSectionWithValuesSchema = object({
14075
14079
  literal(4)
14076
14080
  ]).optional(),
14077
14081
  tab: string().optional(),
14078
- location: _enum(["settings", "top-tab"]).optional(),
14082
+ location: _enum([
14083
+ "settings",
14084
+ "top-tab",
14085
+ "hero"
14086
+ ]).optional(),
14079
14087
  order: number().optional(),
14080
14088
  fields: array(any())
14081
14089
  });
@@ -17955,6 +17963,52 @@ var TierStatusSchema = object({
17955
17963
  countedAt: number().nullable()
17956
17964
  });
17957
17965
  /** Operator/diagnostic view: rows per tier, last runs, refusals and drops since boot. */
17966
+ /**
17967
+ * Why a series is orphan. `device-gone`: its device is absent from the
17968
+ * successful device listings (the departure clock). `undeclared`: its `cap:`
17969
+ * key is declared by no capability any more (a field a cap removed).
17970
+ */
17971
+ var DeviceHistoryOrphanReasonSchema = _enum(["device-gone", "undeclared"]);
17972
+ /** Rows held per stored tier. */
17973
+ var TierRowsSchema = object({
17974
+ raw: number().int(),
17975
+ "5m": number().int(),
17976
+ "1h": number().int(),
17977
+ "1d": number().int()
17978
+ });
17979
+ var OrphanSeriesSchema = object({
17980
+ seriesId: number().int(),
17981
+ deviceId: number().int(),
17982
+ key: string(),
17983
+ scope: string(),
17984
+ /** The metric's display name; `null` when its metric row is gone too. */
17985
+ displayName: string().nullable(),
17986
+ reason: DeviceHistoryOrphanReasonSchema,
17987
+ /** `device-gone`: since when the device has been absent; `null` otherwise. */
17988
+ missingSince: number().nullable(),
17989
+ firstTs: number(),
17990
+ lastTs: number(),
17991
+ rows: TierRowsSchema
17992
+ });
17993
+ var DeviceHistoryOrphanDeleteRefusalSchema = _enum([
17994
+ "not-found",
17995
+ "not-orphan",
17996
+ "failed"
17997
+ ]);
17998
+ var OrphanDeleteEntrySchema = discriminatedUnion("ok", [object({
17999
+ seriesId: number().int(),
18000
+ ok: literal(true),
18001
+ deleted: TierRowsSchema
18002
+ }), object({
18003
+ seriesId: number().int(),
18004
+ ok: literal(false),
18005
+ reason: DeviceHistoryOrphanDeleteRefusalSchema
18006
+ })]);
18007
+ var OrphanListSchema = object({
18008
+ series: array(OrphanSeriesSchema).readonly(),
18009
+ /** More orphans exist than {@link DEVICE_HISTORY_ORPHAN_LIST_MAX}. */
18010
+ truncated: boolean()
18011
+ });
17958
18012
  var DeviceHistoryStatusSchema = object({
17959
18013
  startedAt: number(),
17960
18014
  /** The store is declared, series loaded and the first reconcile has answered. */
@@ -18052,7 +18106,10 @@ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly())
18052
18106
  }), object({ enabled: boolean() }), {
18053
18107
  kind: "mutation",
18054
18108
  auth: "admin"
18055
- }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" });
18109
+ }), 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() }), {
18110
+ kind: "mutation",
18111
+ auth: "admin"
18112
+ });
18056
18113
  var DeviceCaStatusSchema = discriminatedUnion("state", [
18057
18114
  object({ state: literal("absent") }),
18058
18115
  object({
@@ -55920,17 +55977,69 @@ var connectivityCapability = {
55920
55977
  volatileStateFields: ["lastChangedAt"]
55921
55978
  };
55922
55979
  /**
55923
- * Generic device-consumables capability — surfaces a device's
55924
- * maintenance items (vacuum filters/brushes, replaceable cartridges,
55925
- * descaling cycles, …) with their remaining life and an optional
55926
- * "Replaced" reset action. Device-agnostic: any provider that knows its
55927
- * device tracks consumables can register it; the cap declares no
55928
- * vocabulary of its own — the provider names each item verbatim.
55980
+ * Generic device-consumables capability — the ONE place a device reports what
55981
+ * it uses up or fills: wear parts (vacuum filters/brushes, cartridges,
55982
+ * descaling cycles), supplies it draws from (a vacuum's clean-water tank and
55983
+ * detergent, a dishwasher's salt and rinse aid) and waste it collects (a dirty
55984
+ * water tank, a dust bin). Each item carries its remaining life or fill and an
55985
+ * optional "Replaced" reset action. Device-agnostic: any provider that knows
55986
+ * its device tracks consumables registers it; the provider names each item
55987
+ * verbatim and says which `kind` it is.
55988
+ *
55989
+ * The admin UI renders it as ONE collapsible section directly under the
55990
+ * device page's hero card (`placement: 'hero'`), for every device bound to
55991
+ * this cap — never drawn by a device type's hero card itself (D915).
55929
55992
  *
55930
55993
  * Like `childLayout`, the cap is INERT until a provider sets items: no
55931
55994
  * provider populates it by guessing (no HA inference). The UI renders a
55932
55995
  * "No consumables reported" placeholder when `items` is empty.
55933
55996
  */
55997
+ /**
55998
+ * What an item IS, which decides which direction is bad:
55999
+ * - `wear` — a part that wears out (a brush, a filter); low life is bad.
56000
+ * - `supply` — something the device draws from (clean water, detergent,
56001
+ * salt, rinse aid); low or empty is bad.
56002
+ * - `waste` — something the device fills (dirty water, a dust bin); full is
56003
+ * bad.
56004
+ * Absent = `wear`.
56005
+ */
56006
+ var ConsumableKindSchema = _enum([
56007
+ "wear",
56008
+ "supply",
56009
+ "waste"
56010
+ ]);
56011
+ /**
56012
+ * What an item LOOKS like, which decides how a client draws it — independent
56013
+ * of `kind`, which decides which direction is bad:
56014
+ * - `part` — a part that wears (a brush, a filter, a mop pad): a wear bar,
56015
+ * remaining time and a reset.
56016
+ * - `tank` — a container of liquid (clean water, dirty water): a fill gauge.
56017
+ * - `product` — something bought and refilled (detergent, salt, rinse aid):
56018
+ * a stepped level and "refill".
56019
+ * - `bin` — a container that collects waste (a dust bin): a fill gauge
56020
+ * that warns when full.
56021
+ * Absent = derived from the kind ({@link consumableFormOf}).
56022
+ */
56023
+ var ConsumableFormSchema = _enum([
56024
+ "part",
56025
+ "tank",
56026
+ "product",
56027
+ "bin"
56028
+ ]);
56029
+ /** The provider's own discrete verdict on an item. */
56030
+ var ConsumableStatusSchema = _enum([
56031
+ "ok",
56032
+ "low",
56033
+ "empty",
56034
+ "full",
56035
+ "replace"
56036
+ ]);
56037
+ _enum([
56038
+ "ok",
56039
+ "low",
56040
+ "empty",
56041
+ "full"
56042
+ ]);
55934
56043
  /** Units a remaining-life counter is reported in. Closed: the panel renders
55935
56044
  * each. */
55936
56045
  var ConsumableRemainingUnitSchema = _enum([
@@ -55945,18 +56054,23 @@ var ConsumableRemainingSchema = object({
55945
56054
  unit: ConsumableRemainingUnitSchema
55946
56055
  });
55947
56056
  /** A single consumable item. Either a continuous `level` (remaining
55948
- * life %) or a discrete `status` may be known — both may be null when a
55949
- * provider only knows the item exists. `level` and `status` are not
55950
- * mutually exclusive; a provider may report both. */
56057
+ * life %, or fill % for a `supply` / `waste` item) or a discrete `status`
56058
+ * may be known — both may be null when a provider only knows the item
56059
+ * exists. `level` and `status` are not mutually exclusive; a provider may
56060
+ * report both. */
55951
56061
  var ConsumableItemSchema = object({
55952
56062
  /** Stable id, e.g. 'main-brush'. */
55953
56063
  key: string().min(1),
55954
56064
  /** Display name. */
55955
56065
  label: string().min(1),
55956
- /** Remaining life % when known (0..100). */
56066
+ /** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
55957
56067
  level: number().min(0).max(100).nullable(),
55958
- /** Discrete state when known (binary mode). */
55959
- status: _enum(["ok", "replace"]).nullable(),
56068
+ /** The provider's discrete verdict when known (binary mode). */
56069
+ status: ConsumableStatusSchema.nullable(),
56070
+ /** What the item is — decides whether low or full is bad. Absent = `wear`. */
56071
+ kind: ConsumableKindSchema.optional(),
56072
+ /** How the item is drawn (part, tank, product, bin). Absent = derived from `kind`. */
56073
+ form: ConsumableFormSchema.optional(),
55960
56074
  /** Ms epoch of the last replace, when known. */
55961
56075
  lastResetAt: number().nullable(),
55962
56076
  /** Whether `reset()` is meaningful for this item. */
@@ -55979,7 +56093,7 @@ var consumablesCapability = {
55979
56093
  kind: "widget",
55980
56094
  widgetId: "host/consumables-panel",
55981
56095
  tab: "consumables",
55982
- topTab: true,
56096
+ placement: "hero",
55983
56097
  label: "Consumables",
55984
56098
  order: 5
55985
56099
  } },
@@ -56040,9 +56154,37 @@ reset: method(object({
56040
56154
  */
56041
56155
  durability: "restored",
56042
56156
  /**
56043
- * History (D850): none — `items` is an array keyed by runtime ids; a history path never enters it.
56157
+ * History (D850, D917): one series per (item field, item `key`) — the item key
56158
+ * is the series scope, the item `label` names it. A vacuum tank's fill, a
56159
+ * brush's remaining life and a dishwasher's salt are each recorded the moment
56160
+ * their provider reports them; an item that appears later gets its series.
56044
56161
  */
56045
- history: "none",
56162
+ history: {
56163
+ fields: {},
56164
+ items: {
56165
+ path: "items",
56166
+ key: "key",
56167
+ label: "label",
56168
+ fields: {
56169
+ level: {
56170
+ kind: "gauge",
56171
+ unit: "%",
56172
+ deadband: 2,
56173
+ displayName: "Level"
56174
+ },
56175
+ status: {
56176
+ kind: "enum",
56177
+ displayName: "Status"
56178
+ },
56179
+ "remaining.value": {
56180
+ kind: "gauge",
56181
+ unitFrom: "remaining.unit",
56182
+ deadband: 1,
56183
+ displayName: "Remaining"
56184
+ }
56185
+ }
56186
+ }
56187
+ },
56046
56188
  /** Clocks, not content: a re-read that changed no item costs no commit. */
56047
56189
  volatileStateFields: ["lastChangedAt", "lastFetchedAt"]
56048
56190
  };
@@ -56457,8 +56599,9 @@ onStatusChanged: { data: object({
56457
56599
  volatileStateFields: ["lastChangedAt"]
56458
56600
  };
56459
56601
  /**
56460
- * Smart-dishwasher cap — program lifecycle, door / remote-start gates,
56461
- * consumable levels (salt, rinse aid) and common program options.
56602
+ * Smart-dishwasher cap — program lifecycle, door / remote-start gates and
56603
+ * common program options. Salt and rinse aid are NOT here: they are items of
56604
+ * the device's `consumables` cap, like every other device's (D915).
56462
56605
  *
56463
56606
  * Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
56464
56607
  * by any integration that exposes the same program / option surface.
@@ -56506,11 +56649,6 @@ var DishwasherAvailabilitySchema = _enum([
56506
56649
  "offline",
56507
56650
  "description-missing"
56508
56651
  ]);
56509
- var DishwasherConsumableLevelSchema = _enum([
56510
- "ok",
56511
- "low",
56512
- "empty"
56513
- ]);
56514
56652
  var DishwasherStatusSchema = object({
56515
56653
  availability: DishwasherAvailabilitySchema,
56516
56654
  /** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
@@ -56543,8 +56681,6 @@ var DishwasherStatusSchema = object({
56543
56681
  powerOn: boolean().nullable(),
56544
56682
  /** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
56545
56683
  powerState: string().nullable(),
56546
- saltLevel: DishwasherConsumableLevelSchema.nullable(),
56547
- rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
56548
56684
  /**
56549
56685
  * True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
56550
56686
  * combined care-and-filter reminder raised); false when every such reminder reads clear; null
@@ -65360,60 +65496,17 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
65360
65496
  auth: "admin",
65361
65497
  access: "delete"
65362
65498
  });
65363
- /**
65364
- * Robot-vacuum cap. Models HA `vacuum.*` entities — anything with a
65365
- * cleaning lifecycle plus a return-to-base / locate surface and an
65366
- * optional fan-speed selector.
65367
- *
65368
- * State follows HA's canonical vacuum lifecycle: `idle` / `cleaning` /
65369
- * `paused` / `returning` / `docked` / `error`. `batteryLevel`
65370
- * (0..100) is nullable — some vacuums don't report a battery
65371
- * percentage. `fanSpeed` is the current speed token (provider-verbatim,
65372
- * e.g. `'standard'` / `'turbo'`) and `availableFanSpeeds` lists the
65373
- * tokens the hardware accepts so the UI renders only supported choices.
65374
- *
65375
- * The `setFanSpeed` method takes the bare `speed` token — the provider
65376
- * validates it against the vacuum's own list. `locate` triggers the
65377
- * find-me chirp; `returnToBase` sends it home.
65378
- *
65379
- * Consumable / waste tanks: `cleanWater` / `dirtyWater` / `detergent` /
65380
- * `dustBin` each carry a nullable `{ level (0..100 %), status ('ok' |
65381
- * 'low' | 'full') }` reading. Native providers (e.g. Dreame, Roborock)
65382
- * SHOULD populate whichever tanks the hardware has — leave a field `null`
65383
- * only when the device has no such tank at all, and use a `TankStatus`
65384
- * with both inner fields `null` when the tank exists but its level is
65385
- * currently unknown. HA `vacuum.*` entities expose no per-tank telemetry,
65386
- * so the HA provider leaves all four `null`.
65387
- */
65388
- var VacuumStateSchema = _enum([
65389
- "idle",
65390
- "cleaning",
65391
- "paused",
65392
- "returning",
65393
- "docked",
65394
- "drying",
65395
- "error"
65396
- ]);
65397
- /**
65398
- * One consumable / waste tank on a robot vacuum (clean-water, dirty-water,
65399
- * detergent or dust-bin). A tank can report a numeric fill `level` (0..100),
65400
- * a discrete `status` (binary-style hardware), or both. Both `null` means the
65401
- * level is currently unknown; the OWNING field being `null` means the
65402
- * hardware has no such tank at all.
65403
- */
65404
- var TankStatusSchema = object({
65405
- /** Numeric fill 0..100 when the hardware reports a percentage; null otherwise. */
65406
- level: number().min(0).max(100).nullable(),
65407
- /** Discrete state when the hardware is binary-mode; null otherwise. */
65408
- status: _enum([
65409
- "ok",
65410
- "low",
65411
- "full"
65412
- ]).nullable()
65413
- });
65414
65499
  var VacuumControlStatusSchema = object({
65415
65500
  /** Lifecycle state of the vacuum. */
65416
- state: VacuumStateSchema,
65501
+ state: _enum([
65502
+ "idle",
65503
+ "cleaning",
65504
+ "paused",
65505
+ "returning",
65506
+ "docked",
65507
+ "drying",
65508
+ "error"
65509
+ ]),
65417
65510
  /** 0..100 battery percentage. Null when the device has no battery
65418
65511
  * reading. */
65419
65512
  batteryLevel: number().min(0).max(100).nullable(),
@@ -65422,14 +65515,6 @@ var VacuumControlStatusSchema = object({
65422
65515
  fanSpeed: string().nullable(),
65423
65516
  /** Speed tokens the hardware accepts — drives the UI selector. */
65424
65517
  availableFanSpeeds: array(string()),
65425
- /** Clean-water (mop) tank. Null when the hardware has no clean-water tank. */
65426
- cleanWater: TankStatusSchema.nullable(),
65427
- /** Dirty-water (recovery) tank. Null when the hardware has no dirty-water tank. */
65428
- dirtyWater: TankStatusSchema.nullable(),
65429
- /** Detergent tank. Null when the hardware has no detergent tank. */
65430
- detergent: TankStatusSchema.nullable(),
65431
- /** Dust bin. Null when the hardware has no dust bin. */
65432
- dustBin: TankStatusSchema.nullable(),
65433
65518
  /** 0..100 cleaning-completion percentage of the current task, or null. */
65434
65519
  progressPercent: number().min(0).max(100).nullable(),
65435
65520
  /** Current error code (0 / null = no error). */
@@ -65491,35 +65576,14 @@ var vacuumControlCapability = {
65491
65576
  */
65492
65577
  durability: "session",
65493
65578
  /**
65494
- * History (D850): recorded series. Tank levels are fixed-object paths (`cleanWater.level`, ...).
65579
+ * History (D850): recorded series. The tanks moved to `consumables` (D915), whose
65580
+ * items are keyed by runtime ids and record no history.
65495
65581
  */
65496
- history: { fields: {
65497
- batteryLevel: {
65498
- kind: "gauge",
65499
- unit: "%",
65500
- deadband: 2
65501
- },
65502
- "cleanWater.level": {
65503
- kind: "gauge",
65504
- unit: "%",
65505
- deadband: 2
65506
- },
65507
- "dirtyWater.level": {
65508
- kind: "gauge",
65509
- unit: "%",
65510
- deadband: 2
65511
- },
65512
- "detergent.level": {
65513
- kind: "gauge",
65514
- unit: "%",
65515
- deadband: 2
65516
- },
65517
- "dustBin.level": {
65518
- kind: "gauge",
65519
- unit: "%",
65520
- deadband: 2
65521
- }
65522
- } }
65582
+ history: { fields: { batteryLevel: {
65583
+ kind: "gauge",
65584
+ unit: "%",
65585
+ deadband: 2
65586
+ } } }
65523
65587
  };
65524
65588
  var ValveStatusSchema = object({
65525
65589
  /** Lifecycle state of the valve. */
@@ -69913,6 +69977,12 @@ Object.freeze({
69913
69977
  addonId: null,
69914
69978
  access: "create"
69915
69979
  },
69980
+ "deviceHistory.deleteOrphanSeries": {
69981
+ capName: "device-history",
69982
+ capScope: "system",
69983
+ addonId: null,
69984
+ access: "delete"
69985
+ },
69916
69986
  "deviceHistory.getDeviceEnabled": {
69917
69987
  capName: "device-history",
69918
69988
  capScope: "system",
@@ -69931,6 +70001,12 @@ Object.freeze({
69931
70001
  addonId: null,
69932
70002
  access: "view"
69933
70003
  },
70004
+ "deviceHistory.listOrphanSeries": {
70005
+ capName: "device-history",
70006
+ capScope: "system",
70007
+ addonId: null,
70008
+ access: "view"
70009
+ },
69934
70010
  "deviceHistory.listSeries": {
69935
70011
  capName: "device-history",
69936
70012
  capScope: "system",
@@ -79936,7 +80012,7 @@ var STATE_SUMMARY_VARS = [
79936
80012
  ([...RULE_TEXT], [...COMBINED_ALARM]),
79937
80013
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
79938
80014
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
79939
- ([...RULE_TEXT], [...CONSUMABLE]),
80015
+ ([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
79940
80016
  ([...RULE_TEXT], [...TANK]),
79941
80017
  [...RULE_TEXT],
79942
80018
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-tuya",
3
- "version": "0.2.142",
3
+ "version": "0.2.143",
4
4
  "description": "Tuya / Smart Life device-provider addon for CamStack — account-onboarded (Tuya IoT cloud fetch of device localKeys) + LOCAL DP control via the @apocaliss92/nodetuya encrypted-LAN client, exposing switch / water-heater-family kettle entities",
5
5
  "keywords": [
6
6
  "camstack",