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
259 lines • 9.11 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.P100Plug = void 0;
const types_1 = require("../../types");
const unified_protocol_1 = require("../../core/unified-protocol");
/**
* P100 Smart Plug - Basic plug without energy monitoring
*/
class P100Plug extends types_1.BaseTapoDevice {
constructor(ip, credentials) {
super(ip, credentials);
this.featureCache = new Map();
this.requestQueue = Promise.resolve();
this.unifiedProtocol = new unified_protocol_1.UnifiedTapoProtocol(ip, credentials);
}
async checkDeviceConnectivity() {
try {
const response = await fetch(`http://${this.ip}`, {
method: 'HEAD',
signal: AbortSignal.timeout(5000)
});
return response.status !== 0;
}
catch (error) {
console.log('Device connectivity check failed:', error);
return false;
}
}
async connect() {
console.log('P100Plug.connect() called - using unified protocol');
// Check basic device connectivity first
console.log('Checking device connectivity...');
const isReachable = await this.checkDeviceConnectivity();
if (!isReachable) {
throw new Error(`Device at ${this.ip} is not reachable. Check IP address and network connectivity.`);
}
console.log('Device is reachable, proceeding with unified protocol connection...');
try {
await this.unifiedProtocol.connect();
console.log(`Connected successfully using ${this.unifiedProtocol.getActiveProtocol()} protocol`);
}
catch (error) {
console.error('Unified protocol connection failed:', error);
throw error;
}
}
async disconnect() {
try {
await this.unifiedProtocol.disconnect();
}
catch (error) {
console.warn('Warning during disconnect:', error);
}
}
/**
* Check if device is currently authenticated
*/
isAuthenticated() {
return this.unifiedProtocol.isConnected();
}
async getDeviceInfo() {
var _a;
const request = {
method: 'get_device_info'
};
const response = await this.sendRequest(request);
const rawData = response.result;
// Transform raw data to match interface expectations
const deviceInfo = {
...rawData,
// Ensure required fields are properly set
on_time: rawData.on_time || 0,
overheated: rawData.overheated || false,
// Computed properties for backward compatibility
deviceId: rawData.device_id,
deviceOn: rawData.device_on,
onTime: rawData.on_time || 0,
fwVer: rawData.fw_ver,
hwVer: rawData.hw_ver,
// Base interface properties
deviceType: 'SMART.TAPOPLUG',
type: 'SMART.TAPOPLUG',
region: ((_a = rawData.lang) === null || _a === void 0 ? void 0 : _a.split('_')[1]) || 'US',
specs: '',
rssi: 0,
signalLevel: 0
};
// Cache device model for feature detection
this.deviceModel = deviceInfo.model;
return deviceInfo;
}
/**
* Check if the device supports energy monitoring features
* P100 does not support energy monitoring
*/
async hasEnergyMonitoring() {
const cacheKey = 'energy_monitoring';
if (this.featureCache.has(cacheKey)) {
return this.featureCache.get(cacheKey);
}
// P100 does not support energy monitoring
this.featureCache.set(cacheKey, false);
return false;
}
/**
* Check if the device supports a specific feature
*/
async supportsFeature(feature) {
switch (feature) {
case 'energy_monitoring':
return this.hasEnergyMonitoring();
case 'schedule':
return true; // Most Tapo devices support scheduling
case 'countdown':
return true; // Most Tapo devices support countdown
default:
return false;
}
}
async turnOn() {
const request = {
method: 'set_device_info',
params: {
device_on: true
}
};
await this.sendRequest(request);
}
async turnOff() {
const request = {
method: 'set_device_info',
params: {
device_on: false
}
};
await this.sendRequest(request);
}
async toggle() {
const deviceInfo = await this.getDeviceInfo();
if (deviceInfo.device_on) {
await this.turnOff();
}
else {
await this.turnOn();
}
}
// Convenience aliases following Python API pattern
async on() {
await this.turnOn();
}
async off() {
await this.turnOff();
}
async isOn() {
const deviceInfo = await this.getDeviceInfo();
return deviceInfo.device_on;
}
async getUsageInfo(options = {}) {
const { throwOnUnsupported = true } = options;
if (throwOnUnsupported) {
throw new types_1.FeatureNotSupportedError('energy_monitoring', this.deviceModel || 'P100', 'P100 devices do not support energy monitoring features');
}
else {
// Return empty/default usage info when not throwing
return {
todayRuntime: 0,
monthRuntime: 0,
todayEnergy: 0,
monthEnergy: 0,
currentPower: 0
};
}
}
/**
* Get usage info using Result pattern for better error handling
*/
async getUsageInfoResult() {
try {
const data = await this.getUsageInfo({ throwOnUnsupported: true });
return { success: true, data };
}
catch (error) {
if (error instanceof types_1.FeatureNotSupportedError || error instanceof types_1.DeviceCapabilityError) {
return { success: false, error };
}
// Re-throw unexpected errors
throw error;
}
}
async getCurrentPower(options = {}) {
const { throwOnUnsupported = true } = options;
if (throwOnUnsupported) {
throw new types_1.FeatureNotSupportedError('energy_monitoring', this.deviceModel || 'P100', 'P100 devices do not support current power monitoring');
}
return 0;
}
async getTodayEnergy(options = {}) {
const { throwOnUnsupported = true } = options;
if (throwOnUnsupported) {
throw new types_1.FeatureNotSupportedError('energy_monitoring', this.deviceModel || 'P100', 'P100 devices do not support energy monitoring');
}
return 0;
}
async getMonthEnergy(options = {}) {
const { throwOnUnsupported = true } = options;
if (throwOnUnsupported) {
throw new types_1.FeatureNotSupportedError('energy_monitoring', this.deviceModel || 'P100', 'P100 devices do not support energy monitoring');
}
return 0;
}
async getTodayRuntime(options = {}) {
const { throwOnUnsupported = true } = options;
if (throwOnUnsupported) {
throw new types_1.FeatureNotSupportedError('energy_monitoring', this.deviceModel || 'P100', 'P100 devices do not support runtime monitoring');
}
return 0;
}
async getMonthRuntime(options = {}) {
const { throwOnUnsupported = true } = options;
if (throwOnUnsupported) {
throw new types_1.FeatureNotSupportedError('energy_monitoring', this.deviceModel || 'P100', 'P100 devices do not support runtime monitoring');
}
return 0;
}
async isOverheated() {
const deviceInfo = await this.getDeviceInfo();
return deviceInfo.overheated || false;
}
async getOnTime() {
const deviceInfo = await this.getDeviceInfo();
return deviceInfo.on_time || 0;
}
async setDeviceInfo(params) {
const request = {
method: 'set_device_info',
params
};
await this.sendRequest(request);
}
async sendRequest(request) {
// Use sequential request queue to prevent KLAP session conflicts (like Python tapo)
return this.requestQueue = this.requestQueue.then(async () => {
try {
// Use unified protocol with improved session management
const result = await this.unifiedProtocol.executeRequest(request);
return {
error_code: 0,
result
};
}
catch (error) {
console.error(`Request ${request.method} failed:`, error);
throw error;
}
});
}
}
exports.P100Plug = P100Plug;
//# sourceMappingURL=p100-plug.js.map