feat(mqtt): enhance timestamp formatting with microsecond precision
Updated the MQTTMessageBuilder to include microsecond precision in the timestamp formatting. The formatIsoTimestampForMqtt function now accepts a microsecond parameter, allowing for more accurate time representation. Modified related functions in MQTTBridge to utilize the new timestamp formatting, ensuring consistency across MQTT messages.
This commit is contained in:
1 parent
50154563ba
commit
618c849d53
3 files changed
+43
-15
No files matched your search
@@ -3,18 +3,26 @@
|
||||
#include <cstring>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <Timezone.h>
|
||||
#include "MeshCore.h"
|
||||
|
||||
void MQTTMessageBuilder::formatIsoTimestampForMqtt(time_t now, Timezone* timezone, char* buffer, size_t buffer_size) {
|
||||
void MQTTMessageBuilder::formatIsoTimestampForMqtt(time_t now, long usec, Timezone* timezone, char* buffer, size_t buffer_size) {
|
||||
if (!buffer || buffer_size == 0) return;
|
||||
// Always emit UTC with an explicit "+00:00" offset, matching Python's
|
||||
// datetime.now(timezone.utc).isoformat(). The system clock is UTC (SNTP offset 0),
|
||||
// so gmtime() is correct regardless of the prefs Timezone (now unused here).
|
||||
(void)timezone;
|
||||
// Clamp the sub-second to a valid microsecond range so the "%06ld" field can never
|
||||
// overflow to 7 digits or go negative on a bad clock read.
|
||||
if (usec < 0) usec = 0;
|
||||
else if (usec > 999999) usec = 999999;
|
||||
struct tm* tm_info = gmtime(&now);
|
||||
if (tm_info && strftime(buffer, buffer_size, "%Y-%m-%dT%H:%M:%S.000000+00:00", tm_info) > 0) {
|
||||
return;
|
||||
if (tm_info) {
|
||||
size_t n = strftime(buffer, buffer_size, "%Y-%m-%dT%H:%M:%S", tm_info);
|
||||
if (n > 0 && snprintf(buffer + n, buffer_size - n, ".%06ld+00:00", usec) > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
strncpy(buffer, "2024-01-01T12:00:00.000000+00:00", buffer_size - 1);
|
||||
buffer[buffer_size - 1] = '\0';
|
||||
@@ -231,9 +239,13 @@ int MQTTMessageBuilder::buildPacketJSON(
|
||||
) {
|
||||
if (!packet) return 0;
|
||||
|
||||
time_t now = time(nullptr);
|
||||
// One wall-clock read: tv_sec feeds both the timestamp and the UTC time/date
|
||||
// fields below (kept consistent), tv_usec is the real sub-second.
|
||||
struct timeval now_tv;
|
||||
gettimeofday(&now_tv, nullptr);
|
||||
time_t now = now_tv.tv_sec;
|
||||
char timestamp[40];
|
||||
formatIsoTimestampForMqtt(now, timezone, timestamp, sizeof(timestamp));
|
||||
formatIsoTimestampForMqtt(now, now_tv.tv_usec, timezone, timestamp, sizeof(timestamp));
|
||||
|
||||
// Packet time/date: UTC (gmtime), same family as meshcoretomqtt serial fields
|
||||
struct tm* utc_timeinfo = gmtime(&now);
|
||||
@@ -305,9 +317,13 @@ int MQTTMessageBuilder::buildPacketJSONFromRaw(
|
||||
) {
|
||||
if (!packet || !raw_data || raw_len <= 0) return 0;
|
||||
|
||||
time_t now = time(nullptr);
|
||||
// One wall-clock read: tv_sec feeds both the timestamp and the UTC time/date
|
||||
// fields below (kept consistent), tv_usec is the real sub-second.
|
||||
struct timeval now_tv;
|
||||
gettimeofday(&now_tv, nullptr);
|
||||
time_t now = now_tv.tv_sec;
|
||||
char timestamp[40];
|
||||
formatIsoTimestampForMqtt(now, timezone, timestamp, sizeof(timestamp));
|
||||
formatIsoTimestampForMqtt(now, now_tv.tv_usec, timezone, timestamp, sizeof(timestamp));
|
||||
|
||||
struct tm* utc_timeinfo = gmtime(&now);
|
||||
|
||||
@@ -370,11 +386,13 @@ int MQTTMessageBuilder::buildRawJSON(
|
||||
size_t buffer_size
|
||||
) {
|
||||
if (!packet) return 0;
|
||||
|
||||
time_t now = time(nullptr);
|
||||
|
||||
// One wall-clock read: tv_sec for the timestamp, tv_usec for the real sub-second.
|
||||
struct timeval now_tv;
|
||||
gettimeofday(&now_tv, nullptr);
|
||||
char timestamp[40];
|
||||
formatIsoTimestampForMqtt(now, timezone, timestamp, sizeof(timestamp));
|
||||
|
||||
formatIsoTimestampForMqtt(now_tv.tv_sec, now_tv.tv_usec, timezone, timestamp, sizeof(timestamp));
|
||||
|
||||
// Convert packet to hex
|
||||
// MAX_TRANS_UNIT is 255, so max hex size is 510 chars + null = 511 bytes
|
||||
char raw_hex[1024];
|
||||
|
||||
@@ -26,11 +26,16 @@ public:
|
||||
/**
|
||||
* Format the MQTT JSON `timestamp` field (same rule for status, packet, raw).
|
||||
* Always UTC with an explicit "+00:00" offset, ISO-8601
|
||||
* "%Y-%m-%dT%H:%M:%S.000000+00:00" (matches Python
|
||||
* "%Y-%m-%dT%H:%M:%S.uuuuuu+00:00" (matches Python
|
||||
* datetime.now(timezone.utc).isoformat()). The `timezone` parameter is retained
|
||||
* for API compatibility but ignored — the system clock is UTC.
|
||||
*
|
||||
* `usec` is the sub-second component in microseconds (0..999999), normally taken
|
||||
* from the same gettimeofday() read as `now` so the two don't tear at a second
|
||||
* boundary. It is a real sub-second (SNTP-maintained wall clock), not a literal;
|
||||
* pass 0 if no sub-second source is available.
|
||||
*/
|
||||
static void formatIsoTimestampForMqtt(time_t now, Timezone* timezone, char* buffer, size_t buffer_size);
|
||||
static void formatIsoTimestampForMqtt(time_t now, long usec, Timezone* timezone, char* buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
* Build status message JSON
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <WiFiUdp.h>
|
||||
#include <Timezone.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef WITH_SNMP
|
||||
@@ -1712,7 +1713,9 @@ void MQTTBridge::publishStatusToSlot(int index) {
|
||||
|
||||
// Status timestamp: UTC with explicit +00:00 offset, same as packet/raw JSON
|
||||
// `timestamp` (system clock is UTC — SNTP offset 0; prefs Timezone is separate).
|
||||
MQTTMessageBuilder::formatIsoTimestampForMqtt(time(nullptr), _timezone, timestamp, sizeof(timestamp));
|
||||
struct timeval now_tv;
|
||||
gettimeofday(&now_tv, nullptr);
|
||||
MQTTMessageBuilder::formatIsoTimestampForMqtt(now_tv.tv_sec, now_tv.tv_usec, _timezone, timestamp, sizeof(timestamp));
|
||||
|
||||
snprintf(radio_info, sizeof(radio_info), "%.6f,%.1f,%d,%d",
|
||||
_prefs->freq, _prefs->bw, _prefs->sf, _prefs->cr);
|
||||
@@ -2423,7 +2426,9 @@ bool MQTTBridge::publishStatus() {
|
||||
|
||||
// Status timestamp: UTC with explicit +00:00 offset, same as packet/raw JSON
|
||||
// `timestamp` (system clock is UTC — SNTP offset 0; prefs Timezone is separate).
|
||||
MQTTMessageBuilder::formatIsoTimestampForMqtt(time(nullptr), _timezone, timestamp, sizeof(timestamp));
|
||||
struct timeval now_tv;
|
||||
gettimeofday(&now_tv, nullptr);
|
||||
MQTTMessageBuilder::formatIsoTimestampForMqtt(now_tv.tv_sec, now_tv.tv_usec, _timezone, timestamp, sizeof(timestamp));
|
||||
|
||||
snprintf(radio_info, sizeof(radio_info), "%.6f,%.1f,%d,%d",
|
||||
_prefs->freq, _prefs->bw, _prefs->sf, _prefs->cr);
|
||||
|
||||
Reference in new issue
Block a user