1#ifndef _PAINLESS_MESH_MESH_HPP_
2#define _PAINLESS_MESH_MESH_HPP_
26#ifdef PAINLESSMESH_ENABLE_OTA
81typedef std::function<void(
bool success, uint16_t httpStatus,
TSTRING error)>
90#define PAINLESSMESH_HAS_INTERNET_RESULT 1
191 return (
static_cast<uint32_t
>(millis()) -
lastSeen) < timeoutMs;
290 using namespace logger;
297 xSemaphore = xSemaphoreCreateMutex();
325 snprintf(errorBuf,
sizeof(errorBuf),
"Node %u %s",
326 static_cast<unsigned>(this->
nodeId),
327 gateway::GATEWAY_NOT_A_GATEWAY_PHRASE);
329 "GATEWAY_DATA from node %u answered: %s\n",
330 static_cast<unsigned>(pkg.originNode), errorBuf);
347 auto msgId = variant.
msgId();
348 if (msgId == 0)
return false;
349 auto origin = variant.
from();
350 if (origin == 0 || origin == this->
nodeId)
return false;
368 std::list<ack::DeliveryResult> results;
370 static_cast<uint32_t
>(millis()),
372 if (!results.empty()) {
373 this->addTask([results]() {
374 for (const auto& result : results) {
375 result.callback(result.nodeId, result.delivered,
392 variant.printTo(str);
393 deserializeJson(doc, str);
394 JsonObject obj = doc.as<JsonObject>();
396 if (obj[
"internetConnected"].is<bool>()) {
397 uint32_t bridgeNodeId = obj[
"from"];
398 if (obj[
"leaving"] |
false) {
402 Log(GENERAL,
"Bridge %u is stepping down\n", bridgeNodeId);
406 bool internetConnected = obj[
"internetConnected"];
407 int8_t routerRSSI = obj[
"routerRSSI"] | 0;
408 uint8_t routerChannel = obj[
"routerChannel"] | 0;
409 uint32_t uptime = obj[
"uptime"] | 0;
411 uint32_t timestamp = obj[
"timestamp"] | 0;
415 routerChannel, uptime, gatewayIP, timestamp);
417 Log(GENERAL,
"Bridge status received from %u: Internet %s\n",
418 bridgeNodeId, internetConnected ?
"Connected" :
"Disconnected");
424 Log(MESH_STATUS,
"Changed connections in neighbour %u\n",
nodeId);
425 if (
nodeId != 0) layout::syncLayout<T>((*
this),
nodeId);
429 Log(MESH_STATUS,
"Dropped connection %u, station %d\n",
nodeId, station);
434 Log(MESH_STATUS,
"New connection %u\n",
nodeId);
438 void init(Scheduler *scheduler, uint32_t
id) {
439 this->setScheduler(scheduler);
443#ifdef PAINLESSMESH_ENABLE_OTA
445 auto announceTask = this->addTask(TASK_SECOND * 60, 60, [
this, announce]() {
446 this->sendPackage(&announce);
452 size_t noPart,
bool forced =
false,
453 bool broadcasted =
false,
bool compressed =
false) {
456 announce.
role = role;
458 announce.
from = this->nodeId;
463 return offerOTA(announce);
468 size_t otaPartSize) {
470 *this->mScheduler, (*
this), callback, otaPartSize);
472 void initOTAReceive(
TSTRING role =
"",
473 std::function<
void(
int,
int)> progress_cb = NULL) {
475 *this->mScheduler, (*
this), role, progress_cb);
492 void setRoot(
bool on =
true) { this->root = on; };
517 using namespace logger;
519 while (this->subs.size() > 0) {
520 auto conn = this->subs.begin();
522 this->eraseClosedConnections();
528 if (ackCheckTask) ackCheckTask->disable();
529 if (broadcastAckTask) broadcastAckTask->disable();
531 pendingBroadcastAcks.clear();
532 ackCheckTask =
nullptr;
533 broadcastAckTask =
nullptr;
537 newConnectionCallbacks.clear();
538 droppedConnectionCallbacks.clear();
539 changedConnectionCallbacks.clear();
541 if (!isExternalScheduler) {
542 if (mScheduler && mScheduler->getCurrentTask() !=
nullptr) {
548 retiredSchedulers.push_back(mScheduler);
549 mScheduler =
nullptr;
552 mScheduler =
nullptr;
563 if (semaphoreTake()) {
565 reclaimRetiredSchedulers();
567 if (!mScheduler->execute())
601 return sendSingle(destId, msg, options);
622 destId, msg.c_str(), options.
priority,
627 return painlessmesh::router::send<T>(single, (*
this));
628 if (ackTracker.full()) {
632 single.msgId = ackTracker.nextMessageId();
633 if (!painlessmesh::router::send<T>(single, (*
this)))
return false;
634 ackTracker.track(single.msgId, {destId}, options.
ackCallback,
636 this->ensureAckScheduling();
673 uint32_t ackTimeoutMs = 5000) {
677 return sendSingle(destId, msg, options);
687 return sendBroadcast(msg,
SendOptions(), includeSelf);
713 bool includeSelf =
false) {
714 using namespace logger;
715 Log(COMMUNICATION,
"sendBroadcast(): msg=%s priority=%u%s\n", msg.c_str(),
721 auto success = router::broadcast<protocol::Broadcast, T>(pkg, (*
this), 0);
724 this->callbackList.execute(var.
type(), var, NULL, 0);
729 if (ackTracker.full()) {
730 Log(ERROR,
"sendBroadcast(): pending-ack limit reached\n");
737 if (ackTimeoutMs < ACK_BROADCAST_MIN_TIMEOUT_MS)
738 ackTimeoutMs = ACK_BROADCAST_MIN_TIMEOUT_MS;
739 auto expected = this->getNodeList(
false);
740 pkg.msgId = ackTracker.nextMessageId();
741 auto success = router::broadcast<protocol::Broadcast, T>(pkg, (*
this), 0);
742 const bool trackingPeers = success > 0 && !expected.empty();
744 ackTracker.track(pkg.msgId, expected, options.
ackCallback, ackTimeoutMs,
745 static_cast<uint32_t
>(millis()));
746 this->ensureAckScheduling();
750 this->callbackList.execute(var.
type(), var, NULL, 0);
755 return trackingPeers;
789 uint32_t ackTimeoutMs = 5000) {
793 return sendBroadcast(msg, options, includeSelf);
807 std::list<ack::DeliveryResult> results;
808 auto pending = ackTracker.collectExpired(
static_cast<uint32_t
>(millis()),
810 if (!results.empty()) {
811 this->addTask([results]() {
812 for (
const auto& result : results) {
813 result.callback(result.nodeId, result.delivered, result.latencyMs);
833 typename IncludeSelf = bool,
834 typename std::enable_if<
835 (std::is_integral<typename std::decay<Priority>::type>::value ||
836 std::is_enum<typename std::decay<Priority>::type>::value) &&
837 !std::is_same<
typename std::decay<Priority>::type,
bool>::value &&
838 std::is_same<
typename std::decay<IncludeSelf>::type,
bool>::value,
841 IncludeSelf includeSelf =
false) {
843 options.
priority =
static_cast<uint8_t
>(priorityLevel);
844 return sendBroadcast(msg, options, includeSelf);
855 using namespace logger;
856 Log(S_TIME,
"startDelayMeas(): NodeId %u\n",
id);
857 auto conn = painlessmesh::router::findRoute<T>((*
this),
id);
858 if (!conn)
return false;
859 return router::send<protocol::TimeDelay, T>(
888 this->callbackList.onPackage(
892 onReceive(pkg.from, pkg.msg);
895 this->callbackList.onPackage(
899 onReceive(pkg.from, pkg.msg);
916 newConnectionCallbacks.push_back([onNewConnection](uint32_t nodeId) {
917 if (nodeId != 0) onNewConnection(nodeId);
931 droppedConnectionCallbacks.push_back(
932 [onDroppedConnection](uint32_t nodeId,
bool station) {
933 if (nodeId != 0) onDroppedConnection(nodeId);
947 changedConnectionCallbacks.push_back(
948 [onChangedConnections](uint32_t nodeId) {
949 if (nodeId != 0) onChangedConnections();
968 nodeTimeAdjustedCallback = onTimeAdjusted;
985 nodeDelayReceivedCallback = onDelayReceived;
1005 bridgeStatusChangedCallback = onBridgeStatusChanged;
1049 for (
const auto& bridge : knownBridges) {
1050 if (bridge.isHealthy(bridgeTimeoutMs) && bridge.internetConnected) {
1073 std::vector<uint32_t> nodesWithInternet;
1074 for (
const auto& bridge : knownBridges) {
1075 if (bridge.isHealthy(bridgeTimeoutMs) && bridge.internetConnected) {
1076 nodesWithInternet.push_back(bridge.nodeId);
1079 return nodesWithInternet;
1088 return knownBridges;
1111 int8_t bestRSSI = -127;
1114 for (
auto& bridge : knownBridges) {
1115 if (bridge.isHealthy(bridgeTimeoutMs) && bridge.internetConnected) {
1116 if (bridge.routerRSSI > bestRSSI) {
1140 int8_t bestRSSI = -127;
1142 for (
auto& bridge : knownBridges) {
1144 if (bridge.internetConnected) {
1145 if (bridge.routerRSSI > bestRSSI) {
1170 for (
auto& conn : this->subs) {
1171 if (conn && conn->connected()) {
1196 for (
auto&& sub : this->subs) {
1197 if (sub && sub->connected() && !sub->station) ++n;
1222 using namespace logger;
1223 size_t children = apChildren();
1224 bool over = freeHeap < floor && children > 1;
1225 uint32_t now = millis();
1226 if (over && (!_overCapacity ||
1227 now - _capacityWarnedAt > CAPACITY_WARN_INTERVAL_MS)) {
1229 "capacity: %u B free with %u AP children on ESP8266. This part is "
1230 "specified as a leaf in meshes of this size; init(..., maxconn=0) "
1231 "or reduce the mesh.\n",
1232 freeHeap, children);
1233 _capacityWarnedAt = now;
1235 _overCapacity = over;
1239 static constexpr uint32_t ESP8266_CAPACITY_FLOOR = 12 * 1024;
1240 static constexpr uint32_t CAPACITY_WARN_INTERVAL_MS = 5 * 60 * 1000;
1260 if (primary ==
nullptr) {
1263 return primary->
nodeId == this->nodeId;
1285 if (primary ==
nullptr) {
1313 auto nodes = getNodesWithInternet();
1314 return std::list<uint32_t>(nodes.begin(), nodes.end());
1335 for (
const auto& bridge : knownBridges) {
1336 if (bridge.isHealthy(bridgeTimeoutMs) && bridge.internetConnected) count++;
1364 gatewayChangedCallback = callback;
1373 bridgeStatusIntervalMs = intervalMs;
1382 bridgeTimeoutMs = timeoutMs;
1391 bridgeStatusBroadcastEnabled = enabled;
1417 size_t sizeBefore = knownBridges.size();
1419 std::remove_if(knownBridges.begin(), knownBridges.end(),
1421 return bridge.nodeId == bridgeNodeId;
1423 knownBridges.end());
1424 return knownBridges.size() != sizeBefore;
1428 using namespace logger;
1429 size_t sizeBefore = knownBridges.size();
1433 std::remove_if(knownBridges.begin(), knownBridges.end(),
1435 return !bridge.isHealthy(bridgeTimeoutMs);
1437 knownBridges.end());
1439 size_t removed = sizeBefore - knownBridges.size();
1441 Log(GENERAL,
"cleanupExpiredBridges(): Removed %lu expired bridges\n",
1442 static_cast<unsigned long>(removed));
1460 using namespace logger;
1461 if (bridgeCleanupTask !=
nullptr) {
1462 Log(GENERAL,
"enableBridgeCleanup(): Already enabled\n");
1466 Log(GENERAL,
"enableBridgeCleanup(): Starting cleanup task (interval: %u ms)\n",
1469 bridgeCleanupTask = this->addTask(
1473 cleanupExpiredBridges();
1481 using namespace logger;
1482 if (bridgeCleanupTask !=
nullptr) {
1483 bridgeCleanupTask->disable();
1486 bridgeCleanupTask =
nullptr;
1487 Log(GENERAL,
"disableBridgeCleanup(): Cleanup task disabled\n");
1497 return bridgeCleanupTask !=
nullptr && bridgeCleanupTask->isEnabled();
1522 return internetHealthChecker.hasLocalInternet();
1540 if (hasLocalInternet())
return true;
1541 if (!isInternetHealthCheckEnabled())
return false;
1542 if (internetHealthChecker.checkOnDemand()) {
1544 "uplinkServesLocally(): on-demand probe found the uplink up\n");
1570 localInternetChangedCallback = callback;
1571 internetHealthChecker.onConnectivityChanged(callback);
1590 return internetHealthChecker.getStatus();
1602 internetHealthChecker.setConfig(config);
1614 internetHealthChecker.setCheckTarget(host, port);
1623 internetHealthChecker.setCheckInterval(intervalMs);
1632 internetHealthChecker.setCheckTimeout(timeoutMs);
1644 return internetHealthChecker.checkNow();
1662 using namespace logger;
1663 if (internetHealthCheckTask !=
nullptr) {
1664 if (internetHealthCheckTask->isEnabled()) {
1665 Log(GENERAL,
"enableInternetHealthCheck(): Already enabled\n");
1674 internetHealthCheckTask =
nullptr;
1677 Log(GENERAL,
"enableInternetHealthCheck(): Starting health check task (interval: %u ms)\n",
1678 internetHealthChecker.getCheckInterval());
1680 internetHealthCheckTask = this->addTask(
1681 internetHealthChecker.getCheckInterval(),
1684 this->internetHealthChecker.checkNow();
1692 using namespace logger;
1693 if (internetHealthCheckTask !=
nullptr) {
1694 internetHealthCheckTask->disable();
1695 internetHealthCheckTask =
nullptr;
1696 Log(GENERAL,
"disableInternetHealthCheck(): Health check task disabled\n");
1706 return internetHealthCheckTask !=
nullptr && internetHealthCheckTask->isEnabled();
1713 internetHealthChecker.resetStats();
1716#ifdef PAINLESSMESH_BOOST
1722 void setMockInternetConnected(
bool connected) {
1723 internetHealthChecker.setMockConnected(connected);
1779 return startInternetRequest(destination, payload, callback,
nullptr, priority);
1798 return startInternetRequest(destination, payload,
nullptr, onResult, priority);
1821 uint16_t httpStatus = 0) {
1824 result.
error = error;
1828 uint32_t startInternetRequest(
1834 using namespace logger;
1839 Log(COMMUNICATION,
"sendToInternet(): msgId=%u dest=%s priority=%u\n",
1840 messageId, destination.c_str(), priority);
1845 if (uplinkServesLocally()) {
1852 request.
timeoutMs = internetRequestTimeout;
1863 pendingInternetRequests[messageId] = request;
1865 dispatchInternetRequestLocally(messageId, priority, 0, destination,
1878 if (!hasActiveMeshConnections()) {
1879 Log(ERROR,
"sendToInternet(): No active mesh connections\n");
1880 if (callback || onResult) {
1881 this->addTask([refused]() {
1882 deliverInternetResult(refused, failedInternetResult(
1883 "No mesh connections - cannot route to gateway"));
1891 if (gateway ==
nullptr) {
1892 Log(ERROR,
"sendToInternet(): No gateway available\n");
1893 if (callback || onResult) {
1894 this->addTask([refused]() {
1895 deliverInternetResult(refused, failedInternetResult(
"No gateway available"));
1908 request.
timeoutMs = internetRequestTimeout;
1918 pendingInternetRequests[messageId] = request;
1922 pkg.
from = this->nodeId;
1937 auto conn = painlessmesh::router::findRoute<T>((*
this), gateway->
nodeId);
1944 Log(ERROR,
"sendToInternet(): sendWithPriority failed to gateway %u (send buffer full?)\n", gateway->
nodeId);
1947 Log(ERROR,
"sendToInternet(): No route to gateway %u\n", gateway->
nodeId);
1951 Log(ERROR,
"sendToInternet(): Failed to send to gateway %u, scheduling retry\n", gateway->
nodeId);
1953 scheduleInternetRetry(messageId);
1955 Log(COMMUNICATION,
"sendToInternet(): Sent to gateway %u\n", gateway->
nodeId);
1957 pendingInternetRequests[messageId].attempts = 1;
1959 scheduleInternetTimeout(messageId);
1972 internetRequestTimeout = timeoutMs;
1981 internetRetryCount = retryCount;
1990 internetRetryDelay = delayMs;
2016 return tcpRetryConfig;
2025 return pendingInternetRequests.size();
2035 auto it = pendingInternetRequests.find(messageId);
2036 if (it != pendingInternetRequests.end()) {
2038 pendingInternetRequests.erase(it);
2040 this->addTask([cancelled]() {
2041 deliverInternetResult(cancelled, failedInternetResult(
"Request cancelled"));
2064 using namespace logger;
2065 Log(GENERAL,
"enableSendToInternet(): Enabling Internet routing API\n");
2068 this->callbackList.onPackage(
2072 this->handleGatewayAck(ack);
2077 if (internetCleanupTask ==
nullptr) {
2078 internetCleanupTask = this->addTask(
2082 this->cleanupTimedOutRequests();
2086 sendToInternetEnabled =
true;
2093 using namespace logger;
2094 Log(GENERAL,
"disableSendToInternet(): Disabling Internet routing API\n");
2096 if (internetCleanupTask !=
nullptr) {
2097 internetCleanupTask->disable();
2098 internetCleanupTask =
nullptr;
2102 for (
auto& pair : pendingInternetRequests) {
2103 deliverInternetResult(pair.second, failedInternetResult(
"API disabled"));
2105 pendingInternetRequests.clear();
2107 sendToInternetEnabled =
false;
2116 return sendToInternetEnabled;
2139 uint16_t httpStatus,
const TSTRING& error,
2140 std::shared_ptr<T> ingressConnection =
nullptr,
2142 uint32_t retryAfterMs = 0) {
2143 using namespace logger;
2146 ack.
from = this->nodeId;
2178 auto held = std::make_shared<gateway::GatewayAckPackage>(std::move(ack));
2179 this->addTask([
this, held]() { this->handleGatewayAck(*held); });
2181 "Completing local GATEWAY_ACK from the scheduler (success=%d, http=%d)\n",
2182 success, httpStatus);
2186 auto conn = router::findRoute<T>((*
this), request.
originNode);
2187 if (!conn && ingressConnection) {
2188 conn = ingressConnection;
2190 "Routing GATEWAY_ACK to node %u through request ingress while "
2191 "topology converges\n",
2197 Log(COMMUNICATION,
"Sent GATEWAY_ACK to node %u (success=%d, http=%d)\n",
2200 Log(ERROR,
"Failed to send GATEWAY_ACK: no route to node %u\n",
2207 using namespace logger;
2208 Log(COMMUNICATION,
"handleGatewayAck(): msgId=%u success=%d http=%u\n",
2211 auto it = pendingInternetRequests.find(ack.
messageId);
2212 if (it == pendingInternetRequests.end()) {
2213 Log(GENERAL,
"handleGatewayAck(): Unknown message ID %u\n", ack.
messageId);
2232 pendingInternetRequests.erase(it);
2233 deliverInternetResult(done, std::move(result));
2245 gateway::GATEWAY_NOT_A_GATEWAY_PHRASE)) {
2247 bool forgot = this->forgetBridge(staleGateway);
2248 if (ack.
from != staleGateway) forgot = this->forgetBridge(ack.
from) || forgot;
2249 Log(ERROR,
"handleGatewayAck(): %s; forgot it as a gateway for msgId=%u\n",
2255 }
else if (this->getPrimaryBridge() ==
nullptr &&
2256 !this->uplinkServesLocally()) {
2263 snprintf(errorBuf,
sizeof(errorBuf),
2264 "No Internet gateway available: %s", ack.
error.c_str());
2269 const uint32_t messageId = ack.
messageId;
2270 this->addTask([
this, messageId]() {
2271 this->retryInternetRequest(messageId);
2285 bool isRetryable =
false;
2286 uint32_t minDelayMs = 0;
2289 if (isRetryable && ack.
retryAfterMs > gateway::GATEWAY_RETRY_AFTER_MAX_MS) {
2292 isRetryable =
false;
2294 snprintf(errorBuf,
sizeof(errorBuf),
"%s (the server asked to retry after %lu s)",
2298 }
else if (isRetryable) {
2305 isRetryable = legacyAckIsRetryable(ack);
2311 Log(COMMUNICATION,
"handleGatewayAck(): Scheduling retry for msgId=%u (attempt %u/%u)\n",
2314 scheduleInternetRetry(ack.
messageId, minDelayMs);
2317 Log(ERROR,
"handleGatewayAck(): Max retries reached for msgId=%u\n", ack.
messageId);
2319 Log(COMMUNICATION,
"handleGatewayAck(): Final failure for msgId=%u (HTTP %u)\n",
2323 pendingInternetRequests.erase(it);
2324 deliverInternetResult(done, std::move(result));
2337 static const char*
const FINAL[] = {
"Router has no internet",
2338 "Gateway WiFi not connected",
2339 "Captive portal detected"};
2340 for (
const char* phrase : FINAL) {
2358 void dispatchInternetRequestLocally(uint32_t messageId, uint8_t priority,
2362 uint32_t requestNonce) {
2364 pkg.
from = this->nodeId;
2365 pkg.
dest = this->nodeId;
2383 void scheduleInternetRetry(uint32_t messageId, uint32_t minDelayMs = 0) {
2384 auto it = pendingInternetRequests.find(messageId);
2385 if (it == pendingInternetRequests.end()) {
2394 Log(
logger::ERROR,
"scheduleInternetRetry(): Max retries reached for msgId=%u\n",
2397 pendingInternetRequests.erase(it);
2398 deliverInternetResult(done, failedInternetResult(
2405 if (delay < minDelayMs) delay = minDelayMs;
2412 if (minDelayMs > 0) {
2413 const uint32_t elapsed =
static_cast<uint32_t
>(millis()) - request.
timestamp;
2414 const uint32_t needed = elapsed + delay + internetRequestTimeout;
2422 this->addTask(delay, TASK_ONCE, [
this, messageId]() {
2423 this->retryInternetRequest(messageId);
2430 void retryInternetRequest(uint32_t messageId) {
2431 auto it = pendingInternetRequests.find(messageId);
2432 if (it == pendingInternetRequests.end()) {
2447 if (request.
gatewayNodeId == this->nodeId && uplinkServesLocally()) {
2448 const uint8_t priority = request.
priority;
2449 const uint8_t retryCount = request.
retryCount;
2455 "retryInternetRequest(): Retrying msgId=%u on the local uplink\n",
2457 dispatchInternetRequestLocally(messageId, priority, retryCount,
2458 destination, payload, nonce);
2464 if (!hasActiveMeshConnections()) {
2465 Log(
logger::ERROR,
"retryInternetRequest(): No active mesh connections for retry msgId=%u, rescheduling\n",
2467 scheduleInternetRetry(messageId);
2473 if (gateway ==
nullptr) {
2474 Log(
logger::ERROR,
"retryInternetRequest(): No gateway for retry msgId=%u\n",
2476 scheduleInternetRetry(messageId);
2485 pkg.
from = this->nodeId;
2499 auto conn = painlessmesh::router::findRoute<T>((*
this), gateway->
nodeId);
2507 Log(
logger::ERROR,
"retryInternetRequest(): Retry send failed msgId=%u\n", messageId);
2508 scheduleInternetRetry(messageId);
2512 messageId, gateway->
nodeId);
2519 void scheduleInternetTimeout(uint32_t messageId) {
2520 auto it = pendingInternetRequests.find(messageId);
2521 if (it == pendingInternetRequests.end()) {
2525 uint32_t timeout = it->second.timeoutMs;
2527 this->addTask(timeout, TASK_ONCE, [
this, messageId]() {
2528 this->checkInternetRequestTimeout(messageId);
2535 void checkInternetRequestTimeout(uint32_t messageId) {
2536 auto it = pendingInternetRequests.find(messageId);
2537 if (it == pendingInternetRequests.end()) {
2544 Log(
logger::ERROR,
"checkInternetRequestTimeout(): Request timed out msgId=%u\n",
2547 pendingInternetRequests.erase(it);
2548 deliverInternetResult(done, failedInternetResult(
"Request timed out"));
2555 void cleanupTimedOutRequests() {
2556 auto it = pendingInternetRequests.begin();
2557 while (it != pendingInternetRequests.end()) {
2558 if (it->second.isTimedOut()) {
2561 deliverInternetResult(it->second, failedInternetResult(
"Request timed out"));
2562 it = pendingInternetRequests.erase(it);
2583 int8_t routerRSSI, uint8_t routerChannel,
2584 uint32_t uptime,
TSTRING gatewayIP, uint32_t timestamp) {
2587 uint32_t oldPrimaryBridgeId = 0;
2588 auto oldPrimary = this->getPrimaryBridge();
2589 if (oldPrimary !=
nullptr) {
2590 oldPrimaryBridgeId = oldPrimary->nodeId;
2593 for (
auto& b : knownBridges) {
2594 if (b.nodeId == bridgeNodeId) {
2600 bool wasConnected =
false;
2601 bool isNewBridge =
false;
2602 if (bridge ==
nullptr) {
2604 if (knownBridges.size() >= MAX_KNOWN_BRIDGES) {
2606 cleanupExpiredBridges();
2609 if (knownBridges.size() >= MAX_KNOWN_BRIDGES && !knownBridges.empty()) {
2610 auto worstBridge = knownBridges.begin();
2611 int8_t worstRSSI = worstBridge->routerRSSI;
2613 for (
auto it = knownBridges.begin(); it != knownBridges.end(); ++it) {
2614 if (it->routerRSSI < worstRSSI) {
2615 worstRSSI = it->routerRSSI;
2620 Log(
logger::GENERAL,
"updateBridgeStatus(): Removing bridge %u (RSSI: %d) to make room\n",
2621 worstBridge->nodeId, worstBridge->routerRSSI);
2622 knownBridges.erase(worstBridge);
2628 newBridge.
nodeId = bridgeNodeId;
2629 knownBridges.push_back(newBridge);
2630 bridge = &knownBridges.back();
2646 auto newPrimary = this->getPrimaryBridge();
2647 uint32_t newPrimaryBridgeId = (newPrimary !=
nullptr) ? newPrimary->nodeId : 0;
2650 if (oldPrimaryBridgeId != newPrimaryBridgeId && gatewayChangedCallback) {
2651 gatewayChangedCallback(oldPrimaryBridgeId, newPrimaryBridgeId);
2654 if (diagnosticsEnabled && oldPrimaryBridgeId != newPrimaryBridgeId) {
2656 lastBridgeChange.timestamp = millis();
2657 lastBridgeChange.oldBridgeId = oldPrimaryBridgeId;
2658 lastBridgeChange.newBridgeId = newPrimaryBridgeId;
2659 lastBridgeChange.internetAvailable = internetConnected;
2661 lastBridgeChange.reason =
"New bridge discovered";
2662 }
else if (internetConnected && !wasConnected) {
2663 lastBridgeChange.reason =
"Bridge Internet restored";
2664 }
else if (!internetConnected && wasConnected) {
2665 lastBridgeChange.reason =
"Bridge Internet lost";
2667 lastBridgeChange.reason =
"Primary bridge changed";
2670 lastBridgeChangeTime = millis();
2675 if (wasConnected != internetConnected && bridgeStatusChangedCallback) {
2676 bridgeStatusChangedCallback(bridgeNodeId, internetConnected);
2700 using namespace logger;
2701 Log(GENERAL,
"enableRTC(): Initializing RTC\n");
2702 bool success = rtcManager.enable(rtcInterface);
2705 setTimeAuthority(
true);
2714 using namespace logger;
2715 Log(GENERAL,
"disableRTC(): Disabling RTC\n");
2716 rtcManager.disable();
2719 setTimeAuthority(
false);
2745 using namespace logger;
2746 Log(GENERAL,
"syncRTCFromNTP(): Syncing RTC to timestamp %u\n", ntpTimestamp);
2748 if (!rtcManager.isEnabled()) {
2749 Log(ERROR,
"syncRTCFromNTP(): RTC not enabled\n");
2753 bool success = rtcManager.syncFromNTP(ntpTimestamp);
2755 if (success && rtcSyncCompleteCallback) {
2756 rtcSyncCompleteCallback(ntpTimestamp);
2771 if (rtcManager.isEnabled()) {
2772 uint32_t rtcTime = rtcManager.getTime();
2778 return getNodeTime() / 1000000;
2787 return rtcManager.isEnabled();
2796 return rtcManager.getType();
2805 return rtcManager.getTimeSinceLastSync();
2821 rtcSyncCompleteCallback = onRTCSyncComplete;
2844 using namespace logger;
2845 if (this->hasTimeAuthority != hasAuthority) {
2846 this->hasTimeAuthority = hasAuthority;
2847 Log(GENERAL,
"setTimeAuthority(): Time authority %s\n",
2848 hasAuthority ?
"enabled" :
"disabled");
2851 for (
auto&& connection : this->subs) {
2852 if (connection->nodeId != 0) {
2853 connection->timeSyncTask.forceNextIteration();
2865 return this->hasTimeAuthority;
2904 if (enabled && !messageQueue) {
2906 Log(
logger::GENERAL,
"enableMessageQueue(): Queue enabled with capacity %u\n", maxSize);
2907 }
else if (!enabled && messageQueue) {
2908 delete messageQueue;
2909 messageQueue =
nullptr;
2937 const TSTRING& destination =
"",
2939 if (!messageQueue) {
2944 return messageQueue->enqueue(priority, payload, destination);
2968 if (!messageQueue) {
2969 return std::vector<QueuedMessage>();
2972 return messageQueue->getMessages();
2982 if (!messageQueue) {
2986 return messageQueue->remove(messageId);
2996 if (!messageQueue) {
3000 return messageQueue->incrementAttempts(messageId);
3010 if (!messageQueue) {
3014 return messageQueue->size(priority);
3018 if (!messageQueue) {
3022 return messageQueue->size();
3031 if (!messageQueue) {
3035 return messageQueue->getStats();
3053 messageQueue->onStateChanged(callback);
3064 if (!messageQueue) {
3068 return messageQueue->pruneOldMessages(maxAgeMs);
3076 messageQueue->clear();
3086 return painlessmesh::router::findRoute<T>((*
this), nodeId) != NULL;
3102 return this->asNodeTree().toString(pretty);
3109 uint32_t nodeId = 0;
3110 uint32_t lastSeen = 0;
3115 uint32_t messagesRx = 0;
3116 uint32_t messagesTx = 0;
3117 uint32_t messagesDropped = 0;
3124 std::vector<ConnectionInfo> connections;
3126 for (
auto conn : this->subs) {
3127 if (conn->connected()) {
3129 info.
nodeId = conn->nodeId;
3130 info.
lastSeen = conn->timeLastReceived;
3131 info.
rssi = conn->getRSSI();
3134 info.
quality = conn->getQuality();
3139 connections.push_back(info);
3152 if (nodeId == this->getNodeId()) {
3157 for (
auto conn : this->subs) {
3158 if (conn->nodeId == nodeId && conn->connected()) {
3164 auto tree = this->asNodeTree();
3167 std::queue<std::pair<uint32_t, uint16_t>> queue;
3168 std::set<uint32_t> visited;
3171 queue.push({this->getNodeId(), 0});
3172 visited.insert(this->getNodeId());
3174 while (!queue.empty()) {
3175 auto current = queue.front();
3178 uint32_t currentNode = current.first;
3179 uint16_t hops = current.second;
3182 if (currentNode == nodeId) {
3187 std::list<uint32_t> neighbors;
3188 if (getNodeNeighbors(tree, currentNode, neighbors)) {
3190 for (
auto neighbor : neighbors) {
3191 if (visited.find(neighbor) == visited.end()) {
3192 visited.insert(neighbor);
3193 queue.push({neighbor,
static_cast<uint16_t
>(hops + 1)});
3211 std::map<uint32_t, uint32_t> table;
3212 auto tree = this->asNodeTree();
3215 std::queue<uint32_t> queue;
3216 std::set<uint32_t> visited;
3217 std::map<uint32_t, uint32_t> nextHop;
3220 queue.push(this->getNodeId());
3221 visited.insert(this->getNodeId());
3223 while (!queue.empty()) {
3224 uint32_t current = queue.front();
3228 std::list<uint32_t> neighbors;
3229 if (getNodeNeighbors(tree, current, neighbors)) {
3230 for (
auto neighbor : neighbors) {
3231 if (visited.find(neighbor) == visited.end()) {
3232 visited.insert(neighbor);
3233 queue.push(neighbor);
3236 if (current == this->getNodeId()) {
3238 nextHop[neighbor] = neighbor;
3241 nextHop[neighbor] = nextHop[current];
3245 table[neighbor] = nextHop[neighbor];
3275 std::vector<uint32_t> path;
3278 if (nodeId == this->getNodeId()) {
3279 path.push_back(this->getNodeId());
3283 auto tree = this->asNodeTree();
3286 std::queue<uint32_t> queue;
3287 std::set<uint32_t> visited;
3288 std::map<uint32_t, uint32_t> parent;
3291 queue.push(this->getNodeId());
3292 visited.insert(this->getNodeId());
3293 parent[this->getNodeId()] = 0;
3296 while (!queue.empty() && !found) {
3297 uint32_t current = queue.front();
3301 if (current == nodeId) {
3307 std::list<uint32_t> neighbors;
3308 if (getNodeNeighbors(tree, current, neighbors)) {
3309 for (
auto neighbor : neighbors) {
3310 if (visited.find(neighbor) == visited.end()) {
3311 visited.insert(neighbor);
3312 parent[neighbor] = current;
3313 queue.push(neighbor);
3321 uint32_t current = nodeId;
3322 size_t maxIter = parent.size() + 1;
3323 while (current != 0 && maxIter-- > 0) {
3324 path.insert(path.begin(), current);
3325 current = parent[current];
3354 auto primaryBridge = getPrimaryBridge();
3355 if (primaryBridge !=
nullptr) {
3361 uint64_t totalBytesRx = 0;
3362 uint64_t totalBytesTx = 0;
3363 uint32_t totalMessagesRx = 0;
3364 uint32_t totalMessagesTx = 0;
3365 uint32_t totalMessagesDropped = 0;
3366 uint32_t totalLatency = 0;
3367 uint32_t latencySampleCount = 0;
3368 int32_t sumRSSI = 0;
3370 int8_t maxRSSI = -127;
3371 uint32_t rssiCount = 0;
3373 for (
auto conn : this->subs) {
3374 if (conn->connected()) {
3375 totalBytesRx += conn->bytesRx;
3376 totalBytesTx += conn->bytesTx;
3377 totalMessagesRx += conn->messagesRx;
3378 totalMessagesTx += conn->messagesTx;
3379 totalMessagesDropped += conn->messagesDropped;
3382 int latency = conn->getLatency();
3384 totalLatency += latency;
3385 latencySampleCount++;
3389 int rssi = conn->getRSSI();
3393 if (rssi < minRSSI || minRSSI == 0) minRSSI = rssi;
3394 if (rssi > maxRSSI) maxRSSI = rssi;
3400 metrics.
bytesRx = totalBytesRx;
3401 metrics.
bytesTx = totalBytesTx;
3407 if (latencySampleCount > 0) {
3408 metrics.
avgLatencyMs = totalLatency / latencySampleCount;
3411 if (rssiCount > 0) {
3412 metrics.
avgRSSI = sumRSSI / rssiCount;
3418 uint32_t totalAttempted = totalMessagesTx + totalMessagesDropped;
3419 if (totalAttempted > 0) {
3444 using namespace logger;
3445 Log(GENERAL,
"resetHealthMetrics(): Resetting all metric counters\n");
3448 for (
auto conn : this->subs) {
3449 if (conn->connected()) {
3450 conn->messagesRx = 0;
3451 conn->messagesTx = 0;
3452 conn->messagesDropped = 0;
3455 conn->latencySamples.clear();
3460 metricsDisconnectCount = 0;
3477 auto metrics = getBridgeHealthMetrics();
3480 json +=
"\"connectivity\":{";
3481 json +=
"\"uptimeSeconds\":";
3482 json += std::to_string(metrics.uptimeSeconds);
3483 json +=
",\"internetUptimeSeconds\":";
3484 json += std::to_string(metrics.internetUptimeSeconds);
3485 json +=
",\"totalDisconnects\":";
3486 json += std::to_string(metrics.totalDisconnects);
3487 json +=
",\"currentUptime\":";
3488 json += std::to_string(metrics.currentUptime);
3491 json +=
"\"signalQuality\":{";
3492 json +=
"\"currentRSSI\":";
3493 json += std::to_string(metrics.currentRSSI);
3494 json +=
",\"avgRSSI\":";
3495 json += std::to_string(metrics.avgRSSI);
3496 json +=
",\"minRSSI\":";
3497 json += std::to_string(metrics.minRSSI);
3498 json +=
",\"maxRSSI\":";
3499 json += std::to_string(metrics.maxRSSI);
3502 json +=
"\"traffic\":{";
3503 json +=
"\"bytesRx\":";
3504 json += std::to_string(metrics.bytesRx);
3505 json +=
",\"bytesTx\":";
3506 json += std::to_string(metrics.bytesTx);
3507 json +=
",\"messagesRx\":";
3508 json += std::to_string(metrics.messagesRx);
3509 json +=
",\"messagesTx\":";
3510 json += std::to_string(metrics.messagesTx);
3511 json +=
",\"messagesQueued\":";
3512 json += std::to_string(metrics.messagesQueued);
3513 json +=
",\"messagesDropped\":";
3514 json += std::to_string(metrics.messagesDropped);
3517 json +=
"\"performance\":{";
3518 json +=
"\"avgLatencyMs\":";
3519 json += std::to_string(metrics.avgLatencyMs);
3520 json +=
",\"packetLossPercent\":";
3521 json += std::to_string(metrics.packetLossPercent);
3522 json +=
",\"meshNodeCount\":";
3523 json += std::to_string(metrics.meshNodeCount);
3547 uint32_t intervalMs = 60000) {
3548 using namespace logger;
3549 Log(GENERAL,
"onHealthMetricsUpdate(): Setting up periodic callback every %u ms\n", intervalMs);
3552 auto metricsTask = this->addTask(intervalMs, TASK_FOREVER, [
this, callback]() {
3553 auto metrics = this->getBridgeHealthMetrics();
3557 metricsTask->enable();
3571 diagnosticsEnabled = enabled;
3596 status.
isBridge = this->isBridge();
3600 status.
role =
"bridge";
3601 }
else if (this->root) {
3602 status.
role =
"root";
3604 status.
role =
"regular";
3608 auto primaryBridge = this->getPrimaryBridge();
3609 if (primaryBridge !=
nullptr) {
3611 status.
bridgeRSSI = primaryBridge->routerRSSI;
3615 if (lastBridgeChangeTime > 0) {
3639 if (!diagnosticsEnabled) {
3641 return std::vector<ElectionRecord>();
3643 return electionHistory;
3662 return lastBridgeChange;
3680 TSTRING dot =
"digraph mesh {\n";
3681 dot +=
" rankdir=TB;\n";
3682 dot +=
" node [shape=box];\n\n";
3685 dot +=
" \"" +
TSTRING(std::to_string(this->nodeId).c_str()) +
"\" ";
3686 if (this->isBridge()) {
3687 dot +=
"[style=filled,fillcolor=lightblue,label=\"" +
TSTRING(std::to_string(this->nodeId).c_str()) +
"\\nBridge\"];\n";
3689 dot +=
"[label=\"" +
TSTRING(std::to_string(this->nodeId).c_str()) +
"\"];\n";
3693 auto primaryBridge = this->getPrimaryBridge();
3694 if (primaryBridge !=
nullptr && primaryBridge->internetConnected) {
3695 dot +=
" \"Internet\" [shape=cloud,style=filled,fillcolor=lightgreen];\n";
3696 dot +=
" \"" +
TSTRING(std::to_string(primaryBridge->nodeId).c_str()) +
"\" -> \"Internet\" [style=dashed,color=green];\n";
3700 auto nodeList = this->getNodeList(
false);
3701 for (
auto node : nodeList) {
3702 dot +=
" \"" +
TSTRING(std::to_string(node).c_str()) +
"\";\n";
3706 for (
auto conn : this->subs) {
3707 if (conn->connected()) {
3708 dot +=
" \"" +
TSTRING(std::to_string(this->nodeId).c_str()) +
"\" -> \"" +
TSTRING(std::to_string(conn->nodeId).c_str()) +
"\"";
3711 int latency = conn->getLatency();
3713 dot +=
" [label=\"" +
TSTRING(std::to_string(latency).c_str()) +
"ms\"]";
3745 auto primaryBridge = this->getPrimaryBridge();
3746 if (primaryBridge ==
nullptr) {
3748 result.
message =
"No bridge available";
3756 result.
message =
"Bridge not reachable";
3761 for (
auto conn : this->subs) {
3762 if (conn->nodeId == primaryBridge->nodeId && conn->connected()) {
3763 int latency = conn->getLatency();
3776 result.
message =
"Bridge reachable with Internet";
3778 result.
message =
"Bridge reachable, no Internet";
3799 return this->isConnected(bridgeNodeId);
3823 TSTRING report =
"=== painlessMesh Diagnostics ===\n";
3826 auto status = this->getBridgeStatus();
3827 report +=
"Node ID: " +
TSTRING(std::to_string(this->nodeId).c_str()) +
"\n";
3828 report +=
"Mode: " + status.role +
"\n";
3831 auto nodeList = this->getNodeList(
true);
3832 report +=
"Mesh Nodes: " +
TSTRING(std::to_string(nodeList.size()).c_str()) +
"\n";
3835 if (status.isBridge) {
3836 report +=
"Bridge: " +
TSTRING(std::to_string(this->nodeId).c_str()) +
" (this node)\n";
3838 auto primaryBridge = this->getPrimaryBridge();
3839 if (primaryBridge !=
nullptr) {
3840 report +=
"Bridge: " +
TSTRING(std::to_string(primaryBridge->nodeId).c_str());
3841 report +=
" (RSSI: " +
TSTRING(std::to_string(primaryBridge->routerRSSI).c_str()) +
" dBm";
3842 report +=
", Internet: " +
TSTRING(primaryBridge->internetConnected ?
"✓" :
"✗") +
")\n";
3844 report +=
"Bridge: None available\n";
3849 report +=
"Direct Connections: " +
TSTRING(std::to_string(this->subs.size()).c_str()) +
"\n";
3852 auto metrics = this->getBridgeHealthMetrics();
3853 report +=
"Messages RX: " +
TSTRING(std::to_string(metrics.messagesRx).c_str()) +
"\n";
3854 report +=
"Messages TX: " +
TSTRING(std::to_string(metrics.messagesTx).c_str()) +
"\n";
3855 report +=
"Messages Dropped: " +
TSTRING(std::to_string(metrics.messagesDropped).c_str()) +
"\n";
3857 if (metrics.avgLatencyMs > 0) {
3858 report +=
"Avg Latency: " +
TSTRING(std::to_string(metrics.avgLatencyMs).c_str()) +
" ms\n";
3862 uint32_t uptimeSeconds = millis() / 1000;
3863 uint32_t hours = uptimeSeconds / 3600;
3864 uint32_t minutes = (uptimeSeconds % 3600) / 60;
3865 uint32_t seconds = uptimeSeconds % 60;
3868 snprintf(uptimeStr,
sizeof(uptimeStr),
"%02u:%02u:%02u", hours, minutes, seconds);
3869 report +=
"Uptime: " +
TSTRING(uptimeStr) +
"\n";
3872 if (diagnosticsEnabled && !electionHistory.empty()) {
3873 auto& lastElection = electionHistory.back();
3874 uint32_t timeSinceElection = millis() - lastElection.timestamp;
3875 uint32_t electionMinutes = (timeSinceElection / 1000) / 60;
3876 uint32_t electionSeconds = (timeSinceElection / 1000) % 60;
3878 char electionTimeStr[32];
3879 snprintf(electionTimeStr,
sizeof(electionTimeStr),
"%02u:%02u", electionMinutes, electionSeconds);
3881 report +=
"Last Election: " +
TSTRING(electionTimeStr) +
" ago";
3882 report +=
" (Winner: " +
TSTRING(std::to_string(lastElection.winnerNodeId).c_str());
3883 report +=
", " +
TSTRING(std::to_string(lastElection.candidateCount).c_str()) +
" candidates)\n";
3886 report +=
"================================\n";
3890 inline std::shared_ptr<Task>
addTask(
unsigned long aInterval,
3892 std::function<
void()> aCallback) {
3894 aIterations, aCallback);
3897 inline std::shared_ptr<Task>
addTask(std::function<
void()> aCallback) {
3908 inline std::shared_ptr<Task>
addTask(std::function<
void()> aCallback,
3909 unsigned long delayMs) {
3911 TASK_ONCE, aCallback);
3917 reclaimRetiredSchedulers();
3918 if (!isExternalScheduler)
delete mScheduler;
3919 if (messageQueue)
delete messageQueue;
3924 for (
auto it = retiredSchedulers.begin();
3925 it != retiredSchedulers.end();) {
3926 if ((*it)->getCurrentTask() !=
nullptr) {
3931 it = retiredSchedulers.erase(it);
3935 std::list<Scheduler*> retiredSchedulers = {};
3938 const auto key = std::make_pair(origin, msgId);
3939 if (std::find(pendingBroadcastAcks.begin(), pendingBroadcastAcks.end(),
3940 key) != pendingBroadcastAcks.end())
3942 if (pendingBroadcastAcks.size() >= MAX_QUEUED_BROADCAST_ACKS) {
3944 (
unsigned)MAX_QUEUED_BROADCAST_ACKS);
3947 pendingBroadcastAcks.push_back(key);
3948 if (!broadcastAckTask) {
3949 broadcastAckTask = this->addTask(
3951 while (!this->pendingBroadcastAcks.empty()) {
3952 auto queued = std::move(this->pendingBroadcastAcks);
3953 this->pendingBroadcastAcks.clear();
3954 for (const auto& item : queued) {
3955 auto pkg = ack::MessageAckPackage(this->nodeId, item.first,
3957 this->sendPackage(&pkg);
3961 this->nodeId % ACK_BROADCAST_JITTER_MS);
3962 }
else if (!broadcastAckTask->isEnabled() ||
3963 broadcastAckTask->isLastIteration()) {
3964 broadcastAckTask->restartDelayed();
3975 if (!ackCheckTask) {
3976 ackCheckTask = this->addTask(ACK_CHECK_INTERVAL_MS, TASK_FOREVER,
3978 if (this->checkAcks() == 0 &&
3980 this->ackCheckTask->disable();
3982 }
else if (!ackCheckTask->isEnabled()) {
3983 ackCheckTask->enable();
3992#ifndef PAINLESSMESH_ACK_CHECK_INTERVAL_MS
3993#define PAINLESSMESH_ACK_CHECK_INTERVAL_MS 100
3995 static constexpr unsigned long ACK_CHECK_INTERVAL_MS =
3999 static constexpr uint32_t ACK_BROADCAST_JITTER_MS = 50;
4001 static constexpr uint32_t ACK_BROADCAST_MIN_TIMEOUT_MS = 1000;
4002 static constexpr size_t MAX_QUEUED_BROADCAST_ACKS =
4010 this->mScheduler = baseScheduler;
4011 isExternalScheduler =
true;
4016 using namespace logger;
4017 Log(S_TIME,
"startTimeSync(): from %u with %u\n", this->nodeId,
4020 if (ntp::adopt(this->asNodeTree(), (*conn))) {
4022 this->getNodeTime());
4023 Log(S_TIME,
"startTimeSync(): Requesting time from %u\n", conn->nodeId);
4026 Log(S_TIME,
"startTimeSync(): Requesting %u to adopt our time\n",
4029 router::send<protocol::TimeSync, T>(timeSync, conn,
true);
4042 std::list<uint32_t>& neighbors, uint32_t parent = 0)
const {
4043 if (tree.
nodeId == nodeId) {
4047 neighbors.push_back(parent);
4050 for (
auto& sub : tree.
subs) {
4051 if (sub.nodeId != 0) {
4052 neighbors.push_back(sub.nodeId);
4059 for (
auto& sub : tree.
subs) {
4060 if (getNodeNeighbors(sub, nodeId, neighbors, tree.
nodeId)) {
4069 auto connection = this->subs.begin();
4070 while (connection != this->subs.end()) {
4071 if ((*connection)->station) {
4073 (*connection)->close();
4082 using namespace logger;
4083 Log(CONNECTION,
"eraseClosedConnections():\n");
4084 this->subs.remove_if(
4085 [](
const std::shared_ptr<T> &conn) {
4087 if (!conn)
return true;
4088 return !conn->connected();
4107 SemaphoreHandle_t xSemaphore = NULL;
4110 bool isExternalScheduler =
false;
4113 bool shouldContainRoot =
false;
4116 Scheduler *mScheduler =
nullptr;
4129 return xSemaphoreTake(xSemaphore, (TickType_t)1000) == pdTRUE;
4142 xSemaphoreGive(xSemaphore);
4148 uint32_t bridgeStatusIntervalMs = 30000;
4149 uint32_t bridgeTimeoutMs = 60000;
4150 bool bridgeStatusBroadcastEnabled =
true;
4152 bool _overCapacity =
false;
4153 uint32_t _capacityWarnedAt = 0;
4156 static const size_t MAX_KNOWN_BRIDGES = 20;
4157 std::shared_ptr<Task> bridgeCleanupTask =
nullptr;
4160 uint32_t metricsDisconnectCount = 0;
4166 bool diagnosticsEnabled =
false;
4168 static const size_t MAX_ELECTION_HISTORY = 10;
4170 uint32_t lastBridgeChangeTime = 0;
4174 std::shared_ptr<Task> internetHealthCheckTask =
nullptr;
4179 std::shared_ptr<Task> internetCleanupTask =
nullptr;
4180 uint32_t internetRequestTimeout = 30000;
4181 uint8_t internetRetryCount = 3;
4182 uint32_t internetRetryDelay = 1000;
4183 bool sendToInternetEnabled =
false;
4196 friend void painlessmesh::ntp::handleTimeSync<Mesh, T>(
4198 friend void painlessmesh::ntp::handleTimeDelay<Mesh, T>(
4200 friend void painlessmesh::router::handleNodeSync<Mesh, T>(
4204 uint16_t,
Mesh &, uint8_t);
4211 bool station =
true;
4212 bool newConnection =
true;
4219 uint32_t messagesRx = 0;
4220 uint32_t messagesTx = 0;
4221 uint32_t messagesDropped = 0;
4222 uint32_t timeLastReceived = 0;
4223 uint64_t bytesRx = 0;
4224 uint64_t bytesTx = 0;
4228 static const size_t MAX_LATENCY_SAMPLES = 10;
4237 auto self = this->shared_from_this();
4238 auto mesh = this->mesh;
4239 this->onReceive([self](
const TSTRING &str) {
4242 router::routePackage<painlessmesh::Connection>(
4243 (*self->mesh), self->shared_from_this(), str,
4244 self->mesh->callbackList, self->mesh->getNodeTime());
4247 this->onDisconnect([mesh, self]() {
4248 Log.
remote(
"id:%u AsyncClient disconnect\n", self->nodeId);
4249 self->timeSyncTask.setCallback(NULL);
4250 self->timeSyncTask.disable();
4251 self->nodeSyncTask.setCallback(NULL);
4252 self->nodeSyncTask.disable();
4253 self->timeOutTask.setCallback(NULL);
4254 self->timeOutTask.disable();
4255 auto nodeId = self->nodeId;
4256 auto station = self->station;
4257 mesh->
addTask([mesh, nodeId, station]() {
4264 using namespace logger;
4267 Log(CONNECTION,
"Time out reached\n");
4268 Log.
remote(
"id:%u TimeOut\n", self->nodeId);
4273 this->nodeSyncTask.set(TASK_MINUTE, TASK_FOREVER, [self]() {
4274 Log(SYNC,
"nodeSyncTask(): request with %u\n", self->nodeId);
4275 router::send<protocol::NodeSyncRequest, Connection>(
4276 self->request(self->mesh->asNodeTree()), self);
4277 self->timeOutTask.disable();
4278 self->timeOutTask.restartDelayed();
4281 mesh->
mScheduler->addTask(this->nodeSyncTask);
4283 this->nodeSyncTask.enable();
4285 this->nodeSyncTask.enableDelayed(10 * TASK_SECOND);
4287 Log(CONNECTION,
"painlessmesh::Connection: New connection established.\n");
4292 return this->write(msg, priority);
4302 return this->writeWithPriority(msg, priorityLevel);
4311 timeLastReceived = millis();
4330 latencySamples.push_back(latencyMs);
4331 if (latencySamples.size() > MAX_LATENCY_SAMPLES) {
4332 latencySamples.erase(latencySamples.begin());
4341 if (latencySamples.empty())
return -1;
4344 for (
auto sample : latencySamples) {
4347 return sum / latencySamples.size();
4359 int latency = getLatency();
4360 if (latency > 100) {
4361 quality -= (latency - 100) / 5;
4365 if (messagesTx > 0) {
4366 int lossRate = (messagesDropped * 100) / messagesTx;
4367 quality -= lossRate;
4371 int rssi = getRSSI();
4372 if (rssi < -80 && rssi != 0) {
4373 quality -= (80 + rssi);
4376 return (std::max)(0, (std::min)(100, quality));
4386 if (WiFi.status() == WL_CONNECTED) {
4390#elif defined(ESP8266)
4392 if (WiFi.status() == WL_CONNECTED) {
#define PAINLESSMESH_MAX_QUEUED_BROADCAST_ACKS
Definition ack.hpp:25
boost::asio::ip::address IPAddress
Definition asynctcp.hpp:29
Definition asynctcp.hpp:31
Definition asynctcp.hpp:217
bool isHealthy(uint32_t timeoutMs=60000) const
Definition mesh.hpp:188
bool internetConnected
Definition mesh.hpp:176
uint32_t timestamp
Definition mesh.hpp:182
uint32_t nodeId
Definition mesh.hpp:175
uint32_t lastSeen
Definition mesh.hpp:179
uint32_t uptime
Definition mesh.hpp:180
int8_t routerRSSI
Definition mesh.hpp:177
TSTRING gatewayIP
Definition mesh.hpp:181
uint8_t routerChannel
Definition mesh.hpp:178
void recordLatency(uint32_t latencyMs)
Definition mesh.hpp:4329
int getRSSI()
Definition mesh.hpp:4383
int getLatency()
Definition mesh.hpp:4340
Task nodeSyncTask
Definition mesh.hpp:4215
bool addMessage(const TSTRING &msg, bool priority=false)
Definition mesh.hpp:4291
int getQuality()
Definition mesh.hpp:4354
bool addMessageWithPriority(const TSTRING &msg, uint8_t priorityLevel)
Definition mesh.hpp:4301
Task timeOutTask
Definition mesh.hpp:4216
std::shared_ptr< Connection > shared_from_this()
Definition mesh.hpp:4403
void initTasks()
Definition mesh.hpp:4236
std::vector< uint32_t > latencySamples
Definition mesh.hpp:4227
void onMessageReceived(size_t bytes=0)
Definition mesh.hpp:4308
Task timeSyncTask
Definition mesh.hpp:4214
Connection(AsyncClient *client, Mesh< painlessmesh::Connection > *mesh, bool station)
Definition mesh.hpp:4230
void onMessageSent(bool success, size_t bytes=0)
Definition mesh.hpp:4317
Mesh< Connection > * mesh
Definition mesh.hpp:4210
friend void onDataCb(void *, AsyncClient *, void *, size_t)
size_t apChildren()
Definition mesh.hpp:1194
friend void meshRecvCb(void *, AsyncClient *, void *, size_t)
bool sendBroadcast(TSTRING msg, Priority priorityLevel, IncludeSelf includeSelf=false)
Definition mesh.hpp:840
void enableBridgeStatusBroadcast(bool enabled)
Definition mesh.hpp:1390
void setTimeAuthority(bool hasAuthority)
Definition mesh.hpp:2843
void stop()
Definition mesh.hpp:516
void enableBridgeCleanup()
Definition mesh.hpp:1459
BridgeChangeEvent getLastBridgeChange()
Definition mesh.hpp:3661
bool sendSingle(uint32_t destId, TSTRING msg, const SendOptions &options)
Definition mesh.hpp:620
void queueBroadcastAck(uint32_t origin, uint32_t msgId)
Definition mesh.hpp:3937
void onReceive(receivedCallback_t onReceive)
Definition mesh.hpp:886
std::list< uint32_t > getNodeList(bool includeSelf=false)
Definition mesh.hpp:3094
callback::List< uint32_t > newConnectionCallbacks
Definition mesh.hpp:4094
bool syncRTCFromNTP(uint32_t ntpTimestamp)
Definition mesh.hpp:2744
bool sendBroadcast(TSTRING msg, bool includeSelf, ack::deliveryCallback_t ackCallback, uint32_t ackTimeoutMs=5000)
Definition mesh.hpp:787
void setInternetRetryCount(uint8_t retryCount)
Definition mesh.hpp:1980
bool enableRTC(rtc::RTCInterface *rtcInterface)
Definition mesh.hpp:2699
void setInternetRequestTimeout(uint32_t timeoutMs)
Definition mesh.hpp:1971
bool cancelInternetRequest(uint32_t messageId)
Definition mesh.hpp:2034
uint32_t pruneQueue(uint32_t maxAgeMs)
Definition mesh.hpp:3063
std::map< uint32_t, uint32_t > getRoutingTable()
Definition mesh.hpp:3210
void setInternetRetryDelay(uint32_t delayMs)
Definition mesh.hpp:1989
void setBridgeStatusInterval(uint32_t intervalMs)
Definition mesh.hpp:1372
void onNodeTimeAdjusted(nodeTimeAdjustedCallback_t onTimeAdjusted)
Definition mesh.hpp:966
BridgeStatus getBridgeStatus()
Definition mesh.hpp:3593
friend void tcpSentCb(void *, AsyncClient *, size_t, uint32_t)
uint32_t getQueuedMessageCount(MessagePriority priority)
Definition mesh.hpp:3009
void resetHealthMetrics()
Definition mesh.hpp:3443
uint32_t getAccurateTime()
Definition mesh.hpp:2770
rtc::RTCType getRTCType() const
Definition mesh.hpp:2795
uint32_t metricsDisconnectCount
Definition mesh.hpp:4160
bool isRoot()
Definition mesh.hpp:506
std::shared_ptr< Task > ackCheckTask
Definition mesh.hpp:4005
uint32_t getTimeSinceRTCSync() const
Definition mesh.hpp:2804
void sendGatewayAck(const gateway::GatewayDataPackage &request, bool success, uint16_t httpStatus, const TSTRING &error, std::shared_ptr< T > ingressConnection=nullptr, const TSTRING &response=TSTRING(), int8_t retryable=-1, uint32_t retryAfterMs=0)
Definition mesh.hpp:2138
size_t getGatewayCount()
Definition mesh.hpp:1333
std::shared_ptr< Task > addTask(std::function< void()> aCallback)
Definition mesh.hpp:3897
std::vector< std::pair< uint32_t, uint32_t > > pendingBroadcastAcks
Definition mesh.hpp:4006
void reclaimRetiredSchedulers()
Definition mesh.hpp:3923
bool uplinkServesLocally()
Definition mesh.hpp:1539
void setTcpRetryConfig(const painlessmesh::tcp::TcpRetryConfig &config)
Definition mesh.hpp:2006
void disableSendToInternet()
Definition mesh.hpp:2092
int getHopCount(uint32_t nodeId)
Definition mesh.hpp:3150
uint32_t queueMessage(const TSTRING &payload, const TSTRING &destination="", MessagePriority priority=PRIORITY_NORMAL)
Definition mesh.hpp:2936
gateway::InternetStatus getInternetStatus()
Definition mesh.hpp:1589
uint32_t incrementQueuedMessageAttempts(uint32_t messageId)
Definition mesh.hpp:2995
BridgeInfo * getLastKnownBridge()
Definition mesh.hpp:1138
BridgeHealthMetrics getBridgeHealthMetrics()
Definition mesh.hpp:3346
std::vector< QueuedMessage > flushMessageQueue()
Definition mesh.hpp:2967
void resetInternetHealthStats()
Definition mesh.hpp:1712
localInternetChangedCallback_t localInternetChangedCallback
Definition mesh.hpp:4175
bool getNodeNeighbors(const protocol::NodeTree &tree, uint32_t nodeId, std::list< uint32_t > &neighbors, uint32_t parent=0) const
Definition mesh.hpp:4041
void onLocalInternetChanged(localInternetChangedCallback_t callback)
Definition mesh.hpp:1568
ack::AckTracker ackTracker
Definition mesh.hpp:4004
void onChangedConnections(changedConnectionsCallback_t onChangedConnections)
Definition mesh.hpp:945
uint32_t getQueuedMessageCount()
Definition mesh.hpp:3017
rtcSyncCompleteCallback_t rtcSyncCompleteCallback
Definition mesh.hpp:4100
bool isConnected(uint32_t nodeId)
Definition mesh.hpp:3085
std::vector< ConnectionInfo > getConnectionDetails()
Definition mesh.hpp:3123
void clearQueue()
Definition mesh.hpp:3074
bool getTimeAuthority() const
Definition mesh.hpp:2864
void configureInternetHealthCheck(const gateway::SharedGatewayConfig &config)
Definition mesh.hpp:1601
void ensureAckScheduling()
Definition mesh.hpp:3974
QueueStats getQueueStats()
Definition mesh.hpp:3030
void onHealthMetricsUpdate(std::function< void(BridgeHealthMetrics)> callback, uint32_t intervalMs=60000)
Definition mesh.hpp:3546
void setBridgeTimeout(uint32_t timeoutMs)
Definition mesh.hpp:1381
std::vector< BridgeInfo > getBridges()
Definition mesh.hpp:1087
void enableDiagnostics(bool enabled=true)
Definition mesh.hpp:3570
void setInternetCheckInterval(uint32_t intervalMs)
Definition mesh.hpp:1622
nodeTimeAdjustedCallback_t nodeTimeAdjustedCallback
Definition mesh.hpp:4097
TSTRING getHealthMetricsJSON()
Definition mesh.hpp:3476
bool sendBroadcast(TSTRING msg, bool includeSelf=false)
Definition mesh.hpp:686
bool forgetBridge(uint32_t bridgeNodeId)
Definition mesh.hpp:1416
bool hasRTC() const
Definition mesh.hpp:2786
std::vector< ElectionRecord > electionHistory
Definition mesh.hpp:4167
bool isInternetHealthCheckEnabled() const
Definition mesh.hpp:1705
void setRoot(bool on=true)
Definition mesh.hpp:492
bool sendSingle(uint32_t destId, TSTRING msg, uint8_t priorityLevel)
Definition mesh.hpp:598
Scheduler * mScheduler
Definition mesh.hpp:4116
void init(Scheduler *scheduler, uint32_t id)
Definition mesh.hpp:438
void eraseClosedConnections()
Definition mesh.hpp:4081
std::map< uint32_t, PendingInternetRequest > pendingInternetRequests
Definition mesh.hpp:4178
TSTRING getDiagnosticReport()
Definition mesh.hpp:3822
callback::List< uint32_t > changedConnectionCallbacks
Definition mesh.hpp:4096
uint32_t sendToInternet(TSTRING destination, TSTRING payload, internetResponseCallback_t onResult, uint8_t priority=static_cast< uint8_t >(gateway::GatewayPriority::PRIORITY_NORMAL))
Definition mesh.hpp:1793
size_t getPendingInternetRequestCount() const
Definition mesh.hpp:2024
uint32_t getPrimaryGateway()
Definition mesh.hpp:1283
void setInternetCheckTarget(const TSTRING &host, uint16_t port=53)
Definition mesh.hpp:1613
void cleanupExpiredBridges()
Definition mesh.hpp:1427
void setScheduler(Scheduler *baseScheduler)
Definition mesh.hpp:4009
rtc::RTCManager rtcManager
Definition mesh.hpp:4163
void enableMessageQueue(bool enabled, uint32_t maxSize=1000)
Definition mesh.hpp:2903
bool isBridgeCleanupEnabled() const
Definition mesh.hpp:1496
bool sendBroadcast(TSTRING msg, const SendOptions &options, bool includeSelf=false)
Definition mesh.hpp:712
std::list< uint32_t > getGateways()
Definition mesh.hpp:1310
void setInternetCheckTimeout(uint32_t timeoutMs)
Definition mesh.hpp:1631
std::vector< BridgeInfo > knownBridges
Definition mesh.hpp:4147
bool startDelayMeas(uint32_t id)
Definition mesh.hpp:854
bool closeConnectionSTA()
Definition mesh.hpp:4068
bool sendSingle(uint32_t destId, TSTRING msg)
Definition mesh.hpp:586
void onBridgeStatusChanged(bridgeStatusChangedCallback_t onBridgeStatusChanged)
Definition mesh.hpp:1003
void onQueueStateChanged(queueStateChangedCallback_t callback)
Definition mesh.hpp:3051
void disableInternetHealthCheck()
Definition mesh.hpp:1691
bool capacityCheck(uint32_t freeHeap, uint32_t floor)
Definition mesh.hpp:1221
void enableSendToInternet()
Definition mesh.hpp:2063
bool hasActiveMeshConnections()
Definition mesh.hpp:1168
void updateBridgeStatus(uint32_t bridgeNodeId, bool internetConnected, int8_t routerRSSI, uint8_t routerChannel, uint32_t uptime, TSTRING gatewayIP, uint32_t timestamp)
Definition mesh.hpp:2582
void setContainsRoot(bool on=true)
Definition mesh.hpp:501
callback::List< uint32_t, bool > droppedConnectionCallbacks
Definition mesh.hpp:4095
size_t checkAcks()
Definition mesh.hpp:806
painlessmesh::tcp::TcpRetryConfig tcpRetryConfig
Definition mesh.hpp:4190
void enableInternetHealthCheck()
Definition mesh.hpp:1661
void disableRTC()
Definition mesh.hpp:2713
nodeDelayCallback_t nodeDelayReceivedCallback
Definition mesh.hpp:4098
TSTRING exportTopologyDOT()
Definition mesh.hpp:3679
bool isExternalScheduler
Definition mesh.hpp:4110
painlessmesh::tcp::TcpRetryConfig getTcpRetryConfig() const
Definition mesh.hpp:2015
bool isPrimaryGateway()
Definition mesh.hpp:1258
bool overCapacity()
Definition mesh.hpp:1214
gateway::InternetHealthChecker internetHealthChecker
Definition mesh.hpp:4173
bool semaphoreTake()
Definition mesh.hpp:4127
void onNodeDelayReceived(nodeDelayCallback_t onDelayReceived)
Definition mesh.hpp:983
bool sendSingle(uint32_t destId, TSTRING msg, ack::deliveryCallback_t ackCallback, uint32_t ackTimeoutMs=5000)
Definition mesh.hpp:671
void update(void)
Definition mesh.hpp:562
uint32_t sendToInternet(TSTRING destination, TSTRING payload, internetResultCallback_t callback, uint8_t priority=static_cast< uint8_t >(gateway::GatewayPriority::PRIORITY_NORMAL))
Definition mesh.hpp:1774
size_t pendingAcks() const
Definition mesh.hpp:821
~Mesh()
Definition mesh.hpp:3914
bool isSendToInternetEnabled() const
Definition mesh.hpp:2115
BridgeTestResult testBridgeConnectivity()
Definition mesh.hpp:3741
TSTRING subConnectionJson(bool pretty=false)
Definition mesh.hpp:3101
std::vector< uint32_t > getPathToNode(uint32_t nodeId)
Definition mesh.hpp:3274
bridgeStatusChangedCallback_t bridgeStatusChangedCallback
Definition mesh.hpp:4099
void onNewConnection(newConnectionCallback_t onNewConnection)
Definition mesh.hpp:914
bool removeQueuedMessage(uint32_t messageId)
Definition mesh.hpp:2981
friend T
Definition mesh.hpp:4192
bool hasLocalInternet()
Definition mesh.hpp:1521
void semaphoreGive()
Definition mesh.hpp:4140
void onDroppedConnection(droppedConnectionCallback_t onDroppedConnection)
Definition mesh.hpp:930
gatewayChangedCallback_t gatewayChangedCallback
Definition mesh.hpp:4101
bool isBridgeReachable(uint32_t bridgeNodeId)
Definition mesh.hpp:3798
bool isBridge()
Definition mesh.hpp:1183
bool checkInternetNow()
Definition mesh.hpp:1643
std::shared_ptr< Task > broadcastAckTask
Definition mesh.hpp:4007
std::vector< uint32_t > getNodesWithInternet()
Definition mesh.hpp:1072
BridgeChangeEvent lastBridgeChange
Definition mesh.hpp:4169
std::shared_ptr< Task > addTask(unsigned long aInterval, long aIterations, std::function< void()> aCallback)
Definition mesh.hpp:3890
void init(uint32_t id)
Definition mesh.hpp:289
BridgeInfo * getPrimaryBridge()
Definition mesh.hpp:1109
void startTimeSync(std::shared_ptr< T > conn)
Definition mesh.hpp:4015
std::shared_ptr< Task > addTask(std::function< void()> aCallback, unsigned long delayMs)
Definition mesh.hpp:3908
void disableBridgeCleanup()
Definition mesh.hpp:1480
void setDebugMsgTypes(uint16_t types)
Definition mesh.hpp:511
bool hasInternetConnection()
Definition mesh.hpp:1046
void onRTCSyncComplete(rtcSyncCompleteCallback_t onRTCSyncComplete)
Definition mesh.hpp:2819
void onGatewayChanged(gatewayChangedCallback_t callback)
Definition mesh.hpp:1362
std::vector< ElectionRecord > getElectionHistory()
Definition mesh.hpp:3638
Definition message_queue.hpp:112
bool collectAck(uint32_t msgId, uint32_t fromNode, uint32_t now, std::list< DeliveryResult > &results)
Definition ack.hpp:196
void seed(uint32_t value)
Definition ack.hpp:133
Definition callback.hpp:18
int execute(Args... args)
Definition callback.hpp:20
void push_back(std::function< void(Args...)> func)
Definition callback.hpp:45
Gateway Acknowledgment Package for delivery confirmations.
Definition gateway.hpp:1651
TSTRING response
The start of the response body, summarized to one line.
Definition gateway.hpp:1709
bool success
Delivery success status.
Definition gateway.hpp:1675
uint32_t messageId
Original message ID being acknowledged.
Definition gateway.hpp:1659
int8_t retryable
Whether the origin node may resend the identical request.
Definition gateway.hpp:1719
uint32_t timestamp
Acknowledgment timestamp.
Definition gateway.hpp:1700
uint32_t retryAfterMs
How long the server asked to wait before a retry, in milliseconds.
Definition gateway.hpp:1727
uint16_t httpStatus
HTTP response code (if applicable)
Definition gateway.hpp:1684
uint32_t originNode
Original sender node ID.
Definition gateway.hpp:1667
TSTRING error
Error message (if failed)
Definition gateway.hpp:1692
Gateway Data Package for routing Internet requests through mesh.
Definition gateway.hpp:815
uint32_t timestamp
Creation timestamp.
Definition gateway.hpp:839
uint8_t priority
Message priority (0=CRITICAL, 1=HIGH, 2=NORMAL, 3=LOW)
Definition gateway.hpp:847
TSTRING destination
Destination URL or endpoint.
Definition gateway.hpp:857
TSTRING payload
Application payload data.
Definition gateway.hpp:865
TSTRING contentType
MIME content type.
Definition gateway.hpp:875
uint32_t messageId
Unique message identifier.
Definition gateway.hpp:823
bool requiresAck
Whether acknowledgment is required.
Definition gateway.hpp:891
uint32_t requestNonce
Random value drawn once per sendToInternet() call.
Definition gateway.hpp:903
uint32_t originNode
Node ID that originated this message.
Definition gateway.hpp:831
uint8_t retryCount
Number of relay attempts.
Definition gateway.hpp:883
static uint32_t generateMessageId(uint32_t nodeId)
Generate a unique message ID.
Definition gateway.hpp:1011
Internet Health Checker class for periodic connectivity monitoring.
Definition gateway.hpp:498
uint32_t nodeId
Definition layout.hpp:125
Definition layout.hpp:159
void remote(const char *format...)
Definition logger.hpp:160
void setLogLevel(uint16_t newTypes)
Definition logger.hpp:56
uint32_t from
Definition plugin.hpp:71
Definition plugin.hpp:178
bool sendPackage(const protocol::PackageInterface *pkg)
Definition plugin.hpp:223
void reclaimQuarantinedTasks()
Definition plugin.hpp:294
std::shared_ptr< Task > addTask(Scheduler &scheduler, unsigned long aInterval, long aIterations, std::function< void()> aCallback)
Definition plugin.hpp:255
callback::MeshPackageCallbackList< T > callbackList
Definition plugin.hpp:307
void stop(Scheduler *scheduler=nullptr)
Definition plugin.hpp:185
uint32_t dest
Definition plugin.hpp:46
uint32_t from
Definition plugin.hpp:45
TSTRING md5
Definition ota.hpp:78
size_t noPart
Definition ota.hpp:115
bool compressed
Definition ota.hpp:113
bool forced
Definition ota.hpp:97
TSTRING role
The type of node the firmware is meant for.
Definition ota.hpp:91
TSTRING hardware
Definition ota.hpp:79
bool broadcasted
Definition ota.hpp:105
Definition protocol.hpp:146
Definition protocol.hpp:167
std::list< NodeTree > subs
Definition protocol.hpp:172
uint32_t nodeId
Definition protocol.hpp:169
Definition protocol.hpp:93
Definition protocol.hpp:463
Definition protocol.hpp:355
Definition protocol.hpp:481
int type()
Definition protocol.hpp:750
uint32_t from()
Definition protocol.hpp:758
uint32_t msgId()
Definition protocol.hpp:766
T to()
Definition protocol.hpp:743
Definition connection.hpp:151
static uint32_t generate()
Definition validation.hpp:54
#define NODE_TIMEOUT
Definition configuration.hpp:105
String TSTRING
Definition configuration.hpp:132
Shared Gateway Mode configuration for painlessMesh.
#define PAINLESSMESH_ACK_CHECK_INTERVAL_MS
Definition mesh.hpp:3993
std::function< void(uint32_t nodeId, bool delivered, uint32_t latencyMs)> deliveryCallback_t
Definition ack.hpp:53
@ PRIORITY_NORMAL
Normal priority - standard processing.
bool reserveGatewayBlockingBudget(T &connection)
Definition gateway.hpp:1929
bool responseContains(const TSTRING &haystack, const char *needle)
Definition gateway.hpp:1162
uint32_t newRequestNonce()
Definition gateway.hpp:1432
std::list< uint32_t > asList(protocol::NodeTree nodeTree, bool includeSelf=true)
Definition layout.hpp:262
@ GENERAL
Definition logger.hpp:26
@ ERROR
Definition logger.hpp:19
@ COMMUNICATION
Definition logger.hpp:25
@ DEBUG
Definition logger.hpp:30
void addPackageCallback(callback::MeshPackageCallbackList< U > &callbackList, T &mesh)
Definition ntp.hpp:252
void addSendPackageCallback(Scheduler &scheduler, plugin::PackageHandler< T > &mesh, otaDataPacketCallbackType_t callback, size_t otaPartSize)
Definition ota.hpp:348
void addReceivePackageCallback(Scheduler &scheduler, plugin::PackageHandler< T > &mesh, TSTRING role="", std::function< void(int, int)> progress_cb=NULL)
Definition ota.hpp:388
std::function< size_t(painlessmesh::plugin::ota::DataRequest, char *buffer)> otaDataPacketCallbackType_t
Definition ota.hpp:345
constexpr int GATEWAY_ACK
Definition protocol.hpp:62
constexpr uint8_t PRIORITY_NORMAL
Definition protocol.hpp:73
constexpr int MESSAGE_ACK
Definition protocol.hpp:66
@ SINGLE
Definition protocol.hpp:42
@ BROADCAST
Definition protocol.hpp:41
constexpr int GATEWAY_DATA
Definition protocol.hpp:61
constexpr int BRIDGE_STATUS
Definition protocol.hpp:54
void addPackageCallback(callback::MeshPackageCallbackList< U > &callbackList, T &mesh)
Definition router.hpp:465
bool send(T &package, std::shared_ptr< U > conn, bool priority=false)
Definition router.hpp:65
bool sendWithPriority(T &package, std::shared_ptr< U > conn, uint8_t priorityLevel)
Definition router.hpp:98
RTCType
Definition rtc.hpp:15
TcpRetryConfig clampTcpRetryConfig(TcpRetryConfig cfg)
Definition tcp.hpp:101
std::function< void(uint32_t timestamp)> rtcSyncCompleteCallback_t
Definition mesh.hpp:38
std::function< void()> changedConnectionsCallback_t
Definition mesh.hpp:34
std::function< void(bool success, uint16_t httpStatus, TSTRING error)> internetResultCallback_t
Definition mesh.hpp:82
std::function< void(QueueState state, uint32_t messageCount)> queueStateChangedCallback_t
Definition message_queue.hpp:73
std::function< void(uint32_t nodeId)> newConnectionCallback_t
Definition mesh.hpp:31
MessagePriority
Definition message_queue.hpp:18
@ PRIORITY_NORMAL
Definition message_queue.hpp:21
std::function< void(uint32_t from, TSTRING &msg)> receivedCallback_t
Definition mesh.hpp:33
std::function< void(int32_t offset)> nodeTimeAdjustedCallback_t
Definition mesh.hpp:35
std::function< void(uint32_t bridgeNodeId, bool internetAvailable)> bridgeStatusChangedCallback_t
Definition mesh.hpp:37
std::function< void(const InternetResult &result)> internetResponseCallback_t
Definition mesh.hpp:131
std::function< void(bool available)> localInternetChangedCallback_t
Definition mesh.hpp:39
std::function< void(uint32_t oldPrimary, uint32_t newPrimary)> gatewayChangedCallback_t
Definition mesh.hpp:40
std::function< void(uint32_t nodeId, int32_t delay)> nodeDelayCallback_t
Definition mesh.hpp:36
std::function< void(uint32_t nodeId)> droppedConnectionCallback_t
Definition mesh.hpp:32
TSTRING reason
Definition mesh.hpp:264
uint32_t oldBridgeId
Definition mesh.hpp:262
uint32_t timestamp
Definition mesh.hpp:261
uint32_t newBridgeId
Definition mesh.hpp:263
bool internetAvailable
Definition mesh.hpp:265
uint32_t messagesQueued
Definition mesh.hpp:219
uint32_t messagesTx
Definition mesh.hpp:218
uint64_t bytesTx
Definition mesh.hpp:216
int8_t minRSSI
Definition mesh.hpp:211
int8_t avgRSSI
Definition mesh.hpp:210
uint32_t avgLatencyMs
Definition mesh.hpp:223
uint32_t currentUptime
Definition mesh.hpp:206
uint32_t internetUptimeSeconds
Definition mesh.hpp:204
uint32_t meshNodeCount
Definition mesh.hpp:225
uint32_t messagesDropped
Definition mesh.hpp:220
uint32_t messagesRx
Definition mesh.hpp:217
int8_t maxRSSI
Definition mesh.hpp:212
int8_t currentRSSI
Definition mesh.hpp:209
uint32_t uptimeSeconds
Definition mesh.hpp:203
uint8_t packetLossPercent
Definition mesh.hpp:224
uint64_t bytesRx
Definition mesh.hpp:215
uint32_t totalDisconnects
Definition mesh.hpp:205
bool internetConnected
Definition mesh.hpp:235
uint32_t timeSinceBridgeChange
Definition mesh.hpp:239
TSTRING role
Definition mesh.hpp:236
int8_t bridgeRSSI
Definition mesh.hpp:238
uint32_t bridgeNodeId
Definition mesh.hpp:237
bool isBridge
Definition mesh.hpp:234
bool success
Definition mesh.hpp:274
TSTRING message
Definition mesh.hpp:278
bool internetReachable
Definition mesh.hpp:276
uint32_t latencyMs
Definition mesh.hpp:277
bool bridgeReachable
Definition mesh.hpp:275
uint32_t candidateCount
Definition mesh.hpp:251
uint32_t timestamp
Definition mesh.hpp:248
uint32_t winnerNodeId
Definition mesh.hpp:249
TSTRING reason
Definition mesh.hpp:252
int8_t winnerRSSI
Definition mesh.hpp:250
bool retryable
Definition mesh.hpp:116
uint8_t attempts
Definition mesh.hpp:118
bool success
Definition mesh.hpp:104
uint16_t httpStatus
Definition mesh.hpp:106
uint32_t messageId
Definition mesh.hpp:102
TSTRING response
Definition mesh.hpp:110
TSTRING error
Definition mesh.hpp:108
uint32_t nodeId
Definition mesh.hpp:3109
uint32_t messagesRx
Definition mesh.hpp:3115
int quality
Definition mesh.hpp:3114
int rssi
Definition mesh.hpp:3111
uint32_t lastSeen
Definition mesh.hpp:3110
int avgLatency
Definition mesh.hpp:3112
uint32_t messagesTx
Definition mesh.hpp:3116
uint32_t messagesDropped
Definition mesh.hpp:3117
int hopCount
Definition mesh.hpp:3113
uint8_t priority
Priority level (0=CRITICAL to 3=LOW)
Definition mesh.hpp:143
internetResponseCallback_t onResult
Definition mesh.hpp:150
uint32_t gatewayNodeId
Target gateway node ID.
Definition mesh.hpp:146
TSTRING lastError
Definition mesh.hpp:158
uint32_t timestamp
When request was sent (millis)
Definition mesh.hpp:140
uint32_t messageId
Unique message ID.
Definition mesh.hpp:139
uint32_t retryDelayMs
Current retry delay (for exponential backoff)
Definition mesh.hpp:145
uint8_t attempts
Definition mesh.hpp:153
uint8_t maxRetries
Maximum retry attempts.
Definition mesh.hpp:142
uint32_t requestNonce
Drawn once for the call, sent on every attempt (GatewayDataPackage).
Definition mesh.hpp:155
internetResultCallback_t callback
User callback for result.
Definition mesh.hpp:149
bool isTimedOut() const
Definition mesh.hpp:163
uint32_t timeoutMs
Timeout in milliseconds.
Definition mesh.hpp:144
TSTRING payload
Request payload.
Definition mesh.hpp:148
TSTRING destination
Internet destination URL.
Definition mesh.hpp:147
uint8_t retryCount
Number of retries attempted.
Definition mesh.hpp:141
Definition message_queue.hpp:58
uint8_t priority
Definition mesh.hpp:65
ack::deliveryCallback_t ackCallback
Definition mesh.hpp:69
uint32_t ackTimeoutMs
Definition mesh.hpp:71
Structure to hold Internet connectivity check results.
Definition gateway.hpp:431
Configuration structure for Shared Gateway Mode.
Definition gateway.hpp:162
painlessmesh::logger::LogClass Log
Definition wifi.cpp:2