Files
iot_skeleton/esp32/main/protocol.cpp
2026-04-22 20:11:55 +03:00

215 lines
4.7 KiB
C++

#include "protocol.h"
#include "ws.h"
#include <stdio.h>
#include <stdarg.h>
#include <inttypes.h>
#define PROTOCOL_VERSION 1
static uint32_t msg_id = 1;
static inline int append(char* buf, size_t size, int pos, const char* fmt, ...)
{
if ((size_t)pos >= size) return -1;
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;
}
return pos + written;
}
int build_telemetry(
char* buf,
size_t buf_size,
int64_t ts,
uint32_t device_id,
const char* metric,
const char* source,
const char* unit,
const int* values,
size_t count
)
{
int pos = 0;
// --- header ---
pos = append(buf, buf_size, pos,
"{\"v\":1,\"t\":\"t\",\"id\":%lu,\"ts\":%lld,\"d\":%lu,\"p\":{",
(unsigned long)protocol_next_id(),
(long long)ts,
(unsigned long)device_id
);
if (pos < 0) return -1;
// --- payload meta ---
pos = append(buf, buf_size, pos,
"\"m\":\"%s\",\"s\":\"%s\",\"u\":\"%s\",\"v\":[",
metric,
source,
unit
);
if (pos < 0) return -1;
// --- values ---
for (size_t i = 0; i < count ; i ++)
{
pos = append(buf, buf_size, pos,
"[%u,%d]%s",
values[i*2 + 0], // delta time
values[i*2 + 1],
(i < count - 1) ? "," : ""
);
if (pos < 0) return -1;
}
// --- close ---
pos = append(buf, buf_size, pos, "]}}");
if (pos < 0) return -1;
return pos;
}
__attribute__((deprecated))
// --- 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;
// 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;
// measurement start
pos = append(buf, buf_size, pos,
"{\"metric\":\"%s\",\"value\":%.3f",
metric,
value
);
if (pos < 0) return -1;
// optional
if (unit)
{
pos = append(buf, buf_size, pos, ",\"unit\":\"%s\"", unit);
if (pos < 0) return -1;
}
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;
}
__attribute__((deprecated))
// --- 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;
}
uint32_t protocol_next_id()
{
return msg_id++;
};
void protocol_send_event_hb(int64_t ts)
{
// формируешь JSON строго по контракту
// пример:
char buf[128];
uint32_t id = protocol_next_id();
snprintf(buf, sizeof(buf),
"{\"v\":1,\"id\":%" PRIu32 ",\"t\":\"e\",\"ts\":%" PRIu64 ",\"d\":%u,\"p\":{\"type\":\"hb\"}}",
id, ts, CONFIG_DEVICE_ID);
ws_send(buf);
}
bool protocol_is_connected()
{
return ws_is_connected();
}