Skip to content

Examples

github-actions[bot] edited this page Nov 25, 2025 · 41 revisions

Examples and API Usage

This page provides practical examples of using painlessMesh.

alteriom

//************************************************************
// AlteriomPainlessMesh Example
//
// This example demonstrates how to use AlteriomPainlessMesh
// with custom packages for sensor data, commands, and status
// 
// This is the primary example that matches the folder name
// for Arduino Library Manager compatibility
//************************************************************

#include "AlteriomPainlessMesh.h"
#include "alteriom_sensor_package.hpp"

#define MESH_PREFIX "AlteriomMesh"
#define MESH_PASSWORD "somethingSneaky"
#define MESH_PORT 5555

Scheduler userScheduler;  // to control your personal task
painlessMesh mesh;

// Alteriom package handlers
using namespace alteriom;

// User stub
void sendSensorData();
void handleIncomingPackage(uint32_t from, String& msg);
void handleCommandPackage(CommandPackage& cmd);
void handleStatusRequest();

Task taskSendSensorData(30000, TASK_FOREVER, &sendSensorData);
Task taskSendStatus(60000, TASK_FOREVER, &handleStatusRequest);

void setup() {
  Serial.begin(115200);

  // Initialize mesh
  mesh.setDebugMsgTypes(ERROR | MESH_STATUS | CONNECTION | SYNC |
                        COMMUNICATION | GENERAL | MSG_TYPES | REMOTE);
  mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
  mesh.onReceive(&handleIncomingPackage);
  mesh.onNewConnection(&newConnectionCallback);
  mesh.onChangedConnections(&changedConnectionCallback);
  mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);

  // Add tasks
  userScheduler.addTask(taskSendSensorData);
  taskSendSensorData.enable();

  userScheduler.addTask(taskSendStatus);
  taskSendStatus.enable();

alteriomImproved

/**
 * Improved Sensor Node Example with Validation and Metrics
 *
 * This example demonstrates the new security and performance improvements
 * in painlessMesh including input validation, rate limiting, and performance
 * metrics.
 */

#include "painlessTaskOptions.h"  // Must be first to configure TaskScheduler
#include <TaskScheduler.h>  // Required for LDF to find TaskScheduler dependency
#include "alteriom_sensor_package.hpp"
#include "painlessMesh.h"

// Note: The improvement modules (validation, metrics, memory) are automatically
// included through painlessMesh.h when the corresponding features are enabled

#define MESH_PREFIX "AlteriomImprovedMesh"
#define MESH_PASSWORD "securePassword123"
#define MESH_PORT 5555

#define SENSOR_TASK_INTERVAL 30000   // Send sensor data every 30 seconds
#define METRICS_TASK_INTERVAL 60000  // Report metrics every minute
#define VALIDATION_ENABLED true      // Enable message validation

Scheduler userScheduler;
painlessMesh mesh;

// New improvement features
painlessmesh::validation::MessageValidator validator;
painlessmesh::validation::RateLimiter rateLimiter(5, 1000);  // 5 msgs/sec max
painlessmesh::metrics::MetricsCollector metrics;
painlessmesh::memory::ObjectPool<alteriom::SensorPackage> sensorPool(5);

// Task declarations
Task sensorTask(SENSOR_TASK_INTERVAL, TASK_FOREVER, &sendSensorData);
Task metricsTask(METRICS_TASK_INTERVAL, TASK_FOREVER, &reportMetrics);

void setup() {
  Serial.begin(115200);

  // Configure validation with custom settings
  painlessmesh::validation::ValidationConfig config;
  config.max_message_size = 4096;      // Smaller max size for sensors
  config.max_string_length = 256;      // Reasonable string limits
  config.strict_type_checking = true;  // Enable strict validation
  validator.set_config(config);

  mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
  mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
  mesh.onReceive(&receivedCallback);

alteriomMetricsHealth

/**
 * Alteriom Metrics and Health Monitoring Node
 * 
 * This example demonstrates the new MetricsPackage (Type 204) and 
 * HealthCheckPackage (Type 605) introduced in painlessMesh v1.7.7.
 * 
 * Features:
 * - Comprehensive performance metrics collection
 * - Proactive health monitoring with problem detection
 * - Configurable collection intervals
 * - Alert threshold detection
 * - Memory leak detection
 * - Network quality monitoring
 * 
 * Hardware: ESP32 or ESP8266
 */

#include "painlessMesh.h"
#include "alteriom_sensor_package.hpp"

using namespace alteriom;

// Mesh Configuration
#define MESH_PREFIX     "AlteriomMesh"
#define MESH_PASSWORD   "your_password"
#define MESH_PORT       5555

// Collection Intervals (milliseconds)
#define METRICS_INTERVAL   30000  // 30 seconds
#define HEALTH_INTERVAL    60000  // 60 seconds

Scheduler userScheduler;
painlessMesh mesh;

// Tasks
Task taskSendMetrics(METRICS_INTERVAL, TASK_FOREVER, &sendMetrics);
Task taskSendHealth(HEALTH_INTERVAL, TASK_FOREVER, &sendHealthCheck);

// Metrics tracking
uint32_t loopCount = 0;
uint32_t lastLoopCount = 0;
uint32_t lastMetricsTime = 0;
uint32_t maxLoopDuration = 0;
uint32_t loopStartTime = 0;

// Network statistics
uint32_t totalBytesRx = 0;
uint32_t totalBytesTx = 0;
uint32_t totalPacketsRx = 0;
uint32_t totalPacketsTx = 0;

alteriomPhase1

/**
 * Phase 1 OTA Features Example - Compressed OTA & Enhanced Status
 *
 * This example demonstrates the Phase 1 enhancements to painlessMesh:
 * - Option 1E: Compressed OTA Transfer for 40-60% bandwidth reduction
 * - Option 2A: Enhanced StatusPackage with comprehensive metrics
 *
 * Features:
 * - Compressed firmware updates reduce network bandwidth
 * - Enhanced status reporting with mesh statistics and performance metrics
 * - Backward compatible with existing nodes
 */

#include "alteriom_sensor_package.hpp"
#include "painlessMesh.h"

#define MESH_PREFIX "AlteriomPhase1Mesh"
#define MESH_PASSWORD "phase1Features"
#define MESH_PORT 5555

#define STATUS_INTERVAL 30000  // Send enhanced status every 30 seconds

Scheduler userScheduler;
painlessMesh mesh;

// Task declarations
Task statusTask(STATUS_INTERVAL, TASK_FOREVER, &sendEnhancedStatus);

// Metrics tracking
unsigned long lastRebootTime = 0;
uint32_t totalMessagesReceived = 0;
uint32_t totalMessagesSent = 0;

void setup() {
  Serial.begin(115200);
  
  lastRebootTime = millis();
  
  mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
  mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
  
  mesh.onReceive(&receivedCallback);
  mesh.onNewConnection(&newConnectionCallback);
  mesh.onChangedConnections(&changedConnectionCallback);
  
  // Add the enhanced status reporting task
  userScheduler.addTask(statusTask);
  statusTask.enable();
  
  Serial.println("Phase 1 Features Example Started");

alteriomPhase2

//************************************************************
// Phase 2 Features Example
//
// This example demonstrates the two major Phase 2 features:
// 1. Broadcast OTA (Option 1A) - True mesh-wide firmware distribution
// 2. MQTT Status Bridge (Option 2E) - Professional monitoring
//
// Phase 2 builds on Phase 1's foundation:
// - Phase 1: Compressed OTA + Enhanced Status
// - Phase 2: Broadcast OTA + MQTT Status Bridge
//
// Broadcast OTA Benefits:
// - Dramatically reduces network traffic (1 broadcast vs N unicasts)
// - Faster distribution to large meshes (parallel vs sequential)
// - Scales to 50+ nodes efficiently
// - Backward compatible with Phase 1
//
// MQTT Status Bridge Benefits:
// - Professional monitoring tools (Grafana, InfluxDB, Prometheus)
// - Cloud integration via MQTT
// - Real-time mesh visibility
// - Automated alerting
//************************************************************

#include "painlessMesh.h"

// Mesh configuration
#define   MESH_PREFIX     "AlteriomMesh"
#define   MESH_PASSWORD   "meshPassword123"
#define   MESH_PORT       5555

// OTA configuration
#define   OTA_PART_SIZE   1024  // Chunk size for OTA transfers

Scheduler userScheduler;
painlessMesh mesh;

// Prototypes
void sendBroadcastOTA();
void receivedCallback(uint32_t from, String& msg);
void newConnectionCallback(uint32_t nodeId);
void changedConnectionCallback();

void setup() {
  Serial.begin(115200);
  Serial.println("\n\n=== Phase 2 Features Demo ===\n");
  
  mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
  mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
  mesh.onReceive(&receivedCallback);

alteriomSensorNode

//************************************************************
// Alteriom Sensor Node Example
//
// This example demonstrates how to create an Alteriom-specific
// sensor node using custom packages with painlessMesh
//************************************************************

#include "painlessTaskOptions.h"  // Must be first to configure TaskScheduler
#include <TaskScheduler.h>  // Required for LDF to find TaskScheduler dependency
#include "alteriom_sensor_package.hpp"
#include "painlessMesh.h"

#define MESH_PREFIX "AlteriomMesh"
#define MESH_PASSWORD "somethingSneaky"
#define MESH_PORT 5555

Scheduler userScheduler;  // to control your personal task
painlessMesh mesh;

// Alteriom package handlers
using namespace alteriom;

// User stub
void sendSensorData();
void handleIncomingPackage(uint32_t from, String& msg);
void handleCommandPackage(CommandPackage& cmd);
void handleStatusRequest();

Task taskSendSensorData(30000, TASK_FOREVER, &sendSensorData);
Task taskSendStatus(60000, TASK_FOREVER, &handleStatusRequest);

void setup() {
  Serial.begin(115200);

  // Initialize mesh
  mesh.setDebugMsgTypes(ERROR | MESH_STATUS | CONNECTION | SYNC |
                        COMMUNICATION | GENERAL | MSG_TYPES | REMOTE);
  mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
  mesh.onReceive(&handleIncomingPackage);
  mesh.onNewConnection(&newConnectionCallback);
  mesh.onChangedConnections(&changedConnectionCallback);
  mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);

  // Add tasks
  userScheduler.addTask(taskSendSensorData);
  taskSendSensorData.enable();

  userScheduler.addTask(taskSendStatus);
  taskSendStatus.enable();

basic

//************************************************************
// this is a simple example that uses the painlessMesh library
//
// 1. sends a silly message to every node on the mesh at a random time between 1 and 5 seconds
// 2. prints anything it receives to Serial.print
//
//
//************************************************************
#include "painlessMesh.h"

#define   MESH_PREFIX     "whateverYouLike"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555

Scheduler userScheduler; // to control your personal task
painlessMesh  mesh;

// User stub
void sendMessage() ; // Prototype so PlatformIO doesn't complain

Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );

void sendMessage() {
  String msg = "Hello from node ";
  msg += mesh.getNodeId();
  mesh.sendBroadcast( msg );
  taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 5 ));
}

// Needed for painless library
void receivedCallback( uint32_t from, String &msg ) {
  Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str());
}

void newConnectionCallback(uint32_t nodeId) {
    Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
}

void changedConnectionCallback() {
  Serial.printf("Changed connections\n");
}

void nodeTimeAdjustedCallback(int32_t offset) {
    Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset);
}

void setup() {
  Serial.begin(115200);

//mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on

bridge

//************************************************************
// Bridge Node Example - Automatic Channel Detection
//
// This example demonstrates the new bridge-centric architecture that
// automatically detects the router's WiFi channel and configures the
// mesh network accordingly.
//
// Features:
// - Connects to router FIRST and auto-detects its channel
// - Creates mesh network on the same channel as router
// - No manual channel configuration required
// - Automatically sets itself as root node
// - Broadcasts bridge status to mesh (Type 610 - BRIDGE_STATUS)
//   - Reports Internet connectivity status
//   - Updates every 30 seconds by default
//   - Enables nodes to implement failover and queueing logic
//
// For more details, see BRIDGE_TO_INTERNET.md
//************************************************************
#include "painlessMesh.h"

// Mesh network configuration
#define MESH_PREFIX "whateverYouLike"
#define MESH_PASSWORD "somethingSneaky"
#define MESH_PORT 5555

// Router credentials
#define ROUTER_SSID "MSYSSID"
#define ROUTER_PASSWORD "SSIDPASSWORD"

// prototypes
void receivedCallback(uint32_t from, String &msg);

Scheduler userScheduler;
painlessMesh mesh;

void setup() {
  Serial.begin(115200);
  
  // Set debug message types before init() to see startup messages
  mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);

  // NEW: Single call to initialize as bridge with auto channel detection
  // This will:
  // 1. Connect to router and detect its channel
  // 2. Initialize mesh on the detected channel
  // 3. Set this node as root
  // 4. Maintain router connection
  // 5. Start broadcasting bridge status (Type 610) every 30 seconds
  bool bridgeSuccess = mesh.initAsBridge(MESH_PREFIX, MESH_PASSWORD,

bridgeAwareSensorNode

//************************************************************
// Bridge-Aware Sensor Node Example
//
// This example demonstrates how to use the bridge status
// callback feature to implement intelligent message queueing.
//
// Features:
// - Monitors bridge Internet connectivity status
// - Queues critical messages when Internet is unavailable
// - Automatically sends queued messages when Internet returns
// - Implements failover logic for multiple bridges
// - Automatic channel detection for bridge discovery
//
// Use case: Fish farm monitoring system that needs to ensure
// critical alarms are delivered even during Internet outages
//
// Important: Uses channel=0 for auto-detection to discover
// bridges operating on the router's WiFi channel.
//************************************************************

#include "painlessTaskOptions.h"  // Must be first to configure TaskScheduler
#include <TaskScheduler.h>  // Required for LDF to find TaskScheduler dependency
#include "alteriom_sensor_package.hpp"
#include "painlessMesh.h"

#define MESH_PREFIX "AlteriomMesh"
#define MESH_PASSWORD "somethingSneaky"
#define MESH_PORT 5555

Scheduler userScheduler;
painlessMesh mesh;

// Alteriom package handlers
using namespace alteriom;

// Message queue for offline mode
struct QueuedMessage {
  uint32_t timestamp;
  bool isCritical;
  SensorPackage data;
};

std::vector<QueuedMessage> messageQueue;
const size_t MAX_QUEUE_SIZE = 100;  // Prevent memory overflow

// Bridge connectivity tracking
bool internetAvailable = false;
uint32_t primaryBridgeId = 0;

// Simulation variables

bridge_failover

//************************************************************
// Bridge Failover with RSSI-Based Election Example
//
// This example demonstrates automatic bridge failover in painlessMesh.
// When the primary bridge loses Internet connectivity, nodes automatically
// hold an election to select a new bridge based on router signal strength.
//
// Hardware Required:
// - ESP32 or ESP8266
// - WiFi router with Internet connection
//
// Setup Options:
//
// OPTION A - Auto-Election Mode (Recommended):
// 1. Configure your mesh credentials (MESH_PREFIX, MESH_PASSWORD)
// 2. Configure your router credentials (ROUTER_SSID, ROUTER_PASSWORD)
// 3. Keep INITIAL_BRIDGE = false on ALL nodes
// 4. Flash multiple nodes with this sketch
// 5. After startup (~60 seconds), nodes will automatically elect a bridge
//    based on best router signal strength (RSSI)
//
// OPTION B - Pre-Designated Bridge Mode:
// 1. Configure your mesh credentials (MESH_PREFIX, MESH_PASSWORD)
// 2. Configure your router credentials (ROUTER_SSID, ROUTER_PASSWORD)
// 3. Set INITIAL_BRIDGE = true on ONE node (your designated bridge)
// 4. Keep INITIAL_BRIDGE = false on all other nodes
// 5. Flash the nodes - designated bridge starts immediately
// 6. If designated bridge fails, others will hold election
//
// Features Demonstrated:
// - Automatic bridge election when no bridge exists
// - Automatic bridge failure detection via heartbeats
// - RSSI-based election protocol
// - Deterministic winner selection with tiebreakers
// - Seamless promotion to bridge role
// - Bridge takeover announcements
// - Automatic mesh channel detection for bridge discovery
//
// Important Note:
// Regular nodes MUST use channel auto-detection (channel=0) to discover
// bridges that are operating on the router's WiFi channel. The example
// automatically uses channel=0 for this purpose.
//
//************************************************************

#include "painlessMesh.h"

// Mesh configuration
#define MESH_PREFIX     "FishFarmMesh"
#define MESH_PASSWORD   "securepass"

diagnosticsExample

/**
 * painlessMesh Diagnostics API Example
 * 
 * This example demonstrates the enhanced diagnostics API for bridge operations.
 * It shows how to:
 * - Enable diagnostics tracking
 * - Get bridge status information
 * - Monitor election history
 * - Test bridge connectivity
 * - Generate diagnostic reports
 * - Export topology for visualization
 * 
 * Hardware: ESP32 or ESP8266
 * 
 * Usage:
 * 1. Upload to multiple devices
 * 2. Configure one device as a bridge (see bridgeExample)
 * 3. Regular nodes will use this diagnostics API to monitor mesh health
 * 4. Open Serial Monitor to see diagnostic information
 */

#include "painlessMesh.h"

#define   MESH_PREFIX     "DiagnosticsMesh"
#define   MESH_PASSWORD   "diagnostic123"
#define   MESH_PORT       5555

Scheduler userScheduler;
painlessMesh mesh;

// Task to periodically print diagnostics
Task taskPrintDiagnostics(30000, TASK_FOREVER, []() {
  Serial.println("\n" + mesh.getDiagnosticReport());
});

// Task to test bridge connectivity
Task taskTestBridge(60000, TASK_FOREVER, []() {
  Serial.println("\n=== Testing Bridge Connectivity ===");
  auto result = mesh.testBridgeConnectivity();
  
  if (result.success) {
    Serial.printf("✓ Bridge test PASSED: %s\n", result.message.c_str());
    Serial.printf("  Latency: %u ms\n", result.latencyMs);
    Serial.printf("  Internet available: %s\n", result.internetReachable ? "Yes" : "No");
  } else {
    Serial.printf("✗ Bridge test FAILED: %s\n", result.message.c_str());
  }
});

// Task to monitor bridge status

echoNode

//************************************************************
// this is a simple example that uses the painlessMesh library and echos any
// messages it receives
//
//************************************************************
#include "painlessMesh.h"

#define   MESH_PREFIX     "whateverYouLike"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555

// Prototypes
void receivedCallback( uint32_t from, String &msg );

painlessMesh  mesh;

void setup() {
  Serial.begin(115200);
    
  mesh.setDebugMsgTypes( ERROR | STARTUP | CONNECTION );  // set before init() so that you can see startup messages

  mesh.init( MESH_PREFIX, MESH_PASSWORD, MESH_PORT );
  mesh.onReceive(&receivedCallback);
}

void loop() {
  mesh.update();
}

void receivedCallback( uint32_t from, String &msg ) {
  Serial.printf("echoNode: Received from %u msg=%s\n", from, msg.c_str());
  mesh.sendSingle(from, msg);
}

logClient

//************************************************************
// this is a simple example that uses the painlessMesh library to 
// setup a node that logs to a central logging node
// The logServer example shows how to configure the central logging nodes
//************************************************************
#include "painlessMesh.h"

#define   MESH_PREFIX     "whateverYouLike"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555

Scheduler     userScheduler; // to control your personal task
painlessMesh  mesh;

// Prototype
void receivedCallback( uint32_t from, String &msg );

size_t logServerId = 0;

// Send message to the logServer every 10 seconds 
Task myLoggingTask(10000, TASK_FOREVER, []() {
#if ARDUINOJSON_VERSION_MAJOR==7
        JsonDocument jsonBuffer;
        JsonObject msg = jsonBuffer.to<JsonObject>();
#elif ARDUINOJSON_VERSION_MAJOR==6
        DynamicJsonDocument jsonBuffer(1024);
        JsonObject msg = jsonBuffer.to<JsonObject>();
#else
        DynamicJsonBuffer jsonBuffer;
        JsonObject& msg = jsonBuffer.createObject();
#endif
    msg["topic"] = "sensor";
    msg["value"] = random(0, 180);

    String str;
#if ARDUINOJSON_VERSION_MAJOR>=6
    serializeJson(msg, str);
#else
    msg.printTo(str);
#endif
    if (logServerId == 0) // If we don't know the logServer yet
        mesh.sendBroadcast(str);
    else
        mesh.sendSingle(logServerId, str);

    // log to serial
#if ARDUINOJSON_VERSION_MAJOR>=6
    serializeJson(msg, Serial);
#else
    msg.printTo(Serial);

logServer

//************************************************************
// this is a simple example that uses the painlessMesh library to 
// setup a single node (this node) as a logging node
// The logClient example shows how to configure the other nodes
// to log to this server
//************************************************************
#include "painlessMesh.h"

#define   MESH_PREFIX     "whateverYouLike"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555

Scheduler     userScheduler; // to control your personal task
painlessMesh  mesh;
// Prototype
void receivedCallback( uint32_t from, String &msg );


// Send my ID every 10 seconds to inform others
Task logServerTask(10000, TASK_FOREVER, []() {
#if ARDUINOJSON_VERSION_MAJOR==7
        JsonDocument jsonBuffer;
        JsonObject msg = jsonBuffer.to<JsonObject>();
#elif ARDUINOJSON_VERSION_MAJOR==6
        DynamicJsonDocument jsonBuffer(1024);
        JsonObject msg = jsonBuffer.to<JsonObject>();
#else
        DynamicJsonBuffer jsonBuffer;
        JsonObject& msg = jsonBuffer.createObject();
#endif
    msg["topic"] = "logServer";
    msg["nodeId"] = mesh.getNodeId();

    String str;
#if ARDUINOJSON_VERSION_MAJOR>=6
    serializeJson(msg, str);
#else
    msg.printTo(str);
#endif
    mesh.sendBroadcast(str);

    // log to serial
#if ARDUINOJSON_VERSION_MAJOR>=6
    serializeJson(msg, Serial);
#else
    msg.printTo(Serial);
#endif
    Serial.printf("\n");
});

meshCommandNode

#include "painlessTaskOptions.h"  // Must be first to configure TaskScheduler
#include <TaskScheduler.h>  // Required for LDF to find TaskScheduler dependency
#include "painlessMesh.h"
#include "alteriom_sensor_package.hpp"

// Define LED_BUILTIN for ESP32 boards that don't have it predefined
#ifndef LED_BUILTIN
#define LED_BUILTIN 2
#endif

#define MESH_PREFIX     "AlteriomMesh"
#define MESH_PASSWORD   "somethingSneaky"
#define MESH_PORT       5555

using namespace alteriom;

Scheduler userScheduler;
painlessMesh mesh;

// Command handlers
void handleCommand(const CommandPackage& cmd);
void sendStatusResponse(uint32_t commandId, String message, uint8_t status = 0);
void sendConfiguration();
void sendStatus();

// Command definitions (matching mqtt_command_bridge.hpp)
enum Commands {
  RESET = 1,
  SLEEP = 2,
  WAKE = 3,
  LED_CONTROL = 10,
  RELAY_SWITCH = 11,
  PWM_SET = 12,
  GET_CONFIG = 100,
  SET_CONFIG = 101,
  GET_STATUS = 200,
  GET_METRICS = 201
};

void setup() {
  Serial.begin(115200);
  
  pinMode(LED_BUILTIN, OUTPUT);
  
  mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
  mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
  
  mesh.onReceive([](uint32_t from, String& msg) {
    Serial.printf("Received from %u\n", from);
    

mqttBridge

//************************************************************
// this is a simple example that uses the painlessMesh library to
// connect to a another network and relay messages from a MQTT broker to the nodes of the mesh network.
// To send a message to a mesh node, you can publish it to "painlessMesh/to/12345678" where 12345678 equals the nodeId.
// To broadcast a message to all nodes in the mesh you can publish it to "painlessMesh/to/broadcast".
// When you publish "getNodes" to "painlessMesh/to/gateway" you receive the mesh topology as JSON
// Every message from the mesh which is send to the gateway node will be published to "painlessMesh/from/12345678" where 12345678 
// is the nodeId from which the packet was send.
//************************************************************

#include <Arduino.h>
#include <painlessMesh.h>
#include <PubSubClient.h>
#include <WiFiClient.h>

#define   MESH_PREFIX     "whateverYouLike"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555

#define   STATION_SSID     "YourAP_SSID"
#define   STATION_PASSWORD "YourAP_PWD"

#define HOSTNAME "MQTT_Bridge"

// Prototypes
void receivedCallback( const uint32_t &from, const String &msg );
void mqttCallback(char* topic, byte* payload, unsigned int length);

IPAddress getlocalIP();

IPAddress myIP(0,0,0,0);
IPAddress mqttBroker(192, 168, 1, 1);

painlessMesh  mesh;
WiFiClient wifiClient;
PubSubClient mqttClient(mqttBroker, 1883, mqttCallback, wifiClient);

void setup() {
  Serial.begin(115200);

  mesh.setDebugMsgTypes( ERROR | STARTUP | CONNECTION );  // set before init() so that you can see startup messages

  // Channel set to 6. Make sure to use the same channel for your mesh and for you other
  // network (STATION_SSID)
  mesh.init( MESH_PREFIX, MESH_PASSWORD, MESH_PORT, WIFI_AP_STA, 6 );
  mesh.onReceive(&receivedCallback);

  mesh.stationManual(STATION_SSID, STATION_PASSWORD);
  mesh.setHostname(HOSTNAME);

mqttCommandBridge

#include <Arduino.h>
#include "painlessTaskOptions.h"  // Must be first to configure TaskScheduler
#include <TaskScheduler.h>  // Required for LDF to find TaskScheduler dependency
#include "painlessMesh.h"
#include <PubSubClient.h>
#include "mqtt_command_bridge.hpp"
#include "mesh_topology_reporter.hpp"
#include "mesh_event_publisher.hpp"

// Mesh configuration
#define MESH_PREFIX     "AlteriomMesh"
#define MESH_PASSWORD   "somethingSneaky"
#define MESH_PORT       5555

// WiFi configuration
#define STATION_SSID     "YourWiFi"
#define STATION_PASSWORD "YourPassword"

// MQTT configuration
#define MQTT_BROKER_IP   "192.168.1.100"
#define MQTT_BROKER_PORT 1883
#define MQTT_CLIENT_ID   "painlessMesh-commandBridge"

Scheduler userScheduler;
painlessMesh mesh;
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
MqttCommandBridge* commandBridge;
MeshTopologyReporter* topologyReporter;
MeshEventPublisher* eventPublisher;

// Task for MQTT reconnection
Task taskMqttReconnect(TASK_SECOND * 5, TASK_FOREVER, []() {
  if (!mqttClient.connected()) {
    Serial.println("MQTT disconnected, reconnecting...");
    if (mqttClient.connect(MQTT_CLIENT_ID)) {
      Serial.println("MQTT reconnected!");
      commandBridge->begin(); // Re-subscribe to topics
    } else {
      Serial.printf("MQTT reconnect failed, rc=%d\n", mqttClient.state());
    }
  }
});

// Task for periodic gateway status
Task taskGatewayStatus(TASK_MINUTE, TASK_FOREVER, []() {
  if (mqttClient.connected()) {
    JsonDocument status;  // ArduinoJson v7: automatic sizing
    status["gateway_id"] = mesh.getNodeId();
    status["status"] = "online";

mqttStatusBridge

//************************************************************
// Phase 2: MQTT Status Bridge Example
//
// This example demonstrates the MQTT Status Bridge feature,
// which publishes comprehensive mesh status to MQTT topics
// for professional monitoring with tools like:
// - Grafana
// - InfluxDB
// - Prometheus
// - Home Assistant
// - Node-RED
//
// MQTT Topics Published:
// - mesh/status/nodes      - List of all nodes in mesh
// - mesh/status/topology   - Complete mesh topology JSON
// - mesh/status/metrics    - Performance metrics
// - mesh/status/alerts     - Active alerts
// - mesh/status/node/{id}  - Per-node detailed status (optional)
//
// Requirements:
// - ESP32 or ESP8266
// - WiFi connection to external network (for MQTT broker)
// - MQTT broker (e.g., Mosquitto, HiveMQ, AWS IoT)
//************************************************************

#include <Arduino.h>
#include "painlessTaskOptions.h"  // Must be first to configure TaskScheduler
#include <TaskScheduler.h>  // Required for LDF to find TaskScheduler dependency
#include <painlessMesh.h>
#include <PubSubClient.h>
#include <WiFiClient.h>
#include "mqtt_status_bridge.hpp"

// Mesh configuration
#define   MESH_PREFIX     "AlteriomMesh"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555

// External WiFi configuration (for MQTT connection)
#define   STATION_SSID     "YourAP_SSID"
#define   STATION_PASSWORD "YourAP_PWD"

// MQTT broker configuration
#define   MQTT_BROKER_IP   "192.168.1.100"  // Change to your MQTT broker IP
#define   MQTT_BROKER_PORT 1883
#define   MQTT_CLIENT_ID   "painlessMesh_StatusBridge"

#define HOSTNAME "MQTT_Status_Bridge"

// Prototypes

mqttTopologyTest

/**
 * @file mqttTopologyTest.ino
 * @brief Hardware test sketch for painlessMesh topology reporting with MQTT
 * 
 * This sketch tests mesh topology reporting according to @alteriom/mqtt-schema v0.5.0
 * 
 * HARDWARE REQUIREMENTS:
 * - 3x ESP32 boards (or ESP8266, but ESP32 recommended)
 * - MQTT broker accessible on network (e.g., Mosquitto)
 * - USB cables for programming and Serial monitoring
 * 
 * TEST CONFIGURATION:
 * - Node 1: Gateway (this sketch with IS_GATEWAY = true)
 * - Node 2: Sensor node (this sketch with IS_GATEWAY = false, role = "sensor")
 * - Node 3: Repeater node (this sketch with IS_GATEWAY = false, role = "repeater")
 * 
 * MQTT TOPICS TESTED:
 * - alteriom/mesh/MESH-001/topology (full topology every 60s, incremental every 5s)
 * - alteriom/mesh/MESH-001/events (node join/leave events)
 * - alteriom/mesh/MESH-001/topology/response (GET_TOPOLOGY command response)
 * - alteriom/mesh/MESH-001/command (receive GET_TOPOLOGY commands)
 * 
 * SCHEMA COMPLIANCE:
 * - Device ID format: ALT-XXXXXXXXXXXX (uppercase hex)
 * - Quality metrics: 0-100 range
 * - RSSI values: negative dBm
 * - Timestamps: ISO 8601 format
 * - Envelope fields: schema_version, device_id, device_type, timestamp, firmware_version
 * 
 * TEST PROCEDURE:
 * 1. Configure WiFi credentials (WIFI_SSID, WIFI_PASSWORD)
 * 2. Configure MQTT broker (MQTT_BROKER, MQTT_PORT)
 * 3. Flash Node 1 with IS_GATEWAY = true
 * 4. Flash Node 2 with IS_GATEWAY = false, NODE_ROLE = "sensor"
 * 5. Flash Node 3 with IS_GATEWAY = false, NODE_ROLE = "repeater"
 * 6. Open Serial monitors for all 3 nodes
 * 7. Wait for mesh formation (watch for "Node joined" messages)
 * 8. Verify full topology published every 60s
 * 9. Verify incremental updates on node join/leave
 * 10. Send GET_TOPOLOGY command and verify response
 * 
 * EXPECTED BEHAVIOR:
 * - All nodes join mesh within 30 seconds
 * - Gateway publishes full topology every 60 seconds
 * - Gateway publishes incremental updates within 5 seconds of node join/leave
 * - All messages conform to @alteriom/mqtt-schema v0.5.0
 * - Connection quality metrics are calculated correctly
 * 
 * @author Alteriom Development Team
 * @date October 14, 2025

multi_bridge

//************************************************************
// Multi-Bridge Example: Secondary Bridge Node
//
// This example demonstrates a secondary bridge (priority 5) in a
// multi-bridge deployment. This provides hot standby redundancy
// and can handle load if the primary bridge is busy.
//
// Features demonstrated:
// - Secondary bridge with medium priority
// - Hot standby mode (always ready)
// - Automatic failover if primary fails
// - Load balancing support
//************************************************************

#include "painlessMesh.h"

#define MESH_PREFIX     "MultiBridgeMesh"
#define MESH_PASSWORD   "meshpassword"
#define MESH_PORT       5555

// Secondary router connection (backup Internet or different ISP)
#define ROUTER_SSID     "SecondaryRouter"
#define ROUTER_PASSWORD "routerpass2"

Scheduler userScheduler;
painlessMesh mesh;

// Task to display bridge coordination status
Task taskBridgeStatus(10000, TASK_FOREVER, [](){
  Serial.println("\n=== Secondary Bridge Status ===");
  Serial.printf("Node ID: %u\n", mesh.getNodeId());
  Serial.printf("Connected Nodes: %d\n", mesh.getNodeList().size());
  
  // Show all active bridges in the mesh
  auto activeBridges = mesh.getActiveBridges();
  Serial.printf("Active Bridges: %d\n", activeBridges.size());
  for (auto bridgeId : activeBridges) {
    Serial.printf("  - Bridge: %u%s\n", bridgeId, 
                  (bridgeId == mesh.getNodeId()) ? " (ME)" : "");
  }
  
  // Show recommended bridge for next message
  uint32_t recommended = mesh.getRecommendedBridge();
  Serial.printf("Recommended Bridge: %u\n", recommended);
  
  if (recommended == mesh.getNodeId()) {
    Serial.println("⚠️  I AM THE ACTIVE BRIDGE (primary likely failed!)");
  } else {
    Serial.println("✓ Standby mode - primary bridge is active");
  }

namedMesh

//************************************************************
// this is a simple example that uses the painlessMesh library
//
// This example shows how to build a mesh with named nodes using the plugin
// system
//
//
//************************************************************
#include <cstdint>
#include <map>
#include "Arduino.h"
#include "painlessMesh.h"
#include "painlessmesh/plugin.hpp"

#define MESH_PREFIX "whateverYouLike"
#define MESH_PASSWORD "somethingSneaky"
#define MESH_PORT 5555

painlessMesh mesh;

// NOTE: various ideas for improvement
// - Send new names regularly and only send all names sometimes
// - Keep track of the names the neighbour already knows (when we receive them)
//   and only send unknown names/nodes
// - Use some kind of bidirectoral map, so both get_name_from_id and
//   get_id_from_name are fast

// Send the names you know to your neighbours
class NamePackage : public painlessmesh::plugin::NeighbourPackage {
 public:
  std::map<TSTRING, uint32_t> names;

  // Set an id for the package. Id can be any unique int not already in use. The
  // mesh uses the numbers 1..12, so using a number larger than that
  NamePackage() : painlessmesh::plugin::NeighbourPackage(21) {}

  NamePackage(JsonObject jsonObj)
      : painlessmesh::plugin::NeighbourPackage(jsonObj) {
    for (JsonPair kv : jsonObj) {
      names.insert(std::pair<TSTRING, uint32_t>(kv.key().c_str(), kv.value()));
    }
  }

  JsonObject addTo(JsonObject&& jsonObj) const {
    jsonObj = painlessmesh::plugin::NeighbourPackage::addTo(std::move(jsonObj));
    for (auto&& kv : names) {
      jsonObj[kv.first] = kv.second;
    }
    return jsonObj;
  }

ntpTimeSyncBridge

/**
 * @file ntpTimeSyncBridge.ino
 * @brief Example: Bridge node with NTP time synchronization
 * 
 * This example demonstrates a bridge node that:
 * 1. Connects to WiFi router (bridge mode)
 * 2. Queries NTP server for accurate time
 * 3. Broadcasts NTP time to mesh nodes via NTPTimeSyncPackage
 * 
 * Regular mesh nodes can receive this broadcast and sync their local time,
 * eliminating the need for each node to query NTP individually.
 */

#include "painlessMesh.h"
#include "alteriom_sensor_package.hpp"

// Mesh configuration
#define MESH_PREFIX     "AlteriomMesh"
#define MESH_PASSWORD   "your_mesh_password"
#define MESH_PORT       5555

// WiFi router configuration (for bridge)
#define ROUTER_SSID     "your_router_ssid"
#define ROUTER_PASSWORD "your_router_password"

// NTP configuration
#define NTP_SERVER      "pool.ntp.org"
#define NTP_OFFSET      0      // Timezone offset in seconds (0 = UTC)
#define NTP_INTERVAL    60000  // Update interval in milliseconds

Scheduler userScheduler;
painlessMesh mesh;

using namespace alteriom;

// Task to broadcast NTP time periodically
Task taskBroadcastNTP(NTP_INTERVAL, TASK_FOREVER, [](){
  // Create NTP time sync package
  auto pkg = NTPTimeSyncPackage();
  pkg.from = mesh.getNodeId();
  
  // Get NTP time from mesh (if available)
  pkg.ntpTime = mesh.getNodeTime() / 1000000;  // Convert to seconds
  pkg.accuracy = 50;  // Estimate 50ms uncertainty
  pkg.source = NTP_SERVER;
  pkg.timestamp = millis();
  
  // Serialize and broadcast to mesh
  JsonDocument doc;
  JsonObject obj = doc.to<JsonObject>();

ntpTimeSyncNode

/**
 * @file ntpTimeSyncNode.ino
 * @brief Example: Regular mesh node receiving NTP time from bridge
 * 
 * This example demonstrates a regular mesh node that:
 * 1. Connects to the mesh network
 * 2. Listens for NTP time broadcasts from bridge nodes
 * 3. Updates local time when NTP sync is received
 * 4. Optionally syncs RTC module if available
 * 
 * No Internet connection needed - time is received from bridge!
 */

#include "painlessMesh.h"
#include "alteriom_sensor_package.hpp"

// Mesh configuration
#define MESH_PREFIX     "AlteriomMesh"
#define MESH_PASSWORD   "your_mesh_password"
#define MESH_PORT       5555

Scheduler userScheduler;
painlessMesh mesh;

using namespace alteriom;

// Track last time sync
uint32_t lastNTPSync = 0;
uint32_t ntpSyncCount = 0;

// Received callback - handle incoming messages
void receivedCallback(uint32_t from, String& msg) {
  // Parse JSON message
  DynamicJsonDocument doc(1024);
  DeserializationError error = deserializeJson(doc, msg);
  
  if (error) {
    Serial.printf("JSON parse error: %s\n", error.c_str());
    return;
  }
  
  JsonObject obj = doc.as<JsonObject>();
  uint16_t msgType = obj["type"];
  
  // Check if this is an NTP time sync message
  if (msgType == 614) {
    // Deserialize NTP time sync package
    auto pkg = NTPTimeSyncPackage(obj);
    
    Serial.printf("\n=== NTP Time Sync Received ===\n");

otaReceiver

//************************************************************
// this is a simple example that uses the painlessMesh library
//
// 1. sends a silly message to every node on the mesh at a random time between 1
// and 5 seconds
// 2. prints anything it receives to Serial.print
// 3. has OTA support and can be updated remotely
//
//************************************************************
#include "painlessMesh.h"

#define MESH_PREFIX "whateverYouLike"
#define MESH_PASSWORD "somethingSneaky"
#define MESH_PORT 5555

Scheduler userScheduler;  // to control your personal task
painlessMesh mesh;

// User stub
void sendMessage();  // Prototype so PlatformIO doesn't complain

Task taskSendMessage(TASK_SECOND * 1, TASK_FOREVER, &sendMessage);

void sendMessage() {
  String msg = "Hello from node ";
  msg += mesh.getNodeId();
  mesh.sendBroadcast(msg);
  taskSendMessage.setInterval(random(TASK_SECOND * 1, TASK_SECOND * 5));
}

// Needed for painless library
void receivedCallback(uint32_t from, String &msg) {
  Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str());
}

void newConnectionCallback(uint32_t nodeId) {
  Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
}

void changedConnectionCallback() { Serial.printf("Changed connections\n"); }

void nodeTimeAdjustedCallback(int32_t offset) {
  Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(), offset);
}

void setup() {
  Serial.begin(115200);

  // mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC |
  // COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on

otaSender

//************************************************************
// this is an example that uses the painlessmesh library to
// upload firmware to another node on the network. 
// This will upload to an ESP device running the otaReceiver.ino
//
// The naming convetions should be as follows for bin files
// firmware_<hardware>_<role>.bin
// To create your own binary files, export them and rename
// them to follow this format, where hardware will be
// "ESP8266" or "ESP32" (capitalized.)
// If sending to the otacreceiver sketch, role should be
// "otareceiver" (lowercase)
//
// This sketch assumes a Nodemcu-32s with an SD card
// connected as shown in the jpg included in the sketch folder
// This code may have to be reworked/hardware adjusted for
// other boards or ESP8266. The core code works well though
//
// MAKE SURE YOUR UPLOADED OTA FIRMWARE INCLUDES OTA SUPPORT 
// OR YOU WILL LOSE THE ABILITY TO UPLOAD MORE FIRMWARE.
// THE INCLUDED .bin DOES NOT HAVE OTA SUPPORT SO THIS MUST BE
// REFLASHED
//************************************************************

#ifdef ESP32
#else
#define CS_PIN  D8
#endif

#include "painlessMesh.h"

#include <FS.h>
#include "SD.h"
#include "SPI.h"

#define MESH_PREFIX "whateverYouLike"
#define MESH_PASSWORD "somethingSneaky"
#define MESH_PORT 5555

#define OTA_PART_SIZE 1024 //How many bytes to send per OTA data packet

painlessMesh mesh;

void setup() {
  Serial.begin(115200);
  delay(1000);
  mesh.setDebugMsgTypes(
      ERROR | STARTUP | CONNECTION |
      DEBUG);  // set before init() so that you can see startup messages

priority

/**
 * Basic Priority Messaging Example for painlessMesh
 * 
 * Demonstrates how to send messages with different priority levels.
 * 
 * Priority levels:
 * - PRIORITY_CRITICAL (0): Life/safety critical messages (alarms, emergencies)
 * - PRIORITY_HIGH (1): Important commands and status requests
 * - PRIORITY_NORMAL (2): Regular sensor data and routine updates (default)
 * - PRIORITY_LOW (3): Non-essential telemetry and debug logs
 * 
 * Hardware: ESP32 or ESP8266
 */

#include "painlessMesh.h"

#define MESH_PREFIX     "PriorityMeshDemo"
#define MESH_PASSWORD   "somethingSneaky"
#define MESH_PORT       5555

Scheduler userScheduler;
painlessMesh mesh;

// Task to send regular sensor data (NORMAL priority)
Task taskSensorData(5000, TASK_FOREVER, []() {
    String sensorData = "{\"type\":\"sensor\",\"temp\":23.5,\"humidity\":45}";
    
    // Send with NORMAL priority (default)
    mesh.sendBroadcast(sensorData, 2);  // Priority level 2 = NORMAL
    
    Serial.println("Sent sensor data (NORMAL priority)");
});

// Task to send status updates (HIGH priority)
Task taskStatusUpdate(10000, TASK_FOREVER, []() {
    String status = "{\"type\":\"status\",\"online\":true,\"uptime\":" + String(millis()) + "}";
    
    // Send with HIGH priority
    mesh.sendBroadcast(status, 1);  // Priority level 1 = HIGH
    
    Serial.println("Sent status update (HIGH priority)");
});

// Task to send low-priority debug logs
Task taskDebugLog(15000, TASK_FOREVER, []() {
    String debug = "{\"type\":\"debug\",\"freeHeap\":" + String(ESP.getFreeHeap()) + "}";
    
    // Send with LOW priority
    mesh.sendBroadcast(debug, 3);  // Priority level 3 = LOW
    

queued_alarms

//************************************************************
// Queued Alarms Example - Message Queueing for Offline Mode
//
// Demonstrates priority-based message queueing for critical alarms
// when Internet connection is unavailable. Perfect for IoT systems
// that cannot afford to lose critical data.
//
// Use Case: Fish farm dissolved oxygen monitoring
// - CRITICAL alarms (low O2) must never be lost
// - Queue messages during Internet outages
// - Automatic delivery when connection restored
//
// Hardware: ESP32 or ESP8266
//************************************************************

#include "painlessMesh.h"

// Mesh configuration
#define   MESH_PREFIX     "FishFarmMesh"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555

// Router credentials for bridge node
#define   ROUTER_SSID     "YourWiFiSSID"
#define   ROUTER_PASSWORD "YourWiFiPassword"

// Sensor thresholds (mg/L for dissolved oxygen)
#define   CRITICAL_O2_THRESHOLD  3.0
#define   WARNING_O2_THRESHOLD   5.0

// Queue configuration
#define   MAX_QUEUE_SIZE  500
#define   QUEUE_PRUNE_AGE (24 * 60 * 60 * 1000)  // 24 hours in ms

Scheduler userScheduler;
painlessMesh mesh;

bool offlineMode = false;
uint32_t lastO2Check = 0;
uint32_t lastQueuePrune = 0;

// Simulated sensor reading (replace with actual sensor code)
float readDissolvedOxygenSensor() {
  // In real application, read from actual sensor
  // For demo, simulate varying O2 levels
  static float o2Level = 7.0;
  o2Level += random(-20, 20) / 10.0;  // +/- 2.0 mg/L variation
  o2Level = constrain(o2Level, 2.0, 10.0);
  return o2Level;
}

routing_demo

/**
 * Multi-Hop Routing Demo
 * 
 * This example demonstrates the new multi-hop routing capabilities of painlessMesh.
 * It shows how to:
 * - Calculate hop count to any node in the mesh
 * - Get the complete routing table
 * - Find the path from this node to any other node
 * 
 * The functions work automatically with any mesh topology - linear chains,
 * star configurations, or complex multi-hop meshes.
 */

#include "painlessMesh.h"

#define MESH_PREFIX     "routingDemo"
#define MESH_PASSWORD   "meshPassword"
#define MESH_PORT       5555

Scheduler userScheduler;
painlessMesh mesh;

// Task to periodically display routing information
Task taskShowRouting(10000, TASK_FOREVER, []() {
  Serial.println("\n=== Routing Information ===");
  
  // Get list of all nodes in the mesh
  auto nodeList = mesh.getNodeList(false);  // false = don't include self
  Serial.printf("Mesh contains %d nodes (plus this node)\n", nodeList.size());
  
  // Display hop count to each node
  Serial.println("\nHop Counts:");
  for (auto nodeId : nodeList) {
    int hops = mesh.getHopCount(nodeId);
    Serial.printf("  Node %u: %d hop%s\n", nodeId, hops, hops == 1 ? "" : "s");
  }
  
  // Display complete routing table
  Serial.println("\nRouting Table (Destination -> Next Hop):");
  auto routingTable = mesh.getRoutingTable();
  for (auto& entry : routingTable) {
    Serial.printf("  To %u -> via %u", entry.first, entry.second);
    if (entry.first == entry.second) {
      Serial.print(" (direct connection)");
    }
    Serial.println();
  }
  
  // Example: Show path to first node in list
  if (!nodeList.empty()) {

rtcIntegration

//************************************************************
// RTC Integration Example
//
// This example demonstrates how to use RTC (Real-Time Clock)
// modules with painlessMesh for accurate offline timekeeping.
//
// When Internet/bridge is unavailable, nodes can still maintain
// accurate timestamps using a local RTC module.
//
// Supported RTC modules:
// - DS3231, DS1307 (I2C)
// - PCF8523, PCF8563 (I2C)
// - ESP32 internal RTC
//
// This example uses DS3231 with the RTClib library.
// Install: https://github.com/adafruit/RTClib
//************************************************************

#include "painlessMesh.h"
#include <RTClib.h>  // Adafruit RTClib for DS3231

#define MESH_PREFIX     "AlteriomMesh"
#define MESH_PASSWORD   "somethingSneaky"
#define MESH_PORT       5555

Scheduler userScheduler;
painlessMesh mesh;

// DS3231 RTC instance
RTC_DS3231 rtc;

// RTC Interface implementation for DS3231
class DS3231Interface : public painlessmesh::rtc::RTCInterface {
private:
  RTC_DS3231* rtcDevice;
  
public:
  DS3231Interface(RTC_DS3231* device) : rtcDevice(device) {}
  
  bool begin() override {
    if (!rtcDevice->begin()) {
      Serial.println("Couldn't find RTC");
      return false;
    }
    
    // Check if RTC lost power and needs time set
    if (rtcDevice->lostPower()) {
      Serial.println("RTC lost power, time needs to be set!");
      // Note: Time will be set via NTP when Internet available
    }

startHere

//************************************************************
// this is a simple example that uses the easyMesh library
//
// 1. blinks led once for every node on the mesh
// 2. blink cycle repeats every BLINK_PERIOD
// 3. sends a silly message to every node on the mesh at a random time between 1 and 5 seconds
// 4. prints anything it receives to Serial.print
//
//
//************************************************************
#include <painlessMesh.h>

// some gpio pin that is connected to an LED...
// on my rig, this is 2, change to the right number of your LED.
#ifndef LED
  #ifdef LED_BUILTIN
    #define LED LED_BUILTIN
  #else
    #define LED 2
  #endif
#endif

#define   BLINK_PERIOD    3000 // milliseconds until cycle repeat
#define   BLINK_DURATION  100  // milliseconds LED is on for

#define   MESH_SSID       "whateverYouLike"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555

// Prototypes
void sendMessage(); 
void receivedCallback(uint32_t from, String & msg);
void newConnectionCallback(uint32_t nodeId);
void changedConnectionCallback(); 
void nodeTimeAdjustedCallback(int32_t offset); 
void delayReceivedCallback(uint32_t from, int32_t delay);

Scheduler     userScheduler; // to control your personal task
painlessMesh  mesh;

bool calc_delay = false;
SimpleList<uint32_t> nodes;

void sendMessage() ; // Prototype
Task taskSendMessage( TASK_SECOND * 1, TASK_FOREVER, &sendMessage ); // start with a one second interval

// Task to blink the number of nodes
Task blinkNoNodes;
bool onFlag = false;

webServer

//************************************************************
// this is a simple example that uses the painlessMesh library to
// connect to a another network and broadcast message from a webpage to the edges of the mesh network.
// This sketch can be extended further using all the abilities of the AsyncWebserver library (WS, events, ...)
// for more details
// https://gitlab.com/painlessMesh/painlessMesh/wikis/bridge-between-mesh-and-another-network
// for more details about my version
// https://gitlab.com/Assassynv__V/painlessMesh
// and for more details about the AsyncWebserver library
// https://github.com/me-no-dev/ESPAsyncWebServer
//************************************************************

#include "IPAddress.h"
#include "painlessMesh.h"

#ifdef ESP8266
#include "Hash.h"
#include <ESPAsyncTCP.h>
#else
#include <AsyncTCP.h>
#endif
#include <ESPAsyncWebServer.h>

#define   MESH_PREFIX     "whateverYouLike"
#define   MESH_PASSWORD   "somethingSneaky"
#define   MESH_PORT       5555

#define   STATION_SSID     "mySSID"
#define   STATION_PASSWORD "myPASSWORD"

#define HOSTNAME "HTTP_BRIDGE"

// Prototype
void receivedCallback( const uint32_t &from, const String &msg );
IPAddress getlocalIP();

painlessMesh  mesh;
AsyncWebServer server(80);
IPAddress myIP(0,0,0,0);
IPAddress myAPIP(0,0,0,0);

void setup() {
  Serial.begin(115200);

  mesh.setDebugMsgTypes( ERROR | STARTUP | CONNECTION );  // set before init() so that you can see startup messages

  // Channel set to 6. Make sure to use the same channel for your mesh and for you other
  // network (STATION_SSID)
  mesh.init( MESH_PREFIX, MESH_PASSWORD, MESH_PORT, WIFI_AP_STA, 6 );
  mesh.onReceive(&receivedCallback);

Clone this wiki locally