@mega-yfue/eufy-sdk 0.5.0-beta.64 → 0.5.0-beta.66

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.
@@ -253,8 +253,8 @@ export declare class EufyMega extends EventEmitter {
253
253
  */
254
254
  private mqttScopesInUse;
255
255
  /**
256
- * Read every Tuya clean-line device's DPs from the Tuya cloud and deliver them as realtime state. A
257
- * failed read is reported, not fatal, and leaves that device's state as it was.
256
+ * Read every Tuya clean-line device's DPs from the Tuya cloud and deliver them as realtime state,
257
+ * concurrently. A failed read is reported, not fatal, and leaves that device's state as it was.
258
258
  */
259
259
  private readTuyaDevices;
260
260
  /**
@@ -619,6 +619,11 @@ export declare class EufyMega extends EventEmitter {
619
619
  * an unchanged VALUE, which is no state change to report but is fresh proof the device is alive. A
620
620
  * device absent from the previous pass is skipped — first sight is discovery, not a transition;
621
621
  * {@link deviceState} answers an initial reading.
622
+ *
623
+ * Then re-reads every Tuya clean-line robot from the Tuya cloud ({@link readTuyaDevices}): its state
624
+ * is not in the cloud record this pass diffs and no live channel carries it, so the poll is where it
625
+ * stays fresh. That read runs after the `try`, not inside it, so a cloud error on the list diff does
626
+ * not skip it; it reports its own failures and never rejects.
622
627
  */
623
628
  private pollOnce;
624
629
  /**
package/dist/index.js CHANGED
@@ -7756,6 +7756,8 @@ var ARMING_CMD = {
7756
7756
  * The ENCRYPTION LEVEL is the session's to pick (`"auto"`), not this command's: the T8030 the envelope
7757
7757
  * was captured on holds a level-2 key and seals it level-2, while an own-session camera that never
7758
7758
  * negotiates one carries the same envelope level-1. See `armingCommand`.
7759
+ *
7760
+ * A T8410C takes the mode as a direct frame instead of this envelope; see {@link DIRECT_ARMING_MODELS}.
7759
7761
  */
7760
7762
  SET_ARMING: 1224,
7761
7763
  /**
@@ -7794,6 +7796,8 @@ var ARMING_CMD = {
7794
7796
  };
7795
7797
  var DEVICE_NOTIFY_FLAG = 8;
7796
7798
  var STANDALONE_ACTION_MODELS = /* @__PURE__ */ new Set(["T8170", "T8171"]);
7799
+ var DIRECT_ARMING_MODELS = /* @__PURE__ */ new Set(["T8410C"]);
7800
+ var DIRECT_ARMING_MODES = /* @__PURE__ */ new Set(["away", "home", "disarmed"]);
7797
7801
  var STANDALONE_READ_MODELS = /* @__PURE__ */ new Set([...STANDALONE_ACTION_MODELS, "T8400", "T8442", "T8410"]);
7798
7802
  function ownAction(read, mode) {
7799
7803
  const value = Number(read(`${mode}Action`)?.value);
@@ -7826,6 +7830,12 @@ function armingCommand(mode, ctx) {
7826
7830
  if (!ctx.accountName) {
7827
7831
  throw new Error(`arming: missing account identity (user_name) [${describeDevice(ctx)}]`);
7828
7832
  }
7833
+ if (DIRECT_ARMING_MODELS.has(ctx.model ?? "")) {
7834
+ if (!DIRECT_ARMING_MODES.has(mode)) {
7835
+ throw new Error(`arming: mode ${mode} is unconfirmed on the direct 1224 frame [${describeDevice(ctx)}]`);
7836
+ }
7837
+ return setStationScalar(ARMING_CMD.SET_ARMING, ARMING_MODE_WIRE[mode], ctx.channel);
7838
+ }
7829
7839
  return setPayload(ARMING_CMD.SET_ARMING, { mode_type: ARMING_MODE_WIRE[mode], user_name: ctx.accountName }, ctx, 0, void 0, "auto");
7830
7840
  }
7831
7841
  function alarmDelayCommand(mode, config, ctx) {
@@ -7880,7 +7890,7 @@ var ARMING_MEMBERS = {
7880
7890
  kind: "enum",
7881
7891
  enumValues: ARMING_MODE_LABELS,
7882
7892
  provenance: "verified",
7883
- description: "Guard mode (verified: param 1224 = GUARD_MODE, read/write mechanism confirmed). Reads and SETS all 9 modes the app defines \u2014 away/home/schedule/custom1/custom2/custom3/off/geo/disarmed. Three are byte-captured writes and six are live-confirmed (each sent and observed to report its own MODE_SWITCH); see ARMING_MODE_WIRE in arming.ts for the per-value evidence.",
7893
+ description: "Guard mode (verified: param 1224 = GUARD_MODE, read/write mechanism confirmed). Reads and SETS all 9 modes the app defines \u2014 away/home/schedule/custom1/custom2/custom3/off/geo/disarmed. Three are byte-captured writes and six are live-confirmed (each sent and observed to report its own MODE_SWITCH); see ARMING_MODE_WIRE in arming.ts for the per-value evidence. On a T8410C only away, home and disarmed are writable.",
7884
7894
  observation: {
7885
7895
  event: "armingModeChanged",
7886
7896
  reflects: (value) => ({ param: ARMING_CMD.SET_ARMING, expected: ARMING_MODE_WIRE[armingModeOf(value)] }),
@@ -28472,16 +28482,14 @@ var EufyMega = class extends EventEmitter13 {
28472
28482
  ];
28473
28483
  }
28474
28484
  /**
28475
- * Read every Tuya clean-line device's DPs from the Tuya cloud and deliver them as realtime state. A
28476
- * failed read is reported, not fatal, and leaves that device's state as it was.
28485
+ * Read every Tuya clean-line device's DPs from the Tuya cloud and deliver them as realtime state,
28486
+ * concurrently. A failed read is reported, not fatal, and leaves that device's state as it was.
28477
28487
  */
28478
- readTuyaDevices() {
28479
- for (const d of this.getMqttDevices().filter(isTuyaVacuum)) {
28480
- this.tuya.fetchDps(d.sn).then((dps) => {
28481
- if (dps)
28482
- this.tuyaDpRouter.deliver(d.sn, dps);
28483
- }).catch((e) => this.reportError(e));
28484
- }
28488
+ async readTuyaDevices() {
28489
+ await Promise.all(this.getMqttDevices().filter(isTuyaVacuum).map((d) => this.tuya.fetchDps(d.sn).then((dps) => {
28490
+ if (dps)
28491
+ this.tuyaDpRouter.deliver(d.sn, dps);
28492
+ }).catch((e) => this.reportError(e))));
28485
28493
  }
28486
28494
  /**
28487
28495
  * Emit a semantic capability event whose name is only known at runtime (`decodeCapabilityEvent`
@@ -29224,7 +29232,7 @@ var EufyMega = class extends EventEmitter13 {
29224
29232
  await this.getDevices();
29225
29233
  if (epoch !== this.realtimeEpoch)
29226
29234
  return this.settleRealtimeGeneration(generation, "superseded");
29227
- this.readTuyaDevices();
29235
+ void this.readTuyaDevices();
29228
29236
  const scopes = this.mqttScopesInUse();
29229
29237
  readiness.mqtt = createPlaneReadiness(scopes.length);
29230
29238
  let push;
@@ -29358,6 +29366,11 @@ var EufyMega = class extends EventEmitter13 {
29358
29366
  * an unchanged VALUE, which is no state change to report but is fresh proof the device is alive. A
29359
29367
  * device absent from the previous pass is skipped — first sight is discovery, not a transition;
29360
29368
  * {@link deviceState} answers an initial reading.
29369
+ *
29370
+ * Then re-reads every Tuya clean-line robot from the Tuya cloud ({@link readTuyaDevices}): its state
29371
+ * is not in the cloud record this pass diffs and no live channel carries it, so the poll is where it
29372
+ * stays fresh. That read runs after the `try`, not inside it, so a cloud error on the list diff does
29373
+ * not skip it; it reports its own failures and never rejects.
29361
29374
  */
29362
29375
  async pollOnce() {
29363
29376
  try {
@@ -29377,6 +29390,7 @@ var EufyMega = class extends EventEmitter13 {
29377
29390
  } catch (e) {
29378
29391
  this.reportError(e);
29379
29392
  }
29393
+ await this.readTuyaDevices();
29380
29394
  }
29381
29395
  /**
29382
29396
  * Land a poll pass's CHANGES on every live {@link Device} and announce what moved, BEFORE anything