阿里云&天猫精灵实战
经言,望而知之谓之神,闻而知之谓之圣,问而知之谓之工,切脉而知之谓之巧。
阿里云创建产品
- 创建项目
- 在已创项目里创建产品
- 产品功能定义
在此仅展示简单的开关控制风扇,各位可以根据自己喜好加别的。
- 设备调试
人机交互步骤根据自己喜好设置,没有什么特殊要求。在设备调试页面下,新增测试设备然后点击查看设备证书,里边就是所需的设备的三元组。
获取到三元组之后我们就可以开始写自己的代码程序了。
编写代码
tasks.json
在成员里添加以下代码,先前一篇文章里编译生成.bin文件的命名处提及的是my_led,可以对比体会一下。
{
"label": "fan",
"type": "shell",
"command": "aos",
"args": [
"make",
"bluetooth.fan@tc825x"
],
"group": "build",
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
}
完整的内容如下:
{
"version": "2.0.0",
"tasks": [
{
"label": "tc825x",
"type": "shell",
"command": "aos",
"args": [
"make",
"bluetooth.light_ctl@tc825x"
],
"group": "build",
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
},
{
"label": "my_led",
"type": "shell",
"command": "aos",
"args": [
"make",
"bluetooth.my_led@tc825x"
],
"group": "build",
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
},
{
"label": "fan",
"type": "shell",
"command": "aos",
"args": [
"make",
"bluetooth.fan@tc825x"
],
"group": "build",
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
},
{
"label": "max",
"type": "shell",
"command": "aos",
"args": [
"make",
"bluetooth.max@tc825x"
],
"group": "build",
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
}
]
}
上边的是tasks.json,下边的是settings.json
{
"search.exclude": { //表示搜索区域
"**/platform/mcu/[a-s]*": true, //[a-s]* 表示a到s字符开头的全部屏蔽,数值也一样,自行体验
"**/board/bk3435devkit": true,
"**/board/pca10040": true,
"**/board/ch6121evb": true,
"**/board/tg7100b": true,
},
"files.exclude": { //表示显示区域
"**/.git": true, //true标识改目录不被显示
"**/.g**": true, //*号标识通配符,.g开头的均屏蔽,根据用途自行配置,多多尝试
"**/platform/mcu/[a-s]*": true, //[a-s]* 表示a到s字符开头的全部屏蔽,数值也一样,自行体验
"**/board/bk3435devkit": true,
"**/board/pca10040": true,
"**/board/ch6121evb": true,
"**/board/tg7100b": true,
},
"files.associations": {
"gpio_8258.h": "c"
},
"C_Cpp.errorSquiggles": "Disabled"
}
创建mk文件
复制一份light_ctl的mk文件来修改即可
这时候就会出现以下这个选项,后续编写好c文件后点击此项编译生成bin文件。
mk文件内容如下:
NAME := fan
GENIE_MAKE_PATH := app/example/bluetooth/$(NAME)
$(NAME)_COMPONENTS += genie_app bluetooth.bt_host bluetooth.bt_mesh yloop cli
$(NAME)_INCLUDES += ../ \
../../../../genie_app \
../../../../genie_app/base \
../../../../genie_app/bluetooth/host \
../../../../genie_app/bluetooth/mesh
$(NAME)_SOURCES := fan.c
ble = 1
bt_mesh = 1
en_bt_smp = 1
bt_host_tinycrypt = 1
# Host configurations
GLOBAL_DEFINES += CONFIG_BLUETOOTH
GLOBAL_DEFINES += CONFIG_BT_CONN
#GLOBAL_DEFINES += CONFIG_BT_CENTRAL
GLOBAL_DEFINES += CONFIG_BT_PERIPHERAL
#GLOBAL_DEFINES += CONFIG_BLE_50
# Mesh function select
GLOBAL_DEFINES += CONFIG_BT_MESH
GLOBAL_DEFINES += CONFIG_BT_MESH_PROV
GLOBAL_DEFINES += CONFIG_BT_MESH_PB_ADV
GLOBAL_DEFINES += CONFIG_BT_MESH_PB_GATT
GLOBAL_DEFINES += CONFIG_BT_MESH_PROXY
GLOBAL_DEFINES += CONFIG_BT_MESH_GATT_PROXY
GLOBAL_DEFINES += CONFIG_BT_MESH_RELAY
#GLOBAL_DEFINES += CONFIG_BT_MESH_FRIEND
#GLOBAL_DEFINES += CONFIG_BT_MESH_LOW_POWER
#GLOBAL_DEFINES += CONFIG_BT_MESH_SHELL
# Mesh foundation model select
GLOBAL_DEFINES += CONFIG_BT_MESH_CFG_SRV
GLOBAL_DEFINES += CONFIG_BT_MESH_HEALTH_SRV
MESH_MODEL_GEN_ONOFF_SRV = 1
#MESH_MODEL_DIABLE_TRANS = 1
MESH_MODEL_LIGHTNESS_SRV = 1
MESH_MODEL_CTL_SRV = 1
MESH_MODEL_VENDOR_SRV = 1
ALI_SIMPLE_MODLE = 1
GLOBAL_DEFINES += CONFIG_BT_DEVICE_NAME=\"light\"
GLOBAL_DEFINES += PROJECT_SW_VERSION=0x00010102
GLOBAL_DEFINES += PROJECT_SECRET_KEY=\"00112233445566770011223344556677\"
# Feature configurations
GLOBAL_DEFINES += GENIE_OLD_AUTH
GLOBAL_DEFINES += CONIFG_OLD_FLASH_PARA
#GLOBAL_DEFINES += GENIE_ULTRA_PROV
genie_ota = 1
#genie_vendor_timer = 1
# Host configurations
GLOBAL_DEFINES += CONFIG_BT_SMP
GLOBAL_DEFINES += CONFIG_BT_HCI_VS_EXT
GLOBAL_DEFINES += CONFIG_BT_RX_BUF_LEN=151
GLOBAL_DEFINES += CONFIG_BT_L2CAP_TX_MTU=143
# project configurations
#GLOBAL_DEFINES += CONIFG_LIGHT_HONGYAN
genie_vendor_timer = 0
tc825x_debug_mode = 1
GLOBAL_DEFINES += CONFIG_BT_DEBUG_LOG
ifeq ($(tc825x_debug_mode),1)
GLOBAL_DEFINES += CONFIG_GENIE_DEBUG_CMD
############### debug ###############
## BLE debug log general control macro (Note: still to be affected by DEBUG)
## Enable below macros if BLE stack debug needed
# Mesh debug message enable
GLOBAL_DEFINES += GENIE_DEBUG_COLOR
GLOBAL_DEFINES += MESH_DEBUG_RX
GLOBAL_DEFINES += MESH_DEBUG_TX
GLOBAL_DEFINES += MESH_DEBUG_PROV
#GLOBAL_DEFINES += CONFIG_INIT_STACKS
#GLOBAL_DEFINES += CONFIG_PRINTK
## BLE subsystem debug log control macro
## Enable below macros if component-specific debug needed
#GLOBAL_DEFINES += CONFIG_BT_DEBUG_L2CAP
#GLOBAL_DEFINES += CONFIG_BT_DEBUG_CONN
#GLOBAL_DEFINES += CONFIG_BT_DEBUG_ATT
#GLOBAL_DEFINES += CONFIG_BT_DEBUG_GATT
#GLOBAL_DEFINES += CONFIG_BT_DEBUG_HCI_DRIVER
#GLOBAL_DEFINES += CONFIG_BT_DEBUG_HCI_CORE
#GLOBAL_DEFINES += CONFIG_BT_DEBUG_CORE
## MESH debug log control macro
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_ADV
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_BEACON
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_PROXY
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_PROV
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_NET
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_CRYPTO
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_TRANS
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_FRIEND
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_LOW_POWER
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_ACCESS
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_FLASH
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_MODEL
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_VENDOR_MODEL
#GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_FACTORY
GLOBAL_DEFINES += CONFIG_BT_MESH_DEBUG_OTA
else
GLOBAL_DEFINES += CONFIG_INFO_DISABLE
endif
编写fan.c文件(重点)
内容比较简单,初始化PB4引脚,通过该引脚的电平高低来实现风扇开关
然后配置组播地址,设置通用开关模型
接着就是user_event部分了,这部分参照genie_event来自定义,在天猫精灵成功触发的地方添加自己的事件
完整代码:
#include "drivers/8258/gpio_8258.h"
#include "vendor/common/alios_app_config.h"
#include "common/log.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <aos/aos.h>
#include <aos/kernel.h>
#include <misc/printk.h>
#include <misc/byteorder.h>
#include <hal/soc/gpio.h>
#include <bluetooth.h>
#include <soc.h>
#include <api/mesh.h>
#include "genie_app.h"
// #ifndef CONFIG_INFO_DISABLE
// #define LIGHT_DBG(fmt, ...) printf("[%s]"fmt"\n", __func__, ##__VA_ARGS__)
// #else
// #define LIGHT_DBG(fmt, ...)
// #endif
// #define LIGHT_CTL_TEMP_MIN (0x0320) // 800
// #define LIGHT_CTL_TEMP_MAX (0x4E20) // 20000
// #define LED_FLASH_CYCLE MESH_TRNSATION_CYCLE
#define FAN_GPIO TC825X_GET_PIN_NUM(GPIO_PB4)
gpio_dev_t fan_gpio;
//配置初始化引脚
void my_fan_init(void)
{
fan_gpio.config = OUTPUT_PUSH_PULL;
fan_gpio.port = FAN_GPIO;
hal_gpio_init(&fan_gpio);
}
void fan_gpio_on(void)
{
hal_gpio_output_high(&fan_gpio);
}
void fan_gpio_off(void)
{
hal_gpio_output_low(&fan_gpio);
}
/* unprovision device beacon adv time */
#define MESH_PBADV_TIME 600 //unit:s
#define DEFAULT_MESH_GROUP1 0xC007
#define DEFAULT_MESH_GROUP2 0xCFFF
uint32_t get_mesh_pbadv_time(void)
{
return MESH_PBADV_TIME * 1000; //ms
}
/* element configuration start */
#define MESH_ELEM_COUNT 1
#define MESH_ELEM_STATE_COUNT MESH_ELEM_COUNT
elem_state_t g_elem_state[MESH_ELEM_STATE_COUNT];
model_powerup_t g_powerup[MESH_ELEM_STATE_COUNT];
static struct bt_mesh_model element_models[] = {
BT_MESH_MODEL_CFG_SRV(),
BT_MESH_MODEL_HEALTH_SRV(),
/*代码添加*/
MESH_MODEL_GEN_ONOFF_SRV(&g_elem_state[0]), //通用开关模型
};
static struct bt_mesh_model g_element_vendor_models[] = {
MESH_MODEL_VENDOR_SRV(&g_elem_state[0]), //厂商自定义模型
};
struct bt_mesh_elem elements[] = {
BT_MESH_ELEM(0, element_models, g_element_vendor_models, 0),
};
uint8_t get_vendor_element_num(void)
{
return MESH_ELEM_COUNT;
}
/* element configuration end */
void mesh_sub_init(u16_t *p_sub)
{
memset(p_sub, 0, CONFIG_BT_MESH_MODEL_GROUP_COUNT << 1);
p_sub[0] = DEFAULT_MESH_GROUP1;
p_sub[1] = DEFAULT_MESH_GROUP2;
}
#ifdef CONFIG_GENIE_OTA
bool ota_check_reboot(void)
{
// the device will reboot when it is off
if (g_elem_state[0].state.onoff[T_CUR] == 0)
{
// save light para, always off
g_powerup[0].last_onoff = 0;
genie_flash_write_userdata(GFI_MESH_POWERUP, (uint8_t *)g_powerup, sizeof(g_powerup));
BT_DBG("reboot!");
return true;
}
BT_DBG("no reboot!");
return false;
}
#endif
static void _init_fan_para(void)
{
uint8_t i = 0;
E_GENIE_FLASH_ERRCODE ret;
// init element state
memset(g_elem_state, 0, sizeof(g_elem_state));
elem_state_init(MESH_ELEM_STATE_COUNT, g_elem_state);
// load light para
ret = genie_flash_read_userdata(GFI_MESH_POWERUP, (uint8_t *)g_powerup, sizeof(g_powerup));
if (ret == GENIE_FLASH_SUCCESS)
{
while (i < MESH_ELEM_STATE_COUNT)
{
#ifdef CONFIG_GENIE_OTA
// if the device reboot by ota, it must be off.
if (g_powerup[0].last_onoff == 0)
{
g_elem_state[0].state.onoff[T_TAR] = 0;
// load lightness
if (g_powerup[0].last_actual)
{
g_elem_state[0].state.actual[T_TAR] = g_powerup[0].last_actual;
g_elem_state[0].powerup.last_actual = g_powerup[0].last_actual;
}
// load temperature
if (g_powerup[0].last_temp)
{
g_elem_state[0].state.temp[T_TAR] = g_powerup[0].last_temp;
g_elem_state[0].powerup.last_temp = g_powerup[0].last_temp;
}
clear_trans_para(&g_elem_state[0]);
}
else
#endif
{
memcpy(&g_elem_state[0].powerup, &g_powerup[0], sizeof(model_powerup_t));
// load lightness
if (g_powerup[0].last_actual)
{
g_elem_state[0].state.actual[T_TAR] = g_powerup[0].last_actual;
}
// load temperature
if (g_powerup[0].last_temp)
{
g_elem_state[0].state.temp[T_TAR] = g_powerup[0].last_temp;
}
//LIGHT_DBG("l:%d t:%d", g_powerup[0].last_actual, g_powerup[0].last_temp);
if (g_elem_state[0].state.onoff[T_TAR] == 1)
{
g_elem_state[0].state.trans_start_time = k_uptime_get() + g_elem_state[0].state.delay * 5;
g_elem_state[0].state.trans_end_time = g_elem_state[0].state.trans_start_time + get_transition_time(g_elem_state[0].state.trans);
}
}
g_elem_state[0].state.temp[T_CUR] = g_elem_state[0].state.temp[T_TAR];
i++;
}
}
}
static void _reset_fan_para(void)
{
uint8_t i = 0;
while (i < MESH_ELEM_STATE_COUNT)
{
g_elem_state[i].state.onoff[T_CUR] = GEN_ONOFF_DEFAULT;
g_elem_state[i].state.actual[T_CUR] = LIGHTNESS_DEFAULT;
g_elem_state[i].state.temp[T_CUR] = CTL_TEMP_DEFAULT;
g_elem_state[i].state.onoff[T_TAR] = GEN_ONOFF_DEFAULT;
g_elem_state[i].state.actual[T_TAR] = LIGHTNESS_DEFAULT;
g_elem_state[i].state.temp[T_TAR] = CTL_TEMP_DEFAULT;
g_elem_state[i].state.trans = 0;
g_elem_state[i].state.delay = 0;
g_elem_state[i].state.trans_start_time = 0;
g_elem_state[i].state.trans_end_time = 0;
g_elem_state[i].powerup.last_actual = LIGHTNESS_DEFAULT;
g_elem_state[i].powerup.last_temp = CTL_TEMP_DEFAULT;
g_powerup[i].last_onoff = GEN_ONOFF_DEFAULT;
g_powerup[i].last_actual = LIGHTNESS_DEFAULT;
g_powerup[i].last_temp = CTL_TEMP_DEFAULT;
i++;
}
genie_flash_write_userdata(GFI_MESH_POWERUP, (uint8_t *)g_powerup, sizeof(g_powerup));
//LIGHT_DBG("done");
}
static void _save_light_state(elem_state_t *p_elem)
{
uint8_t *p_read = aos_malloc(sizeof(g_powerup));
if (p_elem->state.actual[T_CUR] != 0)
{
p_elem->powerup.last_actual = p_elem->state.actual[T_CUR];
g_powerup[p_elem->elem_index].last_actual = p_elem->state.actual[T_CUR];
}
p_elem->powerup.last_temp = p_elem->state.temp[T_CUR];
g_powerup[p_elem->elem_index].last_temp = p_elem->state.temp[T_CUR];
// always on
g_powerup[p_elem->elem_index].last_onoff = 1;
genie_flash_read_userdata(GFI_MESH_POWERUP, p_read, sizeof(g_powerup));
if (memcmp(g_powerup, p_read, sizeof(g_powerup)))
{
LIGHT_DBG("save %d %d", g_powerup[p_elem->elem_index].last_actual, g_powerup[p_elem->elem_index].last_temp);
genie_flash_write_userdata(GFI_MESH_POWERUP, (uint8_t *)g_powerup, sizeof(g_powerup));
}
aos_free(p_read);
}
static void _user_init(void)
{
my_fan_init(); //初始化
fan_gpio_off(); //初始化时灯灭
#ifdef CONFIG_GENIE_OTA
// check ota flag
if (ais_get_ota_indicat())
{
g_indication_flag |= INDICATION_FLAG_VERSION;
}
#endif
}
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:
break;
case GENIE_EVT_HW_RESET_DONE:
_reset_fan_para();
break;
case GENIE_EVT_SDK_MESH_INIT:
_init_fan_para();
_user_init();
if (!genie_reset_get_flag())
{
next_event = GENIE_EVT_SDK_ANALYZE_MSG;
}
break;
case GENIE_EVT_SDK_MESH_PROV_SUCCESS:
break;
case GENIE_EVT_SDK_TRANS_CYCLE:
case GENIE_EVT_SDK_ACTION_DONE:
{
//添加自己事件
printf("GENIE_EVT_SDK_ACTION_DONE \r\n");
elem_state_t *user_state = (elem_state_t *)p_arg; //获取状态,把user_event参数 p_arg 传进来
/********通用开关********/
if (user_state->state.onoff[TYPE_NUM]) //elem_state_t->model_state_t->onoff[TYPE_NUM],0关闭1打开
{
fan_gpio_on();
}
else
{
fan_gpio_off();
}
}
break;
case GENIE_EVT_SDK_INDICATE:
break;
case GENIE_EVT_SDK_VENDOR_MSG:
printf("GENIE_EVT_SDK_VENDOR_MSG \r\n");
{
vnd_model_msg *my_vnd_msg = (vnd_model_msg *)p_arg;
printf("opcode = %x\r\n", my_vnd_msg->opid);
int i = 0;
for (; i < my_vnd_msg->len; i++)
{
printf("%x ", my_vnd_msg->data[i]);
}
}
break;
default:
break;
}
if (next_event != event)
{
genie_event(next_event, p_arg);
}
}
int application_start(int argc, char **argv)
{
genie_init();
return 0;
}
编译
烧录
找到生成的bin文件烧录即可