第11章 IOT模块控制
约 954 字大约 3 分钟
2026-03-23
1 小智后台的IOT格式要求
1.1 请求数据格式
建立信道后,设备需要向服务器发送本设备的IOT外设,以供AI调用。
{
"descriptors":
[
{
"description": "Speaker",
"methods":
{
"SetMute":
{
"description": "Set mute status",
"parameters":
{
"mute":
{
"description": "Mute status",
"type": "boolean"
}
}
},
"SetVolume":
{
"description": "Set volume level",
"parameters":
{
"volume":
{
"description": "Volume level[0-100]",
"type": "number"
}
}
}
},
"name": "Speaker",
"properties":
{
"mute":
{
"description": "Mute status",
"type": "boolean"
},
"volume":
{
"description": "Volume level[0-100]",
"type": "number"
}
}
}
],
"session_id": "e50e69eb",
"type": "iot",
"update": true
}还需要向服务器发送当前设备状态:
{
"session_id": "e50e69eb",
"states":
[
{
"name": "Speaker",
"state":
{
"mute": false,
"volume": 60
}
}
],
"type": "iot",
"update": true
}1.2 响应数据格式
这两条信息服务器不会有任何回复。这部分代码使用C语言包装非常麻烦,详见IOT控制模块。同时我们还需要再IOT控制模块实现回调,当服务器发送类似下面的调用函数JSON,我们需要调整设备相应的参数:
{
"commands":
[
{
"method": "SetVolume",
"name": "Speaker",
"parameters":
{
"volume": 100
}
}
],
"session_id": "39e871fb",
"type": "iot"
}{
"commands":
[
{
"method": "SetMute",
"name": "Speaker",
"parameters":
{
"mute": true
}
}
],
"session_id": "39e871fb",
"type": "iot"
}2 代码实现
2.1 发送学习命令和IOT状态
dri_websocket.h
/**
* @brief 发送IOT控制学习
*/
void dri_websocket_send_iot_learn(void);
/**
* @brief 发送IOT状态
*/
void dri_websocket_send_iot_status(void);dri_websocket.c
/**
* @brief 发送IOT控制学习
*/
void dri_websocket_send_iot_learn(void)
{
if (client != NULL && esp_websocket_client_is_connected(client))
{
// 准备数据
char *data1 = "{\"descriptors\":[{\"description\":\"Speaker\",\"methods\":{\"SetMute\":{\"description\":\"Set mute status\",\"parameters\":{\"mute\":{\"description\":\"Mute status\",\"type\":\"boolean\"}}},\"SetVolume\":{\"description\":\"Set volume level\",\"parameters\":{\"volume\":{\"description\":\"Volume level[0-100]\",\"type\":\"number\"}}}},\"name\":\"Speaker\",\"properties\":{\"mute\":{\"description\":\"Mute status\",\"type\":\"boolean\"},\"volume\":{\"description\":\"Volume level[0-100]\",\"type\":\"number\"}}}],\"session_id\":\"";
char *data2 = "\",\"type\":\"iot\",\"update\":true}";
// 使用heap_caps_malloc申请空间
char *json_str = heap_caps_malloc(strlen(data1) + strlen(data2) + 8, MALLOC_CAP_SPIRAM);
// 拼接字符串和session_id
memcpy(json_str, data1, strlen(data1));
memcpy(json_str + strlen(data1), session_id, 8);
memcpy(json_str + strlen(data1) + 8, data2, strlen(data2));
// 发送数据
esp_websocket_client_send_text(client, json_str, strlen(data2) + strlen(data1) + 8, portMAX_DELAY);
// 释放
free(json_str);
}
}
/**
* @brief 发送IOT状态
*/
void dri_websocket_send_iot_status(void)
{
if (client != NULL && esp_websocket_client_is_connected(client))
{
// 准备数据
char *data1 = "{\"session_id\": \"";
char *data2 = "\",\"states\": [{\"name\": \"Speaker\",\"state\": {\"mute\": false,\"volume\": 60}}],\"type\": \"iot\",\"update\": true}";
// 使用heap_caps_malloc申请空间
char *json_str = heap_caps_malloc(strlen(data1) + strlen(data2) + 8, MALLOC_CAP_SPIRAM);
// 拼接字符串和session_id
memcpy(json_str, data1, strlen(data1));
memcpy(json_str + strlen(data1), session_id, 8);
memcpy(json_str + strlen(data1) + 8, data2, strlen(data2));
// 发送数据
esp_websocket_client_send_text(client, json_str, strlen(data2) + strlen(data1) + 8, portMAX_DELAY);
// 释放
free(json_str);
}
}2.2 接收回调处理
main.c
回调函数 app_main_websocket_text_cb 中添加代码:
// 处理websocket服务器回复的文本数据的回调函数
void app_main_websocket_text_cb(char *data, size_t len)
{
// 代码省略 ...
// iot 类型的回复
else if (strcmp(type->valuestring, "iot") == 0)
{
// 拿到commands字段 值是一个数组
cJSON *commands = cJSON_GetObjectItem(root, "commands");
// 拿到commands的数组的第一个值
cJSON *command = cJSON_GetArrayItem(commands, 0);
// 拿到command中的method字段
cJSON *method = cJSON_GetObjectItem(command, "method");
// 判断method字段的值
if (strcmp(method->valuestring, "SetVolume") == 0)
{
// 拿到command中parameters字段 值是一个对象
cJSON *parameters = cJSON_GetObjectItem(command, "parameters");
// 拿到parameters中的volume字段
cJSON *volume = cJSON_GetObjectItem(parameters, "volume");
// 调用本地的改变音量大小的函数 控制
MY_LOGE("volume:%d", volume->valueint);
int_es8311_set_volume(volume->valueint);
}
else if (strcmp(method->valuestring, "SetMute") == 0)
{
// 拿到command中parameters字段 值是一个对象
cJSON *parameters = cJSON_GetObjectItem(command, "parameters");
// 拿到parameters中的mute字段
cJSON *mute = cJSON_GetObjectItem(parameters, "mute");
// 拿到mute字段的值,值的类型是boolean
bool mute_value = cJSON_IsTrue(mute);
// 调用本地的改变静音状态的函数 控制
MY_LOGE("mute:%s", mute_value ? "静音" : "非静音");
int_es8311_set_mute(mute_value);
}
}
// 释放JSON对象占用的内存
free(root);
}2.3 唤醒时候发送外设信息
main.c
回调函数 app_main_wakeup_cb 中添加代码:
// 定义检测到唤醒词次回调函数
void app_main_wakeup_cb(void)
{
MY_LOGI("AI小智被唤醒!");
// 如果档期是空闲状态,说明是第一次唤醒
if (g_current_status == IDLE)
{
// 代码省略 ...
// 发送hello消息, 获取session_id
dri_websocket_send_hello();
// 让小智学习ito命令并发送iot状态
dri_websocket_send_iot_learn();
dri_websocket_send_iot_status();
}
// 代码省略 ...
}