mirror of
https://github.com/skydiver/ewelink-api.git
synced 2025-12-21 21:33:11 +01:00
Release v1.8.0 (#23)
* new method to check for device firmware updates * moved mixin * generate firmware update payload * new method to check for devices firmware updates * removed unused function * moved firmware tests to own file * added firmware test cases * return device id on response * updated credentials list * version bump
This commit is contained in:
15
lib/payloads/firmwareUpdate.js
Normal file
15
lib/payloads/firmwareUpdate.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
const { _get } = require('../../lib/helpers');
|
||||||
|
|
||||||
|
const firmwareUpdate = devicesList =>
|
||||||
|
devicesList.map(device => {
|
||||||
|
const model = _get(device, 'extra.extra.model', false);
|
||||||
|
const fwVersion = _get(device, 'params.fwVersion', false);
|
||||||
|
|
||||||
|
if (!model || !fwVersion) {
|
||||||
|
return { error: 500, msg: "Can't get model or firmware version" };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { model, version: fwVersion, deviceid: device.deviceid };
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = firmwareUpdate;
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
|
const firmwareUpdate = require('./firmwareUpdate');
|
||||||
const loginPayload = require('./loginPayload');
|
const loginPayload = require('./loginPayload');
|
||||||
const wssLoginPayload = require('./wssLoginPayload');
|
const wssLoginPayload = require('./wssLoginPayload');
|
||||||
const wssUpdatePayload = require('./wssUpdatePayload');
|
const wssUpdatePayload = require('./wssUpdatePayload');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
firmwareUpdate,
|
||||||
loginPayload,
|
loginPayload,
|
||||||
wssLoginPayload,
|
wssLoginPayload,
|
||||||
wssUpdatePayload,
|
wssUpdatePayload,
|
||||||
|
|||||||
45
main.js
45
main.js
@@ -28,6 +28,14 @@ class eWeLink {
|
|||||||
return `https://${this.region}-api.coolkit.cc:8080/api`;
|
return `https://${this.region}-api.coolkit.cc:8080/api`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate eWeLink OTA API URL
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
getOtaUrl() {
|
||||||
|
return `https://${this.region}-ota.coolkit.cc:8080/otaother`;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate eWeLink WebSocket URL
|
* Generate eWeLink WebSocket URL
|
||||||
*
|
*
|
||||||
@@ -41,22 +49,29 @@ class eWeLink {
|
|||||||
* Generate http requests helpers
|
* Generate http requests helpers
|
||||||
*
|
*
|
||||||
* @param method
|
* @param method
|
||||||
|
* @param url
|
||||||
* @param uri
|
* @param uri
|
||||||
* @param body
|
* @param body
|
||||||
* @param qs
|
* @param qs
|
||||||
*
|
*
|
||||||
* @returns {Promise<{msg: string, error: *}>}
|
* @returns {Promise<{msg: string, error: *}>}
|
||||||
*/
|
*/
|
||||||
async makeRequest({ method = 'GET', uri, body = {}, qs = {} }) {
|
async makeRequest({ method = 'GET', url, uri, body = {}, qs = {} }) {
|
||||||
const { at } = this;
|
const { at } = this;
|
||||||
|
|
||||||
if (!at) {
|
if (!at) {
|
||||||
await this.login();
|
await this.login();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let apiUrl = this.getApiUrl();
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
apiUrl = url;
|
||||||
|
}
|
||||||
|
|
||||||
const response = await rp({
|
const response = await rp({
|
||||||
method,
|
method,
|
||||||
uri: `${this.getApiUrl()}${uri}`,
|
uri: `${apiUrl}${uri}`,
|
||||||
headers: { Authorization: `Bearer ${this.at}` },
|
headers: { Authorization: `Bearer ${this.at}` },
|
||||||
body,
|
body,
|
||||||
qs,
|
qs,
|
||||||
@@ -111,16 +126,6 @@ class eWeLink {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if authentication credentials doesn't exists then perform a login
|
|
||||||
*
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
async logIfNeeded() {
|
|
||||||
if (!this.at) {
|
|
||||||
await this.login();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* LOAD MIXINS: power state */
|
/* LOAD MIXINS: power state */
|
||||||
@@ -139,7 +144,11 @@ const getTHMixin = require('./mixins/temphumd/getTHMixin');
|
|||||||
const getDevicesMixin = require('./mixins/devices/getDevicesMixin');
|
const getDevicesMixin = require('./mixins/devices/getDevicesMixin');
|
||||||
const getDeviceMixin = require('./mixins/devices/getDeviceMixin');
|
const getDeviceMixin = require('./mixins/devices/getDeviceMixin');
|
||||||
const getDeviceChannelCountMixin = require('./mixins/devices/getDeviceChannelCountMixin');
|
const getDeviceChannelCountMixin = require('./mixins/devices/getDeviceChannelCountMixin');
|
||||||
const getFirmwareVersionMixin = require('./mixins/devices/getFirmwareVersionMixin');
|
|
||||||
|
/* LOAD MIXINS: firmware */
|
||||||
|
const getFirmwareVersionMixin = require('./mixins/firmware/getFirmwareVersionMixin');
|
||||||
|
const checkDeviceUpdateMixin = require('./mixins/firmware/checkDeviceUpdateMixin');
|
||||||
|
const checkDevicesUpdatesMixin = require('./mixins/firmware/checkDevicesUpdatesMixin');
|
||||||
|
|
||||||
/* LOAD MIXINS: websocket */
|
/* LOAD MIXINS: websocket */
|
||||||
const openWebSocketMixin = require('./mixins/websocket/openWebSocketMixin');
|
const openWebSocketMixin = require('./mixins/websocket/openWebSocketMixin');
|
||||||
@@ -163,8 +172,14 @@ Object.assign(
|
|||||||
eWeLink.prototype,
|
eWeLink.prototype,
|
||||||
getDevicesMixin,
|
getDevicesMixin,
|
||||||
getDeviceMixin,
|
getDeviceMixin,
|
||||||
getDeviceChannelCountMixin,
|
getDeviceChannelCountMixin
|
||||||
getFirmwareVersionMixin
|
);
|
||||||
|
|
||||||
|
Object.assign(
|
||||||
|
eWeLink.prototype,
|
||||||
|
getFirmwareVersionMixin,
|
||||||
|
checkDeviceUpdateMixin,
|
||||||
|
checkDevicesUpdatesMixin
|
||||||
);
|
);
|
||||||
|
|
||||||
Object.assign(eWeLink.prototype, openWebSocketMixin);
|
Object.assign(eWeLink.prototype, openWebSocketMixin);
|
||||||
|
|||||||
48
mixins/firmware/checkDeviceUpdateMixin.js
Normal file
48
mixins/firmware/checkDeviceUpdateMixin.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
const { _get } = require('../../lib/helpers');
|
||||||
|
const payloads = require('../../lib/payloads');
|
||||||
|
|
||||||
|
const checkDeviceUpdateMixin = {
|
||||||
|
/**
|
||||||
|
* Check device firmware update
|
||||||
|
*
|
||||||
|
* @param deviceId
|
||||||
|
*
|
||||||
|
* @returns {Promise<{msg: string, version: *}|{msg: string, error: number}|{msg: string, error: *}|Device|{msg: string}>}
|
||||||
|
*/
|
||||||
|
async checkDeviceUpdate(deviceId) {
|
||||||
|
const device = await this.getDevice(deviceId);
|
||||||
|
|
||||||
|
const error = _get(device, 'error', false);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deviceInfoList = payloads.firmwareUpdate([device]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return deviceInfoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
const update = await this.makeRequest({
|
||||||
|
method: 'POST',
|
||||||
|
url: this.getOtaUrl(),
|
||||||
|
uri: '/app',
|
||||||
|
body: { deviceInfoList },
|
||||||
|
});
|
||||||
|
|
||||||
|
const isUpdate = _get(update, 'upgradeInfoList.0.version', false);
|
||||||
|
|
||||||
|
if (!isUpdate) {
|
||||||
|
return { status: 'ok', msg: 'No update available' };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 'ok',
|
||||||
|
msg: 'Update available',
|
||||||
|
version: isUpdate,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = checkDeviceUpdateMixin;
|
||||||
54
mixins/firmware/checkDevicesUpdatesMixin.js
Normal file
54
mixins/firmware/checkDevicesUpdatesMixin.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
const { _get } = require('../../lib/helpers');
|
||||||
|
const payloads = require('../../lib/payloads');
|
||||||
|
|
||||||
|
const checkDevicesUpdatesMixin = {
|
||||||
|
async checkDevicesUpdates() {
|
||||||
|
const devices = await this.getDevices();
|
||||||
|
|
||||||
|
const error = _get(devices, 'error', false);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
const deviceInfoList = payloads.firmwareUpdate(devices);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return deviceInfoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updates = await this.makeRequest({
|
||||||
|
method: 'POST',
|
||||||
|
url: this.getOtaUrl(),
|
||||||
|
uri: '/app',
|
||||||
|
body: { deviceInfoList },
|
||||||
|
});
|
||||||
|
|
||||||
|
const upgradeInfoList = _get(updates, 'upgradeInfoList', false);
|
||||||
|
|
||||||
|
if (!upgradeInfoList) {
|
||||||
|
return { error: "Can't find firmware update information" };
|
||||||
|
}
|
||||||
|
|
||||||
|
return upgradeInfoList.map(device => {
|
||||||
|
const upd = _get(device, 'version', false);
|
||||||
|
|
||||||
|
if (!upd) {
|
||||||
|
return {
|
||||||
|
status: 'ok',
|
||||||
|
deviceId: device.deviceid,
|
||||||
|
msg: 'No update available',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 'ok',
|
||||||
|
deviceId: device.deviceid,
|
||||||
|
msg: 'Update available',
|
||||||
|
version: upd,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = checkDevicesUpdatesMixin;
|
||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ewelink-api",
|
"name": "ewelink-api",
|
||||||
"version": "1.7.0",
|
"version": "1.8.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ewelink-api",
|
"name": "ewelink-api",
|
||||||
"version": "1.7.0",
|
"version": "1.8.0",
|
||||||
"description": "eWeLink API for Node.js",
|
"description": "eWeLink API for Node.js",
|
||||||
"author": "Martín M.",
|
"author": "Martín M.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -6,5 +6,7 @@
|
|||||||
"deviceIdWithoutPower": "<your device id>",
|
"deviceIdWithoutPower": "<your device id>",
|
||||||
"deviceIdWithTempAndHum": "<your device id>",
|
"deviceIdWithTempAndHum": "<your device id>",
|
||||||
"deviceIdWithoutTempAndHum": "<your device id>",
|
"deviceIdWithoutTempAndHum": "<your device id>",
|
||||||
"fourChannelsDevice": "<your device id>"
|
"fourChannelsDevice": "<your device id>",
|
||||||
|
"outdatedFirmwareDevice": "<your device id>",
|
||||||
|
"updatedFirmwareDevice": "<your device id>"
|
||||||
}
|
}
|
||||||
@@ -44,10 +44,17 @@ const currentMonthPowerUsageExpectations = {
|
|||||||
daily: expect.any(Array),
|
daily: expect.any(Array),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const firmwareExpectations = {
|
||||||
|
status: expect.any(String),
|
||||||
|
deviceId: expect.any(String),
|
||||||
|
msg: expect.any(String),
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
loginExpectations,
|
loginExpectations,
|
||||||
allDevicesExpectations,
|
allDevicesExpectations,
|
||||||
specificDeviceExpectations,
|
specificDeviceExpectations,
|
||||||
rawPowerUsageExpectations,
|
rawPowerUsageExpectations,
|
||||||
currentMonthPowerUsageExpectations,
|
currentMonthPowerUsageExpectations,
|
||||||
|
firmwareExpectations,
|
||||||
};
|
};
|
||||||
|
|||||||
101
test/firmware.spec.js
Normal file
101
test/firmware.spec.js
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
const ewelink = require('../main');
|
||||||
|
|
||||||
|
const {
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
singleChannelDeviceId,
|
||||||
|
outdatedFirmwareDevice,
|
||||||
|
updatedFirmwareDevice,
|
||||||
|
} = require('./_setup/credentials.json');
|
||||||
|
|
||||||
|
const { firmwareExpectations } = require('./_setup/expectations');
|
||||||
|
|
||||||
|
describe('firmware: get version methods', () => {
|
||||||
|
let connection;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
connection = new ewelink({ email, password });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('get firmware version', async () => {
|
||||||
|
const device = await connection.getDevice(singleChannelDeviceId);
|
||||||
|
const currentVersion = device.params.fwVersion;
|
||||||
|
const firmware = await connection.getFirmwareVersion(singleChannelDeviceId);
|
||||||
|
expect(typeof firmware).toBe('object');
|
||||||
|
expect(firmware.status).toBe('ok');
|
||||||
|
expect(firmware.fwVersion).toBe(currentVersion);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('get device firmware version should be right message', async () => {
|
||||||
|
const login = await connection.login();
|
||||||
|
const accessToken = login.at;
|
||||||
|
const conn = new ewelink({ at: accessToken });
|
||||||
|
const device = await conn.getDevice(singleChannelDeviceId);
|
||||||
|
const currentVersion = device.params.fwVersion;
|
||||||
|
const firmware = await conn.getFirmwareVersion(singleChannelDeviceId);
|
||||||
|
expect(typeof firmware).toBe('object');
|
||||||
|
expect(firmware.status).toBe('ok');
|
||||||
|
expect(firmware.fwVersion).toBe(currentVersion);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('get invalid device firmware version should fail', async () => {
|
||||||
|
const conn = new ewelink({ email, password });
|
||||||
|
const firmwareVersion = await conn.getFirmwareVersion('invalid deviceid');
|
||||||
|
expect(typeof firmwareVersion).toBe('object');
|
||||||
|
expect(firmwareVersion.msg).toBe('Device does not exist');
|
||||||
|
expect(firmwareVersion.error).toBe(500);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('get device firmware version using invalid credentials should fail', async () => {
|
||||||
|
const conn = new ewelink({ email: 'invalid', password: 'credentials' });
|
||||||
|
const firmware = await conn.getFirmwareVersion(singleChannelDeviceId);
|
||||||
|
expect(typeof firmware).toBe('object');
|
||||||
|
expect(firmware.msg).toBe('Authentication error');
|
||||||
|
expect(firmware.error).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('firmware: check updates methods', () => {
|
||||||
|
let connection;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
connection = new ewelink({ email, password });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('outdated device firmware should return available version', async () => {
|
||||||
|
const status = await connection.checkDeviceUpdate(outdatedFirmwareDevice);
|
||||||
|
expect(typeof status).toBe('object');
|
||||||
|
expect(typeof status).toBe('object');
|
||||||
|
expect(status.status).toBe('ok');
|
||||||
|
expect(status.msg).toBe('Update available');
|
||||||
|
expect(typeof status.version).toBe('string');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('updated device firmware should return right message', async () => {
|
||||||
|
const status = await connection.checkDeviceUpdate(updatedFirmwareDevice);
|
||||||
|
expect(typeof status).toBe('object');
|
||||||
|
expect(typeof status).toBe('object');
|
||||||
|
expect(status.status).toBe('ok');
|
||||||
|
expect(status.msg).toBe('No update available');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('invalid device update check should return error', async () => {
|
||||||
|
const status = await connection.checkDeviceUpdate('invalid deviceid');
|
||||||
|
expect(typeof status).toBe('object');
|
||||||
|
expect(status.error).toBe(500);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('get devices update check should be valid response', async () => {
|
||||||
|
const status = await connection.checkDevicesUpdates();
|
||||||
|
expect(typeof status).toBe('object');
|
||||||
|
expect(status[0]).toMatchObject(firmwareExpectations);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('get devices update check with invalid credentials should fail', async () => {
|
||||||
|
const conn = new ewelink({ email: 'invalid', password: 'credentials' });
|
||||||
|
const status = await conn.checkDevicesUpdates();
|
||||||
|
expect(typeof status).toBe('object');
|
||||||
|
expect(status.msg).toBe('Authentication error');
|
||||||
|
expect(status.error).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -152,13 +152,4 @@ describe('env: node script', () => {
|
|||||||
expect(result.status).toBe('ok');
|
expect(result.status).toBe('ok');
|
||||||
expect(result.switchesAmount).toBe(4);
|
expect(result.switchesAmount).toBe(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('get firmware version', async () => {
|
|
||||||
const device = await conn.getDevice(singleChannelDeviceId);
|
|
||||||
const currentVersion = device.params.fwVersion;
|
|
||||||
const firmware = await conn.getFirmwareVersion(singleChannelDeviceId);
|
|
||||||
expect(typeof firmware).toBe('object');
|
|
||||||
expect(firmware.status).toBe('ok');
|
|
||||||
expect(firmware.fwVersion).toBe(currentVersion);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -108,14 +108,4 @@ describe('env: serverless', () => {
|
|||||||
expect(result.status).toBe('ok');
|
expect(result.status).toBe('ok');
|
||||||
expect(result.switchesAmount).toBe(4);
|
expect(result.switchesAmount).toBe(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('get device firmware version', async () => {
|
|
||||||
const conn = new ewelink({ at: accessToken });
|
|
||||||
const device = await conn.getDevice(singleChannelDeviceId);
|
|
||||||
const currentVersion = device.params.fwVersion;
|
|
||||||
const firmware = await conn.getFirmwareVersion(singleChannelDeviceId);
|
|
||||||
expect(typeof firmware).toBe('object');
|
|
||||||
expect(firmware.status).toBe('ok');
|
|
||||||
expect(firmware.fwVersion).toBe(currentVersion);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -88,12 +88,4 @@ describe('invalid credentials', () => {
|
|||||||
expect(switchesAmount.msg).toBe('Authentication error');
|
expect(switchesAmount.msg).toBe('Authentication error');
|
||||||
expect(switchesAmount.error).toBe(401);
|
expect(switchesAmount.error).toBe(401);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('get device firmware version should fail', async () => {
|
|
||||||
const conn = new ewelink({ email: 'invalid', password: 'credentials' });
|
|
||||||
const firmware = await conn.getFirmwareVersion(singleChannelDeviceId);
|
|
||||||
expect(typeof firmware).toBe('object');
|
|
||||||
expect(firmware.msg).toBe('Authentication error');
|
|
||||||
expect(firmware.error).toBe(401);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -96,14 +96,6 @@ describe('valid credentials, invalid device', () => {
|
|||||||
expect(switchesAmount.msg).toBe('Device does not exist');
|
expect(switchesAmount.msg).toBe('Device does not exist');
|
||||||
expect(switchesAmount.error).toBe(500);
|
expect(switchesAmount.error).toBe(500);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('get device firmware version should fail', async () => {
|
|
||||||
const conn = new ewelink({ email, password });
|
|
||||||
const firmwareVersion = await conn.getFirmwareVersion('invalid deviceid');
|
|
||||||
expect(typeof firmwareVersion).toBe('object');
|
|
||||||
expect(firmwareVersion.msg).toBe('Device does not exist');
|
|
||||||
expect(firmwareVersion.error).toBe(500);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('valid credentials, wrong region', () => {
|
describe('valid credentials, wrong region', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user