@apocaliss92/nodedreame 1.11.1 → 1.11.2

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.cjs CHANGED
@@ -44,6 +44,7 @@ __export(index_exports, {
44
44
  DreameTransportError: () => DreameTransportError,
45
45
  LIBRARY_NAME: () => LIBRARY_NAME,
46
46
  MOWER_MODEL_CAPABILITIES: () => MODEL_CAPABILITIES2,
47
+ MOWER_TASK_SUBSTATES: () => MOWER_TASK_SUBSTATES,
47
48
  MiotError: () => MiotError,
48
49
  MiotState: () => MiotState,
49
50
  MowerCapabilityResolver: () => MowerCapabilityResolver,
@@ -75,6 +76,7 @@ __export(index_exports, {
75
76
  isDreameConsumableKey: () => isDreameConsumableKey,
76
77
  mowerConsumableIndex: () => mowerConsumableIndex,
77
78
  parseMowerConsumables: () => parseMowerConsumables,
79
+ parseMowerHeartbeat: () => parseMowerHeartbeat,
78
80
  renderMowerSvg: () => renderMowerSvg,
79
81
  renderVacuumPng: () => renderVacuumPng,
80
82
  resolveCapabilities: () => resolveCapabilities,
@@ -84,7 +86,7 @@ module.exports = __toCommonJS(index_exports);
84
86
 
85
87
  // src/support/version.ts
86
88
  var LIBRARY_NAME = "nodedreame";
87
- var LIBRARY_VERSION = "1.11.1";
89
+ var LIBRARY_VERSION = "1.11.2";
88
90
 
89
91
  // src/transport/errors.ts
90
92
  var DreameError = class extends Error {
@@ -1659,7 +1661,9 @@ function encodeAiFeatureWrite(raw, feature, value) {
1659
1661
  if (typeof raw === "number") {
1660
1662
  const bit = AI_FEATURE_BIT[feature];
1661
1663
  if (bit === void 0) {
1662
- throw new Error(`encodeAiFeatureWrite: feature "${feature}" has no int-bitmask representation`);
1664
+ throw new Error(
1665
+ `encodeAiFeatureWrite: feature "${feature}" has no int-bitmask representation`
1666
+ );
1663
1667
  }
1664
1668
  return value ? raw | bit : raw & ~bit;
1665
1669
  }
@@ -1776,18 +1780,53 @@ function encodeAutoSwitchWrite(key2, value) {
1776
1780
 
1777
1781
  // src/models/vacuum/consumables.ts
1778
1782
  var VACUUM_CONSUMABLES = [
1779
- { key: "main-brush", label: "Main Brush", life: { siid: 9, piid: 2 }, reset: { siid: 9, aiid: 1 } },
1780
- { key: "side-brush", label: "Side Brush", life: { siid: 10, piid: 2 }, reset: { siid: 10, aiid: 1 } },
1783
+ {
1784
+ key: "main-brush",
1785
+ label: "Main Brush",
1786
+ life: { siid: 9, piid: 2 },
1787
+ reset: { siid: 9, aiid: 1 }
1788
+ },
1789
+ {
1790
+ key: "side-brush",
1791
+ label: "Side Brush",
1792
+ life: { siid: 10, piid: 2 },
1793
+ reset: { siid: 10, aiid: 1 }
1794
+ },
1781
1795
  { key: "filter", label: "Filter", life: { siid: 11, piid: 1 }, reset: { siid: 11, aiid: 1 } },
1782
1796
  { key: "sensor", label: "Sensor", life: { siid: 16, piid: 1 }, reset: { siid: 16, aiid: 1 } },
1783
- { key: "tank-filter", label: "Tank Filter", life: { siid: 17, piid: 1 }, reset: { siid: 17, aiid: 1 } },
1797
+ {
1798
+ key: "tank-filter",
1799
+ label: "Tank Filter",
1800
+ life: { siid: 17, piid: 1 },
1801
+ reset: { siid: 17, aiid: 1 }
1802
+ },
1784
1803
  { key: "mop-pad", label: "Mop Pad", life: { siid: 18, piid: 1 }, reset: { siid: 18, aiid: 1 } },
1785
- { key: "silver-ion", label: "Silver-ion", life: { siid: 19, piid: 2 }, reset: { siid: 19, aiid: 1 } },
1786
- { key: "detergent", label: "Detergent", life: { siid: 20, piid: 1 }, reset: { siid: 20, aiid: 1 } },
1804
+ {
1805
+ key: "silver-ion",
1806
+ label: "Silver-ion",
1807
+ life: { siid: 19, piid: 2 },
1808
+ reset: { siid: 19, aiid: 1 }
1809
+ },
1810
+ {
1811
+ key: "detergent",
1812
+ label: "Detergent",
1813
+ life: { siid: 20, piid: 1 },
1814
+ reset: { siid: 20, aiid: 1 }
1815
+ },
1787
1816
  { key: "squeegee", label: "Squeegee", life: { siid: 24, piid: 1 }, reset: { siid: 24, aiid: 1 } },
1788
- { key: "deodorizer", label: "Deodorizer", life: { siid: 29, piid: 2 }, reset: { siid: 29, aiid: 1 } },
1817
+ {
1818
+ key: "deodorizer",
1819
+ label: "Deodorizer",
1820
+ life: { siid: 29, piid: 2 },
1821
+ reset: { siid: 29, aiid: 1 }
1822
+ },
1789
1823
  { key: "wheel", label: "Wheel", life: { siid: 30, piid: 2 }, reset: { siid: 30, aiid: 1 } },
1790
- { key: "scale-inhibitor", label: "Scale Inhibitor", life: { siid: 31, piid: 2 }, reset: { siid: 31, aiid: 1 } },
1824
+ {
1825
+ key: "scale-inhibitor",
1826
+ label: "Scale Inhibitor",
1827
+ life: { siid: 31, piid: 2 },
1828
+ reset: { siid: 31, aiid: 1 }
1829
+ },
1791
1830
  { key: "dust-bag", label: "Dust Bag", life: { siid: 27, piid: 17 }, reset: null }
1792
1831
  ];
1793
1832
  function consumableSpec(key2) {
@@ -3902,6 +3941,9 @@ var VacuumDevice = class _VacuumDevice extends BaseDevice {
3902
3941
 
3903
3942
  // src/models/mower/properties.ts
3904
3943
  var MOWER_PROP = {
3944
+ /** VERIFIED-by-donor — 20-byte heartbeat (sentinel 0xCE at [0]/[19]); byte 11
3945
+ * battery, byte 12 main-state, byte 13 task sub-state. See parseHeartbeat. */
3946
+ HEARTBEAT: { siid: 1, piid: 1 },
3905
3947
  /** VERIFIED-by-donor — pose + coverage telemetry (binary). P4 uses progress % only. */
3906
3948
  POSE_COVERAGE: { siid: 1, piid: 4 },
3907
3949
  /** VERIFIED-by-donor — MowerStatus (DeviceStatus). */
@@ -4251,6 +4293,39 @@ function parseMowerConsumables(result) {
4251
4293
  };
4252
4294
  });
4253
4295
  }
4296
+ var MOWER_TASK_SUBSTATES = [
4297
+ "idle",
4298
+ "starting",
4299
+ "mowing",
4300
+ "paused",
4301
+ "finished",
4302
+ "failed",
4303
+ "exit",
4304
+ "returning-to-dock"
4305
+ ];
4306
+ var HEARTBEAT_SENTINEL = 206;
4307
+ var HEARTBEAT_SUBSTATE_BASE = 33;
4308
+ var HEARTBEAT_MAIN_STATE_MOWING = 4;
4309
+ function parseMowerHeartbeat(value) {
4310
+ if (!Array.isArray(value) || value.length < 14) {
4311
+ return null;
4312
+ }
4313
+ const bytes = [];
4314
+ for (const b of value) {
4315
+ if (typeof b !== "number") {
4316
+ return null;
4317
+ }
4318
+ bytes.push(b);
4319
+ }
4320
+ if (bytes[0] !== HEARTBEAT_SENTINEL || bytes[bytes.length - 1] !== HEARTBEAT_SENTINEL) {
4321
+ return null;
4322
+ }
4323
+ const rawBattery = bytes[11] ?? 0;
4324
+ const mainState = ((bytes[12] ?? 0) & 15) - 1;
4325
+ const subStateRaw = bytes[13] ?? 0;
4326
+ const taskSubState = mainState === HEARTBEAT_MAIN_STATE_MOWING ? MOWER_TASK_SUBSTATES[subStateRaw - HEARTBEAT_SUBSTATE_BASE] ?? null : null;
4327
+ return { rawBattery, mainState, subStateRaw, taskSubState };
4328
+ }
4254
4329
 
4255
4330
  // src/models/mower/capabilities.ts
4256
4331
  var FALLBACK2 = {
@@ -4924,6 +4999,19 @@ var MowerDevice = class _MowerDevice extends BaseDevice {
4924
4999
  get fault() {
4925
5000
  return FAULT(this.faultRaw);
4926
5001
  }
5002
+ /**
5003
+ * Live mowing task sub-state decoded from the HEARTBEAT (1:1) blob —
5004
+ * idle/starting/mowing/paused/finished/failed/exit/returning-to-dock — or null
5005
+ * when no mowing session is in progress (or the heartbeat is absent). This is
5006
+ * the donor's "current task" sensor; the heartbeat is push-only (the mower does
5007
+ * not answer live reads), so it tracks the device while it is actively mowing.
5008
+ */
5009
+ get taskSubState() {
5010
+ const hb = parseMowerHeartbeat(
5011
+ this.getProperty(MOWER_PROP.HEARTBEAT.siid, MOWER_PROP.HEARTBEAT.piid)?.value
5012
+ );
5013
+ return hb?.taskSubState ?? null;
5014
+ }
4927
5015
  /** Parsed scheduling task descriptor (2:50), or null. */
4928
5016
  get task() {
4929
5017
  return parseTaskDescriptor(
@@ -5115,6 +5203,7 @@ var MowerDevice = class _MowerDevice extends BaseDevice {
5115
5203
  }
5116
5204
  /** Props worth seeding on start() / polling — exported for the facade. */
5117
5205
  static DEFAULT_PROPS = [
5206
+ MOWER_PROP.HEARTBEAT,
5118
5207
  MOWER_PROP.STATUS,
5119
5208
  MOWER_PROP.DEVICE_CODE,
5120
5209
  MOWER_PROP.BATTERY,
@@ -5743,6 +5832,7 @@ function createClientDumper(client, options) {
5743
5832
  DreameTransportError,
5744
5833
  LIBRARY_NAME,
5745
5834
  MOWER_MODEL_CAPABILITIES,
5835
+ MOWER_TASK_SUBSTATES,
5746
5836
  MiotError,
5747
5837
  MiotState,
5748
5838
  MowerCapabilityResolver,
@@ -5774,6 +5864,7 @@ function createClientDumper(client, options) {
5774
5864
  isDreameConsumableKey,
5775
5865
  mowerConsumableIndex,
5776
5866
  parseMowerConsumables,
5867
+ parseMowerHeartbeat,
5777
5868
  renderMowerSvg,
5778
5869
  renderVacuumPng,
5779
5870
  resolveCapabilities,