UNPKG

homebridge-levoit-humidifiers

Version:
296 lines 11.1 kB
import { Logger, PlatformConfig } from 'homebridge'; import DebugMode from '../debugMode'; import VeSyncFan from './VeSyncFan'; /** * VeSync API bypass methods for device control. * These methods are sent to the VeSync API to control device features. */ export declare enum BypassMethod { STATUS = "getHumidifierStatus", MODE = "setHumidityMode", NIGHT_LIGHT_BRIGHTNESS = "setNightLightBrightness", DISPLAY = "setDisplay", SWITCH = "setSwitch", HUMIDITY = "setTargetHumidity", MIST_LEVEL = "setVirtualLevel", LEVEL = "setLevel", LIGHT_STATUS = "setLightStatus", DRYING_MODE = "setDryingMode" } interface DeviceResult { humidity?: number; targetHumidity?: number; screenSwitch?: boolean; workMode?: string; powerSwitch?: number; autoStopState?: boolean; virtualLevel?: number; configuration?: { auto_target_humidity?: number; }; display?: boolean; mode?: string; enabled?: boolean; automatic_stop_reach_target?: boolean; mist_virtual_level?: number; warm_level?: number; warm_enabled?: boolean; night_light_brightness?: number; rgbNightLight?: { brightness?: number; action?: string; blue?: number; green?: number; red?: number; colorMode?: string; speed?: number; colorSliderLocation?: number; }; } interface DeviceInfoResponse { result?: { result?: DeviceResult; }; msg?: string; } /** * VeSync API client for authenticating and communicating with VeSync devices. * * Features: * - Two-step authentication with session persistence * - Automatic cross-region detection and switching * - Session token caching to disk for faster re-authentication * - Automatic token refresh on 401 errors * - Login backoff to prevent API abuse * - Support for US and EU API endpoints * * The authentication flow: * 1. Step 1: authByPWDOrOTM - Authenticates with email/password, returns authorizeCode * 2. Step 2: loginByAuthorizeCode4Vesync - Exchanges authorizeCode for session token * 3. If cross-region detected, retries step 2 with correct region */ export default class VeSync { private readonly email; private readonly password; readonly config: PlatformConfig; readonly debugMode: DebugMode; readonly log: Logger; private api?; private accountId?; private token?; /** * Dynamic baseURL; starts from config/country and may flip on cross-region detection. * Automatically switches between US and EU hosts based on account region. */ private baseURL; /** * Track account country once known from login response. * Used to determine correct API host. */ private countryCode; /** * Device region (e.g., 'US', 'EU') from login response. */ private region?; private readonly VERSION; private readonly FULL_VERSION; private readonly AGENT; private readonly TIMEZONE; private readonly OS; private readonly BRAND; private readonly LANG; /** * Terminal/device identifier that VeSync expects to remain stable across sessions. * Generated once per instance and used for all API calls. */ private readonly terminalId; /** * Application ID used for authentication requests. * Randomly generated per instance. */ private readonly appID; /** * Simple login backoff to prevent hammering the API on repeated failures. * Starts at 10 seconds, doubles on each failure, caps at 5 minutes. */ private lastLoginAttempt; private loginBackoffMs; /** * Session persistence file path. * Stores authentication token and account info for faster re-authentication. */ private readonly sessionFilePath?; /** * Maximum age for session tokens (25 days). * Tokens older than this are considered invalid even if JWT doesn't specify expiration. */ private readonly TOKEN_MAX_AGE_MS; private readonly BYPASS_HEADER_UA; private readonly AUTH_APP_VERSION; private readonly AUTH_CLIENT_VERSION; private readonly AUTH_CLIENT_INFO; private readonly AUTH_OS_INFO; constructor(email: string, password: string, config: PlatformConfig, debugMode: DebugMode, log: Logger, sessionPath?: string); /** * Gets axios options for device API calls. * @returns Axios configuration with baseURL and timeout */ private AXIOS_OPTIONS; /** * Gets axios options for authentication API calls. * @param host - Optional host override (defaults to baseURL) * @returns Axios configuration with authentication headers */ private AUTH_AXIOS_OPTIONS; /** * Generates detail body for device API requests. * Contains app version, device info, and trace ID. * @returns Detail body object */ private generateDetailBody; /** * Generates base body for API requests. * @param includeAuth - Whether to include accountID and token * @returns Base body object with language, timezone, and optionally auth */ private generateBody; /** * Generates V2 bypass body for device control commands. * @param fan - The device to send command to * @param method - The bypass method to execute * @param data - Command-specific data payload * @returns V2 bypass body object */ private generateV2Body; /** * Generates a unique trace ID for authentication requests. * Format: APP{appID}{timestamp} * @returns Trace ID string */ private generateAuthTraceId; /** * Loads persisted session from disk if available and valid. * Validates token expiration and account match before returning. * * @returns Session data if valid, null otherwise */ private loadSessionFromDisk; /** * Saves current session to disk for faster re-authentication. * Includes token, account ID, country code, and expiration info. */ private saveSessionToDisk; /** * Checks if the current token is still valid. * Validates JWT expiration if present, or checks token age against max age. * * @returns true if token is valid, false if expired or missing */ private isTokenValid; /** * Builds and configures the axios API client with authentication headers. * Sets up automatic token refresh on 401 errors. * * @throws Error if token or accountId is missing */ private buildApiClient; /** * Handles device offline error response. * Checks if the response indicates device is offline and handles accordingly. * * @param responseMsg - The message from the API response (may be undefined) * @param returnValue - Value to return if showOffWhenDisconnected is enabled * @returns The returnValue if showOffWhenDisconnected is enabled and device is offline * @throws Error if showOffWhenDisconnected is disabled and device is offline * @returns undefined if device is not offline (caller should continue normal processing) */ private handleDeviceOffline; /** * Checks if the API response indicates quota exceeded error. * Logs a warning and returns true if quota is exceeded. * * @param responseCode - The error code from the API response * @param responseMsg - The error message from the API response * @returns true if quota is exceeded, false otherwise */ private handleQuotaExceeded; /** * Ensures the authentication token is valid before making API calls. * Proactively checks token expiration and refreshes if needed. * * @throws Error if token refresh fails or API client is unavailable */ private ensureValidToken; /** * Sends a control command to a device. * Thread-safe: Uses AsyncLock to prevent concurrent API calls. * Automatically refreshes token if expired before making the request. * * @param fan - The device to send command to * @param method - The bypass method to execute * @param body - Command-specific data payload * @returns true if command succeeded (code === 0), false otherwise * @throws Error if not logged in or device is unreachable (unless showOffWhenDisconnected is enabled) */ sendCommand(fan: VeSyncFan, method: BypassMethod, body?: {}): Promise<boolean>; /** * Gets current device state/info from the VeSync API. * Thread-safe: Uses AsyncLock to prevent concurrent API calls. * Automatically refreshes token if expired before making the request. * * @param fan - The device to get info for * @returns Device info response, or null if device is offline and showOffWhenDisconnected is enabled * @throws Error if not logged in or device is unreachable (unless showOffWhenDisconnected is enabled) */ getDeviceInfo(fan: VeSyncFan): Promise<DeviceInfoResponse | null>; /** * Starts an authentication session. * First attempts to reuse a persisted session from disk. * If no valid session exists, performs a fresh login. * * @returns true if session started successfully, false otherwise */ startSession(): Promise<boolean>; /** * Performs a two-step login flow with cross-region detection. * Step 1: Authenticates with email/password to get authorizeCode * Step 2: Exchanges authorizeCode for session token * If cross-region detected, automatically retries with correct region. * * Implements login backoff to prevent API abuse on failures. * * @returns true if login successful, false otherwise * @throws Error if email/password are missing */ private login; /** * Step 1 of authentication: Authenticates with email/password. * Returns an authorizeCode that is used in step 2 to get the session token. * Falls back to accountapi.vesync.com if smartapi fails. * * @param userCountryCode - Country code for the authentication request * @returns Object with authorizeCode and optional bizToken * @throws Error if authentication fails */ private authByPWDOrOTM; /** * Step 2 of authentication: Exchanges authorizeCode for session token. * May return a cross-region response indicating the account is in a different region. * * @param opts - Login options including country code, host, authorizeCode, etc. * @returns Login response with token and account info, or undefined on network error */ private loginByAuthorizeCode4Vesync; /** * Gets all supported humidifier devices from the VeSync account. * Filters devices to only include supported models (wifi-air type). * Thread-safe: Uses AsyncLock to prevent concurrent API calls. * * Token expiration is handled automatically by the axios interceptor. * * @returns Array of VeSyncFan instances for supported devices */ getDevices(): Promise<VeSyncFan[]>; } export {}; //# sourceMappingURL=VeSync.d.ts.map