最近公司业务需要一个小程序去控制硬件设备,利用机智云sdk做了一个小demo,效果还不错,微信小程序控制效果比react native的要好
1. taro创建小程序
这个地方之前一直踩坑,用最新版的脚手架有问题,会跑不起来,后来咨询了群里一个大佬,换了taro3.6版本就ok了,执行命令
npx @tarojs/cli@3.6 init myApp
然后就得到了这样的项目目录,
2. 接下来我们下载机智云小程序sdk
- 执行命令
yarn add mini_program_gizwits_sdk - 为了后续开发方便,这里就简单的封装一下机智云sdk
3. 封装机智云sdk
1. 这里不需要状态,所以直接在utils里封装,避免在状态管理时可能出现的循环引用问题
2.新建constant.ts来存放一些常量,我这里把产品需要的id和screct放这,当然也可能放环境变量中
export const ANDROID_INFO = {
androidId: "91732**********3",
androidSecret: "a4e*******d8d78d74",
};
export const PRODUCTION_INFO = {
productKey: "e3****bb6",
productSecret: "a5***46fa24",
};
3.然后我们创建globalData.ts文件
在里面初始化机智云sdk,上代码
import GizwitsSdk from 'mini_program_gizwits_sdk'
import { ANDROID_INFO, PRODUCTION_INFO } from './constants';
const gizConfig = {
appID: ANDROID_INFO.androidId,
appSecret: ANDROID_INFO.androidSecret,
productInfo: [
{
productKey: PRODUCTION_INFO.productKey,
productSecret: PRODUCTION_INFO.productSecret,
},
],
uid: "giz_uid", // 必填
token: "giz_token", // 必填
};
let gizSdk: GizwitsSdk | null = null;
const initSdk = async () => {
gizSdk = await new GizwitsSdk(gizConfig);
console.log("giz", gizSdk);
return gizSdk;
}
export {
gizSdk,
initSdk
}
4. 我这里只做蓝牙设备连接
所以不需要登录,所以uid和token也不用填,然后我们可以在用户进入小程序时初始化机智云sdk,更改
app.ts代码
import { PropsWithChildren } from 'react'
import { useLaunch } from '@tarojs/taro'
import 'taro-ui/dist/style/index.scss' // 全局引入一次即可
import './app.less'
import {initSdk} from './utils/globalData'
function App({ children }: PropsWithChildren<any>) {
useLaunch(() => {
initSdk() // 初始化SDK
console.log('App launched.')
})
// children 是将要会渲染的页面
return children
}
export default App
5. 接着要初始化蓝牙设备
这里我使用了zustand进行状态管理,由于后续需要对设备列表进行管理,所以这段代码也写进入了,新建文件
store/useDeviceStore.ts
import { create } from "zustand";
import GizwitsSdk from 'mini_program_gizwits_sdk'
import {gizSdk} from '../utils/globalData'
6. 创建store,初始化蓝牙
以及订阅,取消订阅等相关功能,initBle后来想了一下,还是放到utils里比较好
import { create } from "zustand";
import GizwitsSdk from 'mini_program_gizwits_sdk'
import {gizSdk} from '../utils/globalData'
interface IDeviceStore {
devices: Array<any>;
setDevices: (devices: Array<any>) => void;
gizSdk: GizwitsSdk | null;
scanning: boolean;
curDeivce: any | null;
setCurDevice: (curDeivce: any) => void;
setScanning: (scanning: boolean) => void;
initBle: () => Promise<void>;
scanBle: () => Promise<void>;
stopScan: () => Promise<void>;
removeOnScanListChange: () => void;
subscribe: (device?) => any;
unSubscribe: (device?) => any;
}
const useDeviceStore = create<IDeviceStore>((set,get) => ({
scanning: false,
setScanning: (scanning: boolean) => set({ scanning }),
curDeivce: null,
setCurDevice: (curDeivce: any) => set({ curDeivce }),
devices: [],
setDevices: (devices) => set({ devices }),
gizSdk: gizSdk,
initBle: async () => {
const res = await gizSdk.initBle();
console.log('res',res);
gizSdk.addEventListener("onScanListChange", (devices) => {
console.log("扫描列表发生变化", devices);
set({ devices });
});
gizSdk.addEventListener("GizDeviceAttrsNotifications", (res) => {
// console.log("====设备状态发生变化====", device, data);
});
gizSdk.addEventListener("GizDeviceStatusNotifications", (e) => {
// console.log("设备在线状态变化", e);
});
gizSdk.addEventListener("GizDeviceListNotifications", (deviceList) => {
// console.log("列表发生变化", deviceList);
});
},
/**
* 扫描蓝牙
*/
scanBle : async () => {
const data = await gizSdk.scanBleDevice();
set({scanning: true})
console.log("开始扫描", data);
},
/**
* 停止扫描
*/
stopScan: async () => {
const data = await gizSdk.stopScanBleDevice();
set({scanning: false})
console.log("停止扫描", data);
},
/**
* 移除监听
*/
removeOnScanListChange:() => {
gizSdk.removeEventListener("onScanListChange")
},
/**
* 订阅设备
* @returns
*/
subscribe:(device = get().curDeivce) => {
return gizSdk.subscribe(device)
},
/**
* 取消订阅设备
* @returns
*/
unSubscribe:(device = get().curDeivce) => {
return gizSdk.unSubscribe(device)
}
}))
export default useDeviceStore;
7. 然后再创建一个页面或者组件都可以,就可以引入了
import { useEffect, useState } from "react";
import { View, Text } from "@tarojs/components";
import { AtButton, AtList, AtListItem, AtSlider } from "taro-ui";
import "./index.less";
import useDeviceStore from "@/store/useDeviceStore";
import { setNightLightBrightness, toggleNightLight, togglePower, toggleStartStatus } from "@/utils/deviceAction";
import { toastTip } from "@/utils/toastUtil";
function DeviceConnection() {
const {
curDeivce,
devices,
setCurDevice,
scanning,
scanBle,
initBle,
removeOnScanListChange,
subscribe,
unSubscribe,
stopScan,
} = useDeviceStore();
const [stepVal,setStepVal] = useState(0)
useEffect(() => {
// 初始化蓝牙
initBle();
// 清理函数
return () => {
removeOnScanListChange();
};
}, []);
// 6. 渲染UI
return (
<View style={{ padding: "10px 20px" }}>
{/* 开关扫描蓝牙 */}
<AtButton
circle
type="primary"
onClick={scanBle}
disabled={scanning}
className="scan-button"
>
{scanning ? "Scanning..." : "Start Scan"}
</AtButton>
<AtButton
type="secondary"
circle
className="scan-button"
onClick={stopScan}
disabled={!scanning}
>
Stop Scan
</AtButton>
<AtButton
className="scan-button"
type="primary"
circle
onClick={() => {
const res = unSubscribe(curDeivce);
toastTip({
success: res.success,
successMsg: "取消订阅成功",
errorMsg: "取消订阅失败",
});
}}
>
取消订阅
</AtButton>
<AtButton
className="scan-button"
type="primary"
circle
onClick={async() => {
const res = await toggleStartStatus(curDeivce,true);
toastTip({
success: res.success,
successMsg: "启动设备成功",
errorMsg: "启动设备失败",
});
}}
>
启动设备
</AtButton>
<AtButton
className="scan-button"
type="secondary"
circle
onClick={async() => {
const res = await toggleStartStatus(curDeivce,false);
toastTip({
success: res.success,
successMsg: "关闭设备成功",
errorMsg: "关闭设备失败",
});
}}
>
关闭设备
</AtButton>
<View style={{ marginTop: "20px", marginBottom: "20px" }}>
设备总数:{devices.length}
</View>
{/* 设备列表 */}
<View>
<Text>设备列表</Text>
<AtList>
{devices.map((device: any) => (
<AtListItem
title={device.mac}
onClick={async () => {
setCurDevice(device);
const res = await subscribe();
toastTip({
success: res.success,
successMsg: "订阅成功",
errorMsg: "订阅失败",
});
}}
/>
))}
</AtList>
</View>
{/* 夜灯控制 */}
<View style={{ display: "flex", marginTop: "20px" }}>
<AtButton
type="primary"
onClick={() => {
console.log("夜灯开");
toggleNightLight(curDeivce, true);
}}
>
夜灯开
</AtButton>
<AtButton
type="secondary"
onClick={() => {
console.log("夜灯关");
toggleNightLight(curDeivce, false);
}}
>
夜灯关
</AtButton>
</View>
{/* 夜灯亮度 */}
<AtSlider max={100} min={0} step={1} blockColor='#4285F4' value={stepVal} showValue onChange={async (value) => {
const res = await setNightLightBrightness(curDeivce, value); //
setStepVal(value)
console.log("亮度", value,res);
}}/>
{/* 电源控制 */}
<View
style={{ display: "flex", marginTop: "20px", marginBottom: "20px" }}
>
<AtButton
type="primary"
onClick={() => {
console.log("电源开");
togglePower(curDeivce, true);
}}
>
电源开
</AtButton>
<AtButton
type="secondary"
onClick={() => {
console.log("电源关");
togglePower(curDeivce, false);
}}
>
电源关
</AtButton>
</View>
</View>
);
}
export default DeviceConnection;
4. 总结
差不多就是这些,我这里使用了taroui,使用自带的ui也可以,页面没有做太多的样式调整,大概就是,一个按钮点击开始扫描,扫描附近蓝牙,前提要打开手机的蓝牙和定位权限,然后扫到相应设备会出现在设备列表中,点击就能进行连接订阅,提示连接成功,后面就可以愉快地控制设备了,进行灯光开关,调节,电源开关等
注:这里的设备必须是机智云后台创建的对应的产品硬件,也就是前文所说的配置文件里的pk和ps要和机智云后台pk和ps对应,这样的设备才能扫描到连接成功,别的设备不行