SiriBlog

siriyang的个人博客


  • 首页

  • 排行榜

  • 标签115

  • 分类37

  • 归档318

  • 关于

  • 搜索

Pythonista中文文档:cb

发表于 2020-04-13 更新于 2021-10-29 分类于 计算机 , 技术 , Python 阅读次数: Valine:
本文字数: 10k 阅读时长 ≈ 9 分钟

Pythonista中文文档

cb — 连接到蓝牙LE外围设备


  cb(“核心蓝牙”)模块使你可以连接到蓝牙LE(“低能量”)外设,如TI SensorTag(包含像红外温度计,加速计等多种传感器小型和负担得起的BTLE设备)。

  本文档中的示例假定你具有标准的Bluetooth LE心率监视器或TI SensorTag,但是该模块还可以与其他类型的Bluetooth LE外设配合使用。请注意,不支持“经典​​”蓝牙(耳机,键盘等)。

  该模块基于CoreBluetooth框架,但未公开其所有功能-例如,它仅实现核心角色,即,你可以连接到外围设备,而不能让设备充当外围设备本身。


快速入门

  连接到Bluetooth LE设备并从中读取数据的基本过程包括以下步骤:

  1. 定义一个代理对象,该对象负责处理有关发现的设备(外围设备),服务和服务特征的通知/回调。稍后将介绍你可以实现的回调方法。
  2. 调用scan_for_peripherals()开始扫描。在许多情况下,你还需要使设备可被发现。对于TI SensorTag,你可以按侧面按钮。
  3. 当你的代理收到did_discover_peripheral回调时,检查其名称或uuid,如果找到了要连接的外围设备,调用connect_peripheral()。你还应该保留对发现的外围设备的引用,因为如果该对象是垃圾回收的,那么你还将失去连接。
  4. 如果一切顺利,则将调用did_connect_peripheral回调。此时,你可以通过调用Peripheral.discover_services()开始发现外围设备的服务。
  5. 发现外围设备的服务后,你将收到did_discover_services回调。现在,你可以访问外围设备的services属性,并-对于你感兴趣的服务-调用Peripheral.discover_characteristics()。
  6. 你可能已经猜到了,这将导致did_discover_characteristics回调。现在,你可以通过调用Peripheral.read_characteristic_value()读取特征的值(成功读取值后将导致另一个回调),或通过调用Peripheral.set_notify_value()启用该特征的通知。
  7. 以下代码显示了如何连接到Bluetooth LE心率监测器。这个特定的示例假设你拥有Polar设备,但是应该很容易将其适应其他品牌(只需相应地更改did_discover_peripheral方法):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import cb
import sound
import time
import struct
from __future__ import print_function

class HeartRateManager (object):
def __init__(self):
self.peripheral = None

def did_discover_peripheral(self, p):
if p.name and 'Polar' in p.name and not self.peripheral:
self.peripheral = p
print('Connecting to heart rate monitor...')
cb.connect_peripheral(p)

def did_connect_peripheral(self, p):
print('Connected:', p.name)
print('Discovering services...')
p.discover_services()

def did_fail_to_connect_peripheral(self, p, error):
print('Failed to connect: %s' % (error,))

def did_disconnect_peripheral(self, p, error):
print('Disconnected, error: %s' % (error,))
self.peripheral = None

def did_discover_services(self, p, error):
for s in p.services:
if s.uuid == '180D':
print('Discovered heart rate service, discovering characteristitcs...')
p.discover_characteristics(s)

def did_discover_characteristics(self, s, error):
print('Did discover characteristics...')
for c in s.characteristics:
if c.uuid == '2A37':
self.peripheral.set_notify_value(c, True)

def did_update_value(self, c, error):
heart_rate = struct.unpack('<B', c.value[1])[0]
self.values.append(heart_rate)
print('Heart rate: %i' % heart_rate)

mngr = HeartRateManager()
cb.set_central_delegate(mngr)
print('Scanning for peripherals...')
cb.scan_for_peripherals()

try:
while True: pass
except KeyboardInterrupt:
cb.reset()

  下面的示例演示如何使用TI SensorTag执行类似的操作。它将记录温度传感器的值(大约每秒一次,与上面的心率监视器示例非常相似),并在按下SensorTag的两个按钮中的任何一个时播放声音:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import cb
import sound
import struct

class MyCentralManagerDelegate (object):
def __init__(self):
self.peripheral = None

def did_discover_peripheral(self, p):
print('+++ Discovered peripheral: %s (%s)' % (p.name, p.uuid))
if p.name and 'Sensor Tag' in p.name and not self.peripheral:
# 保留外围设备的引用,这样他就不会被垃圾回收:
self.peripheral = p
cb.connect_peripheral(self.peripheral)

def did_connect_peripheral(self, p):
print('*** Connected: %s' % p.name)
print('Discovering services...')
p.discover_services()

def did_fail_to_connect_peripheral(self, p, error):
print('Failed to connect')

def did_disconnect_peripheral(self, p, error):
print('Disconnected, error: %s' % (error,))
self.peripheral = None

def did_discover_services(self, p, error):
for s in p.services:
if 'AA00' in s.uuid:
print('+++ IR Thermometer found')
p.discover_characteristics(s)
elif 'FFE0' in s.uuid:
print('+++ Simple Key Service found')
p.discover_characteristics(s)

def did_discover_characteristics(self, s, error):
if 'AA00' in s.uuid:
for c in s.characteristics:
if 'AA02' in c.uuid:
print('Enabling temperature sensor...')
self.peripheral.write_characteristic_value(c, chr(0x01), True)
elif 'AA01' in c.uuid:
# 启用温度传感器的通知:
print('Enabling temperature sensor notifications...')
self.peripheral.set_notify_value(c, True)
elif 'FFE0' in s.uuid:
print('Enabling notifications for Simple Key Service...')
key_characteristic = s.characteristics[0]
self.peripheral.set_notify_value(key_characteristic, True)

def did_write_value(self, c, error):
# 温度传感器已被激活 (参见 did_discover_characteristic)
print('Did enable temperature sensor')

def did_update_value(self, c, error):
if 'FFE1' == c.uuid:
# 当SensorTag上的一个按钮被按下(或者释放):
print('Button value: %s' % c.value.encode('hex'))
sound.play_effect('Beep')
else:
# 温度传感器发送了更新的数据:
tobj, mtmpamb = self.convert_temperature(c.value)
print('Object temperature: %f -- Ambient: %f' % (tobj, mtmpamb))

def convert_temperature(self, raw_data):
# 这将会将原生的传感器数据转换为摄氏度标准的温度数据.
# 该示例的算法细节并不重要, 你可以在SensorTag的用户手册上找到更多信息:
# http://processors.wiki.ti.com/index.php/SensorTag_User_Guide
rawT = struct.unpack('<h', raw_data[:2])[0]
tmpAmb = struct.unpack('<H', raw_data[2:])[0]
vobj2 = float(rawT) * 0.00000015625
mtmpamb = float(tmpAmb) / 128.0
tdie2 = mtmpamb + 273.15
s0, a1, a2 = 6.4E-14, 1.75E-3, -1.678E-5
b0, b1, b2, c2 = -2.94E-5, -5.7E-7, 4.63E-9, 13.4
Tref = 298.15
S = s0 * (1.0+a1*(tdie2 - Tref) + a2 * pow((tdie2 - Tref), 2))
vos = b0 + b1*(tdie2-Tref) + b2*pow((tdie2-Tref), 2)
fobj = (vobj2 - vos) + c2 * pow((vobj2 - vos), 2)
tobj = pow(pow(tdie2, 4) + (fobj/S), 0.25) - 273.15
return tobj, mtmpamb

delegate = MyCentralManagerDelegate()
print('Scanning for peripherals...')
cb.set_central_delegate(delegate)
cb.scan_for_peripherals()

# 保持连接活跃,直到“停止”按钮被按下:
try:
while True: pass
except KeyboardInterrupt:
# 断开所有连接:
cb.reset()

函数

cb.set_central_delegate(delegate)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class MyDelegate (object):
def did_update_state(self):
# 状态更新 (例如 蓝牙电源开/关)
pass

def did_discover_peripheral(self, p):
# 你一般会在此检查外设的 name/uuid 属性,
# 然后通过cb.connect_peripheral(p)进行连接.
# 你同样需要保持对 p 的引用 (例如 self.peripheral = p),
# 这样它就不会被垃圾回收.
# 注意对于同一外设这可能会被调用多次.
pass

def did_connect_peripheral(self, p):
# 你通常会在此调用 p.discover_services()
pass

def did_fail_to_connect_peripheral(self, p, error):
# `error` 是一个错误信息代码 (整数) 和描述 (字符串) 的元组
pass

def did_disconnect_peripheral(self, p, error):
# `error` 是一个错误信息代码 (整数) 和描述 (字符串) 的元组
pass

def did_discover_services(self, p, error):
# 你通常会在此对你感兴趣的服务调用 discover_characteristics
# .
pass

def did_discover_characteristics(self, s, error):
# 你可以读写特征的值
pass

def did_write_value(self, c, error):
pass

def did_update_value(self, c, error):
# 你可以通过 c.value 访问特征值
pass

cb.set_verbose(flag)
  设置为True时,所有回调事件都会记录到控制台,无论代理(请参阅set_central_delegate())是否实现了这些事件–这对于调试很有用。

cb.scan_for_peripherals()
  开始扫描广播服务的外围设备。

cb.stop_scan()
  停止扫描外围设备。

cb.connect_peripheral(peripheral)
  建立与外围设备的连接。通常,这将从您的did_discover_peripheral回调实现中调用。

cb.cancel_peripheral_connection(peripheral)
  取消与外围设备的活动或本地连接。

cb.get_state()
  返回中央管理器的当前状态(有关可能的值,请参见常量)

cb.reset()
  断开所有外围设备的连接。这还将中央代理设置为None,因此您将不再收到任何回调。


类

注意: 此模块中的类不能直接实例化。相反,你将获得不同类的实例作为代理实现的回调函数的参数(请参阅参考资料set_central_delegate())。


外设类

class cb.Peripheral
  Peripheral类表示已经通过scan_for_peripherals()被发现的外围设备。外围设备由通用唯一标识符(UUID)标识。外围设备可能包含一个或多个服务(由Service对象表示)。


外设类的方法

Peripheral.discover_services()
  发现外围设备的服务。发现完成后,中央代理将收到did_discover_services回调。

Peripheral.discover_characteristics(service)
  发现给定Service的特征。通常,这将从did_discover_services回调中调用。发现特征后,代理将收到did_discover_characteristics回调。

Peripheral.set_notify_value(characteristic, flag=True)
  启用或禁用给定Characteristic的通知(注意:并非所有特征都支持通知)。启用通知后,您可能会did_update_value在中央代理中收到did_update_value回调(请参阅参考资料set_central_delegate())。

Peripheral.write_characteristic_value(characteristic, data, with_response)
  写下Characteristic的值。数据应为字节字符串。with_response确定写入完成(或失败)后是否将调用did_write_value回调。请注意,并非所有特征都支持无响应的书写值。

Peripheral.read_characteristic_value(characteristic)
  检索给定Characteristic的值。读取值后,代理将收到一个did_update_value回调,此时您可以使用特征的value属性访问该值。并非所有特性都保证具有可读值。


外设类的属性

Peripheral.manufacturer_data
  制造商特定的数据,是外围设备广告数据的一部分。您可以在不连接外围设备的情况下(通常在did_discover_peripheral回调中)阅读此内容。

Peripheral.name
  外设的名称(字符串或None)

Peripheral.uuid
  外设的唯一标识符(十六进制字符串)

Peripheral.state
  外围设备的连接状态(0 =断开连接,1 =连接,2 =连接)

Peripheral.services
  外设的发现服务(Service对象列表)。请注意,在您成功调用Peripheral.discover_services()(并收到did_discover_services回调)之前,该字段通常为空。


服务类

class cb.Service
  Service对象代表一种Peripheral服务-用于完成设备(或设备的某些部分)功能或特性的数据和相关行为的集合。服务是主要的或辅助的,并且可能包含许多:Characteristic类。


服务类的属性

Service.characteristics
  服务的特征(如果尚未发现特征,则为空的Characteristic对象列表)

Service.primary
  指示服务是主服务还是辅助服务的布尔标志

Service.uuid
  服务的唯一标识符(十六进制字符串)


特征类

class cb.Characteristic
  Characteristic对象代表有关外围设备服务的更多信息。特征包含单个值。特性的属性决定了如何使用特性的值。


特征类的属性

Characteristic.uuid
  特征的唯一标识符(十六进制字符串)。

Characteristic.value
  特征的当前值(字节字符串,如果尚未读取或没有值,则为None)

Characteristic.notifying
  一个标志,用于确定是否为此特性启用了通知(只读,通过设置Peripheral.set_notify_value())

Characteristic.properties
  特征属性的位掩码(请参见下面的CH_PROP_*常量)


常量

get_state()可能的返回值:

cb.CM_STATE_UNKNOWN
cb.CM_STATE_RESETTING
cb.CM_STATE_UNSUPPORTED
cb.CM_STATE_UNAUTHORIZED
cb.CM_STATE_POWERED_OFF
cb.CM_STATE_POWERED_ON

特征属性 (注意: 这些值可以被组合为一个位掩码):

cb.CH_PROP_BROADCAST
cb.CH_PROP_READ
cb.CH_PROP_WRITE_WITHOUT_RESPONSE
cb.CH_PROP_WRITE
cb.CH_PROP_NOTIFY
cb.CH_PROP_INDICATE
cb.CH_PROP_AUTHENTICATED_SIGNED_WRITES
cb.CH_PROP_EXTENDED_PROPERTIES
cb.CH_PROP_NOTIFY_ENCRYPTION_REQUIRED
cb.CH_PROP_INDICATE_ENCRYPTION_REQUIRED

-------- 本文结束 感谢阅读 --------
相关文章
  • Pythonista中文文档:scene
  • Pythonista中文文档:contacts
  • Pythonista中文文档:canvas
  • Pythonista中文文档:photos
  • Pythonista中文文档:sound
觉得文章写的不错的话,请我喝瓶怡宝吧!😀
SiriYang 微信支付

微信支付

SiriYang 支付宝

支付宝

  • 本文标题: Pythonista中文文档:cb
  • 本文作者: SiriYang
  • 创建时间: 2020年04月13日 - 15时04分
  • 修改时间: 2021年10月29日 - 18时10分
  • 本文链接: https://blog.siriyang.cn/posts/20200413155027id.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
Python Pythonista 文档
Pythonista中文文档:scene
Pythonista中文文档:contacts
SiriYang

SiriYang

努力搬砖攒钱买镜头的摄影迷
318 日志
33 分类
88 标签
RSS
GitHub E-Mail
Creative Commons
Links
  • 友情链接
  • 作品商铺

蜀ICP备19008337号 © 2019 – 2025 SiriYang | 1.7m | 25:40
0%