diff --git a/classes/PowerUsage/DeviceRaw.js b/classes/PowerUsage/DeviceRaw.js index f67e104..e4fd120 100644 --- a/classes/PowerUsage/DeviceRaw.js +++ b/classes/PowerUsage/DeviceRaw.js @@ -27,9 +27,10 @@ class DeviceRaw extends WebSocket { payloadUpdate, ]); - const error = _get(response, 'error', false); - if (error) { - return response; + const error = _get(response[1], 'error', false); + + if (error === 403) { + return { error, msg: response[1].reason }; } const hundredDaysKwhData = _get( diff --git a/main.js b/main.js index 9df8ce3..0b5827c 100644 --- a/main.js +++ b/main.js @@ -133,8 +133,7 @@ const getDevicePowerUsageMixin = require('./mixins/powerUsage/getDevicePowerUsag const getDeviceRawPowerUsageMixin = require('./mixins/powerUsage/getDeviceRawPowerUsageMixin'); /* LOAD MIXINS: temperature & humidity */ -const getDeviceCurrentTemperatureMixin = require('./mixins/temperature/getDeviceCurrentTemperatureMixin'); -const getDeviceCurrentHumidityMixin = require('./mixins/humidity/getDeviceCurrentHumidityMixin'); +const getTHMixin = require('./mixins/temphumd/getTHMixin'); /* LOAD MIXINS: devices */ const getDevicesMixin = require('./mixins/devices/getDevicesMixin'); @@ -158,11 +157,7 @@ Object.assign( getDeviceRawPowerUsageMixin ); -Object.assign( - eWeLink.prototype, - getDeviceCurrentTemperatureMixin, - getDeviceCurrentHumidityMixin -); +Object.assign(eWeLink.prototype, getTHMixin); Object.assign( eWeLink.prototype, diff --git a/mixins/humidity/getDeviceCurrentHumidityMixin.js b/mixins/humidity/getDeviceCurrentHumidityMixin.js deleted file mode 100644 index 26b41d2..0000000 --- a/mixins/humidity/getDeviceCurrentHumidityMixin.js +++ /dev/null @@ -1,28 +0,0 @@ -const { _get } = require('../../lib/helpers'); - -const getDeviceCurrentHumidityMixin = { - /** - * Get device current humidity - * - * @param deviceId - * - * @returns {Promise<{humidity: *, status: string}|{msg: string, error: *}>} - */ - async getDeviceCurrentHumidity(deviceId) { - const device = await this.getDevice(deviceId); - const error = _get(device, 'error', false); - const model = _get(device, 'extra.extra.model', ''); - const humidity = _get(device, 'params.currentHumidity', false); - - if (error || model !== 'PSA-BHA-GL' || !humidity) { - if (error && parseInt(error) === 401) { - return device; - } - return { error, msg: 'Device does not exist' }; - } - - return { status: 'ok', humidity }; - }, -}; - -module.exports = getDeviceCurrentHumidityMixin; diff --git a/mixins/powerState/setDevicePowerStateMixin.js b/mixins/powerState/setDevicePowerStateMixin.js index d02d125..29c82e2 100644 --- a/mixins/powerState/setDevicePowerStateMixin.js +++ b/mixins/powerState/setDevicePowerStateMixin.js @@ -15,6 +15,7 @@ const setDevicePowerState = { */ async setDevicePowerState(deviceId, state, channel = 1) { const device = await this.getDevice(deviceId); + const deviceApiKey = _get(device, 'apikey', false); const error = _get(device, 'error', false); const uiid = _get(device, 'extra.extra.uiid', false); @@ -52,14 +53,20 @@ const setDevicePowerState = { params.switch = stateToSwitch; } - return ChangeState.set({ + const actionParams = { apiUrl: this.getApiWebSocket(), at: this.at, apiKey: this.apiKey, deviceId, params, state: stateToSwitch, - }); + }; + + if (this.apiKey !== deviceApiKey) { + actionParams.apiKey = deviceApiKey; + } + + return ChangeState.set(actionParams); }, }; diff --git a/mixins/powerUsage/getDeviceRawPowerUsageMixin.js b/mixins/powerUsage/getDeviceRawPowerUsageMixin.js index 3c1eb5c..e85f365 100644 --- a/mixins/powerUsage/getDeviceRawPowerUsageMixin.js +++ b/mixins/powerUsage/getDeviceRawPowerUsageMixin.js @@ -1,3 +1,5 @@ +const { _get } = require('../../lib/helpers'); + const { DeviceRaw } = require('../../classes/PowerUsage'); const getDeviceRawPowerUsageMixin = { @@ -9,14 +11,21 @@ const getDeviceRawPowerUsageMixin = { * @returns {Promise<{error: string}|{response: {hundredDaysKwhData: *}, status: string}>} */ async getDeviceRawPowerUsage(deviceId) { - await this.logIfNeeded(); + const device = await this.getDevice(deviceId); + const deviceApiKey = _get(device, 'apikey', false); - return DeviceRaw.get({ + const actionParams = { apiUrl: this.getApiWebSocket(), at: this.at, apiKey: this.apiKey, deviceId, - }); + }; + + if (this.apiKey !== deviceApiKey) { + actionParams.apiKey = deviceApiKey; + } + + return DeviceRaw.get(actionParams); }, }; diff --git a/mixins/temperature/getDeviceCurrentTemperatureMixin.js b/mixins/temperature/getDeviceCurrentTemperatureMixin.js deleted file mode 100644 index d53ada4..0000000 --- a/mixins/temperature/getDeviceCurrentTemperatureMixin.js +++ /dev/null @@ -1,28 +0,0 @@ -const { _get } = require('../../lib/helpers'); - -const getDeviceCurrentTemperatureMixin = { - /** - * Get device current temperature - * - * @param deviceId - * - * @returns {Promise<{temperature: *, status: string}|{msg: string, error: *}>} - */ - async getDeviceCurrentTemperature(deviceId) { - const device = await this.getDevice(deviceId); - const error = _get(device, 'error', false); - const model = _get(device, 'extra.extra.model', ''); - const temperature = _get(device, 'params.currentTemperature', false); - - if (error || model !== 'PSA-BHA-GL' || !temperature) { - if (error && parseInt(error) === 401) { - return device; - } - return { error, msg: 'Device does not exist' }; - } - - return { status: 'ok', temperature }; - }, -}; - -module.exports = getDeviceCurrentTemperatureMixin; diff --git a/mixins/temphumd/getTHMixin.js b/mixins/temphumd/getTHMixin.js new file mode 100644 index 0000000..3b9f84d --- /dev/null +++ b/mixins/temphumd/getTHMixin.js @@ -0,0 +1,55 @@ +const { _get } = require('../../lib/helpers'); + +const getTHMixin = { + /** + * Get device current temperature & humidity + * @param deviceId + * @param type + * @returns {Promise<{temperature: *, humidity: *, status: string}|{msg: string, error: *}>} + */ + async getDeviceCurrentTH(deviceId, type = '') { + const device = await this.getDevice(deviceId); + const error = _get(device, 'error', false); + const temperature = _get(device, 'params.currentTemperature', false); + const humidity = _get(device, 'params.currentHumidity', false); + + if (error || !temperature || !humidity) { + if (error && parseInt(error) === 401) { + return device; + } + return { error, msg: 'Device does not exist' }; + } + + const data = { status: 'ok', temperature, humidity }; + + if (type === 'temp') { + delete data.humidity; + } + + if (type === 'humd') { + delete data.temperature; + } + + return data; + }, + + /** + * Get device current temperature + * @param deviceId + * @returns {Promise<*|{temperature: *, status: string}|{msg: string, error: *}>} + */ + async getDeviceCurrentTemperature(deviceId) { + return this.getDeviceCurrentTH(deviceId, 'temp'); + }, + + /** + * Get device current humidity + * @param deviceId + * @returns {Promise<*|{temperature: *, status: string}|{msg: string, error: *}>} + */ + async getDeviceCurrentHumidity(deviceId) { + return this.getDeviceCurrentTH(deviceId, 'humd'); + }, +}; + +module.exports = getTHMixin; diff --git a/package-lock.json b/package-lock.json index 962e211..7f62631 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "ewelink-api", - "version": "1.6.0", + "version": "1.6.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 249167f..5507608 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ewelink-api", - "version": "1.6.0", + "version": "1.6.1", "description": "eWeLink API for Node.js", "author": "Martín M.", "license": "MIT", @@ -21,7 +21,7 @@ "main": "main.js", "scripts": { "test": "jest --runInBand --verbose", - "coverage": "jest --runInBand --verbose --coverage --coverageDirectory=output/coverage/jest", + "coverage": "jest --runInBand --verbose --coverage --coverageDirectory=coverage/jest", "lint": "eslint .", "lint:fix": "eslint . --fix" }, diff --git a/test/main-invalid-credentials.spec.js b/test/main-invalid-credentials.spec.js index b818e29..f73e0e7 100644 --- a/test/main-invalid-credentials.spec.js +++ b/test/main-invalid-credentials.spec.js @@ -5,7 +5,6 @@ const ewelink = require('../main'); const { singleChannelDeviceId, deviceIdWithPower, - deviceIdWithTempAndHum, fourChannelsDevice, } = require('./_setup/credentials.json'); @@ -68,30 +67,10 @@ describe('invalid credentials', () => { const conn = new ewelink({ email: 'invalid', password: 'credentials' }); const powerUsage = await conn.getDevicePowerUsage(deviceIdWithPower); expect(typeof powerUsage).toBe('object'); - expect(powerUsage.msg).toBe('Authentication error'); - expect(powerUsage.error).toBe(401); + expect(powerUsage.msg).toBe('Forbidden'); + expect(powerUsage.error).toBe(403); }); - // test('get device current temperature should fail', async () => { - // const conn = new ewelink({ email: 'invalid', password: 'credentials' }); - // const powerState = await conn.getDeviceCurrentTemperature( - // deviceIdWithTempAndHum - // ); - // expect(typeof powerState).toBe('object'); - // expect(powerUsage.msg).toBe('Authentication error'); - // expect(powerUsage.error).toBe(401); - // }); - - // test('get device current humidity should fail', async () => { - // const conn = new ewelink({ email: 'invalid', password: 'credentials' }); - // const powerState = await conn.getDeviceCurrentHumidity( - // deviceIdWithTempAndHum - // ); - // expect(typeof powerState).toBe('object'); - // expect(powerUsage.msg).toBe('Authentication error'); - // expect(powerUsage.error).toBe(401); - // }); - test('get channel count 1 should fail', async () => { const conn = new ewelink({ email: 'invalid', password: 'credentials' }); const switchesAmount = await conn.getDeviceChannelCount( diff --git a/test/main-valid-credentials.spec.js b/test/main-valid-credentials.spec.js index cf17e5b..a7d4a96 100644 --- a/test/main-valid-credentials.spec.js +++ b/test/main-valid-credentials.spec.js @@ -68,7 +68,8 @@ describe('valid credentials, invalid device', () => { const conn = new ewelink({ email, password }); const powerUsage = await conn.getDeviceRawPowerUsage('invalid deviceid'); expect(typeof powerUsage).toBe('object'); - expect(powerUsage.error).toBe('No power usage data found.'); + expect(powerUsage.msg).toBe('Forbidden'); + expect(powerUsage.error).toBe(403); }); test('current month power usage on invalid device should fail', async () => { @@ -76,7 +77,8 @@ describe('valid credentials, invalid device', () => { const conn = new ewelink({ email, password }); const powerUsage = await conn.getDevicePowerUsage('invalid deviceid'); expect(typeof powerUsage).toBe('object'); - expect(powerUsage.error).toBe('No power usage data found.'); + expect(powerUsage.msg).toBe('Forbidden'); + expect(powerUsage.error).toBe(403); }); test('raw power on device without electricity monitor should fail', async () => { @@ -87,24 +89,6 @@ describe('valid credentials, invalid device', () => { expect(powerUsage.error).toBe('No power usage data found.'); }); - test('get device current temperature should fail', async () => { - const conn = new ewelink({ email, password }); - const temperature = await conn.getDeviceCurrentTemperature( - 'invalid deviceid' - ); - expect(typeof temperature).toBe('object'); - expect(temperature.msg).toBe('Device does not exist'); - expect(temperature.error).toBe(500); - }); - - test('get device current humidity should fail', async () => { - const conn = new ewelink({ email, password }); - const humidity = await conn.getDeviceCurrentHumidity('invalid deviceid'); - expect(typeof humidity).toBe('object'); - expect(humidity.msg).toBe('Device does not exist'); - expect(humidity.error).toBe(500); - }); - test('get channel count should fail', async () => { const conn = new ewelink({ email, password }); const switchesAmount = await conn.getDeviceChannelCount('invalid deviceid'); diff --git a/test/temperature-humidity.spec.js b/test/temperature-humidity.spec.js index 83255f1..546f16c 100644 --- a/test/temperature-humidity.spec.js +++ b/test/temperature-humidity.spec.js @@ -1,45 +1,58 @@ +const delay = require('delay'); + const ewelink = require('../main'); const { email, password, - deviceIdWithTempAndHum, + deviceIdWithTempAndHum: thDevice, } = require('./_setup/credentials.json'); -describe.skip('current temerature and humidity: node script', () => { +describe('current temperature and humidity: node script', () => { let conn; + let device; beforeAll(async () => { conn = new ewelink({ email, password }); await conn.login(); }); + beforeEach(async () => { + await delay(1000); + device = await conn.getDevice(thDevice); + }); + + test('should return current temperature/humidity', async () => { + const { currentTemperature, currentHumidity } = device.params; + const result = await conn.getDeviceCurrentTH(thDevice); + expect(typeof result).toBe('object'); + expect(result.status).toBe('ok'); + expect(result.temperature).toBe(currentTemperature); + expect(result.humidity).toBe(currentHumidity); + }); + test('should return current temperature', async () => { - const device = await conn.getDevice(deviceIdWithTempAndHum); const { currentTemperature } = device.params; - const temperature = await conn.getDeviceCurrentTemperature( - deviceIdWithTempAndHum - ); - expect(typeof temperature).toBe('object'); - expect(temperature.status).toBe('ok'); - expect(temperature.state).toBe(currentTemperature); + const result = await conn.getDeviceCurrentTemperature(thDevice); + expect(typeof result).toBe('object'); + expect(result.status).toBe('ok'); + expect(result.temperature).toBe(currentTemperature); }); test('should return current humidity', async () => { - const device = await conn.getDevice(deviceIdWithTempAndHum); const { currentHumidity } = device.params; - const humidity = await conn.getDeviceCurrentHumidity( - deviceIdWithTempAndHum - ); - expect(typeof humidity).toBe('object'); - expect(humidity.status).toBe('ok'); - expect(humidity.state).toBe(currentHumidity); + const result = await conn.getDeviceCurrentHumidity(thDevice); + expect(typeof result).toBe('object'); + expect(result.status).toBe('ok'); + expect(result.humidity).toBe(currentHumidity); }); }); -describe.skip('current temerature and humidity: serverless', () => { +describe('current temperature and humidity: serverless', () => { let accessToken; let apiKey; + let connSL; + let device; beforeAll(async () => { const conn = new ewelink({ email, password }); @@ -48,27 +61,70 @@ describe.skip('current temerature and humidity: serverless', () => { apiKey = login.user.apikey; }); + beforeEach(async () => { + await delay(1000); + connSL = new ewelink({ at: accessToken, apiKey }); + device = await connSL.getDevice(thDevice); + }); + + test('should return current temperature/humidity', async () => { + const { currentTemperature, currentHumidity } = device.params; + const result = await connSL.getDeviceCurrentTH(thDevice); + expect(typeof result).toBe('object'); + expect(result.status).toBe('ok'); + expect(result.temperature).toBe(currentTemperature); + expect(result.humidity).toBe(currentHumidity); + }); + test('should return current temperature', async () => { - const conn = new ewelink({ at: accessToken, apiKey }); - const device = await conn.getDevice(deviceIdWithTempAndHum); const { currentTemperature } = device.params; - const temperature = await conn.getDeviceCurrentTemperature( - deviceIdWithTempAndHum - ); - expect(typeof temperature).toBe('object'); - expect(temperature.status).toBe('ok'); - expect(temperature.state).toBe(currentTemperature); + const result = await connSL.getDeviceCurrentTemperature(thDevice); + expect(typeof result).toBe('object'); + expect(result.status).toBe('ok'); + expect(result.temperature).toBe(currentTemperature); }); test('should return current humidity', async () => { - const conn = new ewelink({ at: accessToken, apiKey }); - const device = await conn.getDevice(deviceIdWithTempAndHum); const { currentHumidity } = device.params; - const humidity = await conn.getDeviceCurrentHumidity( - deviceIdWithTempAndHum - ); - expect(typeof humidity).toBe('object'); - expect(humidity.status).toBe('ok'); - expect(humidity.state).toBe(currentHumidity); + const result = await connSL.getDeviceCurrentHumidity(thDevice); + expect(typeof result).toBe('object'); + expect(result.status).toBe('ok'); + expect(result.humidity).toBe(currentHumidity); + }); +}); + +describe('current temperature and humidity: invalid device', () => { + test('get device current temperature should fail', async () => { + const conn = new ewelink({ email, password }); + const temperature = await conn.getDeviceCurrentTemperature('invalid'); + expect(typeof temperature).toBe('object'); + expect(temperature.msg).toBe('Device does not exist'); + expect(temperature.error).toBe(500); + }); + + test('get device current humidity should fail', async () => { + const conn = new ewelink({ email, password }); + const humidity = await conn.getDeviceCurrentHumidity('invalid'); + expect(typeof humidity).toBe('object'); + expect(humidity.msg).toBe('Device does not exist'); + expect(humidity.error).toBe(500); + }); +}); + +describe('current temperature and humidity: invalid credentials', () => { + test('get device current temperature should fail', async () => { + const conn = new ewelink({ email: 'invalid', password: 'credentials' }); + const result = await conn.getDeviceCurrentTemperature(thDevice); + expect(typeof result).toBe('object'); + expect(result.msg).toBe('Authentication error'); + expect(result.error).toBe(401); + }); + + test('get device current humidity should fail', async () => { + const conn = new ewelink({ email: 'invalid', password: 'credentials' }); + const result = await conn.getDeviceCurrentHumidity(thDevice); + expect(typeof result).toBe('object'); + expect(result.msg).toBe('Authentication error'); + expect(result.error).toBe(401); }); });