1. 前言

如果您阅读本文的时候有障碍或者有疑问,可以评论区留言或者看看本专栏的前部分内容。

从这一章节开始,我们不再仅仅讲解源码当中的例子了,因为越来越深入了。

特征的读写是BLE通讯中较为常用的数据交换手段了,因为源码给的例子中没有专门针对这个部分的内容,所以在这里我们自己制定一个实战DEMO。

2. 涉及到的API

2.1. write_gatt_char

写特征,在对特征进行写时,我们要提前获取到它的UUID或者Handle或者其他能体现特征身份的相关信息。在API里面有这样的解释道:

char_specifier (BleakGATTCharacteristic, int, str or UUID): The characteristic to writeto, specified by either integer handle, UUID or directly by theBleakGATTCharacteristic object representing it.

完整的API源码是这样的:

async def write_gatt_char(self,char_specifier: Union[BleakGATTCharacteristic, int, str, uuid.UUID],data: Union[bytes, bytearray, memoryview],response: bool = False,) -> None:"""Perform a write operation of the specified GATT characteristic.Args:char_specifier (BleakGATTCharacteristic, int, str or UUID): The characteristic to writeto, specified by either integer handle, UUID or directly by theBleakGATTCharacteristic object representing it.data (bytes or bytearray): The data to send.response (bool): If write-with-response operation should be done. Defaults to `False`."""if not isinstance(char_specifier, BleakGATTCharacteristic):characteristic = self.services.get_characteristic(char_specifier)else:characteristic = char_specifierif not characteristic:raise BleakError("Characteristic {} was not found!".format(char_specifier))response = (GattWriteOption.WRITE_WITH_RESPONSEif responseelse GattWriteOption.WRITE_WITHOUT_RESPONSE)buf = Buffer(len(data))buf.length = buf.capacitywith memoryview(buf) as mv:mv[:] = data_ensure_success(await characteristic.obj.write_value_with_result_async(buf, response),None,f"Could not write value {data} to characteristic {characteristic.handle:04X}",)

2.2. read_gatt_char

读特征,在对特征进行读取时,同样需要提前获取到它的UUID或者Handle或者其他能体现特征身份的相关信息。

完整的API源码是这样的:

async def read_gatt_char(self,char_specifier: Union[BleakGATTCharacteristic, int, str, uuid.UUID],**kwargs,) -> bytearray:"""Perform read operation on the specified GATT characteristic.Args:char_specifier (BleakGATTCharacteristic, int, str or UUID): The characteristic to read from,specified by either integer handle, UUID or directly by theBleakGATTCharacteristic object representing it.Keyword Args:use_cached (bool): ``False`` forces Windows to read the value from thedevice again and not use its own cached value. Defaults to ``False``.Returns:(bytearray) The read data."""use_cached = kwargs.get("use_cached", False)if not isinstance(char_specifier, BleakGATTCharacteristic):characteristic = self.services.get_characteristic(char_specifier)else:characteristic = char_specifierif not characteristic:raise BleakError("Characteristic {0} was not found!".format(char_specifier))value = bytearray(_ensure_success(await characteristic.obj.read_value_async(BluetoothCacheMode.CACHEDif use_cachedelse BluetoothCacheMode.UNCACHED),"value",f"Could not read characteristic handle {characteristic.handle}",))logger.debug(f"Read Characteristic {characteristic.handle:04X} : {value}")return value

3. 实战

现在要实现一个这样的功能:
用nRF Connect模拟一个设备,将GATT SERVICE里面一个特征设置成同时可读可写的属性。然后使用Bleak的在电脑上对刚刚模拟的设备进行读写操作(先写数据,再读取出来,看看是不是相同的内容)。

3.1 nRF Connect模拟设备

将Generic Access中的设备名字设置成可读可写属性:

3.2 代码编写

这次我们基于官方例子 service_explorer.py 进行二次开发,因为在对特征进行读取之前,我们需要先获取到它的句柄或者UUID相关信息。

对nRF Connect模拟的设备进行连接时,最好是通过名字进行扫描及搜索。对 service_explorer.py 进行一番简化及修改:

  • 通过设备名字扫描设备,获取到其设备地址
  • 通过扫描获取到的设备发起连接
import sys
import platform
import asyncio
import loggingfrom bleak import BleakClient
from bleak import BleakScannerlogger = logging.getLogger(__name__)DEVICE_NAME = "dabai"async def main():device = await BleakScanner.find_device_by_filter(lambda d, ad: d.name and d.name.lower() == DEVICE_NAME.lower())print(device)async with BleakClient(device.address) as client:logger.info(f"Connected: {client.is_connected}")for service in client.services:logger.info(f"[Service] {service}")for char in service.characteristics:if "read" in char.properties:try:value = bytes(await client.read_gatt_char(char.uuid))logger.info(f"\t[Characteristic] {char} ({','.join(char.properties)}), Value: {value}")except Exception as e:logger.error(f"\t[Characteristic] {char} ({','.join(char.properties)}), Value: {e}")else:value = Nonelogger.info(f"\t[Characteristic] {char} ({','.join(char.properties)}), Value: {value}")for descriptor in char.descriptors:try:value = bytes(await client.read_gatt_descriptor(descriptor.handle))logger.info(f"\t\t[Descriptor] {descriptor}) | Value: {value}")except Exception as e:logger.error(f"\t\t[Descriptor] {descriptor}) | Value: {e}")if __name__ == "__main__":logging.basicConfig(level=logging.INFO)asyncio.run(main())

运行结果,目前仅对目标进行了发现服务特征的操作:

EE:A6:84:0B:23:20: dabai
INFO:bleak.backends.winrt.client:Services resolved for BleakClientWinRT (EE:A6:84:0B:23:20)
INFO:__main__:Connected: True
INFO:__main__:[Service] 00001800-0000-1000-8000-00805f9b34fb (Handle: 1): Generic Access Profile
INFO:__main__:  [Characteristic] 00002a00-0000-1000-8000-00805f9b34fb (Handle: 2):  (read,write), Value: b'dabai'
INFO:__main__:  [Characteristic] 00002a01-0000-1000-8000-00805f9b34fb (Handle: 4):  (read), Value: b'\xc1\x00'
INFO:__main__:  [Characteristic] 00002a04-0000-1000-8000-00805f9b34fb (Handle: 6):  (read), Value: b'P\x00\xa0\x00\x00\x00\x90\x01'
INFO:__main__:  [Characteristic] 00002aa6-0000-1000-8000-00805f9b34fb (Handle: 8):  (read), Value: b'\x01'
INFO:__main__:[Service] 00001801-0000-1000-8000-00805f9b34fb (Handle: 10): Generic Attribute Profile
INFO:__main__:  [Characteristic] 00002a05-0000-1000-8000-00805f9b34fb (Handle: 11):  (indicate), Value: None
INFO:__main__:          [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 13): Client Characteristic Configuration) | Value: b'\x02\x00'
INFO:__main__:[Service] 0000180d-0000-1000-8000-00805f9b34fb (Handle: 14): Heart Rate
INFO:__main__:  [Characteristic] 00002a37-0000-1000-8000-00805f9b34fb (Handle: 15):  (notify), Value: None
INFO:__main__:          [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 17): Client Characteristic Configuration) | Value: b'\x00\x00'
INFO:__main__:  [Characteristic] 00002a38-0000-1000-8000-00805f9b34fb (Handle: 18):  (read), Value: b'\x03'
INFO:__main__:[Service] 0000180f-0000-1000-8000-00805f9b34fb (Handle: 20): Battery Service
INFO:__main__:  [Characteristic] 00002a19-0000-1000-8000-00805f9b34fb (Handle: 21):  (read), Value: b'a'
INFO:__main__:[Service] 0000180a-0000-1000-8000-00805f9b34fb (Handle: 23): Device Information
INFO:__main__:  [Characteristic] 00002a29-0000-1000-8000-00805f9b34fb (Handle: 24):  (read), Value: b'YFTech'
INFO:__main__:  [Characteristic] 00002a24-0000-1000-8000-00805f9b34fb (Handle: 26):  (read), Value: b'COROS M1D_4R9'
INFO:__main__:  [Characteristic] 00002a25-0000-1000-8000-00805f9b34fb (Handle: 28):  (read), Value: b'4B948172B1E2'
INFO:__main__:  [Characteristic] 00002a27-0000-1000-8000-00805f9b34fb (Handle: 30):  (read), Value: b'UVWbejJZpqrsPtwuvxy'
INFO:__main__:  [Characteristic] 00002a28-0000-1000-8000-00805f9b34fb (Handle: 32):  (read), Value: b'V 2.70.0'
INFO:__main__:[Service] 6e400001-b5a3-f393-e0a9-77656c6f6f70 (Handle: 34): Unknown
INFO:__main__:  [Characteristic] 6e400003-b5a3-f393-e0a9-77656c6f6f70 (Handle: 35):  (notify), Value: None
INFO:__main__:          [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 37): Client Characteristic Configuration) | Value: b'\x00\x00'
INFO:__main__:  [Characteristic] 6e400002-b5a3-f393-e0a9-77656c6f6f70 (Handle: 38):  (write-without-response,write), Value: None
INFO:__main__:[Service] 6e400001-b5a3-f393-e0a9-77757c7f7f70 (Handle: 40): Unknown
INFO:__main__:  [Characteristic] 6e400003-b5a3-f393-e0a9-77757c7f7f70 (Handle: 41):  (notify), Value: None
INFO:__main__:          [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 43): Client Characteristic Configuration) | Value: b'\x00\x00'
INFO:__main__:  [Characteristic] 6e400002-b5a3-f393-e0a9-77757c7f7f70 (Handle: 44):  (write-without-response,write), Value: None
INFO:__main__:[Service] 6e400001-b5a3-f393-e0a9-e50e24dcca9e (Handle: 46): Nordic UART Service
INFO:__main__:  [Characteristic] 6e400003-b5a3-f393-e0a9-e50e24dcca9e (Handle: 47):  (notify), Value: None
INFO:__main__:          [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 49): Client Characteristic Configuration) | Value: b'\x00\x00'
INFO:__main__:  [Characteristic] 6e400002-b5a3-f393-e0a9-e50e24dcca9e (Handle: 50):  (write-without-response,write), Value: None
INFO:__main__:[Service] 0000fee7-0000-1000-8000-00805f9b34fb (Handle: 52): Tencent Holdings Limited
INFO:__main__:  [Characteristic] 0000fea1-0000-1000-8000-00805f9b34fb (Handle: 53):  (read,notify,indicate), Value: b'\x01\x00\x00\x00'
INFO:__main__:          [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 55): Client Characteristic Configuration) | Value: b'\x00\x00'
INFO:__main__:  [Characteristic] 0000fea2-0000-1000-8000-00805f9b34fb (Handle: 56):  (read,write,indicate), Value: b"\x01\x10'\x00"
INFO:__main__:          [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 58): Client Characteristic Configuration) | Value: b'\x00\x00'
INFO:__main__:  [Characteristic] 0000fec9-0000-1000-8000-00805f9b34fb (Handle: 59):  (read), Value: b'\xee\xa6\x84\x0b# '
INFO:__main__:[Service] 00001814-0000-1000-8000-00805f9b34fb (Handle: 61): Running Speed and Cadence
INFO:__main__:  [Characteristic] 00002a53-0000-1000-8000-00805f9b34fb (Handle: 62):  (notify), Value: None
INFO:__main__:          [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 64): Client Characteristic Configuration) | Value: b'\x00\x00'
INFO:__main__:  [Characteristic] 00002a54-0000-1000-8000-00805f9b34fb (Handle: 65):  (read), Value: b'\x05\x00'
INFO:__main__:[Service] 00001816-0000-1000-8000-00805f9b34fb (Handle: 67): Cycling Speed and Cadence
INFO:__main__:  [Characteristic] 00002a5b-0000-1000-8000-00805f9b34fb (Handle: 68):  (notify), Value: None
INFO:__main__:          [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 70): Client Characteristic Configuration) | Value: b'\x00\x00'
INFO:__main__:  [Characteristic] 00002a5c-0000-1000-8000-00805f9b34fb (Handle: 71):  (read), Value: b'\x07\x00'
INFO:__main__:  [Characteristic] 00002a5d-0000-1000-8000-00805f9b34fb (Handle: 73):  (read), Value: b'\x04'
INFO:__main__:  [Characteristic] 00002a55-0000-1000-8000-00805f9b34fb (Handle: 75):  (write,indicate), Value: None
INFO:__main__:          [Descriptor] 00002902-0000-1000-8000-00805f9b34fb (Handle: 77): Client Characteristic Configuration) | Value: b'\x00\x00'

我们主要在意这部分输出结果:

可以得知我们设置的这个特征的UUID是这样的

【Bleak】八、特征的读写相关推荐

  1. Go语言学习笔记(十八)之文件读写

    25.文件读写 1.文件打开和读 A.文件分类:文本和二进制文件 B.文件存取方式:随机存取和顺序存取 文件打开代码示例: 1: package main 2: 3: import ( 4: &quo ...

  2. SO逆向入门实战教程八:文件读写

    文章目录 一.前言 二.demo1设计 三.Unidbg模拟执行demo1 四.demo2设计 五.Unidbg模拟执行demo2 六.尾声 一.前言 本篇分析的是自写demo,帮助大家熟悉Unidb ...

  3. 八、Python读写文件的方法

    Python读写文件的方法 读取文件的对象:fin = open("data.txt") 写出文件的对象:fout = open("data.txt",&quo ...

  4. 【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验十八:SDRAM模块① — 单字读写...

    实验十八:SDRAM模块① - 单字读写 笔者与SDRAM有段不短的孽缘,它作为冤魂日夜不断纠缠笔者.笔者尝试过许多方法将其退散,不过屡试屡败的笔者,最终心情像橘子一样橙.<整合篇>之际, ...

  5. hdfs读写流程_深度探索Hadoop分布式文件系统(HDFS)数据读取流程

    一.开篇 Hadoop分布式文件系统(HDFS)是Hadoop大数据生态最底层的数据存储设施.因其具备了海量数据分布式存储能力,针对不同批处理业务的大吞吐数据计算承载力,使其综合复杂度要远远高于其他数 ...

  6. .locked勒索病毒来势汹汹该怎么办?

    一.勒索病毒来势汹汹 从8月28日开始,多个社交媒体以及安全技术社区均有用户称遭遇".locked"后缀勒索病毒攻击,计算机文件被病毒加密,用户"中招"后,需支 ...

  7. 蓝牙4.0--Android BLE(二)BleLib开源库

    简介 首先非常感谢BleLib的作者为我们提供了如此方便的开源库:这个库大大的简化了我们BLE开发的步骤,操作非常简单 BleLib中的关键类 BleService是单个Ble连接操作的服务类 Gat ...

  8. 2020:下一个十年,存储发展的趋势是什么?(全集)

    前   言 今天是五四青年节,祝朋友们永葆青春的心态,积极乐观.开放真实.审慎务实. " 青春不是年华,而是心境.   无论年届花甲,抑或二八芳龄,心中皆有生命之欢乐,奇迹之诱惑,孩童般天真 ...

  9. python常用的内置函数

    内置函数,就是Python提供的, 可以直接拿来直接用的函数. 一.数字相关 01 数据类型 bool() 描述:测试一个对象是True, 还是False.bool 是 int 的子类. 语法:cla ...

最新文章

  1. 语义分割--Pixel Deconvolutional Networks
  2. 关于线程池你不得不知道的一些设置
  3. Python 公众号 小程序抓包分析
  4. 地理标志农产品数据发布 特色产业对话农民丰收节交易会
  5. MySQL数据库:读写分离
  6. MyEclipse配置Tomcat没有Tomcat选项没有小猫图
  7. uva 12442 . Forwarding Emails
  8. php中的rand,php rand() 随机数生成的方法介绍
  9. Debian 7.8 通过 apt-get 安装 nodejs
  10. css学习之border 边框
  11. 16 Managing Undo
  12. bzoj 1015: [JSOI2008]星球大战starwar
  13. 高德地图android离线包下载,高德地图(车机版)离线包下载与安装
  14. 基于html制作一个介绍自己家乡的网站,排版整洁,内容丰富,主题鲜明
  15. 微信小游戏3d入门视频教程
  16. 打开注册表regedit
  17. ts快捷键 vscode_vscode这篇就够了
  18. Qt Quick事件处理之鼠标 键盘 定时器
  19. VSCode选中变量高亮颜色及注释颜色更改
  20. 自建CA给内部网站颁发SSL证书

热门文章

  1. 轻巧好用的开源 Redis 可视化工具
  2. JS注释(多行注释+单行注释)
  3. UpdatePanel的简单用法(非嵌套)
  4. SpringCloud - Oauth2增加短信验证码验证登录
  5. liunx系统下载VSCODE教程
  6. Ajax -模板引擎方法 -循环、分支、原生语法、实例
  7. Ubuntu22.04常用软件安装新手向
  8. 2023年中国传媒大学程序设计大赛(同步赛)A — E
  9. 主板上常见英文标识的解释及功能说明
  10. 【UPCOJ】14045问题 G: 坐船