@camstack/addon-provider-dreame 0.2.150 → 0.2.151
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.
- package/dist/addon.js +302 -143
- package/dist/addon.mjs +302 -143
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -5476,7 +5476,7 @@ var ZodIssueCode$1 = {
|
|
|
5476
5476
|
var ZodFirstPartyTypeKind$1;
|
|
5477
5477
|
ZodFirstPartyTypeKind$1 || (ZodFirstPartyTypeKind$1 = {});
|
|
5478
5478
|
//#endregion
|
|
5479
|
-
//#region ../types/dist/sleep-
|
|
5479
|
+
//#region ../types/dist/sleep-CUp20JkO.mjs
|
|
5480
5480
|
/**
|
|
5481
5481
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5482
5482
|
* window to float samples (D455).
|
|
@@ -8368,7 +8368,11 @@ var ContributionSectionSchema = object({
|
|
|
8368
8368
|
literal(4)
|
|
8369
8369
|
]).optional(),
|
|
8370
8370
|
tab: string().optional(),
|
|
8371
|
-
location: _enum([
|
|
8371
|
+
location: _enum([
|
|
8372
|
+
"settings",
|
|
8373
|
+
"top-tab",
|
|
8374
|
+
"hero"
|
|
8375
|
+
]).optional(),
|
|
8372
8376
|
order: number().optional(),
|
|
8373
8377
|
fields: array(any())
|
|
8374
8378
|
});
|
|
@@ -13315,7 +13319,11 @@ var ConfigSectionWithValuesSchema = object({
|
|
|
13315
13319
|
literal(4)
|
|
13316
13320
|
]).optional(),
|
|
13317
13321
|
tab: string().optional(),
|
|
13318
|
-
location: _enum([
|
|
13322
|
+
location: _enum([
|
|
13323
|
+
"settings",
|
|
13324
|
+
"top-tab",
|
|
13325
|
+
"hero"
|
|
13326
|
+
]).optional(),
|
|
13319
13327
|
order: number().optional(),
|
|
13320
13328
|
fields: array(any())
|
|
13321
13329
|
});
|
|
@@ -17195,6 +17203,52 @@ var TierStatusSchema = object({
|
|
|
17195
17203
|
countedAt: number().nullable()
|
|
17196
17204
|
});
|
|
17197
17205
|
/** Operator/diagnostic view: rows per tier, last runs, refusals and drops since boot. */
|
|
17206
|
+
/**
|
|
17207
|
+
* Why a series is orphan. `device-gone`: its device is absent from the
|
|
17208
|
+
* successful device listings (the departure clock). `undeclared`: its `cap:`
|
|
17209
|
+
* key is declared by no capability any more (a field a cap removed).
|
|
17210
|
+
*/
|
|
17211
|
+
var DeviceHistoryOrphanReasonSchema = _enum(["device-gone", "undeclared"]);
|
|
17212
|
+
/** Rows held per stored tier. */
|
|
17213
|
+
var TierRowsSchema = object({
|
|
17214
|
+
raw: number().int(),
|
|
17215
|
+
"5m": number().int(),
|
|
17216
|
+
"1h": number().int(),
|
|
17217
|
+
"1d": number().int()
|
|
17218
|
+
});
|
|
17219
|
+
var OrphanSeriesSchema = object({
|
|
17220
|
+
seriesId: number().int(),
|
|
17221
|
+
deviceId: number().int(),
|
|
17222
|
+
key: string(),
|
|
17223
|
+
scope: string(),
|
|
17224
|
+
/** The metric's display name; `null` when its metric row is gone too. */
|
|
17225
|
+
displayName: string().nullable(),
|
|
17226
|
+
reason: DeviceHistoryOrphanReasonSchema,
|
|
17227
|
+
/** `device-gone`: since when the device has been absent; `null` otherwise. */
|
|
17228
|
+
missingSince: number().nullable(),
|
|
17229
|
+
firstTs: number(),
|
|
17230
|
+
lastTs: number(),
|
|
17231
|
+
rows: TierRowsSchema
|
|
17232
|
+
});
|
|
17233
|
+
var DeviceHistoryOrphanDeleteRefusalSchema = _enum([
|
|
17234
|
+
"not-found",
|
|
17235
|
+
"not-orphan",
|
|
17236
|
+
"failed"
|
|
17237
|
+
]);
|
|
17238
|
+
var OrphanDeleteEntrySchema = discriminatedUnion("ok", [object({
|
|
17239
|
+
seriesId: number().int(),
|
|
17240
|
+
ok: literal(true),
|
|
17241
|
+
deleted: TierRowsSchema
|
|
17242
|
+
}), object({
|
|
17243
|
+
seriesId: number().int(),
|
|
17244
|
+
ok: literal(false),
|
|
17245
|
+
reason: DeviceHistoryOrphanDeleteRefusalSchema
|
|
17246
|
+
})]);
|
|
17247
|
+
var OrphanListSchema = object({
|
|
17248
|
+
series: array(OrphanSeriesSchema).readonly(),
|
|
17249
|
+
/** More orphans exist than {@link DEVICE_HISTORY_ORPHAN_LIST_MAX}. */
|
|
17250
|
+
truncated: boolean()
|
|
17251
|
+
});
|
|
17198
17252
|
var DeviceHistoryStatusSchema = object({
|
|
17199
17253
|
startedAt: number(),
|
|
17200
17254
|
/** The store is declared, series loaded and the first reconcile has answered. */
|
|
@@ -17292,7 +17346,10 @@ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly())
|
|
|
17292
17346
|
}), object({ enabled: boolean() }), {
|
|
17293
17347
|
kind: "mutation",
|
|
17294
17348
|
auth: "admin"
|
|
17295
|
-
}), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" })
|
|
17349
|
+
}), 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() }), {
|
|
17350
|
+
kind: "mutation",
|
|
17351
|
+
auth: "admin"
|
|
17352
|
+
});
|
|
17296
17353
|
var DeviceCaStatusSchema = discriminatedUnion("state", [
|
|
17297
17354
|
object({ state: literal("absent") }),
|
|
17298
17355
|
object({
|
|
@@ -55189,17 +55246,73 @@ var connectivityCapability = {
|
|
|
55189
55246
|
volatileStateFields: ["lastChangedAt"]
|
|
55190
55247
|
};
|
|
55191
55248
|
/**
|
|
55192
|
-
* Generic device-consumables capability —
|
|
55193
|
-
*
|
|
55194
|
-
* descaling cycles,
|
|
55195
|
-
*
|
|
55196
|
-
*
|
|
55197
|
-
*
|
|
55249
|
+
* Generic device-consumables capability — the ONE place a device reports what
|
|
55250
|
+
* it uses up or fills: wear parts (vacuum filters/brushes, cartridges,
|
|
55251
|
+
* descaling cycles), supplies it draws from (a vacuum's clean-water tank and
|
|
55252
|
+
* detergent, a dishwasher's salt and rinse aid) and waste it collects (a dirty
|
|
55253
|
+
* water tank, a dust bin). Each item carries its remaining life or fill and an
|
|
55254
|
+
* optional "Replaced" reset action. Device-agnostic: any provider that knows
|
|
55255
|
+
* its device tracks consumables registers it; the provider names each item
|
|
55256
|
+
* verbatim and says which `kind` it is.
|
|
55257
|
+
*
|
|
55258
|
+
* The admin UI renders it as ONE collapsible section directly under the
|
|
55259
|
+
* device page's hero card (`placement: 'hero'`), for every device bound to
|
|
55260
|
+
* this cap — never drawn by a device type's hero card itself (D915).
|
|
55198
55261
|
*
|
|
55199
55262
|
* Like `childLayout`, the cap is INERT until a provider sets items: no
|
|
55200
55263
|
* provider populates it by guessing (no HA inference). The UI renders a
|
|
55201
55264
|
* "No consumables reported" placeholder when `items` is empty.
|
|
55202
55265
|
*/
|
|
55266
|
+
/**
|
|
55267
|
+
* What an item IS, which decides which direction is bad:
|
|
55268
|
+
* - `wear` — a part that wears out (a brush, a filter); low life is bad.
|
|
55269
|
+
* - `supply` — something the device draws from (clean water, detergent,
|
|
55270
|
+
* salt, rinse aid); low or empty is bad.
|
|
55271
|
+
* - `waste` — something the device fills (dirty water, a dust bin); full is
|
|
55272
|
+
* bad.
|
|
55273
|
+
* Absent = `wear`.
|
|
55274
|
+
*/
|
|
55275
|
+
var ConsumableKindSchema = _enum([
|
|
55276
|
+
"wear",
|
|
55277
|
+
"supply",
|
|
55278
|
+
"waste"
|
|
55279
|
+
]);
|
|
55280
|
+
/**
|
|
55281
|
+
* What an item LOOKS like, which decides how a client draws it — independent
|
|
55282
|
+
* of `kind`, which decides which direction is bad:
|
|
55283
|
+
* - `part` — a part that wears (a brush, a filter, a mop pad): a wear bar,
|
|
55284
|
+
* remaining time and a reset.
|
|
55285
|
+
* - `tank` — a container of liquid (clean water, dirty water): a fill gauge.
|
|
55286
|
+
* - `product` — something bought and refilled (detergent, salt, rinse aid):
|
|
55287
|
+
* a stepped level and "refill".
|
|
55288
|
+
* - `bin` — a container that collects waste (a dust bin): a fill gauge
|
|
55289
|
+
* that warns when full.
|
|
55290
|
+
* Absent = derived from the kind ({@link consumableFormOf}).
|
|
55291
|
+
*/
|
|
55292
|
+
var ConsumableFormSchema = _enum([
|
|
55293
|
+
"part",
|
|
55294
|
+
"tank",
|
|
55295
|
+
"product",
|
|
55296
|
+
"bin"
|
|
55297
|
+
]);
|
|
55298
|
+
/** The provider's own discrete verdict on an item. */
|
|
55299
|
+
var ConsumableStatusSchema = _enum([
|
|
55300
|
+
"ok",
|
|
55301
|
+
"low",
|
|
55302
|
+
"empty",
|
|
55303
|
+
"full",
|
|
55304
|
+
"replace"
|
|
55305
|
+
]);
|
|
55306
|
+
_enum([
|
|
55307
|
+
"ok",
|
|
55308
|
+
"low",
|
|
55309
|
+
"empty",
|
|
55310
|
+
"full"
|
|
55311
|
+
]);
|
|
55312
|
+
/** The kind of an item, with the documented default for an absent one. */
|
|
55313
|
+
function consumableKindOf(item) {
|
|
55314
|
+
return item.kind ?? "wear";
|
|
55315
|
+
}
|
|
55203
55316
|
/** Units a remaining-life counter is reported in. Closed: the panel renders
|
|
55204
55317
|
* each. */
|
|
55205
55318
|
var ConsumableRemainingUnitSchema = _enum([
|
|
@@ -55214,18 +55327,23 @@ var ConsumableRemainingSchema = object({
|
|
|
55214
55327
|
unit: ConsumableRemainingUnitSchema
|
|
55215
55328
|
});
|
|
55216
55329
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
55217
|
-
* life
|
|
55218
|
-
*
|
|
55219
|
-
* mutually exclusive; a provider may
|
|
55330
|
+
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
55331
|
+
* may be known — both may be null when a provider only knows the item
|
|
55332
|
+
* exists. `level` and `status` are not mutually exclusive; a provider may
|
|
55333
|
+
* report both. */
|
|
55220
55334
|
var ConsumableItemSchema = object({
|
|
55221
55335
|
/** Stable id, e.g. 'main-brush'. */
|
|
55222
55336
|
key: string().min(1),
|
|
55223
55337
|
/** Display name. */
|
|
55224
55338
|
label: string().min(1),
|
|
55225
|
-
/** Remaining life % when known (0..100). */
|
|
55339
|
+
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
55226
55340
|
level: number().min(0).max(100).nullable(),
|
|
55227
|
-
/**
|
|
55228
|
-
status:
|
|
55341
|
+
/** The provider's discrete verdict when known (binary mode). */
|
|
55342
|
+
status: ConsumableStatusSchema.nullable(),
|
|
55343
|
+
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
55344
|
+
kind: ConsumableKindSchema.optional(),
|
|
55345
|
+
/** How the item is drawn (part, tank, product, bin). Absent = derived from `kind`. */
|
|
55346
|
+
form: ConsumableFormSchema.optional(),
|
|
55229
55347
|
/** Ms epoch of the last replace, when known. */
|
|
55230
55348
|
lastResetAt: number().nullable(),
|
|
55231
55349
|
/** Whether `reset()` is meaningful for this item. */
|
|
@@ -55248,7 +55366,7 @@ var consumablesCapability = {
|
|
|
55248
55366
|
kind: "widget",
|
|
55249
55367
|
widgetId: "host/consumables-panel",
|
|
55250
55368
|
tab: "consumables",
|
|
55251
|
-
|
|
55369
|
+
placement: "hero",
|
|
55252
55370
|
label: "Consumables",
|
|
55253
55371
|
order: 5
|
|
55254
55372
|
} },
|
|
@@ -55309,9 +55427,37 @@ reset: method(object({
|
|
|
55309
55427
|
*/
|
|
55310
55428
|
durability: "restored",
|
|
55311
55429
|
/**
|
|
55312
|
-
* History (D850):
|
|
55430
|
+
* History (D850, D917): one series per (item field, item `key`) — the item key
|
|
55431
|
+
* is the series scope, the item `label` names it. A vacuum tank's fill, a
|
|
55432
|
+
* brush's remaining life and a dishwasher's salt are each recorded the moment
|
|
55433
|
+
* their provider reports them; an item that appears later gets its series.
|
|
55313
55434
|
*/
|
|
55314
|
-
history:
|
|
55435
|
+
history: {
|
|
55436
|
+
fields: {},
|
|
55437
|
+
items: {
|
|
55438
|
+
path: "items",
|
|
55439
|
+
key: "key",
|
|
55440
|
+
label: "label",
|
|
55441
|
+
fields: {
|
|
55442
|
+
level: {
|
|
55443
|
+
kind: "gauge",
|
|
55444
|
+
unit: "%",
|
|
55445
|
+
deadband: 2,
|
|
55446
|
+
displayName: "Level"
|
|
55447
|
+
},
|
|
55448
|
+
status: {
|
|
55449
|
+
kind: "enum",
|
|
55450
|
+
displayName: "Status"
|
|
55451
|
+
},
|
|
55452
|
+
"remaining.value": {
|
|
55453
|
+
kind: "gauge",
|
|
55454
|
+
unitFrom: "remaining.unit",
|
|
55455
|
+
deadband: 1,
|
|
55456
|
+
displayName: "Remaining"
|
|
55457
|
+
}
|
|
55458
|
+
}
|
|
55459
|
+
}
|
|
55460
|
+
},
|
|
55315
55461
|
/** Clocks, not content: a re-read that changed no item costs no commit. */
|
|
55316
55462
|
volatileStateFields: ["lastChangedAt", "lastFetchedAt"]
|
|
55317
55463
|
};
|
|
@@ -55726,8 +55872,9 @@ onStatusChanged: { data: object({
|
|
|
55726
55872
|
volatileStateFields: ["lastChangedAt"]
|
|
55727
55873
|
};
|
|
55728
55874
|
/**
|
|
55729
|
-
* Smart-dishwasher cap — program lifecycle, door / remote-start gates
|
|
55730
|
-
*
|
|
55875
|
+
* Smart-dishwasher cap — program lifecycle, door / remote-start gates and
|
|
55876
|
+
* common program options. Salt and rinse aid are NOT here: they are items of
|
|
55877
|
+
* the device's `consumables` cap, like every other device's (D915).
|
|
55731
55878
|
*
|
|
55732
55879
|
* Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
|
|
55733
55880
|
* by any integration that exposes the same program / option surface.
|
|
@@ -55775,11 +55922,6 @@ var DishwasherAvailabilitySchema = _enum([
|
|
|
55775
55922
|
"offline",
|
|
55776
55923
|
"description-missing"
|
|
55777
55924
|
]);
|
|
55778
|
-
var DishwasherConsumableLevelSchema = _enum([
|
|
55779
|
-
"ok",
|
|
55780
|
-
"low",
|
|
55781
|
-
"empty"
|
|
55782
|
-
]);
|
|
55783
55925
|
var DishwasherStatusSchema = object({
|
|
55784
55926
|
availability: DishwasherAvailabilitySchema,
|
|
55785
55927
|
/** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
|
|
@@ -55812,8 +55954,6 @@ var DishwasherStatusSchema = object({
|
|
|
55812
55954
|
powerOn: boolean().nullable(),
|
|
55813
55955
|
/** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
|
|
55814
55956
|
powerState: string().nullable(),
|
|
55815
|
-
saltLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
55816
|
-
rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
55817
55957
|
/**
|
|
55818
55958
|
* True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
|
|
55819
55959
|
* combined care-and-filter reminder raised); false when every such reminder reads clear; null
|
|
@@ -64777,60 +64917,17 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
|
|
|
64777
64917
|
auth: "admin",
|
|
64778
64918
|
access: "delete"
|
|
64779
64919
|
});
|
|
64780
|
-
/**
|
|
64781
|
-
* Robot-vacuum cap. Models HA `vacuum.*` entities — anything with a
|
|
64782
|
-
* cleaning lifecycle plus a return-to-base / locate surface and an
|
|
64783
|
-
* optional fan-speed selector.
|
|
64784
|
-
*
|
|
64785
|
-
* State follows HA's canonical vacuum lifecycle: `idle` / `cleaning` /
|
|
64786
|
-
* `paused` / `returning` / `docked` / `error`. `batteryLevel`
|
|
64787
|
-
* (0..100) is nullable — some vacuums don't report a battery
|
|
64788
|
-
* percentage. `fanSpeed` is the current speed token (provider-verbatim,
|
|
64789
|
-
* e.g. `'standard'` / `'turbo'`) and `availableFanSpeeds` lists the
|
|
64790
|
-
* tokens the hardware accepts so the UI renders only supported choices.
|
|
64791
|
-
*
|
|
64792
|
-
* The `setFanSpeed` method takes the bare `speed` token — the provider
|
|
64793
|
-
* validates it against the vacuum's own list. `locate` triggers the
|
|
64794
|
-
* find-me chirp; `returnToBase` sends it home.
|
|
64795
|
-
*
|
|
64796
|
-
* Consumable / waste tanks: `cleanWater` / `dirtyWater` / `detergent` /
|
|
64797
|
-
* `dustBin` each carry a nullable `{ level (0..100 %), status ('ok' |
|
|
64798
|
-
* 'low' | 'full') }` reading. Native providers (e.g. Dreame, Roborock)
|
|
64799
|
-
* SHOULD populate whichever tanks the hardware has — leave a field `null`
|
|
64800
|
-
* only when the device has no such tank at all, and use a `TankStatus`
|
|
64801
|
-
* with both inner fields `null` when the tank exists but its level is
|
|
64802
|
-
* currently unknown. HA `vacuum.*` entities expose no per-tank telemetry,
|
|
64803
|
-
* so the HA provider leaves all four `null`.
|
|
64804
|
-
*/
|
|
64805
|
-
var VacuumStateSchema = _enum([
|
|
64806
|
-
"idle",
|
|
64807
|
-
"cleaning",
|
|
64808
|
-
"paused",
|
|
64809
|
-
"returning",
|
|
64810
|
-
"docked",
|
|
64811
|
-
"drying",
|
|
64812
|
-
"error"
|
|
64813
|
-
]);
|
|
64814
|
-
/**
|
|
64815
|
-
* One consumable / waste tank on a robot vacuum (clean-water, dirty-water,
|
|
64816
|
-
* detergent or dust-bin). A tank can report a numeric fill `level` (0..100),
|
|
64817
|
-
* a discrete `status` (binary-style hardware), or both. Both `null` means the
|
|
64818
|
-
* level is currently unknown; the OWNING field being `null` means the
|
|
64819
|
-
* hardware has no such tank at all.
|
|
64820
|
-
*/
|
|
64821
|
-
var TankStatusSchema = object({
|
|
64822
|
-
/** Numeric fill 0..100 when the hardware reports a percentage; null otherwise. */
|
|
64823
|
-
level: number().min(0).max(100).nullable(),
|
|
64824
|
-
/** Discrete state when the hardware is binary-mode; null otherwise. */
|
|
64825
|
-
status: _enum([
|
|
64826
|
-
"ok",
|
|
64827
|
-
"low",
|
|
64828
|
-
"full"
|
|
64829
|
-
]).nullable()
|
|
64830
|
-
});
|
|
64831
64920
|
var VacuumControlStatusSchema = object({
|
|
64832
64921
|
/** Lifecycle state of the vacuum. */
|
|
64833
|
-
state:
|
|
64922
|
+
state: _enum([
|
|
64923
|
+
"idle",
|
|
64924
|
+
"cleaning",
|
|
64925
|
+
"paused",
|
|
64926
|
+
"returning",
|
|
64927
|
+
"docked",
|
|
64928
|
+
"drying",
|
|
64929
|
+
"error"
|
|
64930
|
+
]),
|
|
64834
64931
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
64835
64932
|
* reading. */
|
|
64836
64933
|
batteryLevel: number().min(0).max(100).nullable(),
|
|
@@ -64839,14 +64936,6 @@ var VacuumControlStatusSchema = object({
|
|
|
64839
64936
|
fanSpeed: string().nullable(),
|
|
64840
64937
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
64841
64938
|
availableFanSpeeds: array(string()),
|
|
64842
|
-
/** Clean-water (mop) tank. Null when the hardware has no clean-water tank. */
|
|
64843
|
-
cleanWater: TankStatusSchema.nullable(),
|
|
64844
|
-
/** Dirty-water (recovery) tank. Null when the hardware has no dirty-water tank. */
|
|
64845
|
-
dirtyWater: TankStatusSchema.nullable(),
|
|
64846
|
-
/** Detergent tank. Null when the hardware has no detergent tank. */
|
|
64847
|
-
detergent: TankStatusSchema.nullable(),
|
|
64848
|
-
/** Dust bin. Null when the hardware has no dust bin. */
|
|
64849
|
-
dustBin: TankStatusSchema.nullable(),
|
|
64850
64939
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
64851
64940
|
progressPercent: number().min(0).max(100).nullable(),
|
|
64852
64941
|
/** Current error code (0 / null = no error). */
|
|
@@ -64908,35 +64997,14 @@ var vacuumControlCapability = {
|
|
|
64908
64997
|
*/
|
|
64909
64998
|
durability: "session",
|
|
64910
64999
|
/**
|
|
64911
|
-
* History (D850): recorded series.
|
|
65000
|
+
* History (D850): recorded series. The tanks moved to `consumables` (D915), whose
|
|
65001
|
+
* items are keyed by runtime ids and record no history.
|
|
64912
65002
|
*/
|
|
64913
|
-
history: { fields: {
|
|
64914
|
-
|
|
64915
|
-
|
|
64916
|
-
|
|
64917
|
-
|
|
64918
|
-
},
|
|
64919
|
-
"cleanWater.level": {
|
|
64920
|
-
kind: "gauge",
|
|
64921
|
-
unit: "%",
|
|
64922
|
-
deadband: 2
|
|
64923
|
-
},
|
|
64924
|
-
"dirtyWater.level": {
|
|
64925
|
-
kind: "gauge",
|
|
64926
|
-
unit: "%",
|
|
64927
|
-
deadband: 2
|
|
64928
|
-
},
|
|
64929
|
-
"detergent.level": {
|
|
64930
|
-
kind: "gauge",
|
|
64931
|
-
unit: "%",
|
|
64932
|
-
deadband: 2
|
|
64933
|
-
},
|
|
64934
|
-
"dustBin.level": {
|
|
64935
|
-
kind: "gauge",
|
|
64936
|
-
unit: "%",
|
|
64937
|
-
deadband: 2
|
|
64938
|
-
}
|
|
64939
|
-
} }
|
|
65003
|
+
history: { fields: { batteryLevel: {
|
|
65004
|
+
kind: "gauge",
|
|
65005
|
+
unit: "%",
|
|
65006
|
+
deadband: 2
|
|
65007
|
+
} } }
|
|
64940
65008
|
};
|
|
64941
65009
|
var ValveStatusSchema = object({
|
|
64942
65010
|
/** Lifecycle state of the valve. */
|
|
@@ -69346,6 +69414,12 @@ Object.freeze({
|
|
|
69346
69414
|
addonId: null,
|
|
69347
69415
|
access: "create"
|
|
69348
69416
|
},
|
|
69417
|
+
"deviceHistory.deleteOrphanSeries": {
|
|
69418
|
+
capName: "device-history",
|
|
69419
|
+
capScope: "system",
|
|
69420
|
+
addonId: null,
|
|
69421
|
+
access: "delete"
|
|
69422
|
+
},
|
|
69349
69423
|
"deviceHistory.getDeviceEnabled": {
|
|
69350
69424
|
capName: "device-history",
|
|
69351
69425
|
capScope: "system",
|
|
@@ -69364,6 +69438,12 @@ Object.freeze({
|
|
|
69364
69438
|
addonId: null,
|
|
69365
69439
|
access: "view"
|
|
69366
69440
|
},
|
|
69441
|
+
"deviceHistory.listOrphanSeries": {
|
|
69442
|
+
capName: "device-history",
|
|
69443
|
+
capScope: "system",
|
|
69444
|
+
addonId: null,
|
|
69445
|
+
access: "view"
|
|
69446
|
+
},
|
|
69367
69447
|
"deviceHistory.listSeries": {
|
|
69368
69448
|
capName: "device-history",
|
|
69369
69449
|
capScope: "system",
|
|
@@ -79369,7 +79449,7 @@ var STATE_SUMMARY_VARS = [
|
|
|
79369
79449
|
([...RULE_TEXT], [...COMBINED_ALARM]),
|
|
79370
79450
|
([...RULE_TEXT], [...DEVICE_EVENTS]),
|
|
79371
79451
|
([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
|
|
79372
|
-
([...RULE_TEXT], [...CONSUMABLE]),
|
|
79452
|
+
([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
|
|
79373
79453
|
([...RULE_TEXT], [...TANK]),
|
|
79374
79454
|
[...RULE_TEXT],
|
|
79375
79455
|
([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
|
|
@@ -135239,8 +135319,7 @@ function dirtyWaterTankStatus(value, errorCode) {
|
|
|
135239
135319
|
return null;
|
|
135240
135320
|
}
|
|
135241
135321
|
/**
|
|
135242
|
-
* The four
|
|
135243
|
-
* dust-bin) decoded from the model's {@link VacuumCapabilities}, with the
|
|
135322
|
+
* The four tanks (clean-water / dirty-water / detergent / dust-bin) decoded from the model's {@link VacuumCapabilities}, with the
|
|
135244
135323
|
* discrete `status` populated from the live MIoT enum props when supplied. Pure.
|
|
135245
135324
|
*
|
|
135246
135325
|
* The nodedreame library exposes NO tank FILL-LEVEL telemetry — the cloud shadow
|
|
@@ -135271,6 +135350,57 @@ function decodeVacuumTanks(caps, props, errorCode = null) {
|
|
|
135271
135350
|
dustBin: tank(Boolean(caps?.canAutoEmpty), props ? dustBinTankStatus(props.dustCollection, props.dustBagStatus) : null)
|
|
135272
135351
|
};
|
|
135273
135352
|
}
|
|
135353
|
+
/** How each tank is named and what it is, in the order the panel lists them. */
|
|
135354
|
+
var TANK_ITEMS = [
|
|
135355
|
+
{
|
|
135356
|
+
key: "cleanWater",
|
|
135357
|
+
label: "Clean water tank",
|
|
135358
|
+
kind: "supply",
|
|
135359
|
+
form: "tank"
|
|
135360
|
+
},
|
|
135361
|
+
{
|
|
135362
|
+
key: "dirtyWater",
|
|
135363
|
+
label: "Dirty water tank",
|
|
135364
|
+
kind: "waste",
|
|
135365
|
+
form: "tank"
|
|
135366
|
+
},
|
|
135367
|
+
{
|
|
135368
|
+
key: "detergent",
|
|
135369
|
+
label: "Detergent",
|
|
135370
|
+
kind: "supply",
|
|
135371
|
+
form: "product"
|
|
135372
|
+
},
|
|
135373
|
+
{
|
|
135374
|
+
key: "dustBin",
|
|
135375
|
+
label: "Dust bin",
|
|
135376
|
+
kind: "waste",
|
|
135377
|
+
form: "bin"
|
|
135378
|
+
}
|
|
135379
|
+
];
|
|
135380
|
+
/**
|
|
135381
|
+
* The tanks as `consumables` items (D915): every PRESENT tank becomes a
|
|
135382
|
+
* `supply` (clean water, detergent) or `waste` (dirty water, dust bin) item
|
|
135383
|
+
* keyed by its old field name, drawn as a `tank` (the two water tanks), a
|
|
135384
|
+
* `product` (detergent) or a `bin` (the dust bin) — the key the notification centre's tank
|
|
135385
|
+
* episodes were built on, so an open episode carries on. A tank is never
|
|
135386
|
+
* resettable: emptying or refilling it is the reset. Pure.
|
|
135387
|
+
*/
|
|
135388
|
+
function vacuumTankItems(tanks) {
|
|
135389
|
+
return TANK_ITEMS.flatMap(({ key, label, kind, form }) => {
|
|
135390
|
+
const tank = tanks[key];
|
|
135391
|
+
if (tank === null) return [];
|
|
135392
|
+
return [{
|
|
135393
|
+
key,
|
|
135394
|
+
label,
|
|
135395
|
+
level: tank.level,
|
|
135396
|
+
status: tank.status,
|
|
135397
|
+
kind,
|
|
135398
|
+
form,
|
|
135399
|
+
lastResetAt: null,
|
|
135400
|
+
resettable: false
|
|
135401
|
+
}];
|
|
135402
|
+
});
|
|
135403
|
+
}
|
|
135274
135404
|
/**
|
|
135275
135405
|
* Clamp a raw consumable percentage to `[0, 100]`, or return `null` when the
|
|
135276
135406
|
* value is absent / non-finite. The library reports remaining life as a 0..100
|
|
@@ -135299,7 +135429,8 @@ function buildVacuumConsumableItems(readings) {
|
|
|
135299
135429
|
level: clampConsumablePct(c.leftPct),
|
|
135300
135430
|
status: null,
|
|
135301
135431
|
lastResetAt: null,
|
|
135302
|
-
resettable: c.resettable
|
|
135432
|
+
resettable: c.resettable,
|
|
135433
|
+
form: "part"
|
|
135303
135434
|
}));
|
|
135304
135435
|
}
|
|
135305
135436
|
/** Structural equality of two JSON-shaped values, key order ignored. */
|
|
@@ -182684,7 +182815,8 @@ function buildMowerConsumables(readings) {
|
|
|
182684
182815
|
level: r.remainingPercent,
|
|
182685
182816
|
status: null,
|
|
182686
182817
|
lastResetAt: null,
|
|
182687
|
-
resettable: true
|
|
182818
|
+
resettable: true,
|
|
182819
|
+
form: "part"
|
|
182688
182820
|
}));
|
|
182689
182821
|
}
|
|
182690
182822
|
//#endregion
|
|
@@ -182708,7 +182840,7 @@ var CONSUMABLES_COLD_START = {
|
|
|
182708
182840
|
lastFetchedAt: 0
|
|
182709
182841
|
};
|
|
182710
182842
|
function itemEqual(a, b) {
|
|
182711
|
-
return a.key === b.key && a.label === b.label && a.level === b.level && a.status === b.status && a.lastResetAt === b.lastResetAt && a.resettable === b.resettable;
|
|
182843
|
+
return a.key === b.key && a.label === b.label && a.level === b.level && a.status === b.status && a.lastResetAt === b.lastResetAt && a.resettable === b.resettable && a.kind === b.kind && a.remaining?.value === b.remaining?.value && a.remaining?.unit === b.remaining?.unit;
|
|
182712
182844
|
}
|
|
182713
182845
|
function itemsEqual(a, b) {
|
|
182714
182846
|
return a.length === b.length && a.every((item, i) => {
|
|
@@ -183698,6 +183830,31 @@ var DreameSwitchDevice = class extends DreameChildDevice {
|
|
|
183698
183830
|
};
|
|
183699
183831
|
//#endregion
|
|
183700
183832
|
//#region src/devices/dreame-vacuum-consumables.ts
|
|
183833
|
+
/**
|
|
183834
|
+
* The vacuum's `consumables` slice: when it is re-read, and what a reset does.
|
|
183835
|
+
*
|
|
183836
|
+
* The life %s and their time-left twins are settings the robot rarely re-pushes
|
|
183837
|
+
* over MQTT, and the library does not poll them. So they are re-read from the
|
|
183838
|
+
* cloud SHADOW (no robot wake) on activate, every {@link CONSUMABLES_REFRESH_MS},
|
|
183839
|
+
* and on the edge INTO `docked` — the moment a run has just used them up. The
|
|
183840
|
+
* same read reseeds the station tank-status props (dirty water, dust bag, …),
|
|
183841
|
+
* which otherwise arrive only as pushes.
|
|
183842
|
+
*
|
|
183843
|
+
* A reset goes through the library, which re-reads the item it reset (live,
|
|
183844
|
+
* else shadow) before it resolves; the slice is rebuilt from that. A shadow
|
|
183845
|
+
* answer may still be the pre-reset value, so it earns ONE follow-up refresh.
|
|
183846
|
+
*
|
|
183847
|
+
* The TANKS ride the same slice (D915): every push hands over the tank items
|
|
183848
|
+
* the device decoded, appended after the wear items. Either half may be
|
|
183849
|
+
* unknown for a while after a restart — the shadow has not answered, or a
|
|
183850
|
+
* refresh lands before the first push brought the tanks — and the slice is
|
|
183851
|
+
* `restored`, so an unknown half keeps the restored rows instead of erasing
|
|
183852
|
+
* them.
|
|
183853
|
+
*/
|
|
183854
|
+
/** A tank item (`supply` / `waste`) as opposed to a wear item. */
|
|
183855
|
+
function isTankItem(item) {
|
|
183856
|
+
return consumableKindOf(item) !== "wear";
|
|
183857
|
+
}
|
|
183701
183858
|
/** Hourly: a consumable moves by hours of cleaning, and the dock edge covers a run. */
|
|
183702
183859
|
var CONSUMABLES_REFRESH_MS = 60 * 6e4;
|
|
183703
183860
|
/** Time for the robot to report a reset to the cloud before the shadow is re-read. */
|
|
@@ -183714,6 +183871,8 @@ var DreameVacuumConsumables = class {
|
|
|
183714
183871
|
#refresher;
|
|
183715
183872
|
/** Last pushed lifecycle state; `null` until the first push after boot. */
|
|
183716
183873
|
#prevState = null;
|
|
183874
|
+
/** Last pushed tank items; `null` until the first push after boot. */
|
|
183875
|
+
#tanks = null;
|
|
183717
183876
|
constructor(deps) {
|
|
183718
183877
|
this.#deps = deps;
|
|
183719
183878
|
this.#refresher = new DreameConsumablesRefresher({
|
|
@@ -183733,12 +183892,14 @@ var DreameVacuumConsumables = class {
|
|
|
183733
183892
|
this.#refresher.stop();
|
|
183734
183893
|
}
|
|
183735
183894
|
/**
|
|
183736
|
-
* Every `stateChanged` push: replay the cache
|
|
183737
|
-
* an item changed) and refresh on the edge into
|
|
183738
|
-
* boot is not an edge — activation already
|
|
183739
|
-
* between station routines (`drying` →
|
|
183895
|
+
* Every `stateChanged` push: replay the cache and the pushed tanks into the
|
|
183896
|
+
* slice (written only if an item changed) and refresh on the edge into
|
|
183897
|
+
* `docked`. The first push after boot is not an edge — activation already
|
|
183898
|
+
* reads — and neither is a hop between station routines (`drying` →
|
|
183899
|
+
* `docked`): only the end of a RUN is.
|
|
183740
183900
|
*/
|
|
183741
|
-
onPush(state) {
|
|
183901
|
+
onPush(state, tanks) {
|
|
183902
|
+
this.#tanks = tanks;
|
|
183742
183903
|
this.#apply(false);
|
|
183743
183904
|
const enteredDock = this.#prevState !== null && DOCK_EDGE_FROM.has(this.#prevState) && state === "docked";
|
|
183744
183905
|
this.#prevState = state;
|
|
@@ -183788,7 +183949,11 @@ var DreameVacuumConsumables = class {
|
|
|
183788
183949
|
const { store, resolveVacuum, now } = this.#deps;
|
|
183789
183950
|
const vacuum = resolveVacuum();
|
|
183790
183951
|
if (vacuum === null) return;
|
|
183791
|
-
|
|
183952
|
+
const prev = store.getCapState("consumables")?.items ?? [];
|
|
183953
|
+
const read = buildVacuumConsumableItems(vacuum.supportedConsumables);
|
|
183954
|
+
const wear = read.length > 0 ? read : prev.filter((item) => !isTankItem(item));
|
|
183955
|
+
const tanks = this.#tanks ?? prev.filter(isTankItem);
|
|
183956
|
+
writeConsumables(store, [...wear, ...tanks], (now ?? Date.now)(), landed);
|
|
183792
183957
|
}
|
|
183793
183958
|
};
|
|
183794
183959
|
function resetMeta(result) {
|
|
@@ -183808,10 +183973,6 @@ var CONTROL_COLD_START = {
|
|
|
183808
183973
|
batteryLevel: null,
|
|
183809
183974
|
fanSpeed: null,
|
|
183810
183975
|
availableFanSpeeds: [],
|
|
183811
|
-
cleanWater: null,
|
|
183812
|
-
dirtyWater: null,
|
|
183813
|
-
detergent: null,
|
|
183814
|
-
dustBin: null,
|
|
183815
183976
|
progressPercent: null,
|
|
183816
183977
|
errorCode: null,
|
|
183817
183978
|
errorLabel: null,
|
|
@@ -183827,11 +183988,13 @@ var CONTROL_COLD_START = {
|
|
|
183827
183988
|
* `setFanSpeed`→`setSuction()` (token validated against the model's supported
|
|
183828
183989
|
* suction levels).
|
|
183829
183990
|
*
|
|
183830
|
-
*
|
|
183831
|
-
*
|
|
183832
|
-
*
|
|
183833
|
-
*
|
|
183834
|
-
*
|
|
183991
|
+
* Tanks (clean water / dirty water / detergent / dust bin) are `supply` /
|
|
183992
|
+
* `waste` items of the `consumables` slice (D915), not `vacuum-control` fields:
|
|
183993
|
+
* the library exposes NO tank fill LEVEL, so `level` is always null. PRESENCE
|
|
183994
|
+
* comes from the model capability flags and a discrete `status` from the
|
|
183995
|
+
* station's tank-status enum props (`decodeVacuumTanks`, ids in
|
|
183996
|
+
* `VACUUM_TANK_PROPS`); an absent tank is no item, an unknown status is `null`
|
|
183997
|
+
* — never `ok`.
|
|
183835
183998
|
*
|
|
183836
183999
|
* Consumables: whatever the model REPORTS (the library's presence-driven
|
|
183837
184000
|
* `supportedConsumables`), re-read from the cloud shadow on activate, hourly and
|
|
@@ -183955,16 +184118,12 @@ var DreameVacuumDevice = class extends DreameChildDevice {
|
|
|
183955
184118
|
recomputeSlice() {
|
|
183956
184119
|
const vacuum = this.resolveVacuum();
|
|
183957
184120
|
if (vacuum === null) return;
|
|
183958
|
-
const tanks = decodeVacuumTanks(vacuum.vacuumCapabilities, this.readTankProps(), vacuum.errorCode);
|
|
184121
|
+
const tanks = vacuumTankItems(decodeVacuumTanks(vacuum.vacuumCapabilities, this.readTankProps(), vacuum.errorCode));
|
|
183959
184122
|
const controlSlice = {
|
|
183960
184123
|
state: mapMiotStateToVacuumState(vacuum.status),
|
|
183961
184124
|
batteryLevel: clampBatteryLevel$1(vacuum.battery),
|
|
183962
184125
|
fanSpeed: suctionLevelToken(vacuum.suction),
|
|
183963
184126
|
availableFanSpeeds: supportedFanSpeedTokens(vacuum.supportedSuctionLevels),
|
|
183964
|
-
cleanWater: tanks.cleanWater,
|
|
183965
|
-
dirtyWater: tanks.dirtyWater,
|
|
183966
|
-
detergent: tanks.detergent,
|
|
183967
|
-
dustBin: tanks.dustBin,
|
|
183968
184127
|
progressPercent: clampPercent$1(vacuum.taskProgressPct),
|
|
183969
184128
|
errorCode: vacuum.errorCode,
|
|
183970
184129
|
errorLabel: vacuum.errorCode ? `Error ${vacuum.errorCode}` : null,
|
|
@@ -183972,7 +184131,7 @@ var DreameVacuumDevice = class extends DreameChildDevice {
|
|
|
183972
184131
|
};
|
|
183973
184132
|
const toWrite = nextVacuumControlSlice(this.runtimeState.getCapState(CAP_NAME$1), controlSlice);
|
|
183974
184133
|
if (toWrite !== null) this.runtimeState.setCapState(CAP_NAME$1, toWrite);
|
|
183975
|
-
this.consumables.onPush(controlSlice.state);
|
|
184134
|
+
this.consumables.onPush(controlSlice.state, tanks);
|
|
183976
184135
|
}
|
|
183977
184136
|
/**
|
|
183978
184137
|
* Read the tank-status MIoT enum props ({@link VACUUM_TANK_PROPS}) from the
|
package/dist/addon.mjs
CHANGED
|
@@ -5473,7 +5473,7 @@ var ZodIssueCode$1 = {
|
|
|
5473
5473
|
var ZodFirstPartyTypeKind$1;
|
|
5474
5474
|
ZodFirstPartyTypeKind$1 || (ZodFirstPartyTypeKind$1 = {});
|
|
5475
5475
|
//#endregion
|
|
5476
|
-
//#region ../types/dist/sleep-
|
|
5476
|
+
//#region ../types/dist/sleep-CUp20JkO.mjs
|
|
5477
5477
|
/**
|
|
5478
5478
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5479
5479
|
* window to float samples (D455).
|
|
@@ -8365,7 +8365,11 @@ var ContributionSectionSchema = object({
|
|
|
8365
8365
|
literal(4)
|
|
8366
8366
|
]).optional(),
|
|
8367
8367
|
tab: string().optional(),
|
|
8368
|
-
location: _enum([
|
|
8368
|
+
location: _enum([
|
|
8369
|
+
"settings",
|
|
8370
|
+
"top-tab",
|
|
8371
|
+
"hero"
|
|
8372
|
+
]).optional(),
|
|
8369
8373
|
order: number().optional(),
|
|
8370
8374
|
fields: array(any())
|
|
8371
8375
|
});
|
|
@@ -13312,7 +13316,11 @@ var ConfigSectionWithValuesSchema = object({
|
|
|
13312
13316
|
literal(4)
|
|
13313
13317
|
]).optional(),
|
|
13314
13318
|
tab: string().optional(),
|
|
13315
|
-
location: _enum([
|
|
13319
|
+
location: _enum([
|
|
13320
|
+
"settings",
|
|
13321
|
+
"top-tab",
|
|
13322
|
+
"hero"
|
|
13323
|
+
]).optional(),
|
|
13316
13324
|
order: number().optional(),
|
|
13317
13325
|
fields: array(any())
|
|
13318
13326
|
});
|
|
@@ -17192,6 +17200,52 @@ var TierStatusSchema = object({
|
|
|
17192
17200
|
countedAt: number().nullable()
|
|
17193
17201
|
});
|
|
17194
17202
|
/** Operator/diagnostic view: rows per tier, last runs, refusals and drops since boot. */
|
|
17203
|
+
/**
|
|
17204
|
+
* Why a series is orphan. `device-gone`: its device is absent from the
|
|
17205
|
+
* successful device listings (the departure clock). `undeclared`: its `cap:`
|
|
17206
|
+
* key is declared by no capability any more (a field a cap removed).
|
|
17207
|
+
*/
|
|
17208
|
+
var DeviceHistoryOrphanReasonSchema = _enum(["device-gone", "undeclared"]);
|
|
17209
|
+
/** Rows held per stored tier. */
|
|
17210
|
+
var TierRowsSchema = object({
|
|
17211
|
+
raw: number().int(),
|
|
17212
|
+
"5m": number().int(),
|
|
17213
|
+
"1h": number().int(),
|
|
17214
|
+
"1d": number().int()
|
|
17215
|
+
});
|
|
17216
|
+
var OrphanSeriesSchema = object({
|
|
17217
|
+
seriesId: number().int(),
|
|
17218
|
+
deviceId: number().int(),
|
|
17219
|
+
key: string(),
|
|
17220
|
+
scope: string(),
|
|
17221
|
+
/** The metric's display name; `null` when its metric row is gone too. */
|
|
17222
|
+
displayName: string().nullable(),
|
|
17223
|
+
reason: DeviceHistoryOrphanReasonSchema,
|
|
17224
|
+
/** `device-gone`: since when the device has been absent; `null` otherwise. */
|
|
17225
|
+
missingSince: number().nullable(),
|
|
17226
|
+
firstTs: number(),
|
|
17227
|
+
lastTs: number(),
|
|
17228
|
+
rows: TierRowsSchema
|
|
17229
|
+
});
|
|
17230
|
+
var DeviceHistoryOrphanDeleteRefusalSchema = _enum([
|
|
17231
|
+
"not-found",
|
|
17232
|
+
"not-orphan",
|
|
17233
|
+
"failed"
|
|
17234
|
+
]);
|
|
17235
|
+
var OrphanDeleteEntrySchema = discriminatedUnion("ok", [object({
|
|
17236
|
+
seriesId: number().int(),
|
|
17237
|
+
ok: literal(true),
|
|
17238
|
+
deleted: TierRowsSchema
|
|
17239
|
+
}), object({
|
|
17240
|
+
seriesId: number().int(),
|
|
17241
|
+
ok: literal(false),
|
|
17242
|
+
reason: DeviceHistoryOrphanDeleteRefusalSchema
|
|
17243
|
+
})]);
|
|
17244
|
+
var OrphanListSchema = object({
|
|
17245
|
+
series: array(OrphanSeriesSchema).readonly(),
|
|
17246
|
+
/** More orphans exist than {@link DEVICE_HISTORY_ORPHAN_LIST_MAX}. */
|
|
17247
|
+
truncated: boolean()
|
|
17248
|
+
});
|
|
17195
17249
|
var DeviceHistoryStatusSchema = object({
|
|
17196
17250
|
startedAt: number(),
|
|
17197
17251
|
/** The store is declared, series loaded and the first reconcile has answered. */
|
|
@@ -17289,7 +17343,10 @@ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly())
|
|
|
17289
17343
|
}), object({ enabled: boolean() }), {
|
|
17290
17344
|
kind: "mutation",
|
|
17291
17345
|
auth: "admin"
|
|
17292
|
-
}), method(object({}), DeviceHistoryStatusSchema, { auth: "admin" })
|
|
17346
|
+
}), 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() }), {
|
|
17347
|
+
kind: "mutation",
|
|
17348
|
+
auth: "admin"
|
|
17349
|
+
});
|
|
17293
17350
|
var DeviceCaStatusSchema = discriminatedUnion("state", [
|
|
17294
17351
|
object({ state: literal("absent") }),
|
|
17295
17352
|
object({
|
|
@@ -55186,17 +55243,73 @@ var connectivityCapability = {
|
|
|
55186
55243
|
volatileStateFields: ["lastChangedAt"]
|
|
55187
55244
|
};
|
|
55188
55245
|
/**
|
|
55189
|
-
* Generic device-consumables capability —
|
|
55190
|
-
*
|
|
55191
|
-
* descaling cycles,
|
|
55192
|
-
*
|
|
55193
|
-
*
|
|
55194
|
-
*
|
|
55246
|
+
* Generic device-consumables capability — the ONE place a device reports what
|
|
55247
|
+
* it uses up or fills: wear parts (vacuum filters/brushes, cartridges,
|
|
55248
|
+
* descaling cycles), supplies it draws from (a vacuum's clean-water tank and
|
|
55249
|
+
* detergent, a dishwasher's salt and rinse aid) and waste it collects (a dirty
|
|
55250
|
+
* water tank, a dust bin). Each item carries its remaining life or fill and an
|
|
55251
|
+
* optional "Replaced" reset action. Device-agnostic: any provider that knows
|
|
55252
|
+
* its device tracks consumables registers it; the provider names each item
|
|
55253
|
+
* verbatim and says which `kind` it is.
|
|
55254
|
+
*
|
|
55255
|
+
* The admin UI renders it as ONE collapsible section directly under the
|
|
55256
|
+
* device page's hero card (`placement: 'hero'`), for every device bound to
|
|
55257
|
+
* this cap — never drawn by a device type's hero card itself (D915).
|
|
55195
55258
|
*
|
|
55196
55259
|
* Like `childLayout`, the cap is INERT until a provider sets items: no
|
|
55197
55260
|
* provider populates it by guessing (no HA inference). The UI renders a
|
|
55198
55261
|
* "No consumables reported" placeholder when `items` is empty.
|
|
55199
55262
|
*/
|
|
55263
|
+
/**
|
|
55264
|
+
* What an item IS, which decides which direction is bad:
|
|
55265
|
+
* - `wear` — a part that wears out (a brush, a filter); low life is bad.
|
|
55266
|
+
* - `supply` — something the device draws from (clean water, detergent,
|
|
55267
|
+
* salt, rinse aid); low or empty is bad.
|
|
55268
|
+
* - `waste` — something the device fills (dirty water, a dust bin); full is
|
|
55269
|
+
* bad.
|
|
55270
|
+
* Absent = `wear`.
|
|
55271
|
+
*/
|
|
55272
|
+
var ConsumableKindSchema = _enum([
|
|
55273
|
+
"wear",
|
|
55274
|
+
"supply",
|
|
55275
|
+
"waste"
|
|
55276
|
+
]);
|
|
55277
|
+
/**
|
|
55278
|
+
* What an item LOOKS like, which decides how a client draws it — independent
|
|
55279
|
+
* of `kind`, which decides which direction is bad:
|
|
55280
|
+
* - `part` — a part that wears (a brush, a filter, a mop pad): a wear bar,
|
|
55281
|
+
* remaining time and a reset.
|
|
55282
|
+
* - `tank` — a container of liquid (clean water, dirty water): a fill gauge.
|
|
55283
|
+
* - `product` — something bought and refilled (detergent, salt, rinse aid):
|
|
55284
|
+
* a stepped level and "refill".
|
|
55285
|
+
* - `bin` — a container that collects waste (a dust bin): a fill gauge
|
|
55286
|
+
* that warns when full.
|
|
55287
|
+
* Absent = derived from the kind ({@link consumableFormOf}).
|
|
55288
|
+
*/
|
|
55289
|
+
var ConsumableFormSchema = _enum([
|
|
55290
|
+
"part",
|
|
55291
|
+
"tank",
|
|
55292
|
+
"product",
|
|
55293
|
+
"bin"
|
|
55294
|
+
]);
|
|
55295
|
+
/** The provider's own discrete verdict on an item. */
|
|
55296
|
+
var ConsumableStatusSchema = _enum([
|
|
55297
|
+
"ok",
|
|
55298
|
+
"low",
|
|
55299
|
+
"empty",
|
|
55300
|
+
"full",
|
|
55301
|
+
"replace"
|
|
55302
|
+
]);
|
|
55303
|
+
_enum([
|
|
55304
|
+
"ok",
|
|
55305
|
+
"low",
|
|
55306
|
+
"empty",
|
|
55307
|
+
"full"
|
|
55308
|
+
]);
|
|
55309
|
+
/** The kind of an item, with the documented default for an absent one. */
|
|
55310
|
+
function consumableKindOf(item) {
|
|
55311
|
+
return item.kind ?? "wear";
|
|
55312
|
+
}
|
|
55200
55313
|
/** Units a remaining-life counter is reported in. Closed: the panel renders
|
|
55201
55314
|
* each. */
|
|
55202
55315
|
var ConsumableRemainingUnitSchema = _enum([
|
|
@@ -55211,18 +55324,23 @@ var ConsumableRemainingSchema = object({
|
|
|
55211
55324
|
unit: ConsumableRemainingUnitSchema
|
|
55212
55325
|
});
|
|
55213
55326
|
/** A single consumable item. Either a continuous `level` (remaining
|
|
55214
|
-
* life
|
|
55215
|
-
*
|
|
55216
|
-
* mutually exclusive; a provider may
|
|
55327
|
+
* life %, or fill % for a `supply` / `waste` item) or a discrete `status`
|
|
55328
|
+
* may be known — both may be null when a provider only knows the item
|
|
55329
|
+
* exists. `level` and `status` are not mutually exclusive; a provider may
|
|
55330
|
+
* report both. */
|
|
55217
55331
|
var ConsumableItemSchema = object({
|
|
55218
55332
|
/** Stable id, e.g. 'main-brush'. */
|
|
55219
55333
|
key: string().min(1),
|
|
55220
55334
|
/** Display name. */
|
|
55221
55335
|
label: string().min(1),
|
|
55222
|
-
/** Remaining life % when known (0..100). */
|
|
55336
|
+
/** Remaining life % (`wear`) or fill % (`supply`, `waste`) when known (0..100). */
|
|
55223
55337
|
level: number().min(0).max(100).nullable(),
|
|
55224
|
-
/**
|
|
55225
|
-
status:
|
|
55338
|
+
/** The provider's discrete verdict when known (binary mode). */
|
|
55339
|
+
status: ConsumableStatusSchema.nullable(),
|
|
55340
|
+
/** What the item is — decides whether low or full is bad. Absent = `wear`. */
|
|
55341
|
+
kind: ConsumableKindSchema.optional(),
|
|
55342
|
+
/** How the item is drawn (part, tank, product, bin). Absent = derived from `kind`. */
|
|
55343
|
+
form: ConsumableFormSchema.optional(),
|
|
55226
55344
|
/** Ms epoch of the last replace, when known. */
|
|
55227
55345
|
lastResetAt: number().nullable(),
|
|
55228
55346
|
/** Whether `reset()` is meaningful for this item. */
|
|
@@ -55245,7 +55363,7 @@ var consumablesCapability = {
|
|
|
55245
55363
|
kind: "widget",
|
|
55246
55364
|
widgetId: "host/consumables-panel",
|
|
55247
55365
|
tab: "consumables",
|
|
55248
|
-
|
|
55366
|
+
placement: "hero",
|
|
55249
55367
|
label: "Consumables",
|
|
55250
55368
|
order: 5
|
|
55251
55369
|
} },
|
|
@@ -55306,9 +55424,37 @@ reset: method(object({
|
|
|
55306
55424
|
*/
|
|
55307
55425
|
durability: "restored",
|
|
55308
55426
|
/**
|
|
55309
|
-
* History (D850):
|
|
55427
|
+
* History (D850, D917): one series per (item field, item `key`) — the item key
|
|
55428
|
+
* is the series scope, the item `label` names it. A vacuum tank's fill, a
|
|
55429
|
+
* brush's remaining life and a dishwasher's salt are each recorded the moment
|
|
55430
|
+
* their provider reports them; an item that appears later gets its series.
|
|
55310
55431
|
*/
|
|
55311
|
-
history:
|
|
55432
|
+
history: {
|
|
55433
|
+
fields: {},
|
|
55434
|
+
items: {
|
|
55435
|
+
path: "items",
|
|
55436
|
+
key: "key",
|
|
55437
|
+
label: "label",
|
|
55438
|
+
fields: {
|
|
55439
|
+
level: {
|
|
55440
|
+
kind: "gauge",
|
|
55441
|
+
unit: "%",
|
|
55442
|
+
deadband: 2,
|
|
55443
|
+
displayName: "Level"
|
|
55444
|
+
},
|
|
55445
|
+
status: {
|
|
55446
|
+
kind: "enum",
|
|
55447
|
+
displayName: "Status"
|
|
55448
|
+
},
|
|
55449
|
+
"remaining.value": {
|
|
55450
|
+
kind: "gauge",
|
|
55451
|
+
unitFrom: "remaining.unit",
|
|
55452
|
+
deadband: 1,
|
|
55453
|
+
displayName: "Remaining"
|
|
55454
|
+
}
|
|
55455
|
+
}
|
|
55456
|
+
}
|
|
55457
|
+
},
|
|
55312
55458
|
/** Clocks, not content: a re-read that changed no item costs no commit. */
|
|
55313
55459
|
volatileStateFields: ["lastChangedAt", "lastFetchedAt"]
|
|
55314
55460
|
};
|
|
@@ -55723,8 +55869,9 @@ onStatusChanged: { data: object({
|
|
|
55723
55869
|
volatileStateFields: ["lastChangedAt"]
|
|
55724
55870
|
};
|
|
55725
55871
|
/**
|
|
55726
|
-
* Smart-dishwasher cap — program lifecycle, door / remote-start gates
|
|
55727
|
-
*
|
|
55872
|
+
* Smart-dishwasher cap — program lifecycle, door / remote-start gates and
|
|
55873
|
+
* common program options. Salt and rinse aid are NOT here: they are items of
|
|
55874
|
+
* the device's `consumables` cap, like every other device's (D915).
|
|
55728
55875
|
*
|
|
55729
55876
|
* Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
|
|
55730
55877
|
* by any integration that exposes the same program / option surface.
|
|
@@ -55772,11 +55919,6 @@ var DishwasherAvailabilitySchema = _enum([
|
|
|
55772
55919
|
"offline",
|
|
55773
55920
|
"description-missing"
|
|
55774
55921
|
]);
|
|
55775
|
-
var DishwasherConsumableLevelSchema = _enum([
|
|
55776
|
-
"ok",
|
|
55777
|
-
"low",
|
|
55778
|
-
"empty"
|
|
55779
|
-
]);
|
|
55780
55922
|
var DishwasherStatusSchema = object({
|
|
55781
55923
|
availability: DishwasherAvailabilitySchema,
|
|
55782
55924
|
/** Coarse state for compact surfaces; `unavailable` whenever the appliance state is not known. */
|
|
@@ -55809,8 +55951,6 @@ var DishwasherStatusSchema = object({
|
|
|
55809
55951
|
powerOn: boolean().nullable(),
|
|
55810
55952
|
/** The raw power state (`On`, `Off`, `Standby`, …); null when not known. */
|
|
55811
55953
|
powerState: string().nullable(),
|
|
55812
|
-
saltLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
55813
|
-
rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
55814
55954
|
/**
|
|
55815
55955
|
* True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
|
|
55816
55956
|
* combined care-and-filter reminder raised); false when every such reminder reads clear; null
|
|
@@ -64774,60 +64914,17 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
|
|
|
64774
64914
|
auth: "admin",
|
|
64775
64915
|
access: "delete"
|
|
64776
64916
|
});
|
|
64777
|
-
/**
|
|
64778
|
-
* Robot-vacuum cap. Models HA `vacuum.*` entities — anything with a
|
|
64779
|
-
* cleaning lifecycle plus a return-to-base / locate surface and an
|
|
64780
|
-
* optional fan-speed selector.
|
|
64781
|
-
*
|
|
64782
|
-
* State follows HA's canonical vacuum lifecycle: `idle` / `cleaning` /
|
|
64783
|
-
* `paused` / `returning` / `docked` / `error`. `batteryLevel`
|
|
64784
|
-
* (0..100) is nullable — some vacuums don't report a battery
|
|
64785
|
-
* percentage. `fanSpeed` is the current speed token (provider-verbatim,
|
|
64786
|
-
* e.g. `'standard'` / `'turbo'`) and `availableFanSpeeds` lists the
|
|
64787
|
-
* tokens the hardware accepts so the UI renders only supported choices.
|
|
64788
|
-
*
|
|
64789
|
-
* The `setFanSpeed` method takes the bare `speed` token — the provider
|
|
64790
|
-
* validates it against the vacuum's own list. `locate` triggers the
|
|
64791
|
-
* find-me chirp; `returnToBase` sends it home.
|
|
64792
|
-
*
|
|
64793
|
-
* Consumable / waste tanks: `cleanWater` / `dirtyWater` / `detergent` /
|
|
64794
|
-
* `dustBin` each carry a nullable `{ level (0..100 %), status ('ok' |
|
|
64795
|
-
* 'low' | 'full') }` reading. Native providers (e.g. Dreame, Roborock)
|
|
64796
|
-
* SHOULD populate whichever tanks the hardware has — leave a field `null`
|
|
64797
|
-
* only when the device has no such tank at all, and use a `TankStatus`
|
|
64798
|
-
* with both inner fields `null` when the tank exists but its level is
|
|
64799
|
-
* currently unknown. HA `vacuum.*` entities expose no per-tank telemetry,
|
|
64800
|
-
* so the HA provider leaves all four `null`.
|
|
64801
|
-
*/
|
|
64802
|
-
var VacuumStateSchema = _enum([
|
|
64803
|
-
"idle",
|
|
64804
|
-
"cleaning",
|
|
64805
|
-
"paused",
|
|
64806
|
-
"returning",
|
|
64807
|
-
"docked",
|
|
64808
|
-
"drying",
|
|
64809
|
-
"error"
|
|
64810
|
-
]);
|
|
64811
|
-
/**
|
|
64812
|
-
* One consumable / waste tank on a robot vacuum (clean-water, dirty-water,
|
|
64813
|
-
* detergent or dust-bin). A tank can report a numeric fill `level` (0..100),
|
|
64814
|
-
* a discrete `status` (binary-style hardware), or both. Both `null` means the
|
|
64815
|
-
* level is currently unknown; the OWNING field being `null` means the
|
|
64816
|
-
* hardware has no such tank at all.
|
|
64817
|
-
*/
|
|
64818
|
-
var TankStatusSchema = object({
|
|
64819
|
-
/** Numeric fill 0..100 when the hardware reports a percentage; null otherwise. */
|
|
64820
|
-
level: number().min(0).max(100).nullable(),
|
|
64821
|
-
/** Discrete state when the hardware is binary-mode; null otherwise. */
|
|
64822
|
-
status: _enum([
|
|
64823
|
-
"ok",
|
|
64824
|
-
"low",
|
|
64825
|
-
"full"
|
|
64826
|
-
]).nullable()
|
|
64827
|
-
});
|
|
64828
64917
|
var VacuumControlStatusSchema = object({
|
|
64829
64918
|
/** Lifecycle state of the vacuum. */
|
|
64830
|
-
state:
|
|
64919
|
+
state: _enum([
|
|
64920
|
+
"idle",
|
|
64921
|
+
"cleaning",
|
|
64922
|
+
"paused",
|
|
64923
|
+
"returning",
|
|
64924
|
+
"docked",
|
|
64925
|
+
"drying",
|
|
64926
|
+
"error"
|
|
64927
|
+
]),
|
|
64831
64928
|
/** 0..100 battery percentage. Null when the device has no battery
|
|
64832
64929
|
* reading. */
|
|
64833
64930
|
batteryLevel: number().min(0).max(100).nullable(),
|
|
@@ -64836,14 +64933,6 @@ var VacuumControlStatusSchema = object({
|
|
|
64836
64933
|
fanSpeed: string().nullable(),
|
|
64837
64934
|
/** Speed tokens the hardware accepts — drives the UI selector. */
|
|
64838
64935
|
availableFanSpeeds: array(string()),
|
|
64839
|
-
/** Clean-water (mop) tank. Null when the hardware has no clean-water tank. */
|
|
64840
|
-
cleanWater: TankStatusSchema.nullable(),
|
|
64841
|
-
/** Dirty-water (recovery) tank. Null when the hardware has no dirty-water tank. */
|
|
64842
|
-
dirtyWater: TankStatusSchema.nullable(),
|
|
64843
|
-
/** Detergent tank. Null when the hardware has no detergent tank. */
|
|
64844
|
-
detergent: TankStatusSchema.nullable(),
|
|
64845
|
-
/** Dust bin. Null when the hardware has no dust bin. */
|
|
64846
|
-
dustBin: TankStatusSchema.nullable(),
|
|
64847
64936
|
/** 0..100 cleaning-completion percentage of the current task, or null. */
|
|
64848
64937
|
progressPercent: number().min(0).max(100).nullable(),
|
|
64849
64938
|
/** Current error code (0 / null = no error). */
|
|
@@ -64905,35 +64994,14 @@ var vacuumControlCapability = {
|
|
|
64905
64994
|
*/
|
|
64906
64995
|
durability: "session",
|
|
64907
64996
|
/**
|
|
64908
|
-
* History (D850): recorded series.
|
|
64997
|
+
* History (D850): recorded series. The tanks moved to `consumables` (D915), whose
|
|
64998
|
+
* items are keyed by runtime ids and record no history.
|
|
64909
64999
|
*/
|
|
64910
|
-
history: { fields: {
|
|
64911
|
-
|
|
64912
|
-
|
|
64913
|
-
|
|
64914
|
-
|
|
64915
|
-
},
|
|
64916
|
-
"cleanWater.level": {
|
|
64917
|
-
kind: "gauge",
|
|
64918
|
-
unit: "%",
|
|
64919
|
-
deadband: 2
|
|
64920
|
-
},
|
|
64921
|
-
"dirtyWater.level": {
|
|
64922
|
-
kind: "gauge",
|
|
64923
|
-
unit: "%",
|
|
64924
|
-
deadband: 2
|
|
64925
|
-
},
|
|
64926
|
-
"detergent.level": {
|
|
64927
|
-
kind: "gauge",
|
|
64928
|
-
unit: "%",
|
|
64929
|
-
deadband: 2
|
|
64930
|
-
},
|
|
64931
|
-
"dustBin.level": {
|
|
64932
|
-
kind: "gauge",
|
|
64933
|
-
unit: "%",
|
|
64934
|
-
deadband: 2
|
|
64935
|
-
}
|
|
64936
|
-
} }
|
|
65000
|
+
history: { fields: { batteryLevel: {
|
|
65001
|
+
kind: "gauge",
|
|
65002
|
+
unit: "%",
|
|
65003
|
+
deadband: 2
|
|
65004
|
+
} } }
|
|
64937
65005
|
};
|
|
64938
65006
|
var ValveStatusSchema = object({
|
|
64939
65007
|
/** Lifecycle state of the valve. */
|
|
@@ -69343,6 +69411,12 @@ Object.freeze({
|
|
|
69343
69411
|
addonId: null,
|
|
69344
69412
|
access: "create"
|
|
69345
69413
|
},
|
|
69414
|
+
"deviceHistory.deleteOrphanSeries": {
|
|
69415
|
+
capName: "device-history",
|
|
69416
|
+
capScope: "system",
|
|
69417
|
+
addonId: null,
|
|
69418
|
+
access: "delete"
|
|
69419
|
+
},
|
|
69346
69420
|
"deviceHistory.getDeviceEnabled": {
|
|
69347
69421
|
capName: "device-history",
|
|
69348
69422
|
capScope: "system",
|
|
@@ -69361,6 +69435,12 @@ Object.freeze({
|
|
|
69361
69435
|
addonId: null,
|
|
69362
69436
|
access: "view"
|
|
69363
69437
|
},
|
|
69438
|
+
"deviceHistory.listOrphanSeries": {
|
|
69439
|
+
capName: "device-history",
|
|
69440
|
+
capScope: "system",
|
|
69441
|
+
addonId: null,
|
|
69442
|
+
access: "view"
|
|
69443
|
+
},
|
|
69364
69444
|
"deviceHistory.listSeries": {
|
|
69365
69445
|
capName: "device-history",
|
|
69366
69446
|
capScope: "system",
|
|
@@ -79366,7 +79446,7 @@ var STATE_SUMMARY_VARS = [
|
|
|
79366
79446
|
([...RULE_TEXT], [...COMBINED_ALARM]),
|
|
79367
79447
|
([...RULE_TEXT], [...DEVICE_EVENTS]),
|
|
79368
79448
|
([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
|
|
79369
|
-
([...RULE_TEXT], [...CONSUMABLE]),
|
|
79449
|
+
([...RULE_TEXT], [...CONSUMABLE, ...TANK]),
|
|
79370
79450
|
([...RULE_TEXT], [...TANK]),
|
|
79371
79451
|
[...RULE_TEXT],
|
|
79372
79452
|
([...RULE_TEXT], [...UPDATES, ...ALERT_EPISODE]),
|
|
@@ -135236,8 +135316,7 @@ function dirtyWaterTankStatus(value, errorCode) {
|
|
|
135236
135316
|
return null;
|
|
135237
135317
|
}
|
|
135238
135318
|
/**
|
|
135239
|
-
* The four
|
|
135240
|
-
* dust-bin) decoded from the model's {@link VacuumCapabilities}, with the
|
|
135319
|
+
* The four tanks (clean-water / dirty-water / detergent / dust-bin) decoded from the model's {@link VacuumCapabilities}, with the
|
|
135241
135320
|
* discrete `status` populated from the live MIoT enum props when supplied. Pure.
|
|
135242
135321
|
*
|
|
135243
135322
|
* The nodedreame library exposes NO tank FILL-LEVEL telemetry — the cloud shadow
|
|
@@ -135268,6 +135347,57 @@ function decodeVacuumTanks(caps, props, errorCode = null) {
|
|
|
135268
135347
|
dustBin: tank(Boolean(caps?.canAutoEmpty), props ? dustBinTankStatus(props.dustCollection, props.dustBagStatus) : null)
|
|
135269
135348
|
};
|
|
135270
135349
|
}
|
|
135350
|
+
/** How each tank is named and what it is, in the order the panel lists them. */
|
|
135351
|
+
var TANK_ITEMS = [
|
|
135352
|
+
{
|
|
135353
|
+
key: "cleanWater",
|
|
135354
|
+
label: "Clean water tank",
|
|
135355
|
+
kind: "supply",
|
|
135356
|
+
form: "tank"
|
|
135357
|
+
},
|
|
135358
|
+
{
|
|
135359
|
+
key: "dirtyWater",
|
|
135360
|
+
label: "Dirty water tank",
|
|
135361
|
+
kind: "waste",
|
|
135362
|
+
form: "tank"
|
|
135363
|
+
},
|
|
135364
|
+
{
|
|
135365
|
+
key: "detergent",
|
|
135366
|
+
label: "Detergent",
|
|
135367
|
+
kind: "supply",
|
|
135368
|
+
form: "product"
|
|
135369
|
+
},
|
|
135370
|
+
{
|
|
135371
|
+
key: "dustBin",
|
|
135372
|
+
label: "Dust bin",
|
|
135373
|
+
kind: "waste",
|
|
135374
|
+
form: "bin"
|
|
135375
|
+
}
|
|
135376
|
+
];
|
|
135377
|
+
/**
|
|
135378
|
+
* The tanks as `consumables` items (D915): every PRESENT tank becomes a
|
|
135379
|
+
* `supply` (clean water, detergent) or `waste` (dirty water, dust bin) item
|
|
135380
|
+
* keyed by its old field name, drawn as a `tank` (the two water tanks), a
|
|
135381
|
+
* `product` (detergent) or a `bin` (the dust bin) — the key the notification centre's tank
|
|
135382
|
+
* episodes were built on, so an open episode carries on. A tank is never
|
|
135383
|
+
* resettable: emptying or refilling it is the reset. Pure.
|
|
135384
|
+
*/
|
|
135385
|
+
function vacuumTankItems(tanks) {
|
|
135386
|
+
return TANK_ITEMS.flatMap(({ key, label, kind, form }) => {
|
|
135387
|
+
const tank = tanks[key];
|
|
135388
|
+
if (tank === null) return [];
|
|
135389
|
+
return [{
|
|
135390
|
+
key,
|
|
135391
|
+
label,
|
|
135392
|
+
level: tank.level,
|
|
135393
|
+
status: tank.status,
|
|
135394
|
+
kind,
|
|
135395
|
+
form,
|
|
135396
|
+
lastResetAt: null,
|
|
135397
|
+
resettable: false
|
|
135398
|
+
}];
|
|
135399
|
+
});
|
|
135400
|
+
}
|
|
135271
135401
|
/**
|
|
135272
135402
|
* Clamp a raw consumable percentage to `[0, 100]`, or return `null` when the
|
|
135273
135403
|
* value is absent / non-finite. The library reports remaining life as a 0..100
|
|
@@ -135296,7 +135426,8 @@ function buildVacuumConsumableItems(readings) {
|
|
|
135296
135426
|
level: clampConsumablePct(c.leftPct),
|
|
135297
135427
|
status: null,
|
|
135298
135428
|
lastResetAt: null,
|
|
135299
|
-
resettable: c.resettable
|
|
135429
|
+
resettable: c.resettable,
|
|
135430
|
+
form: "part"
|
|
135300
135431
|
}));
|
|
135301
135432
|
}
|
|
135302
135433
|
/** Structural equality of two JSON-shaped values, key order ignored. */
|
|
@@ -182681,7 +182812,8 @@ function buildMowerConsumables(readings) {
|
|
|
182681
182812
|
level: r.remainingPercent,
|
|
182682
182813
|
status: null,
|
|
182683
182814
|
lastResetAt: null,
|
|
182684
|
-
resettable: true
|
|
182815
|
+
resettable: true,
|
|
182816
|
+
form: "part"
|
|
182685
182817
|
}));
|
|
182686
182818
|
}
|
|
182687
182819
|
//#endregion
|
|
@@ -182705,7 +182837,7 @@ var CONSUMABLES_COLD_START = {
|
|
|
182705
182837
|
lastFetchedAt: 0
|
|
182706
182838
|
};
|
|
182707
182839
|
function itemEqual(a, b) {
|
|
182708
|
-
return a.key === b.key && a.label === b.label && a.level === b.level && a.status === b.status && a.lastResetAt === b.lastResetAt && a.resettable === b.resettable;
|
|
182840
|
+
return a.key === b.key && a.label === b.label && a.level === b.level && a.status === b.status && a.lastResetAt === b.lastResetAt && a.resettable === b.resettable && a.kind === b.kind && a.remaining?.value === b.remaining?.value && a.remaining?.unit === b.remaining?.unit;
|
|
182709
182841
|
}
|
|
182710
182842
|
function itemsEqual(a, b) {
|
|
182711
182843
|
return a.length === b.length && a.every((item, i) => {
|
|
@@ -183695,6 +183827,31 @@ var DreameSwitchDevice = class extends DreameChildDevice {
|
|
|
183695
183827
|
};
|
|
183696
183828
|
//#endregion
|
|
183697
183829
|
//#region src/devices/dreame-vacuum-consumables.ts
|
|
183830
|
+
/**
|
|
183831
|
+
* The vacuum's `consumables` slice: when it is re-read, and what a reset does.
|
|
183832
|
+
*
|
|
183833
|
+
* The life %s and their time-left twins are settings the robot rarely re-pushes
|
|
183834
|
+
* over MQTT, and the library does not poll them. So they are re-read from the
|
|
183835
|
+
* cloud SHADOW (no robot wake) on activate, every {@link CONSUMABLES_REFRESH_MS},
|
|
183836
|
+
* and on the edge INTO `docked` — the moment a run has just used them up. The
|
|
183837
|
+
* same read reseeds the station tank-status props (dirty water, dust bag, …),
|
|
183838
|
+
* which otherwise arrive only as pushes.
|
|
183839
|
+
*
|
|
183840
|
+
* A reset goes through the library, which re-reads the item it reset (live,
|
|
183841
|
+
* else shadow) before it resolves; the slice is rebuilt from that. A shadow
|
|
183842
|
+
* answer may still be the pre-reset value, so it earns ONE follow-up refresh.
|
|
183843
|
+
*
|
|
183844
|
+
* The TANKS ride the same slice (D915): every push hands over the tank items
|
|
183845
|
+
* the device decoded, appended after the wear items. Either half may be
|
|
183846
|
+
* unknown for a while after a restart — the shadow has not answered, or a
|
|
183847
|
+
* refresh lands before the first push brought the tanks — and the slice is
|
|
183848
|
+
* `restored`, so an unknown half keeps the restored rows instead of erasing
|
|
183849
|
+
* them.
|
|
183850
|
+
*/
|
|
183851
|
+
/** A tank item (`supply` / `waste`) as opposed to a wear item. */
|
|
183852
|
+
function isTankItem(item) {
|
|
183853
|
+
return consumableKindOf(item) !== "wear";
|
|
183854
|
+
}
|
|
183698
183855
|
/** Hourly: a consumable moves by hours of cleaning, and the dock edge covers a run. */
|
|
183699
183856
|
var CONSUMABLES_REFRESH_MS = 60 * 6e4;
|
|
183700
183857
|
/** Time for the robot to report a reset to the cloud before the shadow is re-read. */
|
|
@@ -183711,6 +183868,8 @@ var DreameVacuumConsumables = class {
|
|
|
183711
183868
|
#refresher;
|
|
183712
183869
|
/** Last pushed lifecycle state; `null` until the first push after boot. */
|
|
183713
183870
|
#prevState = null;
|
|
183871
|
+
/** Last pushed tank items; `null` until the first push after boot. */
|
|
183872
|
+
#tanks = null;
|
|
183714
183873
|
constructor(deps) {
|
|
183715
183874
|
this.#deps = deps;
|
|
183716
183875
|
this.#refresher = new DreameConsumablesRefresher({
|
|
@@ -183730,12 +183889,14 @@ var DreameVacuumConsumables = class {
|
|
|
183730
183889
|
this.#refresher.stop();
|
|
183731
183890
|
}
|
|
183732
183891
|
/**
|
|
183733
|
-
* Every `stateChanged` push: replay the cache
|
|
183734
|
-
* an item changed) and refresh on the edge into
|
|
183735
|
-
* boot is not an edge — activation already
|
|
183736
|
-
* between station routines (`drying` →
|
|
183892
|
+
* Every `stateChanged` push: replay the cache and the pushed tanks into the
|
|
183893
|
+
* slice (written only if an item changed) and refresh on the edge into
|
|
183894
|
+
* `docked`. The first push after boot is not an edge — activation already
|
|
183895
|
+
* reads — and neither is a hop between station routines (`drying` →
|
|
183896
|
+
* `docked`): only the end of a RUN is.
|
|
183737
183897
|
*/
|
|
183738
|
-
onPush(state) {
|
|
183898
|
+
onPush(state, tanks) {
|
|
183899
|
+
this.#tanks = tanks;
|
|
183739
183900
|
this.#apply(false);
|
|
183740
183901
|
const enteredDock = this.#prevState !== null && DOCK_EDGE_FROM.has(this.#prevState) && state === "docked";
|
|
183741
183902
|
this.#prevState = state;
|
|
@@ -183785,7 +183946,11 @@ var DreameVacuumConsumables = class {
|
|
|
183785
183946
|
const { store, resolveVacuum, now } = this.#deps;
|
|
183786
183947
|
const vacuum = resolveVacuum();
|
|
183787
183948
|
if (vacuum === null) return;
|
|
183788
|
-
|
|
183949
|
+
const prev = store.getCapState("consumables")?.items ?? [];
|
|
183950
|
+
const read = buildVacuumConsumableItems(vacuum.supportedConsumables);
|
|
183951
|
+
const wear = read.length > 0 ? read : prev.filter((item) => !isTankItem(item));
|
|
183952
|
+
const tanks = this.#tanks ?? prev.filter(isTankItem);
|
|
183953
|
+
writeConsumables(store, [...wear, ...tanks], (now ?? Date.now)(), landed);
|
|
183789
183954
|
}
|
|
183790
183955
|
};
|
|
183791
183956
|
function resetMeta(result) {
|
|
@@ -183805,10 +183970,6 @@ var CONTROL_COLD_START = {
|
|
|
183805
183970
|
batteryLevel: null,
|
|
183806
183971
|
fanSpeed: null,
|
|
183807
183972
|
availableFanSpeeds: [],
|
|
183808
|
-
cleanWater: null,
|
|
183809
|
-
dirtyWater: null,
|
|
183810
|
-
detergent: null,
|
|
183811
|
-
dustBin: null,
|
|
183812
183973
|
progressPercent: null,
|
|
183813
183974
|
errorCode: null,
|
|
183814
183975
|
errorLabel: null,
|
|
@@ -183824,11 +183985,13 @@ var CONTROL_COLD_START = {
|
|
|
183824
183985
|
* `setFanSpeed`→`setSuction()` (token validated against the model's supported
|
|
183825
183986
|
* suction levels).
|
|
183826
183987
|
*
|
|
183827
|
-
*
|
|
183828
|
-
*
|
|
183829
|
-
*
|
|
183830
|
-
*
|
|
183831
|
-
*
|
|
183988
|
+
* Tanks (clean water / dirty water / detergent / dust bin) are `supply` /
|
|
183989
|
+
* `waste` items of the `consumables` slice (D915), not `vacuum-control` fields:
|
|
183990
|
+
* the library exposes NO tank fill LEVEL, so `level` is always null. PRESENCE
|
|
183991
|
+
* comes from the model capability flags and a discrete `status` from the
|
|
183992
|
+
* station's tank-status enum props (`decodeVacuumTanks`, ids in
|
|
183993
|
+
* `VACUUM_TANK_PROPS`); an absent tank is no item, an unknown status is `null`
|
|
183994
|
+
* — never `ok`.
|
|
183832
183995
|
*
|
|
183833
183996
|
* Consumables: whatever the model REPORTS (the library's presence-driven
|
|
183834
183997
|
* `supportedConsumables`), re-read from the cloud shadow on activate, hourly and
|
|
@@ -183952,16 +184115,12 @@ var DreameVacuumDevice = class extends DreameChildDevice {
|
|
|
183952
184115
|
recomputeSlice() {
|
|
183953
184116
|
const vacuum = this.resolveVacuum();
|
|
183954
184117
|
if (vacuum === null) return;
|
|
183955
|
-
const tanks = decodeVacuumTanks(vacuum.vacuumCapabilities, this.readTankProps(), vacuum.errorCode);
|
|
184118
|
+
const tanks = vacuumTankItems(decodeVacuumTanks(vacuum.vacuumCapabilities, this.readTankProps(), vacuum.errorCode));
|
|
183956
184119
|
const controlSlice = {
|
|
183957
184120
|
state: mapMiotStateToVacuumState(vacuum.status),
|
|
183958
184121
|
batteryLevel: clampBatteryLevel$1(vacuum.battery),
|
|
183959
184122
|
fanSpeed: suctionLevelToken(vacuum.suction),
|
|
183960
184123
|
availableFanSpeeds: supportedFanSpeedTokens(vacuum.supportedSuctionLevels),
|
|
183961
|
-
cleanWater: tanks.cleanWater,
|
|
183962
|
-
dirtyWater: tanks.dirtyWater,
|
|
183963
|
-
detergent: tanks.detergent,
|
|
183964
|
-
dustBin: tanks.dustBin,
|
|
183965
184124
|
progressPercent: clampPercent$1(vacuum.taskProgressPct),
|
|
183966
184125
|
errorCode: vacuum.errorCode,
|
|
183967
184126
|
errorLabel: vacuum.errorCode ? `Error ${vacuum.errorCode}` : null,
|
|
@@ -183969,7 +184128,7 @@ var DreameVacuumDevice = class extends DreameChildDevice {
|
|
|
183969
184128
|
};
|
|
183970
184129
|
const toWrite = nextVacuumControlSlice(this.runtimeState.getCapState(CAP_NAME$1), controlSlice);
|
|
183971
184130
|
if (toWrite !== null) this.runtimeState.setCapState(CAP_NAME$1, toWrite);
|
|
183972
|
-
this.consumables.onPush(controlSlice.state);
|
|
184131
|
+
this.consumables.onPush(controlSlice.state, tanks);
|
|
183973
184132
|
}
|
|
183974
184133
|
/**
|
|
183975
184134
|
* Read the tank-status MIoT enum props ({@link VACUUM_TANK_PROPS}) from the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-dreame",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.151",
|
|
4
4
|
"description": "Dreame robot-vacuum / lawn-mower device-provider addon for CamStack — wraps the @apocaliss92/nodedreame Dreamehome cloud client",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|