@camstack/addon-provider-unifi 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
@@ -5431,7 +5431,7 @@ var ZodIssueCode = {
5431
5431
  var ZodFirstPartyTypeKind;
5432
5432
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5433
5433
  //#endregion
5434
- //#region ../types/dist/sleep-DJFUfKvA.mjs
5434
+ //#region ../types/dist/sleep-CUp20JkO.mjs
5435
5435
  /**
5436
5436
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5437
5437
  * window to float samples (D455).
@@ -8323,7 +8323,11 @@ var ContributionSectionSchema = object({
8323
8323
  literal(4)
8324
8324
  ]).optional(),
8325
8325
  tab: string().optional(),
8326
- location: _enum(["settings", "top-tab"]).optional(),
8326
+ location: _enum([
8327
+ "settings",
8328
+ "top-tab",
8329
+ "hero"
8330
+ ]).optional(),
8327
8331
  order: number().optional(),
8328
8332
  fields: array(any())
8329
8333
  });
@@ -13270,7 +13274,11 @@ var ConfigSectionWithValuesSchema = object({
13270
13274
  literal(4)
13271
13275
  ]).optional(),
13272
13276
  tab: string().optional(),
13273
- location: _enum(["settings", "top-tab"]).optional(),
13277
+ location: _enum([
13278
+ "settings",
13279
+ "top-tab",
13280
+ "hero"
13281
+ ]).optional(),
13274
13282
  order: number().optional(),
13275
13283
  fields: array(any())
13276
13284
  });
@@ -17150,6 +17158,52 @@ var TierStatusSchema = object({
17150
17158
  countedAt: number().nullable()
17151
17159
  });
17152
17160
  /** Operator/diagnostic view: rows per tier, last runs, refusals and drops since boot. */
17161
+ /**
17162
+ * Why a series is orphan. `device-gone`: its device is absent from the
17163
+ * successful device listings (the departure clock). `undeclared`: its `cap:`
17164
+ * key is declared by no capability any more (a field a cap removed).
17165
+ */
17166
+ var DeviceHistoryOrphanReasonSchema = _enum(["device-gone", "undeclared"]);
17167
+ /** Rows held per stored tier. */
17168
+ var TierRowsSchema = object({
17169
+ raw: number().int(),
17170
+ "5m": number().int(),
17171
+ "1h": number().int(),
17172
+ "1d": number().int()
17173
+ });
17174
+ var OrphanSeriesSchema = object({
17175
+ seriesId: number().int(),
17176
+ deviceId: number().int(),
17177
+ key: string(),
17178
+ scope: string(),
17179
+ /** The metric's display name; `null` when its metric row is gone too. */
17180
+ displayName: string().nullable(),
17181
+ reason: DeviceHistoryOrphanReasonSchema,
17182
+ /** `device-gone`: since when the device has been absent; `null` otherwise. */
17183
+ missingSince: number().nullable(),
17184
+ firstTs: number(),
17185
+ lastTs: number(),
17186
+ rows: TierRowsSchema
17187
+ });
17188
+ var DeviceHistoryOrphanDeleteRefusalSchema = _enum([
17189
+ "not-found",
17190
+ "not-orphan",
17191
+ "failed"
17192
+ ]);
17193
+ var OrphanDeleteEntrySchema = discriminatedUnion("ok", [object({
17194
+ seriesId: number().int(),
17195
+ ok: literal(true),
17196
+ deleted: TierRowsSchema
17197
+ }), object({
17198
+ seriesId: number().int(),
17199
+ ok: literal(false),
17200
+ reason: DeviceHistoryOrphanDeleteRefusalSchema
17201
+ })]);
17202
+ var OrphanListSchema = object({
17203
+ series: array(OrphanSeriesSchema).readonly(),
17204
+ /** More orphans exist than {@link DEVICE_HISTORY_ORPHAN_LIST_MAX}. */
17205
+ truncated: boolean()
17206
+ });
17153
17207
  var DeviceHistoryStatusSchema = object({
17154
17208
  startedAt: number(),
17155
17209
  /** The store is declared, series loaded and the first reconcile has answered. */
@@ -17247,7 +17301,10 @@ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly())
17247
17301
  }), object({ enabled: boolean() }), {
17248
17302
  kind: "mutation",
17249
17303
  auth: "admin"
17250
- }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" });
17304
+ }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" }), method(object({}), OrphanListSchema, { auth: "admin" }), method(object({ seriesIds: array(number().int()).min(1).max(50) }), object({ results: array(OrphanDeleteEntrySchema).readonly() }), {
17305
+ kind: "mutation",
17306
+ auth: "admin"
17307
+ });
17251
17308
  var DeviceCaStatusSchema = discriminatedUnion("state", [
17252
17309
  object({ state: literal("absent") }),
17253
17310
  object({
@@ -48071,7 +48128,6 @@ var RecommendationReasonSchema = discriminatedUnion("kind", [
48071
48128
  modelId: string()
48072
48129
  }),
48073
48130
  object({ kind: literal("cpu-device") }),
48074
- object({ kind: literal("coral-untouched") }),
48075
48131
  object({ kind: literal("device-disabled") }),
48076
48132
  object({ kind: literal("device-unavailable") }),
48077
48133
  object({ kind: literal("node-offline") }),
@@ -48169,11 +48225,6 @@ var AutoTuneWarningSchema = discriminatedUnion("kind", [
48169
48225
  kind: literal("detector-store-unreadable"),
48170
48226
  error: string()
48171
48227
  }),
48172
- object({
48173
- kind: literal("coral-enabled"),
48174
- nodeId: string(),
48175
- deviceKey: string()
48176
- }),
48177
48228
  object({
48178
48229
  kind: literal("custom-pin-kept"),
48179
48230
  nodeId: string(),
@@ -55226,17 +55277,69 @@ var connectivityCapability = {
55226
55277
  volatileStateFields: ["lastChangedAt"]
55227
55278
  };
55228
55279
  /**
55229
- * Generic device-consumables capability — surfaces a device's
55230
- * maintenance items (vacuum filters/brushes, replaceable cartridges,
55231
- * descaling cycles, …) with their remaining life and an optional
55232
- * "Replaced" reset action. Device-agnostic: any provider that knows its
55233
- * device tracks consumables can register it; the cap declares no
55234
- * vocabulary of its own — the provider names each item verbatim.
55280
+ * Generic device-consumables capability — the ONE place a device reports what
55281
+ * it uses up or fills: wear parts (vacuum filters/brushes, cartridges,
55282
+ * descaling cycles), supplies it draws from (a vacuum's clean-water tank and
55283
+ * detergent, a dishwasher's salt and rinse aid) and waste it collects (a dirty
55284
+ * water tank, a dust bin). Each item carries its remaining life or fill and an
55285
+ * optional "Replaced" reset action. Device-agnostic: any provider that knows
55286
+ * its device tracks consumables registers it; the provider names each item
55287
+ * verbatim and says which `kind` it is.
55288
+ *
55289
+ * The admin UI renders it as ONE collapsible section directly under the
55290
+ * device page's hero card (`placement: 'hero'`), for every device bound to
55291
+ * this cap — never drawn by a device type's hero card itself (D915).
55235
55292
  *
55236
55293
  * Like `childLayout`, the cap is INERT until a provider sets items: no
55237
55294
  * provider populates it by guessing (no HA inference). The UI renders a
55238
55295
  * "No consumables reported" placeholder when `items` is empty.
55239
55296
  */
55297
+ /**
55298
+ * What an item IS, which decides which direction is bad:
55299
+ * - `wear` — a part that wears out (a brush, a filter); low life is bad.
55300
+ * - `supply` — something the device draws from (clean water, detergent,
55301
+ * salt, rinse aid); low or empty is bad.
55302
+ * - `waste` — something the device fills (dirty water, a dust bin); full is
55303
+ * bad.
55304
+ * Absent = `wear`.
55305
+ */
55306
+ var ConsumableKindSchema = _enum([
55307
+ "wear",
55308
+ "supply",
55309
+ "waste"
55310
+ ]);
55311
+ /**
55312
+ * What an item LOOKS like, which decides how a client draws it — independent
55313
+ * of `kind`, which decides which direction is bad:
55314
+ * - `part` — a part that wears (a brush, a filter, a mop pad): a wear bar,
55315
+ * remaining time and a reset.
55316
+ * - `tank` — a container of liquid (clean water, dirty water): a fill gauge.
55317
+ * - `product` — something bought and refilled (detergent, salt, rinse aid):
55318
+ * a stepped level and "refill".
55319
+ * - `bin` — a container that collects waste (a dust bin): a fill gauge
55320
+ * that warns when full.
55321
+ * Absent = derived from the kind ({@link consumableFormOf}).
55322
+ */
55323
+ var ConsumableFormSchema = _enum([
55324
+ "part",
55325
+ "tank",
55326
+ "product",
55327
+ "bin"
55328
+ ]);
55329
+ /** The provider's own discrete verdict on an item. */
55330
+ var ConsumableStatusSchema = _enum([
55331
+ "ok",
55332
+ "low",
55333
+ "empty",
55334
+ "full",
55335
+ "replace"
55336
+ ]);
55337
+ _enum([
55338
+ "ok",
55339
+ "low",
55340
+ "empty",
55341
+ "full"
55342
+ ]);
55240
55343
  /** Units a remaining-life counter is reported in. Closed: the panel renders
55241
55344
  * each. */
55242
55345
  var ConsumableRemainingUnitSchema = _enum([
@@ -55251,18 +55354,23 @@ var ConsumableRemainingSchema = object({
55251
55354
  unit: ConsumableRemainingUnitSchema
55252
55355
  });
55253
55356
  /** A single consumable item. Either a continuous `level` (remaining
55254
- * life %) or a discrete `status` may be known — both may be null when a
55255
- * provider only knows the item exists. `level` and `status` are not
55256
- * mutually exclusive; a provider may report both. */
55357
+ * life %, or fill % for a `supply` / `waste` item) or a discrete `status`
55358
+ * may be known — both may be null when a provider only knows the item
55359
+ * exists. `level` and `status` are not mutually exclusive; a provider may
55360
+ * report both. */
55257
55361
  var ConsumableItemSchema = object({
55258
55362
  /** Stable id, e.g. 'main-brush'. */
55259
55363
  key: string().min(1),
55260
55364
  /** Display name. */
55261
55365
  label: string().min(1),
55262
- /** Remaining life % when known (0..100). */
55366
+ /** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
55263
55367
  level: number().min(0).max(100).nullable(),
55264
- /** Discrete state when known (binary mode). */
55265
- status: _enum(["ok", "replace"]).nullable(),
55368
+ /** The provider's discrete verdict when known (binary mode). */
55369
+ status: ConsumableStatusSchema.nullable(),
55370
+ /** What the item is — decides whether low or full is bad. Absent = `wear`. */
55371
+ kind: ConsumableKindSchema.optional(),
55372
+ /** How the item is drawn (part, tank, product, bin). Absent = derived from `kind`. */
55373
+ form: ConsumableFormSchema.optional(),
55266
55374
  /** Ms epoch of the last replace, when known. */
55267
55375
  lastResetAt: number().nullable(),
55268
55376
  /** Whether `reset()` is meaningful for this item. */
@@ -55285,7 +55393,7 @@ var consumablesCapability = {
55285
55393
  kind: "widget",
55286
55394
  widgetId: "host/consumables-panel",
55287
55395
  tab: "consumables",
55288
- topTab: true,
55396
+ placement: "hero",
55289
55397
  label: "Consumables",
55290
55398
  order: 5
55291
55399
  } },
@@ -55346,9 +55454,37 @@ reset: method(object({
55346
55454
  */
55347
55455
  durability: "restored",
55348
55456
  /**
55349
- * History (D850): none — `items` is an array keyed by runtime ids; a history path never enters it.
55457
+ * History (D850, D917): one series per (item field, item `key`) — the item key
55458
+ * is the series scope, the item `label` names it. A vacuum tank's fill, a
55459
+ * brush's remaining life and a dishwasher's salt are each recorded the moment
55460
+ * their provider reports them; an item that appears later gets its series.
55350
55461
  */
55351
- history: "none",
55462
+ history: {
55463
+ fields: {},
55464
+ items: {
55465
+ path: "items",
55466
+ key: "key",
55467
+ label: "label",
55468
+ fields: {
55469
+ level: {
55470
+ kind: "gauge",
55471
+ unit: "%",
55472
+ deadband: 2,
55473
+ displayName: "Level"
55474
+ },
55475
+ status: {
55476
+ kind: "enum",
55477
+ displayName: "Status"
55478
+ },
55479
+ "remaining.value": {
55480
+ kind: "gauge",
55481
+ unitFrom: "remaining.unit",
55482
+ deadband: 1,
55483
+ displayName: "Remaining"
55484
+ }
55485
+ }
55486
+ }
55487
+ },
55352
55488
  /** Clocks, not content: a re-read that changed no item costs no commit. */
55353
55489
  volatileStateFields: ["lastChangedAt", "lastFetchedAt"]
55354
55490
  };
@@ -55763,8 +55899,9 @@ onStatusChanged: { data: object({
55763
55899
  volatileStateFields: ["lastChangedAt"]
55764
55900
  };
55765
55901
  /**
55766
- * Smart-dishwasher cap — program lifecycle, door / remote-start gates,
55767
- * consumable levels (salt, rinse aid) and common program options.
55902
+ * Smart-dishwasher cap — program lifecycle, door / remote-start gates and
55903
+ * common program options. Salt and rinse aid are NOT here: they are items of
55904
+ * the device's `consumables` cap, like every other device's (D915).
55768
55905
  *
55769
55906
  * Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
55770
55907
  * by any integration that exposes the same program / option surface.
@@ -55812,11 +55949,6 @@ var DishwasherAvailabilitySchema = _enum([
55812
55949
  "offline",
55813
55950
  "description-missing"
55814
55951
  ]);
55815
- var DishwasherConsumableLevelSchema = _enum([
55816
- "ok",
55817
- "low",
55818
- "empty"
55819
- ]);
55820
55952
  var DishwasherStatusSchema = object({
55821
55953
  availability: DishwasherAvailabilitySchema,
55822
55954
  /** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
@@ -55849,8 +55981,6 @@ var DishwasherStatusSchema = object({
55849
55981
  powerOn: boolean().nullable(),
55850
55982
  /** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
55851
55983
  powerState: string().nullable(),
55852
- saltLevel: DishwasherConsumableLevelSchema.nullable(),
55853
- rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
55854
55984
  /**
55855
55985
  * True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
55856
55986
  * combined care-and-filter reminder raised); false when every such reminder reads clear; null
@@ -64666,60 +64796,17 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
64666
64796
  auth: "admin",
64667
64797
  access: "delete"
64668
64798
  });
64669
- /**
64670
- * Robot-vacuum cap. Models HA `vacuum.*` entities — anything with a
64671
- * cleaning lifecycle plus a return-to-base / locate surface and an
64672
- * optional fan-speed selector.
64673
- *
64674
- * State follows HA's canonical vacuum lifecycle: `idle` / `cleaning` /
64675
- * `paused` / `returning` / `docked` / `error`. `batteryLevel`
64676
- * (0..100) is nullable — some vacuums don't report a battery
64677
- * percentage. `fanSpeed` is the current speed token (provider-verbatim,
64678
- * e.g. `'standard'` / `'turbo'`) and `availableFanSpeeds` lists the
64679
- * tokens the hardware accepts so the UI renders only supported choices.
64680
- *
64681
- * The `setFanSpeed` method takes the bare `speed` token — the provider
64682
- * validates it against the vacuum's own list. `locate` triggers the
64683
- * find-me chirp; `returnToBase` sends it home.
64684
- *
64685
- * Consumable / waste tanks: `cleanWater` / `dirtyWater` / `detergent` /
64686
- * `dustBin` each carry a nullable `{ level (0..100 %), status ('ok' |
64687
- * 'low' | 'full') }` reading. Native providers (e.g. Dreame, Roborock)
64688
- * SHOULD populate whichever tanks the hardware has — leave a field `null`
64689
- * only when the device has no such tank at all, and use a `TankStatus`
64690
- * with both inner fields `null` when the tank exists but its level is
64691
- * currently unknown. HA `vacuum.*` entities expose no per-tank telemetry,
64692
- * so the HA provider leaves all four `null`.
64693
- */
64694
- var VacuumStateSchema = _enum([
64695
- "idle",
64696
- "cleaning",
64697
- "paused",
64698
- "returning",
64699
- "docked",
64700
- "drying",
64701
- "error"
64702
- ]);
64703
- /**
64704
- * One consumable / waste tank on a robot vacuum (clean-water, dirty-water,
64705
- * detergent or dust-bin). A tank can report a numeric fill `level` (0..100),
64706
- * a discrete `status` (binary-style hardware), or both. Both `null` means the
64707
- * level is currently unknown; the OWNING field being `null` means the
64708
- * hardware has no such tank at all.
64709
- */
64710
- var TankStatusSchema = object({
64711
- /** Numeric fill 0..100 when the hardware reports a percentage; null otherwise. */
64712
- level: number().min(0).max(100).nullable(),
64713
- /** Discrete state when the hardware is binary-mode; null otherwise. */
64714
- status: _enum([
64715
- "ok",
64716
- "low",
64717
- "full"
64718
- ]).nullable()
64719
- });
64720
64799
  var VacuumControlStatusSchema = object({
64721
64800
  /** Lifecycle state of the vacuum. */
64722
- state: VacuumStateSchema,
64801
+ state: _enum([
64802
+ "idle",
64803
+ "cleaning",
64804
+ "paused",
64805
+ "returning",
64806
+ "docked",
64807
+ "drying",
64808
+ "error"
64809
+ ]),
64723
64810
  /** 0..100 battery percentage. Null when the device has no battery
64724
64811
  * reading. */
64725
64812
  batteryLevel: number().min(0).max(100).nullable(),
@@ -64728,14 +64815,6 @@ var VacuumControlStatusSchema = object({
64728
64815
  fanSpeed: string().nullable(),
64729
64816
  /** Speed tokens the hardware accepts — drives the UI selector. */
64730
64817
  availableFanSpeeds: array(string()),
64731
- /** Clean-water (mop) tank. Null when the hardware has no clean-water tank. */
64732
- cleanWater: TankStatusSchema.nullable(),
64733
- /** Dirty-water (recovery) tank. Null when the hardware has no dirty-water tank. */
64734
- dirtyWater: TankStatusSchema.nullable(),
64735
- /** Detergent tank. Null when the hardware has no detergent tank. */
64736
- detergent: TankStatusSchema.nullable(),
64737
- /** Dust bin. Null when the hardware has no dust bin. */
64738
- dustBin: TankStatusSchema.nullable(),
64739
64818
  /** 0..100 cleaning-completion percentage of the current task, or null. */
64740
64819
  progressPercent: number().min(0).max(100).nullable(),
64741
64820
  /** Current error code (0 / null = no error). */
@@ -64797,35 +64876,14 @@ var vacuumControlCapability = {
64797
64876
  */
64798
64877
  durability: "session",
64799
64878
  /**
64800
- * History (D850): recorded series. Tank levels are fixed-object paths (`cleanWater.level`, ...).
64879
+ * History (D850): recorded series. The tanks moved to `consumables` (D915), whose
64880
+ * items are keyed by runtime ids and record no history.
64801
64881
  */
64802
- history: { fields: {
64803
- batteryLevel: {
64804
- kind: "gauge",
64805
- unit: "%",
64806
- deadband: 2
64807
- },
64808
- "cleanWater.level": {
64809
- kind: "gauge",
64810
- unit: "%",
64811
- deadband: 2
64812
- },
64813
- "dirtyWater.level": {
64814
- kind: "gauge",
64815
- unit: "%",
64816
- deadband: 2
64817
- },
64818
- "detergent.level": {
64819
- kind: "gauge",
64820
- unit: "%",
64821
- deadband: 2
64822
- },
64823
- "dustBin.level": {
64824
- kind: "gauge",
64825
- unit: "%",
64826
- deadband: 2
64827
- }
64828
- } }
64882
+ history: { fields: { batteryLevel: {
64883
+ kind: "gauge",
64884
+ unit: "%",
64885
+ deadband: 2
64886
+ } } }
64829
64887
  };
64830
64888
  var ValveStatusSchema = object({
64831
64889
  /** Lifecycle state of the valve. */
@@ -69219,6 +69277,12 @@ Object.freeze({
69219
69277
  addonId: null,
69220
69278
  access: "create"
69221
69279
  },
69280
+ "deviceHistory.deleteOrphanSeries": {
69281
+ capName: "device-history",
69282
+ capScope: "system",
69283
+ addonId: null,
69284
+ access: "delete"
69285
+ },
69222
69286
  "deviceHistory.getDeviceEnabled": {
69223
69287
  capName: "device-history",
69224
69288
  capScope: "system",
@@ -69237,6 +69301,12 @@ Object.freeze({
69237
69301
  addonId: null,
69238
69302
  access: "view"
69239
69303
  },
69304
+ "deviceHistory.listOrphanSeries": {
69305
+ capName: "device-history",
69306
+ capScope: "system",
69307
+ addonId: null,
69308
+ access: "view"
69309
+ },
69240
69310
  "deviceHistory.listSeries": {
69241
69311
  capName: "device-history",
69242
69312
  capScope: "system",
@@ -79242,7 +79312,7 @@ var STATE_SUMMARY_VARS = [
79242
79312
  ([...RULE_TEXT], [...COMBINED_ALARM]),
79243
79313
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
79244
79314
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
79245
- ([...RULE_TEXT], [...CONSUMABLE]),
79315
+ ([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
79246
79316
  ([...RULE_TEXT], [...TANK]),
79247
79317
  [...RULE_TEXT],
79248
79318
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
package/dist/addon.mjs CHANGED
@@ -5430,7 +5430,7 @@ var ZodIssueCode = {
5430
5430
  var ZodFirstPartyTypeKind;
5431
5431
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5432
5432
  //#endregion
5433
- //#region ../types/dist/sleep-DJFUfKvA.mjs
5433
+ //#region ../types/dist/sleep-CUp20JkO.mjs
5434
5434
  /**
5435
5435
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5436
5436
  * window to float samples (D455).
@@ -8322,7 +8322,11 @@ var ContributionSectionSchema = object({
8322
8322
  literal(4)
8323
8323
  ]).optional(),
8324
8324
  tab: string().optional(),
8325
- location: _enum(["settings", "top-tab"]).optional(),
8325
+ location: _enum([
8326
+ "settings",
8327
+ "top-tab",
8328
+ "hero"
8329
+ ]).optional(),
8326
8330
  order: number().optional(),
8327
8331
  fields: array(any())
8328
8332
  });
@@ -13269,7 +13273,11 @@ var ConfigSectionWithValuesSchema = object({
13269
13273
  literal(4)
13270
13274
  ]).optional(),
13271
13275
  tab: string().optional(),
13272
- location: _enum(["settings", "top-tab"]).optional(),
13276
+ location: _enum([
13277
+ "settings",
13278
+ "top-tab",
13279
+ "hero"
13280
+ ]).optional(),
13273
13281
  order: number().optional(),
13274
13282
  fields: array(any())
13275
13283
  });
@@ -17149,6 +17157,52 @@ var TierStatusSchema = object({
17149
17157
  countedAt: number().nullable()
17150
17158
  });
17151
17159
  /** Operator/diagnostic view: rows per tier, last runs, refusals and drops since boot. */
17160
+ /**
17161
+ * Why a series is orphan. `device-gone`: its device is absent from the
17162
+ * successful device listings (the departure clock). `undeclared`: its `cap:`
17163
+ * key is declared by no capability any more (a field a cap removed).
17164
+ */
17165
+ var DeviceHistoryOrphanReasonSchema = _enum(["device-gone", "undeclared"]);
17166
+ /** Rows held per stored tier. */
17167
+ var TierRowsSchema = object({
17168
+ raw: number().int(),
17169
+ "5m": number().int(),
17170
+ "1h": number().int(),
17171
+ "1d": number().int()
17172
+ });
17173
+ var OrphanSeriesSchema = object({
17174
+ seriesId: number().int(),
17175
+ deviceId: number().int(),
17176
+ key: string(),
17177
+ scope: string(),
17178
+ /** The metric's display name; `null` when its metric row is gone too. */
17179
+ displayName: string().nullable(),
17180
+ reason: DeviceHistoryOrphanReasonSchema,
17181
+ /** `device-gone`: since when the device has been absent; `null` otherwise. */
17182
+ missingSince: number().nullable(),
17183
+ firstTs: number(),
17184
+ lastTs: number(),
17185
+ rows: TierRowsSchema
17186
+ });
17187
+ var DeviceHistoryOrphanDeleteRefusalSchema = _enum([
17188
+ "not-found",
17189
+ "not-orphan",
17190
+ "failed"
17191
+ ]);
17192
+ var OrphanDeleteEntrySchema = discriminatedUnion("ok", [object({
17193
+ seriesId: number().int(),
17194
+ ok: literal(true),
17195
+ deleted: TierRowsSchema
17196
+ }), object({
17197
+ seriesId: number().int(),
17198
+ ok: literal(false),
17199
+ reason: DeviceHistoryOrphanDeleteRefusalSchema
17200
+ })]);
17201
+ var OrphanListSchema = object({
17202
+ series: array(OrphanSeriesSchema).readonly(),
17203
+ /** More orphans exist than {@link DEVICE_HISTORY_ORPHAN_LIST_MAX}. */
17204
+ truncated: boolean()
17205
+ });
17152
17206
  var DeviceHistoryStatusSchema = object({
17153
17207
  startedAt: number(),
17154
17208
  /** The store is declared, series loaded and the first reconcile has answered. */
@@ -17246,7 +17300,10 @@ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly())
17246
17300
  }), object({ enabled: boolean() }), {
17247
17301
  kind: "mutation",
17248
17302
  auth: "admin"
17249
- }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" });
17303
+ }), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" }), method(object({}), OrphanListSchema, { auth: "admin" }), method(object({ seriesIds: array(number().int()).min(1).max(50) }), object({ results: array(OrphanDeleteEntrySchema).readonly() }), {
17304
+ kind: "mutation",
17305
+ auth: "admin"
17306
+ });
17250
17307
  var DeviceCaStatusSchema = discriminatedUnion("state", [
17251
17308
  object({ state: literal("absent") }),
17252
17309
  object({
@@ -48070,7 +48127,6 @@ var RecommendationReasonSchema = discriminatedUnion("kind", [
48070
48127
  modelId: string()
48071
48128
  }),
48072
48129
  object({ kind: literal("cpu-device") }),
48073
- object({ kind: literal("coral-untouched") }),
48074
48130
  object({ kind: literal("device-disabled") }),
48075
48131
  object({ kind: literal("device-unavailable") }),
48076
48132
  object({ kind: literal("node-offline") }),
@@ -48168,11 +48224,6 @@ var AutoTuneWarningSchema = discriminatedUnion("kind", [
48168
48224
  kind: literal("detector-store-unreadable"),
48169
48225
  error: string()
48170
48226
  }),
48171
- object({
48172
- kind: literal("coral-enabled"),
48173
- nodeId: string(),
48174
- deviceKey: string()
48175
- }),
48176
48227
  object({
48177
48228
  kind: literal("custom-pin-kept"),
48178
48229
  nodeId: string(),
@@ -55225,17 +55276,69 @@ var connectivityCapability = {
55225
55276
  volatileStateFields: ["lastChangedAt"]
55226
55277
  };
55227
55278
  /**
55228
- * Generic device-consumables capability — surfaces a device's
55229
- * maintenance items (vacuum filters/brushes, replaceable cartridges,
55230
- * descaling cycles, …) with their remaining life and an optional
55231
- * "Replaced" reset action. Device-agnostic: any provider that knows its
55232
- * device tracks consumables can register it; the cap declares no
55233
- * vocabulary of its own — the provider names each item verbatim.
55279
+ * Generic device-consumables capability — the ONE place a device reports what
55280
+ * it uses up or fills: wear parts (vacuum filters/brushes, cartridges,
55281
+ * descaling cycles), supplies it draws from (a vacuum's clean-water tank and
55282
+ * detergent, a dishwasher's salt and rinse aid) and waste it collects (a dirty
55283
+ * water tank, a dust bin). Each item carries its remaining life or fill and an
55284
+ * optional "Replaced" reset action. Device-agnostic: any provider that knows
55285
+ * its device tracks consumables registers it; the provider names each item
55286
+ * verbatim and says which `kind` it is.
55287
+ *
55288
+ * The admin UI renders it as ONE collapsible section directly under the
55289
+ * device page's hero card (`placement: 'hero'`), for every device bound to
55290
+ * this cap — never drawn by a device type's hero card itself (D915).
55234
55291
  *
55235
55292
  * Like `childLayout`, the cap is INERT until a provider sets items: no
55236
55293
  * provider populates it by guessing (no HA inference). The UI renders a
55237
55294
  * "No consumables reported" placeholder when `items` is empty.
55238
55295
  */
55296
+ /**
55297
+ * What an item IS, which decides which direction is bad:
55298
+ * - `wear` — a part that wears out (a brush, a filter); low life is bad.
55299
+ * - `supply` — something the device draws from (clean water, detergent,
55300
+ * salt, rinse aid); low or empty is bad.
55301
+ * - `waste` — something the device fills (dirty water, a dust bin); full is
55302
+ * bad.
55303
+ * Absent = `wear`.
55304
+ */
55305
+ var ConsumableKindSchema = _enum([
55306
+ "wear",
55307
+ "supply",
55308
+ "waste"
55309
+ ]);
55310
+ /**
55311
+ * What an item LOOKS like, which decides how a client draws it — independent
55312
+ * of `kind`, which decides which direction is bad:
55313
+ * - `part` — a part that wears (a brush, a filter, a mop pad): a wear bar,
55314
+ * remaining time and a reset.
55315
+ * - `tank` — a container of liquid (clean water, dirty water): a fill gauge.
55316
+ * - `product` — something bought and refilled (detergent, salt, rinse aid):
55317
+ * a stepped level and "refill".
55318
+ * - `bin` — a container that collects waste (a dust bin): a fill gauge
55319
+ * that warns when full.
55320
+ * Absent = derived from the kind ({@link consumableFormOf}).
55321
+ */
55322
+ var ConsumableFormSchema = _enum([
55323
+ "part",
55324
+ "tank",
55325
+ "product",
55326
+ "bin"
55327
+ ]);
55328
+ /** The provider's own discrete verdict on an item. */
55329
+ var ConsumableStatusSchema = _enum([
55330
+ "ok",
55331
+ "low",
55332
+ "empty",
55333
+ "full",
55334
+ "replace"
55335
+ ]);
55336
+ _enum([
55337
+ "ok",
55338
+ "low",
55339
+ "empty",
55340
+ "full"
55341
+ ]);
55239
55342
  /** Units a remaining-life counter is reported in. Closed: the panel renders
55240
55343
  * each. */
55241
55344
  var ConsumableRemainingUnitSchema = _enum([
@@ -55250,18 +55353,23 @@ var ConsumableRemainingSchema = object({
55250
55353
  unit: ConsumableRemainingUnitSchema
55251
55354
  });
55252
55355
  /** A single consumable item. Either a continuous `level` (remaining
55253
- * life %) or a discrete `status` may be known — both may be null when a
55254
- * provider only knows the item exists. `level` and `status` are not
55255
- * mutually exclusive; a provider may report both. */
55356
+ * life %, or fill % for a `supply` / `waste` item) or a discrete `status`
55357
+ * may be known — both may be null when a provider only knows the item
55358
+ * exists. `level` and `status` are not mutually exclusive; a provider may
55359
+ * report both. */
55256
55360
  var ConsumableItemSchema = object({
55257
55361
  /** Stable id, e.g. 'main-brush'. */
55258
55362
  key: string().min(1),
55259
55363
  /** Display name. */
55260
55364
  label: string().min(1),
55261
- /** Remaining life % when known (0..100). */
55365
+ /** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
55262
55366
  level: number().min(0).max(100).nullable(),
55263
- /** Discrete state when known (binary mode). */
55264
- status: _enum(["ok", "replace"]).nullable(),
55367
+ /** The provider's discrete verdict when known (binary mode). */
55368
+ status: ConsumableStatusSchema.nullable(),
55369
+ /** What the item is — decides whether low or full is bad. Absent = `wear`. */
55370
+ kind: ConsumableKindSchema.optional(),
55371
+ /** How the item is drawn (part, tank, product, bin). Absent = derived from `kind`. */
55372
+ form: ConsumableFormSchema.optional(),
55265
55373
  /** Ms epoch of the last replace, when known. */
55266
55374
  lastResetAt: number().nullable(),
55267
55375
  /** Whether `reset()` is meaningful for this item. */
@@ -55284,7 +55392,7 @@ var consumablesCapability = {
55284
55392
  kind: "widget",
55285
55393
  widgetId: "host/consumables-panel",
55286
55394
  tab: "consumables",
55287
- topTab: true,
55395
+ placement: "hero",
55288
55396
  label: "Consumables",
55289
55397
  order: 5
55290
55398
  } },
@@ -55345,9 +55453,37 @@ reset: method(object({
55345
55453
  */
55346
55454
  durability: "restored",
55347
55455
  /**
55348
- * History (D850): none — `items` is an array keyed by runtime ids; a history path never enters it.
55456
+ * History (D850, D917): one series per (item field, item `key`) — the item key
55457
+ * is the series scope, the item `label` names it. A vacuum tank's fill, a
55458
+ * brush's remaining life and a dishwasher's salt are each recorded the moment
55459
+ * their provider reports them; an item that appears later gets its series.
55349
55460
  */
55350
- history: "none",
55461
+ history: {
55462
+ fields: {},
55463
+ items: {
55464
+ path: "items",
55465
+ key: "key",
55466
+ label: "label",
55467
+ fields: {
55468
+ level: {
55469
+ kind: "gauge",
55470
+ unit: "%",
55471
+ deadband: 2,
55472
+ displayName: "Level"
55473
+ },
55474
+ status: {
55475
+ kind: "enum",
55476
+ displayName: "Status"
55477
+ },
55478
+ "remaining.value": {
55479
+ kind: "gauge",
55480
+ unitFrom: "remaining.unit",
55481
+ deadband: 1,
55482
+ displayName: "Remaining"
55483
+ }
55484
+ }
55485
+ }
55486
+ },
55351
55487
  /** Clocks, not content: a re-read that changed no item costs no commit. */
55352
55488
  volatileStateFields: ["lastChangedAt", "lastFetchedAt"]
55353
55489
  };
@@ -55762,8 +55898,9 @@ onStatusChanged: { data: object({
55762
55898
  volatileStateFields: ["lastChangedAt"]
55763
55899
  };
55764
55900
  /**
55765
- * Smart-dishwasher cap — program lifecycle, door / remote-start gates,
55766
- * consumable levels (salt, rinse aid) and common program options.
55901
+ * Smart-dishwasher cap — program lifecycle, door / remote-start gates and
55902
+ * common program options. Salt and rinse aid are NOT here: they are items of
55903
+ * the device's `consumables` cap, like every other device's (D915).
55767
55904
  *
55768
55905
  * Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
55769
55906
  * by any integration that exposes the same program / option surface.
@@ -55811,11 +55948,6 @@ var DishwasherAvailabilitySchema = _enum([
55811
55948
  "offline",
55812
55949
  "description-missing"
55813
55950
  ]);
55814
- var DishwasherConsumableLevelSchema = _enum([
55815
- "ok",
55816
- "low",
55817
- "empty"
55818
- ]);
55819
55951
  var DishwasherStatusSchema = object({
55820
55952
  availability: DishwasherAvailabilitySchema,
55821
55953
  /** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
@@ -55848,8 +55980,6 @@ var DishwasherStatusSchema = object({
55848
55980
  powerOn: boolean().nullable(),
55849
55981
  /** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
55850
55982
  powerState: string().nullable(),
55851
- saltLevel: DishwasherConsumableLevelSchema.nullable(),
55852
- rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
55853
55983
  /**
55854
55984
  * True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
55855
55985
  * combined care-and-filter reminder raised); false when every such reminder reads clear; null
@@ -64665,60 +64795,17 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
64665
64795
  auth: "admin",
64666
64796
  access: "delete"
64667
64797
  });
64668
- /**
64669
- * Robot-vacuum cap. Models HA `vacuum.*` entities — anything with a
64670
- * cleaning lifecycle plus a return-to-base / locate surface and an
64671
- * optional fan-speed selector.
64672
- *
64673
- * State follows HA's canonical vacuum lifecycle: `idle` / `cleaning` /
64674
- * `paused` / `returning` / `docked` / `error`. `batteryLevel`
64675
- * (0..100) is nullable — some vacuums don't report a battery
64676
- * percentage. `fanSpeed` is the current speed token (provider-verbatim,
64677
- * e.g. `'standard'` / `'turbo'`) and `availableFanSpeeds` lists the
64678
- * tokens the hardware accepts so the UI renders only supported choices.
64679
- *
64680
- * The `setFanSpeed` method takes the bare `speed` token — the provider
64681
- * validates it against the vacuum's own list. `locate` triggers the
64682
- * find-me chirp; `returnToBase` sends it home.
64683
- *
64684
- * Consumable / waste tanks: `cleanWater` / `dirtyWater` / `detergent` /
64685
- * `dustBin` each carry a nullable `{ level (0..100 %), status ('ok' |
64686
- * 'low' | 'full') }` reading. Native providers (e.g. Dreame, Roborock)
64687
- * SHOULD populate whichever tanks the hardware has — leave a field `null`
64688
- * only when the device has no such tank at all, and use a `TankStatus`
64689
- * with both inner fields `null` when the tank exists but its level is
64690
- * currently unknown. HA `vacuum.*` entities expose no per-tank telemetry,
64691
- * so the HA provider leaves all four `null`.
64692
- */
64693
- var VacuumStateSchema = _enum([
64694
- "idle",
64695
- "cleaning",
64696
- "paused",
64697
- "returning",
64698
- "docked",
64699
- "drying",
64700
- "error"
64701
- ]);
64702
- /**
64703
- * One consumable / waste tank on a robot vacuum (clean-water, dirty-water,
64704
- * detergent or dust-bin). A tank can report a numeric fill `level` (0..100),
64705
- * a discrete `status` (binary-style hardware), or both. Both `null` means the
64706
- * level is currently unknown; the OWNING field being `null` means the
64707
- * hardware has no such tank at all.
64708
- */
64709
- var TankStatusSchema = object({
64710
- /** Numeric fill 0..100 when the hardware reports a percentage; null otherwise. */
64711
- level: number().min(0).max(100).nullable(),
64712
- /** Discrete state when the hardware is binary-mode; null otherwise. */
64713
- status: _enum([
64714
- "ok",
64715
- "low",
64716
- "full"
64717
- ]).nullable()
64718
- });
64719
64798
  var VacuumControlStatusSchema = object({
64720
64799
  /** Lifecycle state of the vacuum. */
64721
- state: VacuumStateSchema,
64800
+ state: _enum([
64801
+ "idle",
64802
+ "cleaning",
64803
+ "paused",
64804
+ "returning",
64805
+ "docked",
64806
+ "drying",
64807
+ "error"
64808
+ ]),
64722
64809
  /** 0..100 battery percentage. Null when the device has no battery
64723
64810
  * reading. */
64724
64811
  batteryLevel: number().min(0).max(100).nullable(),
@@ -64727,14 +64814,6 @@ var VacuumControlStatusSchema = object({
64727
64814
  fanSpeed: string().nullable(),
64728
64815
  /** Speed tokens the hardware accepts — drives the UI selector. */
64729
64816
  availableFanSpeeds: array(string()),
64730
- /** Clean-water (mop) tank. Null when the hardware has no clean-water tank. */
64731
- cleanWater: TankStatusSchema.nullable(),
64732
- /** Dirty-water (recovery) tank. Null when the hardware has no dirty-water tank. */
64733
- dirtyWater: TankStatusSchema.nullable(),
64734
- /** Detergent tank. Null when the hardware has no detergent tank. */
64735
- detergent: TankStatusSchema.nullable(),
64736
- /** Dust bin. Null when the hardware has no dust bin. */
64737
- dustBin: TankStatusSchema.nullable(),
64738
64817
  /** 0..100 cleaning-completion percentage of the current task, or null. */
64739
64818
  progressPercent: number().min(0).max(100).nullable(),
64740
64819
  /** Current error code (0 / null = no error). */
@@ -64796,35 +64875,14 @@ var vacuumControlCapability = {
64796
64875
  */
64797
64876
  durability: "session",
64798
64877
  /**
64799
- * History (D850): recorded series. Tank levels are fixed-object paths (`cleanWater.level`, ...).
64878
+ * History (D850): recorded series. The tanks moved to `consumables` (D915), whose
64879
+ * items are keyed by runtime ids and record no history.
64800
64880
  */
64801
- history: { fields: {
64802
- batteryLevel: {
64803
- kind: "gauge",
64804
- unit: "%",
64805
- deadband: 2
64806
- },
64807
- "cleanWater.level": {
64808
- kind: "gauge",
64809
- unit: "%",
64810
- deadband: 2
64811
- },
64812
- "dirtyWater.level": {
64813
- kind: "gauge",
64814
- unit: "%",
64815
- deadband: 2
64816
- },
64817
- "detergent.level": {
64818
- kind: "gauge",
64819
- unit: "%",
64820
- deadband: 2
64821
- },
64822
- "dustBin.level": {
64823
- kind: "gauge",
64824
- unit: "%",
64825
- deadband: 2
64826
- }
64827
- } }
64881
+ history: { fields: { batteryLevel: {
64882
+ kind: "gauge",
64883
+ unit: "%",
64884
+ deadband: 2
64885
+ } } }
64828
64886
  };
64829
64887
  var ValveStatusSchema = object({
64830
64888
  /** Lifecycle state of the valve. */
@@ -69218,6 +69276,12 @@ Object.freeze({
69218
69276
  addonId: null,
69219
69277
  access: "create"
69220
69278
  },
69279
+ "deviceHistory.deleteOrphanSeries": {
69280
+ capName: "device-history",
69281
+ capScope: "system",
69282
+ addonId: null,
69283
+ access: "delete"
69284
+ },
69221
69285
  "deviceHistory.getDeviceEnabled": {
69222
69286
  capName: "device-history",
69223
69287
  capScope: "system",
@@ -69236,6 +69300,12 @@ Object.freeze({
69236
69300
  addonId: null,
69237
69301
  access: "view"
69238
69302
  },
69303
+ "deviceHistory.listOrphanSeries": {
69304
+ capName: "device-history",
69305
+ capScope: "system",
69306
+ addonId: null,
69307
+ access: "view"
69308
+ },
69239
69309
  "deviceHistory.listSeries": {
69240
69310
  capName: "device-history",
69241
69311
  capScope: "system",
@@ -79241,7 +79311,7 @@ var STATE_SUMMARY_VARS = [
79241
79311
  ([...RULE_TEXT], [...COMBINED_ALARM]),
79242
79312
  ([...RULE_TEXT], [...DEVICE_EVENTS]),
79243
79313
  ([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
79244
- ([...RULE_TEXT], [...CONSUMABLE]),
79314
+ ([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
79245
79315
  ([...RULE_TEXT], [...TANK]),
79246
79316
  [...RULE_TEXT],
79247
79317
  ([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-unifi",
3
- "version": "0.2.142",
3
+ "version": "0.2.144",
4
4
  "description": "UniFi Network controller device-provider addon for CamStack — local-controller infra switches/APs (as containers) + network-client presence. NO cameras/Protect.",
5
5
  "keywords": [
6
6
  "camstack",