暂存
This commit is contained in:
parent
18c9ef9b0c
commit
2de447402e
@ -94,6 +94,7 @@ page {
|
||||
font-family: Microsoft YaHei, Microsoft YaHei-Regular;
|
||||
font-weight: 400;
|
||||
color: #707070;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -101,6 +102,13 @@ page {
|
||||
.color_bock {
|
||||
width: 290px;
|
||||
height: 290px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.color_bocktwo {
|
||||
width: 290px;
|
||||
height: 290px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.nameColor {
|
||||
|
@ -3,6 +3,7 @@ import { Image, Text, Textarea, View } from "@tarojs/components"
|
||||
import Taro, { useDidShow, usePullDownRefresh, useRouter } from "@tarojs/taro";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useBluetooth } from "@/use/contextBlueTooth"
|
||||
import { useBluetoothTwo } from "@/use/BlueToothCopy"
|
||||
import classnames from "classnames";
|
||||
import LinkBlueTooth from "./compoents/bluetooth/LinkBlueTooth";
|
||||
import { toRgb } from '@/common/bluetooth/color/colorSpace'
|
||||
@ -21,10 +22,22 @@ export default () => {
|
||||
product_kind_id: '',
|
||||
component: ''
|
||||
})
|
||||
|
||||
const [colorList, setColorList] = useState({
|
||||
one: [],
|
||||
two: []
|
||||
})
|
||||
const { state: colorState, measureAndGetLab } = useBluetooth()
|
||||
const getLab = () => {
|
||||
|
||||
const getLab = async (val) => {
|
||||
if (colorState.connected) {
|
||||
measureAndGetLab()
|
||||
let res = await measureAndGetLab()
|
||||
if (val === 1) {
|
||||
setColorList({ ...colorList, one: res })
|
||||
} else {
|
||||
setColorList({ ...colorList, two: res })
|
||||
console.log('colorList',colorList)
|
||||
}
|
||||
} else {
|
||||
Taro.showToast({
|
||||
title: '请链接设备',
|
||||
@ -32,15 +45,24 @@ export default () => {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//监听lab数据变化
|
||||
const [blueToothColor, setBlueToothColor] = useState('')
|
||||
const [blueToothColorTwo, setBlueToothColorTwo] = useState('')
|
||||
useEffect(() => {
|
||||
if (colorState.deviceLab) {
|
||||
const rgb = toRgb([colorState.deviceLab.L, colorState.deviceLab.a, colorState.deviceLab.b])
|
||||
console.log(colorList, 'colorList.one.lengthcolorList.one.length')
|
||||
if (colorList.one?.constructor === Object) {
|
||||
setBlueToothColor(`rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`)
|
||||
setSearchField({ ...searchField, l: rgb[0], a: rgb[1], b: rgb[2], size: 10 })
|
||||
console.log(blueToothColor, 'blueToothColorblueToothColor')
|
||||
}
|
||||
}, [colorState.deviceLab])
|
||||
if (colorList.two?.constructor === Object) {
|
||||
setBlueToothColorTwo(`rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`)
|
||||
}
|
||||
// setSearchField({ ...searchField, l: rgb[0], a: rgb[1], b: rgb[2], size: 10 })
|
||||
}
|
||||
}, [colorList])
|
||||
return (
|
||||
<View className={styles.body}>
|
||||
{/* <View className={styles.topBox}>
|
||||
@ -58,7 +80,7 @@ export default () => {
|
||||
<View className={styles.firstLeftName} >对比样品</View>
|
||||
{
|
||||
blueToothColor === '' &&
|
||||
<View className={styles.firstLeftbox} onClick={() => getLab()}>
|
||||
<View className={styles.firstLeftbox} onClick={() => getLab(1)}>
|
||||
<View className={styles.clickFont} >点击取色</View>
|
||||
</View>
|
||||
}
|
||||
@ -69,9 +91,15 @@ export default () => {
|
||||
</View>
|
||||
<View className={styles.firstBox}>
|
||||
<View className={styles.firstLeftName}>对比样品</View>
|
||||
<View className={styles.firstLeftbox}>
|
||||
<View className={styles.clickFont} onClick={() => getLab()}>点击取色</View>
|
||||
{
|
||||
blueToothColorTwo === '' &&
|
||||
<View className={styles.firstLeftbox} onClick={() => getLab(2)}>
|
||||
<View className={styles.clickFont} >点击取色</View>
|
||||
</View>
|
||||
}
|
||||
{blueToothColorTwo && <View className={classnames(styles.color_bocktwo)} style={{ background: blueToothColorTwo }}></View>
|
||||
|
||||
}
|
||||
<View className={styles.nameColor}>--</View>
|
||||
</View>
|
||||
</View>
|
||||
|
477
src/use/BlueToothCopy.tsx
Normal file
477
src/use/BlueToothCopy.tsx
Normal file
@ -0,0 +1,477 @@
|
||||
import React, {useRef, useState } from "react"
|
||||
import Taro from "@tarojs/taro";
|
||||
import { Command } from "@/common/bluetooth/command";
|
||||
import { uint8ArrayToFloat32, uint8ArrayToHex, waitFor } from "@/common/bluetooth/utils";
|
||||
|
||||
|
||||
interface params {
|
||||
init: () => void
|
||||
state: Object,
|
||||
startScan: () => void,
|
||||
measureAndGetLab: () => any,
|
||||
getAdapterState: () => void,
|
||||
connect: (any) => void,
|
||||
disconnect: () => void
|
||||
}
|
||||
const Context = React.createContext<params|unknown>(null)
|
||||
|
||||
interface stateStype {
|
||||
listeners: any,
|
||||
discovering: boolean,
|
||||
available: boolean,
|
||||
connected: any,
|
||||
connecting: any,
|
||||
serviceRule: any,
|
||||
serviceId: any,
|
||||
characteristicRule: any,
|
||||
characteristicId: any,
|
||||
|
||||
/** 正在执行的命令 */
|
||||
command: any,
|
||||
responseResolve: any,
|
||||
responseReject: any,
|
||||
responseTimer: any,
|
||||
|
||||
/** 是否显示蓝牙调试信息 */
|
||||
debug: any,
|
||||
//搜索到的设备
|
||||
devices: any,
|
||||
//取色仪主动返回的数据
|
||||
deviceLab: any
|
||||
}
|
||||
|
||||
let stateObj: stateStype = {
|
||||
/** 事件监听器 */
|
||||
listeners: new Set(),
|
||||
/** 正在扫描设备 */
|
||||
discovering: false,
|
||||
/** 蓝牙是否可用 */
|
||||
available: true,
|
||||
/** 当前连接的设备 */
|
||||
connected: null,
|
||||
/** 正在连接的设备 */
|
||||
connecting: null,
|
||||
|
||||
serviceRule: /^0000FFE0/,
|
||||
serviceId: null,
|
||||
characteristicRule: /^0000FFE1/,
|
||||
characteristicId: null,
|
||||
|
||||
/** 正在执行的命令 */
|
||||
command: null,
|
||||
responseResolve: null,
|
||||
responseReject: null,
|
||||
responseTimer: null,
|
||||
|
||||
/** 是否显示蓝牙调试信息 */
|
||||
debug: true,
|
||||
//搜索到的设备
|
||||
devices: [],
|
||||
//取色仪主动返回的数据
|
||||
deviceLab: null
|
||||
}
|
||||
|
||||
export default (props) => {
|
||||
let refStatus = useRef(stateObj)
|
||||
let [state, setState] = useState(refStatus.current)
|
||||
|
||||
const changeStatus = (obj:Object): void => {
|
||||
refStatus.current = {...refStatus.current, ...obj}
|
||||
setState({...refStatus.current})
|
||||
}
|
||||
|
||||
const init = async () => {
|
||||
try{
|
||||
await openAdapter();
|
||||
}catch(e) {
|
||||
changeStatus({available:false})
|
||||
}
|
||||
|
||||
// 绑定事件通知
|
||||
Taro.onBluetoothAdapterStateChange(res => {
|
||||
emit({ type: 'stateUpdate', detail: res });
|
||||
});
|
||||
Taro.onBLEConnectionStateChange(res => {
|
||||
emit({ type: res.connected ? 'connected' : 'disconnect', detail: res });
|
||||
});
|
||||
Taro.onBLECharacteristicValueChange(({ value }) => notifySubscriber(value));
|
||||
subscribe(async ev => {
|
||||
if (ev.type === 'stateUpdate') {
|
||||
// 蓝牙状态发生的变化
|
||||
changeStatus({discovering:ev.detail.discovering, available:ev.detail.available})
|
||||
} else if (ev.type === 'disconnect' && refStatus.current.connected && refStatus.current.connected.deviceId === ev.detail.deviceId) {
|
||||
// 断开连接
|
||||
changeStatus({
|
||||
connected:null,
|
||||
serviceId:null,
|
||||
characteristicId:null,
|
||||
deviceLab:null,
|
||||
devices:[]
|
||||
})
|
||||
Taro.showToast({ icon: 'none', title: '蓝牙连接已断开' });
|
||||
} else if (ev.type === 'connected' && refStatus.current.connecting) {
|
||||
// 连接成功
|
||||
changeStatus({connected: refStatus.current.connecting, connecting: null})
|
||||
Taro.showToast({ title: '蓝牙已连接' });
|
||||
} else if (ev.type === 'measure') {
|
||||
//监听取色仪主动推送lab
|
||||
await measureAndGetLab()
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/** 打开蓝牙适配器 */
|
||||
const openAdapter = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
Taro.openBluetoothAdapter({
|
||||
success: resolve,
|
||||
fail: reject
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送事件
|
||||
* @param {{type: string; data: any}} event
|
||||
*/
|
||||
const emit = (event) => {
|
||||
refStatus.current.listeners.forEach(cb => {
|
||||
cb && cb(event);
|
||||
});
|
||||
}
|
||||
|
||||
const subscribe = (cb) => {
|
||||
if (cb) {
|
||||
changeStatus({
|
||||
listeners: refStatus.current.listeners.add(cb)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取蓝牙适配器状态
|
||||
* @returns {Promise<{discovering: boolean; available: boolean}>}
|
||||
*/
|
||||
const getAdapterState = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
Taro.getBluetoothAdapterState({
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动设备扫描
|
||||
* @param {(res: { devices: { name: string, deviceId: string, RSSI: number }[] }) => void} cb
|
||||
* @param {number} duration
|
||||
*/
|
||||
const startScan = (duration = 30000) => {
|
||||
console.log('开始寻找')
|
||||
changeStatus({devices:[]})
|
||||
Taro.onBluetoothDeviceFound(getDevices);
|
||||
return new Promise((resolve, reject) => {
|
||||
Taro.startBluetoothDevicesDiscovery({
|
||||
allowDuplicatesKey: true,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
});
|
||||
|
||||
if (duration > 0) {
|
||||
setTimeout(() => {
|
||||
Taro.offBluetoothDeviceFound(getDevices);
|
||||
Taro.stopBluetoothDevicesDiscovery();
|
||||
console.log("停止搜索")
|
||||
}, duration);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//获取搜索到的设备
|
||||
const getDevices = (res) => {
|
||||
res.devices.forEach(device => {
|
||||
// 排除掉已搜索到的设备和名称不合法的设备, 将新发现的设备添加到列表中
|
||||
if (/^CM/.test(device.name) && !refStatus.current.devices.find(i => i.deviceId === device.deviceId)) {
|
||||
changeStatus({devices: [ ...refStatus.current.devices, device ]})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接设备
|
||||
* @param {{ name: string, deviceId: string, RSSI: number }} device
|
||||
*/
|
||||
const connect = async (device) => {
|
||||
try {
|
||||
changeStatus({connecting: device})
|
||||
console.log('connecting::', device)
|
||||
await createConnection(device.deviceId);
|
||||
await discoverService(device.deviceId);
|
||||
await discoverCharacteristic(device.deviceId);
|
||||
await notifyCharacteristicValueChange(device.deviceId);
|
||||
} catch (e) {
|
||||
changeStatus({connecting: null})
|
||||
Taro.showToast({ icon: 'none', title: '蓝牙连接失败' });
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/** 断开当前连接的设备 */
|
||||
const disconnect = async () => {
|
||||
if (!refStatus.current.connected && !refStatus.current.connecting) return;
|
||||
if (refStatus.current.connected) {
|
||||
await closeConnection(refStatus.current.connected.deviceId);
|
||||
resetCommand();
|
||||
changeStatus({
|
||||
connected: null,
|
||||
serviceId: null,
|
||||
characteristicId: null,
|
||||
devices: [],
|
||||
deviceLab: null
|
||||
})
|
||||
}
|
||||
|
||||
if (refStatus.current.connecting) {
|
||||
await closeConnection(refStatus.current.connecting.deviceId);
|
||||
changeStatus({connecting:null})
|
||||
}
|
||||
}
|
||||
|
||||
/** 创建 BLE 连接 */
|
||||
function createConnection(deviceId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Taro.createBLEConnection({
|
||||
deviceId,
|
||||
timeout: 2000,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 关闭 BLE 连接 */
|
||||
function closeConnection(deviceId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Taro.closeBLEConnection({
|
||||
deviceId,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 搜索服务 */
|
||||
function discoverService(deviceId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Taro.getBLEDeviceServices({
|
||||
deviceId,
|
||||
success: ({ services }) => {
|
||||
const service = services.find(i => refStatus.current.serviceRule.test(i.uuid));
|
||||
if (!service) {
|
||||
reject(new Error('服务不可用'));
|
||||
} else {
|
||||
changeStatus({serviceId: service.uuid})
|
||||
resolve(service);
|
||||
}
|
||||
},
|
||||
fail: reject
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 搜索特征 */
|
||||
function discoverCharacteristic(deviceId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Taro.getBLEDeviceCharacteristics({
|
||||
deviceId,
|
||||
serviceId: refStatus.current.serviceId,
|
||||
success: ({ characteristics }) => {
|
||||
const characteristic = characteristics.find(i => refStatus.current.characteristicRule.test(i.uuid));
|
||||
if (!characteristic) {
|
||||
reject(new Error('特征不可用'));
|
||||
} else {
|
||||
changeStatus({characteristicId: characteristic.uuid})
|
||||
resolve(characteristic);
|
||||
}
|
||||
},
|
||||
fail: reject
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/** 启动特征通知 */
|
||||
function notifyCharacteristicValueChange(deviceId, stateParm = true) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Taro.notifyBLECharacteristicValueChange({
|
||||
deviceId,
|
||||
serviceId: refStatus.current.serviceId,
|
||||
characteristicId: refStatus.current.characteristicId,
|
||||
state:stateParm,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知订阅器
|
||||
* @param {ArrayBuffer} buffer
|
||||
*/
|
||||
function notifySubscriber(buffer) {
|
||||
if (refStatus.current.command) {
|
||||
if (refStatus.current.debug) {
|
||||
console.log(`[BLE RESP] ${uint8ArrayToHex(new Uint8Array(buffer))}`);
|
||||
}
|
||||
refStatus.current.command.fillResponse(buffer);
|
||||
if (refStatus.current.command.isComplete) {
|
||||
if (refStatus.current.command.isValid && refStatus.current.responseResolve) {
|
||||
refStatus.current.responseResolve(refStatus.current.command.response);
|
||||
} else if (!refStatus.current.command.isValid) {
|
||||
refStatus.current.responseReject(new Error('无效数据'));
|
||||
}
|
||||
resetCommand();
|
||||
}
|
||||
} else {
|
||||
const uint8Array = new Uint8Array(buffer);
|
||||
if (uint8Array[0] === 0xbb && uint8Array[1] === 1 && uint8Array[3] === 0) {
|
||||
const ev = { type: 'measure', detail: { mode: uint8Array[2] } };
|
||||
emit(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送命令
|
||||
* @param {Command}} command
|
||||
* @returns {Promise<Uint8Array>}
|
||||
*/
|
||||
function exec(command) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (refStatus.current.command) {
|
||||
reject(new Error('正在执行其他命令'));
|
||||
} else {
|
||||
try {
|
||||
refStatus.current.command = command;
|
||||
const data = command.data;
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
await sendData(data[i]);
|
||||
}
|
||||
|
||||
if (command.responseSize <= 0) {
|
||||
resolve(true);
|
||||
resetCommand();
|
||||
} else {
|
||||
refStatus.current.responseReject = reject;
|
||||
refStatus.current.responseResolve = resolve;
|
||||
refStatus.current.responseTimer = setTimeout(() => {
|
||||
reject(new Error('命令响应超时'));
|
||||
resetCommand();
|
||||
}, command.timeout);
|
||||
}
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送命令
|
||||
* @param {ArrayBuffer} buffer
|
||||
*/
|
||||
function sendData(buffer) {
|
||||
if (refStatus.current.debug) {
|
||||
console.log(`[BLE SEND] ${uint8ArrayToHex(new Uint8Array(buffer))}`);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log('current:::',refStatus.current)
|
||||
Taro.writeBLECharacteristicValue({
|
||||
deviceId: refStatus.current.connected.deviceId,
|
||||
serviceId: refStatus.current.serviceId,
|
||||
characteristicId: refStatus.current.characteristicId,
|
||||
value: buffer,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function resetCommand() {
|
||||
if (refStatus.current.responseTimer) {
|
||||
clearTimeout(refStatus.current.responseTimer);
|
||||
}
|
||||
changeStatus({
|
||||
command: null,
|
||||
responseResolve: null,
|
||||
responseReject: null,
|
||||
responseTimer: null
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 测量
|
||||
* @param {number} mode
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async function measure (mode = 0) {
|
||||
console.log('current1:::',Command.WakeUp)
|
||||
await exec(Command.WakeUp);
|
||||
console.log('current2:::',Command.WakeUp)
|
||||
await waitFor(50);
|
||||
console.log('current3:::',Command.WakeUp)
|
||||
return await exec(Command.measure(mode));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取测量的 lab 值
|
||||
* @param {number} mode
|
||||
* @returns {Promise<{ L: number, a: number, b: number }>}
|
||||
*/
|
||||
async function getLab(mode = 0) {
|
||||
await exec(Command.WakeUp);
|
||||
await waitFor(50);
|
||||
const data: any = await exec(Command.getLab(mode));
|
||||
return {
|
||||
L: uint8ArrayToFloat32(data.slice(5, 9)),
|
||||
a: uint8ArrayToFloat32(data.slice(9, 13)),
|
||||
b: uint8ArrayToFloat32(data.slice(13, 17)),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 测量并获取 lab 值
|
||||
* @param {number} mode
|
||||
* @returns {Promise<{L: number, a: number, b: number}>}
|
||||
*/
|
||||
async function measureAndGetLab(mode = 0) {
|
||||
await measure(mode);
|
||||
await waitFor(50);
|
||||
const lab = await getLab(mode);
|
||||
console.log('lab2::',lab)
|
||||
changeStatus({deviceLab:lab})
|
||||
return lab
|
||||
}
|
||||
|
||||
return <Context.Provider children={props.children} value={{
|
||||
init,
|
||||
state,
|
||||
startScan,
|
||||
measureAndGetLab,
|
||||
getAdapterState,
|
||||
connect,
|
||||
disconnect
|
||||
}} />
|
||||
}
|
||||
|
||||
|
||||
export const useBluetoothTwo = () => {
|
||||
const res = React.useContext<any>(Context)
|
||||
if(res) {
|
||||
return {...res}
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user