From fc50bc08c3a94a2d1cbbb9e87e7199f9cf28b79e Mon Sep 17 00:00:00 2001 From: Andreas Zimnas Date: Wed, 9 Oct 2024 14:02:05 +0300 Subject: [PATCH] reauthenticate on 403 fixes for power consumption --- .DS_Store | Bin 8196 -> 8196 bytes package-lock.json | 26 +++++++++++++++++++ package.json | 4 +-- src/platformL530Accessory.ts | 38 +++++++++++++++++----------- src/platformP110Accessory.ts | 14 +++++++++-- src/utils/l530.ts | 8 ++++-- src/utils/p100.ts | 47 ++++++++++++++++++++++++++++------- src/utils/p110.ts | 4 +-- 8 files changed, 110 insertions(+), 31 deletions(-) diff --git a/.DS_Store b/.DS_Store index d8048f4f50eff2e56730fcd9a5e881295bf99817..03b32c58ce2c2798141887911502518add28d3a8 100644 GIT binary patch delta 106 zcmZp1XmQw}CJ_5uoPmLXg+Y%YogtH=22" } }, + "node_modules/luxon": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", + "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", diff --git a/package.json b/package.json index e5fff04..faa5ebc 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,7 @@ "displayName": "Tapo P100 Plugin", "name": "homebridge-tapo", "type": "module", - "private": true, - "version": "1.5.2-beta0", + "version": "1.5.2-beta2", "description": "Homebridge Plugin for TP-Link Tapo P100 Plugs", "license": "Apache-2.0", "homepage": "https://github.com/apatsufas/homebridge-tapo-p100#readme", @@ -38,6 +37,7 @@ ], "dependencies": { "axios": "^1.7.7", + "cron": "^3.1.7", "fakegato-history": "^0.6.5", "lodash.defaults": "^4.2.0", "utf8": "^3.0.0", diff --git a/src/platformL530Accessory.ts b/src/platformL530Accessory.ts index 88f51f3..1c0ab43 100644 --- a/src/platformL530Accessory.ts +++ b/src/platformL530Accessory.ts @@ -12,7 +12,6 @@ import { TPLinkPlatformAccessory } from './platformTPLinkAccessory.js'; export class L530Accessory extends TPLinkPlatformAccessory { private adaptiveLightingController!: AdaptiveLightingController; private readonly fakeGatoHistoryService?; - private lastMeasurement: number | null = null; constructor( public readonly log: Logger, @@ -87,11 +86,26 @@ export class L530Accessory extends TPLinkPlatformAccessory { .on('set', this.setSaturation.bind(this)) // SET - bind to the `setSaturation` method below .on('get', this.getSaturation.bind(this)); // GET - bind to the `getSaturation` method below + this.service.addOptionalCharacteristic(this.platform.customCharacteristics.CurrentConsumptionCharacteristic); + this.service.getCharacteristic(this.platform.customCharacteristics.CurrentConsumptionCharacteristic) + .on('get', this.getCurrentConsumption.bind(this)); + + this.service.addOptionalCharacteristic(this.platform.customCharacteristics.TotalConsumptionCharacteristic); + this.service.getCharacteristic(this.platform.customCharacteristics.TotalConsumptionCharacteristic) + .on('get', this.getTotalConsumption.bind(this)); + + /* this.service.addOptionalCharacteristic(this.platform.customCharacteristics.ResetConsumptionCharacteristic); + this.service.getCharacteristic(this.platform.customCharacteristics.ResetConsumptionCharacteristic) + .on('set', this.resetConsumption.bind(this));*/ + // Setup the adaptive lighting controller if available if (this.platform.api.versionGreaterOrEqual && this.platform.api.versionGreaterOrEqual('1.3.0-beta.23')) { this.log.debug('Enabling Adaptvie Lightning'); this.adaptiveLightingController = new platform.api.hap.AdaptiveLightingController( - this.service, + this.service, { + controllerMode: + this.platform.api.hap.AdaptiveLightingControllerMode.AUTOMATIC, + }, ); this.accessory.configureController(this.adaptiveLightingController); } @@ -344,23 +358,19 @@ export class L530Accessory extends TPLinkPlatformAccessory { this.tpLinkAccessory.getEnergyUsage().then((response) => { this.log.debug('Get Characteristic Power consumption ->', JSON.stringify(response)); if (response && response.power_usage) { - if(this.lastMeasurement){ - this.log.debug('Get Characteristic Power consumption ->', JSON.stringify(response)); - if (this.fakeGatoHistoryService ) { - this.fakeGatoHistoryService.addEntry({ - time: new Date().getTime() / 1000, - power: response.power_usage.today > 0 ? response.power_usage.today - this.lastMeasurement > 0 ? - response.power_usage.today - this.lastMeasurement : 0 : 0, - }); - } + this.log.debug('Get Characteristic Power consumption ->', JSON.stringify(response)); + if (this.fakeGatoHistoryService ) { + this.fakeGatoHistoryService.addEntry({ + time: new Date().getTime() / 1000, + power: this.tpLinkAccessory.getPowerConsumption().current, + }); } - this.lastMeasurement = response.power_usage.today; } }); setTimeout(()=>{ this.updateConsumption(); - }, 300000); + }, 600000); } /** @@ -415,7 +425,7 @@ export class L530Accessory extends TPLinkPlatformAccessory { this.log.debug('updateState called'); this.tpLinkAccessory.getDeviceInfo(true).then((response) => { if(response){ - this.log.info('Device Info: ' + JSON.stringify(response)); + this.log.debug('Device Info: ' + JSON.stringify(response)); const isOn = response.device_on; const saturation = response.saturation; const hue = response.hue; diff --git a/src/platformP110Accessory.ts b/src/platformP110Accessory.ts index ff32b89..12c28f3 100644 --- a/src/platformP110Accessory.ts +++ b/src/platformP110Accessory.ts @@ -56,6 +56,14 @@ export class P110Accessory extends TPLinkPlatformAccessory{ .on('set', this.setOn.bind(this)) // SET - bind to the `setOn` method below .on('get', this.getOn.bind(this)); // GET - bind to the `getOn` method below + this.service.addOptionalCharacteristic(this.platform.customCharacteristics.CurrentConsumptionCharacteristic); + this.service.getCharacteristic(this.platform.customCharacteristics.CurrentConsumptionCharacteristic) + .on('get', this.getCurrentConsumption.bind(this)); + + this.service.addOptionalCharacteristic(this.platform.customCharacteristics.TotalConsumptionCharacteristic); + this.service.getCharacteristic(this.platform.customCharacteristics.TotalConsumptionCharacteristic) + .on('get', this.getTotalConsumption.bind(this)); + this.updateConsumption(); const interval = updateInterval ? updateInterval*1000 : 10000; @@ -69,19 +77,21 @@ export class P110Accessory extends TPLinkPlatformAccessory{ } private updateConsumption(){ + this.log.debug('updateConsumption called'); this.tpLinkAccessory.getEnergyUsage().then((response) => { + this.log.debug('Get Characteristic Power consumption ->', JSON.stringify(response)); if (this.fakeGatoHistoryService && response && response.current_power) { this.platform.log.debug('Get Characteristic Power consumption ->', response.current_power); this.fakeGatoHistoryService.addEntry({ time: new Date().getTime() / 1000, - power: response.current_power, + power: this.tpLinkAccessory.getPowerConsumption().current, }); } }); setTimeout(()=>{ this.updateConsumption(); - }, 300000); + }, 600000); } /** diff --git a/src/utils/l530.ts b/src/utils/l530.ts index 44361da..94863aa 100644 --- a/src/utils/l530.ts +++ b/src/utils/l530.ts @@ -74,7 +74,7 @@ export default class L530 extends L520E { if(response && response.result){ this._consumption = { total: response.result.power_usage.today / 1000, - current: this._consumption ? response.result.power_usage.today - this._consumption.current : 0, + current: this._consumption ? response.result.power_usage.today / this.toHours(response.result.time_usage.today) : 0, }; } else{ this._consumption = { @@ -100,7 +100,7 @@ export default class L530 extends L520E { if(response && response.result){ this._consumption = { total: response.result.power_usage.today / 1000, - current: this._consumption ? response.result.power_usage.today - this._consumption.current : 0, + current: this._consumption ? response.result.power_usage.today / this.toHours(response.result.time_usage.today) : 0, }; } else{ this._consumption = { @@ -127,4 +127,8 @@ export default class L530 extends L520E { public getPowerConsumption():ConsumptionInfo{ return this._consumption; } + + private toHours(minutes: number):number{ + return minutes/60; + } } \ No newline at end of file diff --git a/src/utils/p100.ts b/src/utils/p100.ts index b5abbfc..e849bbc 100644 --- a/src/utils/p100.ts +++ b/src/utils/p100.ts @@ -24,6 +24,7 @@ export default class P100 implements TpLinkAccessory{ private publicKey!: string; protected ip: string; protected cookie!: string; + protected tplink_timeout!: number; protected token!: string; protected terminalUUID: string; private _plugSysInfo!: PlugSysinfo; @@ -168,8 +169,8 @@ export default class P100 implements TpLinkAccessory{ .then((res: AxiosResponse) => { this.log.debug('Received Handshake P100 on host response: ' + this.ip); - if (res.data.error_code) { - return this.handleError(res.data.error_code, '97'); + if (res.data.error_code || res.status !== 200) { + return this.handleError(res.data!.error_code ? res.data.error_code : res.status, '172'); } try { @@ -222,8 +223,8 @@ export default class P100 implements TpLinkAccessory{ await this._axios.post(URL, securePassthroughPayload, config) .then((res: AxiosResponse) => { - if (res.data.error_code) { - return this.handleError(res.data.error_code, '146'); + if (res.data.error_code || res.status !== 200) { + return this.handleError(res.data!.error_code ? res.data.error_code : res.status, '226'); } const decryptedResponse = this.tpLinkCipher.decrypt(res.data.result.response); try { @@ -269,13 +270,15 @@ export default class P100 implements TpLinkAccessory{ return this._axios.post(URL, data, config) .then((res: AxiosResponse) => { this.log.debug('Received request on host response: ' + this.ip); - if (res.data.error_code) { - return this.handleError(res.data.error_code, '309'); + if (res.data.error_code || res.status !== 200) { + return this.handleError(res.data!.error_code ? res.data.error_code : res.status, '273'); } try { if (res.headers && res.headers['set-cookie']) { + this.log.debug('Handshake 1 cookie: ' + JSON.stringify(res.headers['set-cookie'][0])); this.cookie = res.headers['set-cookie'][0].split(';')[0]; + this.tplink_timeout = Number(res.headers['set-cookie'][0].split(';')[1]); } return res.data; } catch (error) { @@ -477,11 +480,16 @@ export default class P100 implements TpLinkAccessory{ return this.getSysInfo(); } catch (error) { this.log.debug(this.newTpLinkCipher.decrypt(res.data)); + this.log.debug('Status: ' + res.status); return this.handleError(res.data.error_code, '480'); } }) .catch((error: Error) => { + this.log.debug('469 Error: ' + JSON.stringify(error)); this.log.error('469 Error: ' + error.message); + if(error.message.indexOf('403') > -1){ + this.reAuthenticate(); + } return error; }); @@ -553,9 +561,11 @@ export default class P100 implements TpLinkAccessory{ protected handleError(errorCode: number | string, line: string): boolean { //@ts-ignore const errorMessage = this.ERROR_CODES[errorCode]; - this.log.error(line + ' Error Code: ' + errorCode + ', ' + errorMessage + ' ' + this.ip); if (typeof errorCode === 'number' && errorCode === 1003) { + this.log.info('Trying KLAP Auth'); this.is_klap = true; + } else{ + this.log.error(line + ' Error Code: ' + errorCode + ', ' + errorMessage + ' ' + this.ip); } return false; } @@ -643,7 +653,7 @@ export default class P100 implements TpLinkAccessory{ } }) .catch((error: Error) => { - return this.handleError(error.message, '372'); + return this.handleError(error.message, '656'); }); } return new Promise((resolve, reject) => { @@ -658,7 +668,7 @@ export default class P100 implements TpLinkAccessory{ return this.raw_request('request', data.encryptedPayload, 'arraybuffer', { seq: data.seq.toString() }).then((res) => { return JSON.parse(this.newTpLinkCipher.decrypt(res)); }).catch((error: Error) => { - return this.handleError(error.message, '372'); + return this.handleError(error.message, '671'); }); } return new Promise((resolve, reject) => { @@ -682,4 +692,23 @@ export default class P100 implements TpLinkAccessory{ return; }); } + + private reAuthenticate():void{ + if(this.is_klap){ + this.handshake_new().then(() => { + this.log.info('KLAP Authenticated successfully'); + }).catch(() => { + this.log.error('KLAP Handshake failed'); + this.is_klap = false; + }); + } else { + this.handshake().then(() => { + this.login().then(() => { + this.log.info('Authenticated successfully'); + }).catch(() => { + this.log.error('Login failed'); + }); + }); + } + } } \ No newline at end of file diff --git a/src/utils/p110.ts b/src/utils/p110.ts index 0e2577f..c577e39 100644 --- a/src/utils/p110.ts +++ b/src/utils/p110.ts @@ -28,7 +28,7 @@ export default class P110 extends P100 { return this.handleKlapRequest(payload).then((response)=>{ if(response && response.result){ this._consumption = { - current: response.result.current_power / 1000, + current: Math.ceil(response.result.current_power / 1000), total: response.result.today_energy / 1000, }; } else{ @@ -44,7 +44,7 @@ export default class P110 extends P100 { return this.handleRequest(payload).then((response)=>{ if(response && response.result){ this._consumption = { - current: response.result.current_power / 1000, + current: Math.ceil(response.result.current_power / 1000), total: response.result.today_energy / 1000, }; } else{