LV03-04-天猫蓝牙Mesh开发-06-厂商模型的使用

本文主要是天猫蓝牙Mesh开发——厂商模型的使用的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows版本 windows11
Ubuntu版本 Ubuntu22.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license))
点击查看本文参考资料
分类 网址 说明
官方网站 阿里云 阿里云官网主页
阿里生活物联平台 生活物联网平台(飞燕平台)主页
AliGenie 天猫精灵开放平台AliGenie主页
阿里物联网平台 阿里物联网平台主页
Bluetooth 技术网站 蓝牙协议规范什么的可以来这里找
Telink Telink | Chips for a Smarter IoT (telink-semi.com)
Telink中文官网
开发手册 AliOS Things开发指南 AliOS Things开发指南,这里是最新版本,可以直接从官网找到
AliOS Things开发指南 AliOS Things应用开发指南,这里应该是3.3版本的完整开发文档
AliOS Things开发指南(3.0) AliOS Things应用开发指南,这里应该是3.0版本的完整开发文档
生活物联网平台开发文档 生活物联网平台(飞燕平台)开发文档
《设备端开发指南》
Wi-Fi IoT品类定义与功能开发 天猫精灵IoT开放平台——Wi-Fi IoT品类定义与功能开发
硬件平台 mk3080 WiFi开发板 WiFi开发板使用指南-阿里云开发者社区
esp8266开发板 一个教程:ESP8266-NodeMCU开发板详解-太极创客 (taichi-maker.com)
TLSR8258 Datasheet Datasheet for Telink BLE + IEEE802.15.4 MultiStandard Wireless SoC TLSR8258
参考资料 AliOS Things 3.0 应用开发指南 这个只是一篇参考文章,里面是一些环境搭建相关的,可以参考
IP知识百科 - 华为 (huawei.com) IP的一些相关知识点
点击查看相关文件下载
分类 网址 说明
蓝牙规范相关文档 Core Specification 5.2 核心规格 5.2,该规范定义了创建可互操作的Bluetooth 设备所需的技术。
《Core_v5.2.pdf》
Mesh Model(v1.1) 本Bluetooth 规范定义了模型(以及它们所需的状态和消息),这些模型用于在mesh 网络中的节点上执行基本功能,超出了Bluetooth Mesh 配置文件 规范中定义的基础模型。
本规范包括定义跨设备类型标准功能的通用模型,以及支持关键mesh 场景的模型,如照明控制、传感器、时间和场景。
《MshMDL_v1.1.pdf》
Mesh Profile(v1.0.1) 该Bluetooth 规范定义了基本要求,以实现可互操作的mesh 网络解决方案,用于Bluetooth 低能量无线技术。
《MshPRFv1.0.1.pdf》
Mesh Device Properties 本规范包含Bluetooth Mesh 配置文件 和Bluetooth Mesh 模型规范所要求的设备属性的定义。
但是跟之前的有些区别,我主要看的之前的版本:《MMeshDeviceProperties_v1.2.pdf》
GATT Specification Supplement GATT Specification Supplement | Bluetooth® Technology Website。
好像可以在线看:《GATT Specification Supplement》
Assigned Numbers GATT的一些类型定义可以在这里找。
AliOS Things alios-things/AliOS-Things Gitee上的AliOSThings SDK源码仓库
alibaba/AliOS-Things GitHub上的AliOSThings SDK源码仓库
天猫精灵蓝牙Mesh协议栈 alibaba-archive/genie-bt-mesh-stack GitHub上的天猫精灵蓝牙Mesh协议栈源码仓库。
之前是在alibaba/genie-bt-mesh-stack这个仓库。
写笔记的时候最新提交为faf523618a6a2560090fc423222b9db80984bb7a
蓝牙Mesh设备开发指南 阿里云生活服务平台开发手册——蓝牙设备开发一节中的内容

前面我们都是使用的通用模型,或者说是阿里云支持的一些模型,那么我们有时候想要一些特殊的,通用模型里面没有的,这个时候就要用到厂商模型啦。这一小节我们来使用厂商模型做一个灯的颜色控制实验。

一、服务平台配置

1. 新增颜色属性

我们首先在产品管理 - 生活物联网平台 (aliyun.com)——功能定义中新增一个颜色的属性:

image-20231227234054871

2. 更换设备面板

然后我们来更换个面板,让它有颜色可以选:产品管理 - 生活物联网平台 (aliyun.com)——设备面板

image-20231227234327568

我们进入编辑面板,然后改成下面这样:

image-20231227234722598

然后我们点击保存即可,回到设备面板,会看到面板已经发生了改变:

image-20231227234819115

这里虽然改变了,但是有可能在手机天猫精灵app不生效,我就暂时没管了,后来我使用的是语音调试的。

3. 在线调试

我们可以在产品管理 - 生活物联网平台 (aliyun.com)——设备调试进行在线调试:

image-20231228075534522

然后我们会看来到这个界面:

image-20231228075734459

二、工程修改

我们会发现,在SDK中没有颜色模型,我们这个时候就需要为元素添加厂商模型啦。

1. 添加厂商模型

我们打开app/example/bluetooth/light_ctl_demo/light_ctl_demo.c,其实demo中之前是直接有的,要是没有的话,在以下两个地方添加:

image-20231228075004789

2. 添加厂商模型事件处理

在user_event中添加:

image-20231228075107764

三、实验现象

1. 下发指令

我们连接好天猫精灵,用语音或者在线调试,这里贴一张在线语音调试的图:

image-20231228075937358

2. 串口信息

比如我们下把灯调成蓝色,然后串口就会有以下打印信息:

image-20231228224729207

3. 打印信息分析

1
2
3
4
5
6
7
8
9
10
>>>>            [RX][MESH]
>>>> [RX][MESH] SRC: 0xCE
>>>> [RX][MESH] DST: 0x1E1B
>>>> [RX][MESH] OPCODE: 0xD101A8
>>>> [RX][MESH] Payload size: 9
>>>> [RX][MESH] 55 23 01 00 80 AA AA FF FF
[095230]<V> opcode:0xd1, tid:85, len:8
++++++++++ GENIE_EVT_SDK_VENDOR_MSG! ++++++++++
opid 0xd1
data 0x23 0x1 0x0 0x80 0xaa 0xaa 0xff 0xff

3.1 OPCODE

从这里可以看到这里有一个OPCODE值为0xD101A8,我们来看一下这是啥意思,我们看官方手册的这一节蓝牙Mesh设备扩展协议——扩展消息操作码-生活物联网平台(飞燕平台)-阿里云帮助中心 (aliyun.com)

image-20231228225119902

根据这里的规则可以知道,后面的01A8表示的是阿里巴巴的Company ID,这个操作码代表的含义在蓝牙Mesh设备扩展协议——操作码定义-生活物联网平台(飞燕平台)-阿里云帮助中心 (aliyun.com)

image-20231228224459403

那第一个D1代表什么?我没在文档中找到,但是代码中有定义,我们这样找:

image-20231228231701523

3.2 data

接下来我们来看看我们收到的这串数据:

1
data 0x23 0x1 0x0 0x80 0xaa 0xaa 0xff 0xff

我们知道这个数据是厂商模型的数据,我们先来看一下这个厂商模型操作码对应的数据结构蓝牙Mesh设备扩展协议——_Vendor Model属性消息结构 -生活物联网平台(飞燕平台)-阿里云帮助中心 (aliyun.com)

image-20231228232050741

可以看到,前面会有两个字节的Attribute Type ,后面都是Attribute Parameter了,再加上手册中有说明Vendor message里的数据都使用小端优先方式传输,所以前面的2个字节正确的顺序应该是0x0123,后面的一堆才是数据,我们来看一下0x0123是代表设备什么属性,我们打开蓝牙设备属性表-生活物联网平台(飞燕平台)-阿里云帮助中心 (aliyun.com),找到0x0123:

image-20231228232441884

如上图,这个属性是一个uint16类型的数组,它有三个元素,其中的Color[0]= Lightness Color[1] = Hue Color[2] = Saturation

uint16是两个字节共16位,所以按照这个规则,上面的组合后含义如下:

1
2
3
Color[0] = Lightness  = 0x8000 = 32768 # 明度
Color[1] = Hue = 0xaaaa = 43690 # 色相
Color[2] = Saturation = 0xffff = 65535 # 饱和度

我们在对应一下阿里云生活服务平台的设备属性(产品管理 - 生活物联网平台 (aliyun.com)——功能定义):

image-20231228233144666

可以看到之类Attr Type也确实是0x0123,上面的颜色值为十进制,我们转化为十六进制:

1
2
3
4
5
6
7
黑色 0         = 0x0000 0000
蓝色 255 = 0x0000 00FF
绿色 65280 = 0x0000 FF00
青色 65535 = 0x0000 FFFF
红色 16711680 = 0x00FF 0000
黄色 16776960 = 0x00FF FF00
白色 16777215 = 0x00FF FFFF

我们前面下发的是将灯调整成蓝色的指令,所以理论上来讲,这里下发的值应该是0x0000 00FF才对,它转化为HSL为(240,100,50)转化为十六进制就是(0xF0,0x64,0x32),看起来似乎跟打印的数值没有任何关系。我们来分析一波:

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
# 这是上面的原始打印信息
data 0x23 0x01 0x00 0x80 0x00 0x00 0xff 0xff 红色
data 0x23 0x01 0x00 0x80 0x55 0x55 0xff 0xff 绿色
data 0x23 0x01 0x00 0x80 0xaa 0xaa 0xff 0xff 蓝色
data 0x23 0x01 0xff 0xff 0x00 0x00 0x00 0x00 白色
data 0x23 0x01 0x00 0x00 0x00 0x00 0x00 0x00 黑色
data 0x23 0x01 0x00 0x80 0x00 0x80 0xff 0xff 青色
data 0x23 0x01 0x00 0x80 0xaa 0x2a 0xff 0xff 黄色
# 这是重新组合的数据
明度 色相 饱和度
data 0x01 0x23 0x8000 0x0000 0xffff 红色
data 0x01 0x23 0x8000 0x5555 0xffff 绿色
data 0x01 0x23 0x8000 0xaaaa 0xffff 蓝色
data 0x01 0x23 0xffff 0x0000 0x0000 白色
data 0x01 0x23 0x0000 0x0000 0x0000 黑色
data 0x01 0x23 0x8000 0x8000 0xffff 青色
data 0x01 0x23 0x8000 0x2aaa 0xffff 黄色
# 我们根据色相来排个序
明度 色相 饱和度
data 0x01 0x23 0x8000 0x0000 0xffff 红色
data 0x01 0x23 0x8000 0x2aaa 0xffff 黄色
data 0x01 0x23 0x8000 0x5555 0xffff 绿色
data 0x01 0x23 0x8000 0x8000 0xffff 青色
data 0x01 0x23 0x8000 0xaaaa 0xffff 蓝色
data 0x01 0x23 0xffff 0x0000 0x0000 白色
data 0x01 0x23 0x0000 0x0000 0x0000 黑色

我们再看一下HSL的含义:

Hue 叫色相,表示了颜色在色环上的角度。纯红色位于 0 度,纯绿色位于 120 度,纯蓝色位于 240 度。Lightness 叫亮度。Saturation 叫饱和度。可以看出,除了白色和黑色,剩下的明度和饱和度都一样,我们主要看色相,我们来看一张色相环:

184FE704-702B-4276-8CEF-82AA1A6B3675

我们来计猜测下,上面色相的十六进制与色相是什么关系,我们知道色相是360度,而uint16最大值为FFFF也就是65535,我们用上面的数值除以65535,然后再乘以360,看一下得到的色相与色相环是否对应?

1
2
3
4
5
红色 (0/65535)*360=0
黄色 (10922/65535)*360=60.382
绿色 (21845/65535)*360=120
青色 (32768/65535)*360=180.002
......

所以基本可以得出,色相就是这样换算成十六进制数的,这样就与HSL中的颜色也是一一对应,其实我也没搞明白为啥这里要用HSL来表示颜色,反正知道中间的转换关系就可以了。综上所述,颜色与下发的值是如下对应关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
data [0]  [1]  [2]  [3]  [4]  [5]  [6]  [7]
data 0x23 0x01 0x00 0x80 0x00 0x00 0xff 0xff # 红色
data 0x23 0x01 0x00 0x80 0x55 0x55 0xff 0xff # 绿色
data 0x23 0x01 0x00 0x80 0xaa 0xaa 0xff 0xff # 蓝色
data 0x23 0x01 0xff 0xff 0x00 0x00 0x00 0x00 # 白色
data 0x23 0x01 0x00 0x00 0x00 0x00 0x00 0x00 # 黑色
data 0x23 0x01 0x00 0x80 0x00 0x80 0xff 0xff # 青色
data 0x23 0x01 0x00 0x80 0xaa 0x2a 0xff 0xff # 黄色

# 重新组合的数据如下
明度 色相 饱和度
data [0] [1] [3][2] [5][4] [7][6]
data 0x01 0x23 0x8000 0x0000 0xffff # 红色
data 0x01 0x23 0x8000 0x5555 0xffff # 绿色
data 0x01 0x23 0x8000 0xaaaa 0xffff # 蓝色
data 0x01 0x23 0xffff 0x0000 0x0000 # 白色
data 0x01 0x23 0x0000 0x0000 0x0000 # 黑色
data 0x01 0x23 0x8000 0x8000 0xffff # 青色
data 0x01 0x23 0x8000 0x2aaa 0xffff # 黄色

这样我们就可以根据这些值来区分不同的颜色啦。

四、厂商模型事件上报

我们写完上面的代码,会发现,我们无法通过询问天猫精灵获取灯的状态,这是因为我们没有对灯的一些状态进行上报,这里我们以颜色为例,了解一下如何上报。

1. 厂商模型的数据上报

我们先看一下些代码:

image-20231230205001133

我么来看一下这个VENDOR_OP_ATTR_INDICATE,在代码中它定义如下:

1
#define VENDOR_OP_ATTR_INDICATE          0xD4

我们来这里搜索一下0xD4表示什么:什么是蓝牙Mesh设备扩展协议_生活物联网平台(飞燕平台)-阿里云帮助中心 (aliyun.com)

image-20231230205541219

我们再往下找一个这个属性的格式:

image-20231230205610119

2. 模仿写一个上报的函数

这里只写一个框架,这里处理完灯的颜色之后,直接进行一次颜色上报。

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

void vnd_model_recv(vnd_model_msg *p_vnd_msg)
{
int i = 0;
uint16_t light = 0;
uint16_t hue = 0;
uint16_t saturation = 0;
uint16_t type = 0;

vnd_model_msg reply_msg = {0};
uint8_t seg_count = 0;

if(p_vnd_msg == NULL)
{
printf("p_vnd_msg is NULL!\r\n");
return;
}
printf("opid 0x%x vnd_msg len=%d\r\n", p_vnd_msg->opid, p_vnd_msg->len);
printf("data ");
for (; i < p_vnd_msg->len; i++)
{
printf("0x%x ", p_vnd_msg->data[i]);
}
printf("\r\n");

type |= p_vnd_msg->data[1];
type <<= 8;
type |= p_vnd_msg->data[0];

switch(type)
{
case 0x0123:
light |= p_vnd_msg->data[3];
light <<= 8;
light |= p_vnd_msg->data[2];

hue |= p_vnd_msg->data[5];
hue <<= 8;
hue |= p_vnd_msg->data[4];

saturation |= p_vnd_msg->data[7];
saturation <<= 8;
saturation |= p_vnd_msg->data[6];

analize_color(light, hue, saturation);
break;
default:
break;
}

seg_count = get_seg_count(p_vnd_msg->len + 4);
reply_msg.opid = VENDOR_OP_ATTR_INDICATE;
reply_msg.tid = vendor_model_msg_gen_tid();
reply_msg.data = p_vnd_msg->data;
reply_msg.len = p_vnd_msg->len;
reply_msg.p_elem = &elements[0];
reply_msg.retry_period = 125 * seg_count + 400;
reply_msg.retry = VENDOR_MODEL_MSG_DFT_RETRY_TIMES;
genie_vendor_model_msg_send(&reply_msg);
return;

}