@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,564 @@
1
+ import { type Surface } from "./members.js";
2
+ import type { CapabilityModule, CommandContext } from "./types.js";
3
+ import { type Command, type MediaProvider } from "../../core/contracts.js";
4
+ /**
5
+ * The P2P **feature-command ids** this camera capability drives (direct-binary switches + `1350`
6
+ * SET_PAYLOAD sub-commands). These are the capability's own wire vocabulary — the transport carries
7
+ * `cmd.param` opaquely and never names them (the full 541-entry id→name catalog lives in the generated
8
+ * `transport/p2p/commands.ts`). Each entry notes its app `CommandType` name.
9
+ */
10
+ export declare const CAMERA_CMD: {
11
+ /** Camera on/off. switch is inverted: camera ON ⇒ 0, OFF ⇒ 1. */
12
+ readonly CAMERA_ENABLE: 1035;
13
+ /**
14
+ * Camera status LED on/off — the "power/recording" indicator. The
15
+ * app JS has a sibling param `1056` (`APP_CMD_LIVEVIEW_LED_SWITCH`) for the SAME UI "Status Light"
16
+ * setting on some other model/generation — confirmed real (a full parser class exists) but tested
17
+ * live with no effect on a T8425 (which uses 1045, shipped here); which model actually uses 1056
18
+ * is unconfirmed. Don't wire 1056 as an alias of this without per-model evidence.
19
+ */
20
+ readonly DEV_LED_SWITCH: 1045;
21
+ /**
22
+ * Rotate the image 180° on/off. Direct param, value 0 = normal, 1 = flipped. The app's constant is
23
+ * `INDOOR_ROTATE_IMAGE`, but it is NOT indoor-only — ✅ verified live on an OUTDOOR floodlight cam
24
+ * (T8425), so we drop the misleading "indoor". App parser: `{cmd:1207, params:{enable:0|1}}`.
25
+ */
26
+ readonly ROTATE_IMAGE: 1207;
27
+ /**
28
+ * On-screen watermark / OSD overlay (app `CMD_SET_DEVS_OSD`). ✅ Wire verified live on T8425 (ch3):
29
+ * a **3-value enum**, not a bool — 0 = off, 1 = timestamp, 2 = timestamp + logo. Direct-binary
30
+ * `[channel][value]`. (Labels/enum in {@link Watermark}.)
31
+ */
32
+ readonly SET_DEVS_OSD: 1214;
33
+ /**
34
+ * Video-doorbell status-LED on/off. Rides the `1350` SET_PAYLOAD envelope
35
+ * (`{account_id,cmd:1716,mChannel,mValue3:1716,payload:{light_enable:0|1}}`),
36
+ * signCode 8. ✅ verified live on Doorbell Dual T8214. Family-specific wire for the same semantic
37
+ * status LED setting ordinary cameras report under 1045.
38
+ */
39
+ readonly DOORBELL_LED: 1716;
40
+ /**
41
+ * Night-vision mode (app `NIGHT_VISION_TYPE`). Enum: 0 = off, 1 = infrared/auto (B&W), 2 = full colour.
42
+ * ✅ All three verified live on T8425: `1350` SET_PAYLOAD, inner cmd 1277, `payload:{channel:<deviceCh>,
43
+ * night_sion:N}`, mChannel 0, mValue3 0. Standalone (SINGLE-connect) uses direct `IC_NIGHT_VISION_TYPE`
44
+ * (1013). (Some models omit full colour; enum in {@link NightVision}.)
45
+ */
46
+ readonly NIGHT_VISION_TYPE: 1277;
47
+ /**
48
+ * Push-notification STYLE — how much a detection push carries: text alone, a thumbnail, or text
49
+ * followed by a thumbnail. App `CMD_INDOOR_PUSH_NOTIFY_TYPE`, and the "indoor" is a misnomer: the
50
+ * wire is confirmed on an OUTDOOR standalone camera (T8171). The app's id→name table carries TWO
51
+ * aliases for this id, `ENTER_OTA` and `INDOOR_PUSH_NOTIFY_TYPE`; the confirmed behaviour is the
52
+ * notification style.
53
+ *
54
+ * Wire verified live on a T8171 (standalone, own channel, reached over the cloud/WAN path): the
55
+ * `1700` CONTROL_PAYLOAD wrapper, signCode 8, plaintext
56
+ * `{"commandType":6020,"data":{"value":N,"transaction":"<epoch ms>"}}`. All three values captured
57
+ * byte-exact, each read back on the cloud param within ~10s. The station answers on the same wrapper
58
+ * ~600ms later with a 4-byte body — the command's int32 result — so this write is not
59
+ * fire-and-forget, unlike the direct-binary switches.
60
+ * (Values in {@link NotificationStyle}.)
61
+ */
62
+ readonly PUSH_NOTIFY_TYPE: 6020;
63
+ /**
64
+ * **Sound detection** switch — whether the camera triggers on what it hears, beside the motion
65
+ * trigger it triggers on what it sees.
66
+ *
67
+ * Wire observed live on an indoor pan-tilt (standalone, mains, own channel): the `1700`
68
+ * CONTROL_PAYLOAD wrapper, plaintext `{"commandType":6043,"data":{"status":0|1}}`. Both directions
69
+ * captured byte-exact and read back on the cloud param, twice each; no other parameter moved.
70
+ */
71
+ readonly SOUND_DETECTION: 6043;
72
+ /**
73
+ * How loud a sound has to be to trigger {@link CAMERA_CMD.SOUND_DETECTION} — the app's three-position
74
+ * control writes `1` lowest, `3` mid, `5` highest.
75
+ *
76
+ * Wire observed live on the same camera: `{"commandType":6044,"data":{"index":N}}` in the `1700`
77
+ * wrapper. The payload field is `index`, NOT the `value` its neighbours use — each of these
78
+ * commands names its field differently, so there is no generic setter for the family.
79
+ */
80
+ readonly SOUND_DETECTION_SENSITIVITY: 6044;
81
+ /**
82
+ * WHICH sounds trigger {@link CAMERA_CMD.SOUND_DETECTION} — all sound, or crying alone.
83
+ *
84
+ * Wire observed live: `{"commandType":6046,"data":{"type":N}}` in the `1700` wrapper, both values
85
+ * captured and read back. (Values in {@link SoundDetectionType}.)
86
+ */
87
+ readonly SOUND_DETECTION_TYPE: 6046;
88
+ /**
89
+ * **Anti-theft detection** switch (app `APP_CMD_EAS_SWITCH`). Despite the "EAS" name the app's own
90
+ * parser maps this id onto `anti_theft_detection_switch`, so the camera member uses that semantic
91
+ * name. The app's "EAS" resource strings mix emergency- and anti-theft-worded copy; the parser is
92
+ * the tiebreak.
93
+ *
94
+ * Wire from the app's own JS: a scalar `params:{value:0|1}`. Emitted with the **adaptive** form so
95
+ * topology picks the level — level-2/direct on a HomeBase-attached device, level-1 on a standalone.
96
+ *
97
+ * ⚠️ Replay + readback confirmed on a **HomeBase-attached** T8425 only (1015 read `0` → write → `1`
98
+ * → restore): the frame is confirmed accepted and persisted, NOT byte-compared to the app's. The
99
+ * **standalone** path is unverified, and newer (v3) devices use a *different* id for the same
100
+ * switch — `APP_CMD_NEW_EAS_SWITCH` (2735) — which has no path here; don't assume 1015 drives them.
101
+ */
102
+ readonly EAS_SWITCH: 1015;
103
+ /**
104
+ * RECORDING quality — what gets stored, not the live view; {@link CAMERA_CMD.STREAMING_QUALITY_SET}
105
+ * below is the live one, and the app's name for this id is `multicamSetRecordQuailty`.
106
+ * Wire confirmed on a T8425 ch3: `1350` SET_PAYLOAD, inner cmd 2731,
107
+ * `payload:{channel:0, mode:0, primary_view:0, quality:N}`, mValue3 0, on the device channel. Tiers
108
+ * 1/2/3, named in {@link RECORDING_QUALITY_TIERS} — no tier 0 on this wire, where streaming has one.
109
+ * That is a fact about 2731 on the cameras it was confirmed on, not about recording everywhere. A
110
+ * doorbell has no recording-quality setting at all, and its live-view quality rides neither 2730 nor
111
+ * 2731 but 1705, on a domain of its own (5 = Auto, 6/7/8 = Low/Medium/High, all four observed).
112
+ */
113
+ readonly RECORDING_QUALITY_SET: 2731;
114
+ /**
115
+ * LIVE-VIEW quality — a separate setting from {@link CAMERA_CMD.RECORDING_QUALITY_SET}, and the app's
116
+ * names for the two invert what they suggest: 2730 is `multicamSetVideoQuailty` and drives the
117
+ * Streaming Quality picker, while 2731 is `multicamSetRecordQuailty` and drives Recording Quality.
118
+ * Changing one leaves the other's parameter untouched, which is how they were told apart.
119
+ *
120
+ * Unlike recording it offers a tier 0, `Auto`. Wire verified live on a T8170 (standalone): the `1350`
121
+ * SET_PAYLOAD envelope, signCode 8, plaintext `{"cmd":2730,"payload":{"transaction":"<epoch ms>",
122
+ * "quality":N,"channel":0,"mode":0,"primary_view":0},"account_id":…}`. All four tiers captured
123
+ * byte-exact and read back on parameter 1020; the station echoes the same payload back as a `1351`
124
+ * NOTIFY_PAYLOAD carrying the same `transaction`.
125
+ */
126
+ readonly STREAMING_QUALITY_SET: 2730;
127
+ };
128
+ /** Whether a model-side record or bound context reports the camera-owned legacy EAS switch. */
129
+ export declare function hasReportedEasSwitch(source: {
130
+ params?: Record<number, string>;
131
+ paramIds?: ReadonlySet<number>;
132
+ }): boolean;
133
+ /**
134
+ * On-screen watermark / OSD overlay options. The value is the UI radio index. Use
135
+ * `Watermark.TimestampAndLogo` etc. with `setWatermark` / `setProperty(sn,"watermark",…)`.
136
+ */
137
+ export declare const Watermark: {
138
+ /** No timestamp or logo. */
139
+ readonly Off: 0;
140
+ /** Timestamp only. */
141
+ readonly Timestamp: 1;
142
+ /** Timestamp + eufy logo. */
143
+ readonly TimestampAndLogo: 2;
144
+ };
145
+ /** A watermark option — the value side of {@link Watermark}. */
146
+ export type WatermarkValue = (typeof Watermark)[keyof typeof Watermark];
147
+ export declare const NotificationStyle: {
148
+ /** The push carries text alone. */
149
+ readonly TextOnly: 1;
150
+ /** The push carries a thumbnail of the detection. */
151
+ readonly IncludedThumbnail: 2;
152
+ /** The push arrives as text, then updates with a thumbnail. */
153
+ readonly TextFirstThenThumbnail: 3;
154
+ };
155
+ /** A notification style — the value side of {@link NotificationStyle}. */
156
+ export type NotificationStyleValue = (typeof NotificationStyle)[keyof typeof NotificationStyle];
157
+ export declare const SoundDetectionType: {
158
+ /** Crying alone triggers a detection. */
159
+ readonly Crying: 1;
160
+ /** Any sound loud enough for the sensitivity triggers a detection. */
161
+ readonly AllSound: 2;
162
+ };
163
+ /** A sound-detection type — the value side of {@link SoundDetectionType}. */
164
+ export type SoundDetectionTypeValue = (typeof SoundDetectionType)[keyof typeof SoundDetectionType];
165
+ /**
166
+ * Night-vision mode: 0=Off, 1=Infrared (the app shows "B&W Auto"), 2=FullColor ("Color"). Use
167
+ * `NightVision.FullColor` etc. with `setNightVision` / `setProperty(sn,"nightVision",…)`. Some models
168
+ * omit `FullColor`.
169
+ */
170
+ export declare const NightVision: {
171
+ /** Off — never use infrared. */
172
+ readonly Off: 0;
173
+ /** Infrared / "B&W Auto" — black-and-white night vision. */
174
+ readonly Infrared: 1;
175
+ /** Full colour night vision (models with a spotlight / starlight sensor). */
176
+ readonly FullColor: 2;
177
+ };
178
+ /** A night-vision mode — the value side of {@link NightVision}. */
179
+ export type NightVisionValue = (typeof NightVision)[keyof typeof NightVision];
180
+ /**
181
+ * Video record-quality names. The stored value is a quality TIER; the two lower tiers are the same
182
+ * resolution on every camera confirmed so far, and the top tier is whatever the camera's sensor gives —
183
+ * 2K on a T8171, 3K on a T8170 and a T8425 — so it is named for its RANK, not for a resolution.
184
+ *
185
+ * Naming it "3K HD" would be a claim the SDK cannot ground: a camera does not report its top
186
+ * resolution (the cloud record's `product` is null and no parameter carries it), and the app's own model
187
+ * registry spells a resolution into only some older families, neither of the confirmed ones among them.
188
+ * A resolution label is presentation, and one that cannot be derived is presentation the SDK would get
189
+ * wrong; `Max` is a fact about the tier.
190
+ */
191
+ export declare const RecordingQuality: {
192
+ readonly HD720: "HD (720P)";
193
+ readonly FullHD1080: "Full HD (1080P)";
194
+ readonly Max: "Max";
195
+ };
196
+ /** A video-quality name — the value side of {@link RecordingQuality}. */
197
+ export type RecordingQualityName = (typeof RecordingQuality)[keyof typeof RecordingQuality];
198
+ /**
199
+ * Quality tier → name. Tiers confirmed on real devices: 1 = 720P, 2 = 1080P, 3 = the sensor's maximum
200
+ * (observed as 2K on a T8171 and 3K on a T8170 and a T8425, hence the rank rather than a resolution).
201
+ * The vendor names by rank itself where a resolution would not travel: a doorbell's live-view picker
202
+ * reads Auto/Low/Medium/High.
203
+ */
204
+ export declare const RECORDING_QUALITY_TIERS: Readonly<Record<number, string>>;
205
+ /**
206
+ * Live-view quality names — the recording tiers plus `Auto`, which 2730 offers and 2731 does not: the
207
+ * camera picks a tier from the link instead of being pinned to one.
208
+ */
209
+ export declare const StreamingQuality: {
210
+ readonly HD720: "HD (720P)";
211
+ readonly FullHD1080: "Full HD (1080P)";
212
+ readonly Max: "Max";
213
+ readonly Auto: "Auto";
214
+ };
215
+ /** A live-view quality name — the value side of {@link StreamingQuality}. */
216
+ export type StreamingQualityName = (typeof StreamingQuality)[keyof typeof StreamingQuality];
217
+ /**
218
+ * Live-view quality tier → name. Tier 0 is `Auto`; 1, 2 and 3 are the recording tiers, confirmed to
219
+ * carry the same names on a T8170 and a T8171.
220
+ */
221
+ export declare const STREAMING_QUALITY_TIERS: Readonly<Record<number, string>>;
222
+ /** Resolve a live-view quality tier to its name — or `undefined` if it is not a tier. */
223
+ export declare function resolveStreamingQuality(value: number): string | undefined;
224
+ /**
225
+ * Resolve a `setStreamingQuality` argument — a name ({@link StreamingQuality}) or a raw tier — to a
226
+ * valid tier, else `undefined`. `Auto` is tier 0 here, so unlike the recording resolver a 0 is
227
+ * accepted; anything outside the tier set is still refused rather than sent.
228
+ */
229
+ export declare function resolveStreamingQualityTier(value: number | string | boolean): number | undefined;
230
+ /** Resolve a raw `quality` tier value to its resolution label — or `undefined`. */
231
+ export declare function resolveRecordingQuality(value: number): string | undefined;
232
+ /** Inverse: the raw `quality` tier value for a resolution NAME — or `undefined` if not a known tier. */
233
+ export declare function resolveRecordingQualityValue(name: string): number | undefined;
234
+ /**
235
+ * Resolve a `setRecordingQuality` argument — a resolution NAME ({@link RecordingQuality}) OR a raw tier — to a
236
+ * valid tier value, else `undefined`. Unlike a bare `Number()`, this rejects a value that isn't a real
237
+ * tier (0, negative, out of range): the write is fire-and-forget, so an out-of-range quality value
238
+ * would look like it worked while doing nothing. A numeric string ("2") is a raw tier; a non-numeric
239
+ * string is looked up as a resolution name; a boolean is not a tier.
240
+ */
241
+ export declare function resolveRecordingQualityTier(value: number | string | boolean): number | undefined;
242
+ /**
243
+ * Bound camera controls — the object returned by `dev.camera()`.
244
+ *
245
+ * The reads, their setters and the media methods are all DERIVED from `CAMERA_MEMBERS`: one
246
+ * declaration per feature gives the getter, the setter, its argument type and its description, and a
247
+ * media method takes its signature from {@link MediaProvider} itself. The media half lands optional
248
+ * because it exists only on a device bound to a provider. Only the no-argument power verbs — which
249
+ * carry no value, so no member can hold them — are written out below.
250
+ */
251
+ export type CameraActions = Surface<typeof CAMERA_MEMBERS> & {
252
+ /** Power the camera on. */
253
+ on(): Promise<void>;
254
+ /** Power the camera off. */
255
+ off(): Promise<void>;
256
+ };
257
+ /**
258
+ * Every `camera` feature, declared once. The property schema, the typed getters, the derived setters,
259
+ * the intent routes, the media methods and the descriptions all come out of this table.
260
+ *
261
+ * The enum members publish no option set of their own beyond `enumValues` — a second copy of a set
262
+ * could only drift from it — and each refusal message is generated from that same set.
263
+ *
264
+ * No `reboot`: it is a STATION operation with an unproven wire, shipped as the device-level
265
+ * `EufyMega.reboot(sn)` (wire-confirmed station-scalar RESTART_HUB) rather than guessed at here.
266
+ *
267
+ * Exported but NOT published: each entry states its wire id and the evidence it was confirmed on,
268
+ * which the reference site does not carry.
269
+ * @internal
270
+ */
271
+ export declare const CAMERA_MEMBERS: {
272
+ /**
273
+ * The READ is the *disable*-bit convention (1035 "0" ⇒ ON, 2001 direct); the WRITE polarity is
274
+ * family-dependent — see `powerValue` / `isEnableBitPolarity`. Battery/solo cams report the state under
275
+ * 1035, standalone indoor/outdoor cams under 2001 OPEN_DEVICE with direct polarity, so 2001 is a
276
+ * read-alias. Both verified live, and the write polarity is confirmed against the app's own frames.
277
+ *
278
+ * The read and the setter observe the SAME wire on every family — see `powerCommand` — which is what
279
+ * makes this value track what it is told, and what lets `enablementReflection` confirm a write.
280
+ *
281
+ * The privacy param (6250) is reported by the outdoor-PT family and by no other camera measured, and both
282
+ * of its polarities are observed. It is deliberately NOT aliased here: it moved in the same step as 1035, so
283
+ * the reading cannot say whether power and privacy are one state or two, and the app drives 1035 — so
284
+ * aliasing a second param could only fold two possible states into one getter for no gain.
285
+ */
286
+ readonly enabled: {
287
+ readonly param: 1035;
288
+ readonly type: "bool";
289
+ readonly kind: "boolean";
290
+ readonly provenance: "verified";
291
+ readonly invert: true;
292
+ readonly readAliases: readonly [{
293
+ readonly paramType: 2001;
294
+ readonly invert: false;
295
+ }];
296
+ readonly description: string;
297
+ readonly observation: {
298
+ readonly event: "cameraEnabledChanged";
299
+ readonly reflects: (value: string | number | boolean, ctx: CommandContext) => {
300
+ param: number;
301
+ expected: boolean | number;
302
+ observed: boolean;
303
+ } | undefined;
304
+ readonly timeoutMs: 20000;
305
+ };
306
+ readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
307
+ readonly aliases: {
308
+ readonly on: true;
309
+ readonly off: false;
310
+ };
311
+ };
312
+ /**
313
+ * A 180° rotation for a ceiling or upside-down mount, not a mirror — the app's own constant calls it
314
+ * `INDOOR_ROTATE_IMAGE` but it is not indoor-only. `apk` provenance: the wire is read out of the app
315
+ * parser and the write has not been driven on hardware, so treat a silent no-op as possible and
316
+ * confirm by re-reading rather than by trusting the dispatch.
317
+ */
318
+ readonly imageFlipped: {
319
+ readonly param: 1207;
320
+ readonly type: "bool";
321
+ readonly kind: "boolean";
322
+ readonly provenance: "apk";
323
+ readonly description: string;
324
+ readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
325
+ };
326
+ /**
327
+ * A THREE-VALUE enum, not the boolean the name suggests — the middle option is timestamp without the
328
+ * logo, so a plain switch cannot express every state the device has. `coerceEnumValue` refuses
329
+ * anything outside {@link Watermark} instead of coercing it: on a fire-and-forget write a bogus index
330
+ * would dispatch and look like it worked. The labels are the app's radio order.
331
+ */
332
+ readonly watermark: {
333
+ readonly param: 1214;
334
+ readonly type: "enum";
335
+ readonly kind: "enum";
336
+ readonly enumValues: {
337
+ readonly 0: "Off";
338
+ readonly 1: "Timestamp";
339
+ readonly 2: "Timestamp + Logo";
340
+ };
341
+ readonly provenance: "verified";
342
+ readonly description: string;
343
+ readonly write: (v: string | number | boolean, ctx: CommandContext) => Command | undefined;
344
+ };
345
+ /**
346
+ * Whether the camera triggers on what it HEARS — the sound counterpart to motion detection, which the
347
+ * app presents beside it. The camera keeps the sensitivity and the type it was last given, so
348
+ * switching this off and on again restores the previous configuration rather than resetting it.
349
+ */
350
+ readonly soundDetection: {
351
+ readonly param: 6043;
352
+ readonly type: "bool";
353
+ readonly kind: "boolean";
354
+ readonly provenance: "verified";
355
+ readonly description: string;
356
+ readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
357
+ };
358
+ /**
359
+ * How loud a sound must be to trigger: `1` lowest, `3` mid, `5` highest, on the app's own
360
+ * three-position control. A `scalar` rather than an enum — the endpoints and the midpoint are
361
+ * observed, so 2 and 4 are a prediction of the scale's shape rather than values the wire is known to
362
+ * take. Independent of {@link CAMERA_MEMBERS.soundDetection}: the camera stores it whether sound
363
+ * detection is on or off.
364
+ */
365
+ readonly soundDetectionSensitivity: {
366
+ readonly param: 6044;
367
+ readonly type: "number";
368
+ readonly kind: "scalar";
369
+ readonly provenance: "verified";
370
+ readonly description: string;
371
+ readonly write: (v: string | number | boolean, ctx: CommandContext) => Command | undefined;
372
+ };
373
+ /**
374
+ * WHICH sounds count — any sound, or crying alone. `coerceEnumValue` refuses anything outside
375
+ * {@link SoundDetectionType} rather than coercing it: both neighbouring values are real types, so a
376
+ * coerced one arms the wrong trigger and reports success.
377
+ */
378
+ readonly soundDetectionType: {
379
+ readonly param: 6046;
380
+ readonly type: "enum";
381
+ readonly kind: "enum";
382
+ readonly enumValues: {
383
+ readonly 1: "Crying";
384
+ readonly 2: "All Sound";
385
+ };
386
+ readonly provenance: "verified";
387
+ readonly description: string;
388
+ readonly write: (v: string | number | boolean, ctx: CommandContext) => Command | undefined;
389
+ };
390
+ /**
391
+ * `coerceEnumValue` refuses anything outside {@link NotificationStyle} instead of coercing it: every
392
+ * neighbouring value is itself a real style, so a coerced one selects the wrong notification and
393
+ * reports success.
394
+ *
395
+ * `transaction` is part of the verified frame — a decimal epoch-in-milliseconds string, fresh per
396
+ * command.
397
+ */
398
+ readonly notificationStyle: {
399
+ readonly param: 6020;
400
+ readonly type: "enum";
401
+ readonly kind: "enum";
402
+ readonly enumValues: {
403
+ readonly 1: "Text Only";
404
+ readonly 2: "Included Thumbnail";
405
+ readonly 3: "Text First, Then Thumbnail";
406
+ };
407
+ readonly provenance: "verified";
408
+ readonly description: string;
409
+ readonly write: (v: string | number | boolean, ctx: CommandContext) => Command | undefined;
410
+ };
411
+ /**
412
+ * Three modes, and `FullColor` is the conditional one: a model without a spotlight or starlight
413
+ * sensor omits it, and the wire accepts the value regardless — the device's own reported set is the
414
+ * only statement of which of the three it has. `coerceEnumValue` rejects a value outside
415
+ * {@link NightVision} rather than coercing it. The payload key on the wire is `night_sion`.
416
+ */
417
+ readonly nightVision: {
418
+ readonly param: 1277;
419
+ readonly type: "enum";
420
+ readonly kind: "enum";
421
+ readonly enumValues: {
422
+ readonly 0: "Off";
423
+ readonly 1: "Infrared";
424
+ readonly 2: "Full Color";
425
+ };
426
+ readonly provenance: "verified";
427
+ readonly description: string;
428
+ readonly write: (v: string | number | boolean, ctx: CommandContext) => Command | undefined;
429
+ };
430
+ /**
431
+ * Live-view quality, the pair to {@link CAMERA_MEMBERS.recordingQuality} and a different setting on a
432
+ * different wire: changing one leaves the other's parameter untouched.
433
+ *
434
+ * The READ is 1020, which reports the resolved tier as a plain integer. 1020 is also the name the
435
+ * param dictionary already gives that id, and `Device` keys state by NAME — a member claiming 2730
436
+ * under this name would collide with it on a device reporting both.
437
+ *
438
+ * `unverified: true` with no `write`: the app's 2730 frame is captured byte-exact, but replaying it
439
+ * from this SDK produced no observable change on a standalone T8171, where the recording sibling's
440
+ * 2731 write on the same envelope and the same session does land. The one difference the capture
441
+ * shows is that the app's frame carries no `mChannel`/`mValue3`, which this envelope always emits.
442
+ * Until a send is confirmed, the setter is absent — a control that silently does nothing is worse
443
+ * than none — and the read ships ahead of it, which verification per direction allows.
444
+ */
445
+ readonly streamingQuality: {
446
+ readonly param: 1020;
447
+ readonly type: "number";
448
+ readonly kind: "enum";
449
+ readonly enumValues: Readonly<Record<number, string>>;
450
+ readonly provenance: "verified";
451
+ readonly unverified: true;
452
+ readonly description: string;
453
+ };
454
+ /**
455
+ * `type` is how the value is STORED, and 2731 stores the whole config — the ACTIVE tier is lifted out
456
+ * of it by `decode`, so the getter answers a tier while the schema stays honest. The setter
457
+ * takes a resolution NAME as well as the tier the getter answers.
458
+ */
459
+ readonly recordingQuality: {
460
+ readonly accepts: RecordingQualityName;
461
+ readonly param: 2731;
462
+ readonly type: "string";
463
+ readonly provenance: "verified";
464
+ readonly decode: (raw: unknown) => number | undefined;
465
+ readonly decodedKind: "enum";
466
+ readonly decodedValues: number[];
467
+ readonly enumValues: Readonly<Record<number, string>>;
468
+ readonly description: string;
469
+ readonly args: readonly [{
470
+ readonly name: "quality";
471
+ readonly kind: "enum";
472
+ readonly description: "A tier; the resolution name it maps to is accepted too.";
473
+ }];
474
+ readonly write: (v: string | number | boolean, ctx: CommandContext) => Command | undefined;
475
+ };
476
+ /**
477
+ * Not every model has the feature, and one without it accepts the frame without acting on it — so the
478
+ * write is offered only where the device reports 1015, the same param the read is gated on.
479
+ */
480
+ readonly antiTheftDetection: {
481
+ readonly param: 1015;
482
+ readonly type: "bool";
483
+ readonly kind: "boolean";
484
+ readonly provenance: "apk";
485
+ readonly description: string;
486
+ readonly requires: readonly [1015];
487
+ readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
488
+ };
489
+ /**
490
+ * Privacy mode — the multi-frame burst. Nothing reports it back, so it is a setter with no getter, and
491
+ * it declares no param: the id the burst is built from is the transport's, not this capability's.
492
+ *
493
+ * Being write-only, it is named by `unobservableMembers(dev.camera())`, which distinguishes "this camera
494
+ * is not in privacy mode" from "this camera cannot say" rather than leaving both as `undefined`. That
495
+ * distinction matters most on the families whose power rides this same envelope — see {@link enabled}.
496
+ */
497
+ readonly privacy: {
498
+ readonly type: "bool";
499
+ readonly kind: "boolean";
500
+ readonly writeOnly: true;
501
+ readonly provenance: "verified";
502
+ readonly description: "Privacy mode (PRIVACY_MODE 6250) — the multi-frame burst the sink plays.";
503
+ readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
504
+ };
505
+ /**
506
+ * The same status LED is reported under 1045 on ordinary cameras and 1716 on video doorbells. The
507
+ * alias is the same semantic value on a family-specific wire. The parameter valid for the resolved
508
+ * family is sufficient evidence to install both the getter and family-aware setter.
509
+ */
510
+ readonly statusLed: {
511
+ readonly param: 1045;
512
+ readonly type: "bool";
513
+ readonly kind: "boolean";
514
+ readonly provenance: "verified";
515
+ readonly readAvailable: (ctx: import("./types.js").AvailabilityContext) => boolean;
516
+ readonly readAliases: readonly [{
517
+ readonly paramType: 1716;
518
+ readonly available: (ctx: import("./types.js").AvailabilityContext) => boolean;
519
+ }];
520
+ readonly requiresRead: true;
521
+ readonly description: "Camera status LED. Video doorbells report the same state under their button-ring LED parameter.";
522
+ readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
523
+ };
524
+ /**
525
+ * Media is not a property: it returns DATA rather than moving state, its options are richer than a
526
+ * value, and it exists only on a device bound to a provider. Each is declared once, with its
527
+ * signature taken FROM {@link MediaProvider} — so a change there is a compile error here, not a drift.
528
+ *
529
+ * Every pull is refused where {@link CAMERA_MEMBERS.enabled} reads false, with {@link CameraDisabledError} —
530
+ * `live`, `snapshotLive`, `record`, `openReadable` and `recordFragments` alike, since each opens media on a
531
+ * camera that serves none. That reading is the on/off source; a live probe is not one, since a disabled
532
+ * camera answers a start with audio and never a video frame.
533
+ *
534
+ * {@link CAMERA_MEMBERS.snapshotStored} is exempt — a retained push thumbnail is not a pull. A reading of
535
+ * `undefined` refuses nothing: families reporting neither wire param leave the state unknown, and unknown is
536
+ * not known-off.
537
+ *
538
+ * The refusal REJECTS on the four that answer with a promise, and THROWS on
539
+ * {@link CAMERA_MEMBERS.recordFragments}, which answers with a handle.
540
+ */
541
+ readonly snapshotStored: import("./members.js").ProvidedMember<"media", (() => Promise<Buffer<ArrayBufferLike>>) | undefined>;
542
+ readonly snapshotLive: import("./members.js").ProvidedMember<"media", (opts?: Parameters<MediaProvider["snapshotLive"]>[0]) => Promise<{
543
+ jpeg: Buffer;
544
+ width: number;
545
+ height: number;
546
+ retained?: true;
547
+ }>>;
548
+ readonly live: import("./members.js").ProvidedMember<"media", (opts?: Parameters<MediaProvider["live"]>[0]) => Promise<import("../../core/contracts.js").LiveStreamConsumer>>;
549
+ readonly record: import("./members.js").ProvidedMember<"media", (seconds: number, opts?: {
550
+ timeoutMs?: number;
551
+ skipKeyframes?: number;
552
+ } | undefined) => Promise<Buffer<ArrayBufferLike>>>;
553
+ readonly openReadable: import("./members.js").ProvidedMember<"media", ((opts?: Parameters<NonNullable<MediaProvider["openReadable"]>>[0]) => Promise<import("node:stream").Readable>) | undefined>;
554
+ readonly recordFragments: import("./members.js").ProvidedMember<"media", ((opts?: Parameters<NonNullable<MediaProvider["recordFragments"]>>[0]) => import("../../core/contracts.js").FragmentRecordingHandle) | undefined>;
555
+ /**
556
+ * Push audio from the host to this camera's speaker. Gated on the **speaker** param specifically —
557
+ * not the `audio` capability, which resolves on a microphone alone and would advertise a speaker the
558
+ * device never reported. Talkback holds a media session open for its duration, so it carries the same
559
+ * power hint `live` does; without it a battery camera talked to with no stream running would stream
560
+ * unbounded.
561
+ */
562
+ readonly talkback: import("./members.js").ProvidedMember<"media", false | ((opts?: Parameters<NonNullable<MediaProvider["talkback"]>>[0]) => Promise<import("../../core/contracts.js").TalkbackHandle>) | undefined>;
563
+ };
564
+ export declare const CAMERA: CapabilityModule;
@@ -0,0 +1,40 @@
1
+ import { type Surface } from "./members.js";
2
+ import type { CapabilityModule } from "./types.js";
3
+ /**
4
+ * Every `co` feature, declared once — the property schema and the evidence-gated getters derive from here.
5
+ *
6
+ * Exported but NOT published: each entry states its wire id and the evidence it was confirmed on,
7
+ * which the reference site does not carry.
8
+ * @internal
9
+ */
10
+ export declare const CO_MEMBERS: {
11
+ /**
12
+ * The alarm flag itself — and the reason this capability is detected by model name rather than by a
13
+ * reported param. 1562 is a `guessed` placeholder: nothing captured from a CO detector confirms the id
14
+ * or which value means alarming, so the evidence gate installs this getter only on a device that
15
+ * happens to report 1562. Promote it once a capture pins the id, not before.
16
+ */
17
+ readonly coDetected: {
18
+ readonly param: 1562;
19
+ readonly type: "bool";
20
+ readonly kind: "boolean";
21
+ readonly provenance: "guessed";
22
+ readonly description: "Carbon-monoxide detected. UNVERIFIED: placeholder id pending capture verification.";
23
+ };
24
+ /**
25
+ * Unix seconds at which the detector last checked in — param 1551, the same last-seen id the other
26
+ * sensor capabilities read. A `timestamp` kind takes no `unit`: the number is an instant, not a
27
+ * duration, and declaring `unit: "s"` beside it fails the value-kind spec.
28
+ */
29
+ readonly lastSeen: {
30
+ readonly param: 1551;
31
+ readonly type: "number";
32
+ readonly kind: "timestamp";
33
+ readonly provenance: "verified";
34
+ readonly description: "Last-seen unix timestamp, seconds (verified: param 1551).";
35
+ };
36
+ };
37
+ /** Bound CO-detector reads — the object returned by `dev.co()`. Read-only. */
38
+ export type CoActions = Surface<typeof CO_MEMBERS>;
39
+ /** `co` — carbon-monoxide detector. Alarm flag is a placeholder pending verification. */
40
+ export declare const CO: CapabilityModule;