1.获取设备token和时间线添加debug投票,使用后移除 2600/3 2600/head 2601/target/1
authorluozheng <1732036298@qq.com>
Fri, 24 Oct 2025 09:52:41 +0000 (17:52 +0800)
committerluozheng <1732036298@qq.com>
Fri, 24 Oct 2025 09:52:41 +0000 (17:52 +0800)
2.添加:角色切换,角色配置,哄睡开始 /结束,绑定/解绑,日程提醒/日程配置,表情下载/删除的ack协议函数

code/sdk/zhihui/leiniao/imsl_ln/CMakeLists.txt
code/sdk/zhihui/leiniao/imsl_ln/ln_api.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api.h
code/sdk/zhihui/leiniao/imsl_ln/ln_api_device_info.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api_emoji.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api_schedule.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api_story_random.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api_timeline_activities.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api_token.c
code/sdk/zhihui/leiniao/imsl_ln/ln_api_web_ack.c [new file with mode: 0644]

index d8c4e76..2db97e4 100644 (file)
@@ -20,6 +20,7 @@ set(SOURCES
     ${CMAKE_CURRENT_SOURCE_DIR}/ln_api_schedule.c
     ${CMAKE_CURRENT_SOURCE_DIR}/ln_api_emoji.c
     ${CMAKE_CURRENT_SOURCE_DIR}/ln_api_timeline_activities.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/ln_api_web_ack.c
 )
 
 # 公共头文件路径(供其他模块引用)
index 7ccd43b..1a56180 100644 (file)
@@ -42,6 +42,7 @@ int g_ln_last_package_size = 0;          // 最近一次查询到的 OTA 包大
 int g_ln_is_device_bound = 0;            /* 设备绑定状态 */
 char g_ln_device_user_id[64] = {0};      // 设备绑定用户ID
 static int g_ln_is_file_downloading = 0; // 是否正在下载文件
+char g_ln_character_id[64] = {0};        // 角色ID
 
 /* 简单的字符串读写(以.bin形式读写原始字节,末尾补'\0')*/
 static int ln_read_string_file(const char *file_path, char **out_str)
@@ -354,6 +355,34 @@ const char *uapi_ln_get_user_id(void)
     return g_ln_device_user_id;
 }
 
+void uapi_ln_set_user_id(const char *user_id)
+{
+    if (user_id && user_id[0])
+    {
+        strncpy(g_ln_device_user_id, user_id, sizeof(g_ln_device_user_id));
+        g_ln_device_user_id[sizeof(g_ln_device_user_id) - 1] = '\0';
+    }
+    else
+    {
+        g_ln_device_user_id[0] = '\0';
+    }
+}
+
+/* 获取角色ID */
+char *uapi_ln_get_character_id(void)
+{
+    return g_ln_character_id;
+}
+
+/* 设置角色ID */
+void uapi_ln_set_character_id(const char *character_id)
+{
+    if (character_id && character_id[0])
+    {
+        strncpy(g_ln_character_id, character_id, sizeof(g_ln_character_id));
+        g_ln_character_id[sizeof(g_ln_character_id) - 1] = '\0';
+    }
+}
 /* 获取当前是否正在下载文件 */
 int uapi_ln_is_file_downloading(void)
 {
@@ -834,6 +863,7 @@ void ln_ws_process_message(const ws_data_msg_t *data_msg, ws_command_t type)
         if (json_str)
         {
             ln_parse_character_config(json_str, (int)strlen(json_str));
+            ln_ws_send_character_change_ack(uapi_ln_get_character_id(), true, "角色切换");
         }
         break;
     }
@@ -843,6 +873,7 @@ void ln_ws_process_message(const ws_data_msg_t *data_msg, ws_command_t type)
         if (json_str)
         {
             ln_parse_character_config(json_str, (int)strlen(json_str));
+            ln_ws_send_character_config_change_ack(uapi_ln_get_character_id(), true, "角色配置更改");
         }
         break;
     }
@@ -860,9 +891,7 @@ void ln_ws_process_message(const ws_data_msg_t *data_msg, ws_command_t type)
         printf("[WS] SleepModeEnd:哄睡模式结束\n");
         if (json_str)
         {
-            // ln_parse_sleep_mode_end(json_str, (int)strlen(json_str));
-            ln_voice_chat_interrupt("哄睡模式结束");
-            push_sleep_mode_end_notification();
+            ln_parse_sleep_mode_end(json_str, (int)strlen(json_str));
         }
         break;
     }
@@ -871,12 +900,16 @@ void ln_ws_process_message(const ws_data_msg_t *data_msg, ws_command_t type)
         printf("[WS] DeviceBind:设备绑定\n");
         do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_GET_CHARACTER, NULL, 0);
         push_bind_and_unbind_notification(LN_DEVICE_BIND_STATUS_BOUND);
+        ln_ws_ack_user_id_from_json(json_str);
+        ln_ws_send_device_bind_ack(uapi_ln_get_user_id(), true, "绑定成功");
         break;
     }
     case WS_CMD_DEVICE_UNBIND:
     {
         printf("[WS] DeviceUnbind:设备解绑\n");
         push_bind_and_unbind_notification(LN_DEVICE_BIND_STATUS_UNBOUND);
+        ln_ws_ack_user_id_from_json(json_str);
+        ln_ws_send_device_unbind_ack(uapi_ln_get_user_id(), true, "解绑成功");
         break;
     }
     case WS_CMD_SCHEDULE_REMINDER:
index ae37cee..4b8dff6 100644 (file)
@@ -195,6 +195,7 @@ typedef struct
 /* 日程 日程提醒醒配置配置信息结构体 */
 typedef struct
 {
+    int scheduleId;
     char *scheduleName; // 日程名称
 } ScheduleReminderConfig;
 
@@ -223,6 +224,13 @@ const char *uapi_ln_ota_get_saved_path(void);
 const char *uapi_ln_get_audio_path(void);
 /* 获取设备绑定用户ID */
 const char *uapi_ln_get_user_id(void);
+/* 设置设备绑定用户ID */
+void uapi_ln_set_user_id(const char *user_id);
+
+/* 获取角色ID */
+char *uapi_ln_get_character_id(void);
+/* 设置角色ID */
+void uapi_ln_set_character_id(const char *character_id);
 //获取当前是否正在下载文件
 int uapi_ln_is_file_downloading(void);
 /* 获取ota包大小 */
@@ -272,7 +280,6 @@ void ln_download_screen_image(void);
 
 // 解析设备角色配置
 void ln_parse_character_config(const char *json_buf, int json_len);
-void ln_parse_character_config_local(const char *json_buf, int json_len);
 /* 解析哄睡模式开始 */
 void ln_parse_sleep_mode_start(const char *json_str, int json_len);
 /* 解析哄睡模式结束 */
@@ -288,6 +295,18 @@ void ln_parse_delete_emoji(const char *json_str, int json_len);
 /* 上报角色表情组下载状态(从队列数据解析)*/
 void ln_emoji_report_status(char *data);
 
+/* 从下发JSON中提取userId */
+void ln_ws_ack_user_id_from_json(const char *json_str);
+/* ========== Ack 发送接口 ========== */
+int ln_ws_send_character_change_ack(const char *character_id, bool success, const char *msg);
+int ln_ws_send_character_config_change_ack(const char *character_id, bool success, const char *msg);
+int ln_ws_send_sleep_mode_start_ack(bool success, const char *msg);
+int ln_ws_send_sleep_mode_end_ack(bool success, const char *msg);
+int ln_ws_send_schedule_reminder_ack(int schedule_id, bool success, const char *msg);
+int ln_ws_send_schedule_reminder_config_ack(int schedule_id, bool success, const char *msg);
+int ln_ws_send_delete_emoji_ack(const char *character_id, const char *eyesColor, const char *eyesShape, bool success, const char *msg);
+int ln_ws_send_download_emoji_ack(const char *character_id, const char *eyesColor, const char *eyesShape, bool success, const char *msg);
+
 /* =================== 时间线状态(Timeline getStatus) =================== */
 /* 查询时间线状态(GET /v1/timeline/getStatus)*/
 uint32_t ln_timeline_get_status_http(const char *device_id,
index 2c31058..7d97a24 100644 (file)
@@ -190,6 +190,10 @@ void ln_parse_character_config(const char *json_buf, int json_len)
 
     /* 基础字段 */
     cJSON *cid = cJSON_GetObjectItem(data, "characterId");
+    if (cid && cJSON_IsString(cid))
+    {
+        uapi_ln_set_character_id(cid->valuestring);
+    }
     cJSON *cname = cJSON_GetObjectItem(data, "characterName");
     ln_assign_dup(&g_ln_character_config.character_id,
                   (cid && cJSON_IsString(cid)) ? cid->valuestring : "");
index bf9763b..48dd484 100644 (file)
@@ -634,7 +634,7 @@ void ln_parse_download_emoji(const char *json_buf, int json_len)
                             }
                         }
                         g_emoji_package.emojis[i].size = (emoji_size > 0) ? emoji_size : 0;
-                        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  emoji %d: emotion=%s, url=%s, size=%lld",
+                        WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "  emoji %d: emotion=%s, url=%s, size=%lld",
                                       i + 1,
                                       g_emoji_package.emojis[i].emotion,
                                       g_emoji_package.emojis[i].emojiUrl,
@@ -654,19 +654,21 @@ void ln_parse_download_emoji(const char *json_buf, int json_len)
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  totalSize: %lld", g_emoji_package.totalSize);
 
 
-    for (int i = 0; i < g_emoji_package.emojiCount; i++)
-    {
-        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  emoji %d: emotion=%s, url=%s",
-                      i + 1,
-                      g_emoji_package.emojis[i].emotion,
-                      g_emoji_package.emojis[i].emojiUrl);
-    }
+    // for (int i = 0; i < g_emoji_package.emojiCount; i++)
+    // {
+    //     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  emoji %d: emotion=%s, url=%s",
+    //                   i + 1,
+    //                   g_emoji_package.emojis[i].emotion,
+    //                   g_emoji_package.emojis[i].emojiUrl);
+    // }
 
     // 解析完成后启动下载任务(通过发送队列触发下载逻辑)
     // 说明:下载所需信息已填充到全局 g_emoji_package,触发命令无需携带负载
     //通知ui切换slice下载表情
     push_download_file_notification(DOWNLOAD_FILE_TYPE_EMOJI);
     //do_ln_http_server_send_data(LN_HTTP_SERVICE_CMD_DOWNLOAD_EMOJI, NULL, 0);
+
+    ln_ws_send_download_emoji_ack(g_emoji_package.characterId, g_emoji_package.eyesColor, g_emoji_package.eyesShape, true, "下载表情");
     // 清理资源
     cJSON_Delete(root);
     free(text);
@@ -784,6 +786,9 @@ void ln_parse_delete_emoji(const char *json_buf, int json_len)
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  eyesColor: %s", del_eyesColor);
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "  eyesShape: %s", del_eyesShape);
 
+    ln_ws_send_delete_emoji_ack(del_characterId, del_eyesColor, del_eyesShape, true, "删除表情");
+
+
     // 删除本地表情缓存
     char del_dir[MAX_PATH_LEN] = {0};
     snprintf(del_dir, sizeof(del_dir),
index 519afb6..7079cf9 100644 (file)
@@ -272,6 +272,7 @@ void ln_parse_schedule_reminder(const char *json_buf, int json_len)
         /* -------------------------------------------------------------------------- */
     }
 
+    ln_ws_send_schedule_reminder_ack(g_schedule_reminder.scheduleId, true, "日程提醒成功"); 
     // 清理资源
     cJSON_Delete(root);
     free(text);
@@ -324,6 +325,14 @@ void ln_parse_schedule_reminder_config(const char *json_buf, int json_len)
         return;
     }
 
+
+    // 解析日程ID字段
+    cJSON *scheduleId = cJSON_GetObjectItem(data, "scheduleId");
+    if (scheduleId && cJSON_IsNumber(scheduleId))
+    {
+        g_schedule_reminder_config.scheduleId = scheduleId->valueint;
+    }
+
     // 解析日程名称字段
     cJSON *scheduleName = cJSON_GetObjectItem(data, "scheduleName");
     ln_assign_dup(&g_schedule_reminder_config.scheduleName,
@@ -332,6 +341,7 @@ void ln_parse_schedule_reminder_config(const char *json_buf, int json_len)
     // 打印解析结果
     printf("[SCHEDULE_REMINDER_CONFIG] parsed successfully:\n");
     printf("  scheduleName: %s\n", g_schedule_reminder_config.scheduleName ? g_schedule_reminder_config.scheduleName : "");
+    printf("  scheduleId: %d\n", g_schedule_reminder_config.scheduleId);
 
     // 推送任务提醒通知
     WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[SCHEDULE_REMINDER_CONFIG] push task reminder notification\n");
@@ -339,6 +349,7 @@ void ln_parse_schedule_reminder_config(const char *json_buf, int json_len)
     //震动
     custom_VibratorFunc_int(0);
 
+    ln_ws_send_schedule_reminder_config_ack(g_schedule_reminder_config.scheduleId, true, "日程提醒配置成功");
     // 清理资源
     cJSON_Delete(root);
     free(text);
index b90588d..f5201f3 100644 (file)
@@ -323,6 +323,7 @@ void ln_parse_sleep_mode_start(const char *json_str, int json_len)
     push_sleep_mode_start_notification(theme, 0);//0小程序直接发起,不是意图识别结果
     //通知websocket发送随机故事请求
     ln_ws_send_random_story_request(theme);
+    ln_ws_send_sleep_mode_start_ack(true, "哄睡模式开始");
     if (root) cJSON_Delete(root);
 }
 
@@ -333,5 +334,7 @@ void ln_parse_sleep_mode_end(const char *json_str, int json_len)
        (void)json_len;
        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "[LN][SLEEP_END] received\n");
        /* 标记故事结束,供UI状态机使用 */
+    ln_voice_chat_interrupt("哄睡模式结束");
     push_sleep_mode_end_notification();
+    ln_ws_send_sleep_mode_end_ack(true, "哄睡模式结束");
 }
index c360ada..0286944 100644 (file)
@@ -3,6 +3,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include "cJSON.h"
+#include "custom_utils.h"
 
 /*
 GET /v1/timeline/getStatus
@@ -64,6 +65,9 @@ uint32_t ln_timeline_get_status_http(const char *device_id,
        cat1_api_disable_cat1_cmd(0);
        LOS_Msleep(200);
 #endif
+       uapi_pm_add_sleep_veto(PM_ID_DEBUG);
+       //亮屏
+       uapi_set_screen_on_api();
 
        HttpClient client = (HttpClient){0};
        HttpClientData clientData = (HttpClientData){0};
@@ -72,7 +76,10 @@ uint32_t ln_timeline_get_status_http(const char *device_id,
 
        char *header_buf = (char *)malloc(512);
        if (!header_buf)
+       {
+               uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
                return ERRCODE_FAIL;
+       }
        int hdr = snprintf(header_buf, 512,
                                          "deviceId: %s\r\n"
                                          "deviceToken: %s\r\n"
@@ -81,6 +88,7 @@ uint32_t ln_timeline_get_status_http(const char *device_id,
        if (hdr <= 0)
        {
                free(header_buf);
+               uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
                return ERRCODE_FAIL;
        }
        HttpClientSetCustomHeader(&client, header_buf);
@@ -89,6 +97,7 @@ uint32_t ln_timeline_get_status_http(const char *device_id,
        if (prep != HTTP_SUCCESS)
        {
                free(header_buf);
+               uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
                return ERRCODE_FAIL;
        }
 
@@ -112,6 +121,7 @@ end:
        HttpClientUnprepare(&clientData);
        HttpClientClse(&client);
        free(header_buf);
+       uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
        return ERRCODE_SUCC;
 }
 
index 2e8be61..898b952 100644 (file)
@@ -289,6 +289,7 @@ uint32_t ln_get_device_token_http(const char *device_id,
     cat1_api_disable_cat1_cmd(0);
     LOS_Msleep(500);
 #endif
+       uapi_pm_add_sleep_veto(PM_ID_DEBUG);
 
     /* 5. 发起HTTPS GET */
     HttpClient client = (HttpClient){0};
@@ -301,6 +302,7 @@ uint32_t ln_get_device_token_http(const char *device_id,
         WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ln_get_device_token_http: HttpClientPrepare failed %d", prep);
         free(sign_data);
         free(header_buf);
+               uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
         return ERRCODE_FAIL;
     }
 
@@ -312,6 +314,7 @@ uint32_t ln_get_device_token_http(const char *device_id,
         HttpClientClse(&client);
         free(sign_data);
         free(header_buf);
+               uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
         return ERRCODE_FAIL;
     }
 
@@ -323,6 +326,7 @@ uint32_t ln_get_device_token_http(const char *device_id,
         HttpClientClse(&client);
         free(sign_data);
         free(header_buf);
+               uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
         return ERRCODE_FAIL;
     }
 
@@ -334,6 +338,7 @@ uint32_t ln_get_device_token_http(const char *device_id,
         HttpClientClse(&client);
         free(sign_data);
         free(header_buf);
+               uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
         return ERRCODE_FAIL;
     }
 
@@ -348,6 +353,7 @@ uint32_t ln_get_device_token_http(const char *device_id,
         HttpClientClse(&client);
         free(sign_data);
         free(header_buf);
+               uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
         return ERRCODE_FAIL;
     }
     memcpy(json_text, clientData.responseBuf, (size_t)body_len);
@@ -362,6 +368,7 @@ uint32_t ln_get_device_token_http(const char *device_id,
         HttpClientClse(&client);
         free(sign_data);
         free(header_buf);
+               uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
         return ERRCODE_FAIL;
     }
 
@@ -376,6 +383,7 @@ uint32_t ln_get_device_token_http(const char *device_id,
         free(json_text);
         HttpClientUnprepare(&clientData);
         HttpClientClse(&client);
+               uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
         return ERRCODE_FAIL;
     }
 
@@ -421,5 +429,6 @@ uint32_t ln_get_device_token_http(const char *device_id,
     HttpClientClse(&client);
     free(sign_data);
     free(header_buf);
+       uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
     return ERRCODE_SUCC;
 }
diff --git a/code/sdk/zhihui/leiniao/imsl_ln/ln_api_web_ack.c b/code/sdk/zhihui/leiniao/imsl_ln/ln_api_web_ack.c
new file mode 100644 (file)
index 0000000..5c621a0
--- /dev/null
@@ -0,0 +1,521 @@
+#include "ln_api.h"
+#include "cJSON.h"
+#include "custom_utils.h"
+
+/* 从下发JSON中提取userId */
+void ln_ws_ack_user_id_from_json(const char *json_str)
+{
+    if (json_str && json_str[0])
+    {
+        cJSON *root = cJSON_Parse(json_str);
+        if (root)
+        {
+            cJSON *data_obj = cJSON_GetObjectItem(root, "data");
+            if (data_obj && cJSON_IsObject(data_obj))
+            {
+                cJSON *uid = cJSON_GetObjectItem(data_obj, "userId");
+                if (uid && cJSON_IsString(uid) && uid->valuestring)
+                {
+                    uapi_ln_set_user_id(uid->valuestring);
+                }
+            }
+            cJSON_Delete(root);
+        }
+    }
+}
+
+/* 发送设备绑定应答 DeviceBindAck */
+int ln_ws_send_device_bind_ack(const char *user_id, bool success, const char *msg)
+{
+    if (ln_ws_get_connection_state() != 2)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Cannot send DeviceBindAck, connection state: %d\n", ln_ws_get_connection_state());
+        return -1;
+    }
+
+    uint32_t timestamp;
+    uapi_get_timestampe_ss(&timestamp);
+
+    cJSON *json = cJSON_CreateObject();
+    if (!json)
+        return -1;
+
+    cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+    cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+
+    char message_id[64];
+    snprintf(message_id, sizeof(message_id), "ack_bind_%u", timestamp);
+    cJSON_AddStringToObject(json, "messageId", message_id);
+    cJSON_AddStringToObject(json, "command", "DeviceBindAck");
+
+    cJSON *data = cJSON_CreateObject();
+    if (!data)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+    cJSON_AddStringToObject(data, "userId", (user_id && user_id[0]) ? user_id : "");
+    cJSON_AddBoolToObject(data, "success", success);
+    cJSON_AddStringToObject(data, "message", msg ? msg : (success ? "绑定成功" : "绑定失败"));
+    cJSON_AddItemToObject(json, "data", data);
+
+    char *json_string = cJSON_Print(json);
+    if (!json_string)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+
+    int ret = uapi_ws_send_text(json_string);
+
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sent DeviceBindAck: %s\n", json_string);
+
+    cJSON_free(json_string);
+    cJSON_Delete(json);
+    return ret;
+}
+
+/* 发送设备解绑应答 DeviceUnbindAck */
+int ln_ws_send_device_unbind_ack(const char *user_id, bool success, const char *msg)
+{
+    if (ln_ws_get_connection_state() != 2)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Cannot send DeviceUnbindAck, connection state: %d\n", ln_ws_get_connection_state());
+        return -1;
+    }
+
+    uint32_t timestamp;
+    uapi_get_timestampe_ss(&timestamp);
+
+    cJSON *json = cJSON_CreateObject();
+    if (!json)
+        return -1;
+
+    cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+    cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+
+    char message_id[64];
+    snprintf(message_id, sizeof(message_id), "ack_unbind_%u", timestamp);
+    cJSON_AddStringToObject(json, "messageId", message_id);
+    cJSON_AddStringToObject(json, "command", "DeviceUnbindAck");
+
+    cJSON *data = cJSON_CreateObject();
+    if (!data)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+    cJSON_AddStringToObject(data, "userId", (user_id && user_id[0]) ? user_id : "");
+    cJSON_AddBoolToObject(data, "success", success);
+    cJSON_AddStringToObject(data, "message", msg ? msg : (success ? "解绑成功" : "解绑失败"));
+    cJSON_AddItemToObject(json, "data", data);
+
+    char *json_string = cJSON_Print(json);
+    if (!json_string)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+
+    int ret = uapi_ws_send_text(json_string);
+
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sent DeviceUnbindAck: %s\n", json_string);
+
+    cJSON_free(json_string);
+    cJSON_Delete(json);
+    return ret;
+}
+
+/* 发送角色切换应答 CharacterChangeAck */
+int ln_ws_send_character_change_ack(const char *character_id, bool success, const char *msg)
+{
+    if (ln_ws_get_connection_state() != 2)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Cannot send CharacterChangeAck, connection state: %d\n", ln_ws_get_connection_state());
+        return -1;
+    }
+
+    uint32_t timestamp;
+    uapi_get_timestampe_ss(&timestamp);
+
+    cJSON *json = cJSON_CreateObject();
+    if (!json)
+        return -1;
+
+    cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+    cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+
+    char message_id[64];
+    snprintf(message_id, sizeof(message_id), "ack_char_change_%u", timestamp);
+    cJSON_AddStringToObject(json, "messageId", message_id);
+    cJSON_AddStringToObject(json, "command", "CharacterChangeAck");
+
+    cJSON *data = cJSON_CreateObject();
+    if (!data)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+    cJSON_AddStringToObject(data, "characterId", (character_id && character_id[0]) ? character_id : "");
+    cJSON_AddBoolToObject(data, "success", success);
+    cJSON_AddStringToObject(data, "message", msg ? msg : (success ? "角色切换成功" : "角色切换失败"));
+    cJSON_AddItemToObject(json, "data", data);
+
+    char *json_string = cJSON_Print(json);
+    if (!json_string)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+
+    int ret = uapi_ws_send_text(json_string);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sent CharacterChangeAck: %s\n", json_string);
+    cJSON_free(json_string);
+    cJSON_Delete(json);
+    return ret;
+}
+
+/* 发送角色配置更改应答 CharacterConfigChangeAck */
+int ln_ws_send_character_config_change_ack(const char *character_id, bool success, const char *msg)
+{
+    if (ln_ws_get_connection_state() != 2)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Cannot send CharacterConfigChangeAck, connection state: %d\n", ln_ws_get_connection_state());
+        return -1;
+    }
+
+    uint32_t timestamp;
+    uapi_get_timestampe_ss(&timestamp);
+
+    cJSON *json = cJSON_CreateObject();
+    if (!json)
+        return -1;
+
+    cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+    cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+
+    char message_id[64];
+    snprintf(message_id, sizeof(message_id), "ack_config_%u", timestamp);
+    cJSON_AddStringToObject(json, "messageId", message_id);
+    cJSON_AddStringToObject(json, "command", "CharacterConfigChangeAck");
+
+    cJSON *data = cJSON_CreateObject();
+    if (!data)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+    cJSON_AddStringToObject(data, "characterId", (character_id && character_id[0]) ? character_id : "");
+    cJSON_AddBoolToObject(data, "success", success);
+    cJSON_AddStringToObject(data, "message", msg ? msg : (success ? "配置更新成功" : "配置更新失败"));
+    cJSON_AddItemToObject(json, "data", data);
+
+    char *json_string = cJSON_Print(json);
+    if (!json_string)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+
+    int ret = uapi_ws_send_text(json_string);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sent CharacterConfigChangeAck: %s\n", json_string);
+    cJSON_free(json_string);
+    cJSON_Delete(json);
+    return ret;
+}
+
+/* 发送哄睡模式开始应答 SleepModeStartAck */
+int ln_ws_send_sleep_mode_start_ack(bool success, const char *msg)
+{
+    if (ln_ws_get_connection_state() != 2)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Cannot send SleepModeStartAck, connection state: %d\n", ln_ws_get_connection_state());
+        return -1;
+    }
+
+    uint32_t timestamp;
+    uapi_get_timestampe_ss(&timestamp);
+
+    cJSON *json = cJSON_CreateObject();
+    if (!json)
+        return -1;
+
+    cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+    cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+
+    char message_id[64];
+    snprintf(message_id, sizeof(message_id), "ack_sleep_start_%u", timestamp);
+    cJSON_AddStringToObject(json, "messageId", message_id);
+    cJSON_AddStringToObject(json, "command", "SleepModeStartAck");
+
+    cJSON *data = cJSON_CreateObject();
+    if (!data)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+    cJSON_AddBoolToObject(data, "success", success);
+    cJSON_AddStringToObject(data, "message", msg ? msg : (success ? "哄睡模式已启动" : "哄睡模式启动失败"));
+    cJSON_AddItemToObject(json, "data", data);
+
+    char *json_string = cJSON_Print(json);
+    if (!json_string)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+
+    int ret = uapi_ws_send_text(json_string);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sent SleepModeStartAck: %s\n", json_string);
+    cJSON_free(json_string);
+    cJSON_Delete(json);
+    return ret;
+}
+
+/* 发送哄睡模式结束应答 SleepModeEndAck */
+int ln_ws_send_sleep_mode_end_ack(bool success, const char *msg)
+{
+    if (ln_ws_get_connection_state() != 2)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Cannot send SleepModeEndAck, connection state: %d\n", ln_ws_get_connection_state());
+        return -1;
+    }
+
+    uint32_t timestamp;
+    uapi_get_timestampe_ss(&timestamp);
+
+    cJSON *json = cJSON_CreateObject();
+    if (!json)
+        return -1;
+
+    cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+    cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+
+    char message_id[64];
+    snprintf(message_id, sizeof(message_id), "ack_sleep_end_%u", timestamp);
+    cJSON_AddStringToObject(json, "messageId", message_id);
+    cJSON_AddStringToObject(json, "command", "SleepModeEndAck");
+
+    cJSON *data = cJSON_CreateObject();
+    if (!data)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+    cJSON_AddBoolToObject(data, "success", success);
+    cJSON_AddStringToObject(data, "message", msg ? msg : (success ? "哄睡模式已结束" : "哄睡模式结束失败"));
+    cJSON_AddItemToObject(json, "data", data);
+
+    char *json_string = cJSON_Print(json);
+    if (!json_string)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+
+    int ret = uapi_ws_send_text(json_string);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sent SleepModeEndAck: %s\n", json_string);
+    cJSON_free(json_string);
+    cJSON_Delete(json);
+    return ret;
+}
+
+/* 发送日程提醒应答 ScheduleReminderAck */
+int ln_ws_send_schedule_reminder_ack(int schedule_id, bool success, const char *msg)
+{
+    if (ln_ws_get_connection_state() != 2)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Cannot send ScheduleReminderAck, connection state: %d\n", ln_ws_get_connection_state());
+        return -1;
+    }
+
+    uint32_t timestamp;
+    uapi_get_timestampe_ss(&timestamp);
+
+    cJSON *json = cJSON_CreateObject();
+    if (!json)
+        return -1;
+
+    cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+    cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+
+    char message_id[64];
+    snprintf(message_id, sizeof(message_id), "ack_reminder_%u", timestamp);
+    cJSON_AddStringToObject(json, "messageId", message_id);
+    cJSON_AddStringToObject(json, "command", "ScheduleReminderAck");
+
+    cJSON *data = cJSON_CreateObject();
+    if (!data)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+    cJSON_AddNumberToObject(data, "scheduleId", schedule_id);
+    cJSON_AddBoolToObject(data, "success", success);
+    cJSON_AddStringToObject(data, "message", msg ? msg : (success ? "提醒已播放" : "提醒播放失败"));
+    cJSON_AddItemToObject(json, "data", data);
+
+    char *json_string = cJSON_Print(json);
+    if (!json_string)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+
+    int ret = uapi_ws_send_text(json_string);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sent ScheduleReminderAck: %s\n", json_string);
+    cJSON_free(json_string);
+    cJSON_Delete(json);
+    return ret;
+}
+
+/* 发送日程提醒配置应答 ScheduleReminderConfigAck */
+int ln_ws_send_schedule_reminder_config_ack(int schedule_id, bool success, const char *msg)
+{
+    if (ln_ws_get_connection_state() != 2)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Cannot send ScheduleReminderConfigAck, connection state: %d\n", ln_ws_get_connection_state());
+        return -1;
+    }
+
+    uint32_t timestamp;
+    uapi_get_timestampe_ss(&timestamp);
+
+    cJSON *json = cJSON_CreateObject();
+    if (!json)
+        return -1;
+
+    cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+    cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+
+    char message_id[64];
+    snprintf(message_id, sizeof(message_id), "ack_reminder_config_%u", timestamp);
+    cJSON_AddStringToObject(json, "messageId", message_id);
+    cJSON_AddStringToObject(json, "command", "ScheduleReminderConfigAck");
+
+    cJSON *data = cJSON_CreateObject();
+    if (!data)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+    cJSON_AddNumberToObject(data, "scheduleId", schedule_id);
+    cJSON_AddBoolToObject(data, "success", success);
+    cJSON_AddStringToObject(data, "message", msg ? msg : (success ? "配置已更新" : "配置更新失败"));
+    cJSON_AddItemToObject(json, "data", data);
+
+    char *json_string = cJSON_Print(json);
+    if (!json_string)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+
+    int ret = uapi_ws_send_text(json_string);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sent ScheduleReminderConfigAck: %s\n", json_string);
+    cJSON_free(json_string);
+    cJSON_Delete(json);
+    return ret;
+}
+
+/* 发送删除表情应答 DeleteEmojiAck */
+int ln_ws_send_delete_emoji_ack(const char *character_id, const char *eyesColor, const char *eyesShape, bool success, const char *msg)
+{
+    if (ln_ws_get_connection_state() != 2)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Cannot send DeleteEmojiAck, connection state: %d\n", ln_ws_get_connection_state());
+        return -1;
+    }
+
+    uint32_t timestamp;
+    uapi_get_timestampe_ss(&timestamp);
+
+    cJSON *json = cJSON_CreateObject();
+    if (!json)
+        return -1;
+
+    cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+    cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+
+    char message_id[64];
+    snprintf(message_id, sizeof(message_id), "ack_delete_emoji_%u", timestamp);
+    cJSON_AddStringToObject(json, "messageId", message_id);
+    cJSON_AddStringToObject(json, "command", "DeleteEmojiAck");
+
+    cJSON *data = cJSON_CreateObject();
+    if (!data)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+    cJSON_AddStringToObject(data, "characterId", character_id ? character_id : "");
+    cJSON_AddStringToObject(data, "eyesColor", eyesColor ? eyesColor : "");
+    cJSON_AddStringToObject(data, "eyesShape", eyesShape ? eyesShape : "");
+    cJSON_AddBoolToObject(data, "success", success);
+    cJSON_AddStringToObject(data, "message", msg ? msg : (success ? "表情已删除" : "表情删除失败"));
+    cJSON_AddItemToObject(json, "data", data);
+
+    char *json_string = cJSON_Print(json);
+    if (!json_string)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+
+    int ret = uapi_ws_send_text(json_string);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sent DeleteEmojiAck: %s\n", json_string);
+    cJSON_free(json_string);
+    cJSON_Delete(json);
+    return ret;
+}
+
+/* 发送下载表情应答 DownloadEmojiAck */
+int ln_ws_send_download_emoji_ack(const char *character_id, const char *eyesColor, const char *eyesShape, bool success, const char *msg)
+{
+    if (ln_ws_get_connection_state() != 2)
+    {
+        WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Cannot send DownloadEmojiAck, connection state: %d\n", ln_ws_get_connection_state());
+        return -1;
+    }
+
+    uint32_t timestamp;
+    uapi_get_timestampe_ss(&timestamp);
+
+    cJSON *json = cJSON_CreateObject();
+    if (!json)
+        return -1;
+
+    cJSON_AddStringToObject(json, "deviceId", uapi_ln_get_device_id());
+    cJSON_AddNumberToObject(json, "timestamp", (double)timestamp);
+
+    char message_id[64];
+    snprintf(message_id, sizeof(message_id), "ack_download_emoji_%u", timestamp);
+    cJSON_AddStringToObject(json, "messageId", message_id);
+    cJSON_AddStringToObject(json, "command", "DownloadEmojiAck");
+
+    cJSON *data = cJSON_CreateObject();
+    if (!data)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+    cJSON_AddStringToObject(data, "characterId", character_id ? character_id : "");
+    cJSON_AddStringToObject(data, "eyesColor", eyesColor ? eyesColor : "");
+    cJSON_AddStringToObject(data, "eyesShape", eyesShape ? eyesShape : "");
+    cJSON_AddBoolToObject(data, "success", success);
+    cJSON_AddStringToObject(data, "message", msg ? msg : (success ? "表情下载成功" : "表情下载失败"));
+    cJSON_AddItemToObject(json, "data", data);
+
+    char *json_string = cJSON_Print(json);
+    if (!json_string)
+    {
+        cJSON_Delete(json);
+        return -1;
+    }
+
+    int ret = uapi_ws_send_text(json_string);
+    WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Sent DownloadEmojiAck: %s\n", json_string);
+    cJSON_free(json_string);
+    cJSON_Delete(json);
+    return ret;
+}
\ No newline at end of file