@mega-yfue/eufy-sdk 0.0.4 → 0.1.0-beta.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.
Files changed (143) hide show
  1. package/README.md +31 -12
  2. package/dist/client/device-registry.d.ts +343 -0
  3. package/dist/client/eufy-mega.d.ts +872 -0
  4. package/dist/client/index.d.ts +1 -6
  5. package/dist/client/map-channels.d.ts +22 -0
  6. package/dist/client/types.d.ts +383 -0
  7. package/dist/core/contracts.d.ts +898 -0
  8. package/dist/core/crypto.d.ts +98 -0
  9. package/dist/core/index.d.ts +9 -7
  10. package/dist/core/logger.d.ts +53 -0
  11. package/dist/core/lz4-block.d.ts +35 -0
  12. package/dist/core/raw-dp-hex.d.ts +32 -0
  13. package/dist/core/raw-dp-writer.d.ts +83 -0
  14. package/dist/core/store.d.ts +43 -0
  15. package/dist/core/types.d.ts +169 -0
  16. package/dist/core/util.d.ts +78 -0
  17. package/dist/index.d.ts +4 -7
  18. package/dist/index.js +25526 -14
  19. package/dist/index.js.map +7 -1
  20. package/dist/model/capabilities/access.d.ts +127 -0
  21. package/dist/model/capabilities/arming.d.ts +201 -0
  22. package/dist/model/capabilities/audio.d.ts +154 -0
  23. package/dist/model/capabilities/battery.d.ts +363 -0
  24. package/dist/model/capabilities/camera.d.ts +564 -0
  25. package/dist/model/capabilities/co.d.ts +40 -0
  26. package/dist/model/capabilities/contact.d.ts +133 -0
  27. package/dist/model/capabilities/doorbell.d.ts +345 -0
  28. package/dist/model/capabilities/dp-catalog.d.ts +38 -0
  29. package/dist/model/capabilities/index.d.ts +561 -0
  30. package/dist/model/capabilities/info.d.ts +28 -0
  31. package/dist/model/capabilities/keypad.d.ts +61 -0
  32. package/dist/model/capabilities/leak.d.ts +43 -0
  33. package/dist/model/capabilities/light.d.ts +174 -0
  34. package/dist/model/capabilities/locate.d.ts +63 -0
  35. package/dist/model/capabilities/lock.d.ts +242 -0
  36. package/dist/model/capabilities/manifest.d.ts +107 -0
  37. package/dist/model/capabilities/members.d.ts +647 -0
  38. package/dist/model/capabilities/motion.d.ts +377 -0
  39. package/dist/model/capabilities/person-detection.d.ts +8 -0
  40. package/dist/model/capabilities/ptz.d.ts +289 -0
  41. package/dist/model/capabilities/rtsp.d.ts +221 -0
  42. package/dist/model/capabilities/siren.d.ts +218 -0
  43. package/dist/model/capabilities/smart-light.d.ts +172 -0
  44. package/dist/model/capabilities/smoke.d.ts +40 -0
  45. package/dist/model/capabilities/snapshot.d.ts +6 -0
  46. package/dist/model/capabilities/storage.d.ts +11 -0
  47. package/dist/model/capabilities/suction.d.ts +104 -0
  48. package/dist/model/capabilities/types.d.ts +484 -0
  49. package/dist/model/capabilities/vacuum-clean.d.ts +1946 -0
  50. package/dist/model/capabilities/vacuum-dock.d.ts +208 -0
  51. package/dist/model/capabilities/video.d.ts +6 -0
  52. package/dist/model/classify.d.ts +78 -0
  53. package/dist/model/clean-record-detail.d.ts +65 -0
  54. package/dist/model/clean-records.d.ts +69 -0
  55. package/dist/model/device-family.d.ts +73 -0
  56. package/dist/model/device-types.d.ts +123 -0
  57. package/dist/model/device.d.ts +265 -0
  58. package/dist/model/index.d.ts +29 -4
  59. package/dist/model/infer.d.ts +23 -0
  60. package/dist/model/inspect.d.ts +61 -0
  61. package/dist/model/life-params.d.ts +21 -0
  62. package/dist/model/map-pixels.d.ts +70 -0
  63. package/dist/model/param-dictionary.d.ts +28 -0
  64. package/dist/model/param-namespace.d.ts +21 -0
  65. package/dist/model/proto-read.d.ts +53 -0
  66. package/dist/model/push-events.d.ts +147 -0
  67. package/dist/model/registry.d.ts +54 -0
  68. package/dist/model/types.d.ts +301 -0
  69. package/dist/model/vacuum-map-store.d.ts +92 -0
  70. package/dist/model/vacuum-map.d.ts +286 -0
  71. package/dist/model/vacuum-scenes.d.ts +76 -0
  72. package/dist/model/vacuum-schedules.d.ts +85 -0
  73. package/dist/transport/dp-preset.d.ts +102 -0
  74. package/dist/transport/ff09.d.ts +444 -0
  75. package/dist/transport/ffmpeg.d.ts +86 -0
  76. package/dist/transport/http/decodeImageV1.d.ts +20 -0
  77. package/dist/transport/http/decodeImageV2.d.ts +19 -0
  78. package/dist/transport/http/index.d.ts +5 -0
  79. package/dist/transport/http/light-catalog.d.ts +62 -0
  80. package/dist/transport/http/media-download.d.ts +14 -0
  81. package/dist/transport/http/mega-client.d.ts +514 -0
  82. package/dist/transport/http/phone-model.d.ts +21 -0
  83. package/dist/transport/index.d.ts +10 -7
  84. package/dist/transport/mqtt/app-client-id.d.ts +16 -0
  85. package/dist/transport/mqtt/availability.d.ts +14 -0
  86. package/dist/transport/mqtt/bare-ip-tls.d.ts +46 -0
  87. package/dist/transport/mqtt/biz-stream.d.ts +98 -0
  88. package/dist/transport/mqtt/broker-discovery.d.ts +55 -0
  89. package/dist/transport/mqtt/clean-codec.d.ts +14 -0
  90. package/dist/transport/mqtt/command-router.d.ts +285 -0
  91. package/dist/transport/mqtt/dp-codec.d.ts +58 -0
  92. package/dist/transport/mqtt/dp-color.d.ts +14 -0
  93. package/dist/transport/mqtt/engine.d.ts +16 -0
  94. package/dist/transport/mqtt/index.d.ts +5 -0
  95. package/dist/transport/mqtt/secure-mqtt.d.ts +107 -0
  96. package/dist/transport/mqtt/topics.d.ts +80 -0
  97. package/dist/transport/p2p/adts.d.ts +91 -0
  98. package/dist/transport/p2p/annexb.d.ts +124 -0
  99. package/dist/transport/p2p/codec.d.ts +166 -0
  100. package/dist/transport/p2p/command-router.d.ts +655 -0
  101. package/dist/transport/p2p/commands.d.ts +550 -0
  102. package/dist/transport/p2p/envelope.d.ts +46 -0
  103. package/dist/transport/p2p/fmp4.d.ts +89 -0
  104. package/dist/transport/p2p/fragment-recording.d.ts +33 -0
  105. package/dist/transport/p2p/index.d.ts +13 -0
  106. package/dist/transport/p2p/lan-ip.d.ts +25 -0
  107. package/dist/transport/p2p/live-stream.d.ts +223 -0
  108. package/dist/transport/p2p/live-trace.d.ts +123 -0
  109. package/dist/transport/p2p/media.d.ts +105 -0
  110. package/dist/transport/p2p/p2p-session.d.ts +620 -0
  111. package/dist/transport/p2p/readable-egress.d.ts +27 -0
  112. package/dist/transport/p2p/session-manager.d.ts +154 -0
  113. package/dist/transport/p2p/shared-live-source.d.ts +431 -0
  114. package/dist/transport/p2p/talkback.d.ts +187 -0
  115. package/dist/transport/p2p/video.d.ts +150 -0
  116. package/dist/transport/p2p/write-commands.d.ts +21 -0
  117. package/dist/transport/protobuf.d.ts +5 -0
  118. package/dist/transport/push/fcm.d.ts +23 -0
  119. package/dist/transport/push/index.d.ts +6 -0
  120. package/dist/transport/push/message-tags.d.ts +26 -0
  121. package/dist/transport/push/parser.d.ts +27 -0
  122. package/dist/transport/push/proto.d.ts +11 -0
  123. package/dist/transport/push/push-client.d.ts +64 -0
  124. package/dist/transport/push/store.d.ts +23 -0
  125. package/dist/transport/push/types.d.ts +180 -0
  126. package/dist/transport/raw-dp.d.ts +6 -0
  127. package/dist/transport/stored-image-cache.d.ts +23 -0
  128. package/dist/transport/tuya/account.d.ts +44 -0
  129. package/dist/transport/tuya/client.d.ts +89 -0
  130. package/dist/transport/tuya/command-router.d.ts +79 -0
  131. package/dist/transport/tuya/dp-codec.d.ts +56 -0
  132. package/dist/transport/tuya/index.d.ts +28 -0
  133. package/dist/transport/tuya/request.d.ts +157 -0
  134. package/dist/transport/tuya/sign.d.ts +64 -0
  135. package/package.json +12 -13
  136. package/dist/client/index.js +0 -2
  137. package/dist/client/index.js.map +0 -1
  138. package/dist/core/index.js +0 -2
  139. package/dist/core/index.js.map +0 -1
  140. package/dist/model/index.js +0 -2
  141. package/dist/model/index.js.map +0 -1
  142. package/dist/transport/index.js +0 -2
  143. package/dist/transport/index.js.map +0 -1
@@ -0,0 +1,133 @@
1
+ import { type Surface } from "./members.js";
2
+ import type { CapabilityModule } from "./types.js";
3
+ /**
4
+ * The entry sensor's own **command/param ids** — its built-in alarm buzzer (sounds when the door
5
+ * opens while armed), separate from the open/close contact read. Both write wires were captured live
6
+ * on a T90E0 (2026-08-03).
7
+ */
8
+ export declare const CONTACT_CMD: {
9
+ /** Alarm sound/tone selection (app `APP_CMD_ALARM_SOUND_TYPE`). See {@link EntryAlarmTone}. */
10
+ readonly ALARM_SOUND_TYPE: 1507;
11
+ /** Alarm volume (app `APP_CMD_ALARM_VOLUME_VALUE`). A device level 1-26, not a percentage. */
12
+ readonly ALARM_VOLUME: 1508;
13
+ };
14
+ /**
15
+ * The entry sensor's built-in alarm tone: silent, or one of four chimes. Pass a value to
16
+ * `setAlarmSoundType`.
17
+ */
18
+ export declare const EntryAlarmTone: {
19
+ /** Silent — no alarm tone. */
20
+ readonly None: 0;
21
+ readonly Water: 1;
22
+ readonly Classic: 2;
23
+ readonly Light: 3;
24
+ readonly Ding: 4;
25
+ };
26
+ /** An entry-sensor alarm tone — the value side of {@link EntryAlarmTone}. */
27
+ export type EntryAlarmToneValue = (typeof EntryAlarmTone)[keyof typeof EntryAlarmTone];
28
+ /**
29
+ * Bound entry-sensor controls — the object returned by `dev.contact()`.
30
+ *
31
+ * Everything is DERIVED from `CONTACT_MEMBERS`. The open/close read is the headline; the entry
32
+ * sensor also carries a built-in alarm buzzer whose tone and volume are writable, each setter present
33
+ * only when the device reports the backing param.
34
+ */
35
+ export type ContactActions = Surface<typeof CONTACT_MEMBERS>;
36
+ /**
37
+ * Every `contact` feature, declared once. `contact` (1550) and `lastSeen` (1551) are verified reads;
38
+ * the built-in alarm tone (1507) and volume (1508) are verified writes captured live on a T90E0.
39
+ *
40
+ * Exported but NOT published: each entry states its wire id and the evidence it was confirmed on,
41
+ * which the reference site does not carry.
42
+ * @internal
43
+ */
44
+ export declare const CONTACT_MEMBERS: {
45
+ /**
46
+ * The headline read: `true` when the door or window is open. Polarity is the V6 app's own
47
+ * `"1".equals(e)` — see `contactOpen`, which normalises every inbound source through one
48
+ * predicate so the poll, the push and the station notify cannot disagree about what open means.
49
+ * Reporting 1550 is also this capability's detection evidence, so a device with this getter is
50
+ * confirmed to be a contact sensor.
51
+ */
52
+ readonly open: {
53
+ readonly param: 1550;
54
+ readonly property: "contact";
55
+ readonly type: "bool";
56
+ readonly kind: "boolean";
57
+ readonly provenance: "verified";
58
+ readonly description: "Contact state, true=open (verified: param 1550 entry-sensor contact).";
59
+ };
60
+ /**
61
+ * Unix seconds at which the sensor last checked in — the liveness read beside the contact state, and
62
+ * the way to tell a genuinely closed door from a sensor that stopped reporting. A `timestamp` kind
63
+ * takes no `unit`: it is an instant, not a duration.
64
+ */
65
+ readonly lastSeen: {
66
+ readonly param: 1551;
67
+ readonly type: "number";
68
+ readonly kind: "timestamp";
69
+ readonly provenance: "verified";
70
+ readonly description: "Last-seen unix timestamp, seconds (verified: param 1551).";
71
+ };
72
+ /**
73
+ * Link quality to whichever radio the sensor is paired over, in dBm as the device measures it. The
74
+ * same param 1141 the other sub-1G sensors report on, so the number is comparable across them —
75
+ * unlike a bars mapping, which this SDK never applies.
76
+ */
77
+ readonly rssi: {
78
+ readonly param: 1141;
79
+ readonly type: "number";
80
+ readonly unit: "dBm";
81
+ readonly kind: "dbm";
82
+ readonly provenance: "verified";
83
+ readonly description: "Sub-1G/Wi-Fi signal strength (verified: param 1141 = RSSI).";
84
+ };
85
+ /**
86
+ * Rejected, not clamped, outside the tone enum: a fire-and-forget write of a bogus tone would look like
87
+ * it worked. The wire is a direct-binary scalar `[ch][value][acct]` at signCode 8 — the app's own
88
+ * captured frame.
89
+ */
90
+ readonly alarmSoundType: {
91
+ readonly param: 1507;
92
+ readonly type: "enum";
93
+ readonly kind: "enum";
94
+ readonly enumValues: Record<number, string>;
95
+ readonly provenance: "verified";
96
+ readonly requires: readonly [1507];
97
+ readonly args: readonly [{
98
+ readonly name: "tone";
99
+ readonly kind: "enum";
100
+ readonly description: "Silent (0) or one of the four chimes.";
101
+ }];
102
+ readonly description: string;
103
+ readonly write: (v: string | number | boolean, ctx: import("./types.js").CommandContext) => import("../../index.js").Command | undefined;
104
+ };
105
+ /**
106
+ * `1350` SET_PAYLOAD, `mChannel` = the device channel, `mValue3` 0, payload carrying the channel and a
107
+ * transaction stamp — the byte-shape of the app's own captured frame. Out of range is refused rather
108
+ * than clamped: the app's slider has no values outside it, so one is a caller error, not a nudge.
109
+ */
110
+ readonly alarmVolume: {
111
+ readonly param: 1508;
112
+ readonly type: "number";
113
+ readonly kind: "scalar";
114
+ readonly provenance: "verified";
115
+ readonly requires: readonly [1508];
116
+ readonly min: 1;
117
+ readonly max: 26;
118
+ readonly args: readonly [{
119
+ readonly name: "level";
120
+ readonly kind: "scalar";
121
+ readonly min: 1;
122
+ readonly max: 26;
123
+ readonly description: "A device level, not a percentage.";
124
+ }];
125
+ readonly description: string;
126
+ readonly write: (v: string | number | boolean, ctx: import("./types.js").CommandContext) => import("../../index.js").Command | undefined;
127
+ };
128
+ };
129
+ /**
130
+ * `contact` — entry/door-window sensor. `contact` (1550) and `lastSeen` (1551) are verified; the
131
+ * built-in alarm tone (1507) and volume (1508) are verified writes captured live on a T90E0.
132
+ */
133
+ export declare const CONTACT: CapabilityModule;
@@ -0,0 +1,345 @@
1
+ import { type Surface } from "./members.js";
2
+ import type { CapabilityModule } from "./types.js";
3
+ /**
4
+ * The P2P **feature-command ids** this doorbell capability drives. Capability-owned wire vocabulary
5
+ * (transport forwards `cmd.param` opaquely; full id→name catalog in the generated
6
+ * `transport/p2p/commands.ts`).
7
+ */
8
+ export declare const DOORBELL_CMD: {
9
+ /**
10
+ * Doorbell "quick response" — make the doorbell PLAY a stored voice reply. Same 136-byte
11
+ * direct-binary shape as the camera setters: `value` = the `voice_id` to play. Reversed from a
12
+ * live capture (outer-cmd 1706, signCode 8, on the doorbell's `device_channel`) + the app's
13
+ * `PlayQuickResponseParser` (`{cmd:1706,voice_id}`).
14
+ */
15
+ readonly QUICK_RESPONSE: 1706;
16
+ /**
17
+ * Mechanical (wired) chime enable/disable — whether the doorbell drives an existing wired chime box
18
+ * (as opposed to / in addition to the wireless indoor chime, param 1702 `chimeSwitch` above). Same
19
+ * 136-byte direct-binary shape as `QUICK_RESPONSE`/camera on-off: `[u32 channel][u32 value][account_id
20
+ * ASCII, zero-padded to 128 bytes]`, outer P2P cmd = 1703 itself, signCode 8, on the device's own
21
+ * channel. Reversed from a live capture (outer-cmd 1703, signCode 8, captured on the doorbell's
22
+ * `device_channel` — channel 2 for that unit, NOT a wire constant, always use `ctx.channel`):
23
+ * turning ON sent `value=1`, turning OFF sent `value=0` — a plain boolean, 1=on/0=off.
24
+ * App `APP_CMD_BAT_DOORBELL_MECHANICAL_CHIME_SWITCH`.
25
+ */
26
+ readonly MECHANICAL_CHIME_SWITCH: 1703;
27
+ /**
28
+ * Wide Dynamic Range (WDR) image switch — a video/image tone-mapping setting that widens the
29
+ * exposure range in high-contrast scenes (bright sky behind a visitor, etc). SAME 136-byte
30
+ * direct-binary shape/polarity/capture session as `MECHANICAL_CHIME_SWITCH` immediately above: outer
31
+ * P2P cmd 1704, signCode 8, device channel, `value` 1=on/0=off.
32
+ * App `APP_CMD_BAT_DOORBELL_WDR_SWITCH`.
33
+ */
34
+ readonly WDR_SWITCH: 1704;
35
+ /**
36
+ * Doorbell chime ("ding-dong") volume — app `APP_CMD_BAT_DOORBELL_SET_DINGDONG_VOLUME`. UNLIKE the 1703/1704 direct-binary switches above, this rides the
37
+ * `SET_PAYLOAD` (1350) JSON envelope: `{account_id,cmd:1717,mChannel:<deviceCh>,mValue3:0,
38
+ * payload:{dingdong_volume:N}}`, GCM signCode 8, on the doorbell's `device_channel` (2 for the
39
+ * captured unit — always use `ctx.channel`, don't hardcode). `mValue3` is an EXPLICIT `0`, not the
40
+ * `SET_PAYLOAD` default of `mValue3:cmd` (see {@link module:./intent setPayload}'s doc comment) —
41
+ * both live frames captured showed `mValue3:0`. Reversed from a live capture (values 3 and 25
42
+ * observed) — a 0-100 loudness level, distinct from the already-shipped `ringtoneVolume` (1708,
43
+ * direct-binary, `audio.ts`), which is a DIFFERENT control.
44
+ */
45
+ readonly DINGDONG_VOLUME: 1717;
46
+ /**
47
+ * Doorbell chime ("ding-dong") RINGTONE SELECTION — app `APP_CMD_BAT_DOORBELL_SET_DINGDONG_RINGTONE`.
48
+ * SAME `SET_PAYLOAD` (1350) JSON envelope shape as
49
+ * `DINGDONG_VOLUME` immediately above: `{account_id,cmd:1718,mChannel:<deviceCh>,mValue3:0,
50
+ * payload:{dingdong_ringtone:N}}`, GCM signCode 8, doorbell `device_channel`, explicit `mValue3:0`.
51
+ * Reversed from a live capture (values 4 and 0 observed) — `N` is an INTEGER INDEX picking one of
52
+ * several stored chime tones, NOT a boolean.
53
+ */
54
+ readonly DINGDONG_RINGTONE: 1718;
55
+ /**
56
+ * Live-view quality AND the video encoding format, both in one integer — app
57
+ * `CMD_BAT_DOORBELL_VIDEO_QUALITY`. The value is `quality + (highCompression ? 5 : 0)`, where quality
58
+ * is 0 Auto / 1 Low / 2 Medium / 3 High ({@link DoorbellVideoQuality}). The app drives the two from
59
+ * separate menus and each write carries both, so setting either requires the other's current value —
60
+ * which is why neither is a derived setter.
61
+ *
62
+ * The encoding is reversed from writing every option in the app and reading the parameter back: High
63
+ * on high compression is 8 and on low compression 3, Low on low compression 1, Auto on high
64
+ * compression 5. Six of the eight combinations were observed that way; `0` (Auto, low compression) and
65
+ * `2` (Medium, low compression) follow the same arithmetic but were not individually written.
66
+ *
67
+ * Wire captured byte-exact from the app on a T8210 behind a HomeBase: outer P2P cmd 1705 itself — no
68
+ * wrapper — signCode 8, on the doorbell's own channel, the same 136-byte direct-binary
69
+ * `[u32 channel][u32 value][account_id ASCII pad 128]` struct as its 1703/1704 siblings. The station
70
+ * answers with an unencrypted level-1 frame carrying 0.
71
+ *
72
+ * Replayed from this SDK and confirmed on that device: three writes in one session, each read back off
73
+ * the parameter — quality alone, then the encoding format with the quality held, then a restore.
74
+ */
75
+ readonly VIDEO_QUALITY: 1705;
76
+ /**
77
+ * Doorbell quick-response LIST fetch — the sub-command carried inside a `SET_PAYLOAD` (1350)
78
+ * wrapper (app `APP_CMD_GET_CUSTOMIZE_VICOE_LIST`). The station replies with a `NOTIFY_PAYLOAD`
79
+ * (1351) frame whose JSON is `{cmd:6237, payload:{voice_list:[{voice_id,voice_name,voice_path}]}}`.
80
+ * Reversed from the app's `GetQuickResponseListP2pParser` + the capture heap. NOTE: 6238
81
+ * (`APP_CMD_GET_QUICK_RESPONSE`) is the single-file DOWNLOAD, not the list.
82
+ */
83
+ readonly GET_QUICK_RESPONSE_LIST: 6237;
84
+ };
85
+ /**
86
+ * Doorbell chime ("ding-dong") ringtone selection, as a 0-indexed list. Three indices were confirmed
87
+ * on-device (`0→Default`, `7→Ding`, `8→Hillside`) and land exactly on a plain top-to-bottom order, so
88
+ * the remaining indices follow that same linear order rather than being individually tested. Full name list
89
+ * (10 entries) read off the app's own picker UI. `Circuit` (index 5) is a BEST-EFFORT spelling — its
90
+ * index was not individually wire-tested, only its position in the read-off list.
91
+ */
92
+ export declare const DoorbellRingtone: {
93
+ readonly Default: 0;
94
+ readonly Silent: 1;
95
+ readonly Beacon: 2;
96
+ readonly Chord: 3;
97
+ readonly Christmas: 4;
98
+ readonly Circuit: 5;
99
+ readonly Clock: 6;
100
+ readonly Ding: 7;
101
+ readonly Hillside: 8;
102
+ readonly Presto: 9;
103
+ };
104
+ /** A doorbell ringtone option — the value side of {@link DoorbellRingtone}. */
105
+ export type DoorbellRingtoneValue = (typeof DoorbellRingtone)[keyof typeof DoorbellRingtone];
106
+ export declare const DoorbellVideoQuality: {
107
+ /** The doorbell picks a quality from the link. */
108
+ readonly Auto: 0;
109
+ readonly Low: 1;
110
+ readonly Medium: 2;
111
+ readonly High: 3;
112
+ };
113
+ /** A doorbell live-view quality — the value side of {@link DoorbellVideoQuality}. */
114
+ export type DoorbellVideoQualityValue = (typeof DoorbellVideoQuality)[keyof typeof DoorbellVideoQuality];
115
+ /**
116
+ * One of a Video Doorbell's **quick responses** — a canned voice reply it can play at a visitor.
117
+ * Returned by `dev.doorbell()?.quickResponses()`; pass `voiceId` to `playQuickResponse`. Owned by the
118
+ * doorbell capability (the client transport stays doorbell-agnostic — it only knows generic P2P).
119
+ */
120
+ export interface QuickResponse {
121
+ /** The response's `voice_id` — pass to `playQuickResponse` to play it. */
122
+ voiceId: number;
123
+ /** Human-readable label, e.g. "Please leave it at the door". */
124
+ name: string;
125
+ /** On-device audio path, e.g. `/system/snd//QuickReply_1.snd` or `/user/quick_respone_diy//QuickReply_5.aac`. */
126
+ path: string;
127
+ /** `false` = predefined/eufy-shipped (`/system/snd/`); `true` = user-recorded custom (`/user/…`). */
128
+ custom: boolean;
129
+ }
130
+ /**
131
+ * Bound doorbell controls — the object returned by `dev.doorbell()`. The status LED is NOT here: a
132
+ * doorbell is a `camera`-codec device, so its LED lives on the shared `dev.camera().setStatusLed()`
133
+ * surface, which swaps to the doorbell's own wire by family (one action, not a duplicate here).
134
+ * `playQuickResponse` is always present (it orchestrates a live stream); `quickResponses` (a P2P
135
+ * request/reply query that RETURNS data) is present only when the device is bound to a live client
136
+ * with a {@link MediaProvider} — hence optional, call with `?.`.
137
+ */
138
+ export type DoorbellActions = Surface<typeof DOORBELL_MEMBERS>;
139
+ /**
140
+ * Parse a doorbell `voice_list` (the `{voice_id,voice_name,voice_path}` records the station returns
141
+ * in the quick-response GET reply) into typed {@link QuickResponse}s. Pure/offline. The `custom` flag
142
+ * is derived from the `voice_path` **prefix** (robust) — predefined responses live under `/system/snd/`,
143
+ * user-recorded ones under `/user/…` — NOT from the id range (ids 1–3 predefined, 100+ custom, but the
144
+ * path is authoritative).
145
+ */
146
+ export declare function parseQuickResponses(voiceList: Array<{
147
+ voice_id?: unknown;
148
+ voice_name?: unknown;
149
+ voice_path?: unknown;
150
+ }>): QuickResponse[];
151
+ /**
152
+ * `doorbell` — chime / ringtone configuration. CONFIRMED against a real Video Doorbell (T8214):
153
+ * the live ids are the `1702-1719` `CMD_BAT_DOORBELL_*` range (provenance "mega", observed). The
154
+ * legacy `2015/2022/1306` ids are excluded — they appear on NO owned device. The button-
155
+ * press *event* (ring) is delivered out-of-band via `CMD_DOORBELL_NOTIFY_PAYLOAD` (1701) /
156
+ * push/MQTT — it is handled by the Phase-1 event normalizers, not as a device-list param.
157
+ */
158
+ /**
159
+ * Every `doorbell` feature, declared once.
160
+ *
161
+ * Three of the seven reads are read-ONLY here even though the device accepts a write, because the write
162
+ * does not belong to this capability or is not confirmed:
163
+ * - `ringtoneVolume` (1708) — the WRITE lives on `audio`, which owns every volume wire. 1708 leaks
164
+ * onto non-doorbell cameras, so `audio` gates its setter on the doorbell capability instead.
165
+ * - `chimeSwitch` (1702) — READ confirmed on a T8214, the WRITE wire never captured. Its 1703/1704
166
+ * siblings share the param range but that is NOT evidence of a shared frame, and a wrong guess on a
167
+ * fire-and-forget P2P write looks exactly like success.
168
+ * - `notificationMode` (1710) — a config JSON the device reports whole; no write is captured.
169
+ *
170
+ * Exported but NOT published: each entry states its wire id and the evidence it was confirmed on,
171
+ * which the reference site does not carry.
172
+ * @internal
173
+ */
174
+ export declare const DOORBELL_MEMBERS: {
175
+ /**
176
+ * The WIRELESS indoor chime — the separate plug-in unit, not the wired chime box
177
+ * `mechanicalChimeSwitch` drives. `unverified: true` with no `write` at all: the read is confirmed but
178
+ * the write frame has never been captured, so the setter is absent from the surface (a compile-time
179
+ * signal) and the intent path throws rather than reporting the doorbell as lacking the feature.
180
+ * Sharing the 1702-1719 range with its captured siblings is not evidence of a shared frame shape.
181
+ */
182
+ readonly chimeSwitch: {
183
+ readonly param: 1702;
184
+ readonly type: "bool";
185
+ readonly kind: "boolean";
186
+ readonly provenance: "mega";
187
+ readonly unverified: true;
188
+ readonly description: string;
189
+ };
190
+ /**
191
+ * `provenance` is "verified" not "mega": the actual write wire is confirmed (
192
+ * our own P2P decrypt), not merely the param id observed on a live device. Direct-binary
193
+ * `[ch][value][acct]`, 1=on/0=off — verified live on a T8214 (ON then OFF).
194
+ */
195
+ readonly mechanicalChimeSwitch: {
196
+ readonly param: 1703;
197
+ readonly type: "bool";
198
+ readonly kind: "boolean";
199
+ readonly provenance: "verified";
200
+ readonly description: "Mechanical chime enabled (1703; confirmed on T8214).";
201
+ readonly write: (v: string | number | boolean, ctx: import("./types.js").CommandContext) => import("../../core/contracts.js").Command;
202
+ };
203
+ /** Same reasoning and the same capture session as {@link DOORBELL_MEMBERS.mechanicalChimeSwitch}. */
204
+ readonly wdrSwitch: {
205
+ readonly param: 1704;
206
+ readonly type: "bool";
207
+ readonly kind: "boolean";
208
+ readonly provenance: "verified";
209
+ readonly description: "Wide Dynamic Range (WDR) image switch (1704; write wire-confirmed live on T8214 — see DOORBELL_CMD.WDR_SWITCH).";
210
+ readonly write: (v: string | number | boolean, ctx: import("./types.js").CommandContext) => import("../../core/contracts.js").Command;
211
+ };
212
+ /**
213
+ * The READ half of a control whose write lives on `audio` — hence `writtenElsewhere`, which is what
214
+ * keeps the published schema's `writable` true even though this member declares no `write`. The split
215
+ * is deliberate: `audio` owns every volume wire, but 1708 leaks onto non-doorbell cameras, so `audio`
216
+ * gates its setter on this capability while the read stays here where it is doorbell-only. Distinct
217
+ * from `dingdongVolume` (1717), which is a different control on a different wire.
218
+ */
219
+ readonly ringtoneVolume: {
220
+ readonly param: 1708;
221
+ readonly type: "number";
222
+ readonly unit: "%";
223
+ readonly kind: "percent";
224
+ readonly provenance: "mega";
225
+ readonly writtenElsewhere: true;
226
+ readonly description: string;
227
+ };
228
+ /**
229
+ * A `1350` SET_PAYLOAD envelope (NOT direct-binary) with an explicit `mValue3` 0 — both live frames
230
+ * captured that value. Bounded 0-100 like every sibling volume setter: the write is fire-and-forget,
231
+ * so an out-of-range value would otherwise be sent as-is and look like it worked. `provenance` is
232
+ * "verified" on our own capture, not merely an observed param id.
233
+ */
234
+ readonly dingdongVolume: {
235
+ readonly param: 1717;
236
+ readonly type: "number";
237
+ readonly unit: "%";
238
+ readonly kind: "percent";
239
+ readonly provenance: "verified";
240
+ readonly min: 0;
241
+ readonly max: 100;
242
+ readonly description: string;
243
+ readonly write: (v: string | number | boolean, ctx: import("./types.js").CommandContext) => import("../../core/contracts.js").Command;
244
+ };
245
+ /**
246
+ * The same `1350` SET_PAYLOAD shape and capture session as {@link DOORBELL_MEMBERS.dingdongVolume},
247
+ * but an INDEX rather than a level. Clamping a bad index would land on a real-but-wrong tone (garbage
248
+ * → 0, too-big → 9) instead of failing, and only 3 of the 10 indices (0, 7, 8) are wire-tested — so
249
+ * anything outside {@link DoorbellRingtone} is refused.
250
+ */
251
+ readonly dingdongRingtone: {
252
+ readonly param: 1718;
253
+ readonly type: "number";
254
+ readonly kind: "enum";
255
+ readonly enumValues: Record<number, string>;
256
+ readonly provenance: "verified";
257
+ readonly args: readonly [{
258
+ readonly name: "ringtone";
259
+ readonly kind: "enum";
260
+ readonly description: "A tone INDEX, not a volume.";
261
+ }];
262
+ readonly description: string;
263
+ readonly write: (v: string | number | boolean, ctx: import("./types.js").CommandContext) => import("../../core/contracts.js").Command | undefined;
264
+ };
265
+ /**
266
+ * The live-view quality half of {@link DOORBELL_CMD.VIDEO_QUALITY}, lifted out of the composite by
267
+ * `decode`. `writtenElsewhere` because the setter needs the OTHER half's current value to rebuild the
268
+ * integer, which a member's `write` — given only the new value and the context — cannot read.
269
+ */
270
+ readonly videoQuality: {
271
+ readonly param: 1705;
272
+ readonly type: "number";
273
+ readonly kind: "enum";
274
+ readonly enumValues: Record<number, string>;
275
+ readonly provenance: "verified";
276
+ readonly writtenElsewhere: true;
277
+ readonly decode: (raw: unknown) => number | undefined;
278
+ readonly decodedKind: "enum";
279
+ readonly decodedValues: (0 | 1 | 2 | 3)[];
280
+ readonly description: string;
281
+ };
282
+ /**
283
+ * The encoding half of the SAME integer, so it declares no param of its own and reaches into the
284
+ * owner's value — two members claiming 1705 would leave the second reading a name nothing is stored
285
+ * under, and a paramless member publishes no schema entry at all, which is what keeps that from
286
+ * happening structurally. High compression is the app's default on the captured device.
287
+ */
288
+ readonly highCompressionEncoding: {
289
+ readonly readsFrom: "videoQuality";
290
+ readonly type: "bool";
291
+ readonly kind: "boolean";
292
+ readonly provenance: "verified";
293
+ readonly decode: (raw: unknown) => boolean | undefined;
294
+ readonly description: string;
295
+ };
296
+ /**
297
+ * Set both halves of {@link DOORBELL_CMD.VIDEO_QUALITY} at once, because the wire has no way to set
298
+ * one alone: every frame carries the whole integer.
299
+ *
300
+ * Taking both is not a convenience choice. An earlier shape took one and preserved the other by
301
+ * reading it back, and it failed on hardware: the state reader is the snapshot the device was bound
302
+ * with, so a second write in the same session composed against the value from before the first and
303
+ * silently reverted it. Requiring both puts that decision where it can be made correctly — a caller
304
+ * reads {@link DOORBELL_MEMBERS.videoQuality} and {@link DOORBELL_MEMBERS.highCompressionEncoding}
305
+ * and passes what it wants, instead of the SDK guessing from a stale copy.
306
+ */
307
+ readonly setVideoQuality: import("./members.js").MethodMember<(quality: DoorbellVideoQualityValue, highCompression: boolean) => Promise<void>>;
308
+ /**
309
+ * A config blob the device reports WHOLE, so it is typed `string` and handed back unparsed — three
310
+ * settings live inside it (motion notifications, ring notifications, notification style) and the SDK
311
+ * lifts none of them out, because no `decode` is evidenced for the shape. Read-only: no write frame
312
+ * has been captured for it, and a config JSON is exactly where a guessed write does the most damage.
313
+ */
314
+ readonly notificationMode: {
315
+ readonly param: 1710;
316
+ readonly type: "string";
317
+ readonly kind: "text";
318
+ readonly provenance: "mega";
319
+ readonly description: string;
320
+ };
321
+ /**
322
+ * Play one of the doorbell's quick responses at the visitor. `voiceId` comes from
323
+ * {@link DOORBELL_MEMBERS.quickResponses}. The doorbell only plays while it has an active media
324
+ * session, so by default this briefly engages a live stream, sends, then tears it down.
325
+ * `{ engage: false }` leaves an already-open stream alone.
326
+ *
327
+ * If engagement was requested but no stream comes up this THROWS, rather than firing 1706 into the
328
+ * void and reporting success — the doorbell would play nothing. The wire is `QUICK_RESPONSE` 1706,
329
+ * the SAME direct-binary command as camera on/off, carrying the voice id as its value.
330
+ */
331
+ readonly playQuickResponse: import("./members.js").MethodMember<(voiceId: number, opts?: {
332
+ engage?: boolean;
333
+ }) => Promise<void>>;
334
+ /**
335
+ * Fetch the doorbell's quick-response list — a P2P request/reply query that returns data, so it
336
+ * exists only on a device bound to a media provider that offers one.
337
+ *
338
+ * The transport stays doorbell-agnostic: it runs a GENERIC SET_PAYLOAD query (sub-cmd → reply
339
+ * payload); this capability owns the sub-command id (6237) and the reply parsing.
340
+ */
341
+ readonly quickResponses: import("./members.js").ProvidedMember<"media", ((opts?: {
342
+ timeoutMs?: number;
343
+ }) => Promise<QuickResponse[]>) | undefined>;
344
+ };
345
+ export declare const DOORBELL: CapabilityModule;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Per-SKU DP capability catalog — the parsed result of a `get_product_data_point` API call.
3
+ *
4
+ * The response carries one entry per data point, each declaring `dp_id`, a stable `code`, a
5
+ * human `name`, an access `mode`, a `data_type` and a `property` blob. Only the enum ranges are
6
+ * read here; the names and writability that same call reports are already resolved offline into
7
+ * `CLEAN_PARAMS`, so what this adds is the per-SKU narrowing a shared dictionary cannot carry —
8
+ * two products with the same DP can offer different value sets.
9
+ *
10
+ * Still defensive at every step: a missing key or a mismatched shape yields an empty catalog and
11
+ * capabilities fall back to their safe defaults, because a wrong range is worse than none.
12
+ *
13
+ * @module model/capabilities/dp-catalog
14
+ */
15
+ /** The parsed DP capability catalog for one product SKU. */
16
+ export interface DpCatalog {
17
+ /**
18
+ * For enum-type DPs: the valid integer values as declared in the catalog.
19
+ * Absent for non-enum DPs (bool, raw, integer, string).
20
+ */
21
+ readonly enumRanges: ReadonlyMap<number, readonly number[]>;
22
+ }
23
+ /** Returned whenever the API call fails or the response shape is not recognised. */
24
+ export declare const EMPTY_DP_CATALOG: DpCatalog;
25
+ /**
26
+ * Parse a `get_product_data_point` response into a {@link DpCatalog}.
27
+ *
28
+ * `raw` is the response's `data` object, already unwrapped by the transport — so the entry array
29
+ * sits at the top level under `data_point_list`.
30
+ *
31
+ * An entry's declared type is `data_type` and its constraint blob is `property`; a range is read
32
+ * only from an enum entry, since that is the only type whose `property` states a closed set.
33
+ * `data_type` is matched case-insensitively — its casing is the server's to choose and nothing
34
+ * here should depend on it.
35
+ *
36
+ * Returns {@link EMPTY_DP_CATALOG} on any shape mismatch — never throws.
37
+ */
38
+ export declare function parseDpCatalog(raw: unknown): DpCatalog;