当前文档版本为 v0.5.0,您可以访问当前页面的 开发中 版本以获取最近可能的更新。

Bluetooth: IoT WeChat

1 功能概述

AirSync是微信硬件平台提供的一种微信客户端与蓝牙设备间通讯的技术协议,它允许蓝牙设备与微信客户端之间收发数据,并支持通过微信客户端透传到远程服务器。该技术在支持微信互联的蓝牙手环、血压计、智能秤、血糖仪等设备上有比较多的应用。

AirSync主要在如下场景中使用:

  • 蓝牙设备与微信客户端间数据收发,如手环、血压计发送运动健康数据到微信客户端。

  • 蓝牙设备与远端服务器收发数据,如获取微信运动排行榜名次,接收设备消息等。

协议架构图如下,其中厂商服务器和外设,由厂商开发完成。微信会提供服务器的接口以对接厂商的服务器,会提供手机的接口(规定的蓝牙协议)以对接厂商的外设,而实际上微信只是数据的中转站,用于厂商服务器与设备之间的数据传递。:

image

微信 AirSync 协议架构

本例程包含AirSync协议的全部功能,通过微信硬件平台的官网提供的AirSyncDebugger APP测试该例程的功能是否符合协议规范。

2 环境要求

  • board: pan108xxb5_evb

  • uart (option): 显示串口log

  • 测试软件: AirSyncDebugger

3 编译和烧录

例程位置:zephyr\samples_panchip\bluetooth\iot_wechat

使用 ZAL 工具可以对其进行编译、烧录、打开 VS Code 调试等操作。关于 ZAL 工具的详细介绍请参考:Zephyr APP Launcher 工具介绍

4 演示说明

  1. PAN1080 EVB板上电后BLE的广播名字是ble_wechat,用AirSyncDebugger APP可以扫描到对应的设备。

  2. 在APP上点击设备,点击AirSync协议就可以进入测试模式,测试分为手动测试和自动测试。

  3. 手动测试过程中第四步需要按下PAN1080 EVB上的K1按键方可完成测试,自动测试可以自己完成测试无需在测试过程中手动参与。

  4. 测试都通过后就可以和微信公众号进行连接了。

    Note:AirSyncDebugger APP的使用可参考“微信蓝牙协议调试工具AirSyncDebugger说明文档 v2.0”。

5 补充说明

5.1 广播包格式

蓝牙外设广播的目的是让手机微信能够识别到。微信AirSync协议是这样规定蓝牙外设广播数据格式的:

  • WeChat primary service UUID:0xFEE7。

    Service UUID:0x03+0x03+0xFEE7(WeChat primary service UUID)

  • 在自定义厂商数据manufature specific data中需以MAC地址(身份注册时的MAC地址,也是该设备真实的MAC地址)结尾,并且要求manufature specific data的长度大于等于8。

    Customer specification:0x09+0xFF+0x6101(BLE core vendor)+设备MAC地址

广播包对应的数组如下:

static const struct bt_data ad[] = {
	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
	BT_DATA_BYTES(BT_DATA_MANUFACTURER_DATA, 0x01,0x61,0xbb,0xaa,0x11,0x20,0x00,0x01),
	BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0xE7, 0xFE),
};

static const struct bt_data sd[] = {
	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};

5.2 GATT Service

微信蓝牙服务使用自定义的GATT Service,如下:

Service Attribute

UUID

Primary service

0xFEE7(经蓝牙官方授权)

Write characteristic declaration

0xFEC7

Read characteristic declaration

0xFEC9

Indication characteristic declaration

0xFEC8

Indication characteristic configuration

0x2902

源码如下:

BT_GATT_SERVICE_DEFINE(proj_wechat,
BT_GATT_PRIMARY_SERVICE(BT_UUID_DECLARE_16(BLE_UUID_WECHAT_SERVICE)),
		       BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_16(BLE_UUID_WECHAT_WRITE_CHARACTERISTICS),
					      BT_GATT_CHRC_WRITE,
					      BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
					      NULL, write_value_cb, cts_data),
		       BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_16(BLE_UUID_WECHAT_READ_CHARACTERISTICS),
					      BT_GATT_CHRC_READ,
					      BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
					      read_value_cb, NULL, stc_data),
		       BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_16(BLE_UUID_WECHAT_INDICATE_CHARACTERISTICS),
					      BT_GATT_CHRC_INDICATE,
					      BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
					      NULL, NULL, temp_data),
		       BT_GATT_CCC(ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
					);

满足广播包和Profile两个条件代表已经能够跟手机微信进行数据通信了。但是交互过程是一个协作的过程,就像我们访问业务系统一样也要先登陆,再初始化后,才能进行正常的业务通信。那么登陆和初始化我们可以理解为应用控制信令,而后续的数据通信也是应用数据通信。

5.3 Airsync协议

Demo例程中是通过嵌入的data_handler结构体实现对于不同事件的处理。

事件主要分成三大类:

  • 上电初始化

  • 微信BLE设备与微信公众号的连接

  • 微信BLE设备与微信公众号的交互

data_handler结构体主要包括以下内容:

data_handler mpbledemo2_data_handler =
{
    .m_product_type              = PRODUCT_TYPE_MPBLEDEMO2,				//产品类型码
    .m_data_produce_func         = &mpbledemo2_data_produce_func,		//打包要发送的数据
    .m_data_free_func            = &mpbledemo2_data_free_func,			//释放申请的内存
    .m_data_consume_func         = &mpbledemo2_data_consume_func,		//处理收到的数据包
    .m_data_error_func           = &mpbledemo2_data_error_func,			//错误处理函数
    .m_data_init_peripheral_func = &mpbledemo2_init_peripheral_func,  	//外设初始化
    .m_data_init_func            = &mpbledemo2_init,      				//demo 初始化
    .m_data_main_process_func    = &mpbledemo2_main_process,    		//连接微信公众号
    .m_data_button_handler_func  = &mpbledemo2_button_handler,			//按键事件处理
    .m_data_produce_args         = &m_info,								//发送数据的context
    .next                        = NULL
};
  1. 连接微信

    连接微信的Auth和Init请求处理都是在mpbledemo2_main_process接口函数中进行的,接口如下:

    void mpbledemo2_main_process()
    {
    	int error_code = 0;
    	if((mpbledemo2Sta.indication_state) && (!mpbledemo2Sta.auth_state) && (!mpbledemo2Sta.auth_send) )
    	{
    		error_code = device_auth();
            if (0 == error_code)
            {
                mpbledemo2Sta.auth_send = true;
            }
    	}
    	if((mpbledemo2Sta.auth_state) && (!mpbledemo2Sta.init_state) && (!mpbledemo2Sta.init_send))
    	{
    		error_code = device_init();
            if (0 == error_code)
            {
                mpbledemo2Sta.init_send = true;
            }
    	}
    }
    

    先进行device_auth然后再进行device_init。

  2. 与微信数据交互

    • 微信发数据到设备

      设备端接收数据的接口如下:

      int mpbledemo2_data_consume_func(uint8_t *data, uint32_t len)
      {
      		BpFixHead *fix_head = (BpFixHead *)data;
      		uint8_t fix_head_len = sizeof(BpFixHead);
      		#ifdef CATCH_LOG
      		arch_printf("\r\n##Received data: ");
      		uint8_t *d = data;
      		for(uint8_t i=0;i<len;++i){
      		arch_printf(" %x",d[i]);}
      		arch_printf("\r\n CMDID: %d", ntohs(fix_head->nCmdId));
      		arch_printf("\r\n len: %d", ntohs(fix_head->nLength));
      		arch_printf("\r\n Seq: %d",ntohs(fix_head->nSeq));
      		#endif
      		switch(ntohs(fix_head->nCmdId))
      		{
      			case ECI_none:
      				{
      				}
      				break;
      			.
      			.
      			.
      		}
      		return 0;
      }
      

      设备端判断不同的”cmdid”做相应的处理。

    • 设备发送数据到微信

      按下开发板的K1按键,设备端将数据发送到微信上。

      发送数据的接口如下:

      // send data to wechat server
      int32_t mpbledemo2_sendData(uint8_t* ptrData, uint32_t lengthInByte)
      {
          uint8_t *data = NULL;
      	uint32_t len = 0;
      	ARGS_ITEM_SET(mpbledemo2_info, m_mpbledemo2_handler->m_data_produce_args, cmd, CMD_SENDDAT);
      	ARGS_ITEM_SET(mpbledemo2_info, m_mpbledemo2_handler->m_data_produce_args, send_msg.len, lengthInByte);
      	ARGS_ITEM_SET(mpbledemo2_info, m_mpbledemo2_handler->m_data_produce_args, send_msg.str, (const char *)ptrData);
      
      	m_mpbledemo2_handler->m_data_produce_func(m_mpbledemo2_handler->m_data_produce_args, &data, &len);
      	if(data == NULL)
      	{
      		return errorCodeProduce;
      	}
      	ble_wechat_indicate_data(data, len);
          return 0;
      }
      

      Demo是将”Hello, WeChat!”发送到公众号上。微信公众号的ID和BLE设备ID都是在”mpbledemo2.h”文件中修改。

6 RAM/Flash资源使用情况

Memory region         Used Size  Region Size  %age Used
FLASH:      219012 B      1020 KB     20.97%
SRAM:       29052 B        52 KB     54.56%
IDT_LIST:          0 GB         2 KB      0.00%