@mega-yfue/eufy-sdk / SolixClient
Class: SolixClient
Login + read client for one Anker account's Solix devices. Construct with the account credentials, await login(), then read getDevices / getSites / getUserMqttInfo. Not tied to any host runtime.
Constructors
Constructor
new SolixClient(opts): SolixClient;Resolve the device id (explicit → stored → deterministic from the email, so it is stable and does not re-trigger 2FA) and adopt a stored session that has not expired, so a warm start skips the handshake. An explicit opts.apiHost outranks a stored session's host in both cases: it is an override that also skips domain-estimate, and every read goes through this.apiHost.
Parameters
opts
Returns
SolixClient
Accessors
session
Get Signature
get session(): SolixSession | undefined;The authenticated session, once login has resolved to ok.
Returns
SolixSession | undefined
Methods
getDeviceAttrs()
getDeviceAttrs(deviceSn, attributes?): Promise<Record<string, unknown>>;Read device attributes — a plain authenticated read (unlike the encrypted write). attributes names the keys to fetch (e.g. ["screen_off_time"]); an empty list asks for the device's default set. Returns the gateway's attribute map as-is (values are device-typed — numbers, strings). Used to reflect a control's live state, e.g. the display/light off-timeout.
Parameters
deviceSn
string
attributes?
string[] = []
Returns
Promise<Record<string, unknown>>
getDevices()
getDevices(): Promise<SolixDeviceRecord[]>;The account's bound Solix devices (flat list; may be empty when devices live under sites). The gateway's JSON is asserted to SolixDeviceRecord here, at the one trust boundary — every field beyond device_sn/product_code is optional on the record, so a caller reads them defensively.
Returns
Promise<SolixDeviceRecord[]>
getPowerCutoff()
getPowerCutoff(deviceSn, siteId?): Promise<SolixPowerCutoffOption[]>;Read the Solarbank's battery discharge-cutoff (minimum-SOC) options — a plain authed read. The gateway returns a preset list (power_cutoff_data): each entry is a selectable minimum state-of-charge output_cutoff_data (percent) with its id and is_selected flag. The caller presents these options and writes the chosen id back via setPowerCutoff — the values and ids come from the device, never assumed. siteId is optional (the device knows its own cutoff).
Parameters
deviceSn
string
siteId?
string = ""
Returns
Promise<SolixPowerCutoffOption[]>
getProductCatalog()
getProductCatalog(): Promise<SolixProductCategory[]>;The pairable-product catalog (categories → products). This is Anker's product registry, not the account's devices — fetch it to label a discovered device's model code with a marketing name and category. Pair with buildModelIndex. It is a live endpoint, so it stays current without a baked-in table.
Returns
Promise<SolixProductCategory[]>
getSafetySocParams()
getSafetySocParams(siteId): Promise<SolixSocParams | undefined>;Read the Solarbank's battery SOC-limit settings (param_type "27") — a plain authenticated read. Returns undefined when the site carries no SOC block (e.g. non-Solarbank hardware). The realtime dischargeLowerLimit also arrives on the MQTT b5 telemetry blob; this is the authoritative, app-synced source for chargeUpperLimit. backupReserve (with its enable switch) also has a second source under the same name, the realtime MQTT b5 frame; whether the two agree while the switch is OFF is not yet verified. Verified live against a known AE103 setting (discharge 20 / charge 80).
Parameters
siteId
string
Returns
Promise<SolixSocParams | undefined>
getSites()
getSites(): Promise<SolixSiteRecord[]>;The account's sites (systems); devices are grouped under a site. Each record carries its site_device_list (the member devices), which discoverSolixSites resolves into a capability-driven SolixSite. Asserted to SolixSiteRecord at this trust boundary — and site_id (the one field the model layer keys a SolixSite on) is validated here, so a record the cloud returns without a usable id is dropped rather than surfacing a SolixSite with id === undefined; every other field is optional and read defensively.
Returns
Promise<SolixSiteRecord[]>
getSiteScene()
getSiteScene(siteId): Promise<SolixSiteScene>;Read a site's "scene" snapshot — the app's dashboard read for a system, a plain authed read. Its battery detail (solarbank_info.solarbank_list[]) carries clean, correctly-named fields including bat_temperature, which the realtime ff09 MQTT push does NOT reliably carry (the fast frame's BMS blob is empty, so the decoder withholds temperature). This is therefore a low-rate BACKSTOP for those gap fields — NOT the realtime source: live power/SOC still come from the MQTT push (which is what the app itself refreshes from every ~5 s; there is no clean-JSON scene PUSH). Verified live against the ff09 floats — the two agree to the watt at the same instant.
Parameters
siteId
string
Returns
Promise<SolixSiteScene>
getUserMqttInfo()
getUserMqttInfo(): Promise<SecureMqttCredentials>;Per-user AWS-IoT MQTT credentials (cert/key/endpoint/thing) for the real-time device plane.
Returns
Promise<SecureMqttCredentials>
login()
login(): Promise<SolixLoginResult>;Authenticate with the account credentials. Resolves to ok with a SolixSession, or 2fa when the passport sent a code — then call submitVerifyCode. A session that is already fresh (adopted from a store) is answered without a handshake.
Returns
Promise<SolixLoginResult>
setAmbientLight()
setAmbientLight(deviceSn, on): Promise<void>;Turn the Solarbank's ambient LED on/off — a confirmed set_device_attrs write.
Parameters
deviceSn
string
on
boolean
Returns
Promise<void>
setDeviceAttrs()
setDeviceAttrs(deviceSn, attributes): Promise<void>;Write device attributes — a CONTROL write, e.g. the Solarbank ambient light { ambient_light_switch: 0 | 1 } (0 = on, 1 = off). Unlike the plain authenticated reads, a write must be encrypted + signed with a freshly negotiated algo_ecdh key: the gateway accepts an unsigned write with code 0 but the device never applies it. The token-bearing request also must NOT carry the device id (openudid), or the gateway answers 401 token error. Both verified live on an AE103 (the LED-enable bit in the ba telemetry flips exactly as commanded).
Parameters
deviceSn
string
attributes
Record<string, unknown>
Returns
Promise<void>
setPowerCutoff()
setPowerCutoff(deviceSn, cutoffDataId): Promise<void>;Select the Solarbank's battery discharge-cutoff (minimum SOC) by option id — a control write. cutoffDataId MUST be an id returned by getPowerCutoff for this device (the preset the user picked), never a raw percentage; the gateway maps the id to its cutoff percent.
Parameters
deviceSn
string
cutoffDataId
number
Returns
Promise<void>
setSafetySocParams()
setSafetySocParams(siteId, changes): Promise<SolixSocParams>;Write the Solarbank's battery SOC limits — an algo_ecdh-encrypted + signed control write. This is read-modify-write: it first reads the current param_type "27" block and overlays only the fields the caller supplies, so changing the discharge limit alone never clobbers the charge limit, backup reserve, or calibration toggle. changes values are whole-percent integers. The full block (all five keys) is sent, matching the app's SocSettingParam.toJson. Throws if the site has no SOC block to modify. Returns the merged parameters that were written (for an immediate optimistic echo).
Parameters
siteId
string
changes
Partial<SolixSocParams>
Returns
Promise<SolixSocParams>
setScreenOffTime()
setScreenOffTime(deviceSn, seconds): Promise<void>;Set the Solarbank display's screen-off timeout, in SECONDS (screen_off_time). The app's picker offers 10/20/30 s and 1/5/30 min; the LCD backlight — and with it the ambient LED that the screen gates — turns off after this idle period. This is the raw-seconds write; the caller maps its own UI options to seconds. The "Never" (always-on) sentinel is device-defined and NOT assumed here — pass the exact integer read back from getDeviceAttrs while the device is in that mode.
Parameters
deviceSn
string
seconds
number
Returns
Promise<void>
submitVerifyCode()
submitVerifyCode(code): Promise<SolixLoginResult>;Complete a 2fa login with the code the passport sent.
Parameters
code
string
Returns
Promise<SolixLoginResult>