/// /// /// /// import { RemoteInfo, Socket } from 'dgram'; import { EventEmitter } from 'events'; import type log from 'loglevel'; import type { MarkOptional } from 'ts-essentials'; import Bulb from './bulb'; import { type Sysinfo } from './device'; import { type Logger } from './logger'; import Plug from './plug'; export type AnyDevice = Bulb | Plug; export type DeviceDiscovery = { status: string; seenOnDiscovery: number; }; export type AnyDeviceDiscovery = (Bulb | Plug) & Partial; export type AnyDeviceOptionsConstructable = MarkOptional[0], 'client' | 'sysInfo'> | MarkOptional[0], 'client' | 'sysInfo'>; export type DeviceOptionsDiscovery = MarkOptional[0], 'client' | 'sysInfo' | 'host'> | MarkOptional[0], 'client' | 'sysInfo' | 'host'>; export type DiscoveryDevice = { host: string; port?: number; }; export interface ClientConstructorOptions { /** * @defaultValue \{ * timeout: 10000, * transport: 'tcp', * useSharedSocket: false, * sharedSocketTimeout: 20000 * \} */ defaultSendOptions?: SendOptions; /** * @defaultValue 'warn' */ logLevel?: log.LogLevelDesc; logger?: Logger; } export interface DiscoveryOptions { /** * address to bind udp socket */ address?: string; /** * port to bind udp socket */ port?: number; /** * broadcast address * @defaultValue '255.255.255.255' */ broadcast?: string; /** * Interval in (ms) * @defaultValue 10000 */ discoveryInterval?: number; /** * Timeout in (ms) * @defaultValue 0 */ discoveryTimeout?: number; /** * Number of consecutive missed replies to consider offline * @defaultValue 3 */ offlineTolerance?: number; deviceTypes?: Array<'plug' | 'bulb'>; /** * MAC will be normalized, comparison will be done after removing special characters (`:`,`-`, etc.) and case insensitive, glob style *, and ? in pattern are supported * @defaultValue [] */ macAddresses?: string[]; /** * MAC will be normalized, comparison will be done after removing special characters (`:`,`-`, etc.) and case insensitive, glob style *, and ? in pattern are supported * @defaultValue [] */ excludeMacAddresses?: string[]; /** * called with fn(sysInfo), return truthy value to include device */ filterCallback?: (sysInfo: Sysinfo) => boolean; /** * if device has multiple outlets, create a separate plug for each outlet, otherwise create a plug for the main device * @defaultValue true */ breakoutChildren?: boolean; /** * Set device port to the port it responded with to the discovery ping * @defaultValue false */ devicesUseDiscoveryPort?: boolean; /** * passed to device constructors */ deviceOptions?: DeviceOptionsDiscovery; /** * known devices to query instead of relying only on broadcast */ devices?: DiscoveryDevice[]; } /** * Send Options. * * @typeParam timeout - (ms) * @typeParam transport - 'tcp','udp' * @typeParam useSharedSocket - attempt to reuse a shared socket if available, UDP only * @typeParam sharedSocketTimeout - (ms) how long to wait for another send before closing a shared socket. 0 = never automatically close socket */ export type SendOptions = { timeout?: number; transport?: 'tcp' | 'udp'; useSharedSocket?: boolean; sharedSocketTimeout?: number; }; export interface ClientEvents { /** * First response from device. */ 'device-new': (device: Bulb | Plug) => void; /** * Follow up response from device. */ 'device-online': (device: Bulb | Plug) => void; /** * No response from device. */ 'device-offline': (device: Bulb | Plug) => void; /** * First response from Bulb. */ 'bulb-new': (device: Bulb) => void; /** * Follow up response from Bulb. */ 'bulb-online': (device: Bulb) => void; /** * No response from Bulb. */ 'bulb-offline': (device: Bulb) => void; /** * First response from Plug. */ 'plug-new': (device: Plug) => void; /** * Follow up response from Plug. */ 'plug-online': (device: Plug) => void; /** * No response from Plug. */ 'plug-offline': (device: Plug) => void; /** * Invalid/Unknown response from device. */ 'discovery-invalid': ({ rinfo, response, decryptedResponse, }: { rinfo: RemoteInfo; response: Buffer; decryptedResponse: Buffer; }) => void; /** * Error during discovery. */ error: (error: Error) => void; } declare interface Client { on(event: U, listener: ClientEvents[U]): this; emit(event: U, ...args: Parameters): boolean; } /** * Client that sends commands to specified devices or discover devices on the local subnet. * - Contains factory methods to create devices. * - Events are emitted after {@link Client#startDiscovery} is called. * @noInheritDoc */ declare class Client extends EventEmitter { defaultSendOptions: Required; log: Logger; devices: Map; discoveryTimer: NodeJS.Timeout | null; discoveryPacketSequence: number; maxSocketId: number; socket?: Socket; isSocketBound: boolean; constructor(options?: ClientConstructorOptions); /** * Used by `tplink-connection` * @internal */ getNextSocketId(): number; /** * {@link https://github.com/plasticrake/tplink-smarthome-crypto | Encrypts} `payload` and sends to device. * - If `payload` is not a string, it is `JSON.stringify`'d. * - Promise fulfills with encrypted string response. * * Devices use JSON to communicate.\ * For Example: * - If a device receives: * - `{"system":{"get_sysinfo":{}}}` * - It responds with: * ``` * {"system":{"get_sysinfo":{ * err_code: 0, * sw_ver: "1.0.8 Build 151113 Rel.24658", * hw_ver: "1.0", * ... * }}} * ``` * * All responses from device contain an `err_code` (`0` is success). * * @returns decrypted string response */ send(payload: Record | string, host: string, port?: number, sendOptions?: SendOptions): Promise; /** * Requests `{system:{get_sysinfo:{}}}` from device. * * @returns parsed JSON response * @throws {@link ResponseError} * @throws Error */ getSysInfo(host: string, port?: number, sendOptions?: SendOptions): Promise; /** * Creates Bulb object. * * See [Device constructor]{@link Device} and [Bulb constructor]{@link Bulb} for valid options. * @param deviceOptions - passed to [Bulb constructor]{@link Bulb} */ getBulb(deviceOptions: MarkOptional[0], 'client'>): Bulb; /** * Creates {@link Plug} object. * * See [Device constructor]{@link Device} and [Plug constructor]{@link Plug} for valid options. * @param deviceOptions - passed to [Plug constructor]{@link Plug} */ getPlug(deviceOptions: MarkOptional[0], 'client'>): Plug; /** * Creates a {@link Plug} or {@link Bulb} from passed in sysInfo or after querying device to determine type. * * See [Device constructor]{@link Device}, [Bulb constructor]{@link Bulb}, [Plug constructor]{@link Plug} for valid options. * @param deviceOptions - passed to [Device constructor]{@link Device} * @throws {@link ResponseError} */ getDevice(deviceOptions: AnyDeviceOptionsConstructable, sendOptions?: SendOptions): Promise; /** * Creates device corresponding to the provided `sysInfo`. * * See [Device constructor]{@link Device}, [Bulb constructor]{@link Bulb}, [Plug constructor]{@link Plug} for valid options * @param deviceOptions - passed to device constructor * @throws Error */ getDeviceFromSysInfo(sysInfo: Sysinfo, deviceOptions: AnyDeviceOptionsConstructable): AnyDevice; /** * Guess the device type from provided `sysInfo`. * * Based on sysinfo.[type|mic_type] */ getTypeFromSysInfo(sysInfo: { type: string; } | { mic_type: string; }): 'plug' | 'bulb' | 'device'; /** * Discover TP-Link Smarthome devices on the network. * * - Sends a discovery packet (via UDP) to the `broadcast` address every `discoveryInterval`(ms). * - Stops discovery after `discoveryTimeout`(ms) (if `0`, runs until {@link Client.stopDiscovery} is called). * - If a device does not respond after `offlineTolerance` number of attempts, {@link ClientEvents.device-offline} is emitted. * - If `deviceTypes` are specified only matching devices are found. * - If `macAddresses` are specified only devices with matching MAC addresses are found. * - If `excludeMacAddresses` are specified devices with matching MAC addresses are excluded. * - if `filterCallback` is specified only devices where the callback returns a truthy value are found. * - If `devices` are specified it will attempt to contact them directly in addition to sending to the broadcast address. * - `devices` are specified as an array of `[{host, [port: 9999]}]`. * @fires Client#error * @fires Client#device-new * @fires Client#device-online * @fires Client#device-offline * @fires Client#bulb-new * @fires Client#bulb-online * @fires Client#bulb-offline * @fires Client#plug-new * @fires Client#plug-online * @fires Client#plug-offline * @fires Client#discovery-invalid */ startDiscovery(options?: DiscoveryOptions): this; private static setSysInfoForDevice; private createOrUpdateDeviceFromSysInfo; /** * Stops discovery and closes UDP socket. */ stopDiscovery(): void; private sendDiscovery; } export default Client; //# sourceMappingURL=client.d.ts.map