@mega-yfue/eufy-sdk 0.2.0-beta.19 → 0.2.0-beta.20

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.js CHANGED
@@ -3810,7 +3810,7 @@ function sensitivityCommand(step, scale, ctx) {
3810
3810
  return setScalar(scale.writeId, value, ctx, "direct-binary");
3811
3811
  if (scale.form === "control")
3812
3812
  return setJson(scale.writeId, { index: value }, ctx);
3813
- return setPayload(scale.writeId, { sensitivity: value, channel: ctx.channel }, ctx, 0);
3813
+ return setPayload(scale.writeId, { sensitivity: value, channel: ctx.channel }, ctx, 0, void 0, "auto");
3814
3814
  }
3815
3815
  var EXIT_TEST_MODE_VALUE = 808464384;
3816
3816
  function requireFamily(action, ctx, verifiedOn) {
@@ -3888,7 +3888,7 @@ var MOTION_MEMBERS = {
3888
3888
  const n = Number(v);
3889
3889
  if (!Number.isInteger(n) || n < 0)
3890
3890
  return void 0;
3891
- return setPayload(MOTION_CMD.AI_DETECT_TYPE, { ai_detect_type: n, channel: ctx.channel }, ctx, 0, 0);
3891
+ return setPayload(MOTION_CMD.AI_DETECT_TYPE, { ai_detect_type: n, channel: ctx.channel }, ctx, 0, 0, "auto");
3892
3892
  }
3893
3893
  },
3894
3894
  /**
@@ -4001,7 +4001,7 @@ var MOTION_MEMBERS = {
4001
4001
  requires: [MOTION_CMD.HUMAN_ONLY_AT_NIGHT],
4002
4002
  write: (v, ctx) => {
4003
4003
  requireFamily("humanOnlyAtNight", ctx, "camera");
4004
- return setPayload(MOTION_CMD.HUMAN_ONLY_AT_NIGHT, { only_ai: asBool(v) ? 1 : 0 }, ctx, 0);
4004
+ return setPayload(MOTION_CMD.HUMAN_ONLY_AT_NIGHT, { only_ai: asBool(v) ? 1 : 0 }, ctx, 0, void 0, "auto");
4005
4005
  }
4006
4006
  },
4007
4007
  /**
@@ -4018,7 +4018,7 @@ var MOTION_MEMBERS = {
4018
4018
  requires: [MOTION_CMD.LOITERING_DETECTION],
4019
4019
  write: (v, ctx) => {
4020
4020
  requireFamily("loiteringDetection", ctx, "camera");
4021
- return setPayload(MOTION_CMD.LOITERING_DETECTION, { radar_wd_switch: asBool(v) ? 1 : 0 }, ctx, 0);
4021
+ return setPayload(MOTION_CMD.LOITERING_DETECTION, { radar_wd_switch: asBool(v) ? 1 : 0 }, ctx, 0, void 0, "auto");
4022
4022
  }
4023
4023
  }
4024
4024
  };
@@ -4275,7 +4275,7 @@ var BATTERY_MEMBERS = cellGated({
4275
4275
  args: [{ name: "source", kind: "enum", description: "The raw value, or the name `battery`/`external`." }],
4276
4276
  ...accepts(),
4277
4277
  description: "Configured power source (1293): 0 = Battery, 1 = External Solar Panel. Verified live on T8124R. The richer raw APP_CMD_SET_POWER_SOURCE blob is surfaced separately as `powerSourceInfo` (6445). Format varies by model (plain int or JSON {power_source:N}); values beyond 0/1 shown raw.",
4278
- write: (v, ctx) => setPayload(BATTERY_PARAM.POWER_CHARGE, { charge_mode: v === "external" ? 1 : v === "battery" ? 0 : asBool(v) ? 1 : 0 }, ctx, 0)
4278
+ write: (v, ctx) => setPayload(BATTERY_PARAM.POWER_CHARGE, { charge_mode: v === "external" ? 1 : v === "battery" ? 0 : asBool(v) ? 1 : 0 }, ctx, 0, void 0, "auto")
4279
4279
  },
4280
4280
  /**
4281
4281
  * A DEVICE-SPECIFIC mode index: the app maps value→mode through a per-model config (Hermes
@@ -4593,6 +4593,10 @@ var CONTACT_MEMBERS = {
4593
4593
  * `1350` SET_PAYLOAD, `mChannel` = the device channel, `mValue3` 0, payload carrying the channel and a
4594
4594
  * transaction stamp — the byte-shape of the app's own captured frame. Out of range is refused rather
4595
4595
  * than clamped: the app's slider has no values outside it, so one is a caller error, not a nudge.
4596
+ *
4597
+ * Level-2 only, though the `mValue3` 0 would allow `"auto"`: an entry sensor's session IS its
4598
+ * HomeBase's, which always holds a key — the second of `setPayload`'s two conditions, not an oversight
4599
+ * of the first.
4596
4600
  */
4597
4601
  alarmVolume: {
4598
4602
  param: CONTACT_CMD.ALARM_VOLUME,
@@ -4820,7 +4824,7 @@ var AUDIO_MEMBERS = {
4820
4824
  provenance: "verified",
4821
4825
  available: isCameraCodec,
4822
4826
  description: "Record audio with video (1288 record_mute, inverted). \u2705 HW-verified on T8425: readback flips (on\u21921288=0, off\u21921288=1). The write is a 1350 SET_PAYLOAD on the device channel with `{channel, record_mute}` \u2014 the key is record_mute and it is INVERTED.",
4823
- write: (v, ctx) => setPayload(AUDIO_CMD.AUDIO_RECORDING, { channel: ctx.channel, record_mute: asBool(v) ? 0 : 1 }, ctx, 0)
4827
+ write: (v, ctx) => setPayload(AUDIO_CMD.AUDIO_RECORDING, { channel: ctx.channel, record_mute: asBool(v) ? 0 : 1 }, ctx, 0, void 0, "auto")
4824
4828
  },
4825
4829
  /**
4826
4830
  * Doorbell ring/chime loudness — WRITE-ONLY here on purpose. The READ property `ringtoneVolume` (1708)
@@ -5268,7 +5272,7 @@ var CAMERA_MEMBERS = {
5268
5272
  description: "Night-vision mode (NIGHT_VISION_TYPE 1277): 0 = off, 1 = infrared (B&W), 2 = full colour. \u2705 wire verified live (T8425 ch3): 1350 SET_PAYLOAD, mChannel 0, {channel:N, night_sion:mode}. Enum labels are best-guess. Some models omit full colour.",
5269
5273
  write: (v, ctx) => {
5270
5274
  const nv = coerceEnumValue(NightVision, v);
5271
- return nv == null ? void 0 : setPayload(CAMERA_CMD.NIGHT_VISION_TYPE, { channel: ctx.channel, night_sion: nv }, ctx, 0, 0);
5275
+ return nv == null ? void 0 : setPayload(CAMERA_CMD.NIGHT_VISION_TYPE, { channel: ctx.channel, night_sion: nv }, ctx, 0, 0, "auto");
5272
5276
  }
5273
5277
  },
5274
5278
  /**
@@ -5316,7 +5320,7 @@ var CAMERA_MEMBERS = {
5316
5320
  ...accepts(),
5317
5321
  write: (v, ctx) => {
5318
5322
  const q = resolveRecordingQualityTier(v);
5319
- return q == null ? void 0 : setPayload(CAMERA_CMD.RECORDING_QUALITY_SET, { channel: 0, mode: 0, primary_view: 0, quality: q }, ctx, 0);
5323
+ return q == null ? void 0 : setPayload(CAMERA_CMD.RECORDING_QUALITY_SET, { channel: 0, mode: 0, primary_view: 0, quality: q }, ctx, 0, void 0, "auto");
5320
5324
  }
5321
5325
  },
5322
5326
  /**
@@ -5696,7 +5700,7 @@ function autoSpotlightCommand(on, ctx, opts = {}) {
5696
5700
  schedule: [],
5697
5701
  sunset2rise: 0,
5698
5702
  time: opts.time ?? 30
5699
- }, ctx, 0);
5703
+ }, ctx, 0, void 0, "auto");
5700
5704
  }
5701
5705
  function lightSwitchWire(ctx) {
5702
5706
  const t = ctx.deviceType;
@@ -6235,7 +6239,7 @@ function zoomCommand(dstZoom, ctx, region) {
6235
6239
  offset,
6236
6240
  orgZoom: r.orgZoom ?? 0,
6237
6241
  dstZoom
6238
- }, ctx, 0);
6242
+ }, ctx, 0, void 0, "auto");
6239
6243
  }
6240
6244
  function gotoPresetCommand(id, ctx) {
6241
6245
  return setJson(PTZ_CMD.PTZ_PRESET_GOTO, { settingstate: 0, value: id }, ctx);
@@ -6631,7 +6635,7 @@ var DOORBELL_MEMBERS = {
6631
6635
  min: 0,
6632
6636
  max: 100,
6633
6637
  description: "Doorbell chime volume, 0-100 (1717 APP_CMD_BAT_DOORBELL_SET_DINGDONG_VOLUME; SET_PAYLOAD envelope, distinct from the direct-binary ringtoneVolume/1708 \u2014 see DOORBELL_CMD.DINGDONG_VOLUME). Write wire-confirmed live on T8214, observed values 3 and 25.",
6634
- write: (v, ctx) => setPayload(DOORBELL_CMD.DINGDONG_VOLUME, { dingdong_volume: Number(v) }, ctx, 0)
6638
+ write: (v, ctx) => setPayload(DOORBELL_CMD.DINGDONG_VOLUME, { dingdong_volume: Number(v) }, ctx, 0, void 0, "auto")
6635
6639
  },
6636
6640
  /**
6637
6641
  * The same `1350` SET_PAYLOAD shape and capture session as {@link DOORBELL_MEMBERS.dingdongVolume},
@@ -6649,7 +6653,7 @@ var DOORBELL_MEMBERS = {
6649
6653
  description: "Doorbell chime ringtone SELECTION INDEX, not a bool (1718 APP_CMD_BAT_DOORBELL_SET_DINGDONG_RINGTONE; SET_PAYLOAD envelope \u2014 see DOORBELL_CMD.DINGDONG_RINGTONE). Write wire-confirmed live on T8214, observed values 4 and 0. Named options: see the {@link DoorbellRingtone} enum. A write outside that enum is REJECTED, not clamped into range \u2014 this is a selection, not a volume, so a bad index would otherwise land on a real-but-wrong tone.",
6650
6654
  write: (v, ctx) => {
6651
6655
  const tone = coerceEnumValue(DoorbellRingtone, v);
6652
- return tone === void 0 ? void 0 : setPayload(DOORBELL_CMD.DINGDONG_RINGTONE, { dingdong_ringtone: tone }, ctx, 0);
6656
+ return tone === void 0 ? void 0 : setPayload(DOORBELL_CMD.DINGDONG_RINGTONE, { dingdong_ringtone: tone }, ctx, 0, void 0, "auto");
6653
6657
  }
6654
6658
  },
6655
6659
  /**
@@ -7230,6 +7234,10 @@ var ARMING_CMD = {
7230
7234
  * first, then `schedule` 2, `custom2` 4, `custom3` 5, `off` 6 and `geo` 47 — each sent as this exact
7231
7235
  * frame and each observed to bring MODE_SWITCH back, so all nine are settable. `ARMING_MODE_WIRE` has
7232
7236
  * the per-value evidence and the dates.
7237
+ *
7238
+ * The ENCRYPTION LEVEL is the session's to pick (`"auto"`), not this command's: the T8030 the envelope
7239
+ * was captured on holds a level-2 key and seals it level-2, while an own-session camera that never
7240
+ * negotiates one carries the same envelope level-1. See `armingCommand`.
7233
7241
  */
7234
7242
  SET_ARMING: 1224,
7235
7243
  /**
@@ -7282,7 +7290,7 @@ function armingCommand(mode, ctx) {
7282
7290
  if (!ctx.accountName) {
7283
7291
  throw new Error(`arming: missing account identity (user_name) [${describeDevice(ctx)}]`);
7284
7292
  }
7285
- return setPayload(ARMING_CMD.SET_ARMING, { mode_type: ARMING_MODE_WIRE[mode], user_name: ctx.accountName }, ctx, 0);
7293
+ return setPayload(ARMING_CMD.SET_ARMING, { mode_type: ARMING_MODE_WIRE[mode], user_name: ctx.accountName }, ctx, 0, void 0, "auto");
7286
7294
  }
7287
7295
  function alarmDelayCommand(mode, config, ctx) {
7288
7296
  const data = {
@@ -21119,13 +21127,22 @@ var P2PCommandRouter = class _P2PCommandRouter {
21119
21127
  * standalone camera never negotiates a level-2 key, so pinning this to level 2 makes the envelope
21120
21128
  * unreachable on exactly the devices that serve their own RTSP stream. Verified live: a standalone
21121
21129
  * camera accepts the level-1 form. With no `form` (default) it stays level-2 only.
21130
+ *
21131
+ * Both seals REPLAY the frame {@link DIRECT_CMD_SENDS}× at 200ms, as every other fire-and-forget
21132
+ * control on this router does: these are unacknowledged datagrams, and a level-1 device is the one
21133
+ * least able to afford a single dropped one — it has no reply, no readback here, and nothing that
21134
+ * would tell a caller the write was lost rather than refused. The level-1 form reports delivery by
21135
+ * throwing (`sendSetPayload` throws when the session has no address) rather than by returning a
21136
+ * boolean, so the first pass carries the failure and the rest are repeats.
21122
21137
  */
21123
21138
  async sendSetPayloadEnvelope(sn, cmd, payload, channel, mValue3, resolved, form) {
21124
21139
  if (form === "auto") {
21125
21140
  await this.sendBySessionLevel(sn, {
21126
- l1: ({ session, accountId }) => {
21127
- session.sendSetPayload(cmd, payload, { accountId, channel });
21128
- return Promise.resolve();
21141
+ l1: async ({ session, accountId }) => {
21142
+ for (let i = 0; i < DIRECT_CMD_SENDS; i++) {
21143
+ session.sendSetPayload(cmd, payload, { accountId, channel });
21144
+ await sleep2(200);
21145
+ }
21129
21146
  },
21130
21147
  // NB: do NOT forward sendBySessionLevel's resolved session here — it was resolved with
21131
21148
  // waitLevel2:false (enough to read topology), so on a HomeBase-attached device the level-2