diff --git a/esp32/main/CMakeLists.txt b/esp32/main/CMakeLists.txt index 2e8421e..46b04b8 100644 --- a/esp32/main/CMakeLists.txt +++ b/esp32/main/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( - SRCS "main.cpp" "protocol.cpp" "protocol_test.cpp" "wifi_manager.cpp" "system_init.cpp" "time_sync.cpp" + SRCS "main.cpp" "protocol.cpp" "wifi_manager.cpp" "system_init.cpp" "time_sync.cpp" INCLUDE_DIRS "." REQUIRES nvs_flash esp_wifi esp_netif freertos log cjson esp_timer ) diff --git a/esp32/main/main.cpp b/esp32/main/main.cpp index 9902b36..1e3eef2 100644 --- a/esp32/main/main.cpp +++ b/esp32/main/main.cpp @@ -1,8 +1,9 @@ +#include "esp_log.h" #include "system_init.h" -#include "protocol_test.h" #include "freertos/FreeRTOS.h" #include "freertos/projdefs.h" #include "freertos/task.h" +#include "protocol.h" static const char* TAG = "iot_fish"; @@ -10,9 +11,14 @@ extern "C" void app_main(void) { system_init(); - for (int i=0; i<10; i++) + for (int i=0; i<5; i++) { - protocol_run_tests(); + char buf[512]; + int len = build_telemetry_single(buf, sizeof(buf), "123", "dev1", 123456, "temperature", 22.5, "C", nullptr, 0); + + if (len > 0) { + ESP_LOGI("protocol", "%s\n", buf); + } vTaskDelay(pdMS_TO_TICKS(1000)); } diff --git a/esp32/main/protocol.cpp b/esp32/main/protocol.cpp index 61ebe0d..683da8b 100644 --- a/esp32/main/protocol.cpp +++ b/esp32/main/protocol.cpp @@ -1,52 +1,123 @@ #include "protocol.h" -#include "cJSON.h" +#include +#include -cJSON* protocol_message_to_json(const ProtocolMessage* msg) { - cJSON* root = cJSON_CreateObject(); +#define PROTOCOL_VERSION 1 - cJSON_AddNumberToObject(root, "v", msg->v); - cJSON_AddStringToObject(root, "id", msg->id.c_str()); - cJSON_AddStringToObject(root, "type", msg->type.c_str()); - cJSON_AddNumberToObject(root, "ts", msg->ts); - cJSON_AddStringToObject(root, "deviceId", msg->deviceId.c_str()); +static inline int append(char* buf, size_t size, int pos, const char* fmt, ...) { + if ((size_t)pos >= size) return -1; - cJSON* payload_obj = nullptr; - if (msg->payload) { - payload_obj = cJSON_Duplicate(msg->payload, 1); // deep copy - } else { - payload_obj = cJSON_CreateObject(); + va_list args; + va_start(args, fmt); + int written = vsnprintf(buf + pos, size - pos, fmt, args); + va_end(args); + + if (written < 0 || (size_t)(pos + written) >= size) { + return -1; } - cJSON_AddItemToObject(root, "payload", payload_obj); - return root; + return pos + written; } -ProtocolMessage protocol_message_from_json(const cJSON* root) { - ProtocolMessage msg; +// --- TELEMETRY (single measurement) --- +int build_telemetry_single( + char* buf, + size_t buf_size, + const char* id, + const char* device_id, + int64_t ts_ms, + const char* metric, + double value, + const char* unit, + const char* source, + int64_t m_ts_ms +) { + int pos = 0; - const cJSON* item = nullptr; + // header + pos = append(buf, buf_size, pos, + "{\"v\":%d,\"id\":\"%s\",\"type\":\"telemetry\",\"ts\":%lld," + "\"deviceId\":\"%s\",\"payload\":{\"measurements\":[", + PROTOCOL_VERSION, + id, + (long long)ts_ms, + device_id + ); + if (pos < 0) return -1; - item = cJSON_GetObjectItem(root, "v"); - if (item && cJSON_IsNumber(item)) msg.v = item->valueint; + // measurement start + pos = append(buf, buf_size, pos, + "{\"metric\":\"%s\",\"value\":%.3f", + metric, + value + ); + if (pos < 0) return -1; - item = cJSON_GetObjectItem(root, "id"); - if (item && cJSON_IsString(item)) msg.id = item->valuestring; - - item = cJSON_GetObjectItem(root, "type"); - if (item && cJSON_IsString(item)) msg.type = item->valuestring; - - item = cJSON_GetObjectItem(root, "ts"); - if (item && cJSON_IsNumber(item)) msg.ts = item->valuedouble; // uint64_t - - item = cJSON_GetObjectItem(root, "deviceId"); - if (item && cJSON_IsString(item)) msg.deviceId = item->valuestring; - - item = cJSON_GetObjectItem(root, "payload"); - if (item && cJSON_IsObject(item)) { - msg.payload = cJSON_Duplicate(item, 1); // deep copy - } else { - msg.payload = cJSON_CreateObject(); + // optional + if (unit) { + pos = append(buf, buf_size, pos, ",\"unit\":\"%s\"", unit); + if (pos < 0) return -1; } - return msg; + if (source) { + pos = append(buf, buf_size, pos, ",\"source\":\"%s\"", source); + if (pos < 0) return -1; + } + + if (m_ts_ms > 0) { + pos = append(buf, buf_size, pos, ",\"ts\":%lld", (long long)m_ts_ms); + if (pos < 0) return -1; + } + + // close measurement + payload + pos = append(buf, buf_size, pos, "}]}}"); + if (pos < 0) return -1; + + return pos; +} + +// --- EVENT --- +int build_event( + char* buf, + size_t buf_size, + const char* id, + const char* device_id, + int64_t ts_ms, + const char* name, + const char* severity, + const char* message +) { + int pos = 0; + + // header + pos = append(buf, buf_size, pos, + "{\"v\":%d,\"id\":\"%s\",\"type\":\"event\",\"ts\":%lld," + "\"deviceId\":\"%s\",\"payload\":{", + PROTOCOL_VERSION, + id, + (long long)ts_ms, + device_id + ); + if (pos < 0) return -1; + + // required + pos = append(buf, buf_size, pos, "\"name\":\"%s\"", name); + if (pos < 0) return -1; + + // optional + if (severity) { + pos = append(buf, buf_size, pos, ",\"severity\":\"%s\"", severity); + if (pos < 0) return -1; + } + + if (message) { + pos = append(buf, buf_size, pos, ",\"message\":\"%s\"", message); + if (pos < 0) return -1; + } + + // close + pos = append(buf, buf_size, pos, "}}"); + if (pos < 0) return -1; + + return pos; } \ No newline at end of file diff --git a/esp32/main/protocol.h b/esp32/main/protocol.h index 4d91d40..59a4fc7 100644 --- a/esp32/main/protocol.h +++ b/esp32/main/protocol.h @@ -1,18 +1,36 @@ #pragma once -#include "cJSON.h" -#include -struct ProtocolMessage { - int v; - std::string id; - std::string type; - uint64_t ts; - std::string deviceId; // C++ строка - cJSON* payload; -}; +#include +#include -// Создание JSON из структуры -cJSON* protocol_message_to_json(const ProtocolMessage *msg); +#ifdef __cplusplus +extern "C" { +#endif -// Разбор JSON в структуру -int protocol_json_to_message(const char *json_str, ProtocolMessage *msg); \ No newline at end of file +int build_telemetry_single( + char* buf, + size_t buf_size, + const char* id, + const char* device_id, + int64_t ts_ms, + const char* metric, + double value, + const char* unit, // optional (NULL) + const char* source, // optional (NULL) + int64_t m_ts_ms // optional (0 = нет) +); + +int build_event( + char* buf, + size_t buf_size, + const char* id, + const char* device_id, + int64_t ts_ms, + const char* name, + const char* severity, // optional + const char* message // optional +); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/esp32/main/protocol_test.cpp b/esp32/main/protocol_test.cpp deleted file mode 100644 index cba1918..0000000 --- a/esp32/main/protocol_test.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "protocol_test.h" - -#include "protocol.h" -#include "cJSON.h" -#include "esp_log.h" -#include "esp_timer.h" - -static const char* TAG = "protocol_test"; - -void protocol_run_tests() -{ - ESP_LOGI(TAG, "Running protocol test..."); - - ProtocolMessage msg; - msg.v = 1; - msg.id = "msg-001"; - msg.type = "command"; - msg.deviceId = "esp32-01"; - msg.ts = esp_timer_get_time(); - - msg.payload = cJSON_CreateObject(); - cJSON_AddStringToObject(msg.payload, "command", "ping"); - - cJSON* json = protocol_message_to_json(&msg); - char* json_str = cJSON_Print(json); - - ESP_LOGI(TAG, "ProtocolMessage JSON:\n%s", json_str); - - cJSON_Delete(json); - free(json_str); - cJSON_Delete(msg.payload); -} diff --git a/esp32/main/protocol_test.h b/esp32/main/protocol_test.h deleted file mode 100644 index 6101e43..0000000 --- a/esp32/main/protocol_test.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void protocol_run_tests(); \ No newline at end of file diff --git a/esp32/sdkconfig.defaults b/esp32/sdkconfig.defaults new file mode 100644 index 0000000..a46a58c --- /dev/null +++ b/esp32/sdkconfig.defaults @@ -0,0 +1,6 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 6.0.0 Project Minimal Configuration +# +CONFIG_WIFI_SSID="IoT_ext" +CONFIG_WIFI_PASS="s1SgU2W3d5UEQi" +CONFIG_SERVER_HOST="192.168.17.90" diff --git a/esp32/sdkconfig.defaults.bak b/esp32/sdkconfig.defaults.bak new file mode 100644 index 0000000..a46a58c --- /dev/null +++ b/esp32/sdkconfig.defaults.bak @@ -0,0 +1,6 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 6.0.0 Project Minimal Configuration +# +CONFIG_WIFI_SSID="IoT_ext" +CONFIG_WIFI_PASS="s1SgU2W3d5UEQi" +CONFIG_SERVER_HOST="192.168.17.90" diff --git a/esp32/sdkconfig.defaults.esp32 b/esp32/sdkconfig.defaults.esp32 new file mode 100644 index 0000000..b003eda --- /dev/null +++ b/esp32/sdkconfig.defaults.esp32 @@ -0,0 +1 @@ +CONFIG_ESP_CONSOLE_UART=y \ No newline at end of file diff --git a/esp32/sdkconfig.defaults.esp32s2 b/esp32/sdkconfig.defaults.esp32s2 new file mode 100644 index 0000000..7862a9c --- /dev/null +++ b/esp32/sdkconfig.defaults.esp32s2 @@ -0,0 +1,12 @@ + # This file was generated using idf.py save-defconfig. It can be edited manually. + # Espressif IoT Development Framework (ESP-IDF) 6.0.0 Project Minimal Configuration + # + # default: +CONFIG_IDF_TARGET="esp32s2" +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESP_CONSOLE_USB_CDC=y +CONFIG_ESP_CONSOLE_USB_CDC_RX_BUF_SIZE=128 +CONFIG_ESP_CONSOLE_USB_CDC_SUPPORT_ETS_PRINTF=y +CONFIG_WIFI_SSID="IoT_ext" +CONFIG_WIFI_PASS="s1SgU2W3d5UEQi" +CONFIG_SERVER_HOST="192.168.17.90"