@apocaliss92/nodedreame 1.6.0 → 1.7.0

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/index.d.cts CHANGED
@@ -755,6 +755,48 @@ declare function decodeAiFeature(raw: AiDetectionRaw, feature: DreameAiFeature):
755
755
  */
756
756
  declare function encodeAiFeatureWrite(raw: AiDetectionRaw, feature: DreameAiFeature, value: boolean): number | string;
757
757
 
758
+ /**
759
+ * Vacuum consumable/maintenance map (ported from Tasshack `dreame-vacuum`
760
+ * v2.0.0b25 — property + action mappings). Each consumable lives on its own MIoT
761
+ * service `siid`: a remaining-life `%` property (`siid/piid`) and a "reset to
762
+ * 100%" action (`siid/aiid 1`). A model exposes only a SUBSET — which is
763
+ * discovered by PRESENCE (the device reports the life property) rather than a
764
+ * hardcoded per-model list, mirroring how the HA integration derives support.
765
+ */
766
+ /** Stable consumable keys (kebab-case so a consumer can use them verbatim). */
767
+ type DreameConsumableKey = 'main-brush' | 'side-brush' | 'filter' | 'sensor' | 'tank-filter' | 'mop-pad' | 'silver-ion' | 'detergent' | 'squeegee' | 'dust-bag';
768
+ /** One consumable's wire coordinates: remaining-life property + optional reset action. */
769
+ interface ConsumableSpec {
770
+ readonly key: DreameConsumableKey;
771
+ readonly label: string;
772
+ /** Remaining-life % property (0..100). */
773
+ readonly life: {
774
+ readonly siid: number;
775
+ readonly piid: number;
776
+ };
777
+ /** "Mark replaced / reset life" action, or null when the model exposes none. */
778
+ readonly reset: {
779
+ readonly siid: number;
780
+ readonly aiid: number;
781
+ } | null;
782
+ }
783
+ /**
784
+ * Every consumable nodedreame knows. The reset action shares the consumable's
785
+ * service `siid` with `aiid 1` (Tasshack action map). `dust-bag` has a life
786
+ * property but no reset action.
787
+ */
788
+ declare const VACUUM_CONSUMABLES: readonly ConsumableSpec[];
789
+ /** Lookup a consumable spec by key (undefined for an unknown key). */
790
+ declare function consumableSpec(key: DreameConsumableKey): ConsumableSpec | undefined;
791
+ /** A resolved consumable reading: which consumable, its remaining life %, and
792
+ * whether a reset action exists. Only the consumables the model REPORTS appear. */
793
+ interface ConsumableReading {
794
+ readonly key: DreameConsumableKey;
795
+ readonly label: string;
796
+ readonly leftPct: number;
797
+ readonly resettable: boolean;
798
+ }
799
+
758
800
  /**
759
801
  * Per-model vacuum capability records (ported from malard/node-dreame
760
802
  * src/capabilities.ts, MIT — attribution retained) plus a resolver that
@@ -1266,6 +1308,33 @@ declare class VacuumDevice extends BaseDevice<VacuumDeviceEvents> {
1266
1308
  get sideBrushLeftPct(): number | null;
1267
1309
  get filterLeftPct(): number | null;
1268
1310
  get volume(): number | null;
1311
+ /**
1312
+ * Remaining-life % (0..100) for one consumable, or `null` when the model does
1313
+ * not report it (presence == support). Call {@link refreshConsumables} first
1314
+ * on a docked robot so the cloud-shadow life values are seeded.
1315
+ */
1316
+ consumableLeftPct(key: DreameConsumableKey): number | null;
1317
+ /**
1318
+ * The consumables this model EXPOSES — discovered by presence (a reported
1319
+ * life property), mirroring how the HA integration derives support. Each
1320
+ * reading carries the current remaining-life % and whether a reset action
1321
+ * exists. Empty until the life properties have been observed (push) or seeded
1322
+ * via {@link refreshConsumables}.
1323
+ */
1324
+ get supportedConsumables(): readonly ConsumableReading[];
1325
+ /**
1326
+ * Seed EVERY consumable life property from the cloud shadow (no robot wake) so
1327
+ * {@link supportedConsumables} reflects the full set on a docked robot. The
1328
+ * consumable life values are static settings the robot rarely re-pushes over
1329
+ * MQTT, so a fresh connect surfaces only the actively-changing ones without this.
1330
+ */
1331
+ refreshConsumables(): Promise<void>;
1332
+ /**
1333
+ * Reset (mark replaced → life back to 100%) one consumable via its MIoT reset
1334
+ * action. Rejects when the model exposes no reset action for the key (e.g.
1335
+ * `dust-bag`) or the key is unknown.
1336
+ */
1337
+ resetConsumable(key: DreameConsumableKey): Promise<unknown>;
1269
1338
  /**
1270
1339
  * The raw `AI_DETECTION` value (siid 4 piid 22) — an int bitmask or a JSON
1271
1340
  * string, depending on firmware — or `null` when not yet observed. Prefer the
@@ -1280,6 +1349,16 @@ declare class VacuumDevice extends BaseDevice<VacuumDeviceEvents> {
1280
1349
  * when the value is unobserved or the feature is not representable.
1281
1350
  */
1282
1351
  aiFeature(feature: DreameAiFeature): boolean | null;
1352
+ /**
1353
+ * Seed {@link aiDetectionRaw} from the CLOUD SHADOW (the last value the robot
1354
+ * pushed for `AI_DETECTION`, siid 4 piid 22) WITHOUT waking it. The AI-obstacle
1355
+ * toggles are STATIC settings the robot rarely re-pushes over MQTT, so a fresh
1356
+ * connect to an idle robot has no value cached — call this on activate to
1357
+ * surface the current toggles. Emits the usual `propertyChanged`/`stateChanged`
1358
+ * (so a watching consumer re-decodes) and returns the resolved raw value
1359
+ * (`null` when the model has no AI detection or the shadow carries none yet).
1360
+ */
1361
+ refreshAiDetection(): Promise<AiDetectionRaw>;
1283
1362
  /**
1284
1363
  * Toggle ONE AI-obstacle feature, preserving the others via a read-modify-write
1285
1364
  * of the packed `AI_DETECTION` property (mirrors Tasshack `set_ai_detection`).
@@ -2235,4 +2314,4 @@ declare function createDumper(target: DumperDevice, options?: DumperOptions): Du
2235
2314
  */
2236
2315
  declare function createClientDumper(client: Nodreame, options?: DumperOptions): Dumper[];
2237
2316
 
2238
- export { AI_FEATURE_BIT, AI_FEATURE_JSON_KEY, type AiDetectionRaw, BaseDevice, type BaseDeviceEvents, type BatchDeviceDataFetcher, type CapabilityResolver, ChargingStatus, type CleanOpts, CleaningMode, type CreateDeviceArgs, DefaultCapabilityResolver, type DeviceCapabilities, type DeviceDump, type DeviceEvent, type DreameAiFeature, DreameApiError, DreameAuthError, type DreameCloudState, type DreameDevice, DreameDeviceOfflineError, DreameError, type DreameRegion, type DreameSession, DreameTransportError, type DumperOptions, LIBRARY_NAME, MODEL_CAPABILITIES as MOWER_MODEL_CAPABILITIES, type MapBoundingBox, type MapCleanedAreaOverlay, type MapDimensions, type MapFrameType, type MapLayer, type MapLayerType, type MapLowLyingArea, type MapObstacle, type MapPath, type MapPathType, type MapPoint, type MapPose, type MapRestrictedArea, type MapRoom, type MapRoomWall, type MapRun, type MapSegment, type MapStorey, type MapVirtualWall, type MapWallsInfo, type MiotAction, MiotError, type MiotProp, MiotState, type MowerAvailableMap, type MowerCapabilities, MowerCapabilityResolver, MowerChargingStatus, type MowerContour, MowerControlAction, type MowerControlState, MowerDevice, type MowerDeviceInput, MowerFault, type MowerMap, type MowerMapBoundary, type MowerMowPath, type MowerPathEntry, type MowerPoint, type MowerSpotArea, MowerStatus, type MowerTaskDescriptor, MowerTaskStatus, type MowerZone, Nodreame, type NodreameDeps, type NodreameEvents, type NodreameOptions, type OssFetchInput, type OssFetcherLike, type PropertyChangedEvent, type PropertyResult, type PropertyState, type PropertyWrite, type RenderMowerSvgOptions, type RenderVacuumPngOptions, type StateChangedEvent, SuctionLevel, TaskStatus, MODEL_CAPABILITIES$1 as VACUUM_MODEL_CAPABILITIES, type VacuumCapabilities, VacuumCapabilityResolver, VacuumDevice, type VacuumGetMapInput, type VacuumMap, WaterVolume, createClientDumper, createDumper, decodeAiFeature, encodeAiFeatureWrite, getMowerCapabilities, getVacuumCapabilities, renderMowerSvg, renderVacuumPng, resolveCapabilities };
2317
+ export { AI_FEATURE_BIT, AI_FEATURE_JSON_KEY, type AiDetectionRaw, BaseDevice, type BaseDeviceEvents, type BatchDeviceDataFetcher, type CapabilityResolver, ChargingStatus, type CleanOpts, CleaningMode, type ConsumableReading, type ConsumableSpec, type CreateDeviceArgs, DefaultCapabilityResolver, type DeviceCapabilities, type DeviceDump, type DeviceEvent, type DreameAiFeature, DreameApiError, DreameAuthError, type DreameCloudState, type DreameConsumableKey, type DreameDevice, DreameDeviceOfflineError, DreameError, type DreameRegion, type DreameSession, DreameTransportError, type DumperOptions, LIBRARY_NAME, MODEL_CAPABILITIES as MOWER_MODEL_CAPABILITIES, type MapBoundingBox, type MapCleanedAreaOverlay, type MapDimensions, type MapFrameType, type MapLayer, type MapLayerType, type MapLowLyingArea, type MapObstacle, type MapPath, type MapPathType, type MapPoint, type MapPose, type MapRestrictedArea, type MapRoom, type MapRoomWall, type MapRun, type MapSegment, type MapStorey, type MapVirtualWall, type MapWallsInfo, type MiotAction, MiotError, type MiotProp, MiotState, type MowerAvailableMap, type MowerCapabilities, MowerCapabilityResolver, MowerChargingStatus, type MowerContour, MowerControlAction, type MowerControlState, MowerDevice, type MowerDeviceInput, MowerFault, type MowerMap, type MowerMapBoundary, type MowerMowPath, type MowerPathEntry, type MowerPoint, type MowerSpotArea, MowerStatus, type MowerTaskDescriptor, MowerTaskStatus, type MowerZone, Nodreame, type NodreameDeps, type NodreameEvents, type NodreameOptions, type OssFetchInput, type OssFetcherLike, type PropertyChangedEvent, type PropertyResult, type PropertyState, type PropertyWrite, type RenderMowerSvgOptions, type RenderVacuumPngOptions, type StateChangedEvent, SuctionLevel, TaskStatus, VACUUM_CONSUMABLES, MODEL_CAPABILITIES$1 as VACUUM_MODEL_CAPABILITIES, type VacuumCapabilities, VacuumCapabilityResolver, VacuumDevice, type VacuumGetMapInput, type VacuumMap, WaterVolume, consumableSpec, createClientDumper, createDumper, decodeAiFeature, encodeAiFeatureWrite, getMowerCapabilities, getVacuumCapabilities, renderMowerSvg, renderVacuumPng, resolveCapabilities };
package/dist/index.d.ts CHANGED
@@ -755,6 +755,48 @@ declare function decodeAiFeature(raw: AiDetectionRaw, feature: DreameAiFeature):
755
755
  */
756
756
  declare function encodeAiFeatureWrite(raw: AiDetectionRaw, feature: DreameAiFeature, value: boolean): number | string;
757
757
 
758
+ /**
759
+ * Vacuum consumable/maintenance map (ported from Tasshack `dreame-vacuum`
760
+ * v2.0.0b25 — property + action mappings). Each consumable lives on its own MIoT
761
+ * service `siid`: a remaining-life `%` property (`siid/piid`) and a "reset to
762
+ * 100%" action (`siid/aiid 1`). A model exposes only a SUBSET — which is
763
+ * discovered by PRESENCE (the device reports the life property) rather than a
764
+ * hardcoded per-model list, mirroring how the HA integration derives support.
765
+ */
766
+ /** Stable consumable keys (kebab-case so a consumer can use them verbatim). */
767
+ type DreameConsumableKey = 'main-brush' | 'side-brush' | 'filter' | 'sensor' | 'tank-filter' | 'mop-pad' | 'silver-ion' | 'detergent' | 'squeegee' | 'dust-bag';
768
+ /** One consumable's wire coordinates: remaining-life property + optional reset action. */
769
+ interface ConsumableSpec {
770
+ readonly key: DreameConsumableKey;
771
+ readonly label: string;
772
+ /** Remaining-life % property (0..100). */
773
+ readonly life: {
774
+ readonly siid: number;
775
+ readonly piid: number;
776
+ };
777
+ /** "Mark replaced / reset life" action, or null when the model exposes none. */
778
+ readonly reset: {
779
+ readonly siid: number;
780
+ readonly aiid: number;
781
+ } | null;
782
+ }
783
+ /**
784
+ * Every consumable nodedreame knows. The reset action shares the consumable's
785
+ * service `siid` with `aiid 1` (Tasshack action map). `dust-bag` has a life
786
+ * property but no reset action.
787
+ */
788
+ declare const VACUUM_CONSUMABLES: readonly ConsumableSpec[];
789
+ /** Lookup a consumable spec by key (undefined for an unknown key). */
790
+ declare function consumableSpec(key: DreameConsumableKey): ConsumableSpec | undefined;
791
+ /** A resolved consumable reading: which consumable, its remaining life %, and
792
+ * whether a reset action exists. Only the consumables the model REPORTS appear. */
793
+ interface ConsumableReading {
794
+ readonly key: DreameConsumableKey;
795
+ readonly label: string;
796
+ readonly leftPct: number;
797
+ readonly resettable: boolean;
798
+ }
799
+
758
800
  /**
759
801
  * Per-model vacuum capability records (ported from malard/node-dreame
760
802
  * src/capabilities.ts, MIT — attribution retained) plus a resolver that
@@ -1266,6 +1308,33 @@ declare class VacuumDevice extends BaseDevice<VacuumDeviceEvents> {
1266
1308
  get sideBrushLeftPct(): number | null;
1267
1309
  get filterLeftPct(): number | null;
1268
1310
  get volume(): number | null;
1311
+ /**
1312
+ * Remaining-life % (0..100) for one consumable, or `null` when the model does
1313
+ * not report it (presence == support). Call {@link refreshConsumables} first
1314
+ * on a docked robot so the cloud-shadow life values are seeded.
1315
+ */
1316
+ consumableLeftPct(key: DreameConsumableKey): number | null;
1317
+ /**
1318
+ * The consumables this model EXPOSES — discovered by presence (a reported
1319
+ * life property), mirroring how the HA integration derives support. Each
1320
+ * reading carries the current remaining-life % and whether a reset action
1321
+ * exists. Empty until the life properties have been observed (push) or seeded
1322
+ * via {@link refreshConsumables}.
1323
+ */
1324
+ get supportedConsumables(): readonly ConsumableReading[];
1325
+ /**
1326
+ * Seed EVERY consumable life property from the cloud shadow (no robot wake) so
1327
+ * {@link supportedConsumables} reflects the full set on a docked robot. The
1328
+ * consumable life values are static settings the robot rarely re-pushes over
1329
+ * MQTT, so a fresh connect surfaces only the actively-changing ones without this.
1330
+ */
1331
+ refreshConsumables(): Promise<void>;
1332
+ /**
1333
+ * Reset (mark replaced → life back to 100%) one consumable via its MIoT reset
1334
+ * action. Rejects when the model exposes no reset action for the key (e.g.
1335
+ * `dust-bag`) or the key is unknown.
1336
+ */
1337
+ resetConsumable(key: DreameConsumableKey): Promise<unknown>;
1269
1338
  /**
1270
1339
  * The raw `AI_DETECTION` value (siid 4 piid 22) — an int bitmask or a JSON
1271
1340
  * string, depending on firmware — or `null` when not yet observed. Prefer the
@@ -1280,6 +1349,16 @@ declare class VacuumDevice extends BaseDevice<VacuumDeviceEvents> {
1280
1349
  * when the value is unobserved or the feature is not representable.
1281
1350
  */
1282
1351
  aiFeature(feature: DreameAiFeature): boolean | null;
1352
+ /**
1353
+ * Seed {@link aiDetectionRaw} from the CLOUD SHADOW (the last value the robot
1354
+ * pushed for `AI_DETECTION`, siid 4 piid 22) WITHOUT waking it. The AI-obstacle
1355
+ * toggles are STATIC settings the robot rarely re-pushes over MQTT, so a fresh
1356
+ * connect to an idle robot has no value cached — call this on activate to
1357
+ * surface the current toggles. Emits the usual `propertyChanged`/`stateChanged`
1358
+ * (so a watching consumer re-decodes) and returns the resolved raw value
1359
+ * (`null` when the model has no AI detection or the shadow carries none yet).
1360
+ */
1361
+ refreshAiDetection(): Promise<AiDetectionRaw>;
1283
1362
  /**
1284
1363
  * Toggle ONE AI-obstacle feature, preserving the others via a read-modify-write
1285
1364
  * of the packed `AI_DETECTION` property (mirrors Tasshack `set_ai_detection`).
@@ -2235,4 +2314,4 @@ declare function createDumper(target: DumperDevice, options?: DumperOptions): Du
2235
2314
  */
2236
2315
  declare function createClientDumper(client: Nodreame, options?: DumperOptions): Dumper[];
2237
2316
 
2238
- export { AI_FEATURE_BIT, AI_FEATURE_JSON_KEY, type AiDetectionRaw, BaseDevice, type BaseDeviceEvents, type BatchDeviceDataFetcher, type CapabilityResolver, ChargingStatus, type CleanOpts, CleaningMode, type CreateDeviceArgs, DefaultCapabilityResolver, type DeviceCapabilities, type DeviceDump, type DeviceEvent, type DreameAiFeature, DreameApiError, DreameAuthError, type DreameCloudState, type DreameDevice, DreameDeviceOfflineError, DreameError, type DreameRegion, type DreameSession, DreameTransportError, type DumperOptions, LIBRARY_NAME, MODEL_CAPABILITIES as MOWER_MODEL_CAPABILITIES, type MapBoundingBox, type MapCleanedAreaOverlay, type MapDimensions, type MapFrameType, type MapLayer, type MapLayerType, type MapLowLyingArea, type MapObstacle, type MapPath, type MapPathType, type MapPoint, type MapPose, type MapRestrictedArea, type MapRoom, type MapRoomWall, type MapRun, type MapSegment, type MapStorey, type MapVirtualWall, type MapWallsInfo, type MiotAction, MiotError, type MiotProp, MiotState, type MowerAvailableMap, type MowerCapabilities, MowerCapabilityResolver, MowerChargingStatus, type MowerContour, MowerControlAction, type MowerControlState, MowerDevice, type MowerDeviceInput, MowerFault, type MowerMap, type MowerMapBoundary, type MowerMowPath, type MowerPathEntry, type MowerPoint, type MowerSpotArea, MowerStatus, type MowerTaskDescriptor, MowerTaskStatus, type MowerZone, Nodreame, type NodreameDeps, type NodreameEvents, type NodreameOptions, type OssFetchInput, type OssFetcherLike, type PropertyChangedEvent, type PropertyResult, type PropertyState, type PropertyWrite, type RenderMowerSvgOptions, type RenderVacuumPngOptions, type StateChangedEvent, SuctionLevel, TaskStatus, MODEL_CAPABILITIES$1 as VACUUM_MODEL_CAPABILITIES, type VacuumCapabilities, VacuumCapabilityResolver, VacuumDevice, type VacuumGetMapInput, type VacuumMap, WaterVolume, createClientDumper, createDumper, decodeAiFeature, encodeAiFeatureWrite, getMowerCapabilities, getVacuumCapabilities, renderMowerSvg, renderVacuumPng, resolveCapabilities };
2317
+ export { AI_FEATURE_BIT, AI_FEATURE_JSON_KEY, type AiDetectionRaw, BaseDevice, type BaseDeviceEvents, type BatchDeviceDataFetcher, type CapabilityResolver, ChargingStatus, type CleanOpts, CleaningMode, type ConsumableReading, type ConsumableSpec, type CreateDeviceArgs, DefaultCapabilityResolver, type DeviceCapabilities, type DeviceDump, type DeviceEvent, type DreameAiFeature, DreameApiError, DreameAuthError, type DreameCloudState, type DreameConsumableKey, type DreameDevice, DreameDeviceOfflineError, DreameError, type DreameRegion, type DreameSession, DreameTransportError, type DumperOptions, LIBRARY_NAME, MODEL_CAPABILITIES as MOWER_MODEL_CAPABILITIES, type MapBoundingBox, type MapCleanedAreaOverlay, type MapDimensions, type MapFrameType, type MapLayer, type MapLayerType, type MapLowLyingArea, type MapObstacle, type MapPath, type MapPathType, type MapPoint, type MapPose, type MapRestrictedArea, type MapRoom, type MapRoomWall, type MapRun, type MapSegment, type MapStorey, type MapVirtualWall, type MapWallsInfo, type MiotAction, MiotError, type MiotProp, MiotState, type MowerAvailableMap, type MowerCapabilities, MowerCapabilityResolver, MowerChargingStatus, type MowerContour, MowerControlAction, type MowerControlState, MowerDevice, type MowerDeviceInput, MowerFault, type MowerMap, type MowerMapBoundary, type MowerMowPath, type MowerPathEntry, type MowerPoint, type MowerSpotArea, MowerStatus, type MowerTaskDescriptor, MowerTaskStatus, type MowerZone, Nodreame, type NodreameDeps, type NodreameEvents, type NodreameOptions, type OssFetchInput, type OssFetcherLike, type PropertyChangedEvent, type PropertyResult, type PropertyState, type PropertyWrite, type RenderMowerSvgOptions, type RenderVacuumPngOptions, type StateChangedEvent, SuctionLevel, TaskStatus, VACUUM_CONSUMABLES, MODEL_CAPABILITIES$1 as VACUUM_MODEL_CAPABILITIES, type VacuumCapabilities, VacuumCapabilityResolver, VacuumDevice, type VacuumGetMapInput, type VacuumMap, WaterVolume, consumableSpec, createClientDumper, createDumper, decodeAiFeature, encodeAiFeatureWrite, getMowerCapabilities, getVacuumCapabilities, renderMowerSvg, renderVacuumPng, resolveCapabilities };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/support/version.ts
2
2
  var LIBRARY_NAME = "nodedreame";
3
- var LIBRARY_VERSION = "1.6.0";
3
+ var LIBRARY_VERSION = "1.7.0";
4
4
 
5
5
  // src/transport/errors.ts
6
6
  var DreameError = class extends Error {
@@ -1570,6 +1570,23 @@ function encodeAiFeatureWrite(raw, feature, value) {
1570
1570
  );
1571
1571
  }
1572
1572
 
1573
+ // src/models/vacuum/consumables.ts
1574
+ var VACUUM_CONSUMABLES = [
1575
+ { key: "main-brush", label: "Main Brush", life: { siid: 9, piid: 2 }, reset: { siid: 9, aiid: 1 } },
1576
+ { key: "side-brush", label: "Side Brush", life: { siid: 10, piid: 2 }, reset: { siid: 10, aiid: 1 } },
1577
+ { key: "filter", label: "Filter", life: { siid: 11, piid: 1 }, reset: { siid: 11, aiid: 1 } },
1578
+ { key: "sensor", label: "Sensor", life: { siid: 16, piid: 1 }, reset: { siid: 16, aiid: 1 } },
1579
+ { key: "tank-filter", label: "Tank Filter", life: { siid: 17, piid: 1 }, reset: { siid: 17, aiid: 1 } },
1580
+ { key: "mop-pad", label: "Mop Pad", life: { siid: 18, piid: 1 }, reset: { siid: 18, aiid: 1 } },
1581
+ { key: "silver-ion", label: "Silver-ion", life: { siid: 19, piid: 2 }, reset: { siid: 19, aiid: 1 } },
1582
+ { key: "detergent", label: "Detergent", life: { siid: 20, piid: 1 }, reset: { siid: 20, aiid: 1 } },
1583
+ { key: "squeegee", label: "Squeegee", life: { siid: 24, piid: 1 }, reset: { siid: 24, aiid: 1 } },
1584
+ { key: "dust-bag", label: "Dust Bag", life: { siid: 27, piid: 17 }, reset: null }
1585
+ ];
1586
+ function consumableSpec(key2) {
1587
+ return VACUUM_CONSUMABLES.find((c) => c.key === key2);
1588
+ }
1589
+
1573
1590
  // src/models/vacuum/capabilities.ts
1574
1591
  var X50_AI_FEATURES = [
1575
1592
  "obstacleDetection",
@@ -2771,6 +2788,51 @@ var VacuumDevice = class _VacuumDevice extends BaseDevice {
2771
2788
  get volume() {
2772
2789
  return this.#num(SETTINGS_PROP.VOLUME.siid, SETTINGS_PROP.VOLUME.piid);
2773
2790
  }
2791
+ // -- consumables --------------------------------------------------------
2792
+ /**
2793
+ * Remaining-life % (0..100) for one consumable, or `null` when the model does
2794
+ * not report it (presence == support). Call {@link refreshConsumables} first
2795
+ * on a docked robot so the cloud-shadow life values are seeded.
2796
+ */
2797
+ consumableLeftPct(key2) {
2798
+ const spec = consumableSpec(key2);
2799
+ if (spec === void 0) return null;
2800
+ return this.#num(spec.life.siid, spec.life.piid);
2801
+ }
2802
+ /**
2803
+ * The consumables this model EXPOSES — discovered by presence (a reported
2804
+ * life property), mirroring how the HA integration derives support. Each
2805
+ * reading carries the current remaining-life % and whether a reset action
2806
+ * exists. Empty until the life properties have been observed (push) or seeded
2807
+ * via {@link refreshConsumables}.
2808
+ */
2809
+ get supportedConsumables() {
2810
+ return VACUUM_CONSUMABLES.flatMap((spec) => {
2811
+ const leftPct = this.#num(spec.life.siid, spec.life.piid);
2812
+ return leftPct === null ? [] : [{ key: spec.key, label: spec.label, leftPct, resettable: spec.reset !== null }];
2813
+ });
2814
+ }
2815
+ /**
2816
+ * Seed EVERY consumable life property from the cloud shadow (no robot wake) so
2817
+ * {@link supportedConsumables} reflects the full set on a docked robot. The
2818
+ * consumable life values are static settings the robot rarely re-pushes over
2819
+ * MQTT, so a fresh connect surfaces only the actively-changing ones without this.
2820
+ */
2821
+ async refreshConsumables() {
2822
+ await this.refreshCachedProperties(VACUUM_CONSUMABLES.map((c) => c.life));
2823
+ }
2824
+ /**
2825
+ * Reset (mark replaced → life back to 100%) one consumable via its MIoT reset
2826
+ * action. Rejects when the model exposes no reset action for the key (e.g.
2827
+ * `dust-bag`) or the key is unknown.
2828
+ */
2829
+ async resetConsumable(key2) {
2830
+ const spec = consumableSpec(key2);
2831
+ if (spec === void 0 || spec.reset === null) {
2832
+ throw new DreameError(`resetConsumable: no reset action for consumable "${key2}"`);
2833
+ }
2834
+ return this.callAction(spec.reset.siid, spec.reset.aiid, []);
2835
+ }
2774
2836
  // -- AI obstacle-detection ----------------------------------------------
2775
2837
  /**
2776
2838
  * The raw `AI_DETECTION` value (siid 4 piid 22) — an int bitmask or a JSON
@@ -2793,6 +2855,20 @@ var VacuumDevice = class _VacuumDevice extends BaseDevice {
2793
2855
  aiFeature(feature) {
2794
2856
  return decodeAiFeature(this.aiDetectionRaw, feature);
2795
2857
  }
2858
+ /**
2859
+ * Seed {@link aiDetectionRaw} from the CLOUD SHADOW (the last value the robot
2860
+ * pushed for `AI_DETECTION`, siid 4 piid 22) WITHOUT waking it. The AI-obstacle
2861
+ * toggles are STATIC settings the robot rarely re-pushes over MQTT, so a fresh
2862
+ * connect to an idle robot has no value cached — call this on activate to
2863
+ * surface the current toggles. Emits the usual `propertyChanged`/`stateChanged`
2864
+ * (so a watching consumer re-decodes) and returns the resolved raw value
2865
+ * (`null` when the model has no AI detection or the shadow carries none yet).
2866
+ */
2867
+ async refreshAiDetection() {
2868
+ if (!this.#caps.hasAiObstacleDetection) return null;
2869
+ await this.refreshCachedProperties([VACUUM_PROP.AI_DETECTION]);
2870
+ return this.aiDetectionRaw;
2871
+ }
2796
2872
  /**
2797
2873
  * Toggle ONE AI-obstacle feature, preserving the others via a read-modify-write
2798
2874
  * of the packed `AI_DETECTION` property (mirrors Tasshack `set_ai_detection`).
@@ -4741,10 +4817,12 @@ export {
4741
4817
  Nodreame,
4742
4818
  SuctionLevel,
4743
4819
  TaskStatus,
4820
+ VACUUM_CONSUMABLES,
4744
4821
  MODEL_CAPABILITIES as VACUUM_MODEL_CAPABILITIES,
4745
4822
  VacuumCapabilityResolver,
4746
4823
  VacuumDevice,
4747
4824
  WaterVolume,
4825
+ consumableSpec,
4748
4826
  createClientDumper,
4749
4827
  createDumper,
4750
4828
  decodeAiFeature,