本文通过树莓派的蓝牙连接nrf52的蓝牙BLE外设,将蓝牙采集的信息同步到阿里云,实现一个类似外设+网关+服务器的物联网平台
1 启用阿里云物联网服务
登陆 https://iot.console.aliyun.com/product/createProduct ,
创建产品,当前我选择一个心率设备,用于采集心率信息
定义设备属性字段名称,标识符,类型和范围,此处的标识符和类型需要记录Heartbeat int32
管理添加设备
这里选择刚才创建的产品心率计
通过查看设备信息获取三元码,阿里的iot设备都是通过三元码作为产品ID,记录这3个信息
到此,阿里云的一个简单的iot平台搭建完成,下面开始pi4 访问服务器的操作
2 启用配置树莓派4,连接到服务器,本文使用MQTT方式联机到IOT
代码里面有2部分组成
1 树莓派通过bluepy连接一个nrf52的心电设备,改心电设备1秒上传一次心率值
2 树莓接受到BLE的心率值上传到服务器端
# -*- coding: utf-8 -*-
from bluepy.btle import UUID, Peripheral, ADDR_TYPE_RANDOM, DefaultDelegate
import paho.mqtt.client as mqtt
from bluepy.btle import Scanner, DefaultDelegate
import binascii
import time
import hashlib
import hmac
def write_uint16(data, value, index):
""" Write 16bit value into data string at index and return new string """
data = data.decode('utf-8') # This line is added to make sure both Python 2 and 3 works
return '{}{:02x}{:02x}{}'.format(
data[:index*4],
value & 0xFF, value >> 8,
data[index*4 + 4:])
def write_uint8(data, value, index):
""" Write 8bit value into data string at index and return new string """
data = data.decode('utf-8') # This line is added to make sure both Python 2 and 3 works
return '{}{:02x}{}'.format(
data[:index*2],
value,
data[index*2 + 2:])
# Please see # Ref https://nordicsemiconductor.github.io/Nordic-Thingy52-FW/documentation
# for more information on the UUIDs of the Services and Characteristics that are being used
def Nordic_UUID(val):
""" Adds base UUID and inserts value to return Nordic UUID """
return UUID("EF68%04X-9B35-4933-9B10-52FFA9740042" % val)
# Definition of all UUID used by Thingy
CCCD_UUID = 0x2902
HEARTRATE_SERVICE_UUID = 0x180D
HEARTRATE_CHAR_UUID = 0x2A37
#此处的3个信息就是前面在阿里云的三元组
options = {
'productKey':'a1loWX9eaVi',
'deviceName':'heartbeat1',
'deviceSecret':'bDIOOsJHWWyh40ZckZiDqbWxIBAA3geN',
'regionId':'cn-shanghai'
}
HOST = options['productKey'] + '.iot-as-mqtt.'+options['regionId']+'.aliyuncs.com'
PORT = 1883
PUB_TOPIC = "/sys/" + options['productKey'] + "/" + options['deviceName'] + "/thing/event/property/post";
#此处是蓝牙相关的服务
class HeartRateService():
"""
Environment service module. Instance the class and enable to get access to the Environment interface.
"""
# serviceUUID = Nordic_UUID(HEARTRATE_SERVICE_UUID)
# heartrate_char_uuid = Nordic_UUID(HEARTRATE_CHAR_UUID)
serviceUUID = HEARTRATE_SERVICE_UUID
heartrate_char_uuid = HEARTRATE_CHAR_UUID
def __init__(self, periph):
self.periph = periph
self.heartrate_service = None
self.heartrate_char = None
self.heartrate_cccd = None
self.config_char = None
def enable(self):
""" Enables the class by finding the service and its characteristics. """
global e_heartrate_handle
if self.heartrate_service is None:
self.heartrate_service = self.periph.getServiceByUUID(self.serviceUUID)
if self.heartrate_char is None:
self.heartrate_char = self.heartrate_service.getCharacteristics(self.heartrate_char)[0]
e_heartrate_handle = self.heartrate_char.getHandle()
self.heartrate_cccd = self.heartrate_char.getDescriptors(forUUID=CCCD_UUID)[0]
def set_heartrate_notification(self, state):
if self.heartrate_cccd is not None:
if state == True:
self.heartrate_cccd.write(b"\x01\x00", True)
else:
self.heartrate_cccd.write(b"\x00\x00", True)
def configure(self, heart_int=None):
if heart_int is not None and self.config_char is not None:
current_config = binascii.b2a_hex(self.config_char.read())
new_config = write_uint16(current_config, heart_int, 0)
self.config_char.write(binascii.a2b_hex(new_config), True)
def disable(self):
set_heartrate_notification(False)
class MyDelegate(DefaultDelegate):
def handleNotification(self, hnd, data):
# Debug print repr(data)
if (hnd == e_heartrate_handle):
heartheart = binascii.b2a_hex(data)
print('Notification: heartheart received: {}.{}'.format(
self._str_to_int(heartheart[:-2]), int(heartheart[-2:], 16)))
payload_json = {
'id': int(time.time()),
#这里的信息是阿里云上的
'params': {
'Heartbeat': int(heartheart[-2:], 16),
},
'method': "thing.event.property.post"
}
print('send data to iot server: ' + str(payload_json))
client.publish(PUB_TOPIC,payload=str(payload_json),qos=1)
else:
teptep = binascii.b2a_hex(data)
print('Notification: UNKOWN: hnd {}, data {}'.format(hnd, teptep))
def _str_to_int(self, s):
""" Transform hex str into int. """
i = int(s, 16)
if i >= 2 ** 7:
i -= 2 ** 8
return i
class HeartRate(Peripheral):
"""
Thingy:52 module. Instance the class and enable to get access to the Thingy:52 Sensors.
The addr of your device has to be know, or can be found by using the hcitool command line
tool, for example. Call "> sudo hcitool lescan" and your Thingy's address should show up.
"""
def __init__(self, addr):
Peripheral.__init__(self, addr)
self.m_Heart = HeartRateService(self)
# DFU Service not implemented
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
# client.subscribe("the/topic")
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
print(msg.topic+" "+str(msg.payload))
def hmacsha1(key, msg):
return hmac.new(key.encode(), msg.encode(), hashlib.sha1).hexdigest()
def getAliyunIoTClient():
timestamp = str(int(time.time()))
CLIENT_ID = "paho.py|securemode=3,signmethod=hmacsha1,timestamp="+timestamp+"|"
CONTENT_STR_FORMAT = "clientIdpaho.pydeviceName"+options['deviceName']+"productKey"+options['productKey']+"timestamp"+timestamp
# set username/password.
USER_NAME = options['deviceName']+"&"+options['productKey']
PWD = hmacsha1(options['deviceSecret'],CONTENT_STR_FORMAT)
client = mqtt.Client(client_id=CLIENT_ID, clean_session=False)
client.username_pw_set(USER_NAME, PWD)
return client
class ScanDelegate(DefaultDelegate):
def __init__(self):
DefaultDelegate.__init__(self)
def handleDiscovery(self, dev, isNewDev, isNewData):
if isNewDev:
print ("Discovered device %s" % (dev.addr))
elif isNewData:
print ("Received new data from %s" % (dev.addr))
if __name__ == '__main__':
client = getAliyunIoTClient()
client.on_connect = on_connect
client.on_message = on_message
client.connect(HOST, 1883, 300)
client.loop_start()
scanner = Scanner().withDelegate(ScanDelegate())
devices = scanner.scan(5.0)
device_msg = [0,0]
found = 0
for dev in devices:
print ("Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi))
for (adtype, desc, value) in dev.getScanData():
print (" %s = %s" % (desc, value))
for (adtype, desc, value) in dev.getScanData():
res = value.find("blehr_sensor")
if res < 0:
None
else:
found = 1
device_msg[1] = dev.addrType
device_msg[0] = dev.addr
print("%s %s %s" % (device_msg[0], value, device_msg[1]))
break
if found:
break
if found:
print('Connecting to ' + device_msg[0])
heart = HeartRate(device_msg[0])
print('Connected...')
heart.setDelegate(MyDelegate())
try:
print('Enabling selected HeartRate...')
heart.m_Heart.enable()
heart.m_Heart.configure(heart_int=1000)
heart.m_Heart.set_heartrate_notification(True)
time.sleep(1.0)
# counter=1
while True:
heart.waitForNotifications(0)
finally:
heart.disconnect()
print('DisConnected...')
# del heart
每一秒树莓派接受到BLE心电的数据(这里模拟的是一个每秒递增1的数据),并上传到服务器