Skip to content

@mega-yfue/eufy-sdk / tuya / TuyaClient

Class: TuyaClient ​

Constructors ​

Constructor ​

ts
new TuyaClient(config?): TuyaClient;

Parameters ​

config? ​

TuyaClientConfig = {}

Returns ​

TuyaClient

Accessors ​

loggedIn ​

Get Signature ​

ts
get loggedIn(): boolean;

True once a login has populated a session id.

Returns ​

boolean

Methods ​

buildRequest() ​

ts
buildRequest(action): Record<string, string>;

Build the full signed param map for an action against the current session. Does not send. Requires a working signer (the sign step).

Parameters ​

action ​

TuyaAction

Returns ​

Record<string, string>


call() ​

ts
call<T>(action): Promise<TuyaEnvelope<T>>;

Build + POST an action, returning the parsed envelope. Requires a working signer.

On an et=3 reply the envelope's result is a base64 AES-128-GCM blob, not an object; this decrypts it (keyed off the request's requestId and the session's ecode) and returns the decrypted inner envelope, so callers read result as an object regardless. A non-string result (an error, or an already-plain reply) passes through untouched.

Type Parameters ​

T ​

T = unknown

Parameters ​

action ​

TuyaAction

Returns ​

Promise<TuyaEnvelope<T>>


getDeviceDps() ​

ts
getDeviceDps<T>(devId): Promise<TuyaEnvelope<T>>;

READ a device's current data-points (smartlife.m.device.dp.get). The envelope's result is a flat { "<dpId>": value } map. Builds the request without needing a working signer; the signer is only exercised on send.

Type Parameters ​

T ​

T = unknown

Parameters ​

devId ​

string

Returns ​

Promise<TuyaEnvelope<T>>


getSession() ​

ts
getSession(): Readonly<TuyaSession>;

The current per-install session identity (sid empty until login).

Returns ​

Readonly<TuyaSession>


login() ​

ts
login(eufyUserId, phoneCode?): Promise<TuyaLoginResult>;

Log into the Tuya cloud from a eufy user id (wire-confirmed from the eufy Security app).

Flow:

  1. smartlife.m.user.username.token.get → { token, publicKey, exponent } (RSA-2048 key). If this returns USER_NOT_EXIST the shadow account has never been provisioned — the vacuum must be added via the eufy Security app (com.oceanwing.battery.cam) at least once.
  2. Derive password: RSA/PKCS1-encrypt( MD5hex(aesPassword), serverKey ) → hex.
  3. smartlife.m.user.uid.password.login.reg → { sid, uid }. On USER_PASSWD_WRONG: re-fetch a token and retry once with the hardcoded fallback password "12345678" (wire-confirmed from the eufy Security app). ⚠️ Two failed attempts in a row can contribute to Tuya-side rate-limiting or lockout — do not add further retry loops on top of this one.

Parameters ​

eufyUserId ​

string

phoneCode? ​

string

Returns ​

Promise<TuyaLoginResult>


publishDps() ​

ts
publishDps<T>(
   devId, 
   gwId, 
   dps, 
   opts?
): Promise<TuyaEnvelope<T>>;

CONTROL: publish data-points to a device (smartlife.m.device.dp.publish). dps is { "<dpId>": <value> }. gwId is the gateway/parent id (equals devId for a standalone gw).

⚠️ UNVERIFIED write — refuses to send by default. The dp.publish param shape (buildPublishDpsAction) is derived, NOT pinned against a confirmed exchange, and the login round-trip that yields a real sid is unproven too. A wrong shape comes back as a generic Tuya error indistinguishable from a real device rejection, so blindly sending would hide that ambiguity. Pass { allowUnverified: true } to send anyway; the gate drops when the write is captured + confirmed against a device.

Type Parameters ​

T ​

T = unknown

Parameters ​

devId ​

string

gwId ​

string

dps ​

Record<string, unknown>

opts? ​
allowUnverified? ​

boolean

Returns ​

Promise<TuyaEnvelope<T>>

Independent and unofficial. Not affiliated with, endorsed by, or sponsored by Anker Innovations, Anker eufy, or eufy. "Anker eufy", "eufy" and "Anker" are trademarks of their respective owners. Use responsibly — rapid or failed logins can trigger captcha or temporary cooldowns.