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.
Files changed (53) hide show
  1. package/dist/index.js +3 -20
  2. package/dist/src/errorCode.d.ts +5 -0
  3. package/dist/src/globalData.d.ts +2 -0
  4. package/dist/src/openApiRequest.d.ts +9 -0
  5. package/dist/src/productConfigFileManage.d.ts +12 -0
  6. package/dist/src/protocol/Bind.d.ts +7 -0
  7. package/dist/src/protocol/DataPoint.d.ts +52 -0
  8. package/dist/src/protocol/GetDeviceStatus.d.ts +5 -0
  9. package/dist/src/protocol/Login.d.ts +12 -0
  10. package/dist/src/protocol/ProtocolBase.d.ts +11 -0
  11. package/dist/src/protocol/WifiConfig.d.ts +6 -0
  12. package/dist/src/protocol/tool.d.ts +9 -0
  13. package/dist/src/randomCode.d.ts +7 -0
  14. package/dist/src/request.d.ts +1 -0
  15. package/dist/src/services/devices.d.ts +53 -0
  16. package/dist/src/services/login.d.ts +8 -0
  17. package/dist/src/services/tool.d.ts +4 -0
  18. package/dist/src/sleep.d.ts +2 -0
  19. package/dist/src/socket.d.ts +107 -0
  20. package/dist/src/utils.d.ts +29 -0
  21. package/dist/src/wechatApi.d.ts +33 -0
  22. package/dist/src/wifiConfig/ConfigBase.d.ts +26 -0
  23. package/dist/src/wifiConfig/ap.d.ts +21 -0
  24. package/dist/src/wifiConfig/ble.d.ts +40 -0
  25. package/global.d.ts +28 -0
  26. package/index.ts +7 -0
  27. package/package.json +6 -3
  28. package/src/ble.ts +566 -0
  29. package/src/errorCode.ts +60 -0
  30. package/src/global.d.ts +42 -0
  31. package/src/globalData.ts +9 -0
  32. package/src/openApiRequest.ts +103 -0
  33. package/src/productConfigFileManage.ts +44 -0
  34. package/src/protocol/Bind.ts +22 -0
  35. package/src/protocol/GetDeviceStatus.ts +61 -0
  36. package/src/protocol/Login.ts +43 -0
  37. package/src/protocol/ProtocolBase.ts +53 -0
  38. package/src/protocol/WifiConfig.ts +41 -0
  39. package/src/protocol/dataPoint.ts +663 -0
  40. package/src/protocol/tool.ts +91 -0
  41. package/src/randomCode.ts +36 -0
  42. package/src/request.ts +22 -0
  43. package/src/sdk.ts +811 -0
  44. package/src/services/devices.ts +210 -0
  45. package/src/services/login.ts +15 -0
  46. package/src/services/tool.ts +10 -0
  47. package/src/sleep.ts +2 -0
  48. package/src/socket.ts +449 -0
  49. package/src/utils.ts +215 -0
  50. package/src/wechatApi.ts +179 -0
  51. package/src/wifiConfig/ConfigBase.ts +183 -0
  52. package/src/wifiConfig/ap.ts +193 -0
  53. package/src/wifiConfig/ble.ts +417 -0
package/src/utils.ts ADDED
@@ -0,0 +1,215 @@
1
+ import { IProductInfo } from './sdk';
2
+
3
+ export function ab2hex(buffer: ArrayBuffer) {
4
+ let hexArr = Array.prototype.map.call(new Uint8Array(buffer), function (bit) {
5
+ return ('00' + bit.toString(16)).slice(-2);
6
+ });
7
+ return hexArr.join('');
8
+ }
9
+
10
+ export function compareWXSDKVersion(v1: string, v2: string) {
11
+ const v1Arr = v1.split('.');
12
+ const v2Arr = v2.split('.');
13
+ const len = Math.max(v1.length, v2.length);
14
+
15
+ while (v1Arr.length < len) {
16
+ v1Arr.push('0');
17
+ }
18
+ while (v2Arr.length < len) {
19
+ v2Arr.push('0');
20
+ }
21
+
22
+ for (let i = 0; i < len; i++) {
23
+ const num1 = parseInt(v1[i]);
24
+ const num2 = parseInt(v2[i]);
25
+
26
+ if (num1 > num2) {
27
+ return 1;
28
+ } else if (num1 < num2) {
29
+ return -1;
30
+ }
31
+ }
32
+ return 0;
33
+ }
34
+
35
+ export const isError = (err: unknown): err is IError => {
36
+ return err != null && typeof (err as IError).errorCode === 'symbol';
37
+ };
38
+
39
+ export const wrapErrorInfo = (errorMessage: string) => ({
40
+ errorCode: errorMessage,
41
+ errorMessage,
42
+ });
43
+
44
+ export const unionBy = <T>(array: T[], key: string) => {
45
+ return array.reduce<T[]>((acc, item) => {
46
+ const keyValue = item[key];
47
+ if (!acc.some((i) => i[key] === keyValue)) {
48
+ acc.push(item);
49
+ }
50
+ return acc;
51
+ }, []);
52
+ };
53
+
54
+ interface IWXDevicesResult {
55
+ success: true;
56
+ bleDevices: WechatMiniprogram.BlueToothDevice[];
57
+ }
58
+ export function isWXDevicesResult(res: unknown): res is IWXDevicesResult {
59
+ return (
60
+ (res as IWXDevicesResult).success &&
61
+ Object.prototype.toString.call((res as IWXDevicesResult).bleDevices) ===
62
+ '[object Array]'
63
+ );
64
+ }
65
+
66
+ // hex转ArrayBuffer
67
+ export function str2Buf(arr: string) {
68
+ var length = arr.length;
69
+ var buffer = new ArrayBuffer(length + 2);
70
+ var dataview = new DataView(buffer);
71
+ for (let i = 0; i < length; i++) {
72
+ dataview.setUint8(i, parseInt(arr[i], 16));
73
+ }
74
+ return buffer;
75
+ }
76
+
77
+ // 把协议导出的数据转换为可以发送给蓝牙的数据
78
+ export const numberArray2Uint8Array = (numArr: number[]) => {
79
+ const buffer = new ArrayBuffer(numArr.length);
80
+ const uint8Array = new Uint8Array(buffer);
81
+ for (let i = 0; i < buffer.byteLength; i++) {
82
+ uint8Array[i] = numArr[i];
83
+ }
84
+ return uint8Array;
85
+ };
86
+
87
+ export const advertisData2PkAndMac = (
88
+ advertisData: ArrayBuffer,
89
+ pks: string[]
90
+ ) => {
91
+ let pkUintArray = advertisData.slice(advertisData.byteLength - 16);
92
+ let macUintArray = advertisData.slice(0, advertisData.byteLength - 16);
93
+ let productKey = ab2hex(pkUintArray);
94
+
95
+ if (pks.find((item) => item === productKey)) {
96
+ // 存在
97
+ const mac = ab2hex(macUintArray);
98
+ return { productKey, mac };
99
+ } else {
100
+ // 由于小程序安卓只接收ff type的广播数据,会乱序,所以这里需要做一次判断
101
+ pkUintArray = advertisData.slice(0, 16);
102
+ macUintArray = advertisData.slice(16);
103
+ productKey = ab2hex(pkUintArray);
104
+ const mac = ab2hex(macUintArray);
105
+ return { productKey, mac };
106
+ }
107
+ };
108
+
109
+ export const isSameDevice = (deviceA: IDevice, deviceB: IDevice) => {
110
+ return (
111
+ deviceA.mac === deviceB.mac && deviceA.productKey === deviceB.productKey
112
+ );
113
+ };
114
+
115
+ export const merageBleLocalDevices = (
116
+ mainDevice: IDevice[],
117
+ localDevice: IDevice[]
118
+ ) => {
119
+ localDevice.map((localD) => {
120
+ const target = mainDevice.find((device) => isSameDevice(device, localD));
121
+ if (!target) {
122
+ // 没有则插入这条本地设备
123
+ mainDevice.push(localD);
124
+ } else {
125
+ target.isBleOnline = true;
126
+ target.bleDeviceID = localD.bleDeviceID;
127
+ }
128
+ });
129
+ return mainDevice;
130
+ };
131
+
132
+ export const merageLanLocalDevices = (
133
+ mainDevice: IDevice[],
134
+ localDevice: IDevice[]
135
+ ) => {
136
+ localDevice.map((localD) => {
137
+ const target = mainDevice.find((device) => isSameDevice(device, localD));
138
+ if (!target) {
139
+ // 没有则插入这条本地设备
140
+ mainDevice.push(localD);
141
+ } else {
142
+ target.isLanOnline = true;
143
+ }
144
+ });
145
+ return mainDevice;
146
+ };
147
+
148
+ export const BTDevice2GDevice = (
149
+ BTDevice: WechatMiniprogram.BlueToothDevice,
150
+ pks: string[]
151
+ ) => {
152
+ const { productKey, mac } = advertisData2PkAndMac(BTDevice.advertisData, pks);
153
+ const device: IDevice = {
154
+ mac,
155
+ did: '',
156
+ connectType: 'NONE',
157
+ isBleOnline: true,
158
+ isLanOnline: false,
159
+ isOnline: false,
160
+ productKey,
161
+ name: BTDevice.name,
162
+ isBind: false,
163
+ bleDeviceID: BTDevice.deviceId,
164
+ ctime: new Date().getTime(),
165
+ };
166
+ return device;
167
+ };
168
+
169
+ // 如果都不存在 就去连接大循环
170
+ export const getFirstConnectType = (
171
+ device: IDevice,
172
+ type?: TConnectType
173
+ ): TConnectType => {
174
+ if (!type) {
175
+ if (device.isLanOnline) return 'LAN';
176
+ if (device.isBleOnline) return 'BLE';
177
+ return 'WAN';
178
+ } else {
179
+ if (type === 'WAN') return 'WAN';
180
+
181
+ switch (type) {
182
+ case 'BLE': {
183
+ return device.isBleOnline ? 'BLE' : 'NONE';
184
+ }
185
+ case 'LAN': {
186
+ return device.isLanOnline ? 'LAN' : 'NONE';
187
+ }
188
+ }
189
+ }
190
+
191
+ return 'WAN';
192
+ };
193
+
194
+ export const getProductInfoThroughPK = (
195
+ pk: string,
196
+ productInfos: IProductInfo[]
197
+ ) => {
198
+ return productInfos.find((item) => item.productKey === pk);
199
+ };
200
+
201
+ export const mergeObject = (obj1: any, obj2: any) => {
202
+ for (let key in obj2) {
203
+ if (obj2[key] == null || obj2[key] === '') continue;
204
+ obj1[key] = obj2[key];
205
+ }
206
+ return obj1;
207
+ };
208
+ export function hex2ab(str) {
209
+ const res = [];
210
+ for (let i = 0; i < str.length; i += 2) {
211
+ var hex = str.slice(i, i + 2);
212
+ res.push(parseInt(hex, 16));
213
+ }
214
+ return new Uint8Array(res);
215
+ }
@@ -0,0 +1,179 @@
1
+ import sleep from "./sleep";
2
+
3
+ interface IBluetoothAdapterStateResult {
4
+ discovering: boolean;
5
+ available: boolean;
6
+ }
7
+
8
+ interface IWechatResult {
9
+ errMsg: string;
10
+ errCode: number;
11
+ }
12
+
13
+ export function openBluetoothAdapter() {
14
+ return new Promise<IWechatResult>((res, rej) => {
15
+ wx.openBluetoothAdapter({
16
+ success: res,
17
+ fail: rej,
18
+ })
19
+ })
20
+ }
21
+
22
+ export function closeBluetoothAdapter() {
23
+ return new Promise<IWechatResult>((res, rej) => {
24
+ wx.closeBluetoothAdapter({
25
+ success: res,
26
+ fail: rej,
27
+ })
28
+ })
29
+ }
30
+
31
+ export function getBluetoothAdapterState() {
32
+ return new Promise<IBluetoothAdapterStateResult>((res, rej) => {
33
+ wx.getBluetoothAdapterState({
34
+ success: res,
35
+ fail: rej,
36
+ })
37
+ })
38
+ }
39
+
40
+ export function startBluetoothDevicesDiscovery() {
41
+ return new Promise<IWechatResult>((res, rej) => {
42
+ wx.startBluetoothDevicesDiscovery({
43
+ success: res,
44
+ fail: rej,
45
+ interval: 100
46
+ })
47
+ })
48
+ }
49
+
50
+ export function getBluetoothDevices() {
51
+ return new Promise<WechatMiniprogram.BlueToothDevice[]>((res, rej) => {
52
+ wx.getBluetoothDevices({
53
+ success: (({ devices }) => res(devices)),
54
+ fail: rej,
55
+ })
56
+ })
57
+ }
58
+
59
+ export function createBLEConnection(deviceId: string, timeout: number) {
60
+ return new Promise<IWechatResult>((res, rej) => {
61
+ wx.createBLEConnection({
62
+ deviceId,
63
+ timeout,
64
+ success: (r => res(r as IWechatResult)),
65
+ fail: ((err) => {
66
+ if (err.errCode === -1) {
67
+ res(err);
68
+ } else {
69
+ rej(err);
70
+ }
71
+ }),
72
+ })
73
+ })
74
+ }
75
+
76
+ interface IBLEService {
77
+ uuid: string;
78
+ isPrimary: boolean;
79
+ }
80
+
81
+ export function getBLEDeviceServices(deviceId: string) {
82
+ return new Promise<IBLEService[]>((res, rej) => {
83
+ wx.getBLEDeviceServices({
84
+ deviceId,
85
+ success: (({ services }) => res(services)),
86
+ fail: rej,
87
+ })
88
+ })
89
+ }
90
+
91
+ interface IBLECharacteristic {
92
+ uuid: string;
93
+ properties: {
94
+ read: boolean;
95
+ write: boolean;
96
+ notify: boolean;
97
+ indicate: boolean;
98
+ }
99
+ }
100
+
101
+ export function getBLEDeviceCharacteristics(deviceId: string, serviceId: string) {
102
+ return new Promise<IBLECharacteristic[]>((res, rej) => {
103
+ wx.getBLEDeviceCharacteristics({
104
+ deviceId,
105
+ serviceId,
106
+ success: (({ characteristics }) => res(characteristics)),
107
+ fail: rej,
108
+ })
109
+ })
110
+ }
111
+
112
+ export function notifyBLECharacteristicValueChange(
113
+ deviceId: string,
114
+ serviceId: string,
115
+ characteristicId: string,
116
+ state: boolean = true
117
+ ) {
118
+ return new Promise<IWechatResult>((res, rej) => {
119
+ wx.notifyBLECharacteristicValueChange({
120
+ deviceId,
121
+ serviceId,
122
+ characteristicId,
123
+ state,
124
+ success: res,
125
+ fail: rej,
126
+ })
127
+ })
128
+ }
129
+
130
+ export function writeBLECharacteristicValue(
131
+ deviceId: string,
132
+ serviceId: string,
133
+ characteristicId: string,
134
+ value: ArrayBuffer,
135
+ ) {
136
+ return new Promise<IWechatResult>((res) => {
137
+ console.log('writeBLECharacteristicValue')
138
+ wx.writeBLECharacteristicValue({
139
+ deviceId,
140
+ serviceId,
141
+ characteristicId,
142
+ value,
143
+ complete: res,
144
+ })
145
+ })
146
+ }
147
+
148
+ export function unpackWriteBLECharacteristicValue(
149
+ deviceId: string,
150
+ serviceId: string,
151
+ characteristicId: string,
152
+ value: ArrayBuffer,
153
+ ) {
154
+ if (value.byteLength === 0) {
155
+ throw new Error('value is not empty');
156
+ }
157
+ return new Promise<IWechatResult>(async (res, rej) => {
158
+ let pos = 0;
159
+ let bytes = value.byteLength;
160
+ let writeRes;
161
+ while (bytes > 0) {
162
+ await sleep(30);
163
+ const tmpBuffer = value.slice(pos, pos + 20);
164
+ pos += 20;
165
+ bytes -= 20;
166
+ writeRes = await writeBLECharacteristicValue(
167
+ deviceId,
168
+ serviceId,
169
+ characteristicId,
170
+ tmpBuffer,
171
+ );
172
+ console.log('unpackWriteBLECharacteristicValue', pos / 20, writeRes);
173
+ if (writeRes.errCode !== 0) {
174
+ break;
175
+ }
176
+ }
177
+ writeRes.errCode !== 0 ? rej(writeRes) : res(writeRes);
178
+ })
179
+ }
@@ -0,0 +1,183 @@
1
+ import { IRandomCodesResult, IResult, TimeoutHandle } from "../sdk";
2
+ import sleep from "../sleep";
3
+ import errorCode from "../errorCode";
4
+ import { bindMac, checkDeviceRegister } from '../services/devices';
5
+
6
+ interface IRejectCallback {
7
+ (result: IResult<unknown>): void;
8
+ }
9
+ class ConfigBase {
10
+ ssid = '';
11
+ password = '';
12
+ specialProductKeys: string[] = [];
13
+ disableSearchDevice = false;
14
+ specialProductKeySecrets: string[] = []
15
+ private timeoutHandler: TimeoutHandle = null;
16
+ private setDeviceOnboardingDeployRej?: (value: unknown) => void = () => {}; // 保存promise的rej,用于临时中断
17
+ // private setDeviceOnboardingDeployRes?: (value: unknown) => void = () => {}; // 保存promise的res,用于临时中断
18
+
19
+ constructor(ssid: string, password: string, specialProductKeys: string[], specialProductKeySecrets: string[]) {
20
+ this.ssid = ssid;
21
+ this.password = password;
22
+ this.specialProductKeys = specialProductKeys;
23
+ this.specialProductKeySecrets = specialProductKeySecrets;
24
+ }
25
+
26
+ public cleanTimeout = () => {
27
+ this.disableSearchDevice = true;
28
+ this.timeoutHandler && clearTimeout(this.timeoutHandler);
29
+ this.timeoutHandler = null;
30
+ console.log("this.timeoutHandler", this.timeoutHandler)
31
+ }
32
+
33
+ stopDeviceOnboardingDeploy = (): void => {
34
+ if (this.setDeviceOnboardingDeployRej) {
35
+ this.setDeviceOnboardingDeployRej({
36
+ success: false,
37
+ err: errorCode.GIZ_SDK_ONBOARDING_STOPPED,
38
+ });
39
+ }
40
+ this.cleanTimeout();
41
+ };
42
+
43
+ hasTimeoutHandler = (cb?: IRejectCallback) => {
44
+ if (this.timeoutHandler) {
45
+ // 方法还在执行中
46
+ cb &&
47
+ cb({
48
+ success: false,
49
+ err: errorCode.GIZ_SDK_DEVICE_CONFIG_IS_RUNNING,
50
+ });
51
+ return true;
52
+ }
53
+ return false;
54
+ };
55
+
56
+ handleTimeout = () => {
57
+ if (this.setDeviceOnboardingDeployRej) {
58
+ this.setDeviceOnboardingDeployRej({
59
+ success: false,
60
+ err: {
61
+ errorCode: errorCode.CONFIG_TIME_OUT,
62
+ errorMessage: 'time out',
63
+ },
64
+ });
65
+ }
66
+ this.timeoutHandler = null;
67
+ }
68
+
69
+ /**
70
+ * 大循环确认
71
+ */
72
+ protected searchDevice = ({ ssid, password }: { ssid: string; password: string }) => {
73
+ return new Promise<IResult<IRandomCodesResult[]>>((res, rej) => {
74
+ console.debug('GIZ_SDK: 开始大循环搜索设备')
75
+ const query = async () => {
76
+
77
+ if (!this.hasTimeoutHandler()) {
78
+ return;
79
+ }
80
+
81
+ try {
82
+ const data = await checkDeviceRegister({
83
+ SSID: ssid,
84
+ password,
85
+ productKeys: this.specialProductKeys,
86
+ })
87
+
88
+ // console.debug('GIZ_SDK: try get device random codes', data);
89
+ if (data.err?.errorCode === errorCode.GIZ_OPENAPI_TOKEN_INVALID.errorCode) {
90
+ // token 失效
91
+ rej({
92
+ success: false,
93
+ err: errorCode.GIZ_OPENAPI_TOKEN_INVALID,
94
+ });
95
+ return;
96
+ }
97
+
98
+ if (data.err || (data.data as IRandomCodesResult[]).length === 0) {
99
+ // 重新请求
100
+ console.debug('GIZ_SDK: 大循环没有发现设备');
101
+ await sleep(1500);
102
+ !this.disableSearchDevice && query();
103
+ } else {
104
+ // 搜索到设备
105
+ console.debug('GIZ_SDK: 大循环搜索到设备', data);
106
+ res({
107
+ success: true,
108
+ data: data.data,
109
+ });
110
+ }
111
+ } catch (error) {
112
+ // 重新请求
113
+ await sleep(3000);
114
+ !this.disableSearchDevice && query();
115
+ // console.debug('GIZ_SDK: random codes error', error);
116
+ }
117
+ };
118
+ query();
119
+ });
120
+ };
121
+
122
+ initDeviceOnboardingDeploy = (_res, rej) => {
123
+ // this.setDeviceOnboardingDeployRes = res;
124
+ this.setDeviceOnboardingDeployRej = rej;
125
+ this.disableSearchDevice = false;
126
+ };
127
+
128
+ protected startTimeoutTimer = (timeout: number) => {
129
+ /**
130
+ * 设置超时时间
131
+ */
132
+ this.timeoutHandler = setTimeout(this.handleTimeout, timeout * 1000);
133
+ };
134
+
135
+ /**
136
+ * 绑定多个设备
137
+ */
138
+ protected bindDevices = (devices: IDevice[]) => {
139
+ console.log('GIZ_SDK: start bind device');
140
+ return new Promise<IResult<IDevice[]>>(async (res, rej) => {
141
+ const promises = devices.map((item) => {
142
+ const index = this.specialProductKeys.findIndex(
143
+ (pk) => item.productKey === pk
144
+ );
145
+ if (index === -1) return;
146
+ const ps = this.specialProductKeySecrets[index];
147
+
148
+ return bindMac({
149
+ mac: item.mac,
150
+ productKey: item.productKey,
151
+ productSecret: ps,
152
+ })
153
+ });
154
+
155
+ try {
156
+ const data = await Promise.all(promises);
157
+ const successDevices = devices.filter((_, index) => {
158
+ const item = data[index];
159
+ return item && item.success;
160
+ });
161
+ if (successDevices.length > 0) {
162
+ console.log('GIZ_SDK: bind device success', successDevices);
163
+ // 绑定成功,重新初始化socket
164
+ res({
165
+ success: true,
166
+ data: successDevices,
167
+ });
168
+ } else {
169
+ console.log('GIZ_SDK: bind device error', data);
170
+ rej({
171
+ success: false,
172
+ data: devices,
173
+ err: errorCode.GIZ_SDK_BIND_DEVICE_FAILED,
174
+ });
175
+ }
176
+ } catch (error) {
177
+ rej(error);
178
+ }
179
+ });
180
+ };
181
+ }
182
+
183
+ export default ConfigBase;