Zigbee SDK FAQ

Last Updated on : 2022-02-23 06:44:20download

How does a Zigbee gateway identify a device

After a device is connected to the Zigbee network, the gateway will identify the device based on the basic device information read. The correct configuration of basic information is a premise for the gateway to correctly identify the device.

Before development, you need to configure the basic information in the package.json file under the project file.

package.json { "fimwareInfo": { "name": "oem_si32_zg_xxxxxx", // Firmware name "description": "Zigbee device", // The user must complete the firmware description "version": "1.0.9", // The version of the firmware, "bv_version": "1.0", // The version of the SDK "ic": "efr32mg13p732gm48", // The model of the Zigbee chip "ota_image_type":"0x____", // It is used for OTA update identification and is fixed for now. "manufacture_id":"0x____", // It is used for OTA update identification and is fixed for now. "model_id": "XXXXXX", // It is used for the device to quickly identify the device type during networking. "pid": "XXXXXXXX", // Default product ID, which is assigned by the product manager. "manufacture_name": "XXXXXXXXX" // Product ID prefix, which is used by the gateway to determine the interaction protocol. } … }

Which function will process the command that the device receives from the gateway?

It will be processed by the callback function ZCL_CMD_RET_T dev_msg_recv_callback(dev_msg_t *dev_msg). After receiving the command from the gateway ZCL layer, the device will parse the command and process it accordingly.

For example, the code for the switch device to process the on/off command sent by the gateway is as follows:

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 processing { 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: // Off command { __dev_switch_op(dev_msg->endpoint, DEV_IO_OFF); // Hardware control API __dev_report_onoff_msg(dev_msg->endpoint, QOS_0);// Report the on/off status of the gateway break; } case CMD_ON_COMMAND_ID: // On command { __dev_switch_op(dev_msg->endpoint, DEV_IO_ON); __dev_report_onoff_msg(dev_msg->endpoint, QOS_0); break; } case CMD_TOGGLE_COMMAND_ID: // Toggle command { __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, and an error status will apply break; } return result; }

How does a device send data to other Zigbee devices?

The data can be sent by the function dev_zigbee_send_data() to other Zigbee devices. For parameter assignment in the function, see the Zigbee SDK Demo Guide.

For example, the code of the on/off information sent by the device to the gateway is as follows:

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; // Retransmission type send_data.direction = ZCL_DATA_DIRECTION_SERVER_TO_CLIENT;// Data direction send_data.command_id = CMD_REPORT_ATTRIBUTES_COMMAND_ID; // Report command send_data.addr.mode = SEND_MODE_GW; // Report to the gateway send_data.addr.type.gw.cluster_id = CLUSTER_ON_OFF_CLUSTER_ID; //Cluster ID send_data.addr.type.gw.src_ep = endpoint; // Source endpoint number send_data.delay_time = 0; send_data.random_time = 0; send_data.data.zg.attr_sum = 1; // The number of attributes reported send_data.data.zg.attr[0].attr_id = ATTR_ON_OFF_ATTRIBUTE_ID; // Attribute ID send_data.data.zg.attr[0].type = ATTR_BOOLEAN_ATTRIBUTE_TYPE; // Attribute value type send_data.data.zg.attr[0].value_size = 1; // Data zize send_data.data.zg.attr[0].value[0] = g_relay_onoff_status[endpoint - 1]; // Data dev_zigbee_send_data(&send_data, NULL, 1000); // Send Zigbee data __dev_status_save(endpoint); // Save the attribute }

How to configure the router device and the end device?

Configure the device type in the power-on initialization function dev_power_on_init(). See the corresponding demo project for specific configuration mode.

For example:

  • Router node type of the switch:

    zg_dev_config_t g_zg_dev_config; g_zg_dev_config.dev_type = ZG_ROUTER; // Configure the router as the uninterruptible power supply (UPS) device. g_zg_dev_config.config.router_cfg.reserved = 0; dev_register_zg_dev_config(&g_zg_dev_config);
  • End device node type of the sensor:

    // Configure the low power device type, search parameter, data poll parameter, and relink parameter. zg_dev_config_t st_zg_dev_config; memset(&st_zg_dev_config, 0, sizeof(st_zg_dev_config)); // Select device type st_zg_dev_config.dev_type = ZG_SLEEPY_END_DEVICE; // Configure the end device as a low power 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 sending interval // Configure the data poll parameter // Poll parameter register 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; // Configure the rejoin parameters // Rejoin parameter register 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; // Rejoin attempts 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);

How does the device search for and connect to the Zigbee network?

Search for the Zigbee network through the function dev_zigbee_join_start( ). If the device is already connected to the network, the function will exit the network and start searching immediately.

In order to connect to the Zigbee network, tap the Add a sub-device on the Zigbee gateway interface in the app (For example Tuya Smart app) and make the device start searching. After the device is connected, the network status changing function nwk_state_changed_callback() will be called.

void nwk_state_changed_callback(NET_EVT_T state) { switch(state) { case NET_POWER_ON_LEAVE: // After power-on, it is detected that the device is not connected. { break; } case NET_JOIN_START: // Searching. { dev_led_start_blink(NET_LED_1_IO_INDEX, 250, 250, DEV_LED_BLINK_FOREVER, DEV_IO_OFF); // The LED flickers at an interval of 250 ms while searching. break; } case NET_JOIN_TIMEOUT: // Searching timeout { dev_led_stop_blink(NET_LED_1_IO_INDEX, DEV_IO_ON); break; } case NET_POWER_ON_ONLINE: // After power-on, it is detected that the device is connected. case NET_JOIN_OK: // The device is connected. { dev_led_stop_blink(NET_LED_1_IO_INDEX, DEV_IO_OFF); break; } case NET_LOST: // The parent node of the end device is lost. { break; } case NET_REMOTE_LEAVE: // Remove the device from the app. { break; } case NET_LOCAL_LEAVE: // The device exits the network. { break; } default: { break; } } }

Things to note while initializing serial port

The SDK of the Tuya Zigbee module includes the function of the serial port production test by default, and the configuration information of the serial port is in the function mf_test_uart_config().

When the production test timed out, the production test serial port will be disabled. You can initialize the serial port in the function dev_system_on_init().

Note: Don’t initialize in the function dev_power_on_init().

// Initialization configuration of the serial port user_uart_config_t uart_config = APP_UART_CONFIG_DEFAULT; // Default configuration. Modify as needed. uart_config.func = serial_rx_callback; // The serial port receives callback functions. user_uart_init(&uart_config);

How to use the general purpose I/O?

The button initialization function gpio_button_init() generally runs in the function dev_power_on_init(). Note that the button initialization function should not be called multiple times. Once the button is pressed, the button callback function will be entered periodically. Press, press and hold, and release can be determined according to the parameters passed in.

The initialization interrupt function gpio_int_register() can also be used if it is not processed as a button type.

// Initialize the interrupt mode of input I/O void gpio_int_register(gpio_config_t *config, gpio_int_func_t func); // Button initialization gpio_button_init((gpio_config_t *)gpio_input_config, get_array_len(gpio_input_config), 50, __dev_key_handle); // Callback function for processing the button. The button enters the callback function every 20 ms until it is raised. 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); // Button production test report } return; } switch(key_id) { case KEY_1_IO_INDEX: // Button ID { if(key_st == KEY_ST_PUSH) // Button pressed { } else // Button released { } break; } default: { break; } } }

How to use the GPIO?

The GPIO initialization function is generally initialized in the function dev_power_on_init(). Note that the function should not be called multiple times.

// Initialize the GPIO port gpio_output_init((gpio_config_t *)gpio_ouput_config, get_array_len(gpio_ouput_config)); // Data I/O port operation function that is commonly used together with it. // Control the high and low level holding period and times. For example, the LED flickering. 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); // Control the switch status of the I/O output, and meanwhile stop the corresponding led_index flickering. void dev_led_stop_blink(uint8_t led_index, DEV_IO_ST_T st);

How to perform the device production test?

Some production test items are processed in the SDK infrastructure. For example, enter the test mode, read the Mac address, identify the firmware version, write the PID, read the PID, perform the RF test, get the RSSI signal value, and perform the authorization test.

You can process the required content in the callback function dev_mf_test_callback(). The serial port production test and the whole device production test share the same process.

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: // All the LED lights are on. { 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: // All the LED lights are off. { 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: // All the LED lights are flickering. { 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: // All the relays are on. { dev_led_stop_blink(RELAY_1_IO_INDEX, DEV_IO_ON); break; } case MF_TEST_RELAY_OFF_ALL: // All the relays are off. { dev_led_stop_blink(RELAY_1_IO_INDEX, DEV_IO_OFF); break; } case MF_TEST_RELAY_BLINK_ALL: // Periodic on/off for all the relays. { dev_led_start_blink(RELAY_1_IO_INDEX, 500, 500, 4, DEV_IO_OFF); break; } case MF_TEST_BUTTON: // Button production test. The app will wait for the button pressed. { g_work_st = DEV_WORK_ST_TEST; return MF_TEST_DOING; // Wait for the test } case MF_TRANSFER: // Other test items can be parsed and processed through this item. { break; } default : { break; } } return MF_TEST_SUCCESS; }

In terms of the gateway production test for the low power device, the data request needs to be expedited when entering the production test. You need to process under the corresponding case in the MF_TRANSFER.

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: // Enter the production 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; } ...

How to add and call a scene?

When adding a scene in the mobile app, a control command and a scene adding command will be sent to the device. The first control command and the last scene adding command will be completed in 15 seconds. After the scene adding command is received, the device shall save the controlled device status within 15 seconds for scene callback.

// When the scene adding command is received, it will enter the callback of adding a scene. 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; // If the device is controled in 15 seconds, the value should be TRUE. out_data[(*in_out_len)++] = Dev_onoff_status[endpoint-1]; // Save the device status } // When the scene calling command is received, it will enter the callback of calling a scene. 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) // Determine whether the scene is valid { Dev_OnOff_op(endpoint,in_data->data[dataOffset + 1],TRUE);// Control device } break; } case SCENE_DATA_TYPE_SERVER_DEFINE: // Parse according to the format of the server configuration. break; case SCENE_DATA_TYPE_ZIGBEE_DEFINE: // Parse according to the format of the Zigbee standard protocol. break; default: break; } }

Things to note in terms of the OTA update of the device

The SDK of the Zigbee module has a built-in OTA update function. After the development compilation is completed, the burnt firmware with the suffix of .s37 and the updated firmware with the suffix of .bin will be generated.

The firmware version can be updated through the gateway. If the OTA firmware version is lower than or equal to the current version, the updating is not feasible. The high version firmware is uploaded to the Tuya IoT Platform. Whitelist the devices for updating. For more information, see Select and Change the Firmware Version.

  • In terms of the router node (UPS device), no additional development is required for the OTA update.

  • In terms of the end device node (low power device), the RF data receiving capability is off due to the long-term sleep of the low power device. After the device is updated on the mobile app, it is necessary to wake up the device to send the data request for the update command. The logic must be processed in the following callback function:

    // OTA update callback void zg_ota_evt_callback(ZG_OTA_EVT_T evt) { switch(evt) { case ZG_OTA_EVT_START: { // Start update zg_poll_interval_change( 250 ); // For faster updating the data request is sent every 250 ms. zg_poll_start(); break; } default: { zg_poll_interval_change( 1000 ); zg_poll_end(); // Stop the data request after update, in order to avoid power waste. break; } } }

What is device authorization and how to authorize a device?

Authorization is one of the test items in the production test. The module can be authorized with both the programming tool software of the Tuya network module and the PCBA production test software. When the programming tool of the Tuya network module is programming, the module is authorized automatically. The device can work properly in the long run only after being authorized.

The authorization function of Tuya SDK is already implemented in the module SDK, so no additional development is required.

Note: The firmware programmed by the J-Link software can only run properly for a week. After the firmware development is completed, it can be uploaded to the Tuya background for authorization by the network module programming tool.