微信小程序蓝牙通讯蓝牙模块demo[通俗易懂]

微信小程序蓝牙通讯蓝牙模块demo[通俗易懂]公司项目用到蓝牙和硬件通讯,APP正在开发,弄一个微信小程序蓝牙通讯的demo,可能后期会有微信蓝牙的项目,第一次搞,遇到2个坑:1.安卓和苹果获取的硬件服务UUID顺序不同2.目前用的这一版“启用低功耗蓝牙设备特征值变化时的notify功能”在安卓和苹果的测试机上都返回启动失败,其实是已经启动成功,在我同事安卓手机上返回的正常。index.wxml适配器状态:{{

大家好,又见面了,我是你们的朋友全栈君。

公司项目用到蓝牙和硬件通讯,APP正在开发,弄一个微信小程序蓝牙通讯的demo,可能后期会有微信蓝牙的项目,第一次搞,遇到2个坑:

1.安卓和苹果获取的硬件服务UUID顺序不同

2.目前用的这一版 “启用低功耗蓝牙设备特征值变化时的 notify 功能”在安卓和苹果的测试机上都返回启动失败,其实是已经启动成功,在我同事安卓手机上返回的正常。

index.wxml

<!--index.wxml-->
<view class="content">
  <text class="status">适配器状态:{
  
  { status }}</text>
  <text class="sousuo">是否搜索:{
  
  { sousuo }}</text>
  <text class="msg">消息:{
  
  { msg }} </text>
  <text class="msg1">消息:{
  
  { msg1 }}</text>
  <button type="primary" class="button" bindtap="lanya1">1初始化蓝牙适配器</button>
  <button type="primary" class="button" bindtap="lanya2">2本机蓝牙适配状态</button>
  <button type="primary" class="button" bindtap="lanya3">3搜索周边设备</button>
  <button type="primary" class="button" bindtap="lanya4">4获取设备后在列表中连接</button>
  <button type="primary" class="button" bindtap="lanya5">5停止搜索周边设备</button>
  <button type="primary" class="button" bindtap="lanya6">6获取连接设备所有service</button>
  <button type="primary" class="button" bindtap="lanya7">7获取连接设备所有特征值</button>
  <button type="primary" class="button" bindtap="lanya8">8发送指定消息</button>
  <button type="primary" class="button" bindtap="lanya9">9启用设备特征值变化时的notify</button>
  <button type="primary" class="button" bindtap="lanya10">10接收消息</button>
  <view class="section">
    <text class="status">接收到消息:{
  
  { jieshou }}</text>

  </view>

  <button type="primary" class="button" bindtap="lanya0">0断开蓝牙连接</button>
</view>
<view class="venues_list">
  <block wx:for="{
  
  {devices}}" wx:key="{
  
  {test}}">
    <view class="venues_item">
      <text class="status">设备名称:{
  
  {item.name}}</text>
      <text class="status">设备ID:{
  
  {item.deviceId}}</text>
      <text class="status">连接状态:{
  
  {connectedDeviceId == item.deviceId?"已连接":"未连接"}}</text>
      <view class="section">
      </view>
      <view class="section">
        <button type="warn" class="button" id="{
  
  {item.deviceId}}" bindtap="connectTO">连接</button>
      </view>
    </view>
  </block>
</view>

index.js

//index.js
//获取应用实例
var app = getApp();
Page({
    data: {
        status: "",
        sousuo: "",
        connectedDeviceId: "", //已连接设备uuid
        services: "", // 连接设备的服务
        characteristics: "",   // 连接设备的状态值
        writeServicweId: "", // 可写服务uuid
        writeCharacteristicsId: "",//可写特征值uuid
        readServicweId: "", // 可读服务uuid
        readCharacteristicsId: "",//可读特征值uuid
        notifyServicweId: "", //通知服务UUid
        notifyCharacteristicsId: "", //通知特征值UUID
        inputValue: "",
        characteristics1: "", // 连接设备的状态值
    },
    onLoad: function () {
        if (wx.openBluetoothAdapter) {
            wx.openBluetoothAdapter()
        } else {
            // 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
            wx.showModal({
                title: '提示',
                content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
            })
        }

    },
    // 初始化蓝牙适配器
    lanya1: function () {
        var that = this;
        wx.openBluetoothAdapter({
            success: function (res) {
                that.setData({
                    msg: "初始化蓝牙适配器成功!" + JSON.stringify(res),
                })
                //监听蓝牙适配器状态
                wx.onBluetoothAdapterStateChange(function (res) {
                    that.setData({
                        sousuo: res.discovering ? "在搜索。" : "未搜索。",
                        status: res.available ? "可用。" : "不可用。",
                    })
                })
            }
        })
    },
    // 本机蓝牙适配器状态
    lanya2: function () {
        var that = this;
        wx.getBluetoothAdapterState({
            success: function (res) {
                that.setData({
                    msg: "本机蓝牙适配器状态" + "/" + JSON.stringify(res.errMsg),
                    sousuo: res.discovering ? "在搜索。" : "未搜索。",
                    status: res.available ? "可用。" : "不可用。",
                })
                //监听蓝牙适配器状态
                wx.onBluetoothAdapterStateChange(function (res) {
                    that.setData({
                        sousuo: res.discovering ? "在搜索。" : "未搜索。",
                        status: res.available ? "可用。" : "不可用。",
                    })
                })
            }
        })
    },
    //搜索设备
    lanya3: function () {
        var that = this;
        wx.startBluetoothDevicesDiscovery({
            success: function (res) {
                that.setData({
                    msg: "搜索设备" + JSON.stringify(res),
                })
                //监听蓝牙适配器状态
                wx.onBluetoothAdapterStateChange(function (res) {
                    that.setData({
                        sousuo: res.discovering ? "在搜索。" : "未搜索。",
                        status: res.available ? "可用。" : "不可用。",
                    })
                })
            }
        })
    },
    // 获取所有已发现的设备
    lanya4: function () {
        var that = this;
        wx.getBluetoothDevices({
            success: function (res) {
                //是否有已连接设备
                wx.getConnectedBluetoothDevices({
                    success: function (res) {
                        console.log(JSON.stringify(res.devices));
                        that.setData({
                            connectedDeviceId: res.deviceId
                        })
                    }
                })

                that.setData({
                    msg: "搜索设备" + JSON.stringify(res.devices),
                    devices: res.devices,
                })
                //监听蓝牙适配器状态
                wx.onBluetoothAdapterStateChange(function (res) {
                    that.setData({
                        sousuo: res.discovering ? "在搜索。" : "未搜索。",
                        status: res.available ? "可用。" : "不可用。",
                    })
                })
            }
        })
    },
    //停止搜索周边设备
    lanya5: function () {
        var that = this;
        wx.stopBluetoothDevicesDiscovery({
            success: function (res) {
                that.setData({
                    msg: "停止搜索周边设备" + "/" + JSON.stringify(res.errMsg),
                    sousuo: res.discovering ? "在搜索。" : "未搜索。",
                    status: res.available ? "可用。" : "不可用。",
                })
            }
        })
    },
    //连接设备
    connectTO: function (e) {
        var that = this;
        wx.createBLEConnection({
            deviceId: e.currentTarget.id,
            success: function (res) {
                console.log(res.errMsg);
                that.setData({
                    connectedDeviceId: e.currentTarget.id,
                    msg: "已连接" + e.currentTarget.id,
                    msg1: "",
                })
            },
            fail: function () {
                console.log("调用失败");
            },
            complete: function () {
                console.log("调用结束");
            }

        })
        console.log(that.data.connectedDeviceId);
    },
    // 获取连接设备的service服务
    lanya6: function () {
        var that = this;
        wx.getBLEDeviceServices({
            // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
            deviceId: that.data.connectedDeviceId,
            success: function (res) {
                console.log('device services:', JSON.stringify(res.services));
                that.setData({
                    services: res.services,
                    msg: JSON.stringify(res.services),
                })
            }
        })
    },
    //获取连接设备的所有特征值  for循环获取不到值
    lanya7: function () {
        var that = this;
        wx.getBLEDeviceCharacteristics({
            // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
            deviceId: that.data.connectedDeviceId,
            // 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取
            serviceId: that.data.services[0].uuid,
            success: function (res) {
                for (var i = 0; i < res.characteristics.length; i++) {
                    if (res.characteristics[i].properties.notify) {
                        console.log("11111111", that.data.services[0].uuid);
                        console.log("22222222222222222", res.characteristics[i].uuid);
                        that.setData({
                            notifyServicweId: that.data.services[0].uuid,
                            notifyCharacteristicsId: res.characteristics[i].uuid,
                        })
                    }
                    if (res.characteristics[i].properties.write) {
                        that.setData({
                            writeServicweId: that.data.services[0].uuid,
                            writeCharacteristicsId: res.characteristics[i].uuid,
                        })

                    } else if (res.characteristics[i].properties.read) {
                        that.setData({
                            readServicweId: that.data.services[0].uuid,
                            readCharacteristicsId: res.characteristics[i].uuid,
                        })

                    }
                }
                console.log('device getBLEDeviceCharacteristics:', res.characteristics);

                that.setData({
                    msg: JSON.stringify(res.characteristics),
                })
            },
            fail: function () {
                console.log("fail");
            },
            complete: function () {
                console.log("complete");
            }
        })

        wx.getBLEDeviceCharacteristics({
            // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
            deviceId: that.data.connectedDeviceId,
            // 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取
            serviceId: that.data.services[1].uuid,
            success: function (res) {
                for (var i = 0; i < res.characteristics.length; i++) {
                    if (res.characteristics[i].properties.notify) {
                        that.setData({
                            notifyServicweId: that.data.services[1].uuid,
                            notifyCharacteristicsId: res.characteristics[i].uuid,
                        })
                    }
                    if (res.characteristics[i].properties.write) {
                        that.setData({
                            writeServicweId: that.data.services[1].uuid,
                            writeCharacteristicsId: res.characteristics[i].uuid,
                        })

                    } else if (res.characteristics[i].properties.read) {
                        that.setData({
                            readServicweId: that.data.services[1].uuid,
                            readCharacteristicsId: res.characteristics[i].uuid,
                        })

                    }
                }
                console.log('device getBLEDeviceCharacteristics1:', res.characteristics);

                that.setData({
                    msg1: JSON.stringify(res.characteristics),
                })
            },
            fail: function () {
                console.log("fail1");
            },
            complete: function () {
                console.log("complete1");
            }
        })
    },
    //断开设备连接
    lanya0: function () {
        var that = this;
        wx.closeBLEConnection({
            deviceId: that.data.connectedDeviceId,
            success: function (res) {
                that.setData({
                    connectedDeviceId: "",
                })
            }
        })
    },
    //监听input表单
    inputTextchange: function (e) {
        this.setData({
            inputValue: e.detail.value
        })
    },
    //发送
    lanya8: function () {
        var that = this;
        // 这里的回调可以获取到 write 导致的特征值改变
        wx.onBLECharacteristicValueChange(function (characteristic) {
            console.log('characteristic value changed:1', characteristic)
        })
        var buf = new ArrayBuffer(16)
        var dataView = new DataView(buf)
        wx.request({
            url: **/getEncrypt',
            success: function (data) {
                var arr = data.data.data.split(",");
                console.log(arr);
                for (var i = 0; i < arr.length; i++) {
                    dataView.setInt8(i, arr[i]);
                }
                console.log('str', buf);
                console.log("writeServicweId", that.data.writeServicweId);
                console.log("writeCharacteristicsId", that.data.writeCharacteristicsId);
                wx.writeBLECharacteristicValue({
                    // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
                    deviceId: that.data.connectedDeviceId,
                    // 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取
                    serviceId: that.data.writeServicweId,
                    // 这里的 characteristicId 需要在上面的 getBLEDeviceCharacteristics 接口中获取
                    characteristicId: that.data.writeCharacteristicsId,
                    // 这里的value是ArrayBuffer类型
                    value: buf,
                    success: function (res) {
                        console.log('writeBLECharacteristicValue success', res.errMsg)
                    }
                })
            }
        })

    },
    //启用低功耗蓝牙设备特征值变化时的 notify 功能
    lanya9: function () {
        var that = this;
        //var notifyServicweId = that.data.notifyServicweId.toUpperCase();
        //var notifyCharacteristicsId = that.data.notifyCharacteristicsId.toUpperCase();
        //console.log("11111111", notifyServicweId);
        //console.log("22222222222222222", notifyCharacteristicsId);
        wx.notifyBLECharacteristicValueChange({
            state: true, // 启用 notify 功能
            // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
            deviceId: that.data.connectedDeviceId,
            // 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取
            serviceId: that.data.notifyServicweId,
            // 这里的 characteristicId 需要在上面的 getBLEDeviceCharacteristics 接口中获取
            characteristicId: that.data.notifyCharacteristicsId,
            success: function (res) {
                console.log('notifyBLECharacteristicValueChange success', res.errMsg)
            },
            fail: function () {
                console.log('shibai');
                console.log(that.data.notifyServicweId);
                console.log(that.data.notifyCharacteristicsId);
            },
        })
    },
    //接收消息
    lanya10: function () {
        var that = this;
        // 必须在这里的回调才能获取
        wx.onBLECharacteristicValueChange(function (characteristic) {
            let hex = Array.prototype.map.call(new Uint8Array(characteristic.value), x => ('00' + x.toString(16)).slice(-2)).join('');
            console.log(hex)
            wx.request({
                url: '***/getDecrypt',
                data: {hexString:hex},
                method:"POST",
                header: {
                    'content-type': 'application/x-www-form-urlencoded'
                },
                success:function(data){
                    //console.log(data)
                    var res = data.data.data;
                    that.setData({
                        jieshou: res,
                    })
                }
            })
        })
        console.log(that.data.readServicweId);
        console.log(that.data.readCharacteristicsId);
        wx.readBLECharacteristicValue({
            // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
            deviceId: that.data.connectedDeviceId,
            // 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取
            serviceId: that.data.readServicweId,
            // 这里的 characteristicId 需要在上面的 getBLEDeviceCharacteristics 接口中获取
            characteristicId: that.data.readCharacteristicsId,
            success: function (res) {
                console.log('readBLECharacteristicValue:', res.errMsg);
            }
        })
    },



})

index.wxss

.content {
  margin: 0 10px;
}

.status, .sousuo, .msg, .msg1 {
  display: block;
  line-height: 35px;
  margin: 0 10px;
}

.button {
  margin: 10px;
}

.sendto {
  line-height: 30px;
  display: block;
  margin: 10px;
}

在服务器端做的蓝牙加解密

/**
	 * 微信蓝牙加密接口
	 */
	public void getEncrypt(){
		byte[] bs = new byte[]{25,1,49};
		String string = null;
		try {
			string = AesEntryDetry.encrypt(bs);
		} catch (Exception e) {
			logger.info("加密错误");
		}
		if(string != null){
			setAttr("msg", "加密成功!");
			setAttr("code", "200");
			setAttr("data", string);
		}else{
			setAttr("msg", "加密失败!");
			setAttr("code", "400");
		}
		renderJson();
	}
	
	/**
	 * 微信蓝牙解密接口
	 */
	public void getDecrypt(){
		String hexString = getPara("hexString");
		byte[] bs = AesEntryDetry.hex2Bytes(hexString);
		String resString = null;
		try {
			resString = AesEntryDetry.decrypt(bs);
		} catch (Exception e) {
			logger.info("解密错误");
		}
		if(resString != null){
			setAttr("msg", "加密成功!");
			setAttr("code", "200");
			setAttr("data", resString);
		}else{
			setAttr("msg", "加密失败!");
			setAttr("code", "400");
		}
		renderJson();
	}


import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AesEntryDetry {
	// 加密秘钥 ,16个字节也就是128 bit
	private static final byte[] AES_KEY = { 需要和硬件统一 };
	// 加密方法
	public static String encrypt(byte[] bs) throws Exception {
		SecretKeySpec skeySpec = new SecretKeySpec(AES_KEY, "AES");
		Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
		cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
		if(bs.length < 16){
			bs = Arrays.copyOf(bs, 16);
		}
		byte[] encrypted = cipher.doFinal(bs);
		return BytetohexString(encrypted);
	}
	// 解密方法
	public static String decrypt(byte[] bs)throws Exception {
		SecretKeySpec skeySpec = new SecretKeySpec(AES_KEY, "AES");
		Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
		cipher.init(Cipher.DECRYPT_MODE, skeySpec);
		byte[] decrypted = cipher.doFinal(bs);
		return BytetohexString(decrypted);
	}
	// 字节数组按照一定格式转换拼装成字符串
	private static String BytetohexString(byte[] b) {
		int len = b.length;
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < len; i++) {
			if (i < len - 1){
				sb.append(b[i]);
				sb.append(",");
			}else{
				sb.append(b[i]);
			}
		}
		return sb.toString();
	}
	
	public static byte[] hex2Bytes(String src){  
        byte[] res = new byte[src.length()/2];  
        char[] chs = src.toCharArray();  
        int[] b = new int[2];  
  
        for(int i=0,c=0; i<chs.length; i+=2,c++){              
            for(int j=0; j<2; j++){  
                if(chs[i+j]>='0' && chs[i+j]<='9'){  
                    b[j] = (chs[i+j]-'0');  
                }else if(chs[i+j]>='A' && chs[i+j]<='F'){  
                    b[j] = (chs[i+j]-'A'+10);  
                }else if(chs[i+j]>='a' && chs[i+j]<='f'){  
                    b[j] = (chs[i+j]-'a'+10);  
                }  
            }
            b[0] = (b[0]&0x0f)<<4;  
            b[1] = (b[1]&0x0f);  
            res[c] = (byte) (b[0] | b[1]);  
        }  
        return res;  
    } 
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/133926.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 美国空间Hostease支付宝人民币购买教程图解[通俗易懂]

    美国空间Hostease支付宝人民币购买教程图解[通俗易懂]这段时间买国外主机的筒子们越来越多,而付款就是首先摆在大家眼前的一道障碍,大部分美国主机商只能通过信用卡购买,付款不方便,因此能够使用支付宝支付的主机商也备受关注。而目前全球支持支付宝付款的美国主机商一共就三家,分别是ixwebhosting、Godaddy、HostEase。第二道障碍就是网站英文界面问题,目前只有ixwebhosting开通了中文站点,因此大家购买ixwebhost…

    2022年10月18日
    0
  • Python实现Mean Shift聚类算法

    Python实现Mean Shift聚类算法MeanShift算法,又称均值聚类算法,聚类中心是通过在给定区域中的样本均值确定的,通过不断更新聚类中心,直到聚类中心不再改变为止,在聚类、图像平滑、分割和视频跟踪等方面有广泛的运用。MeanShift向量对于给定的n维空间RnR^nRn中的m个样本点X(i),i=1,…,mX^{(i)},i=1,…,mX(i),i=1,…,m对于其中的一个样本X,其MeanShift向量…

    2022年7月13日
    17
  • linux fsync实例,Python os.fsync()方法「建议收藏」

    linux fsync实例,Python os.fsync()方法「建议收藏」Python的os.fsync()方法返回强制将文件描述符fd写入磁盘。如果使用Python文件对象f,首先要执行f.flush(),然后执行os.fsync(f.fileno()),以确保与f关联的所有内部缓冲区都被写入磁盘。语法以下是fsync()方法的语法-os.fsync(fd)参数fd−这是缓冲区同步的文件描述符(必需的)。返回值此方法没有返回值。示例以下示例显示了fsync()…

    2022年5月31日
    79
  • rabbitmqkafka对比_全场景

    rabbitmqkafka对比_全场景这是陈东景于2021年8月29日下午16点原创作品,转载请标明出处!!!!在进行软件设计的过程中,如果软件设计业务上存在需要短时间内处理大批量的信息,又需要能保证软件能正常运行(保证软件的高可靠和高可用)。因为大批量(几十万,几百万级别的数据或者消息需要同一个时间处理),软件的IO过高,会导致软件运行阻塞或者消耗内存过高而崩溃,甚至是宕机。消息队列的概念被提了出来,通过缓存消息的模式,进行生产和消费。通过异步处理的方式,解耦这种短时间内出现大批量需要处理消息的场景。目前我们使用到的比…

    2022年10月14日
    0
  • 如何打开sln文件并显示窗口_在本机打开别人的sln文件[通俗易懂]

    如何打开sln文件并显示窗口_在本机打开别人的sln文件[通俗易懂]sln:在开发环境中使用的解决方案文件。它将一个或多个项目的所有元素组织到单个的解决方案中。此文件存储在父项目目录中.解决方案文件,他是一个或多个.proj(项目)的集合呵呵,今天没带书,就去网上找了个ASP.NET的源代码,叫简单实用的BLOG,一开始在web.config里捣鼓了半天,终于能把程序运行起来了,一看是MVP刘巍~真是意外啊。去看了看他的博客,言及两年来如何如何,及参加会议云云,想…

    2022年6月12日
    49
  • AutoMapper学习

    AutoMapper学习http://automapper.org/这是一款DTO的映射工具,AutoMapper是基于对象到对象约定的映射工具,它可以把复杂的对象模型转为DTO,或者其他的–那些让设计更合理更适于序列化、通信、传递消息的简单对象或者干脆就只是在领域层与应用层之间搭建一个简单的ACL防护层(就像DTO一样,用于代码的显示转换)来增加各自层的相互独立性。简单来说就是:就是根据A的模型和B的模型中的定义,自动将A模型映射为一个全新的B模型。前言VO、DTO、DO、PO、DAOVO(ViewObject.

    2022年10月22日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号