mirror of
https://github.com/skydiver/ewelink-api.git
synced 2025-12-21 21:33:11 +01:00
Added multi-channel devices and get/set power state (#2)
* added multi-channel device * added get and set power state * added some fixes * add “this” to call class methods * create params object before build payload * typo fixed on “switches” param * added new test cases * improved error message * added more test cases * added authentication error * added fix channel number too high * added region change if wrong * linting + small fixes * linting + renamed method * linting
This commit is contained in:
@@ -63,9 +63,99 @@ const makeAuthorizationSign = body =>
|
|||||||
.update(JSON.stringify(body))
|
.update(JSON.stringify(body))
|
||||||
.digest('base64');
|
.digest('base64');
|
||||||
|
|
||||||
|
const getDeviceTypeByUiid = uiid => {
|
||||||
|
const MAPPING = {
|
||||||
|
1: 'SOCKET',
|
||||||
|
2: 'SOCKET_2',
|
||||||
|
3: 'SOCKET_3',
|
||||||
|
4: 'SOCKET_4',
|
||||||
|
5: 'SOCKET_POWER',
|
||||||
|
6: 'SWITCH',
|
||||||
|
7: 'SWITCH_2',
|
||||||
|
8: 'SWITCH_3',
|
||||||
|
9: 'SWITCH_4',
|
||||||
|
10: 'OSPF',
|
||||||
|
11: 'CURTAIN',
|
||||||
|
12: 'EW-RE',
|
||||||
|
13: 'FIREPLACE',
|
||||||
|
14: 'SWITCH_CHANGE',
|
||||||
|
15: 'THERMOSTAT',
|
||||||
|
16: 'COLD_WARM_LED',
|
||||||
|
17: 'THREE_GEAR_FAN',
|
||||||
|
18: 'SENSORS_CENTER',
|
||||||
|
19: 'HUMIDIFIER',
|
||||||
|
22: 'RGB_BALL_LIGHT',
|
||||||
|
23: 'NEST_THERMOSTAT',
|
||||||
|
24: 'GSM_SOCKET',
|
||||||
|
25: 'AROMATHERAPY',
|
||||||
|
26: 'BJ_THERMOSTAT',
|
||||||
|
27: 'GSM_UNLIMIT_SOCKET',
|
||||||
|
28: 'RF_BRIDGE',
|
||||||
|
29: 'GSM_SOCKET_2',
|
||||||
|
30: 'GSM_SOCKET_3',
|
||||||
|
31: 'GSM_SOCKET_4',
|
||||||
|
32: 'POWER_DETECTION_SOCKET',
|
||||||
|
33: 'LIGHT_BELT',
|
||||||
|
34: 'FAN_LIGHT',
|
||||||
|
35: 'EZVIZ_CAMERA',
|
||||||
|
36: 'SINGLE_CHANNEL_DIMMER_SWITCH',
|
||||||
|
38: 'HOME_KIT_BRIDGE',
|
||||||
|
40: 'FUJIN_OPS',
|
||||||
|
41: 'CUN_YOU_DOOR',
|
||||||
|
42: 'SMART_BEDSIDE_AND_NEW_RGB_BALL_LIGHT',
|
||||||
|
43: '',
|
||||||
|
44: '',
|
||||||
|
45: 'DOWN_CEILING_LIGHT',
|
||||||
|
46: 'AIR_CLEANER',
|
||||||
|
49: 'MACHINE_BED',
|
||||||
|
51: 'COLD_WARM_DESK_LIGHT',
|
||||||
|
52: 'DOUBLE_COLOR_DEMO_LIGHT',
|
||||||
|
53: 'ELECTRIC_FAN_WITH_LAMP',
|
||||||
|
55: 'SWEEPING_ROBOT',
|
||||||
|
56: 'RGB_BALL_LIGHT_4',
|
||||||
|
57: 'MONOCHROMATIC_BALL_LIGHT',
|
||||||
|
59: 'MEARICAMERA',
|
||||||
|
1001: 'BLADELESS_FAN',
|
||||||
|
1002: 'NEW_HUMIDIFIER',
|
||||||
|
1003: 'WARM_AIR_BLOWER',
|
||||||
|
};
|
||||||
|
return MAPPING[uiid] || '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDeviceChannelCountByType = deviceType => {
|
||||||
|
const DEVICE_CHANNEL_LENGTH = {
|
||||||
|
SOCKET: 1,
|
||||||
|
SWITCH_CHANGE: 1,
|
||||||
|
GSM_UNLIMIT_SOCKET: 1,
|
||||||
|
SWITCH: 1,
|
||||||
|
THERMOSTAT: 1,
|
||||||
|
SOCKET_POWER: 1,
|
||||||
|
GSM_SOCKET: 1,
|
||||||
|
POWER_DETECTION_SOCKET: 1,
|
||||||
|
SOCKET_2: 2,
|
||||||
|
GSM_SOCKET_2: 2,
|
||||||
|
SWITCH_2: 2,
|
||||||
|
SOCKET_3: 3,
|
||||||
|
GSM_SOCKET_3: 3,
|
||||||
|
SWITCH_3: 3,
|
||||||
|
SOCKET_4: 4,
|
||||||
|
GSM_SOCKET_4: 4,
|
||||||
|
SWITCH_4: 4,
|
||||||
|
CUN_YOU_DOOR: 4,
|
||||||
|
};
|
||||||
|
return DEVICE_CHANNEL_LENGTH[deviceType] || 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDeviceTotalChannels = deviceUUID => {
|
||||||
|
const deviceType = getDeviceTypeByUiid(deviceUUID);
|
||||||
|
const channels = getDeviceChannelCountByType(deviceType);
|
||||||
|
return channels;
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
makeAuthorizationSign,
|
makeAuthorizationSign,
|
||||||
loginPayload,
|
loginPayload,
|
||||||
wssLoginPayload,
|
wssLoginPayload,
|
||||||
wssUpdatePayload,
|
wssUpdatePayload,
|
||||||
|
getDeviceTotalChannels,
|
||||||
};
|
};
|
||||||
|
|||||||
114
main.js
114
main.js
@@ -10,6 +10,7 @@ const {
|
|||||||
loginPayload,
|
loginPayload,
|
||||||
wssLoginPayload,
|
wssLoginPayload,
|
||||||
wssUpdatePayload,
|
wssUpdatePayload,
|
||||||
|
getDeviceTotalChannels,
|
||||||
} = require('./lib/ewelink-helper');
|
} = require('./lib/ewelink-helper');
|
||||||
|
|
||||||
class eWeLink {
|
class eWeLink {
|
||||||
@@ -18,14 +19,21 @@ class eWeLink {
|
|||||||
return { error: 'No credentials provided' };
|
return { error: 'No credentials provided' };
|
||||||
}
|
}
|
||||||
|
|
||||||
this.apiUrl = `https://${region}-api.coolkit.cc:8080/api`;
|
this.region = region;
|
||||||
this.apiWebSocket = `wss://${region}-pconnect3.coolkit.cc:8080/api/ws`;
|
|
||||||
this.email = email;
|
this.email = email;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.at = at;
|
this.at = at;
|
||||||
this.apiKey = apiKey;
|
this.apiKey = apiKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getApiUrl() {
|
||||||
|
return `https://${this.region}-api.coolkit.cc:8080/api`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getApiWebSocket() {
|
||||||
|
return `wss://${this.region}-pconnect3.coolkit.cc:8080/api/ws`;
|
||||||
|
}
|
||||||
|
|
||||||
async makeRequest({ method = 'GET', uri, body = {}, qs = {} }) {
|
async makeRequest({ method = 'GET', uri, body = {}, qs = {} }) {
|
||||||
const { at } = this;
|
const { at } = this;
|
||||||
|
|
||||||
@@ -35,13 +43,18 @@ class eWeLink {
|
|||||||
|
|
||||||
const response = await rp({
|
const response = await rp({
|
||||||
method,
|
method,
|
||||||
uri: `${this.apiUrl}${uri}`,
|
uri: `${this.getApiUrl()}${uri}`,
|
||||||
headers: { Authorization: `Bearer ${this.at}` },
|
headers: { Authorization: `Bearer ${this.at}` },
|
||||||
body,
|
body,
|
||||||
qs,
|
qs,
|
||||||
json: true,
|
json: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const error = _get(response, 'error', false);
|
||||||
|
if (error && [401, 402].indexOf(parseInt(error)) !== -1) {
|
||||||
|
return { error, msg: 'Authentication error' };
|
||||||
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,13 +63,31 @@ class eWeLink {
|
|||||||
email: this.email,
|
email: this.email,
|
||||||
password: this.password,
|
password: this.password,
|
||||||
});
|
});
|
||||||
const response = await rp({
|
|
||||||
|
let response = await rp({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
uri: `${this.apiUrl}/user/login`,
|
uri: `${this.getApiUrl()}/user/login`,
|
||||||
headers: { Authorization: `Sign ${makeAuthorizationSign(body)}` },
|
headers: { Authorization: `Sign ${makeAuthorizationSign(body)}` },
|
||||||
body,
|
body,
|
||||||
json: true,
|
json: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const error = _get(response, 'error', false);
|
||||||
|
const region = _get(response, 'region', false);
|
||||||
|
|
||||||
|
if (error && [400, 401, 404].indexOf(parseInt(error)) !== -1) {
|
||||||
|
return { error, msg: 'Authentication error' };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error && parseInt(error) === 301 && region) {
|
||||||
|
if (this.region !== region) {
|
||||||
|
this.region = region;
|
||||||
|
response = await this.login();
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
return { error, msg: 'Region does not exist' };
|
||||||
|
}
|
||||||
|
|
||||||
this.apiKey = _get(response, 'user.apikey', '');
|
this.apiKey = _get(response, 'user.apikey', '');
|
||||||
this.at = _get(response, 'at', '');
|
this.at = _get(response, 'at', '');
|
||||||
return response;
|
return response;
|
||||||
@@ -78,24 +109,58 @@ class eWeLink {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
async toggleDevice(deviceId) {
|
async getDevicePowerState(deviceId, channel = 1) {
|
||||||
const device = await this.getDevice(deviceId);
|
const device = await this.getDevice(deviceId);
|
||||||
const status = _get(device, 'params.switch', false);
|
const error = _get(device, 'error', false);
|
||||||
|
const switchesAmount = getDeviceTotalChannels(device.uiid);
|
||||||
|
let state = _get(device, 'params.switch', false);
|
||||||
|
const switches = _get(device, 'params.switches', false);
|
||||||
|
|
||||||
if (!status) {
|
if (error || switchesAmount < channel || (!state && !switches)) {
|
||||||
return { error: 'Device does not exist' };
|
if (error && parseInt(error) === 401) {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
return { error, msg: 'Device does not exist' };
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = status === 'on' ? 'off' : 'on';
|
if (switches) {
|
||||||
|
state = switches[channel - 1].switch;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { status: 'ok', state };
|
||||||
|
}
|
||||||
|
|
||||||
|
async setDevicePowerState(deviceId, state, channel = 1) {
|
||||||
|
const device = await this.getDevice(deviceId);
|
||||||
|
const error = _get(device, 'error', false);
|
||||||
|
const switchesAmount = getDeviceTotalChannels(device.uiid);
|
||||||
|
const status = _get(device, 'params.switch', false);
|
||||||
|
const switches = _get(device, 'params.switches', false);
|
||||||
|
|
||||||
|
if (error || switchesAmount < channel || (!status && !switches)) {
|
||||||
|
if (error && parseInt(error) === 401) {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
return { error, msg: 'Device does not exist' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = {};
|
||||||
|
|
||||||
|
if (switches) {
|
||||||
|
params.switches = switches;
|
||||||
|
params.switches[channel - 1].switch = state;
|
||||||
|
} else {
|
||||||
|
params.switch = state;
|
||||||
|
}
|
||||||
|
|
||||||
const payloadLogin = wssLoginPayload({ at: this.at, apiKey: this.apiKey });
|
const payloadLogin = wssLoginPayload({ at: this.at, apiKey: this.apiKey });
|
||||||
const payloadUpdate = wssUpdatePayload({
|
const payloadUpdate = wssUpdatePayload({
|
||||||
apiKey: this.apiKey,
|
apiKey: this.apiKey,
|
||||||
deviceId,
|
deviceId,
|
||||||
params: { switch: state },
|
params,
|
||||||
});
|
});
|
||||||
|
|
||||||
const wsp = new WebSocketAsPromised(this.apiWebSocket, {
|
const wsp = new WebSocketAsPromised(this.getApiWebSocket(), {
|
||||||
createWebSocket: url => new W3CWebSocket(url),
|
createWebSocket: url => new W3CWebSocket(url),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -107,6 +172,31 @@ class eWeLink {
|
|||||||
|
|
||||||
return { status: 'ok', state };
|
return { status: 'ok', state };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async toggleDevice(deviceId, channel = 1) {
|
||||||
|
const powerState = await this.getDevicePowerState(deviceId, channel);
|
||||||
|
const state = _get(powerState, 'state', false);
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
return { error: powerState.error, msg: 'Device does not exist' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const newState = state === 'on' ? 'off' : 'on';
|
||||||
|
|
||||||
|
const newResponse = await this.setDevicePowerState(
|
||||||
|
deviceId,
|
||||||
|
newState,
|
||||||
|
channel
|
||||||
|
);
|
||||||
|
|
||||||
|
return newResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDeviceChannelCount(deviceId) {
|
||||||
|
const device = await this.getDevice(deviceId);
|
||||||
|
const switchesAmount = getDeviceTotalChannels(device.uiid);
|
||||||
|
return switchesAmount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = eWeLink;
|
module.exports = eWeLink;
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ const allDevicesExpectations = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const specificDeviceExpectations = {
|
const specificDeviceExpectations = {
|
||||||
apikey: expect.any(String),
|
|
||||||
deviceid: expect.any(String),
|
|
||||||
name: expect.any(String),
|
name: expect.any(String),
|
||||||
|
deviceid: expect.any(String),
|
||||||
|
apikey: expect.any(String),
|
||||||
online: expect.any(Boolean),
|
online: expect.any(Boolean),
|
||||||
uiid: expect.any(Number),
|
uiid: expect.any(Number),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,15 +31,40 @@ describe('env: node script', () => {
|
|||||||
expect(device.deviceid).toBe(deviceId);
|
expect(device.deviceid).toBe(deviceId);
|
||||||
expect(device).toMatchObject(specificDeviceExpectations);
|
expect(device).toMatchObject(specificDeviceExpectations);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('get device power state', async () => {
|
||||||
|
const device = await conn.getDevice(deviceId);
|
||||||
|
const currentState = device.params.switch;
|
||||||
|
const powerState = await conn.getDevicePowerState(deviceId);
|
||||||
|
expect(typeof powerState).toBe('object');
|
||||||
|
expect(powerState.status).toBe('ok');
|
||||||
|
expect(powerState.state).toBe(currentState);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('set device power state', async () => {
|
||||||
|
jest.setTimeout(30000);
|
||||||
|
const device = await conn.getDevice(deviceId);
|
||||||
|
const currentState = device.params.switch;
|
||||||
|
const newState = currentState === 'on' ? 'off' : 'on';
|
||||||
|
const powerState = await conn.setDevicePowerState(deviceId, newState);
|
||||||
|
expect(typeof powerState).toBe('object');
|
||||||
|
expect(powerState.status).toBe('ok');
|
||||||
|
expect(powerState.state).toBe(newState);
|
||||||
|
const deviceVerify = await conn.getDevice(deviceId);
|
||||||
|
const currentStateVerify = deviceVerify.params.switch;
|
||||||
|
expect(newState).toBe(currentStateVerify);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('env: serverless', () => {
|
describe('env: serverless', () => {
|
||||||
let accessToken;
|
let accessToken;
|
||||||
|
let apiKey;
|
||||||
|
|
||||||
test('login into ewelink', async () => {
|
test('login into ewelink', async () => {
|
||||||
const conn = new ewelink({ email, password });
|
const conn = new ewelink({ email, password });
|
||||||
const login = await conn.login();
|
const login = await conn.login();
|
||||||
accessToken = login.at;
|
accessToken = login.at;
|
||||||
|
apiKey = login.user.apikey;
|
||||||
expect(typeof login).toBe('object');
|
expect(typeof login).toBe('object');
|
||||||
expect(login).toMatchObject(loginExpectations);
|
expect(login).toMatchObject(loginExpectations);
|
||||||
});
|
});
|
||||||
@@ -58,6 +83,61 @@ describe('env: serverless', () => {
|
|||||||
expect(device.deviceid).toBe(deviceId);
|
expect(device.deviceid).toBe(deviceId);
|
||||||
expect(device).toMatchObject(specificDeviceExpectations);
|
expect(device).toMatchObject(specificDeviceExpectations);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('get device power state', async () => {
|
||||||
|
const conn = new ewelink({ at: accessToken });
|
||||||
|
const device = await conn.getDevice(deviceId);
|
||||||
|
const currentState = device.params.switch;
|
||||||
|
const powerState = await conn.getDevicePowerState(deviceId);
|
||||||
|
expect(typeof powerState).toBe('object');
|
||||||
|
expect(powerState.status).toBe('ok');
|
||||||
|
expect(powerState.state).toBe(currentState);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('set device power state', async () => {
|
||||||
|
jest.setTimeout(30000);
|
||||||
|
const conn = new ewelink({ at: accessToken, apiKey });
|
||||||
|
const device = await conn.getDevice(deviceId);
|
||||||
|
const currentState = device.params.switch;
|
||||||
|
const newState = currentState === 'on' ? 'off' : 'on';
|
||||||
|
const powerState = await conn.setDevicePowerState(deviceId, newState);
|
||||||
|
expect(typeof powerState).toBe('object');
|
||||||
|
expect(powerState.status).toBe('ok');
|
||||||
|
expect(powerState.state).toBe(newState);
|
||||||
|
const deviceVerify = await conn.getDevice(deviceId);
|
||||||
|
const currentStateVerify = deviceVerify.params.switch;
|
||||||
|
expect(newState).toBe(currentStateVerify);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('valid credentials, invalid device', () => {
|
||||||
|
test('get device power state should fail', async () => {
|
||||||
|
const conn = new ewelink({ email, password });
|
||||||
|
const powerState = await conn.getDevicePowerState('invalid deviceid');
|
||||||
|
expect(typeof powerState).toBe('object');
|
||||||
|
expect(powerState.msg).toBe('Device does not exist');
|
||||||
|
expect(powerState.error).toBe(500);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('set device power state should fail', async () => {
|
||||||
|
jest.setTimeout(30000);
|
||||||
|
const conn = new ewelink({ email, password });
|
||||||
|
const powerState = await conn.setDevicePowerState('invalid deviceid', 'on');
|
||||||
|
expect(typeof powerState).toBe('object');
|
||||||
|
expect(powerState.msg).toBe('Device does not exist');
|
||||||
|
expect(powerState.error).toBe(500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('valid credentials, wrong region', () => {
|
||||||
|
test('login into ewelink should fail', async () => {
|
||||||
|
const conn = new ewelink({ region: 'eu', email, password });
|
||||||
|
expect(conn.region).toBe('eu');
|
||||||
|
const login = await conn.login();
|
||||||
|
expect(typeof login).toBe('object');
|
||||||
|
expect(login).toMatchObject(loginExpectations);
|
||||||
|
expect(conn.region).toBe('us');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('invalid credentials', () => {
|
describe('invalid credentials', () => {
|
||||||
@@ -71,9 +151,7 @@ describe('invalid credentials', () => {
|
|||||||
const conn = new ewelink({ email: 'invalid', password: 'credentials' });
|
const conn = new ewelink({ email: 'invalid', password: 'credentials' });
|
||||||
const login = await conn.login();
|
const login = await conn.login();
|
||||||
expect(typeof login).toBe('object');
|
expect(typeof login).toBe('object');
|
||||||
expect(login).toMatchObject({
|
expect(login.msg).toBe('Authentication error');
|
||||||
error: expect.any(Number),
|
|
||||||
});
|
|
||||||
expect(login.error).toBe(400);
|
expect(login.error).toBe(400);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -81,19 +159,32 @@ describe('invalid credentials', () => {
|
|||||||
const conn = new ewelink({ email: 'invalid', password: 'credentials' });
|
const conn = new ewelink({ email: 'invalid', password: 'credentials' });
|
||||||
const devices = await conn.getDevices();
|
const devices = await conn.getDevices();
|
||||||
expect(typeof devices).toBe('object');
|
expect(typeof devices).toBe('object');
|
||||||
expect(devices).toMatchObject({
|
expect(devices.msg).toBe('Authentication error');
|
||||||
msg: expect.any(String),
|
|
||||||
});
|
|
||||||
expect(devices.error).toBe(401);
|
expect(devices.error).toBe(401);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('get error response on specific device', async () => {
|
test('get error response on specific device', async () => {
|
||||||
const conn = new ewelink({ email: 'invalid', password: 'credentials' });
|
const conn = new ewelink({ email: 'invalid', password: 'credentials' });
|
||||||
const device = await conn.getDevice('invalid device id');
|
const device = await conn.getDevice(deviceId);
|
||||||
expect(typeof device).toBe('object');
|
expect(typeof device).toBe('object');
|
||||||
expect(device).toMatchObject({
|
expect(device.msg).toBe('Authentication error');
|
||||||
msg: expect.any(String),
|
|
||||||
});
|
|
||||||
expect(device.error).toBe(401);
|
expect(device.error).toBe(401);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('get device power state should fail', async () => {
|
||||||
|
const conn = new ewelink({ email: 'invalid', password: 'credentials' });
|
||||||
|
const powerState = await conn.getDevicePowerState(deviceId);
|
||||||
|
expect(typeof powerState).toBe('object');
|
||||||
|
expect(powerState.msg).toBe('Authentication error');
|
||||||
|
expect(powerState.error).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('set device power state should fail', async () => {
|
||||||
|
jest.setTimeout(30000);
|
||||||
|
const conn = new ewelink({ email: 'invalid', password: 'credentials' });
|
||||||
|
const powerState = await conn.setDevicePowerState(deviceId, 'on');
|
||||||
|
expect(typeof powerState).toBe('object');
|
||||||
|
expect(powerState.msg).toBe('Authentication error');
|
||||||
|
expect(powerState.error).toBe(401);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user