import { UnifiedDevice, UnifiedDeviceFactory, DeviceProtocol } from './unified-device-factory'; import unifiedDiscover, { UnifiedDiscoveryConfig } from './unified-discovery'; import { TapoLightState } from './lightstate/tapo-lightstate'; import { KasaLightState } from './lightstate/kasa-lightstate'; import { TapoApi } from './protocols/tapo-api'; export interface UnifiedApiConfig { email?: string; password?: string; token?: string; timeout?: number; httpTimeout?: number; } export class UnifiedTpLinkApi { private config: UnifiedApiConfig; private deviceFactory: UnifiedDeviceFactory; private discoveredDevices: Map = new Map(); constructor(config: UnifiedApiConfig = {}) { this.config = config; this.deviceFactory = new UnifiedDeviceFactory(config); } // Discover all TP-Link devices (both Kasa and Tapo) async discover(options: UnifiedDiscoveryConfig = {}): Promise<{ kasaDevices: any; tapoDevices: any[]; allDevices: UnifiedDevice[]; }> { const discoveryConfig = { ...this.config, ...options, }; const result = await unifiedDiscover(discoveryConfig); // Store discovered devices for easy access this.discoveredDevices.clear(); result.allDevices.forEach(device => { this.discoveredDevices.set(device.id, device); }); return result; } // Get a device by ID getDevice(deviceId: string): UnifiedDevice | undefined { return this.discoveredDevices.get(deviceId); } // Get all discovered devices getAllDevices(): UnifiedDevice[] { return Array.from(this.discoveredDevices.values()); } // Get devices by protocol getDevicesByProtocol(protocol: DeviceProtocol): UnifiedDevice[] { return this.getAllDevices().filter(device => device.protocol === protocol); } // Get devices by type getDevicesByType(deviceType: string): UnifiedDevice[] { return this.getAllDevices().filter(device => device.deviceType.includes(deviceType)); } // Set power state for any device async setPower(deviceId: string, power: boolean): Promise { const device = this.getDevice(deviceId); if (!device) { throw new Error(`Device ${deviceId} not found`); } return await this.deviceFactory.setPower(device, power); } // Turn device on async turnOn(deviceId: string): Promise { return await this.setPower(deviceId, true); } // Turn device off async turnOff(deviceId: string): Promise { return await this.setPower(deviceId, false); } // Set light state (for bulbs and light strips) async setLightState(deviceId: string, state: any): Promise { const device = this.getDevice(deviceId); if (!device) { throw new Error(`Device ${deviceId} not found`); } return await this.deviceFactory.setLightState(device, state); } // Set brightness (0-100) async setBrightness(deviceId: string, brightness: number): Promise { return await this.setLightState(deviceId, { brightness }); } // Set color using RGB values async setRgb(deviceId: string, r: number, g: number, b: number): Promise { return await this.setLightState(deviceId, { rgb: [r, g, b] }); } // Set color using HSL values async setHsl(deviceId: string, h: number, s: number, l: number): Promise { const device = this.getDevice(deviceId); if (!device) { throw new Error(`Device ${deviceId} not found`); } if (device.protocol === DeviceProtocol.TAPO) { // Use Tapo HSL method const lightState = new TapoLightState(); lightState.hsl(h, s, l); return await this.deviceFactory.setLightState(device, lightState.getValues()); } else { // Convert HSL to RGB for Kasa devices const rgb = this.hslToRgb(h / 360, s / 100, l / 100); return await this.setRgb(deviceId, rgb[0], rgb[1], rgb[2]); } } // Set color temperature async setColorTemperature(deviceId: string, colorTemp: number): Promise { return await this.setLightState(deviceId, { colorTemperature: colorTemp }); } // Get device information async getDeviceInfo(deviceId: string): Promise { const device = this.getDevice(deviceId); if (!device) { throw new Error(`Device ${deviceId} not found`); } return await this.deviceFactory.getDeviceInfo(device); } // Get energy usage (for compatible devices) async getEnergyUsage(deviceId: string): Promise { const device = this.getDevice(deviceId); if (!device) { throw new Error(`Device ${deviceId} not found`); } return await this.deviceFactory.getEnergyUsage(device); } // Setup Tapo devices for communication async setupTapoDevices(devices: Array<{ id: string; host: string }>): Promise> { return await this.deviceFactory.setupTapoDevices(devices); } // Convenience method to create light states createTapoLightState(initialState?: any): TapoLightState { return new TapoLightState(initialState); } createKasaLightState(initialState?: any): KasaLightState { return new KasaLightState(initialState); } // Get the appropriate light state class for a device getLightStateClass(deviceId: string): typeof TapoLightState | typeof KasaLightState | null { const device = this.getDevice(deviceId); if (!device) { return null; } return device.protocol === DeviceProtocol.TAPO ? TapoLightState : KasaLightState; } // Helper method to convert HSL to RGB private hslToRgb(h: number, s: number, l: number): [number, number, number] { let r, g, b; if (s === 0) { r = g = b = l; // achromatic } else { const hue2rgb = (p: number, q: number, t: number) => { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1/6) return p + (q - p) * 6 * t; if (t < 1/2) return q; if (t < 2/3) return p + (q - p) * (2/3 - t) * 6; return p; }; const q = l < 0.5 ? l * (1 + s) : l + s - l * s; const p = 2 * l - q; r = hue2rgb(p, q, h + 1/3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1/3); } return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; } // Get protocol-specific API instances getTapoApi(): TapoApi | null { return this.deviceFactory['tapoApi'] || null; } // Static method to detect device protocol static detectDeviceProtocol(deviceInfo: any): DeviceProtocol { return UnifiedDeviceFactory.detectProtocol(deviceInfo); } // Static method to create unified device static createDevice(deviceInfo: any, protocol?: DeviceProtocol): UnifiedDevice { return UnifiedDeviceFactory.createUnifiedDevice(deviceInfo, protocol); } }