@mega-yfue/eufy-sdk 0.5.0-beta.57 → 0.5.0-beta.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/eufy-mega.d.ts +13 -4
- package/dist/core/contracts.d.ts +12 -3
- package/dist/index.js +41 -24
- package/dist/index.js.map +2 -2
- package/dist/transport/p2p/readable-egress.d.ts +4 -0
- package/package.json +1 -1
|
@@ -185,7 +185,8 @@ export declare class EufyMega extends EventEmitter {
|
|
|
185
185
|
*
|
|
186
186
|
* Skipped entirely for a device with a pollable cloud record, for an already-reporting device, and
|
|
187
187
|
* when realtime is off — so the common path adds nothing. Resolving on timeout leaves a silent device
|
|
188
|
-
* read-less rather than failing the lookup.
|
|
188
|
+
* read-less rather than failing the lookup. A Tuya clean-line device waits on the Tuya cloud read the
|
|
189
|
+
* bring-up started, so no broker is brought up for it.
|
|
189
190
|
*/
|
|
190
191
|
private awaitFirstRealtimeState;
|
|
191
192
|
/**
|
|
@@ -245,8 +246,17 @@ export declare class EufyMega extends EventEmitter {
|
|
|
245
246
|
* to land it under the property's name.
|
|
246
247
|
*/
|
|
247
248
|
private rebindReads;
|
|
248
|
-
/**
|
|
249
|
+
/**
|
|
250
|
+
* The distinct credential scopes the current MQTT roster needs — no devices on a scope, no connection.
|
|
251
|
+
* A Tuya clean-line device (`eufy_home_tuya`) needs none: the broker refuses its topics, and its state
|
|
252
|
+
* is read from the Tuya cloud.
|
|
253
|
+
*/
|
|
249
254
|
private mqttScopesInUse;
|
|
255
|
+
/**
|
|
256
|
+
* Read every Tuya clean-line device's DPs from the Tuya cloud and deliver them as realtime state. A
|
|
257
|
+
* failed read is reported, not fatal, and leaves that device's state as it was.
|
|
258
|
+
*/
|
|
259
|
+
private readTuyaDevices;
|
|
250
260
|
/**
|
|
251
261
|
* Emit a semantic capability event whose name is only known at runtime (`decodeCapabilityEvent`
|
|
252
262
|
* returns a plain-string `event` + `payload`). The typed `emit` overload requires a literal event
|
|
@@ -793,8 +803,7 @@ export declare class EufyMega extends EventEmitter {
|
|
|
793
803
|
* unreachable device must not stop the rest of the roster from coming up).
|
|
794
804
|
*
|
|
795
805
|
* A Tuya clean-line device (`eufy_home_tuya`) is not subscribed: its state lives on the Tuya cloud,
|
|
796
|
-
* and the broker refuses its `eufy_home` topics on every credential.
|
|
797
|
-
* cloud instead.
|
|
806
|
+
* and the broker refuses its `eufy_home` topics on every credential.
|
|
798
807
|
*/
|
|
799
808
|
private subscribeMqttDevices;
|
|
800
809
|
/**
|
package/dist/core/contracts.d.ts
CHANGED
|
@@ -544,6 +544,12 @@ export interface LiveVideoConfig {
|
|
|
544
544
|
width: number;
|
|
545
545
|
height: number;
|
|
546
546
|
}
|
|
547
|
+
/** Video frame paired with its original SDK source-arrival time. */
|
|
548
|
+
export interface ReceivedVideoFrame {
|
|
549
|
+
readonly frame: LiveVideoFrame;
|
|
550
|
+
/** Wall-clock milliseconds when the shared source received the frame; preserved on replay. */
|
|
551
|
+
readonly timestampMs: number;
|
|
552
|
+
}
|
|
547
553
|
/**
|
|
548
554
|
* Elementary-stream audio codec of a {@link LiveAudioFrame}. The station declares it per frame as a
|
|
549
555
|
* byte in the `CMD_AUDIO_FRAME` header — unlike video, nothing is sniffed. These are the three values
|
|
@@ -823,12 +829,15 @@ export interface MediaProvider {
|
|
|
823
829
|
}): Promise<Buffer>;
|
|
824
830
|
/**
|
|
825
831
|
* Open a video-only `node:stream` Readable over a shared source consumer — raw Annex-B bytes
|
|
826
|
-
* (default) or `objectMode` {@link LiveVideoFrame}s.
|
|
827
|
-
* {@link
|
|
828
|
-
*
|
|
832
|
+
* (default) or `objectMode` {@link LiveVideoFrame}s. With objectMode and arrivalTime, it yields
|
|
833
|
+
* {@link ReceivedVideoFrame} envelopes whose original source-arrival time survives retained replay.
|
|
834
|
+
* Raw mode ignores arrivalTime. Audio is available separately through {@link live} or muxed through
|
|
835
|
+
* {@link recordFragments}; it is never interleaved into raw video. The caller owns the Readable's
|
|
836
|
+
* lifetime, and destroying it releases the shared pull.
|
|
829
837
|
*/
|
|
830
838
|
openReadable?(opts?: {
|
|
831
839
|
objectMode?: boolean;
|
|
840
|
+
arrivalTime?: boolean;
|
|
832
841
|
} & SharedSourceHints & AbortableCall): Promise<import("node:stream").Readable>;
|
|
833
842
|
/**
|
|
834
843
|
* Continuously record the live feed as fragmented-MP4 (CMAF). The caller-owned
|
package/dist/index.js
CHANGED
|
@@ -20396,12 +20396,15 @@ function openReadableFromConsumer(consumer, opts = {}) {
|
|
|
20396
20396
|
cb(err);
|
|
20397
20397
|
}
|
|
20398
20398
|
});
|
|
20399
|
-
|
|
20400
|
-
|
|
20401
|
-
|
|
20399
|
+
consumer.onMedia((item) => {
|
|
20400
|
+
if (item.kind !== "video")
|
|
20401
|
+
return;
|
|
20402
|
+
const value = objectMode ? opts.arrivalTime ? { frame: item.frame, timestampMs: item.timestampMs } : item.frame : item.frame.data;
|
|
20403
|
+
if (!readable.push(value))
|
|
20402
20404
|
consumer.pause();
|
|
20403
|
-
};
|
|
20404
|
-
consumer.on("video",
|
|
20405
|
+
});
|
|
20406
|
+
consumer.on("video", () => {
|
|
20407
|
+
});
|
|
20405
20408
|
consumer.on("stop", () => readable.push(null));
|
|
20406
20409
|
consumer.on("error", (err) => readable.destroy(err));
|
|
20407
20410
|
return readable;
|
|
@@ -28301,7 +28304,8 @@ var EufyMega = class extends EventEmitter13 {
|
|
|
28301
28304
|
*
|
|
28302
28305
|
* Skipped entirely for a device with a pollable cloud record, for an already-reporting device, and
|
|
28303
28306
|
* when realtime is off — so the common path adds nothing. Resolving on timeout leaves a silent device
|
|
28304
|
-
* read-less rather than failing the lookup.
|
|
28307
|
+
* read-less rather than failing the lookup. A Tuya clean-line device waits on the Tuya cloud read the
|
|
28308
|
+
* bring-up started, so no broker is brought up for it.
|
|
28305
28309
|
*/
|
|
28306
28310
|
async awaitFirstRealtimeState(sn) {
|
|
28307
28311
|
if (this.opts.autoRealtime === false || this.realtimeGeneration?.epoch !== this.realtimeEpoch)
|
|
@@ -28319,10 +28323,12 @@ var EufyMega = class extends EventEmitter13 {
|
|
|
28319
28323
|
const caps = this.registry.capabilitiesForDevice(sn);
|
|
28320
28324
|
if (!caps || !hasRealtimeReads(caps))
|
|
28321
28325
|
return;
|
|
28322
|
-
|
|
28323
|
-
|
|
28324
|
-
|
|
28325
|
-
|
|
28326
|
+
if (!isTuyaVacuum(dev)) {
|
|
28327
|
+
try {
|
|
28328
|
+
await this.ensureMqttStarted(mqttScopeFor(dev));
|
|
28329
|
+
} catch {
|
|
28330
|
+
return;
|
|
28331
|
+
}
|
|
28326
28332
|
}
|
|
28327
28333
|
await this.registry.awaitRealtimeState(sn, timeoutMs);
|
|
28328
28334
|
}
|
|
@@ -28429,9 +28435,27 @@ var EufyMega = class extends EventEmitter13 {
|
|
|
28429
28435
|
this.reportError(e);
|
|
28430
28436
|
}
|
|
28431
28437
|
}
|
|
28432
|
-
/**
|
|
28438
|
+
/**
|
|
28439
|
+
* The distinct credential scopes the current MQTT roster needs — no devices on a scope, no connection.
|
|
28440
|
+
* A Tuya clean-line device (`eufy_home_tuya`) needs none: the broker refuses its topics, and its state
|
|
28441
|
+
* is read from the Tuya cloud.
|
|
28442
|
+
*/
|
|
28433
28443
|
mqttScopesInUse() {
|
|
28434
|
-
return [
|
|
28444
|
+
return [
|
|
28445
|
+
...new Set(this.getMqttDevices().filter((d) => !isTuyaVacuum(d)).map(mqttScopeFor))
|
|
28446
|
+
];
|
|
28447
|
+
}
|
|
28448
|
+
/**
|
|
28449
|
+
* Read every Tuya clean-line device's DPs from the Tuya cloud and deliver them as realtime state. A
|
|
28450
|
+
* failed read is reported, not fatal, and leaves that device's state as it was.
|
|
28451
|
+
*/
|
|
28452
|
+
readTuyaDevices() {
|
|
28453
|
+
for (const d of this.getMqttDevices().filter(isTuyaVacuum)) {
|
|
28454
|
+
this.tuya.fetchDps(d.sn).then((dps) => {
|
|
28455
|
+
if (dps)
|
|
28456
|
+
this.tuyaDpRouter.deliver(d.sn, dps);
|
|
28457
|
+
}).catch((e) => this.reportError(e));
|
|
28458
|
+
}
|
|
28435
28459
|
}
|
|
28436
28460
|
/**
|
|
28437
28461
|
* Emit a semantic capability event whose name is only known at runtime (`decodeCapabilityEvent`
|
|
@@ -28942,7 +28966,7 @@ var EufyMega = class extends EventEmitter13 {
|
|
|
28942
28966
|
}
|
|
28943
28967
|
if (cmd.kind === "aiot-dp") {
|
|
28944
28968
|
const dev = this.registry.require(sn);
|
|
28945
|
-
if (dev
|
|
28969
|
+
if (isTuyaVacuum(dev))
|
|
28946
28970
|
return this.tuya.dispatchCommand(sn, cmd);
|
|
28947
28971
|
return this.mqtt.dispatchCommand(sn, cmd);
|
|
28948
28972
|
}
|
|
@@ -29000,7 +29024,7 @@ var EufyMega = class extends EventEmitter13 {
|
|
|
29000
29024
|
async getDevices() {
|
|
29001
29025
|
const devices = await this.registry.getDevices();
|
|
29002
29026
|
for (const dev of devices) {
|
|
29003
|
-
if (dev
|
|
29027
|
+
if (!isTuyaVacuum(dev))
|
|
29004
29028
|
continue;
|
|
29005
29029
|
const raw = dev.raw ?? {};
|
|
29006
29030
|
this.tuya.registerDevice(dev.sn, tuyaDevIdFrom(raw) ?? dev.sn);
|
|
@@ -29174,6 +29198,7 @@ var EufyMega = class extends EventEmitter13 {
|
|
|
29174
29198
|
await this.getDevices();
|
|
29175
29199
|
if (epoch !== this.realtimeEpoch)
|
|
29176
29200
|
return this.settleRealtimeGeneration(generation, "superseded");
|
|
29201
|
+
this.readTuyaDevices();
|
|
29177
29202
|
const scopes = this.mqttScopesInUse();
|
|
29178
29203
|
readiness.mqtt = createPlaneReadiness(scopes.length);
|
|
29179
29204
|
let push;
|
|
@@ -29663,18 +29688,10 @@ var EufyMega = class extends EventEmitter13 {
|
|
|
29663
29688
|
* unreachable device must not stop the rest of the roster from coming up).
|
|
29664
29689
|
*
|
|
29665
29690
|
* A Tuya clean-line device (`eufy_home_tuya`) is not subscribed: its state lives on the Tuya cloud,
|
|
29666
|
-
* and the broker refuses its `eufy_home` topics on every credential.
|
|
29667
|
-
* cloud instead.
|
|
29691
|
+
* and the broker refuses its `eufy_home` topics on every credential.
|
|
29668
29692
|
*/
|
|
29669
29693
|
async subscribeMqttDevices(scope, transport) {
|
|
29670
|
-
for (const d of this.getMqttDevices().filter((dev) => mqttScopeFor(dev) === scope)) {
|
|
29671
|
-
if (d.category === "eufy_home_tuya") {
|
|
29672
|
-
this.tuya.fetchDps(d.sn).then((dps) => {
|
|
29673
|
-
if (dps)
|
|
29674
|
-
this.tuyaDpRouter.deliver(d.sn, dps);
|
|
29675
|
-
}).catch((e) => this.reportError(e));
|
|
29676
|
-
continue;
|
|
29677
|
-
}
|
|
29694
|
+
for (const d of this.getMqttDevices().filter((dev) => !isTuyaVacuum(dev) && mqttScopeFor(dev) === scope)) {
|
|
29678
29695
|
try {
|
|
29679
29696
|
await transport.subscribeDevice(d);
|
|
29680
29697
|
await this.sendRealtimeInit(d.sn);
|