本文主要是天猫蓝牙Mesh项目——初级开发 设备接入天猫精灵 的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows版本 | windows11 |
Ubuntu版本 | Ubuntu22.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
终端软件 | MobaXterm(Professional Edition v23.0 Build 5042 (license)) |
点击查看本文参考资料
点击查看相关文件下载
这一LV的笔记起始跟前面有所重叠,互相补充吧算是。
一、创建风扇控制工程
(1)复制key_fan工程,更名为fan_node。
(2)修改fan_node.mk文件,工程和文件名,并开启天猫精灵认证宏和厂商模型服务。
1 2 3
| GLOBAL_DEFINES += GENIE_OLD_AUTH MESH_MODEL_VENDOR_SRV = 1
|
(3)配置天猫精灵三元组信息。
在 genie-bt-mesh-stack-master/genie_app/base/tri_tuple_default.h 文件中。
1 2 3
| #define DEFAULT_PID 18662569 #define DEFAULT_SECRET "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" #define DEFAULT_MAC "xxxxxxxxxxxx"
|
二、初始化流程代码分析
1. 函数调用关系
2. 配网信息广播包
2.1 UUID格式
下面这个表在AliGenie开发者平台 (tmall.com)——天猫精灵蓝牙mesh软件基础规范的3.2.1 mesh广播包一节,新的文档中也有,只是有些许不同,但大概都是一个意思,新的文档在这里:蓝牙Mesh模组软件规范——UUID格式-生活物联网平台(飞燕平台)-阿里云帮助中心 (aliyun.com)
2.2 代码中组合UUID
下面两个函数都位于genie_app/base/tri_tuple.c中:
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
| int8_t genie_tri_tuple_load(void) { char l_mac[] = DEFAULT_MAC; char l_key[] = DEFAULT_SECRET; E_GENIE_FLASH_ERRCODE ret; ret = genie_flash_read_trituple(&g_pid, g_mac, g_key);
if(ret != GENIE_FLASH_SUCCESS) { BT_ERR("read error, use default"); g_pid = DEFAULT_PID; stringtohex(l_key, g_key, 16); stringtohex(l_mac, g_mac, 6); return -1; }
return 0; }
uint8_t *genie_tri_tuple_get_uuid(void) { int i;
g_uuid[0] = 0xa8; g_uuid[1] = 0x01;
g_uuid[2] = 0x71;
for (i = 0; i < 4; i++) { g_uuid[3 + i] = (g_pid >> (i<<3)) & 0xFF; }
for (i = 0; i < 6; i++) { g_uuid[7 + i] = g_mac[5 - i]; }
g_uuid[13] = UNPROV_ADV_FEATURE_AUTO_BIND_MODEL_SUB;
g_uuid[14] = UNPROV_ADV_FLAG_GENIE_MESH_STACK; #ifdef GENIE_ULTRA_PROV g_uuid[14] |= UNPROV_ADV_FEATURE_ULTRA_PROV; #endif BT_INFO("uuid: %s", bt_hex(g_uuid, 16));
return g_uuid; }
|
3. 成分数据
3.1 成分数据包格式
3.2 代码实现
成分数据注册是在network/bluetooth/bt_mesh/src/main.c的bt_mesh_init()函数中:
4. 元素封装
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
| #define MESH_ELEM_COUNT 1 #define MESH_ELEM_STATE_COUNT MESH_ELEM_COUNT
elem_state_t g_elem_state[MESH_ELEM_STATE_COUNT];
static struct bt_mesh_model element_models[] = { BT_MESH_MODEL_CFG_SRV(), BT_MESH_MODEL_HEALTH_SRV(),
#ifdef CONFIG_MESH_MODEL_GEN_ONOFF_SRV MESH_MODEL_GEN_ONOFF_SRV(&g_elem_state[0]), #endif };
static struct bt_mesh_model g_element_vendor_models[] = {
#ifdef CONFIG_MESH_MODEL_VENDOR_SRV MESH_MODEL_VENDOR_SRV(&g_elem_state[0]), #endif };
struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, element_models, g_element_vendor_models, 0), };
|
三、代码实现
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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
| static float last_speed = 0.0;
static uint8_t vendor_fan_ctrl(vnd_model_msg *p_msg) { float speed = 0.0; if(p_msg == NULL) { printf("p_msg 错误\r\n"); goto error; } if(p_msg->len == 3) { if(p_msg->data[0] == 0x21 && p_msg->data[1] == 0x05) { if(p_msg->data[2] == 0) current_status = FOREWARD; else if(p_msg->data[2] == 1) current_status = REVERSAL;
fan_ctrl(current_status,current_speed);
} else if(p_msg->data[0] == 0x0A && p_msg->data[1] == 0x01) { speed = ((float)p_msg->data[2]) / 10; fan_ctrl(current_status,speed); } else { printf("属性类型不支持\r\n"); goto error; }
} else if(p_msg->len == 5) { if(p_msg->data[0] == 0x0B && p_msg->data[1] == 0xF0) { if(p_msg->data[2] == 0x0A && p_msg->data[3] == 0x01) { speed = current_speed; if(p_msg->data[4] == 0x01) { speed += 0.1; if(speed > 1) speed = 1; } else if(p_msg->data[4] == 0xFF) { speed -= 0.1; if(speed < 0) speed = 0; } else goto error;
fan_ctrl(current_status,speed); } } else goto error; } return 0;
error: return 1;
}
static uint8_t vendor_fan_status_send(void) { vnd_model_msg reply_msg; uint8_t payload[3] = {0}; static uint8_t tid = 0; uint16_t attr_type = SPEED_TYPE;
payload[0] = attr_type & 0xff; payload[1] = (attr_type >> 8) & 0xff; payload[2] = (uint8_t)(current_speed*10);
reply_msg.opid = VENDOR_OP_ATTR_STATUS; reply_msg.tid = tid++; reply_msg.data = payload; reply_msg.len = sizeof(payload); reply_msg.p_elem = &elements[0]; reply_msg.retry_period = 120 + 300; reply_msg.retry = 1;
genie_vendor_model_msg_send(&reply_msg);
printf("发送风扇风速 = %u tid = %u\r\n",payload[2],reply_msg.tid);
}
u16_t vendor_model_msg_handle(vnd_model_msg *p_msg) { printk("vendor model message received\n"); if (!p_msg) return -1;
printf("opcode:0x%x, tid:%d, len:%d\r\n", p_msg->opid, p_msg->tid, p_msg->len); if (p_msg->data && p_msg->len) printk("payload: %s", bt_hex(p_msg->data, p_msg->len));
switch (p_msg->opid) { case VENDOR_OP_ATTR_GET_STATUS:
printf("获得属性状态\r\n"); break; case VENDOR_OP_ATTR_SET_ACK:
printf("设置属性状态需应答\r\n"); if(vendor_fan_ctrl(p_msg) == 0) { printf("设置成功\r\n"); genie_vendor_model_msg_send(p_msg); }
break; case VENDOR_OP_ATTR_SET_UNACK: printf("设置属性状态不需应答\r\n"); break; case VENDOR_OP_ATTR_CONFIME:
break; case VENDOR_OP_ATTR_TRANS_MSG: break; default: break; }
return 0; }
void user_event(E_GENIE_EVENT event, void *p_arg) { E_GENIE_EVENT next_event = event;
switch(event) { case GENIE_EVT_SW_RESET: case GENIE_EVT_HW_RESET_START: BT_DBG("FLASH x5"); led_flash(5); reset_light_para(); break; case GENIE_EVT_SDK_MESH_INIT: user_init(); if (!genie_reset_get_flag()) { next_event = GENIE_EVT_SDK_ANALYZE_MSG; } break; case GENIE_EVT_SDK_MESH_PROV_SUCCESS: BT_DBG("FLASH x3"); led_flash(3); break; case GENIE_EVT_SDK_ACTION_DONE: { elem_state_t *p_elem = (elem_state_t *)p_arg; #if defined(CONFIG_MESH_MODEL_GEN_ONOFF_SRV) if(p_elem->state.onoff[0] == 0) { fan_ctrl(current_status,0.0); last_speed = current_speed; printf("关闭风扇\r\n"); } else if(p_elem->state.onoff[0] == 1) { fan_ctrl(current_status,last_speed); printf("开启风扇\r\n"); } #endif break; } #ifdef CONFIG_MESH_MODEL_VENDOR_SRV case GENIE_EVT_SDK_INDICATE: break; case GENIE_EVT_SDK_VENDOR_MSG: { printf("进入到厂商消息\r\n"); vendor_model_msg_handle((vnd_model_msg *)p_arg); break; } #endif case GENIE_EVT_HW_RESET_DONE: printk("GENIE_EVT_HW_RESET_DONE\n"); break; default: break; } if(next_event != event) { genie_event(next_event, p_arg); } }
|