当前位置: 首页 > news >正文

MAUI APP开发蓝牙协议的经验分享:与跳绳设备对接

在开发MAUI应用程序时,蓝牙协议的应用是一个重要的环节,尤其是在需要与外部设备如智能跳绳进行数据交换的场景中。以下是我在开发过程中的一些经验和心得,希望能为你的项目提供帮助。

1. 蓝牙协议基础

蓝牙协议是无线通信的一种标准,允许设备之间进行短距离的数据交换。在MAUI开发中,我们主要关注的是BLE(Bluetooth Low Energy,低功耗蓝牙)协议,它以其低功耗和低成本的特点被广泛应用于智能设备中。

2. 使用Ble蓝牙助手

在开发过程中,我使用了“BLE蓝牙助手”这款应用来辅助调试和理解蓝牙协议。这款应用可以帮助我们扫描周围的BLE设备,查看设备的信号强度(RSSI),连接设备,并查看服务和特征。通过这个工具,我们可以更直观地理解BLE协议的工作原理和数据交换过程。

3. MAUI中的蓝牙开发

        MAUI(.NET Multi-platform App UI)是一个跨平台框架,它允许开发者使用C#和XAML创建跨平台的移动和桌面应用。MAUI以其性能优异、可扩展性强和结构简单而受到开发者的青睐。在本次开发中,MAUI作为主要的开发框架,提供了丰富的控件和API,使得与蓝牙设备的对接成为可能。

        MAUI支持多种平台,包括Android、iOS、macOS和Windows,这为开发跨平台应用提供了极大的便利。在本项目中,我们将重点利用MAUI的跨平台特性,开发一款能够在不同操作系统上运行的跳绳计数应用。

        在MAUI中,我们可以通过Plugin.BLE来实现蓝牙功能。以下是一些关键步骤:

3.1 扫描设备

首先,我们需要扫描周围的BLE设备。在MAUI中,我们可以使用以下代码来启动扫描:

await CurrentAdapter.StartScanningForDevicesAsync();public  async Task<bool> StartScanAsync(){//检查获取蓝牙权限bool isPermissionPass = await CheckAndRequestBluetoothPermission();if (!isPermissionPass)return false;// 在使用之前,确保 _scanForAedCts 已经被实例化ListDevice.Clear();try{if(CurrentAdapter == null){CurrentAdapter = CrossBluetoothLE.Current.Adapter;}await CurrentAdapter.StopScanningForDevicesAsync();CurrentAdapter.DeviceDiscovered += Adapter_DeviceDiscovered;CurrentAdapter.ScanTimeoutElapsed += Adapter_ScanTimeoutElapsed;//蓝牙扫描时间CurrentAdapter.ScanTimeout = 30 * 1000;//默认LowPowerCurrentAdapter.ScanMode = Plugin.BLE.Abstractions.Contracts.ScanMode.LowPower;Debug.WriteLine($"开始扫描外设, IsAvailable={CrossBluetoothLE.Current.IsAvailable}, IsOn={CrossBluetoothLE.Current.IsOn}, State={CrossBluetoothLE.Current.State}, ScanMode={CurrentAdapter.ScanMode}, ScanTimeout={CurrentAdapter.ScanTimeout}");await CurrentAdapter.StartScanningForDevicesAsync(cancellationToken: _scanForAedCts.Token);Debug.WriteLine($"结束扫描外设");}catch (OperationCanceledException){Debug.WriteLine($"扫描外设任务取消");}catch (Exception ex){Debug.WriteLine($"扫描外设出错, {ex.Message}");}finally{CurrentAdapter.DeviceDiscovered -= Adapter_DeviceDiscovered;CurrentAdapter.ScanTimeoutElapsed -= Adapter_ScanTimeoutElapsed;//_scanForAedCts.Dispose();}return true;}

在扫描过程中,我们可以通过DeviceDiscovered事件来获取发现的设备信息。

3.2 连接设备

一旦找到目标设备,我们就可以建立连接。在MAUI中,连接设备的过程如下:

await CurrentAdapter.ConnectToDeviceAsync(device, new ConnectParameters(false, true));/// <summary>/// 连接设备/// </summary>/// <param name="uuid"></param>/// <returns></returns>public async Task<IDevice?> ConnectDeviceAsync(Guid uuid){try{if (CurrentAdapter == null){CurrentAdapter = CrossBluetoothLE.Current.Adapter;}var connectedDevices = CurrentAdapter.ConnectedDevices;if (connectedDevices.Count > 0){// 至少有一个设备已经连接foreach (var device in connectedDevices){// 可以在这里处理每个已连接的设备if (device.Id == uuid){await StartNotify(device);return device;}Console.WriteLine(device.Name);}}else{try{using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15))){var device = await CurrentAdapter.ConnectToKnownDeviceAsync(uuid, default(ConnectParameters), cts.Token);await StartNotify(device);return device;}}catch (Exception ex) { Debug.WriteLine($"蓝牙连接设备失败, {ex.Message}"); }}}catch(Exception ex){Debug.WriteLine($"蓝牙连接设备失败, {ex.Message}");}return null;}

这里device是我们通过扫描得到的设备对象,ConnectParameters用于设置连接参数。

3.3 获取服务和特征

连接成功后,我们可以获取设备提供的服务和特征,这对于数据交换至关重要:

var services = await device.GetGattServicesAsync();

3.4 数据读写

通过获取的特征,我们可以进行数据的读写操作。例如,读取跳绳的次数和时间:

var characteristic = services.First().GetCharacteristics().First();
var readResult = await characteristic.ReadValueAsync();/// <summary>/// 读取数据/// </summary>/// <param name="characteristic"></param>/// <returns></returns>public async Task<byte[]?> ReadDataAsync(ICharacteristic characteristic){//根据Plugin.BLE要求,在主线程读写数据var result = await MainThread.InvokeOnMainThreadAsync(async () =>{try{//读取数据var ary = await characteristic.ReadAsync();Debug.WriteLine($"读取成功,长度={ary.data.Length}");return (ary.data);}catch (Exception ex){Debug.WriteLine($"读取错误, 目标设备蓝牙连接状态={BleDevice?.State}, {ex.Message}");return null;}});return result;}/// <summary>/// 读取蓝牙设备数据/// </summary>/// <param name="guid"></param>/// <returns></returns>public async Task<byte[]?> ReadDataAsync(IDevice device){var service = await device.GetServiceAsync(new Guid("0000180D-0000-1000-8000-00805F9B34FB"));if (service != null){var characteristic = await service.GetCharacteristicAsync(new Guid("00002A37-0000-1000-8000-00805F9B34FB"));if (characteristic != null){var ary = await characteristic.ReadAsync();return (ary.data);}}return null;}/// <summary>/// 写入蓝牙设备数据/// </summary>/// <param name="device"></param>/// <param name="ary"></param>/// <returns></returns>public async Task<int> SendDataAsync(IDevice device, byte[] ary){var service = await device.GetServiceAsync(_serviceUuid);if (service != null){var characteristic = await service.GetCharacteristicAsync(_characteristicUuid);if (characteristic != null && characteristic.CanWrite==true){return await characteristic.WriteAsync(ary);}}return 0;}

3.5事件订阅

通过获取的特征,我们可以进行数据的通知操作。

#region 订阅事件private async Task<int> StartNotify(IDevice device){try{var service = await device.GetServiceAsync(_serviceUuid);if (service != null){var notifyCharacteristic = await service.GetCharacteristicAsync(_characteristicUuid);if (notifyCharacteristic.Properties.HasFlag(CharacteristicPropertyType.Notify)){// 特性支持通知// 订阅事件notifyCharacteristic.ValueUpdated += NotifyCharacteristic_ValueUpdated;// 启用通知await notifyCharacteristic.StartUpdatesAsync();}}}catch(Exception ex){}return 0;}// 处理特性值更新事件private void NotifyCharacteristic_ValueUpdated(object sender, Plugin.BLE.Abstractions.EventArgs.CharacteristicUpdatedEventArgs e){// 处理特性值更新NotifyQueue.Enqueue( e.Characteristic.Value);// ...}public async Task<byte[]?> ReadNotify(IDevice device){if (device.IsConnectable == true){if (NotifyQueue.Count > 0){return NotifyQueue.Dequeue();}}return null;}private async Task<int> StopNotify(IDevice device){var service = await device.GetServiceAsync(_serviceUuid);if (service != null){// 获取服务和特性var notifyCharacteristic = await service.GetCharacteristicAsync(_characteristicUuid);if (notifyCharacteristic.Properties.HasFlag(CharacteristicPropertyType.Notify)){// 特性支持通知// 订阅事件notifyCharacteristic.ValueUpdated -= NotifyCharacteristic_ValueUpdated;// 启用通知await notifyCharacteristic.StopUpdatesAsync();}}return 0;}#endregion

 

4. 跳绳设备对接实践

        在实际对接跳绳设备时,我们需要根据设备的技术文档来确定服务和特征的UUID。一旦确定,就可以按照上述步骤进行连接和数据交换。例如,读取跳绳次数的特征可能有一个特定的UUID,我们可以通过这个UUID来读取或写入数据。

5. 注意事项

  • 确保在开发过程中,手机的蓝牙功能处于开启状态。
  • 在配对设备时,确保手机与跳绳设备的距离足够近,以保证信号的稳定性。
  • 在读取和写入数据时,要注意数据格式和编码方式,确保数据的正确解析。

通过上述步骤和注意事项,可以在MAUI中顺利实现与BLE设备的对接,记录跳绳的次数与时间。希望这些经验能够帮助你在开发过程中少走弯路,快速实现功能

相关文章:

MAUI APP开发蓝牙协议的经验分享:与跳绳设备对接

在开发MAUI应用程序时&#xff0c;蓝牙协议的应用是一个重要的环节&#xff0c;尤其是在需要与外部设备如智能跳绳进行数据交换的场景中。以下是我在开发过程中的一些经验和心得&#xff0c;希望能为你的项目提供帮助。 1. 蓝牙协议基础 蓝牙协议是无线通信的一种标准&#x…...

最新版Node.js下载安装及环境配置教程

目录 初识&#xff1a;Node.js 一、下载&#xff1a;Node.js 二、安装&#xff1a;Node.js 1.下载【node.js】压缩包安装文件 2.解压下载的安装包 3.打开解压的【node-v22.11.0-x64】文件夹 4.双击启动安装程序 5.点击【Next】 6.勾选【I accept the terms in the Lic…...

51c自动驾驶~合集39

我自己的原文哦~ https://blog.51cto.com/whaosoft/12707676 #DiffusionDrive 大幅超越所有SOTA&#xff01;地平线DiffusionDrive&#xff1a;生成式方案或将重塑端到端格局&#xff1f; 近年来&#xff0c;由于感知模型的性能持续进步&#xff0c;端到端自动驾驶受到了来…...

单链表基础操作

文章目录 abstract定义结点结构初始化链表遍历链表求表长查找结点根据序号查找结点根据值查找结点 插入结点首尾位置插入一般位置插入(通用插入)找到尾元素|尾指针相关操作 删除结点 abstract 单链表是一种简单的动态数据结构&#xff0c;它由一系列结点组成&#xff0c;每个结…...

Asp.net MVC在VSCore中的页面的增删改查(以Blog项目为例),用命令代码

在VSCore中的页面的增删改查(以Blog项目为例) 1.创建项目&#xff08;无解决方案&#xff09;复杂项目才需要 dotnet new mvc -o Blog2.控制器 BlogsController.cs 控制器&#xff08;Controller&#xff09;名字和视图&#xff08;View&#xff09;中的文件名要一模一样 u…...

【Leecode】Leecode刷题之路第66天之加一

题目出处 66-加一-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 66-加一-官方解法 方法1&#xff1a;找出最长的后缀9 思路&#xff1a; 代码示例&#xff1a;&#xff08;Java&#…...

使用 VLC 在本地搭建流媒体服务器 (详细版)

提示&#xff1a;详细流程 避坑指南 Hi~&#xff01;欢迎来到碧波空间&#xff0c;平时喜欢用博客记录学习的点滴&#xff0c;欢迎大家前来指正&#xff0c;欢迎欢迎~~ ✨✨ 主页&#xff1a;碧波 &#x1f4da; &#x1f4da; 专栏&#xff1a;音视频 目录 借助VLC media pl…...

Ubuntu 常用解压与压缩命令

.zip文件 unzip FileName.zip # 解压 zip DirName.zip DirName # 将DirName本身压缩 zip -r DirName.zip DirName # 压缩&#xff0c;递归处理&#xff0c;将指定目录下的所有文件和子目录一起压缩 zip DirName.zip DirName 行为&#xff1a; 只压缩 DirName 目录本身&#xff…...

【深度学习】四大图像分类网络之AlexNet

AlexNet是由Alex Krizhevsky、Ilya Sutskever&#xff08;均为Hinton的学生&#xff09;和Geoffrey Hinton&#xff08;被誉为”人工智能教父“&#xff0c;首先将反向传播用于多层神经网络&#xff09;在2012年ImageNet图像分类竞赛中提出的一种经典的卷积神经网络。AlexNet在…...

Day1——GitHub项目共同开发

MarkDowm解释 Markdown是一种轻量级标记语言&#xff0c;它允许人们使用易读易写的纯文本格式编写文档&#xff0c;然后转换成结构化的HTML代码。Markdown的目的是让文档的编写和阅读变得更加容易&#xff0c;同时也不失HTML的强大功能。以下是Markdown的一些基本概念和用法&a…...

基于PHP的香水销售系统的设计与实现

摘 要 时代科技高速发展的背后&#xff0c;也带动了经济的增加&#xff0c;人们对生活质量的要求也不断提高。香水作为一款在人际交往过程中&#xff0c;给对方留下良好地第一印象的产品&#xff0c;在生活中也可以独自享受其为生活带来的点缀。目前香水市场体量庞大&#xff…...

A-star算法

算法简介 A*&#xff08;A-star&#xff09;算法是一种用于图形搜索和路径规划的启发式搜索算法&#xff0c;它结合了最佳优先搜索&#xff08;Best-First Search&#xff09;和Dijkstra算法的思想&#xff0c;能够有效地寻找从起点到目标点的最短路径。A*算法广泛应用于导航、…...

前端用原生js下载File对象文件,多用于上传附件时,提交之前进行点击预览,或打开本地已经选择待上传的附件列表

用于如上图场景&#xff0c;已经点击选择了将要上传的文件&#xff0c;在附件列表里面用户希望点击下载文件&#xff0c;以核实自己是否选中了需要上传的文件&#xff0c;此刻就需要 用到下面的方法&#xff1a; // 下载File对象文件 downloadByFileObject(file, { fileName }…...

服务器记录所有用户docker操作,监控删除容器/镜像的人

文章目录 使用场景安装auditd添加docker审计规则设置监控日志大小与定期清除查询 Docker 操作日志查看所有用户&#xff0c;所有操作日志查看特定用户的 Docker 操作查看所有用户删除容器/镜像日志过滤特定时间范围内日志 使用场景 多人使用的服务器&#xff0c;使用的docker …...

关于使用天地图、leaflet、ENVI、Vue工具实现 前端地图上覆盖上处理的农业地块图层任务

1.项目框架搭建 项目地址&#xff1a;Webgis: 一个关于webgis、天地图、Leaflet、Vue、数据库的学习框架。 ①git到本地&#xff0c;vscode打开。 ② 配置后端 搜索下载MySQL插件&#xff08;前提&#xff1a;电脑中装有MySQL才可应用&#xff09;。 连接数据库。 配置基本…...

基于yolov4深度学习网络的排队人数统计系统matlab仿真,带GUI界面

目录 1.算法仿真效果 2.算法涉及理论知识概要 3.MATLAB核心程序 4.完整算法代码文件获得 1.算法仿真效果 matlab2022a仿真结果如下&#xff08;完整代码运行后无水印&#xff09;&#xff1a; 仿真操作步骤可参考程序配套的操作视频。 2.算法涉及理论知识概要 在现代社会…...

用 React 编写一个笔记应用程序

这篇文章会教大家用 React 编写一个笔记应用程序。用户可以创建、编辑、和切换 Markdown 笔记。 1. nanoid nanoid 是一个轻量级和安全的唯一字符串ID生成器&#xff0c;常用于JavaScript环境中生成随机、唯一的字符串ID&#xff0c;如数据库主键、会话ID、文件名等场景。 …...

如何离线安装dockerio

如何离线安装dockerio 一、下载Docker离线安装包二、上传离线安装包三、解压安装包四、复制文件到系统目录五、配置Docker服务六、设置文件权限并重新加载配置七、启动Docker服务八、设置开机自启动九、验证安装Docker是一个开源的容器化平台,用于开发、发布和运行应用程序。离…...

LocalDateTime序列化(跟redis有关)

使用过 没成功&#xff0c;序列化后是[2024 11 10 17 22 20]差不多是这样&#xff0c; 反序列化后就是&#xff1a; [ 2024 11 10.... ] 可能是我漏了什么 这是序列化后的&#xff1a; 反序列化后&#xff1a; 方法&#xff08;加序列化和反序列化注解&#xff09;&…...

【redis】如何跑

在 Windows 上配置 Redis 需要一些额外的步骤&#xff0c;因为 Redis 官方并没有为 Windows 提供原生支持。不过&#xff0c;可以通过以下方法来安装和配置 Redis。 方法一&#xff1a;使用 Windows 版 Redis&#xff08;非官方版本&#xff09; 下载 Redis for Windows Redis…...

Scala学习记录,全文单词统计

package test32 import java.io.PrintWriter import scala.io.Source //知识点 // 字符串.split("分隔符"&#xff1a;把字符串用指定的分隔符&#xff0c;拆分成多个部分&#xff0c;保存在数组中) object test {def main(args: Array[String]): Unit {//从文件1.t…...

【MyBatis】验证多级缓存及 Cache Aside 模式的应用

文章目录 前言1. 多级缓存的概念1.1 CPU 多级缓存1.2 MyBatis 多级缓存 2. MyBatis 本地缓存3. MyBatis 全局缓存3.1 MyBatis 全局缓存过期算法3.2 CacheAside 模式 后记MyBatis 提供了缓存切口&#xff0c; 采用 Redis 会引入什么问题&#xff1f;万一遇到需强一致场景&#x…...

学习ASP.NET Core的身份认证(基于Session的身份认证3)

开源博客项目Blog中提供了另一种访问控制方式&#xff0c;其基于自定义类及函数的特性类控制访问权限。本文学习并测试开源博客项目Blog的访问控制方式&#xff0c;测试程序中直接复用开源博客项目Blog中的相关类及接口定义&#xff0c;并在其上调整判断逻辑。   首先是接口A…...

速盾:高防 CDN 可以配置客户端请求超时配置?

在高防 CDN&#xff08;Content Delivery Network&#xff0c;内容分发网络&#xff09;的运行管理中&#xff0c;客户端请求超时配置是一项重要的功能设定&#xff0c;它对于优化网络资源分配、保障服务质量以及维护系统稳定性有着关键意义。 一、客户端请求超时配置的概念 …...

DRM(数字权限管理技术)防截屏录屏----ffmpeg安装

提示&#xff1a;ffmpeg安装 文章目录 [TOC](文章目录) 前言一、下载二、配置环境变量三、运行ffmpeg四、文档总结 前言 FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的…...

使用PyQt5开发一个GUI程序的实例演示

一、安装Python 下载安装到这个目录 G:\Python38-32 安装完成有这些工具&#xff0c;后面备用&#xff1a; G:\Python38-32\Scripts\pyrcc5.exe G:\Python38-32\Scripts\pyuic5.exe 二、PyQt环境配置 pip install PyQt5 pip install pyqt5-tools 建议使用国内源&#xff0c…...

【VUE3】【Naive UI】<NCard> 标签

【Vue3】【Naive UI】 标签 title 属性bordered 属性header-style 和 body-style 属性footer 属性actions 属性hoverable 属性loading 属性size 属性type 属性cover 和 avatar 属性description 属性style 属性 【VUE3】【Naive UI】&#xff1c;NCard&#xff1e; 标签 【VUE3】…...

选择排序之大根堆

大根堆&#xff1a;树的根节点大于左右子树的结点值&#xff0c;这样就能保证每次从树根取的是最大值 灵魂在于HeadAdjust函数&#xff0c;以某节点为树根通过下落调整为大根堆&#xff0c; 建树思想 就是&#xff0c;从最后一个非终端结点开始调整以该结点为根的子树&#x…...

AI的魔力:如何为开源软件注入智慧,开启无限可能

“AI的魔力&#xff1a;如何为开源软件注入智慧&#xff0c;开启无限可能” 引言&#xff1a; 在科技发展的浪潮中&#xff0c;开源软件生态一直扮演着推动创新与共享的重要角色。从Linux到Python&#xff0c;开源项目赋予了开发者全球协作的机会&#xff0c;推动了技术的飞速…...

如何在 VPS 上使用 Git 设置自动部署

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 介绍 要了解 Git 的基本知识以及如何安装&#xff0c;请参考介绍教程。 本文将教你如何在部署应用程序时使用 Git。虽然有许多使用 Gi…...

保定行业网站/百度非企推广开户

1.安装 1.1安装mmseg ./bootstrap # 必须执行&#xff0c;不然安装会失败 ./configure --prefix/usr/local/mmseg-3.2.14 #指定安装目录 make make install 1.2安装coreseek # 在csft-4.1/configure.ac中 # 查找 AM_INIT_AUTOMAKE([-Wall -Werror foreign]) # 更改 AM_INIT_AUT…...

网站建设毕业设计心得/google浏览器入口

VLAN之间在二层是分隔开的&#xff0c;如果要实现VLAN之间的通信&#xff0c;必须要借助到三层路由功能。 支持VLAN间路由的设备&#xff1a;  1.任意的3层交换机  2.支持以太口起子接口的路由器   &#xff1c;单臂路由&#xff08;Router on a Stick&#xff09;&#xf…...

网站策划方案ppt/如何推广自己的微信号

字符串分割&#xff0c;将一个字符串分裂成多个字符串组成的列表&#xff0c;可以理解为字符串转列表&#xff0c;经常会用到语法&#xff1a;str.split(sep, [,max]),sep可以指定切割的符号&#xff0c;max可以指定切割的次数(次数不常用)不带参数时以空格进行分割带参数时&am…...

做网站需要编程/东莞seo外包公司

反射的基础: java.lang.ClassClass类的实例对象&#xff0c;用于记录类描述信息。源码说&#xff1a;represent classes and interfaces in a running Java applicationClass类没有公共的构造方法&#xff0c;无法通过new运算符实例化&#xff1b;只能通过对象的getClass方法&a…...

哪些网站是用织梦做的/上海seo网站排名优化公司

| 管道符 #将前一个命令作为后一个命令的输入 cat > t who | wc -l #crtld chmod x t #! 指定处理脚本所需的shell&#xff0c;常见shell有bash&#xff0c;还有expect此类不常见的shell printf 输出 printf "%s\t\n" china # 输出 china IO重定向 # crtll…...

网站建设ppt/百度新闻头条

摘要&#xff1a;分形(Fractal)是在二十世纪70年代兴起的最重要的非线性科学之一,曼德尔布罗特(Mandelbrot)通过数学公式迭代和计算机编程技术构建了以自己名字命名的Mandelbrot集,分形理论由此产生.分形理论是一种新型的数学语言,可以用于对大自然几何图形的描述,可以在分形理…...