Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion components/ts_api/src/ts_api_automation.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "ts_variable.h"
#include "ts_rule_engine.h"
#include "ts_source_manager.h"
#include "ts_temp_source.h"
#include "ts_action_manager.h"
#include "ts_config_pack.h"
#include "ts_cert.h"
Expand All @@ -29,6 +30,7 @@
#include "esp_heap_caps.h"
#include "esp_crt_bundle.h"
#include "esp_log.h"
#include "esp_timer.h"
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
Expand Down Expand Up @@ -219,15 +221,53 @@ static esp_err_t api_automation_variables_list(const cJSON *params, ts_api_resul
{
result->data = cJSON_CreateObject();
cJSON *vars_array = cJSON_AddArrayToObject(result->data, "variables");
int64_t now_ms = esp_timer_get_time() / 1000;
const char *prefix = NULL;
const char *source_id = NULL;
size_t prefix_len = 0;
bool include_value = true;
bool include_meta = true;

if (params) {
cJSON *prefix_param = cJSON_GetObjectItem(params, "prefix");
if (prefix_param && cJSON_IsString(prefix_param) && prefix_param->valuestring) {
prefix = prefix_param->valuestring;
prefix_len = strlen(prefix);
}

cJSON *source_id_param = cJSON_GetObjectItem(params, "source_id");
if (source_id_param && cJSON_IsString(source_id_param) && source_id_param->valuestring) {
source_id = source_id_param->valuestring;
}

cJSON *include_value_param = cJSON_GetObjectItem(params, "include_value");
if (include_value_param && cJSON_IsBool(include_value_param)) {
include_value = cJSON_IsTrue(include_value_param);
}

cJSON *include_meta_param = cJSON_GetObjectItem(params, "include_meta");
if (include_meta_param && cJSON_IsBool(include_meta_param)) {
include_meta = cJSON_IsTrue(include_meta_param);
}
}

// 遍历所有变量(使用内部迭代器)
ts_variable_iterate_ctx_t ctx = {0};
ts_auto_variable_t var;

while (ts_variable_iterate(&ctx, &var) == ESP_OK) {
if (prefix_len > 0 && strncmp(var.name, prefix, prefix_len) != 0) {
continue;
}
if (source_id && strcmp(var.source_id, source_id) != 0) {
continue;
}

cJSON *var_obj = cJSON_CreateObject();
cJSON_AddStringToObject(var_obj, "name", var.name);
cJSON_AddItemToObject(var_obj, "value", value_to_json(&var.value));
if (include_value) {
cJSON_AddItemToObject(var_obj, "value", value_to_json(&var.value));
}

// 类型字符串
const char *type_str = "null";
Expand All @@ -241,6 +281,20 @@ static esp_err_t api_automation_variables_list(const cJSON *params, ts_api_resul
cJSON_AddStringToObject(var_obj, "type", type_str);
cJSON_AddBoolToObject(var_obj, "persistent", (var.flags & TS_AUTO_VAR_PERSISTENT) != 0);
cJSON_AddBoolToObject(var_obj, "readonly", (var.flags & TS_AUTO_VAR_READONLY) != 0);
if (include_meta) {
cJSON_AddNumberToObject(var_obj, "last_change_ms", (double)var.last_change_ms);
cJSON_AddNumberToObject(var_obj, "last_update_ms", (double)var.last_update_ms);
if (var.last_update_ms > 0) {
int64_t age_ms = now_ms - var.last_update_ms;
bool stale = (age_ms < 0 || age_ms > TS_TEMP_DATA_TIMEOUT_MS);
if (age_ms < 0) age_ms = 0;
cJSON_AddNumberToObject(var_obj, "age_ms", (double)age_ms);
cJSON_AddBoolToObject(var_obj, "stale", stale);
} else {
cJSON_AddNullToObject(var_obj, "age_ms");
cJSON_AddBoolToObject(var_obj, "stale", true);
}
}

if (var.source_id[0] != '\0') {
cJSON_AddStringToObject(var_obj, "source_id", var.source_id);
Expand Down
29 changes: 27 additions & 2 deletions components/ts_api/src/ts_api_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@ static const char *fan_mode_to_str(ts_fan_mode_t mode)
case TS_FAN_MODE_OFF: return "off";
case TS_FAN_MODE_MANUAL: return "manual";
case TS_FAN_MODE_AUTO: return "auto";
case TS_FAN_MODE_CURVE: return "curve";
default: return "unknown";
}
}

static const char *fan_auto_state_to_str(ts_fan_auto_state_t state)
{
switch (state) {
case TS_FAN_AUTO_STATE_IDLE: return "idle";
case TS_FAN_AUTO_STATE_BASELINE: return "baseline";
case TS_FAN_AUTO_STATE_ACTIVE: return "active";
case TS_FAN_AUTO_STATE_GUARD: return "guard";
case TS_FAN_AUTO_STATE_STALE: return "stale";
default: return "unknown";
}
}
Expand Down Expand Up @@ -215,6 +228,15 @@ static esp_err_t api_device_fan_status(const cJSON *params, ts_api_result_t *res
cJSON_AddNumberToObject(fan, "rpm", status.rpm);
cJSON_AddNumberToObject(fan, "temp", status.temp / 10.0);
cJSON_AddBoolToObject(fan, "running", status.is_running);
cJSON_AddNumberToObject(fan, "control_temperature", status.control_temp / 10.0);
cJSON_AddNumberToObject(fan, "guard_temperature", status.guard_temp / 10.0);
cJSON_AddNumberToObject(fan, "predicted_temperature", status.predicted_temp / 10.0);
cJSON_AddNumberToObject(fan, "slope_c_per_min", status.slope_c_per_min);
cJSON_AddNumberToObject(fan, "controller_gain", status.controller_gain);
cJSON_AddNumberToObject(fan, "cooling_response", status.cooling_response);
cJSON_AddStringToObject(fan, "auto_state", fan_auto_state_to_str(status.auto_state));
cJSON_AddBoolToObject(fan, "guard_active", status.guard_active);
cJSON_AddBoolToObject(fan, "temp_stale", status.temp_stale);
cJSON_AddItemToArray(fans, fan);
}
}
Expand All @@ -226,7 +248,7 @@ static esp_err_t api_device_fan_status(const cJSON *params, ts_api_result_t *res
/**
* @brief device.fan.set - Set fan parameters
* @param fan: fan id
* @param mode: "off", "manual", "auto"
* @param mode: "off", "manual", "auto", "curve"
* @param duty: duty cycle (0-100) for manual mode
*/
static esp_err_t api_device_fan_set(const cJSON *params, ts_api_result_t *result)
Expand Down Expand Up @@ -254,6 +276,8 @@ static esp_err_t api_device_fan_set(const cJSON *params, ts_api_result_t *result
fan_mode = TS_FAN_MODE_MANUAL;
} else if (strcmp(mode->valuestring, "auto") == 0) {
fan_mode = TS_FAN_MODE_AUTO;
} else if (strcmp(mode->valuestring, "curve") == 0) {
fan_mode = TS_FAN_MODE_CURVE;
} else {
ts_api_result_error(result, TS_API_ERR_INVALID_ARG, "Invalid mode");
return ESP_ERR_INVALID_ARG;
Expand All @@ -264,7 +288,8 @@ static esp_err_t api_device_fan_set(const cJSON *params, ts_api_result_t *result
cJSON *duty = cJSON_GetObjectItem(params, "duty");
if (ret == ESP_OK && duty && cJSON_IsNumber(duty)) {
int duty_val = (int)cJSON_GetNumberValue(duty);
if (duty_val >= 0 && duty_val <= 100) {
if ((!mode || !cJSON_IsString(mode) || strcmp(mode->valuestring, "manual") == 0) &&
duty_val >= 0 && duty_val <= 100) {
ret = ts_fan_set_duty(fan_id, duty_val);
}
}
Expand Down
26 changes: 23 additions & 3 deletions components/ts_api/src/ts_api_fan.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ static const char *mode_to_string(ts_fan_mode_t mode)
}
}

static const char *auto_state_to_string(ts_fan_auto_state_t state)
{
switch (state) {
case TS_FAN_AUTO_STATE_IDLE: return "idle";
case TS_FAN_AUTO_STATE_BASELINE: return "baseline";
case TS_FAN_AUTO_STATE_ACTIVE: return "active";
case TS_FAN_AUTO_STATE_GUARD: return "guard";
case TS_FAN_AUTO_STATE_STALE: return "stale";
default: return "unknown";
}
}

static ts_fan_mode_t string_to_mode(const char *str)
{
if (!str) return TS_FAN_MODE_MANUAL;
Expand All @@ -53,6 +65,15 @@ static cJSON *status_to_json(ts_fan_id_t fan_id, const ts_fan_status_t *status)
cJSON_AddBoolToObject(obj, "enabled", status->enabled);
cJSON_AddBoolToObject(obj, "running", status->is_running);
cJSON_AddBoolToObject(obj, "fault", status->fault);
cJSON_AddNumberToObject(obj, "control_temperature", status->control_temp / 10.0);
cJSON_AddNumberToObject(obj, "guard_temperature", status->guard_temp / 10.0);
cJSON_AddNumberToObject(obj, "predicted_temperature", status->predicted_temp / 10.0);
cJSON_AddNumberToObject(obj, "slope_c_per_min", status->slope_c_per_min);
cJSON_AddNumberToObject(obj, "controller_gain", status->controller_gain);
cJSON_AddNumberToObject(obj, "cooling_response", status->cooling_response);
cJSON_AddStringToObject(obj, "auto_state", auto_state_to_string(status->auto_state));
cJSON_AddBoolToObject(obj, "guard_active", status->guard_active);
cJSON_AddBoolToObject(obj, "temp_stale", status->temp_stale);
return obj;
}

Expand Down Expand Up @@ -102,9 +123,8 @@ static esp_err_t api_fan_status(const cJSON *params, ts_api_result_t *result)
/* 添加全局温度信息(从绑定变量读取) */
ts_temp_status_t temp_status;
if (ts_temp_get_status(&temp_status) == ESP_OK) {
float temp_c = temp_status.current_temp / 10.0f;
cJSON_AddNumberToObject(data, "temperature", temp_c);
cJSON_AddBoolToObject(data, "temp_valid", temp_status.current_temp > -400); // > -40°C 表示有效
cJSON_AddNumberToObject(data, "temperature", temp_status.current_temp / 10.0f);
cJSON_AddBoolToObject(data, "temp_valid", temp_status.current_valid);
if (temp_status.bound_variable[0] != '\0') {
cJSON_AddStringToObject(data, "temp_source", temp_status.bound_variable);
}
Expand Down
Loading
Loading