Skip to content

Commit f683868

Browse files
author
realtag
committed
Add repeater NTP sync and default test ping
1 parent a25724f commit f683868

2 files changed

Lines changed: 154 additions & 10 deletions

File tree

examples/simple_repeater/MyMesh.cpp

Lines changed: 145 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include <WiFi.h>
77
#include <HTTPClient.h>
88
#include <WiFiClientSecure.h>
9+
#include <esp_sntp.h>
10+
#include <time.h>
911
#endif
1012

1113
/* ------------------------------ Config -------------------------------- */
@@ -81,6 +83,16 @@ static const uint8_t TEST_GROUP_SECRET[16] = {
8183
#define DISCORD_WEBHOOK_RETRY_DELAY_MS 2000
8284
#define DISCORD_WEBHOOK_MAX_RETRIES 2
8385
#define DISCORD_WEBHOOK_DEDUPE_TTL_MS 30000UL
86+
#define NTP_SYNC_TIMEOUT_MS 20000UL
87+
#define NTP_SYNC_RETRY_DELAY_MS 60000UL
88+
#define NTP_SYNC_INTERVAL_MS (6UL * 60UL * 60UL * 1000UL)
89+
static volatile uint32_t g_ntp_sync_epoch = 0;
90+
91+
static void onNtpTimeSync(struct timeval* tv) {
92+
if (tv && tv->tv_sec > 0) {
93+
g_ntp_sync_epoch = (uint32_t)tv->tv_sec;
94+
}
95+
}
8496

8597
static size_t jsonEscape(const char* src, char* dst, size_t dst_len) {
8698
if (dst_len == 0) return 0;
@@ -852,6 +864,10 @@ bool MyMesh::shouldQueueDiscordWebhook(const char* sender, const char* body) {
852864
}
853865

854866
void MyMesh::initWifiClient() {
867+
wifi_connected_last = false;
868+
ntp_sync_in_progress = false;
869+
next_ntp_attempt_at = 0;
870+
ntp_request_deadline_at = 0;
855871
if (_prefs.wifi_ssid[0] == 0 || _prefs.wifi_pwd[0] == 0) return;
856872
WiFi.mode(WIFI_STA);
857873
WiFi.setAutoReconnect(true);
@@ -860,6 +876,106 @@ void MyMesh::initWifiClient() {
860876
next_wifi_attempt_at = futureMillis(15000);
861877
}
862878

879+
bool MyMesh::pumpWifiClient() {
880+
if (_prefs.wifi_ssid[0] == 0 || _prefs.wifi_pwd[0] == 0) {
881+
wifi_connected_last = false;
882+
ntp_sync_in_progress = false;
883+
ntp_request_deadline_at = 0;
884+
return false;
885+
}
886+
887+
wl_status_t status = WiFi.status();
888+
if (status == WL_CONNECTED) {
889+
if (!wifi_connected_last) {
890+
String ip = WiFi.localIP().toString();
891+
MESH_DEBUG_PRINTLN("WiFi: connected ip=%s", ip.c_str());
892+
next_wifi_attempt_at = 0;
893+
next_ntp_attempt_at = 0;
894+
}
895+
wifi_connected_last = true;
896+
return true;
897+
}
898+
899+
if (wifi_connected_last) {
900+
MESH_DEBUG_PRINTLN("WiFi: disconnected status=%d", (int)status);
901+
ntp_sync_in_progress = false;
902+
ntp_request_deadline_at = 0;
903+
next_ntp_attempt_at = 0;
904+
}
905+
wifi_connected_last = false;
906+
907+
if (next_wifi_attempt_at == 0 || millisHasNowPassed(next_wifi_attempt_at)) {
908+
MESH_DEBUG_PRINTLN("WiFi: not connected, retrying AP '%s'", _prefs.wifi_ssid);
909+
WiFi.begin(_prefs.wifi_ssid, _prefs.wifi_pwd);
910+
next_wifi_attempt_at = futureMillis(15000);
911+
}
912+
return false;
913+
}
914+
915+
void MyMesh::startNtpSync() {
916+
if (WiFi.status() != WL_CONNECTED) return;
917+
g_ntp_sync_epoch = 0;
918+
esp_sntp_set_sync_mode(SNTP_SYNC_MODE_IMMED);
919+
esp_sntp_set_sync_interval(NTP_SYNC_INTERVAL_MS);
920+
esp_sntp_set_time_sync_notification_cb(onNtpTimeSync);
921+
configTzTime("UTC0", "pool.ntp.org", "time.nist.gov", "time.google.com");
922+
ntp_sync_in_progress = true;
923+
ntp_request_deadline_at = futureMillis(NTP_SYNC_TIMEOUT_MS);
924+
MESH_DEBUG_PRINTLN("NTP: sync requested");
925+
}
926+
927+
void MyMesh::formatNtpStatus(char* reply, size_t reply_len) const {
928+
if (_prefs.wifi_ssid[0] == 0 || _prefs.wifi_pwd[0] == 0) {
929+
StrHelper::strncpy(reply, "wifi.ntp=off", reply_len);
930+
return;
931+
}
932+
if (ntp_sync_in_progress) {
933+
StrHelper::strncpy(reply, "wifi.ntp=syncing", reply_len);
934+
return;
935+
}
936+
if (last_ntp_sync_time == 0) {
937+
StrHelper::strncpy(reply, "wifi.ntp=pending", reply_len);
938+
return;
939+
}
940+
941+
DateTime dt(last_ntp_sync_time);
942+
snprintf(reply, reply_len, "wifi.ntp=ok last=%02d:%02d %d/%d/%d UTC",
943+
dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
944+
}
945+
946+
void MyMesh::pumpNtpClient() {
947+
if (WiFi.status() != WL_CONNECTED) return;
948+
949+
uint32_t synced_epoch = g_ntp_sync_epoch;
950+
if (synced_epoch != 0) {
951+
g_ntp_sync_epoch = 0;
952+
getRTCClock()->setCurrentTime(synced_epoch);
953+
last_ntp_sync_time = synced_epoch;
954+
ntp_sync_in_progress = false;
955+
ntp_request_deadline_at = 0;
956+
next_ntp_attempt_at = futureMillis(NTP_SYNC_INTERVAL_MS);
957+
958+
DateTime dt(synced_epoch);
959+
MESH_DEBUG_PRINTLN("NTP: synced %02d:%02d - %d/%d/%d UTC",
960+
dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
961+
return;
962+
}
963+
964+
if (ntp_sync_in_progress) {
965+
if (ntp_request_deadline_at && millisHasNowPassed(ntp_request_deadline_at)) {
966+
ntp_sync_in_progress = false;
967+
ntp_request_deadline_at = 0;
968+
next_ntp_attempt_at = futureMillis(NTP_SYNC_RETRY_DELAY_MS);
969+
MESH_DEBUG_PRINTLN("NTP: sync timed out");
970+
}
971+
return;
972+
}
973+
974+
if (next_ntp_attempt_at && !millisHasNowPassed(next_ntp_attempt_at)) return;
975+
976+
startNtpSync();
977+
}
978+
863979
void MyMesh::queueDiscordWebhook(const char* sender, const char* body) {
864980
if (_prefs.discord_webhook_url[0] == 0) return;
865981
if (!shouldQueueDiscordWebhook(sender, body)) {
@@ -883,15 +999,7 @@ void MyMesh::queueDiscordWebhook(const char* sender, const char* body) {
883999
void MyMesh::pumpDiscordWebhook() {
8841000
if (webhook_count == 0) return;
8851001

886-
if (WiFi.status() != WL_CONNECTED) {
887-
if (next_wifi_attempt_at && millisHasNowPassed(next_wifi_attempt_at)) {
888-
if (_prefs.wifi_ssid[0] == 0 || _prefs.wifi_pwd[0] == 0) return;
889-
MESH_DEBUG_PRINTLN("WiFi: not connected, retrying AP '%s'", _prefs.wifi_ssid);
890-
WiFi.begin(_prefs.wifi_ssid, _prefs.wifi_pwd);
891-
next_wifi_attempt_at = futureMillis(15000);
892-
}
893-
return;
894-
}
1002+
if (WiFi.status() != WL_CONNECTED) return;
8951003

8961004
if (next_webhook_attempt_at && !millisHasNowPassed(next_webhook_attempt_at)) return;
8971005

@@ -1591,7 +1699,12 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
15911699
pending_ping_channel_ready = false;
15921700
#if defined(ESP32)
15931701
next_wifi_attempt_at = 0;
1702+
next_ntp_attempt_at = 0;
1703+
ntp_request_deadline_at = 0;
15941704
next_webhook_attempt_at = 0;
1705+
last_ntp_sync_time = 0;
1706+
wifi_connected_last = false;
1707+
ntp_sync_in_progress = false;
15951708
webhook_head = 0;
15961709
webhook_tail = 0;
15971710
webhook_count = 0;
@@ -1656,7 +1769,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
16561769
_prefs.discord_webhook_url[0] = 0;
16571770
_prefs.ping_public_enabled = 0;
16581771
_prefs.ping_public_max_replies = 0;
1659-
_prefs.ping_test_enabled = 0;
1772+
_prefs.ping_test_enabled = 1;
16601773
_prefs.ping_test_max_replies = 3;
16611774
_prefs.ping_simple_enabled = 0;
16621775
_prefs.hourly_status_enabled = 1;
@@ -2090,6 +2203,26 @@ void MyMesh::handleCommand(uint32_t sender_timestamp, char *command, char *reply
20902203
savePrefs();
20912204
strcpy(reply, "OK");
20922205
}
2206+
} else if (memcmp(sub, "ntp", 3) == 0) {
2207+
const char* val = sub + 3;
2208+
while (*val == ' ') val++;
2209+
if (*val == 0 || strcmp(val, "status") == 0) {
2210+
formatNtpStatus(reply, 160);
2211+
} else if (strcmp(val, "sync") == 0 || strcmp(val, "now") == 0) {
2212+
if (_prefs.wifi_ssid[0] == 0 || _prefs.wifi_pwd[0] == 0) {
2213+
strcpy(reply, "Err - wifi not set");
2214+
} else {
2215+
next_ntp_attempt_at = 0;
2216+
ntp_sync_in_progress = false;
2217+
ntp_request_deadline_at = 0;
2218+
if (WiFi.status() == WL_CONNECTED) {
2219+
startNtpSync();
2220+
}
2221+
strcpy(reply, "OK");
2222+
}
2223+
} else {
2224+
strcpy(reply, "Err - ??");
2225+
}
20932226
} else if (strcmp(sub, "connect") == 0) {
20942227
initWifiClient();
20952228
strcpy(reply, "OK");
@@ -2323,6 +2456,8 @@ void MyMesh::loop() {
23232456
mesh::Mesh::loop();
23242457

23252458
#if defined(ESP32)
2459+
pumpWifiClient();
2460+
pumpNtpClient();
23262461
pumpDiscordWebhook();
23272462
#endif
23282463

examples/simple_repeater/MyMesh.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,13 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
136136
#if defined(ESP32)
137137
static const uint8_t DISCORD_WEBHOOK_QUEUE_SIZE = 128;
138138
static const uint8_t DISCORD_WEBHOOK_DEDUPE_SIZE = 24;
139+
bool wifi_connected_last;
140+
bool ntp_sync_in_progress;
139141
unsigned long next_wifi_attempt_at;
142+
unsigned long next_ntp_attempt_at;
143+
unsigned long ntp_request_deadline_at;
140144
unsigned long next_webhook_attempt_at;
145+
uint32_t last_ntp_sync_time;
141146
uint8_t webhook_head;
142147
uint8_t webhook_tail;
143148
uint8_t webhook_count;
@@ -153,6 +158,10 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
153158
WebhookItem webhook_queue[DISCORD_WEBHOOK_QUEUE_SIZE];
154159
WebhookDedupeItem webhook_dedupe[DISCORD_WEBHOOK_DEDUPE_SIZE];
155160
void initWifiClient();
161+
bool pumpWifiClient();
162+
void startNtpSync();
163+
void pumpNtpClient();
164+
void formatNtpStatus(char* reply, size_t reply_len) const;
156165
bool shouldQueueDiscordWebhook(const char* sender, const char* body);
157166
void queueDiscordWebhook(const char* sender, const char* body);
158167
void pumpDiscordWebhook();

0 commit comments

Comments
 (0)