The content of this page has been automatically translated by AI. If you encounter any problems while reading, you can view the corresponding content in Chinese.

LLSync Assisted Network Configuration Development

Last updated: 2026-05-27 09:53:19

LLSync Bluetooth-assisted network configuration feature is an official Combo chip solution for Wi-Fi + BLE launched by Tencent Cloud IoT. It creates a designated GATT service through BLE. Mobile phones connect to the GATT SERVER. Leveraging the wireless communication capability of BLE, it transmits information required for IoT device connection, such as SSID and PASSWORD, to the Combo chip or module of Wi-Fi + BLE, enabling devices to smoothly integrate into the IoT platform and then complete functions such as device binding.
The main process of porting Bluetooth-assisted network configuration is as follows:

Hardware Device Selection

Choose appropriate Combo chips or modules according to product features.

Create a Product through the Console

1. Refer to console operations to create a device.
2. Select the device network configuration method in the console. Once confirmed, you can connect the device Bluetooth by scanning the QR code to configure the network.










Get SDK

The Bluetooth-assisted network configuration feature uses C SDK and LLSync SDK. Download the latest version for use. You can download ESP32 to use the LLSync network configuration sample program for reference.

Port SDK

The Bluetooth-assisted network configuration feature uses the communication capabilities of WI-Fi and BLE, so it includes the porting of C SDK and LLSync SDK.
1. Porting the LLSync SDK mainly involves configuration compilation, HAL implementation, and API calls.
1.1 Configuration compilation Modify the config/ble_qiot_config.h file to configure features relevant to network setup, ignoring standard Bluetooth functions.
// Configured as 0, broadcast by default after SDK initialization. Configured as 1, no broadcast after SDK initialization. Need to trigger broadcast through device UI operation (for example, pressing a key).
#define BLE_QIOT_BUTTON_BROADCAST (0)

#define __ORDER_LITTLE_ENDIAN__ (1234)
#define __ORDER_BIG_ENDIAN__ (4321)
// Device endianness definition.
#define __BYTE_ORDER__ (__ORDER_LITTLE_ENDIAN__)

// Serial port output function on the device side.
#define BLE_QIOT_LOG_PRINT(...) printf(__VA_ARGS__)
#define BLE_QIOT_USER_DEFINE_HEXDUMP 0

The maximum length of single data in the communication process between the device and the mini program is 128 by default for the networking functionality.
#define BLE_QIOT_EVENT_MAX_SIZE (128)

// Take the smaller value between MTU and BLE_QIOT_EVENT_MAX_SIZE. LLSync will perform data sharding before sending.
#define BLE_QIOT_EVENT_BUF_SIZE (23)

// Configured as 1, the mini program attempts to set MTU after establishing a bluetooth connection, obtained through the ble_get_user_data_mtu_size API; configured as 0, the default MTU is 23.
#define BLE_QIOT_REMOTE_SET_MTU (1)

// Configured as 1, enable the LLSync networking feature
#define BLE_QIOT_LLSYNC_CONFIG_NET (1)
LLSync's network configuration feature does not require ota, data templates and other capabilities. The SDK will control the compilation through feature macros.
1.2 HAL implementation The LLSync SDK dependency on the device HAL implementation is defined in inc/ble_qiot_import.h. This needs to be implemented on your own hardware platform.
/* Obtain device MAC address, for example:
int ble_get_mac(char *mac)
{
char *address = (char *)esp_bt_dev_get_address();
memcpy(mac, address, 6);
return 0;
}
*/
int ble_get_mac(char *mac);
Set WIFI mode. Currently supported: wifi station. Example:
ble_qiot_ret_status_t ble_combo_wifi_mode_set(BLE_WIFI_MODE mode)
{
if (mode != BLE_WIFI_MODE_STA){
return ble_event_report_wifi_mode(-1)
}
ESP_ERROR_CHECK(esp_wifi_set_mode(mode);
return ble_event_report_wifi_mode(0);
}
*/
ble_qiot_ret_status_t ble_combo_wifi_mode_set(BLE_WIFI_MODE mode);
Set WIFI SSID and PASSWORD. For example:
ble_qiot_ret_status_t ble_combo_wifi_info_set(const char *ssid, uint8_t ssid_len, const char *passwd, uint8_t passwd_len)
{
......
memcpy(wifi_config.sta.ssid, ssid, ssid_len);
memcpy(wifi_config.sta.password, passwd, passwd_len);
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
return ble_event_report_wifi_info(0);
}
*/
ble_qiot_ret_status_t ble_combo_wifi_info_set(const char *ssid, uint8_t ssid_len, const char *passwd, uint8_t passwd_len);
/* Request a connection to WIFI using the set WIFI information. Example:
ble_qiot_ret_status_t ble_combo_wifi_connect()
{
ESP_ERROR_CHECK(esp_wifi_connect());
return 0;
}
*/
ble_qiot_ret_status_t ble_combo_wifi_connect();
inc/ble_qiot_import.h defines the implementation of the Bluetooth protocol stack HAL required by the LLSync SDK. You need to implement it on your own hardware platform.
/* Obtain the Bluetooth service through ble_get_qiot_services and add the Bluetooth service to the protocol stack. The service UUID used for the configuration function is 0xFFF0, and the characteristic value UUIDs are 0xFFE1 and 0xFFE3. You can also choose other methods to add the service to the protocol stack. The following is a sample code for adding a Bluetooth service on ESP32:
static uint8_t llsync_service_uuid[16] = {
0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xf0, 0xff, 0x00, 0x00,};
static uint8_t llsync_device_info_uuid[16] = {
0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe1, 0xff, 0x00, 0x00,};
static uint8_t llsync_event_uuid[16] = {
0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe3, 0xff, 0x00, 0x00,};
static const esp_gatts_attr_db_t gatt_db[HRS_IDX_NB] = {
[IDX_SVC] = {{ESP_GATT_AUTO_RSP},
{ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ, sizeof(llsync_service_uuid), sizeof(llsync_service_uuid), (uint8_t *)llsync_service_uuid}},
[IDX_CHAR_A] = {{ESP_GATT_AUTO_RSP},
{ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_write}},
[IDX_CHAR_VAL_A] = {{ESP_GATT_AUTO_RSP},
{ESP_UUID_LEN_128, (uint8_t *)llsync_device_info_uuid, ESP_GATT_PERM_WRITE,
LLSYNC_CHAR_VAL_LEN_MAX, 0, NULL}},
[IDX_CHAR_C] = {{ESP_GATT_AUTO_RSP},
{ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_notify}},
[IDX_CHAR_VAL_C] = {{ESP_GATT_AUTO_RSP},
{ESP_UUID_LEN_128, (uint8_t *)llsync_event_uuid, 0, LLSYNC_CHAR_VAL_LEN_MAX, 0, NULL}},
[IDX_CHAR_CFG_C] = {{ESP_GATT_AUTO_RSP},
{ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid,
ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, sizeof(uint16_t), sizeof(heart_measurement_ccc), (uint8_t *)heart_measurement_ccc}},
}
...
esp_err_t create_attr_ret = esp_ble_gatts_create_attr_tab(gatt_db, gatts_if, HRS_IDX_NB, SVC_INST_ID);
};
*/
void ble_services_add(const qiot_service_init_s *p_service);
/* Obtain the broadcast data through ble_get_my_broadcast_data, and start broadcasting it as vendor data. The Company ID is 0xFEE7. Example:
...
adv_info_s my_adv_info;
adv_data_len = ble_get_my_broadcast_data((char *)adv_data, sizeof(adv_data));
my_adv_info.manufacturer_info.company_identifier = TENCENT_COMPANY_IDENTIFIER;
my_adv_info.manufacturer_info.adv_data = adv_data;
my_adv_info.manufacturer_info.adv_data_len = adv_data_len;
ble_advertising_start(&my_adv_info);
...
ble_qiot_ret_status_t ble_advertising_start(adv_info_s *adv)
{
static uint8_t raw_adv_data[32] = {0x02, 0x01, 0x06, 0x03, 0x03, 0xF0, 0xFF};
uint8_t usr_adv_data[31] = {0};
uint8_t len = 0;
uint8_t index = 0;
memcpy(usr_adv_data, &adv->manufacturer_info.company_identifier, sizeof(uint16_t));
len = sizeof(uint16_t);
memcpy(usr_adv_data + len, adv->manufacturer_info.adv_data, adv->manufacturer_info.adv_data_len);
len += adv->manufacturer_info.adv_data_len;
index = 7;
raw_adv_data[index++] = len + 1;
raw_adv_data[index++] = 0xFF;
// Add manufacturer broadcast data
memcpy(raw_adv_data + index, usr_adv_data, len);
index += len;
...
esp_log_buffer_hex("adv", raw_adv_data, index);
esp_err_t ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, index);
if (ret) {
ESP_LOGE(LLSYNC_LOG_TAG, "config adv data failed, error code = %x", ret);
}
adv_config_done |= ADV_CONFIG_FLAG;
esp_ble_gap_start_advertising(&adv_params);
return 0;
}
*/
ble_qiot_ret_status_t ble_advertising_start(adv_info_s *adv);
Stop the broadcast interface. Example:
ble_qiot_ret_status_t ble_advertising_stop(void)
{
esp_ble_gap_stop_advertising();
return 0;
}
*/
ble_qiot_ret_status_t ble_advertising_stop(void);
API for writing data to the mini program with eigenvalue UUID FFE3. Example:
ble_qiot_ret_status_t ble_send_notify(uint8_t *buf, uint8_t len)
{
esp_ble_gatts_send_indicate(llsync_profile_tab[PROFILE_APP_IDX].gatts_if,
llsync_profile_tab[PROFILE_APP_IDX].conn_id, llsync_handle_table[IDX_CHAR_VAL_C], len, buf, false);
return BLE_QIOT_RS_OK;
}
*/
ble_qiot_ret_status_t ble_send_notify(uint8_t *buf, uint8_t len);
/* User-specified MTU. When BLE_QIOT_REMOTE_SET_MTU is set to 1, the mini program will modify the MTU and notify the device after connecting to the device. Otherwise, communicate using the default MTU (23).
uint16_t ble_get_user_data_mtu_size(void)
{
return 128;
}
*/
uint16_t ble_get_user_data_mtu_size(void);
1.3 API call The API provided to the outside by the LLSync SDK is defined in inc/ble_qiot_export.h.
/* Obtain the LLSync Bluetooth service. You can add the Bluetooth service to the Bluetooth protocol stack after obtaining the Bluetooth service in code.*/
const qiot_service_init_s *ble_get_qiot_services(void);
/* Initialization API for LLSync SDK, mainly performing the addition of Bluetooth services. It is called within start_device_btcomboconfig by default. You can also choose to call it in other positions.*/
ble_qiot_ret_status_t ble_qiot_explorer_init(void);
LLSync broadcast startup API. Please call it at an appropriate position. For example, restart the broadcast when the Bluetooth is disconnected.
...
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_DISCONNECT_EVT, reason = 0x%x", param->disconnect.reason);
ble_qiot_advertising_start();
...
*/
ble_qiot_ret_status_t ble_qiot_advertising_start(void);
LLSync broadcast stop API. Please call it at an appropriate position. For example, stop the broadcast when the network configuration is finished.
int stop_device_btcomboconfig(void)
{
ble_qiot_advertising_stop();
return QCLOUD_RET_SUCCESS;
}
*/
ble_qiot_ret_status_t ble_qiot_advertising_stop(void);
/* Notify LLSync SDK when connecting GAP. For example:
case ESP_GATTS_CONNECT_EVT:
...
esp_ble_gap_update_conn_params(&conn_params);
ble_gap_connect_cb();
...
*/
void ble_gap_connect_cb(void);
/* Notify LLSync SDK when GAP is disconnected. For example:
...
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_DISCONNECT_EVT, reason = 0x%x", param->disconnect.reason);
ble_gap_disconnect_cb();
...
*/
void ble_gap_disconnect_cb(void);
// The mini program cannot obtain the Bluetooth MTU API. After the device receives the MTU modification notification, call this API to notify the mini program. For example:
case ESP_GATTS_MTU_EVT:
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu);
ble_event_sync_mtu(param->mtu.mtu);
break;
*/
ble_qiot_ret_status_t ble_event_sync_mtu(uint16_t llsync_mtu);
Data processing API for eigenvalue UUID FFE1. Call this API after data is received. For example:
case ESP_GATTS_WRITE_EVT:
if (!param->write.is_prep) {
// the data length of gattc write must be less than LLSYNC_CHAR_VAL_LEN_MAX.
if (param->write.handle == llsync_handle_table[IDX_CHAR_VAL_A]) {
ble_device_info_write_cb(param->write.value, param->write.len);}
...
}
*/
void ble_device_info_write_cb(const uint8_t *buf, uint16_t len);
After setting WIFI Mode, the device side replies to the mini program with the setting results. A result of 0 indicates successful setting, while others indicate an error. Example:
ble_qiot_ret_status_t ble_combo_wifi_mode_set(BLE_WIFI_MODE mode)
{
if (mode != BLE_WIFI_MODE_STA){
return ble_event_report_wifi_mode(-1)
}
ESP_ERROR_CHECK(esp_wifi_set_mode(mode);
return ble_event_report_wifi_mode(0);
}
*/
ble_qiot_ret_status_t ble_event_report_wifi_mode(uint8_t result);
/* After setting WIFI information, the device side replies to the mini program with the setting results. A result of 0 indicates successful setting, while others indicate an error. Example:
ble_qiot_ret_status_t ble_combo_wifi_info_set(const char *ssid, uint8_t ssid_len, const char *passwd, uint8_t passwd_len)
{
......
memcpy(wifi_config.sta.ssid, ssid, ssid_len);
memcpy(wifi_config.sta.password, passwd, passwd_len);
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
return ble_event_report_wifi_info(0);
}
*/
ble_qiot_ret_status_t ble_event_report_wifi_info(uint8_t result);
/* Once the WIFI connection ends, reply to the mini program with the WIFI connection results. Example of reply after successful WIFI connection:
static void bt_combo_report_wificonn_success()
{
wifi_config_t cfg;
esp_wifi_get_config(WIFI_IF_STA, &cfg);
ble_event_report_wifi_connect(BLE_WIFI_MODE_STA, BLE_WIFI_STATE_CONNECT, (uint8_t)strlen((const char *)cfg.sta.ssid), (const char *)cfg.sta.ssid);
}
Note: Reply to the mini program even if the WIFI connection fails.
*/
ble_qiot_ret_status_t ble_event_report_wifi_connect(BLE_WIFI_MODE mode, BLE_WIFI_STATE state, uint8_t ssid_len, const char *ssid);
2. C SDK porting, please refer to C SDK Usage Reference. C SDK has implemented the Distribution Network Code framework. You only need to implement the related HAL interfaces as required. To further simplify the adaptation steps, some C SDK HAL interfaces have already been implemented under the directory qcloud-iot-explorer-BLE-sdk-embedded/lib/qcloud_iot_c_sdk. You need to copy and overwrite the corresponding files in the directories qcloud-iot-explorer-sdk-embedded-c/platform and qcloud-iot-explorer-sdk-embedded-c/sdk_src/wifi_config.
cp qcloud-iot-explorer-BLE-sdk-embedded/lib/qcloud_iot_c_sdk/platform/* qcloud-iot-explorer-sdk-embedded-c/platform/
cp qcloud-iot-explorer-BLE-sdk-embedded/lib/qcloud_iot_c_sdk/sdk_src/* qcloud-iot-explorer-sdk-embedded-c/sdk_src/wifi_config/
You also need to implement the following HAL interfaces to complete the adaptation work of the network configuration feature.
/* Startup API for the COMBO device networking feature. By default, it calls the LLSync SDK initialization API. Modifications are needed as required. Sample code */
int start_device_btcomboconfig(void)
{
// TODO other init (for example, Bluetooth protocol stack initialization)
ble_qiot_explorer_init(); // init llsync sdk
return QCLOUD_RET_SUCCESS;
}
*/
int start_device_btcomboconfig(void);
/* COMBO device network configuration feature stop API. By default, it calls the LLSync broadcast stop API. Modifications are needed as required. For example,
int stop_device_btcomboconfig(void)
{
ble_qiot_advertising_stop();
// TODO other deinit
return QCLOUD_RET_SUCCESS;
}
*/
int stop_device_btcomboconfig(void)
/* After the WIFI connection is successful, report to the mini program. You need to get the current WIFI connection information and call the ble_event_report_wifi_connect api to report. Example
static void bt_combo_report_wificonn_success()
{
wifi_config_t cfg;
esp_wifi_get_config(WIFI_IF_STA, &cfg);
ble_event_report_wifi_connect(BLE_WIFI_MODE_STA, BLE_WIFI_STATE_CONNECT, (uint8_t)strlen((const char *)cfg.sta.ssid), (const char *)cfg.sta.ssid);
}
*/
void bt_combo_report_wificonn_success();
Set WIFI configuration status. Modify the status according to the result after WIFI information is set. Example
...
ESP_LOGI(TAG, "wifi info %s, %s", wifi_config.sta.ssid,wifi_config.sta.password);
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
// WIFI information setting is successful
set_bt_combo_config_state(WIFI_CONFIG_SUCCESS);
...
*/
void set_bt_combo_config_state(eWiFiConfigState state);
/* Retrieve WIFI connection status. It is recommended to consider WIFI connected successfully only after obtaining an IP address. Example
bool HAL_Wifi_IsConnected(void)
{
// TODO, retrun true when you got ip
return false;
}
*/
bool HAL_Wifi_IsConnected(void);
/* Operation interface for network configuration error log. The following interfaces can be implemented when it is required to solidify log storage. When an error occurs, the device stores logs. When the device restarts, the logs are read to prevent loss of error information.
*/
int HAL_Wifi_read_err_log(uint32_t offset, void *log, size_t log_size);
int HAL_Wifi_write_err_log(uint32_t offset, void *log, size_t log_size);
int HAL_Wifi_clear_err_log(void);
Select and configure the network connection feature in qcloud-iot-explorer-sdk-embedded-c/sdk_src/internal/inc/qcloud_wifi_config.h.
#define WIFI_ERR_LOG_POST 1 // Submit Wi-Fi configuration error log to the mini program on error
#define WIFI_LOG_UPLOAD 1 // Submit configuration process log to the mini program on configuration error
#define WIFI_PROV_BT_COMBO_CONFIG_ENABLE 1 // Select the LLSync networking feature. Networking options such as soft ap and airkiss need to be disabled.

5. Verify Bluetooth Assisted Network Configuration Functionality

1. After BLE adaptation is completed, device broadcast information and Bluetooth service information can be viewed through Nrf Connect.


2. Mini program LLSync network configuration example.