feat: Implement Tapo P110/P115 power and energy monitoring, add Tapo device testing utilities, and include a database upsert test.

This commit is contained in:
sebseb7
2026-01-22 01:17:46 -05:00
parent 22050d1350
commit d093e18877
5 changed files with 279 additions and 12 deletions

View File

@@ -320,6 +320,22 @@ class TapoDevice {
throw new Error(`get_child_device_list failed: ${response.error_code}`);
}
async getCurrentPower() {
const response = await this.request('get_current_power');
if (response.error_code === 0) {
return response.result;
}
throw new Error(`get_current_power failed: ${response.error_code}`);
}
async getEnergyUsage() {
const response = await this.request('get_energy_usage');
if (response.error_code === 0) {
return response.result;
}
throw new Error(`get_energy_usage failed: ${response.error_code}`);
}
async turnOn() {
const response = await this.request('set_device_info', { device_on: true });
return response.error_code === 0;
@@ -661,9 +677,9 @@ class TapoManager {
}
// On time (how long has it been on)
if (typeof deviceInfo.on_time !== 'undefined') {
this.onDeviceStateChange(mac, 'switch:0', 'on_time', 'range', deviceInfo.on_time, deviceInfo);
}
// if (typeof deviceInfo.on_time !== 'undefined') {
// this.onDeviceStateChange(mac, 'switch:0', 'on_time', 'range', deviceInfo.on_time, deviceInfo);
// }
// Signal strength
if (typeof deviceInfo.rssi !== 'undefined') {
@@ -679,6 +695,28 @@ class TapoManager {
if (typeof deviceInfo.power_protection_status !== 'undefined') {
this.onDeviceStateChange(mac, 'power', 'protection_status', 'enum', deviceInfo.power_protection_status, deviceInfo);
}
// Power Monitoring for P110/P115
if (info.model && (info.model.includes('P110') || info.model.includes('P115'))) {
try {
const powerData = await client.getCurrentPower();
if (powerData && typeof powerData.current_power !== 'undefined') {
// current_power is in mW, convert to W for Shelly compatibility usually or keep as is?
// Shelly usually reports W. Tapo P110 returns current_power in mW.
const powerWatts = powerData.current_power / 1000.0;
this.onDeviceStateChange(mac, 'power:0', 'apower', 'range', powerWatts, deviceInfo);
}
const energyData = await client.getEnergyUsage();
if (energyData && typeof energyData.today_energy !== 'undefined') {
// today_energy is in Wh
this.onDeviceStateChange(mac, 'power:0', 'aenergy', 'range', energyData.today_energy, deviceInfo);
}
} catch (err) {
// Ignore power poll errors, don't fail the whole poll
console.error(`[Tapo] Error polling power for ${mac}:`, err.message);
}
}
}
} catch (e) {