@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.
- package/README.md +31 -12
- package/dist/client/device-registry.d.ts +343 -0
- package/dist/client/eufy-mega.d.ts +872 -0
- package/dist/client/index.d.ts +1 -6
- package/dist/client/map-channels.d.ts +22 -0
- package/dist/client/types.d.ts +383 -0
- package/dist/core/contracts.d.ts +898 -0
- package/dist/core/crypto.d.ts +98 -0
- package/dist/core/index.d.ts +9 -7
- package/dist/core/logger.d.ts +53 -0
- package/dist/core/lz4-block.d.ts +35 -0
- package/dist/core/raw-dp-hex.d.ts +32 -0
- package/dist/core/raw-dp-writer.d.ts +83 -0
- package/dist/core/store.d.ts +43 -0
- package/dist/core/types.d.ts +169 -0
- package/dist/core/util.d.ts +78 -0
- package/dist/index.d.ts +4 -7
- package/dist/index.js +25526 -14
- package/dist/index.js.map +7 -1
- package/dist/model/capabilities/access.d.ts +127 -0
- package/dist/model/capabilities/arming.d.ts +201 -0
- package/dist/model/capabilities/audio.d.ts +154 -0
- package/dist/model/capabilities/battery.d.ts +363 -0
- package/dist/model/capabilities/camera.d.ts +564 -0
- package/dist/model/capabilities/co.d.ts +40 -0
- package/dist/model/capabilities/contact.d.ts +133 -0
- package/dist/model/capabilities/doorbell.d.ts +345 -0
- package/dist/model/capabilities/dp-catalog.d.ts +38 -0
- package/dist/model/capabilities/index.d.ts +561 -0
- package/dist/model/capabilities/info.d.ts +28 -0
- package/dist/model/capabilities/keypad.d.ts +61 -0
- package/dist/model/capabilities/leak.d.ts +43 -0
- package/dist/model/capabilities/light.d.ts +174 -0
- package/dist/model/capabilities/locate.d.ts +63 -0
- package/dist/model/capabilities/lock.d.ts +242 -0
- package/dist/model/capabilities/manifest.d.ts +107 -0
- package/dist/model/capabilities/members.d.ts +647 -0
- package/dist/model/capabilities/motion.d.ts +377 -0
- package/dist/model/capabilities/person-detection.d.ts +8 -0
- package/dist/model/capabilities/ptz.d.ts +289 -0
- package/dist/model/capabilities/rtsp.d.ts +221 -0
- package/dist/model/capabilities/siren.d.ts +218 -0
- package/dist/model/capabilities/smart-light.d.ts +172 -0
- package/dist/model/capabilities/smoke.d.ts +40 -0
- package/dist/model/capabilities/snapshot.d.ts +6 -0
- package/dist/model/capabilities/storage.d.ts +11 -0
- package/dist/model/capabilities/suction.d.ts +104 -0
- package/dist/model/capabilities/types.d.ts +484 -0
- package/dist/model/capabilities/vacuum-clean.d.ts +1946 -0
- package/dist/model/capabilities/vacuum-dock.d.ts +208 -0
- package/dist/model/capabilities/video.d.ts +6 -0
- package/dist/model/classify.d.ts +78 -0
- package/dist/model/clean-record-detail.d.ts +65 -0
- package/dist/model/clean-records.d.ts +69 -0
- package/dist/model/device-family.d.ts +73 -0
- package/dist/model/device-types.d.ts +123 -0
- package/dist/model/device.d.ts +265 -0
- package/dist/model/index.d.ts +29 -4
- package/dist/model/infer.d.ts +23 -0
- package/dist/model/inspect.d.ts +61 -0
- package/dist/model/life-params.d.ts +21 -0
- package/dist/model/map-pixels.d.ts +70 -0
- package/dist/model/param-dictionary.d.ts +28 -0
- package/dist/model/param-namespace.d.ts +21 -0
- package/dist/model/proto-read.d.ts +53 -0
- package/dist/model/push-events.d.ts +147 -0
- package/dist/model/registry.d.ts +54 -0
- package/dist/model/types.d.ts +301 -0
- package/dist/model/vacuum-map-store.d.ts +92 -0
- package/dist/model/vacuum-map.d.ts +286 -0
- package/dist/model/vacuum-scenes.d.ts +76 -0
- package/dist/model/vacuum-schedules.d.ts +85 -0
- package/dist/transport/dp-preset.d.ts +102 -0
- package/dist/transport/ff09.d.ts +444 -0
- package/dist/transport/ffmpeg.d.ts +86 -0
- package/dist/transport/http/decodeImageV1.d.ts +20 -0
- package/dist/transport/http/decodeImageV2.d.ts +19 -0
- package/dist/transport/http/index.d.ts +5 -0
- package/dist/transport/http/light-catalog.d.ts +62 -0
- package/dist/transport/http/media-download.d.ts +14 -0
- package/dist/transport/http/mega-client.d.ts +514 -0
- package/dist/transport/http/phone-model.d.ts +21 -0
- package/dist/transport/index.d.ts +10 -7
- package/dist/transport/mqtt/app-client-id.d.ts +16 -0
- package/dist/transport/mqtt/availability.d.ts +14 -0
- package/dist/transport/mqtt/bare-ip-tls.d.ts +46 -0
- package/dist/transport/mqtt/biz-stream.d.ts +98 -0
- package/dist/transport/mqtt/broker-discovery.d.ts +55 -0
- package/dist/transport/mqtt/clean-codec.d.ts +14 -0
- package/dist/transport/mqtt/command-router.d.ts +285 -0
- package/dist/transport/mqtt/dp-codec.d.ts +58 -0
- package/dist/transport/mqtt/dp-color.d.ts +14 -0
- package/dist/transport/mqtt/engine.d.ts +16 -0
- package/dist/transport/mqtt/index.d.ts +5 -0
- package/dist/transport/mqtt/secure-mqtt.d.ts +107 -0
- package/dist/transport/mqtt/topics.d.ts +80 -0
- package/dist/transport/p2p/adts.d.ts +91 -0
- package/dist/transport/p2p/annexb.d.ts +124 -0
- package/dist/transport/p2p/codec.d.ts +166 -0
- package/dist/transport/p2p/command-router.d.ts +655 -0
- package/dist/transport/p2p/commands.d.ts +550 -0
- package/dist/transport/p2p/envelope.d.ts +46 -0
- package/dist/transport/p2p/fmp4.d.ts +89 -0
- package/dist/transport/p2p/fragment-recording.d.ts +33 -0
- package/dist/transport/p2p/index.d.ts +13 -0
- package/dist/transport/p2p/lan-ip.d.ts +25 -0
- package/dist/transport/p2p/live-stream.d.ts +223 -0
- package/dist/transport/p2p/live-trace.d.ts +123 -0
- package/dist/transport/p2p/media.d.ts +105 -0
- package/dist/transport/p2p/p2p-session.d.ts +620 -0
- package/dist/transport/p2p/readable-egress.d.ts +27 -0
- package/dist/transport/p2p/session-manager.d.ts +154 -0
- package/dist/transport/p2p/shared-live-source.d.ts +431 -0
- package/dist/transport/p2p/talkback.d.ts +187 -0
- package/dist/transport/p2p/video.d.ts +150 -0
- package/dist/transport/p2p/write-commands.d.ts +21 -0
- package/dist/transport/protobuf.d.ts +5 -0
- package/dist/transport/push/fcm.d.ts +23 -0
- package/dist/transport/push/index.d.ts +6 -0
- package/dist/transport/push/message-tags.d.ts +26 -0
- package/dist/transport/push/parser.d.ts +27 -0
- package/dist/transport/push/proto.d.ts +11 -0
- package/dist/transport/push/push-client.d.ts +64 -0
- package/dist/transport/push/store.d.ts +23 -0
- package/dist/transport/push/types.d.ts +180 -0
- package/dist/transport/raw-dp.d.ts +6 -0
- package/dist/transport/stored-image-cache.d.ts +23 -0
- package/dist/transport/tuya/account.d.ts +44 -0
- package/dist/transport/tuya/client.d.ts +89 -0
- package/dist/transport/tuya/command-router.d.ts +79 -0
- package/dist/transport/tuya/dp-codec.d.ts +56 -0
- package/dist/transport/tuya/index.d.ts +28 -0
- package/dist/transport/tuya/request.d.ts +157 -0
- package/dist/transport/tuya/sign.d.ts +64 -0
- package/package.json +12 -13
- package/dist/client/index.js +0 -2
- package/dist/client/index.js.map +0 -1
- package/dist/core/index.js +0 -2
- package/dist/core/index.js.map +0 -1
- package/dist/model/index.js +0 -2
- package/dist/model/index.js.map +0 -1
- package/dist/transport/index.js +0 -2
- package/dist/transport/index.js.map +0 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type Surface } from "./members.js";
|
|
2
|
+
import type { CapabilityModule } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Every `leak` 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 LEAK_MEMBERS: {
|
|
11
|
+
/**
|
|
12
|
+
* The alarm flag, modelled as state even though the sensor announces a leak as a PUSH EVENT rather
|
|
13
|
+
* than by holding a param — so 1560 is a `guessed` placeholder and the evidence gate will normally
|
|
14
|
+
* leave this getter uninstalled. The push event is the reliable channel for a leak; this read is
|
|
15
|
+
* here so the flag has a home once a capture pins a real id.
|
|
16
|
+
*/
|
|
17
|
+
readonly leakDetected: {
|
|
18
|
+
readonly param: 1560;
|
|
19
|
+
readonly type: "bool";
|
|
20
|
+
readonly kind: "boolean";
|
|
21
|
+
readonly provenance: "guessed";
|
|
22
|
+
readonly description: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Unix seconds at which the sensor 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 leak-sensor reads — the object returned by `dev.leak()`. Read-only. */
|
|
38
|
+
export type LeakActions = Surface<typeof LEAK_MEMBERS>;
|
|
39
|
+
/**
|
|
40
|
+
* `leak` — water/leak (and freeze) sensor. Alarm flag is a placeholder — the T8920 Water & Freeze
|
|
41
|
+
* sensor reports leak via a push event, not a stable param id.
|
|
42
|
+
*/
|
|
43
|
+
export declare const LEAK: CapabilityModule;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import type { CapabilityModule, CommandContext } from "./types.js";
|
|
2
|
+
import { type Surface } from "./members.js";
|
|
3
|
+
import type { Command } from "../../core/contracts.js";
|
|
4
|
+
/**
|
|
5
|
+
* The P2P **feature-command ids** this light capability drives. Capability-owned wire vocabulary —
|
|
6
|
+
* the transport forwards `cmd.param` opaquely and never names them (full id→name catalog in the
|
|
7
|
+
* generated `transport/p2p/commands.ts`).
|
|
8
|
+
*/
|
|
9
|
+
export declare const LIGHT_CMD: {
|
|
10
|
+
/** Spotlight momentary on/off; `{time,type,value}` under 1700. ✅ Verified via P2P state readback (3/3). */
|
|
11
|
+
readonly FLOODLIGHT_SWITCH: 1400;
|
|
12
|
+
/**
|
|
13
|
+
* Spotlight brightness 1..100. ✅ SOLVED & verified live (T8425 + T8124): direct-binary command,
|
|
14
|
+
* 136-byte struct `[u32 ch][u32 value][account_id pad→128]` (value = raw 1..100), NOT a JSON wrapper.
|
|
15
|
+
*/
|
|
16
|
+
readonly SPOTLIGHT_BRIGHTNESS: 1401;
|
|
17
|
+
/** Spotlight master enable — distinct from the on/off switch. ✅ Verified live T8124 (same 136-byte direct-binary struct as brightness). */
|
|
18
|
+
readonly SPOTLIGHT_ENABLE: 1403;
|
|
19
|
+
/** Spotlight color temperature 0=warm..100=cool. ✅ Verified live T8124 (only tunable-white spotlights respond; T8425 is white-only). */
|
|
20
|
+
readonly SPOTLIGHT_COLOR_TEMP: 1410;
|
|
21
|
+
/**
|
|
22
|
+
* Auto-spotlight = "motion-activated light" — light up when motion fires. ✅ Wire reversed from a live
|
|
23
|
+
* OUTBOUND P2P capture + replay-verified on T8425 (ch3, 2026-07-13, ON+OFF): the real command
|
|
24
|
+
* is **cmd 1422**, carried in a `1350` SET_PAYLOAD envelope on the DEVICE channel (mChannel = device
|
|
25
|
+
* channel, mValue3 0), with a COMPOSITE payload — NOT a bare bool:
|
|
26
|
+
* `{brightness:0..100, enable:0|1, latitude:"", longtitude:"" (sic), mode:1, schedule:[], sunset2rise:0, time}`
|
|
27
|
+
* `enable` is the on/off; `time` = auto-off seconds; `mode`/`schedule`/`sunset2rise` are the scheduling
|
|
28
|
+
* knobs. See {@link AutoSpotlightOptions}.
|
|
29
|
+
* NB: the app-JS constant `APP_CMD_SET_LIGHT_CTRL_PIR_SWITCH` (1408) is a RED HERRING for this device —
|
|
30
|
+
* the T8425 never emits 1408; three 1408 wire attempts all no-op'd. (No `1408` constant is defined — it's
|
|
31
|
+
* dead; do not add one.)
|
|
32
|
+
*/
|
|
33
|
+
readonly MOTION_ACTIVATE_LIGHT: 1422;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Tunables for the "motion-activated light" (auto-spotlight): the spotlight lights up when the camera
|
|
37
|
+
* detects motion. The device takes the WHOLE config on every write — there's no isolated on/off — so
|
|
38
|
+
* these carry the scheduling knobs alongside the enable flag. Defaults mirror the app's; the current
|
|
39
|
+
* values can't be read back, so any field left unset is written as its default rather than preserved.
|
|
40
|
+
*/
|
|
41
|
+
export type AutoSpotlightOptions = {
|
|
42
|
+
/** Spotlight brightness 1..100 when it triggers (default 50). */
|
|
43
|
+
brightness?: number;
|
|
44
|
+
/** Auto-off timer in seconds after the light triggers (default 30). */
|
|
45
|
+
time?: number;
|
|
46
|
+
/** Scheduling mode (default 1). */
|
|
47
|
+
mode?: number;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Bound spotlight / floodlight controls — the object returned by `dev.light()`.
|
|
51
|
+
*
|
|
52
|
+
* The reads and their setters are DERIVED from `LIGHT_MEMBERS`: one declaration per feature gives
|
|
53
|
+
* the getter, the setter, its argument type and its description. Only what a member table cannot state
|
|
54
|
+
* is written out below.
|
|
55
|
+
*/
|
|
56
|
+
export type LightActions = Surface<typeof LIGHT_MEMBERS> & {
|
|
57
|
+
/** Turn the light on. Throws if this model's switch wire is unverified. */
|
|
58
|
+
on(): Promise<void>;
|
|
59
|
+
/** Turn the light off. Throws if this model's switch wire is unverified. */
|
|
60
|
+
off(): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Enable/disable the **motion-activated light** (auto-spotlight): the spotlight lights up when the
|
|
63
|
+
* camera detects motion.
|
|
64
|
+
*
|
|
65
|
+
* ⚠️ This is a COMPOSITE write, and it is WRITE-ONLY: the setting is not reported back in the device's
|
|
66
|
+
* params, so the current config cannot be read and merged. Calling it with just `on` re-sends the
|
|
67
|
+
* DEFAULT brightness/auto-off/mode ({@link AutoSpotlightOptions}), overwriting whatever the user set.
|
|
68
|
+
* To preserve their config, pass the current values in `opts`. That is why this is a method and not a
|
|
69
|
+
* member — the caller must own the composite.
|
|
70
|
+
*/
|
|
71
|
+
setAutoSpotlight(on: boolean, opts?: AutoSpotlightOptions): Promise<void>;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Every `light` feature, declared once. The property schema, the typed getters, the derived setters,
|
|
75
|
+
* the intent routes and the descriptions all come out of this table.
|
|
76
|
+
*
|
|
77
|
+
* Auto-spotlight (1422) is deliberately absent: it is a COMPOSITE write — brightness, auto-off, mode
|
|
78
|
+
* and enable sent together — and WRITE-ONLY, so a plain toggle would re-send hardcoded defaults and
|
|
79
|
+
* clobber whatever the user set. It stays the explicit `setAutoSpotlight(on, opts)` method, where the
|
|
80
|
+
* composite is visible at the call site.
|
|
81
|
+
*
|
|
82
|
+
* Exported but NOT published: each entry states its wire id and the evidence it was confirmed on,
|
|
83
|
+
* which the reference site does not carry.
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
export declare const LIGHT_MEMBERS: {
|
|
87
|
+
/**
|
|
88
|
+
* Whether the lamp is lit RIGHT NOW — the momentary switch, not a setting. Measured on a T8170: 1400
|
|
89
|
+
* goes to `1` when a client lights the spotlight and back to `0` when that client stops, so the value
|
|
90
|
+
* tracks whoever is streaming rather than a preference anyone set. The vendor app lights the lamp for a
|
|
91
|
+
* live view and drops it on quitting.
|
|
92
|
+
*
|
|
93
|
+
* So it reads on whenever any client is watching. The setting a user changes and expects to persist
|
|
94
|
+
* is {@link spotlightEnabled}.
|
|
95
|
+
*
|
|
96
|
+
* The switch refuses for a reason a value check cannot give — this model's frame SHAPE is unconfirmed —
|
|
97
|
+
* so `switchFrame` throws that reason and `bindMembers` turns it into the rejection, rather than
|
|
98
|
+
* letting the generated "not a valid value" blame a boolean that was never the problem.
|
|
99
|
+
*/
|
|
100
|
+
readonly isOn: {
|
|
101
|
+
readonly param: 1400;
|
|
102
|
+
readonly property: "light";
|
|
103
|
+
readonly type: "bool";
|
|
104
|
+
readonly kind: "boolean";
|
|
105
|
+
readonly provenance: "verified";
|
|
106
|
+
readonly description: string;
|
|
107
|
+
readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
|
|
108
|
+
readonly writeAs: "set";
|
|
109
|
+
readonly aliases: {
|
|
110
|
+
readonly on: true;
|
|
111
|
+
readonly off: false;
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Manual level for the spotlight, 1-100 — the floor is 1 rather than 0 because a 0 reads as "off" and
|
|
116
|
+
* that is `isOn`'s job. The write is pinned to the level-2 direct-binary frame (`directBinary`),
|
|
117
|
+
* the only shape captured for it, so a standalone camera that never negotiates a level-2 key cannot
|
|
118
|
+
* set it even though the getter reads fine.
|
|
119
|
+
*/
|
|
120
|
+
readonly brightness: {
|
|
121
|
+
readonly param: 1401;
|
|
122
|
+
readonly type: "number";
|
|
123
|
+
readonly unit: "%";
|
|
124
|
+
readonly kind: "percent";
|
|
125
|
+
readonly provenance: "verified";
|
|
126
|
+
readonly min: 1;
|
|
127
|
+
readonly max: 100;
|
|
128
|
+
readonly description: "Manual brightness, range 1-100 (1401). Verified live (T8425 + T8124).";
|
|
129
|
+
readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Warm-to-cool on a 0-100 scale — a `scalar`, not a percentage or a mired value, since 0 is one end
|
|
133
|
+
* of a range rather than "none". `writeOnly`, so there is a setter and no getter at all: the device
|
|
134
|
+
* accepts the setting and never reports it back.
|
|
135
|
+
* Only tunable-white spotlights respond; a white-only model accepts the frame and does nothing.
|
|
136
|
+
*/
|
|
137
|
+
readonly colorTemp: {
|
|
138
|
+
readonly param: 1410;
|
|
139
|
+
readonly type: "number";
|
|
140
|
+
readonly kind: "scalar";
|
|
141
|
+
readonly provenance: "verified";
|
|
142
|
+
readonly writeOnly: true;
|
|
143
|
+
readonly min: 0;
|
|
144
|
+
readonly max: 100;
|
|
145
|
+
readonly description: "Colour temperature, 0 (warm) to 100 (cool). Not reported back, so it is write-only.";
|
|
146
|
+
readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* The master enable, one level above {@link isOn}: this decides whether the spotlight may light at all,
|
|
150
|
+
* where `isOn` is the momentary switch. `writeAs` names the setter `setEnabled` rather than the
|
|
151
|
+
* `setSpotlightEnabled` the key would derive, since the capability is already the spotlight.
|
|
152
|
+
*
|
|
153
|
+
* Reported, so it is a read as well as a write. ✅ Verified live on a T8170: the cloud device list
|
|
154
|
+
* carries 1403, and its value tracks the vendor app's spotlight setting in both directions — `1` to `0`
|
|
155
|
+
* when the setting is switched off, `0` to `1` when it is switched back on, so the polarity is direct
|
|
156
|
+
* and 1 means enabled. The poll reports a param only when its PREVIOUS value differed, so the id is in
|
|
157
|
+
* the record rather than newly appearing. The param dictionary names it `floodlightTotalSwitch`
|
|
158
|
+
* (`app:FLOODLIGHT_TOTAL_SWITCH`) and lists the T8170 among its models.
|
|
159
|
+
*
|
|
160
|
+
* This is the switch a user changes and expects to STAY changed. {@link isOn} is a different fact:
|
|
161
|
+
* the lamp being lit right now, driven by whichever
|
|
162
|
+
* client is streaming — the vendor app lights it for a live view and drops it on quitting.
|
|
163
|
+
*/
|
|
164
|
+
readonly spotlightEnabled: {
|
|
165
|
+
readonly param: 1403;
|
|
166
|
+
readonly type: "bool";
|
|
167
|
+
readonly kind: "boolean";
|
|
168
|
+
readonly provenance: "verified";
|
|
169
|
+
readonly description: string;
|
|
170
|
+
readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
|
|
171
|
+
readonly writeAs: "setEnabled";
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
export declare const LIGHT: CapabilityModule;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { isTuyaVacuum } from "../device-family.js";
|
|
2
|
+
import { type Surface } from "./members.js";
|
|
3
|
+
import type { CapabilityModule } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Every `locate` feature, declared once.
|
|
6
|
+
*
|
|
7
|
+
* `locate()` is a `method` rather than a derived setter because its argument is OPTIONAL — the
|
|
8
|
+
* common call is a bare `locate()` meaning "start beeping" — and a derived setter always takes its
|
|
9
|
+
* value. Dispatches DP 103 (legacy Tuya) or DP 160 (AIoT) based on which DP the device has reported.
|
|
10
|
+
*
|
|
11
|
+
* Exported but NOT published: each entry states its wire id and the evidence it was confirmed on,
|
|
12
|
+
* which the reference site does not carry.
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export declare const LOCATE_MEMBERS: {
|
|
16
|
+
/**
|
|
17
|
+
* The find-robot DP read back. `writtenElsewhere` rather than carrying its own `write`, because the
|
|
18
|
+
* setter is the `locate` method below — its argument is optional, which a derived setter cannot be.
|
|
19
|
+
* Expect this to read `undefined` on most robots: DP 160 is a momentary trigger, so a device that has
|
|
20
|
+
* never been asked to beep has no value to report and the evidence gate skips the getter entirely.
|
|
21
|
+
*/
|
|
22
|
+
readonly locating: {
|
|
23
|
+
readonly param: 160;
|
|
24
|
+
readonly type: "bool";
|
|
25
|
+
readonly kind: "boolean";
|
|
26
|
+
readonly provenance: "mega";
|
|
27
|
+
readonly writtenElsewhere: true;
|
|
28
|
+
readonly readAliases: readonly [{
|
|
29
|
+
readonly paramType: 103;
|
|
30
|
+
readonly available: typeof isTuyaVacuum;
|
|
31
|
+
}];
|
|
32
|
+
readonly description: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Writes DP 160 (AIoT) — `true` starts the beep, `false` cancels one already sounding. AIoT only:
|
|
36
|
+
* the legacy Tuya DP 103 is read as an alias above, but its WRITE direction is unconfirmed, so no
|
|
37
|
+
* Tuya dispatch is offered. The default
|
|
38
|
+
* argument is what makes this a `method`: a bare `locate()` is the call that matters, and a derived
|
|
39
|
+
* setter always demands its value.
|
|
40
|
+
*
|
|
41
|
+
* That default is also why the argument is named here: it is absent from the function's arity, so the
|
|
42
|
+
* description would otherwise derive as taking NO arguments and leave the cancel form undeclared.
|
|
43
|
+
*/
|
|
44
|
+
readonly locate: {
|
|
45
|
+
readonly method: (deps: import("./members.js").MemberDeps) => (on?: boolean) => Promise<void>;
|
|
46
|
+
readonly description: string;
|
|
47
|
+
readonly available: ((ctx: import("./types.js").CommandContext) => boolean) & ((ctx: import("./types.js").CommandContext) => boolean);
|
|
48
|
+
readonly answers?: true;
|
|
49
|
+
readonly args: readonly [{
|
|
50
|
+
readonly name: "on";
|
|
51
|
+
readonly kind: "boolean";
|
|
52
|
+
readonly optional: true;
|
|
53
|
+
readonly description: "False cancels a beep in progress.";
|
|
54
|
+
}];
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Bound locate reads and controls — the object returned by `dev.locate()`. The `locating` read is
|
|
59
|
+
* present only when the device has reported DP 160; `locate()` is always present on a bound device.
|
|
60
|
+
*/
|
|
61
|
+
export type LocateActions = Surface<typeof LOCATE_MEMBERS>;
|
|
62
|
+
/** `locate` — make the robot beep to find it. */
|
|
63
|
+
export declare const LOCATE: CapabilityModule;
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { type Surface } from "./members.js";
|
|
2
|
+
import type { AvailabilityContext, CapabilityModule, CommandContext } from "./types.js";
|
|
3
|
+
import type { Command, AutoLockSnapshot } from "../../core/contracts.js";
|
|
4
|
+
/**
|
|
5
|
+
* Setting-id selectors for the compact `ff09-setting-toggle` write — this capability's OWN wire
|
|
6
|
+
* vocabulary, named not inlined per the capability wire-id convention, so `setRainMode`
|
|
7
|
+
* below references `LOCK_SETTING_ID.RAIN_MODE` and this module's own spec can import it too, instead
|
|
8
|
+
* of a bare `7` at either call site.
|
|
9
|
+
*
|
|
10
|
+
* Unlike a normal capability id (owned by exactly one layer, crossing into `transport/` only as an
|
|
11
|
+
* opaque number), this value is a GENUINE duplicate of `transport/ff09.ts`'s `FF09_SETTING_ID.RAIN_MODE`
|
|
12
|
+
* — the capability↔transport decorrelation rule (`model/` never imports `transport/`) leaves no way to
|
|
13
|
+
* share one source of truth across the boundary, and no test can cross-check them without violating
|
|
14
|
+
* that same rule (`guard:decorrelation` forbids any `transport/` import under `src/model`, including
|
|
15
|
+
* tests). If a future capture revises this id, BOTH copies must be updated by hand.
|
|
16
|
+
*/
|
|
17
|
+
export declare const LOCK_SETTING_ID: {
|
|
18
|
+
/** One-touch lock toggle. Structurally confirmed via the app's own JS (2026-07-18) — see the module doc. */
|
|
19
|
+
readonly ONE_TOUCH_LOCK: 1;
|
|
20
|
+
/** Scramble-passcode toggle. Structurally confirmed via the app's own JS (2026-07-18) — see the module doc. */
|
|
21
|
+
readonly SCRAMBLE_PASSCODE: 3;
|
|
22
|
+
/** Wifi-status toggle. Structurally confirmed via the app's own JS (2026-07-18) — see the module doc. */
|
|
23
|
+
readonly WIFI_STATUS: 5;
|
|
24
|
+
/** Event-log-enable toggle. Structurally confirmed via the app's own JS (2026-07-18) — see the module doc. */
|
|
25
|
+
readonly ENABLE_LOG: 6;
|
|
26
|
+
/** Rain Mode toggle on the T8531 video lock. Verified live 2026-07-18. */
|
|
27
|
+
readonly RAIN_MODE: 7;
|
|
28
|
+
/** Privacy-mode toggle. Structurally confirmed via the app's own JS (2026-07-18) — see the module doc. */
|
|
29
|
+
readonly PRIVACY_MODE: 9;
|
|
30
|
+
/** One-touch rear-lock toggle. Structurally confirmed via the app's own JS (2026-07-18) — see the module doc. */
|
|
31
|
+
readonly ONE_TOUCH_REAR_LOCK: 11;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Bound lock controls — the object returned by `dev.lock()`.
|
|
35
|
+
*
|
|
36
|
+
* Everything is DERIVED from `LOCK_MEMBERS`. `lock`/`unlock` and the setting toggles drive any
|
|
37
|
+
* lock-family actuator — currently the T8531 video smart lock and the T85D0 garage door, which share one
|
|
38
|
+
* actuation frame. This module emits ONE transport-neutral intent (identity fields only, no wire bytes,
|
|
39
|
+
* no cipher, no routing key) and names no transport: the command sink routes P2P vs MQTT by the device's
|
|
40
|
+
* topology, and the chosen transport's command router builds the frame + envelope and re-resolves its own
|
|
41
|
+
* routing tail. Which pipe it is does not reach `dev.lock()` — its surface is identical either way,
|
|
42
|
+
* the same way P2P-vs-cloud is hidden for live media.
|
|
43
|
+
*/
|
|
44
|
+
export type LockActions = Surface<typeof LOCK_MEMBERS>;
|
|
45
|
+
/**
|
|
46
|
+
* Whether the device is reachable over P2P — the topology fact that decides which lock settings exist.
|
|
47
|
+
* The compact toggles are only known on the P2P video lock; the MQTT garage door does not expose them in
|
|
48
|
+
* the app, so offering them there would guess a frame shape that likely does not exist.
|
|
49
|
+
*/
|
|
50
|
+
declare const overP2p: (ctx: AvailabilityContext) => boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Every `lock` feature, declared once.
|
|
53
|
+
*
|
|
54
|
+
* The six toggles after `setRainMode` share its confirmed frame SHAPE and are grounded in the app's own
|
|
55
|
+
* JS, but none has been captured against a real device — so each is `unverified`: DECLARED, so the
|
|
56
|
+
* capability documents what the lock has, and NOT installed, because a fire-and-forget write that is
|
|
57
|
+
* wrong looks exactly like success. A caller sees them as optional and learns at compile time that they
|
|
58
|
+
* are not settable yet; promoting one is a single edit once a capture lands.
|
|
59
|
+
*
|
|
60
|
+
* They carry no `param`: a setting id is not a param id, nothing reports these back, and declaring one
|
|
61
|
+
* would put a wire number where the schema expects a reported value.
|
|
62
|
+
*
|
|
63
|
+
* Exported but NOT published: each entry states its wire id and the evidence it was confirmed on,
|
|
64
|
+
* which the reference site does not carry.
|
|
65
|
+
* @internal
|
|
66
|
+
*/
|
|
67
|
+
export declare const LOCK_MEMBERS: {
|
|
68
|
+
/**
|
|
69
|
+
* The lock's own state, and the weakest thing in this table: 1200 is a `guessed` placeholder because
|
|
70
|
+
* the lock announces (un)locking as a pushed event rather than holding a param, so the evidence gate
|
|
71
|
+
* will normally leave this getter uninstalled and `lockState` is the real read. `writtenElsewhere`
|
|
72
|
+
* points at the `lock`/`unlock` methods — a single `write` cannot express two verbs that carry no
|
|
73
|
+
* value.
|
|
74
|
+
*/
|
|
75
|
+
readonly locked: {
|
|
76
|
+
readonly param: 1200;
|
|
77
|
+
readonly type: "bool";
|
|
78
|
+
readonly kind: "boolean";
|
|
79
|
+
readonly provenance: "guessed";
|
|
80
|
+
readonly writtenElsewhere: true;
|
|
81
|
+
readonly description: "Lock state, true=locked. UNVERIFIED: no stable state param to key off; placeholder id pending verification.";
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Cell charge as a percentage, on the same param 1101 every battery device reports. Named `battery`
|
|
85
|
+
* within this capability rather than deferring to the `battery` capability: a lock resolves as a lock,
|
|
86
|
+
* so the accessor is `dev.lock().battery`.
|
|
87
|
+
*/
|
|
88
|
+
readonly battery: {
|
|
89
|
+
readonly param: 1101;
|
|
90
|
+
readonly type: "number";
|
|
91
|
+
readonly unit: "%";
|
|
92
|
+
readonly kind: "percent";
|
|
93
|
+
readonly provenance: "verified";
|
|
94
|
+
readonly description: "Lock battery level 0-100 (verified: param 1101).";
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Link quality in dBm as the lock measures it, on the shared param 1141. Both actuation methods here
|
|
98
|
+
* are fire-and-forget, so a weak link is silent rather than an error.
|
|
99
|
+
*/
|
|
100
|
+
readonly rssi: {
|
|
101
|
+
readonly param: 1141;
|
|
102
|
+
readonly type: "number";
|
|
103
|
+
readonly unit: "dBm";
|
|
104
|
+
readonly kind: "dbm";
|
|
105
|
+
readonly provenance: "verified";
|
|
106
|
+
readonly description: "Lock signal strength (verified: param 1141 = RSSI).";
|
|
107
|
+
};
|
|
108
|
+
/** Lock the deadbolt/door. Fire-and-forget — rejects only on missing member identity, never on a device timeout. */
|
|
109
|
+
readonly lock: import("./members.js").MethodMember<() => Promise<void>>;
|
|
110
|
+
/** Unlock the deadbolt/door. Fire-and-forget — rejects only on missing member identity. */
|
|
111
|
+
readonly unlock: import("./members.js").MethodMember<() => Promise<void>>;
|
|
112
|
+
/**
|
|
113
|
+
* Read-modify-write the auto-lock setting: the transport GETs the device's current settings, changes
|
|
114
|
+
* only `enabled` (+ `delaySeconds` if given — otherwise the current delay is preserved), and writes the
|
|
115
|
+
* rest back verbatim. Works on both the T8531 video lock and the T85D0 garage/lock, which share the
|
|
116
|
+
* identical settings frame; confirmed on-device in both directions on both families.
|
|
117
|
+
*
|
|
118
|
+
* **Unlike `lock`/`unlock` this can reject on a device TIMEOUT**, not just missing identity — the GET
|
|
119
|
+
* step is a genuine precondition, so this one is not fire-and-forget.
|
|
120
|
+
*/
|
|
121
|
+
readonly setAutoLock: import("./members.js").MethodMember<(enabled: boolean, delaySeconds?: number) => Promise<void>>;
|
|
122
|
+
/**
|
|
123
|
+
* Toggle Rain Mode — a pure blind write, unlike `setAutoLock`: the compact frame carries only this one
|
|
124
|
+
* field, so there is no GET pass and it is fire-and-forget. Confirmed on-device end-to-end in both
|
|
125
|
+
* directions, with the app UI reflecting the new state afterward. P2P video lock only.
|
|
126
|
+
*/
|
|
127
|
+
readonly setRainMode: import("./members.js").MethodMember<(enabled: boolean) => Promise<void>> & {
|
|
128
|
+
available: (ctx: CommandContext) => boolean;
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Lock the door by a single touch on the pad, with no code. First of the six compact toggles: all
|
|
132
|
+
* `unverified` (frame shape read out of the app's JS, never captured), so no setter is installed and
|
|
133
|
+
* `setOneTouchLock` lands optional on the surface — a caller learns at compile time. `writeOnly` too:
|
|
134
|
+
* nothing reports the setting back, so there is no getter either.
|
|
135
|
+
*/
|
|
136
|
+
readonly oneTouchLock: {
|
|
137
|
+
readonly type: "bool";
|
|
138
|
+
readonly kind: "boolean";
|
|
139
|
+
readonly writeOnly: true;
|
|
140
|
+
readonly unverified: true;
|
|
141
|
+
readonly available: typeof overP2p;
|
|
142
|
+
readonly provenance: "apk";
|
|
143
|
+
readonly description: "One-touch locking (setting-id 1). Wire shape confirmed in the app's own JS, NOT captured.";
|
|
144
|
+
readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Pad anti-shoulder-surfing: the lock asks for extra random digits around the real code so a watcher
|
|
148
|
+
* cannot read it off worn keys. Same `unverified` + `writeOnly` + P2P-only standing as its five
|
|
149
|
+
* siblings — declared so the capability documents the lock, not installed.
|
|
150
|
+
*/
|
|
151
|
+
readonly scramblePasscode: {
|
|
152
|
+
readonly type: "bool";
|
|
153
|
+
readonly kind: "boolean";
|
|
154
|
+
readonly writeOnly: true;
|
|
155
|
+
readonly unverified: true;
|
|
156
|
+
readonly available: typeof overP2p;
|
|
157
|
+
readonly provenance: "apk";
|
|
158
|
+
readonly description: "Scramble the passcode entry pad (setting-id 3). Wire shape confirmed in the app's own JS, NOT captured.";
|
|
159
|
+
readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Whether the lock reports its Wi-Fi status — a reporting toggle, not the radio itself, on the app's
|
|
163
|
+
* own naming. Same `unverified` + `writeOnly` + P2P-only standing as its five siblings; treat the
|
|
164
|
+
* meaning as the app's label until a capture pins the behaviour.
|
|
165
|
+
*/
|
|
166
|
+
readonly wifiStatus: {
|
|
167
|
+
readonly type: "bool";
|
|
168
|
+
readonly kind: "boolean";
|
|
169
|
+
readonly writeOnly: true;
|
|
170
|
+
readonly unverified: true;
|
|
171
|
+
readonly available: typeof overP2p;
|
|
172
|
+
readonly provenance: "apk";
|
|
173
|
+
readonly description: "Wi-Fi status reporting (setting-id 5). Wire shape confirmed in the app's own JS, NOT captured.";
|
|
174
|
+
readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Whether the lock records its own event history on-device. Same `unverified` + `writeOnly` +
|
|
178
|
+
* P2P-only standing as its five siblings — the frame shape comes from the app's JS and has never been
|
|
179
|
+
* driven against hardware.
|
|
180
|
+
*/
|
|
181
|
+
readonly logEnabled: {
|
|
182
|
+
readonly type: "bool";
|
|
183
|
+
readonly kind: "boolean";
|
|
184
|
+
readonly writeOnly: true;
|
|
185
|
+
readonly unverified: true;
|
|
186
|
+
readonly available: typeof overP2p;
|
|
187
|
+
readonly provenance: "apk";
|
|
188
|
+
readonly description: "Event-log recording (setting-id 6). Wire shape confirmed in the app's own JS, NOT captured.";
|
|
189
|
+
readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* The lock's own privacy mode — unrelated to the camera capability's privacy burst, which is a
|
|
193
|
+
* different device, a different wire and a different meaning. Same `unverified` + `writeOnly` +
|
|
194
|
+
* P2P-only standing as its five siblings.
|
|
195
|
+
*/
|
|
196
|
+
readonly privacyMode: {
|
|
197
|
+
readonly type: "bool";
|
|
198
|
+
readonly kind: "boolean";
|
|
199
|
+
readonly writeOnly: true;
|
|
200
|
+
readonly unverified: true;
|
|
201
|
+
readonly available: typeof overP2p;
|
|
202
|
+
readonly provenance: "apk";
|
|
203
|
+
readonly description: "Lock privacy mode (setting-id 9). Wire shape confirmed in the app's own JS, NOT captured.";
|
|
204
|
+
readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
|
|
205
|
+
};
|
|
206
|
+
/**
|
|
207
|
+
* The rear-deadbolt counterpart to `oneTouchLock`, on a lock that has a second bolt — so a model with
|
|
208
|
+
* one bolt has nothing for it to drive. Last of the six compact toggles and shares their standing
|
|
209
|
+
* exactly: `unverified`, `writeOnly`, P2P-only, no setter installed.
|
|
210
|
+
*/
|
|
211
|
+
readonly oneTouchRearLock: {
|
|
212
|
+
readonly type: "bool";
|
|
213
|
+
readonly kind: "boolean";
|
|
214
|
+
readonly writeOnly: true;
|
|
215
|
+
readonly unverified: true;
|
|
216
|
+
readonly available: typeof overP2p;
|
|
217
|
+
readonly provenance: "apk";
|
|
218
|
+
readonly description: "One-touch rear locking (setting-id 11). Wire shape confirmed in the app's own JS, NOT captured.";
|
|
219
|
+
readonly write: (v: string | number | boolean, ctx: CommandContext) => Command;
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* Read the device's current auto-lock settings via a live `GET_SETTINGS` round-trip — the SAME read
|
|
223
|
+
* `setAutoLock` does internally, exposed standalone with no write attached. Works over BOTH transports.
|
|
224
|
+
* A genuine request/reply query, not a passive property, so it always talks to the device.
|
|
225
|
+
*
|
|
226
|
+
* `answers` for that reason: the returned snapshot IS the point, so it is not a control to offer even
|
|
227
|
+
* though it takes no arguments — offering it as one would run a round-trip and discard the answer.
|
|
228
|
+
*/
|
|
229
|
+
readonly getAutoLockState: {
|
|
230
|
+
readonly needs: "ff09Settings";
|
|
231
|
+
readonly provided: (provider: import("../../core/contracts.js").Ff09SettingsReader, deps: import("./members.js").MemberDeps) => () => Promise<AutoLockSnapshot>;
|
|
232
|
+
readonly description: string;
|
|
233
|
+
readonly requiredCapabilities?: readonly import("../types.js").Capability[];
|
|
234
|
+
readonly answers: true;
|
|
235
|
+
};
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* `lock` — smart lock. `locked` is the reported lock state, but there's no stable state param to
|
|
239
|
+
* key off (only pushed via a CommandType-style event), so the param id here is a placeholder.
|
|
240
|
+
*/
|
|
241
|
+
export declare const LOCK: CapabilityModule;
|
|
242
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a device exposes, as data — one JSON-safe shape per device, with no branch per capability.
|
|
3
|
+
*
|
|
4
|
+
* A bound device is fully callable but states nothing about ITSELF from outside the package: neither
|
|
5
|
+
* what is installed nor what a value means is readable off it. The member table states both, and this
|
|
6
|
+
* turns that statement into a public, JSON-safe shape: which reads a device actually installed, which
|
|
7
|
+
* of its actions are offerable, and which events it emits.
|
|
8
|
+
*
|
|
9
|
+
* **Derived from the LIVE bound objects, not recomputed from the tables.** The descriptors of the bound
|
|
10
|
+
* object are the only source that cannot disagree with what `bindMembers` installed — evidence
|
|
11
|
+
* gates, provider gates and unverified writes are all already applied there. Recomputing the same answer
|
|
12
|
+
* from the module tables would be a second implementation of the gate, and it would be wrong in exactly
|
|
13
|
+
* the cases that matter: a media method on a device bound without that provider, a read for a param
|
|
14
|
+
* the device never reported. The table is joined in only for SEMANTICS (what the value means), which the
|
|
15
|
+
* bound object does not carry.
|
|
16
|
+
*
|
|
17
|
+
* **Never spread, `Object.entries` or `JSON.stringify` a bound object here.** All three invoke its
|
|
18
|
+
* getters, and a getter with a `decode` calls into the injected codec. Property descriptors only.
|
|
19
|
+
*
|
|
20
|
+
* @module model/capabilities/manifest
|
|
21
|
+
*/
|
|
22
|
+
import type { Capability, Codec, PropertyValueType, ResolvedDevice, ValueKind } from "../types.js";
|
|
23
|
+
import type { ActionSpec, AvailabilityContext, CapabilityModule } from "./types.js";
|
|
24
|
+
/** One read installed on a bound capability object — a value the device reports, and what it means. */
|
|
25
|
+
export interface ReadDescriptor {
|
|
26
|
+
/** The getter's name on the capability object (`dev.battery()?.level` → `level`). */
|
|
27
|
+
accessor: string;
|
|
28
|
+
/** The name the same value carries in the device's flat property namespace (`getProperty`). */
|
|
29
|
+
property: string;
|
|
30
|
+
/** How the value is stored. */
|
|
31
|
+
type: PropertyValueType;
|
|
32
|
+
/** What the value MEANS, as opposed to how it is stored. See {@link ValueKind}. */
|
|
33
|
+
kind?: ValueKind;
|
|
34
|
+
/** The unit the device reports the value in, when it has one (`"%"`, `"°C"`, `"dBm"`). */
|
|
35
|
+
unit?: string;
|
|
36
|
+
/** The option set, for a value out of a fixed domain. */
|
|
37
|
+
values?: readonly (string | number)[];
|
|
38
|
+
/** Labels for {@link values}, keyed by the raw value as a string. */
|
|
39
|
+
labels?: Readonly<Record<string, string>>;
|
|
40
|
+
/**
|
|
41
|
+
* Whether a setter for this value is installed BESIDE the getter on the same object.
|
|
42
|
+
*
|
|
43
|
+
* Read off the bound object rather than the schema, so it means "a caller can write this on THIS
|
|
44
|
+
* device" — a write the device gave no evidence for, or one whose wire is not confirmed, is not
|
|
45
|
+
* installed and reads `false` here. A value driven by a differently-named method (a pair of frames,
|
|
46
|
+
* a validating setter) is `false` too and appears under the capability's {@link
|
|
47
|
+
* CapabilityDescriptor.actions} instead, which is where its signature is described.
|
|
48
|
+
*/
|
|
49
|
+
writable: boolean;
|
|
50
|
+
description?: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* One offerable action: an {@link ActionSpec} plus the name it is installed under.
|
|
54
|
+
*
|
|
55
|
+
* The name is taken from the enumeration rather than carried in the spec, so a renamed method takes its
|
|
56
|
+
* description with it and cannot leave one behind pointing at nothing.
|
|
57
|
+
*/
|
|
58
|
+
export interface ActionDescriptor extends ActionSpec {
|
|
59
|
+
name: string;
|
|
60
|
+
}
|
|
61
|
+
/** What one capability exposes on a device — the join of its bound object and its own declaration. */
|
|
62
|
+
export interface CapabilityDescriptor {
|
|
63
|
+
capability: Capability;
|
|
64
|
+
/** The fluent accessor this capability is reached under: `dev[accessor]()`. */
|
|
65
|
+
accessor: string;
|
|
66
|
+
/** The reads INSTALLED on this device, never the theoretical set. */
|
|
67
|
+
reads: readonly ReadDescriptor[];
|
|
68
|
+
/** The installed actions that carry a description. */
|
|
69
|
+
actions: readonly ActionDescriptor[];
|
|
70
|
+
/**
|
|
71
|
+
* Installed, callable actions with no description — usable, but not auto-offerable. Published rather
|
|
72
|
+
* than hidden so the gap is visible instead of looking like the action doesn't exist.
|
|
73
|
+
*/
|
|
74
|
+
undescribedActions: readonly string[];
|
|
75
|
+
/** The semantic event names this capability emits. */
|
|
76
|
+
events: readonly string[];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* A device's public shape: its identity, its capabilities, and what each of those exposes.
|
|
80
|
+
*
|
|
81
|
+
* `bound` is explicit because an unbound model object (no live client) has no bound objects to
|
|
82
|
+
* enumerate, so its `details` are empty — a caller has to be able to tell "this device exposes nothing"
|
|
83
|
+
* from "ask again once it is bound".
|
|
84
|
+
*/
|
|
85
|
+
export interface DeviceManifest {
|
|
86
|
+
sn: string;
|
|
87
|
+
/** What the user named the device in the app; falls back to {@link modelName} when unnamed. */
|
|
88
|
+
name: string;
|
|
89
|
+
/** Model / T-code ("T8410"), when the record states one. */
|
|
90
|
+
model?: string;
|
|
91
|
+
/** The model's own display name ("Indoor Cam Pan & Tilt") — the product, not this unit. */
|
|
92
|
+
modelName: string;
|
|
93
|
+
codec: Codec;
|
|
94
|
+
source: ResolvedDevice["source"];
|
|
95
|
+
bound: boolean;
|
|
96
|
+
capabilities: readonly Capability[];
|
|
97
|
+
details: readonly CapabilityDescriptor[];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Describe the capability objects a device has bound, one descriptor each.
|
|
101
|
+
*
|
|
102
|
+
* Parameterised over the module list; the barrel binds it to the real one. A capability the device did
|
|
103
|
+
* not bind — because it does not have it, or because nothing is bound yet — contributes no descriptor
|
|
104
|
+
* at all.
|
|
105
|
+
* @internal
|
|
106
|
+
*/
|
|
107
|
+
export declare function describeBound(modules: readonly CapabilityModule[], bound: Readonly<Record<string, unknown>>, ctx?: AvailabilityContext): CapabilityDescriptor[];
|