feat(ui): add weather and lucky color commands
This commit is contained in:
@@ -26,7 +26,9 @@ typedef enum {
|
||||
CONTROL_PLANE_MODEL_COMMAND_UNKNOWN = 0,
|
||||
CONTROL_PLANE_MODEL_COMMAND_DIRECTION,
|
||||
CONTROL_PLANE_MODEL_COMMAND_CALIBRATE,
|
||||
CONTROL_PLANE_MODEL_COMMAND_CHOUQIAN
|
||||
CONTROL_PLANE_MODEL_COMMAND_CHOUQIAN,
|
||||
CONTROL_PLANE_MODEL_COMMAND_WEATHER,
|
||||
CONTROL_PLANE_MODEL_COMMAND_LUCKY_COLOR,
|
||||
} control_plane_model_command_type_t;
|
||||
|
||||
typedef void (*control_plane_model_command_callback_t)(
|
||||
|
||||
@@ -147,6 +147,8 @@ bool control_plane_extract_model_command(const char *text,
|
||||
cJSON *direction = cJSON_GetObjectItemCaseSensitive(cmd_json, "转向");
|
||||
cJSON *calibrate = cJSON_GetObjectItemCaseSensitive(cmd_json, "校准");
|
||||
cJSON *chouqian = cJSON_GetObjectItemCaseSensitive(cmd_json, "抽签");
|
||||
cJSON *weather = cJSON_GetObjectItemCaseSensitive(cmd_json, "天气");
|
||||
cJSON *lucky_color = cJSON_GetObjectItemCaseSensitive(cmd_json, "喜色");
|
||||
|
||||
if (cJSON_IsString(direction) && direction->valuestring != NULL) {
|
||||
if (is_supported_model_direction(direction->valuestring)) {
|
||||
@@ -173,6 +175,16 @@ bool control_plane_extract_model_command(const char *text,
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
} else if (cJSON_IsString(weather) && weather->valuestring != NULL &&
|
||||
weather->valuestring[0] != '\0') {
|
||||
*out_command_type = CONTROL_PLANE_MODEL_COMMAND_WEATHER;
|
||||
strlcpy(out_value, weather->valuestring, out_value_capacity);
|
||||
found = true;
|
||||
} else if (cJSON_IsString(lucky_color) && lucky_color->valuestring != NULL &&
|
||||
lucky_color->valuestring[0] != '\0') {
|
||||
*out_command_type = CONTROL_PLANE_MODEL_COMMAND_LUCKY_COLOR;
|
||||
strlcpy(out_value, lucky_color->valuestring, out_value_capacity);
|
||||
found = true;
|
||||
}
|
||||
|
||||
cJSON_Delete(cmd_json);
|
||||
|
||||
@@ -1040,6 +1040,57 @@ static esp_err_t control_plane_run_model_calibration_motion(void)
|
||||
return control_plane_rotate_to_angle(start_angle);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *color_name;
|
||||
domain_wuxing_element_t element;
|
||||
} control_plane_lucky_color_mapping_t;
|
||||
|
||||
/*
|
||||
* Lucky-color names are intentionally mapped in one place so product changes
|
||||
* can replace colors without touching model-command parsing or LCD playback.
|
||||
*/
|
||||
static const control_plane_lucky_color_mapping_t s_lucky_color_mappings[] = {
|
||||
{"金", DOMAIN_WUXING_ELEMENT_METAL},
|
||||
{"棕", DOMAIN_WUXING_ELEMENT_WOOD},
|
||||
{"蓝", DOMAIN_WUXING_ELEMENT_WATER},
|
||||
{"红", DOMAIN_WUXING_ELEMENT_FIRE},
|
||||
{"黄", DOMAIN_WUXING_ELEMENT_EARTH},
|
||||
};
|
||||
|
||||
static bool control_plane_resolve_lucky_color(const char *color_name,
|
||||
domain_wuxing_element_t *out_element)
|
||||
{
|
||||
if (color_name == NULL || out_element == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0;
|
||||
i < sizeof(s_lucky_color_mappings) / sizeof(s_lucky_color_mappings[0]);
|
||||
++i) {
|
||||
if (strcmp(color_name, s_lucky_color_mappings[i].color_name) == 0) {
|
||||
*out_element = s_lucky_color_mappings[i].element;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static esp_err_t control_plane_show_lucky_color_expression(const char *color_name)
|
||||
{
|
||||
domain_wuxing_element_t element = DOMAIN_WUXING_ELEMENT_WATER;
|
||||
if (!control_plane_resolve_lucky_color(color_name, &element)) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
const domain_expression_request_t request = {
|
||||
.id = DOMAIN_EXPRESSION_WUXING,
|
||||
.trigger = DOMAIN_EXPRESSION_TRIGGER_MODEL_LUCKY_COLOR,
|
||||
.wuxing_element = element,
|
||||
.wuxing_element_valid = true,
|
||||
};
|
||||
return domain_runtime_request_expression(&request);
|
||||
}
|
||||
|
||||
static esp_err_t control_plane_show_chouqian_expression(size_t result_index, bool result_index_valid)
|
||||
{
|
||||
const domain_expression_request_t request = {
|
||||
@@ -1107,6 +1158,22 @@ static void control_plane_model_command_task(void *arg)
|
||||
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
||||
ESP_LOGW(TAG, "Chouqian expression failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
} else if (cmd.command_type == CONTROL_PLANE_MODEL_COMMAND_WEATHER) {
|
||||
/*
|
||||
* TODO: Request the weather LCD expression here after its assets
|
||||
* and domain expression mapping are available. Parsing and
|
||||
* dispatch stay active now to preserve the model-command contract.
|
||||
*/
|
||||
ESP_LOGI(TAG, "Weather UI pending, received model command: %s", cmd.value);
|
||||
} else if (cmd.command_type == CONTROL_PLANE_MODEL_COMMAND_LUCKY_COLOR) {
|
||||
ESP_LOGI(TAG, "Lucky color triggered by model command: %s", cmd.value);
|
||||
esp_err_t err = control_plane_show_lucky_color_expression(cmd.value);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG,
|
||||
"Show lucky-color expression failed for '%s': %s",
|
||||
cmd.value,
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -166,6 +166,15 @@ typedef enum {
|
||||
DOMAIN_EXPRESSION_OTA_UPDATE,
|
||||
} domain_expression_id_t;
|
||||
|
||||
typedef enum {
|
||||
DOMAIN_WUXING_ELEMENT_WATER = 0,
|
||||
DOMAIN_WUXING_ELEMENT_WOOD,
|
||||
DOMAIN_WUXING_ELEMENT_FIRE,
|
||||
DOMAIN_WUXING_ELEMENT_EARTH,
|
||||
DOMAIN_WUXING_ELEMENT_METAL,
|
||||
DOMAIN_WUXING_ELEMENT_COUNT,
|
||||
} domain_wuxing_element_t;
|
||||
|
||||
typedef enum {
|
||||
DOMAIN_EXPRESSION_TRIGGER_UNSPECIFIED = 0,
|
||||
DOMAIN_EXPRESSION_TRIGGER_SERVER_TASK_FAILED,
|
||||
@@ -181,6 +190,7 @@ typedef enum {
|
||||
DOMAIN_EXPRESSION_TRIGGER_SW2_DOUBLE_CLICK,
|
||||
DOMAIN_EXPRESSION_TRIGGER_LOCAL_WAKE,
|
||||
DOMAIN_EXPRESSION_TRIGGER_OTA_UPDATE,
|
||||
DOMAIN_EXPRESSION_TRIGGER_MODEL_LUCKY_COLOR,
|
||||
} domain_expression_trigger_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -189,6 +199,8 @@ typedef struct {
|
||||
size_t direction_index; /* Only used by DOMAIN_EXPRESSION_WEALTH_DIRECTION */
|
||||
size_t chouqian_result_index; /* Optional for DOMAIN_EXPRESSION_CHOUQIAN */
|
||||
bool chouqian_result_index_valid;
|
||||
domain_wuxing_element_t wuxing_element; /* Optional for DOMAIN_EXPRESSION_WUXING */
|
||||
bool wuxing_element_valid;
|
||||
} domain_expression_request_t;
|
||||
|
||||
esp_err_t domain_init(const domain_direction_axis_config_t *config,
|
||||
|
||||
@@ -96,6 +96,7 @@ typedef struct {
|
||||
uint16_t icon_y;
|
||||
} domain_wuxing_result_t;
|
||||
|
||||
/* Keep this table ordered by domain_wuxing_element_t. */
|
||||
static const domain_wuxing_result_t s_wuxing_results[] = {
|
||||
{.asset_dir = "shui", .icon_id = 0, .icon_x = 124, .icon_y = 8},
|
||||
{.asset_dir = "mu", .icon_id = 1, .icon_x = 217, .icon_y = 92},
|
||||
@@ -104,6 +105,10 @@ static const domain_wuxing_result_t s_wuxing_results[] = {
|
||||
{.asset_dir = "jin", .icon_id = 4, .icon_x = 18, .icon_y = 102},
|
||||
};
|
||||
|
||||
_Static_assert(sizeof(s_wuxing_results) / sizeof(s_wuxing_results[0]) ==
|
||||
DOMAIN_WUXING_ELEMENT_COUNT,
|
||||
"Wuxing result assets must match domain_wuxing_element_t");
|
||||
|
||||
/*
|
||||
* Wealth-direction reveal asset directories, indexed parallel to the direction
|
||||
* catalog order in components/domain/src/direction/domain_direction_catalog.c
|
||||
@@ -1461,7 +1466,18 @@ static esp_err_t domain_resolve_expression_platform_request(
|
||||
if (request->id == DOMAIN_EXPRESSION_WUXING) {
|
||||
static platform_lcd_presentation_step_t s_wuxing_steps[3];
|
||||
const size_t result_count = sizeof(s_wuxing_results) / sizeof(s_wuxing_results[0]);
|
||||
const domain_wuxing_result_t *result = &s_wuxing_results[esp_random() % result_count];
|
||||
size_t result_index = esp_random() % result_count;
|
||||
if (request->wuxing_element_valid) {
|
||||
if ((size_t)request->wuxing_element >= result_count) {
|
||||
ESP_LOGW(TAG,
|
||||
"Wuxing element out of range: %u (max %u)",
|
||||
(unsigned int)request->wuxing_element,
|
||||
(unsigned int)result_count);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
result_index = (size_t)request->wuxing_element;
|
||||
}
|
||||
const domain_wuxing_result_t *result = &s_wuxing_results[result_index];
|
||||
|
||||
s_wuxing_steps[0] = (platform_lcd_presentation_step_t) {
|
||||
.asset_dir = "qianzhiwuxing",
|
||||
|
||||
Reference in New Issue
Block a user