更新时间:2024-06-24 03:25:06下载pdf
设备加入 Zigbee 网络后,网关会根据读取到的设备基础信息来识别一个设备。基础信息配置正确是网关能正确识别设备的前提。
在开发之前,您需要在工程文件中的 package.json
文件中配置好相关的基础信息。
package.json
{
"fimwareInfo": {
"name": "oem_si32_zg_xxxxxx", //固件名称
"description": "Zigbee device", //固件描述,用户自己填充
"version": "1.0.9", //固件版本号,
"bv_version": "1.0", //SDK版本号
"ic": "efr32mg13p732gm48", // Zigbee 芯片型号
"ota_image_type":"0x____", //OTA 升级识别使用,目前固定
"manufacture_id":"0x____", //OTA 升级识别使用,目前固定
"model_id":"XXXXXX", //设备组网快速识别设备类型使用
"pid": "XXXXXXXX", //设备默认产品 id,产品经理分配
"manufacture_name": "XXXXXXXXX" //产品id前缀,网关识别用什么协议来交互,
}
…
}
由 ZCL_CMD_RET_T dev_msg_recv_callback(dev_msg_t *dev_msg)
回调函数处理。设备接收到网关 ZCL 层命令后,可以解析命令后做出相应的处理。
例如,开关设备处理网关发送的开关指令的相关代码如下:
ZCL_CMD_RET_T dev_msg_recv_callback(dev_msg_t *dev_msg)
{
ZCL_CMD_RET_T result = ZCL_CMD_RET_SUCCESS;
switch (dev_msg->cluster)
{
case CLUSTER_PRIVATE_TUYA_CLUSTER_ID: //private data processing
{
break;
}
case CLUSTER_ON_OFF_CLUSTER_ID: //0x0006 Zigbee ON OFF Cluster //standard data processin
{
attr_value_t *attr_list = dev_msg->data.attr_data.attr_value;
uint8_t attr_sums = dev_msg->data.attr_data.attr_value_sums;
uint8_t i;
for(i = 0; i < attr_sums; i++)
{
switch(attr_list[i].cmd)
{
case CMD_OFF_COMMAND_ID: //关命令
{
__dev_switch_op(dev_msg->endpoint, DEV_IO_OFF); //控制硬件接口
__dev_report_onoff_msg(dev_msg->endpoint, QOS_0);//上报网关设备开关状态
break;
}
case CMD_ON_COMMAND_ID: //开命令
{
__dev_switch_op(dev_msg->endpoint, DEV_IO_ON);
__dev_report_onoff_msg(dev_msg->endpoint, QOS_0);
break;
}
case CMD_TOGGLE_COMMAND_ID: //反转命令
{
__dev_switch_op(dev_msg->endpoint, (DEV_IO_ST_T)!g_relay_onoff_status[dev_msg->endpoint - 1]);
__dev_report_onoff_msg(dev_msg->endpoint,QOS_0);
break;
}
default:
{
break;
}
}
break;
}
}
default:
// Unrecognized cluster ID, error status will apply.
break;
}
return result;
}
可以通过 dev_zigbee_send_data()
来发送数据到其他 Zigbee 设备。该函数数据参数赋值,可以参考 Zigbee SDK Demo 说明 中的使用方法。
例如,设备向网关发送的开关信息的相关代码如下:
static void __dev_report_onoff_msg(uint8_t endpoint, SEND_QOS_T qs)
{
dev_send_data_t send_data;
memset(&send_data, 0, sizeof(dev_send_data_t));
send_data.zcl_id = 0;
send_data.qos = qs; //重传类型
send_data.direction = ZCL_DATA_DIRECTION_SERVER_TO_CLIENT;//数据方向
send_data.command_id = CMD_REPORT_ATTRIBUTES_COMMAND_ID; //Report命令
send_data.addr.mode = SEND_MODE_GW; //上报给网关
send_data.addr.type.gw.cluster_id = CLUSTER_ON_OFF_CLUSTER_ID; //Cluster ID
send_data.addr.type.gw.src_ep = endpoint; //源端点号
send_data.delay_time = 0;
send_data.random_time = 0;
send_data.data.zg.attr_sum = 1; //上报的属性数量
send_data.data.zg.attr[0].attr_id = ATTR_ON_OFF_ATTRIBUTE_ID; //属性 ID
send_data.data.zg.attr[0].type = ATTR_BOOLEAN_ATTRIBUTE_TYPE; //属性值类型
send_data.data.zg.attr[0].value_size = 1; //数据大小
send_data.data.zg.attr[0].value[0] = g_relay_onoff_status[endpoint - 1]; //数据
dev_zigbee_send_data(&send_data, NULL, 1000); //发送Zigbee数据
__dev_status_save(endpoint); //保存属性
}
在上电初始化函数 dev_power_on_init()
中配置设备类型,具体配置方式可以参照对应的 Demo 工程。
例如:
开关(Switch)配置的 Router 节点类型:
zg_dev_config_t g_zg_dev_config;
g_zg_dev_config.dev_type = ZG_ROUTER; // 设置 Router 类型,常供电设备
g_zg_dev_config.config.router_cfg.reserved = 0;
dev_register_zg_dev_config(&g_zg_dev_config);
传感(Sensor)配置的 End device 节点类型:
// 配置低功耗设备类型,搜网参数,data poll 参数,重连参数
zg_dev_config_t st_zg_dev_config;
memset(&st_zg_dev_config, 0, sizeof(st_zg_dev_config));
// device type choice
st_zg_dev_config.dev_type = ZG_SLEEPY_END_DEVICE;
// 设置 End device 类型,低功耗设备
st_zg_dev_config.beacon_send_interval_for_join = CHANNEL_SW_PER_MS; // Channel switching period
st_zg_dev_config.zb_scan_duration = ZB_SCAN_DURATION_3; // RF rx open interval
st_zg_dev_config.beacon_send_interval_for_rejoin = BEACON_PER_MS; // rejoin beacon send interval
//配置 data poll 相关参数
// poll parameter registe
st_zg_dev_config.config.sleep_dev_cfg.poll_conifg.poll_interval = POLL_INTERVAL_MS;
st_zg_dev_config.config.sleep_dev_cfg.poll_conifg.wait_app_ack_time = WAIT_APP_ACK_MS;
st_zg_dev_config.config.sleep_dev_cfg.poll_conifg.poll_forever_flag = POLL_FOREVER;
st_zg_dev_config.config.sleep_dev_cfg.poll_conifg.poll_failed_times = POLL_MISS_MAX;
// 配置 rejion 相关参数
// rejoin parameter registe
st_zg_dev_config.config.sleep_dev_cfg.rejoin_config.next_rejoin_time = (NEXT_REJOIN_PER_HOUR*60*60*1000); // rejoin group interval
st_zg_dev_config.config.sleep_dev_cfg.rejoin_config.wake_up_time_after_join = JOINED_CONTINUE_POLL_TIME_MS; // continuous poll interval after joined
st_zg_dev_config.config.sleep_dev_cfg.rejoin_config.wake_up_time_after_rejoin = REJOINED_CONTINUE_POLL_TIME_MS; // continuous poll interval after rejoined
st_zg_dev_config.config.sleep_dev_cfg.rejoin_config.rejoin_try_times = BEACON_TIME; // try rejoin times
st_zg_dev_config.config.sleep_dev_cfg.rejoin_config.power_on_auto_rejoin_flag = POWER_ON_REJOIN;
st_zg_dev_config.config.sleep_dev_cfg.rejoin_config.auto_rejoin_send_data = AUTO_REJOIN_POLL;
dev_register_zg_dev_config(&st_zg_dev_config);
通过 dev_zigbee_join_start( )
函数搜索 Zigbee 网络。如果设备已经加入网络,该函数会退网并立即搜网。
设备如果要加入 Zigbee 网络,需要用户在应用上(例如 涂鸦智能 App)在 Zigbee 网关界面点击 添加子设备 ,并让设备进入搜网状态,设备入网后,会进入网络状态改变函数 nwk_state_changed_callback()
。
void nwk_state_changed_callback(NET_EVT_T state)
{
switch(state)
{
case NET_POWER_ON_LEAVE: // 上电检测到设备没有加入网络
{
break;
}
case NET_JOIN_START: //设备正在搜网
{
dev_led_start_blink(NET_LED_1_IO_INDEX, 250, 250, DEV_LED_BLINK_FOREVER, DEV_IO_OFF); //搜网时LED灯250ms间隔闪烁
break;
}
case NET_JOIN_TIMEOUT: //设备搜网超时
{
dev_led_stop_blink(NET_LED_1_IO_INDEX, DEV_IO_ON);
break;
}
case NET_POWER_ON_ONLINE: //上电检测到设备已加入网络
case NET_JOIN_OK: //设备入网
{
dev_led_stop_blink(NET_LED_1_IO_INDEX, DEV_IO_OFF);
break;
}
case NET_LOST: //End device 丢失父节点
{
break;
}
case NET_REMOTE_LEAVE: // APP 上删除设备
{
break;
}
case NET_LOCAL_LEAVE: // 设备本地退网
{
break;
}
default:
{
break;
}
}
}
涂鸦 Zigbee 模组 SDK 默认包含串口产测功能,使用的串口配置信息在 mf_test_uart_config()
函数中。
产测超时后,产测串口被禁用。如果用户需要使用串口,可以在 dev_system_on_init()
函数中进行初始化。
注意:不能在
dev_power_on_init()
函数中进行初始化。
// 串口初始化配置
user_uart_config_t uart_config = APP_UART_CONFIG_DEFAULT; // 默认配置,根据需要自己修改
uart_config.func = serial_rx_callback; // 串口接收回调函数
user_uart_init(&uart_config);
按键初始化函数 gpio_button_init()
一般在 dev_power_on_init()
函数中进行。请注意,按键初始化函数不要调用多次。一旦按键按下后,按键回调函数会周期性进入,可以根据传入的参数来判断短按,长按,松开。
如果不作为按键类型处理,可以使用中断初始化 gpio_int_register()
。
// 输入 IO 口中断方式初始化
void gpio_int_register(gpio_config_t *config, gpio_int_func_t func);
// 按键初始化
gpio_button_init((gpio_config_t *)gpio_input_config, get_array_len(gpio_input_config), 50, __dev_key_handle);
//处理按键的回调函数,按键有效会间隔 20 ms 进入该回调函数,直到按键被抬起
static void __dev_key_handle(uint32_t key_id, key_st_t key_st, uint32_t push_time)
{
uint8_t ep = 1;
if(EP_SUMS <= key_id)
{
return;
}
if(g_work_st == DEV_WORK_ST_TEST) // mf test mode
{
if(key_st != KEY_ST_PUSH)
{
dev_mf_button_test_notify(key_id); //按键产测上报
}
return;
}
switch(key_id)
{
case KEY_1_IO_INDEX: //按键 ID
{
if(key_st == KEY_ST_PUSH) //按键按下
{
}
else //按键松开
{
}
break;
}
default:
{
break;
}
}
}
通用 I/O 初始化函数一般在 dev_power_on_init()
中进行初始化。请注意不要调用多次。
//通用输出 IO 口初始化
gpio_output_init((gpio_config_t *)gpio_ouput_config, get_array_len(gpio_ouput_config));
//与之配套常用的数据 IO 口操作函数
//可以操作 IO 高低电平保持时间和次数,例如 LED 灯闪烁
void dev_led_start_blink(uint8_t led_index, uint16_t on_time, uint16_t off_time, uint16_t blink_times, DEV_IO_ST_T st);
//操作 IO 的输出开关状态,同时会停止对应 led_index 输出闪烁。
void dev_led_stop_blink(uint8_t led_index, DEV_IO_ST_T st);
SDK 底层已经对部分产测测试项进行过处理。例如,进入测试模式,读取 Mac,检测固件版本,写入 PID,读取 PID,进行 RF 测试,获取 RSSI 信号值,授权测试等。
您需要处理的内容可以在回调函数 dev_mf_test_callback()
中处理,串口产测和整机产测通用同一个处理方式。
MF_TEST_RET_T dev_mf_test_callback(MF_TEST_CMD_T cmd, uint8_t *args, uint16_t arg_len)
{
switch(cmd)
{
case MF_TEST_LED_ON_ALL: //所有 LED 灯开
{
dev_led_stop_blink(NET_LED_1_IO_INDEX, DEV_IO_ON);
dev_led_stop_blink(LED_1_IO_INDEX, DEV_IO_ON);
break;
}
case MF_TEST_LED_OFF_ALL: //所有 LED 灯关
{
dev_led_stop_blink(NET_LED_1_IO_INDEX, DEV_IO_OFF);
dev_led_stop_blink(LED_1_IO_INDEX, DEV_IO_OFF);
break;
}
case MF_TEST_LED_BLINK_ALL: //所有 LED 灯闪烁
{
dev_led_start_blink(NET_LED_1_IO_INDEX, 500, 500, 4, DEV_IO_OFF);
dev_led_start_blink(LED_1_IO_INDEX, 500, 500, 4, DEV_IO_OFF);
break;
}
case MF_TEST_RELAY_ON_ALL: //所有继电器开
{
dev_led_stop_blink(RELAY_1_IO_INDEX, DEV_IO_ON);
break;
}
case MF_TEST_RELAY_OFF_ALL: //所有继电器关
{
dev_led_stop_blink(RELAY_1_IO_INDEX, DEV_IO_OFF);
break;
}
case MF_TEST_RELAY_BLINK_ALL: //所有继电器周期开关
{
dev_led_start_blink(RELAY_1_IO_INDEX, 500, 500, 4, DEV_IO_OFF);
break;
}
case MF_TEST_BUTTON: //按键产测,APP 会等待按键按下
{
g_work_st = DEV_WORK_ST_TEST;
return MF_TEST_DOING; //等待测试
}
case MF_TRANSFER: //其他测试项可以通过这个项进行详细解析处理
{
break;
}
default :
{
break;
}
}
return MF_TEST_SUCCESS;
}
低功耗设备在进行网关产测时,需要在进入产测时,加快数据请求。您需要在 MF_TRANSFER
对应的 case
下进行以下处理。
typedef struct{
uint8_t test_cmd;
uint16_t test_data_len;
uint8_t test_data[128];
}dev_test_t;
...
case MF_TRANSFER: {
dev_test_t dev_test;
dev_test.test_cmd = args[0];
dev_test.test_data_len = arg_len;
if(arg_len > 1 && arg_len < 128)
{
memcpy(dev_test.test_data,&args[1],arg_len -1);
}
switch(dev_test.test_cmd) {
case MF_ENTER_TEST: //进入产测
{
zg_poll_interval_change(1000);
zg_poll_start(); //Start data request
break;
}
case MF_DIGIT_TEST: {
return MF_TEST_DOING;
break;
}
default : {
break;
}
}
break;
}
...
移动应用上配置添加场景时,会发送控制命令和添加场景命令给设备。第一条控制命令和最后的添加场景命令,会在 15s 内完成,收到添加场景命令后,设备需要保存 15s 内控制的设备的状态,以便在场景调用时使用。
// 收到添加场景命令后,会进入添加场景回调
void dev_scene_add_callback(uint8_t endpoint, uint8_t *out_data, uint8_t *in_out_len)
{
*in_out_len = 0;
out_data[(*in_out_len)++] = SceneOnOff_Flag; //如果设备 15s 内控制,该位是 TRUE
out_data[(*in_out_len)++] = Dev_onoff_status[endpoint-1]; //保存设备的状态
}
// 收到调用场景命令后,会进入调用场景回调
void dev_scene_recall_callback(uint8_t endpoint, const scene_save_data_t *in_data)
{
uint8_t dataOffset = 0;
switch(in_data->type) {
case SCENE_DATA_TYPE_USER_DEFINE: {
if(in_data->data[dataOffset] == SCENE_TRUE) //判断场景是否有效
{
Dev_OnOff_op(endpoint,in_data->data[dataOffset + 1],TRUE);//控制设备
}
break;
}
case SCENE_DATA_TYPE_SERVER_DEFINE: //根据服务器的配置格式解析
break;
case SCENE_DATA_TYPE_ZIGBEE_DEFINE: //根据 zigbee 标准协议格式解析
break;
default:
break;
}
}
Zigbee 模组 SDK 自带 OTA 升级功能。工程开发编译完成后,会生成后缀为 .s37
的烧录固件以及后缀为 .bin
的 OTA 升级固件。
设备可以通过网关升级固件版本。如果 OTA 版本固件比当前版本低或者一致,就不能进行升级。高版本固件上传到涂鸦开发者平台,可以给要升级的设备配置白名单进行升级,详情请参考 选择和管理固件版本。
对于 Router 节点(常供电设备),您不需要对 OTA 升级进行额外的开发。
对于 End device 节点(低功耗设备),因为低功耗设备长期进行休眠,关闭了接收 RF 数据能力,所以在移动应用上操作设备升级后,需要唤醒设备发送数据请求获取升级命令,并且设备需要在以下回调函数中处理相关逻辑:
// OTA 升级回调
void zg_ota_evt_callback(ZG_OTA_EVT_T evt)
{
switch(evt) {
case ZG_OTA_EVT_START: { //开始升级
zg_poll_interval_change( 250 ); // 配置数据请求间隔时间为 250ms,以加快升级。
zg_poll_start();
break;
}
default: {
zg_poll_interval_change( 1000 );
zg_poll_end(); // 升级完成后,停止数据请求,避免电量浪费。
break;
}
}
}
授权是产测中的其中一个测试项。涂鸦云模组烧录工具软件,以及 PCBA 产测软件都可以对模组进行授权。涂鸦云模组烧录工具进行烧录时,会自动对模组进行授权。只有对设备授权后,设备才能长期正常运行。
涂鸦 SDK 授权功能,已经在模组 SDK 内部实现,您无需开发。
说明:通过 J-Link 软件烧录的固件的设备,不能长期的运行,只能正常运行一周。固件开发好后,可以上传到涂鸦后台,进行云模组烧录工具进行授权。
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈