esp-openclaw-node/examples/common/esp_openclaw_node_common_device_node_cmd.c

253 lines
7.7 KiB
C

/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_openclaw_node_common_device_node_cmd.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "cJSON.h"
#include "esp_app_desc.h"
#include "esp_check.h"
#include "esp_chip_info.h"
#include "esp_heap_caps.h"
#include "esp_mac.h"
#include "esp_system.h"
#include "esp_timer.h"
#include "esp_wifi.h"
#include "esp_openclaw_node_example_json.h"
#include "esp_openclaw_node_wifi.h"
static const char *TAG = "esp_openclaw_node_device_cmd";
static void bytes_to_lower_hex(const uint8_t *input, size_t input_len, char *output, size_t output_size)
{
static const char HEX[] = "0123456789abcdef";
if (output_size < (input_len * 2U) + 1U) {
if (output_size > 0) {
output[0] = '\0';
}
return;
}
for (size_t i = 0; i < input_len; ++i) {
output[(i * 2U)] = HEX[(input[i] >> 4) & 0x0f];
output[(i * 2U) + 1U] = HEX[input[i] & 0x0f];
}
output[input_len * 2U] = '\0';
}
static const char *firmware_version(void)
{
return esp_app_get_description()->version;
}
static const char *wifi_auth_mode_name(uint8_t authmode)
{
switch ((wifi_auth_mode_t)authmode) {
case WIFI_AUTH_OPEN:
return "open";
case WIFI_AUTH_WEP:
return "wep";
case WIFI_AUTH_WPA_PSK:
return "wpa-psk";
case WIFI_AUTH_WPA2_PSK:
return "wpa2-psk";
case WIFI_AUTH_WPA_WPA2_PSK:
return "wpa-wpa2-psk";
case WIFI_AUTH_WPA2_ENTERPRISE:
return "wpa2-enterprise";
case WIFI_AUTH_WPA3_PSK:
return "wpa3-psk";
case WIFI_AUTH_WPA2_WPA3_PSK:
return "wpa2-wpa3-psk";
case WIFI_AUTH_WAPI_PSK:
return "wapi-psk";
default:
return "unknown";
}
}
static void format_mac_address(const uint8_t mac[6], char *buffer, size_t buffer_size)
{
snprintf(
buffer,
buffer_size,
"%02x:%02x:%02x:%02x:%02x:%02x",
mac[0],
mac[1],
mac[2],
mac[3],
mac[4],
mac[5]);
}
static void add_wifi_status_fields(cJSON *object)
{
esp_openclaw_node_wifi_status_t wifi = {0};
esp_openclaw_node_wifi_get_status(&wifi);
cJSON_AddBoolToObject(object, "connected", wifi.connected);
cJSON_AddStringToObject(object, "ssid", wifi.ssid);
if (wifi.ip[0] != '\0') {
cJSON_AddStringToObject(object, "ip", wifi.ip);
cJSON_AddStringToObject(object, "netmask", wifi.netmask);
cJSON_AddStringToObject(object, "gateway", wifi.gateway);
}
if (wifi.connected) {
cJSON_AddNumberToObject(object, "rssi", wifi.rssi);
cJSON_AddNumberToObject(object, "channel", wifi.channel);
cJSON_AddStringToObject(object, "authMode", wifi_auth_mode_name(wifi.authmode));
}
if (wifi.last_disconnect_reason != 0) {
cJSON_AddNumberToObject(object, "lastDisconnectReason", wifi.last_disconnect_reason);
}
}
static cJSON *build_device_info_payload(esp_openclaw_node_handle_t node)
{
const char *device_id = esp_openclaw_node_get_device_id(node);
const esp_app_desc_t *app = esp_app_get_description();
esp_chip_info_t chip = {0};
esp_chip_info(&chip);
uint8_t mac[6] = {0};
char mac_text[18] = {0};
char app_sha256[65] = {0};
esp_read_mac(mac, ESP_MAC_WIFI_STA);
format_mac_address(mac, mac_text, sizeof(mac_text));
bytes_to_lower_hex(app->app_elf_sha256, sizeof(app->app_elf_sha256), app_sha256, sizeof(app_sha256));
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "deviceId", device_id != NULL ? device_id : "");
cJSON_AddStringToObject(root, "firmwareVersion", firmware_version());
cJSON_AddStringToObject(root, "idfVersion", esp_get_idf_version());
cJSON_AddStringToObject(root, "chipModel", CONFIG_IDF_TARGET);
cJSON_AddNumberToObject(root, "chipRevision", chip.revision);
cJSON_AddNumberToObject(root, "cores", chip.cores);
cJSON_AddStringToObject(root, "projectName", app->project_name);
cJSON_AddStringToObject(root, "appVersion", app->version);
cJSON_AddStringToObject(root, "appElfSha256", app_sha256);
cJSON_AddStringToObject(root, "wifiMac", mac_text);
return root;
}
static cJSON *build_device_status_payload(esp_openclaw_node_handle_t node)
{
cJSON *root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "uptimeMs", esp_timer_get_time() / 1000LL);
cJSON_AddNumberToObject(root, "freeHeap", esp_get_free_heap_size());
cJSON_AddNumberToObject(root, "minFreeHeap", esp_get_minimum_free_heap_size());
cJSON_AddNumberToObject(
root,
"largestFreeBlock",
heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
cJSON_AddBoolToObject(root, "savedSessionAvailable", esp_openclaw_node_has_saved_session(node));
cJSON *wifi = cJSON_CreateObject();
add_wifi_status_fields(wifi);
cJSON_AddItemToObject(root, "wifi", wifi);
return root;
}
static cJSON *build_wifi_status_payload(void)
{
cJSON *root = cJSON_CreateObject();
add_wifi_status_fields(root);
return root;
}
static esp_err_t handle_device_info(
esp_openclaw_node_handle_t node,
void *context,
const char *params_json,
size_t params_len,
char **out_payload_json,
esp_openclaw_node_error_t *out_error)
{
(void)context;
(void)params_json;
(void)params_len;
(void)out_error;
return esp_openclaw_node_example_take_json_payload(
build_device_info_payload(node),
out_payload_json);
}
static esp_err_t handle_device_status(
esp_openclaw_node_handle_t node,
void *context,
const char *params_json,
size_t params_len,
char **out_payload_json,
esp_openclaw_node_error_t *out_error)
{
(void)context;
(void)params_json;
(void)params_len;
(void)out_error;
return esp_openclaw_node_example_take_json_payload(
build_device_status_payload(node),
out_payload_json);
}
static esp_err_t handle_wifi_status(
esp_openclaw_node_handle_t node,
void *context,
const char *params_json,
size_t params_len,
char **out_payload_json,
esp_openclaw_node_error_t *out_error)
{
(void)node;
(void)context;
(void)params_json;
(void)params_len;
(void)out_error;
return esp_openclaw_node_example_take_json_payload(
build_wifi_status_payload(),
out_payload_json);
}
esp_err_t esp_openclaw_node_common_register_device_node_commands(esp_openclaw_node_handle_t node)
{
static const esp_openclaw_node_command_t DEVICE_INFO_COMMAND = {
.name = "device.info",
.handler = handle_device_info,
.context = NULL,
};
static const esp_openclaw_node_command_t DEVICE_STATUS_COMMAND = {
.name = "device.status",
.handler = handle_device_status,
.context = NULL,
};
static const esp_openclaw_node_command_t WIFI_STATUS_COMMAND = {
.name = "wifi.status",
.handler = handle_wifi_status,
.context = NULL,
};
ESP_RETURN_ON_ERROR(
esp_openclaw_node_register_capability(node, "device"),
TAG,
"registering device capability failed");
ESP_RETURN_ON_ERROR(
esp_openclaw_node_register_capability(node, "wifi"),
TAG,
"registering wifi capability failed");
ESP_RETURN_ON_ERROR(
esp_openclaw_node_register_command(node, &DEVICE_INFO_COMMAND),
TAG,
"registering device.info failed");
ESP_RETURN_ON_ERROR(
esp_openclaw_node_register_command(node, &DEVICE_STATUS_COMMAND),
TAG,
"registering device.status failed");
ESP_RETURN_ON_ERROR(
esp_openclaw_node_register_command(node, &WIFI_STATUS_COMMAND),
TAG,
"registering wifi.status failed");
return ESP_OK;
}