Commit 7d9d885d by 姜雷

添加蓝牙和websocket的hook方法

parent e77fcdb1
import Taro, { useEffect, useReducer } from '@tarojs/taro';
import { ab2str, str2ab } from '@/utils/arrayBuffer';
import Actions from '@/types/Store/Actions';
enum BlueToothError {
BlueToothNotOpen = 'BlueToothNotOpen',
DeviceNotFound = 'DeviceNotFound',
}
type NotifyUUIDs = {
notifyId: string;
writeId: string;
readId: string;
};
type DeviceInfo = {
deviceId: string;
uuid: string;
isPrimary: boolean;
serviceId: string;
notifyId: string;
writeId: string;
readId: string;
};
type StoreState = {
bluetoothState: boolean;
deviceDone: boolean;
deviceInfo: DeviceInfo;
};
const initState = {
bluetoothState: false,
deviceDone: false,
deviceInfo: {
deviceId: '',
uuid: '',
isPrimary: false,
serviceId: '',
notifyId: '',
writeId: '',
readId: '',
},
};
const reducer = (state: StoreState, action: Actions): StoreState => {
switch (action.type) {
case 'BLUETOOTH_STATE_CHANGE':
return {
...state,
bluetoothState: action.payload,
};
case 'GET_DEVICE_ID':
return {
...state,
deviceInfo: {
...state.deviceInfo,
deviceId: action.payload,
},
};
case 'GET_NOTIFY_UUID':
return {
...state,
deviceInfo: {
...state.deviceInfo,
...action.payload,
},
};
case 'DEVICE_STATE_CHANGE':
return {
...state,
deviceDone: action.payload,
};
default:
return state;
}
};
const useBluetooth = (
deviceCode: string,
getBluetoothData: (data: string) => void,
): {
state: boolean;
sendMessageToDevice: (
msg: string,
) => Promise<Taro.writeBLECharacteristicValue.Promised>;
} => {
const [state, dispatch] = useReducer(reducer, initState);
const warnBluetoothOpen = () => {
return Taro.showModal({
title: '警告',
content: '为保障正常使用,请打开蓝牙功能',
});
};
const DevicesDiscoveryHandle = (): Promise<string> => {
let timer: NodeJS.Timeout | null = null;
return new Promise((resolve, reject) => {
// if (isOnlyBluetooth) {
// timer = setTimeout(() => {
// reject({ msg: BlueToothError.DeviceNotFound });
// }, 10000);
// } else {
timer = setTimeout(() => {
reject({ msg: BlueToothError.DeviceNotFound });
}, 5000);
// }
Taro.onBluetoothDeviceFound(res => {
const devices = res.devices;
if (devices[0].name === deviceCode) {
let deviceId = devices[0].deviceId;
Taro.stopBluetoothDevicesDiscovery();
dispatch({ type: 'GET_DEVICE_ID', payload: deviceId });
if (timer) {
clearInterval(timer);
}
resolve(deviceId);
}
});
});
};
const createConnection = (deviceId: string): Promise<string> => {
return new Promise((resolve, reject) => {
Taro.createBLEConnection({
deviceId,
});
let abStr = '';
Taro.onBLECharacteristicValueChange(res => {
console.log(
`characteristic ${res.characteristicId} has changed, now is ${
res.value
}`,
);
console.log(res.value);
let datastr = ab2str(res.value);
console.log('获取socket消息: ', datastr);
if (datastr === '<>') {
console.log('结束蓝牙以及socket: ', datastr);
this.closeDeviceSocket();
this.closeBluetoothConnection();
} else {
if (
datastr.substring(0, 1) === '{' &&
datastr.substring(datastr.length - 1, datastr.length) === '}'
) {
console.log('<---发送完整数据: ', datastr);
// if (socketTask) {
// socketTask.send({
// data: str2ab(datastr),
// success: msg => {
// console.log('发送完整数据:', msg, '--->');
// },
// fail: err => {
// console.log('发送完整数据:', err, '--->');
// },
// });
// }
getBluetoothData(datastr);
} else if (datastr.substring(0, 1) === '{') {
console.log('接受头部数据: ', datastr);
abStr = datastr;
} else if (
abStr.length &&
datastr.substring(datastr.length - 1, datastr.length) === '}'
) {
abStr += datastr;
console.log('接受尾部数据后: ', abStr);
console.log('<---发送完整数据: ', abStr);
// if (socketTask) {
// socketTask.send({
// data: str2ab(abStr),
// success: msg => {
// console.log('发送完整数据:', msg, '--->');
// },
// fail: err => {
// console.log('发送完整数据:', err, '--->');
// },
// });
// }
getBluetoothData(datastr);
abStr = '';
} else {
console.log('弃掉数据:', datastr);
}
}
});
Taro.onBLEConnectionStateChange(res => {
// const { showerState } = this.state;
console.log(
`device ${res.deviceId} state has changed, connected: ${
res.connected
}`,
);
if (res.connected) {
// this.setState({
// deviceDone: true,
// showerState: true,
// });
dispatch({ type: 'DEVICE_STATE_CHANGE', payload: true });
resolve(res.deviceId);
} else {
console.log(res);
this.setState({
deviceDone: false,
});
dispatch({ type: 'DEVICE_STATE_CHANGE', payload: false });
// if (showerState) {
// this.reConnectDeviceBluetooth();
// }
reject('蓝牙未成功连接');
}
});
});
};
const getDeviceServices = (
deviceId: string,
): Promise<{
deviceId: string;
serviceId: string;
}> => {
return Taro.getBLEDeviceServices({
deviceId: deviceId,
}).then(services => {
const serviceArr = services.services;
let tempService = serviceArr.find(
item =>
item.uuid.toLocaleLowerCase() ===
'6e401103-b5a3-f393-e0a9-e50e24dcca9e',
);
let service: Taro.getBLEDeviceServices.PromisedPropServicesItem = tempService
? tempService
: services[0];
console.log('获取全部services: ', services, '. serviceId: ', service);
const serviceId = service.uuid;
return { deviceId: deviceId, serviceId: serviceId };
});
};
const getDeviceCharacter = ({
deviceId,
serviceId,
}: {
deviceId: string;
serviceId: string;
}): Promise<NotifyUUIDs> => {
return Taro.getBLEDeviceCharacteristics({
deviceId,
serviceId,
}).then(res => {
let notifyId = '',
writeId = '',
readId = '';
for (let i = 0; i < res.characteristics.length; i++) {
let charc = res.characteristics[i];
if (charc.properties.notify) {
notifyId = charc.uuid;
}
if (charc.properties.write) {
writeId = charc.uuid;
}
if (charc.properties.write) {
readId = charc.uuid;
}
}
dispatch({
type: 'GET_NOTIFY_UUID',
payload: {
notifyId,
writeId,
readId,
},
});
return {
notifyId,
writeId,
readId,
};
});
};
const openNotify = ({ notifyId }: NotifyUUIDs) => {
const { deviceInfo } = this.state;
return Taro.notifyBLECharacteristicValueChange({
deviceId: deviceInfo.deviceId,
serviceId: deviceInfo.serviceId,
characteristicId: notifyId,
state: true,
}).then(res => {
console.log(res);
let abStr = '';
Taro.onBLECharacteristicValueChange(res => {
let msg = ab2str(res.value);
console.log('获取蓝牙设备消息: ', msg);
if (msg === '<>') {
this.closeBluetoothConnection();
this.closeDeviceSocket();
} else {
if (
msg.substring(0, 1) === '{' &&
msg.substring(msg.length - 1, msg.length) === '}'
) {
getBluetoothData(msg);
} else if (msg.substring(0, 1) === '{') {
abStr = msg;
} else if (
abStr.length &&
msg.substring(msg.length - 1, msg.length) === '}'
) {
abStr += msg;
getBluetoothData(abStr);
abStr = '';
} else {
if (abStr.length) {
abStr += msg;
} else {
console.log('弃掉数据:', msg);
}
}
}
});
});
};
const sendMessageToDevice = (msg: string) => {
const { deviceInfo } = state;
console.log(msg, str2ab(msg).byteLength);
if (deviceInfo.writeId) {
return Taro.writeBLECharacteristicValue({
deviceId: deviceInfo.deviceId,
serviceId: deviceInfo.serviceId,
characteristicId: deviceInfo.writeId,
value: str2ab(msg),
});
} else {
return Promise.reject();
}
};
useEffect(() => {
Taro.onBluetoothAdapterStateChange(res => {
console.log('adapterState changed, now is', res);
if (res.available) {
dispatch({ type: 'BLUETOOTH_STATE_CHANGE', payload: true });
} else {
dispatch({ type: 'BLUETOOTH_STATE_CHANGE', payload: false });
}
});
Taro.openBluetoothAdapter()
.then(res => {
console.log('openBluetoothAdapter: ', res);
dispatch({ type: 'BLUETOOTH_STATE_CHANGE', payload: true });
})
.catch(err => {
console.error(err);
});
return () => {
Taro.closeBluetoothAdapter();
};
}, []);
useEffect(() => {
if (state) {
Taro.startBluetoothDevicesDiscovery()
.then(DevicesDiscoveryHandle)
.then(createConnection)
.then(getDeviceServices)
.then(getDeviceCharacter)
.then(openNotify)
.then(() => {
dispatch({ type: 'DEVICE_STATE_CHANGE', payload: true });
})
.catch(err => {
// Taro.stopBluetoothDevicesDiscovery();
// if (timer) {
// clearInterval(timer);
// }
// Taro.hideLoading();
console.error('startBluetoothDevicesDiscovery: ', err);
// if (err.msg === BlueToothError.DeviceNotFound) {
Taro.stopBluetoothDevicesDiscovery();
// this.sendStartShower();
throw err;
// } else {
// return this.warnBluetoothOpen();
// }
});
} else {
warnBluetoothOpen();
}
}, [state, deviceCode]);
return {
state: state.bluetoothState,
sendMessageToDevice,
};
};
export default useBluetooth;
import Actions from '@/types/Store/Actions';
import Taro, { useReducer, useEffect } from '@tarojs/taro';
import { str2ab, ab2str } from '@/utils/arrayBuffer';
type StoreState = {
socketState: boolean;
socketTask: Taro.SocketTask | null;
};
const StopCode = 1000;
let reConnectting: boolean = false;
let timer: NodeJS.Timeout | null = null;
const initState = {
socketState: false,
socketTask: null,
};
const reducer = (state: StoreState, action: Actions): StoreState => {
switch (action.type) {
case 'GET_SOCKET_TASK':
return { ...state, socketTask: action.payload };
case 'SOCKET_STATE_CHANGE':
return { ...state, socketState: action.payload };
default:
return state;
}
};
const useDeviceWS = ({
url,
getSocketData,
}: {
url: string;
getSocketData: (msg: string) => void;
}): {
state: StoreState;
sendMessageToServer: (
msg: string,
successHandle: Taro.SocketTask.send.ParamPropSuccess,
failHandle: Taro.SocketTask.send.ParamPropFail,
) => void;
} => {
const [state, dispatch] = useReducer(reducer, initState);
const connectDeviceSocket = (url: string) => {
Taro.connectSocket({ url: url }).then(task => {
dispatch({ type: 'GET_SOCKET_TASK', payload: task });
task.onOpen(() => {
console.log('onOpen');
if (reConnectting) {
// reConnectDeviceSocket(true);
timer && clearTimeout(timer);
timer = null;
reConnectting = false;
}
task.send({ data: str2ab('{}') });
dispatch({ type: 'SOCKET_STATE_CHANGE', payload: true });
// this.sendDeviceCode();
});
task.onMessage(res => {
const msg: string = ab2str(res.data);
console.log('socket onMessage: ', msg);
if (msg === '[0]') {
console.log('结束蓝牙以及socket: ', msg);
closeDeviceSocket();
} else if (msg === '[]') {
} else {
if (msg.length > 100) {
getSocketData('[]');
} else if (msg.length > 20) {
for (let index = 0; index <= Math.floor(msg.length / 20); index++) {
let str = msg.substring(index * 20, (index + 1) * 20);
getSocketData(str);
}
} else {
if (msg) {
getSocketData(msg);
}
}
}
});
task.onClose(e => {
console.log('socked关闭', e, reConnectting, timer);
dispatch({ type: 'SOCKET_STATE_CHANGE', payload: false });
dispatch({ type: 'GET_SOCKET_TASK', payload: null });
if (e.code === StopCode) {
console.log('正确结束socket连接');
} else {
console.log('开始重连socket');
reConnectDeviceSocket();
}
});
});
};
const closeDeviceSocket = () => {
const { socketTask } = state;
console.log('in close', socketTask, timer);
if (socketTask) {
socketTask.close({
code: StopCode,
complete: () => {
dispatch({ type: 'SOCKET_STATE_CHANGE', payload: false });
dispatch({ type: 'GET_SOCKET_TASK', payload: null });
},
});
}
if (timer) {
clearTimeout(timer);
}
};
const reConnectDeviceSocket = () => {
console.log(reConnectting, timer);
if (reConnectting) {
connectDeviceSocket(url);
} else if (timer) {
clearTimeout(timer);
reConnectting = false;
timer = null;
console.log('请保证网络正常');
Taro.showModal({
title: '警告',
content: '请保持网络畅通正常',
});
} else {
timer = setTimeout(() => {
reConnectting = false;
}, 10000);
reConnectting = true;
console.log(reConnectting, timer);
connectDeviceSocket(url);
}
};
const sendMessageToServer = (
msg: string,
successHandle: Taro.SocketTask.send.ParamPropSuccess,
failHandle: Taro.SocketTask.send.ParamPropFail,
) => {
const { socketTask } = state;
socketTask &&
socketTask.send({
data: str2ab(msg),
success: successHandle,
fail: failHandle,
});
};
useEffect(() => {
connectDeviceSocket(url);
return closeDeviceSocket;
}, [url]);
return { state, sendMessageToServer };
};
export default useDeviceWS;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment