node-red-contrib-tplink-tapo-connect-api
Version:
This unofficial node-RED node allows connection to TP-Link Tapo devices. This project has been enhanced with AI support to enable new features. Starting with v0.50, we have added support for the KLAP protocol. To prioritize the operation of this node, we
129 lines • 5.53 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DeviceFactory = void 0;
const generic_device_info_1 = require("../devices/generic-device-info");
const device_common_1 = require("../types/device-common");
const plug_device_1 = require("../devices/plug-device");
const bulb_device_1 = require("../devices/bulb-device");
/**
* Factory class for creating appropriate Tapo device instances
* Handles automatic device type detection and caching for optimal performance
*/
class DeviceFactory {
/**
* Get device information using lightweight generic retriever
* @param ip Device IP address
* @param credentials Authentication credentials
* @param useCache Whether to use cached results (default: true)
* @returns Device information
*/
static async getDeviceInfo(ip, credentials, useCache = true) {
const cacheKey = `${ip}-${credentials.username}`;
// Check cache for existing device info
if (useCache && this.genericInfoCache.has(cacheKey)) {
const cached = this.genericInfoCache.get(cacheKey);
if (Date.now() - cached.timestamp < this.CACHE_TTL) {
return cached.info;
}
this.genericInfoCache.delete(cacheKey);
}
// Retrieve device information using generic retriever
const infoRetriever = new generic_device_info_1.GenericDeviceInfoRetriever(ip, credentials);
try {
await infoRetriever.connect();
const deviceInfo = await infoRetriever.getDeviceInfo();
// Cache the retrieved device information
if (useCache) {
this.genericInfoCache.set(cacheKey, {
info: deviceInfo,
timestamp: Date.now()
});
}
return deviceInfo;
}
finally {
await infoRetriever.disconnect();
}
}
/**
* Create device instance with automatic device type detection
* Always detects the device type first, then creates the appropriate device instance
* @param ip Device IP address
* @param credentials Authentication credentials
* @param methodHint Optional method hint for better type inference (fallback only)
* @returns Device instance
*/
static async createDevice(ip, credentials, methodHint) {
try {
// Always get device info first to determine the correct device type
const deviceInfo = await this.getDeviceInfo(ip, credentials);
const actualDeviceType = (0, device_common_1.inferTapoDeviceType)(deviceInfo);
return this.createSpecificDevice(actualDeviceType, ip, credentials);
}
catch (error) {
// Fallback to method hint or UNKNOWN if device info retrieval fails
const fallbackType = methodHint ? this.getDeviceTypeForMethod(methodHint) : 'UNKNOWN';
return this.createSpecificDevice(fallbackType, ip, credentials);
}
}
/**
* Create specific device instance based on device type
* @param deviceType Specific device type
* @param ip Device IP address
* @param credentials Authentication credentials
* @returns Device instance
*/
static createSpecificDevice(deviceType, ip, credentials) {
// Handle unknown device type
if (deviceType === 'UNKNOWN') {
throw new Error(`Unknown device type for device at ${ip}. Device model could not be determined. Please check device compatibility or update the device model mapping.`);
}
// Determine if device is a bulb or plug
const bulbModels = ['L510', 'L520', 'L530', 'L535', 'L610', 'L630', 'L900', 'L920', 'L930'];
const isBulb = bulbModels.includes(deviceType);
if (isBulb) {
return new bulb_device_1.BulbDevice(ip, credentials, deviceType);
}
else {
// All other known devices are treated as plugs (P100, P105, P110, P115, etc.)
return new plug_device_1.PlugDevice(ip, credentials, deviceType);
}
}
/**
* Clear the device info cache
*/
static clearDeviceInfoCache() {
this.genericInfoCache.clear();
}
static getDeviceTypeForMethod(method) {
// Basic control methods suggest plug devices
if (method === 'basic_control') {
return 'P100'; // Default basic plug
}
// Energy monitoring methods require P110/P115
if (method === 'getEnergyUsage' || method === 'getCurrentPower') {
return 'P110';
}
// Brightness/color methods require bulb devices
if (method === 'setBrightness') {
return 'L510'; // L510 supports brightness
}
if (method === 'setColor' || method === 'setColorRGB' || method === 'setNamedColor') {
return 'L530'; // L530 supports full color
}
if (method === 'setColorTemperature') {
return 'L520'; // L520/L530 support color temperature
}
if (method === 'setLightEffect') {
return 'L530'; // Only L530 supports effects
}
// Default to UNKNOWN for unknown methods
return 'UNKNOWN';
}
}
exports.DeviceFactory = DeviceFactory;
/** Device information cache to minimize redundant API calls */
DeviceFactory.genericInfoCache = new Map();
/** Cache TTL in milliseconds (30 seconds) */
DeviceFactory.CACHE_TTL = 30000;
//# sourceMappingURL=device-factory.js.map