mini_program_gizwits_sdk 3.0.2-beta → 3.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +3 -20
- package/dist/src/errorCode.d.ts +5 -0
- package/dist/src/globalData.d.ts +2 -0
- package/dist/src/openApiRequest.d.ts +9 -0
- package/dist/src/productConfigFileManage.d.ts +12 -0
- package/dist/src/protocol/Bind.d.ts +7 -0
- package/dist/src/protocol/DataPoint.d.ts +52 -0
- package/dist/src/protocol/GetDeviceStatus.d.ts +5 -0
- package/dist/src/protocol/Login.d.ts +12 -0
- package/dist/src/protocol/ProtocolBase.d.ts +11 -0
- package/dist/src/protocol/WifiConfig.d.ts +6 -0
- package/dist/src/protocol/tool.d.ts +9 -0
- package/dist/src/randomCode.d.ts +7 -0
- package/dist/src/request.d.ts +1 -0
- package/dist/src/services/devices.d.ts +53 -0
- package/dist/src/services/login.d.ts +8 -0
- package/dist/src/services/tool.d.ts +4 -0
- package/dist/src/sleep.d.ts +2 -0
- package/dist/src/socket.d.ts +107 -0
- package/dist/src/utils.d.ts +29 -0
- package/dist/src/wechatApi.d.ts +33 -0
- package/dist/src/wifiConfig/ConfigBase.d.ts +26 -0
- package/dist/src/wifiConfig/ap.d.ts +21 -0
- package/dist/src/wifiConfig/ble.d.ts +40 -0
- package/global.d.ts +28 -0
- package/index.ts +7 -0
- package/package.json +6 -3
- package/src/ble.ts +566 -0
- package/src/errorCode.ts +60 -0
- package/src/global.d.ts +42 -0
- package/src/globalData.ts +9 -0
- package/src/openApiRequest.ts +103 -0
- package/src/productConfigFileManage.ts +44 -0
- package/src/protocol/Bind.ts +22 -0
- package/src/protocol/GetDeviceStatus.ts +61 -0
- package/src/protocol/Login.ts +43 -0
- package/src/protocol/ProtocolBase.ts +53 -0
- package/src/protocol/WifiConfig.ts +41 -0
- package/src/protocol/dataPoint.ts +663 -0
- package/src/protocol/tool.ts +91 -0
- package/src/randomCode.ts +36 -0
- package/src/request.ts +22 -0
- package/src/sdk.ts +811 -0
- package/src/services/devices.ts +210 -0
- package/src/services/login.ts +15 -0
- package/src/services/tool.ts +10 -0
- package/src/sleep.ts +2 -0
- package/src/socket.ts +449 -0
- package/src/utils.ts +215 -0
- package/src/wechatApi.ts +179 -0
- package/src/wifiConfig/ConfigBase.ts +183 -0
- package/src/wifiConfig/ap.ts +193 -0
- package/src/wifiConfig/ble.ts +417 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import openApiRequest, { IServiceResult } from '../openApiRequest';
|
|
2
|
+
import getRandomCodes from '../randomCode';
|
|
3
|
+
import { IRandomCodesResult } from '../sdk';
|
|
4
|
+
import { psKeySign } from './tool';
|
|
5
|
+
// eslint-disable-next-line import/no-commonjs
|
|
6
|
+
// const CryptoJS = require('crypto-js');
|
|
7
|
+
import { enc, AES, mode, pad } from 'crypto-js';
|
|
8
|
+
|
|
9
|
+
export interface IOpenApiDevice {
|
|
10
|
+
product_key: string;
|
|
11
|
+
did: string;
|
|
12
|
+
mac: string;
|
|
13
|
+
passcode: string;
|
|
14
|
+
is_online: boolean;
|
|
15
|
+
host: string;
|
|
16
|
+
port: string;
|
|
17
|
+
port_s: string;
|
|
18
|
+
ws_port: number;
|
|
19
|
+
wss_port: number;
|
|
20
|
+
dev_alias: string;
|
|
21
|
+
remark: string;
|
|
22
|
+
type: 'normal' | 'center_control' | 'sub_dev';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface IDeviceRes {
|
|
26
|
+
devices: IOpenApiDevice[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const getBindingList = async (): Promise<IServiceResult<IDevice[]>> => {
|
|
30
|
+
const data = await openApiRequest<IDeviceRes>(
|
|
31
|
+
'/app/bindings?show_disabled=0&limit=1000&skip=0',
|
|
32
|
+
{
|
|
33
|
+
method: 'GET',
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if (data.success) {
|
|
38
|
+
const newDevices: IDevice[] = data.data!.devices.map((item) => {
|
|
39
|
+
return {
|
|
40
|
+
productKey: item.product_key,
|
|
41
|
+
mac: item.mac,
|
|
42
|
+
did: item.did,
|
|
43
|
+
host: item.host,
|
|
44
|
+
port_s: item.port_s,
|
|
45
|
+
port: item.port,
|
|
46
|
+
ws_port: item.ws_port,
|
|
47
|
+
wss_port: item.wss_port,
|
|
48
|
+
isBleOnline: false,
|
|
49
|
+
isLanOnline: false,
|
|
50
|
+
connectType: 'NONE',
|
|
51
|
+
name: item.dev_alias,
|
|
52
|
+
isBind: true,
|
|
53
|
+
isOnline: item.is_online,
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
success: true,
|
|
58
|
+
data: newDevices,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
success: false,
|
|
63
|
+
err: data.err,
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export interface IBindMacParams {
|
|
68
|
+
mac: string;
|
|
69
|
+
productKey: string;
|
|
70
|
+
productSecret: string;
|
|
71
|
+
alias?: string;
|
|
72
|
+
beOwner?: boolean;
|
|
73
|
+
}
|
|
74
|
+
export async function bindMac({
|
|
75
|
+
mac,
|
|
76
|
+
productKey,
|
|
77
|
+
productSecret,
|
|
78
|
+
alias,
|
|
79
|
+
beOwner,
|
|
80
|
+
}: IBindMacParams): Promise<IServiceResult<IOpenApiDevice>> {
|
|
81
|
+
const dataJson = {
|
|
82
|
+
mac,
|
|
83
|
+
product_key: productKey,
|
|
84
|
+
dev_alias: alias,
|
|
85
|
+
set_owner: beOwner,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const { Signature, timestamp } = psKeySign(productSecret);
|
|
89
|
+
|
|
90
|
+
const data = await openApiRequest<IOpenApiDevice>('/app/bind_mac', {
|
|
91
|
+
method: 'POST',
|
|
92
|
+
data: dataJson,
|
|
93
|
+
headers: {
|
|
94
|
+
'X-Gizwits-Signature': Signature,
|
|
95
|
+
'X-Gizwits-Timestamp': timestamp,
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
return data;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface IUnbindReturn {
|
|
102
|
+
failed: string[];
|
|
103
|
+
success: string[];
|
|
104
|
+
}
|
|
105
|
+
export async function unbindDevice({
|
|
106
|
+
devices,
|
|
107
|
+
}: {
|
|
108
|
+
devices: IDevice[];
|
|
109
|
+
}): Promise<IServiceResult<IUnbindReturn>> {
|
|
110
|
+
const data = await openApiRequest<IUnbindReturn>('/app/bindings', {
|
|
111
|
+
method: 'DELETE',
|
|
112
|
+
data: {
|
|
113
|
+
devices: devices.map((device) => {
|
|
114
|
+
return { did: device.did };
|
|
115
|
+
}),
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
return data;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
interface ICheckDeviceRegisterParams {
|
|
122
|
+
SSID: string;
|
|
123
|
+
password: string;
|
|
124
|
+
productKeys: string[];
|
|
125
|
+
}
|
|
126
|
+
export async function checkDeviceRegister({
|
|
127
|
+
SSID,
|
|
128
|
+
password,
|
|
129
|
+
productKeys,
|
|
130
|
+
}: ICheckDeviceRegisterParams): Promise<IServiceResult<IRandomCodesResult[]>> {
|
|
131
|
+
const codes = getRandomCodes({
|
|
132
|
+
SSID,
|
|
133
|
+
password,
|
|
134
|
+
pks: productKeys,
|
|
135
|
+
});
|
|
136
|
+
let codeStr = '';
|
|
137
|
+
codes.map((item) => {
|
|
138
|
+
codeStr += `${item},`;
|
|
139
|
+
});
|
|
140
|
+
codeStr = codeStr.substring(0, codeStr.length - 1);
|
|
141
|
+
const data = await openApiRequest<IRandomCodesResult[]>(
|
|
142
|
+
`/app/device_register?random_codes=${codeStr}`,
|
|
143
|
+
{ method: 'get' }
|
|
144
|
+
);
|
|
145
|
+
return data;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
interface ISafeRegisterParams {
|
|
149
|
+
productKey: string;
|
|
150
|
+
productSecret: string;
|
|
151
|
+
mac: string;
|
|
152
|
+
passcode: string;
|
|
153
|
+
gwDid?: string;
|
|
154
|
+
isReset: boolean;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface ISafeRegisterReturn {
|
|
158
|
+
successDevices: IDevice[];
|
|
159
|
+
failedDevices: IDevice[];
|
|
160
|
+
}
|
|
161
|
+
export async function safeRegister({
|
|
162
|
+
productKey,
|
|
163
|
+
productSecret,
|
|
164
|
+
mac,
|
|
165
|
+
passcode,
|
|
166
|
+
gwDid,
|
|
167
|
+
isReset,
|
|
168
|
+
}: ISafeRegisterParams): Promise<IServiceResult<ISafeRegisterReturn>> {
|
|
169
|
+
let dataStr = `is_reset=${isReset ? 1 : 0}&mac=${mac}&passcode=${passcode}`;
|
|
170
|
+
if (gwDid) {
|
|
171
|
+
dataStr += `&gw_did=${gwDid}`;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const key = enc.Hex.parse(productSecret);
|
|
175
|
+
const iv = enc.Hex.parse('');
|
|
176
|
+
const srcs = enc.Utf8.parse(dataStr);
|
|
177
|
+
const encrypted = AES.encrypt(srcs, key, {
|
|
178
|
+
iv: iv,
|
|
179
|
+
mode: mode.ECB,
|
|
180
|
+
padding: pad.Pkcs7,
|
|
181
|
+
});
|
|
182
|
+
const hexStr = encrypted.ciphertext.toString().toUpperCase();
|
|
183
|
+
const data = await openApiRequest<string>(
|
|
184
|
+
`/dev/${productKey}/device`,
|
|
185
|
+
{
|
|
186
|
+
method: 'POST',
|
|
187
|
+
data: {
|
|
188
|
+
data: hexStr,
|
|
189
|
+
},
|
|
190
|
+
headers: {
|
|
191
|
+
'content-type': 'application/x-www-form-urlencoded',
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
false
|
|
195
|
+
);
|
|
196
|
+
if (data.success) {
|
|
197
|
+
// 解码
|
|
198
|
+
return {
|
|
199
|
+
success: true,
|
|
200
|
+
data: {
|
|
201
|
+
successDevices: [],
|
|
202
|
+
failedDevices: [],
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
success: false,
|
|
208
|
+
err: data.err,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import openApiRequest from "../openApiRequest";
|
|
2
|
+
|
|
3
|
+
export interface ILoginRes {
|
|
4
|
+
expire_at: number;
|
|
5
|
+
token: string;
|
|
6
|
+
uid: string;
|
|
7
|
+
}
|
|
8
|
+
export async function AnonymousLogin ({uid}: {uid: string}) {
|
|
9
|
+
return openApiRequest<ILoginRes>('/app/users', {
|
|
10
|
+
data: {
|
|
11
|
+
phone_id: uid,
|
|
12
|
+
},
|
|
13
|
+
method: 'POST',
|
|
14
|
+
}, false)
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-commonjs
|
|
2
|
+
import { MD5 } from "crypto-js";
|
|
3
|
+
|
|
4
|
+
export const psKeySign = (productSecret: string) => {
|
|
5
|
+
const timestamp = Math.round(new Date().getTime()/1000);
|
|
6
|
+
|
|
7
|
+
const str = productSecret + timestamp;
|
|
8
|
+
const Signature = MD5(str).toString();
|
|
9
|
+
return {Signature, timestamp};
|
|
10
|
+
}
|
package/src/sleep.ts
ADDED
package/src/socket.ts
ADDED
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
import errorCode from "./errorCode";
|
|
2
|
+
import request from "./openApiRequest";
|
|
3
|
+
import { compareWXSDKVersion, isError } from './utils';
|
|
4
|
+
|
|
5
|
+
// commType = 'custom' | 'attrs_v4'
|
|
6
|
+
// socketType = 'socket' | 'ssl_socket'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
interface IRespError {
|
|
10
|
+
err?: IError;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface ICommonProps {
|
|
14
|
+
appID: string;
|
|
15
|
+
token: string;
|
|
16
|
+
uid: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface IGWSProps extends ICommonProps {
|
|
20
|
+
limitSocketNum?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default class GizwitsWS {
|
|
24
|
+
|
|
25
|
+
appID: string;
|
|
26
|
+
token: string;
|
|
27
|
+
uid: string;
|
|
28
|
+
_maxSocketNum: number;
|
|
29
|
+
_bindingDevices: { [did: string]: IDevice } | null = null;
|
|
30
|
+
_connections: { [wsInfo: string]: Connection } = {};
|
|
31
|
+
_onDeviceStatusChanged?: IOnDeviceStatusChanged;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param limitSocketNum 是否限制 socket 连接数,如果限制则按照小程序sdk限制最大连接数,否则如果超过小程序限制连接数,微信可能会关闭之前的连接,也可以会有异常。
|
|
35
|
+
*/
|
|
36
|
+
constructor({
|
|
37
|
+
appID,
|
|
38
|
+
token,
|
|
39
|
+
uid,
|
|
40
|
+
limitSocketNum = true,
|
|
41
|
+
}: IGWSProps) {
|
|
42
|
+
this.appID = appID;
|
|
43
|
+
this.token = token;
|
|
44
|
+
this.uid = uid;
|
|
45
|
+
const wxSDKVersion = wx.getSystemInfoSync().SDKVersion
|
|
46
|
+
this._maxSocketNum = limitSocketNum
|
|
47
|
+
? compareWXSDKVersion(wxSDKVersion, '1.7.0') === -1 ? 1 : 5
|
|
48
|
+
: 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async init() {
|
|
52
|
+
try {
|
|
53
|
+
const result = await this._getBindingList();
|
|
54
|
+
if ((result as IRespError).err?.errorCode) {
|
|
55
|
+
return { errorCode: (result as IRespError).err?.errorCode, errorMessage: 'getting binding list failed' };
|
|
56
|
+
} else {
|
|
57
|
+
this._bindingDevices = (result as IDevice[]).reduce((map, device) => ({ ...map, [device.did]: device }), {});
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return errorCode.GIZ_SDK_OTHERWISE
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
_getDevice = (did: string): IDevice | IError => {
|
|
66
|
+
if (this._bindingDevices === null) {
|
|
67
|
+
return errorCode.GIZ_SDK_SDK_NOT_INITIALIZED
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const device = this._bindingDevices[did];
|
|
71
|
+
if (device == null) {
|
|
72
|
+
return errorCode.GIZ_OPENAPI_DEVICE_NOT_BOUND;
|
|
73
|
+
}
|
|
74
|
+
return device;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
_getConnect = (device: IDevice): Connection => {
|
|
78
|
+
const wsInfo = this._getWebsocketConnInfo(device);
|
|
79
|
+
return this._connections[wsInfo];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
_getDeviceAndConnect = (did: string): [IDevice, Connection] | IError => {
|
|
83
|
+
const device = this._getDevice(did)
|
|
84
|
+
if (isError(device)) {
|
|
85
|
+
return device;
|
|
86
|
+
}
|
|
87
|
+
const conn = this._getConnect(device);
|
|
88
|
+
if (conn == null) {
|
|
89
|
+
return errorCode.GIZ_SDK_DEVICE_NOT_SUBSCRIBED;
|
|
90
|
+
}
|
|
91
|
+
return [device, conn]
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
connectDevice = (device: IDevice) => {
|
|
95
|
+
const wsInfo = this._getWebsocketConnInfo(device);
|
|
96
|
+
let conn = this._connections[wsInfo];
|
|
97
|
+
if (conn == null) {
|
|
98
|
+
const connNum = Object.keys(this._connections).length;
|
|
99
|
+
if (this._maxSocketNum !== 0 && connNum >= this._maxSocketNum) {
|
|
100
|
+
return { success: false, errorCode: errorCode.MAX_CONNECT };
|
|
101
|
+
}
|
|
102
|
+
conn = new Connection({
|
|
103
|
+
appID: this.appID,
|
|
104
|
+
token: this.token,
|
|
105
|
+
uid: this.uid,
|
|
106
|
+
wsInfo,
|
|
107
|
+
onDeviceStatusChanged: this._handleDeviceStatusChanged
|
|
108
|
+
});
|
|
109
|
+
this._connections[wsInfo] = conn;
|
|
110
|
+
}
|
|
111
|
+
conn._addSubDid(device.did);
|
|
112
|
+
if (conn._websocket == null) {
|
|
113
|
+
conn._connectWS();
|
|
114
|
+
} else if (conn.ready) {
|
|
115
|
+
conn._subDevices([device.did]);
|
|
116
|
+
}
|
|
117
|
+
return { success: true };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
connect = (did: string) => {
|
|
121
|
+
const device = this._getDevice(did)
|
|
122
|
+
if (isError(device)) {
|
|
123
|
+
return device;
|
|
124
|
+
}
|
|
125
|
+
const res = this.connectDevice(device);
|
|
126
|
+
return res.success ? null : res.errorCode;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
send = (did: string, raw: Uint8Array[]) => {
|
|
130
|
+
const res = this._getDeviceAndConnect(did);
|
|
131
|
+
if (isError(res)) {
|
|
132
|
+
return res;
|
|
133
|
+
}
|
|
134
|
+
return res[1]._send({
|
|
135
|
+
cmd: "c2s_raw",
|
|
136
|
+
data: {
|
|
137
|
+
did: did,
|
|
138
|
+
raw
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
writeData = (device: IDevice, attrs: ICommonObj) => {
|
|
144
|
+
const conn = this._getConnect(device);
|
|
145
|
+
const success = conn != null;
|
|
146
|
+
if (success) {
|
|
147
|
+
conn._send({
|
|
148
|
+
cmd: "c2s_write",
|
|
149
|
+
data: {
|
|
150
|
+
did: device.did,
|
|
151
|
+
attrs
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return { success };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
write = (did: string, attrs: ICommonObj) => {
|
|
159
|
+
const res = this._getDeviceAndConnect(did);
|
|
160
|
+
if (isError(res)) {
|
|
161
|
+
return res;
|
|
162
|
+
}
|
|
163
|
+
return res[1]._send({
|
|
164
|
+
cmd: "c2s_write",
|
|
165
|
+
data: {
|
|
166
|
+
did: did,
|
|
167
|
+
attrs: attrs
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
readStatus = (device: IDevice, names?: string[]) => {
|
|
173
|
+
const conn = this._getConnect(device);
|
|
174
|
+
const success = conn != null;
|
|
175
|
+
if (success) {
|
|
176
|
+
conn._send({
|
|
177
|
+
cmd: "c2s_read",
|
|
178
|
+
data: {
|
|
179
|
+
did: device.did,
|
|
180
|
+
names,
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return { success };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
read = (did: string, names?: string[]) => {
|
|
188
|
+
const res = this._getDeviceAndConnect(did);
|
|
189
|
+
if (isError(res)) {
|
|
190
|
+
return res;
|
|
191
|
+
}
|
|
192
|
+
return res[1]._send({
|
|
193
|
+
cmd: "c2s_read",
|
|
194
|
+
data: {
|
|
195
|
+
did: did,
|
|
196
|
+
names: names
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
close = () => {
|
|
202
|
+
Object.values(this._connections).forEach(conn => conn.close());
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
subscribeDeviceStatus = (cb: IOnDeviceStatusChanged) => {
|
|
206
|
+
this._onDeviceStatusChanged = cb;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
_handleDeviceStatusChanged: IOnDeviceStatusChanged = (data) => {
|
|
210
|
+
const device = this._getDevice(data.did);
|
|
211
|
+
if (!isError(device)) {
|
|
212
|
+
this._onDeviceStatusChanged && this._onDeviceStatusChanged(data);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
_getBindingList = async (limit: number = 20, skip: number = 0, cacheList: IDevice[] = []): Promise<IDevice[] | IRespError> => {
|
|
217
|
+
const url = `/app/bindings?show_disabled=0&limit=${limit}&skip=${skip}`;
|
|
218
|
+
const { err, data } = await request<{ devices: IDevice[] }>(`${url}`, { method: 'GET' });
|
|
219
|
+
if (err) {
|
|
220
|
+
return {err};
|
|
221
|
+
}
|
|
222
|
+
const devices = [...cacheList, ...data?.devices || []]
|
|
223
|
+
if (data && data.devices.length === limit) {
|
|
224
|
+
return await this._getBindingList(limit, limit + skip, devices);
|
|
225
|
+
}
|
|
226
|
+
return devices;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
_getWebsocketConnInfo = (device) => {
|
|
230
|
+
return device.host.includes('stage')
|
|
231
|
+
? 'wss://wxstage.gizwits.com'
|
|
232
|
+
: 'wss://wxm2m.gizwits.com';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
interface IConnectProps extends ICommonProps {
|
|
239
|
+
wsInfo: string;
|
|
240
|
+
onDeviceStatusChanged?: IOnDeviceStatusChanged;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export class Connection {
|
|
244
|
+
ready: boolean = false;
|
|
245
|
+
appID: string;
|
|
246
|
+
token: string;
|
|
247
|
+
uid: string;
|
|
248
|
+
commType: string = 'attrs_v4';
|
|
249
|
+
_heartbeatInterval = 60;
|
|
250
|
+
_keepaliveTime = 180;
|
|
251
|
+
_loginIntveral = 5000;
|
|
252
|
+
autoSubscribe = false;
|
|
253
|
+
_wsUrl: string;
|
|
254
|
+
_websocket: WechatMiniprogram.SocketTask | null = null;
|
|
255
|
+
_heartbeatTimerId?: any;
|
|
256
|
+
_loginFailedTimes: number = 0;
|
|
257
|
+
_subDids: Set<string> = new Set();
|
|
258
|
+
_socketRespHandleMap: { [cmd: string]: (resp?: any) => void } = {};
|
|
259
|
+
_onDeviceStatusChanged?: IOnDeviceStatusChanged;
|
|
260
|
+
|
|
261
|
+
constructor({
|
|
262
|
+
appID,
|
|
263
|
+
token,
|
|
264
|
+
uid,
|
|
265
|
+
wsInfo,
|
|
266
|
+
onDeviceStatusChanged,
|
|
267
|
+
}: IConnectProps) {
|
|
268
|
+
this.appID = appID;
|
|
269
|
+
this.token = token;
|
|
270
|
+
this.uid = uid;
|
|
271
|
+
this._wsUrl = `${wsInfo}/ws/app/v1`;
|
|
272
|
+
this._heartbeatTimerId = undefined;
|
|
273
|
+
this._loginFailedTimes = 0;
|
|
274
|
+
this._onDeviceStatusChanged = onDeviceStatusChanged;
|
|
275
|
+
this._socketRespHandleMap = {
|
|
276
|
+
pong: this.pongResp,
|
|
277
|
+
login_res: this._loginResp,
|
|
278
|
+
subscribe_res: this._subscribeResp,
|
|
279
|
+
s2c_online_status: this._onlineResp,
|
|
280
|
+
s2c_raw: this._rawChangedResp,
|
|
281
|
+
s2c_noti: this._statusChangedResp,
|
|
282
|
+
s2c_invalid_msg: this._invalidMsgResp,
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
_addSubDid = (did) => {
|
|
287
|
+
this._subDids.add(did);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
_connectWS = () => {
|
|
291
|
+
this._websocket = wx.connectSocket({ url: this._wsUrl });
|
|
292
|
+
this._websocket.onClose(this.handleClose);
|
|
293
|
+
this._websocket.onOpen(this.handleOpen);
|
|
294
|
+
this._websocket.onError(this.handleError);
|
|
295
|
+
this._websocket.onMessage(this.handleMessage);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
_subDevices = (dids: string[]) => {
|
|
299
|
+
const json = {
|
|
300
|
+
cmd: "subscribe_req",
|
|
301
|
+
data: dids.map(did => ({ did }))
|
|
302
|
+
};
|
|
303
|
+
this._send(json);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
_send = (data: object, forced: boolean = false) => {
|
|
307
|
+
console.log('Socket send', data, forced);
|
|
308
|
+
return new Promise<WechatMiniprogram.GeneralCallbackResult>((resolve) => {
|
|
309
|
+
if (this._websocket && (forced || this.ready)) {
|
|
310
|
+
this._websocket.send({
|
|
311
|
+
data: JSON.stringify(data),
|
|
312
|
+
complete: (res) => {
|
|
313
|
+
console.debug('GIZ_SDK: socket send res', res);
|
|
314
|
+
if ([
|
|
315
|
+
'sendSocketMessage:fail debug invoke no active session',
|
|
316
|
+
'sendSocketMessage:fail wcwss taskID not exist'
|
|
317
|
+
].includes(res && res.errMsg)) {
|
|
318
|
+
// 重新connect
|
|
319
|
+
this._websocket && this._websocket.close({});
|
|
320
|
+
this._connectWS();
|
|
321
|
+
}
|
|
322
|
+
resolve(res);
|
|
323
|
+
}
|
|
324
|
+
})
|
|
325
|
+
}
|
|
326
|
+
})
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
close = () => {
|
|
330
|
+
this.ready = false;
|
|
331
|
+
if (this._heartbeatTimerId) {
|
|
332
|
+
clearInterval(this._heartbeatTimerId);
|
|
333
|
+
}
|
|
334
|
+
if (this._websocket) {
|
|
335
|
+
this._websocket.close({});
|
|
336
|
+
this._websocket = null;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
handleClose = (res: { code: number, reason: string }) => {
|
|
341
|
+
console.log('socket close', res);
|
|
342
|
+
this.close();
|
|
343
|
+
this._stopPing();
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
handleOpen = () => {
|
|
347
|
+
// socket 打开后执行登录
|
|
348
|
+
console.log(' socket open')
|
|
349
|
+
this._login();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
handleMessage = ({ data }: { data: string | ArrayBuffer }) => {
|
|
353
|
+
console.log('message', data);
|
|
354
|
+
const res = JSON.parse(data as string);
|
|
355
|
+
const handle = this._socketRespHandleMap[res.cmd];
|
|
356
|
+
handle && handle(res.data);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
handleError = (err: { errMsg: string }) => {
|
|
360
|
+
console.debug('GIZ_SDK: socket error', err);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
_login = () => {
|
|
364
|
+
const data = {
|
|
365
|
+
cmd: 'login_req',
|
|
366
|
+
data: {
|
|
367
|
+
appid: this.appID,
|
|
368
|
+
uid: this.uid,
|
|
369
|
+
token: this.token,
|
|
370
|
+
p0_type: this.commType,
|
|
371
|
+
heartbeat_interval: this._keepaliveTime,
|
|
372
|
+
auto_subscribe: this.autoSubscribe
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
this._send(data, true);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
_tryLoginAgain = () => {
|
|
379
|
+
this._loginFailedTimes += 1;
|
|
380
|
+
setTimeout(() => {
|
|
381
|
+
this._login();
|
|
382
|
+
}, this._loginFailedTimes * this._loginIntveral);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
_startPing = () => {
|
|
386
|
+
this._heartbeatTimerId = setInterval(() => {
|
|
387
|
+
this._send({ cmd: 'ping' });
|
|
388
|
+
}, this._heartbeatInterval * 1000);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
_stopPing = () => {
|
|
392
|
+
this._heartbeatTimerId && clearInterval(this._heartbeatTimerId);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
pongResp = () => {
|
|
396
|
+
// 不处理
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
_loginResp = (data) => {
|
|
400
|
+
if (data.success == true) {
|
|
401
|
+
this._loginFailedTimes = 0;
|
|
402
|
+
this.ready = true;
|
|
403
|
+
this._startPing();
|
|
404
|
+
this._subDevices([...this._subDids]);
|
|
405
|
+
} else if (this._loginFailedTimes < 3) {
|
|
406
|
+
console.debug('GIZ_SDK: Login failed, will try again, please wait...');
|
|
407
|
+
this._tryLoginAgain();
|
|
408
|
+
} else {
|
|
409
|
+
console.debug('GIZ_SDK: Login failed');
|
|
410
|
+
this.close();
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
_subscribeResp = (data) => {
|
|
415
|
+
console.log('GIZ_SDK: subscribe_res', data);
|
|
416
|
+
if (data && data.success) {
|
|
417
|
+
// 订阅成功设备获取设备状态
|
|
418
|
+
data.success.forEach(d => this._send({
|
|
419
|
+
cmd: "c2s_read",
|
|
420
|
+
data: {
|
|
421
|
+
did: d.did,
|
|
422
|
+
}
|
|
423
|
+
}))
|
|
424
|
+
}
|
|
425
|
+
console.debug('GIZ_SDK: subscribe_res', data);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
_onlineResp = (data: { did: string, online: boolean }) => {
|
|
429
|
+
this._onDeviceStatusChanged && this._onDeviceStatusChanged({
|
|
430
|
+
did: data.did, attrs: { is_online: data.online, ...data }
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
_rawChangedResp = (data: IDeviceRawStatusChangedProps) => {
|
|
435
|
+
this._onDeviceStatusChanged && this._onDeviceStatusChanged(data);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
_statusChangedResp = (data: IDeviceStatusChangedProps) => {
|
|
439
|
+
this._onDeviceStatusChanged && this._onDeviceStatusChanged(data);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
_invalidMsgResp = (data) => {
|
|
443
|
+
if (data.error_code === 1003) {
|
|
444
|
+
// 重新登录
|
|
445
|
+
this._login();
|
|
446
|
+
}
|
|
447
|
+
console.debug('GIZ_SDK: s2c_invalid_msg', data);
|
|
448
|
+
}
|
|
449
|
+
}
|