Repository navigation
Examples
github-actions[bot] edited this page Nov 25, 2025
·
41 revisions
This page provides practical examples of using painlessMesh.
//************************************************************
// 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();/**
* 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);/**
* 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;/**
* 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");//************************************************************
// 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);//************************************************************
// 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();
//************************************************************
// 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 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,//************************************************************
// 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 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"/**
* 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//************************************************************
// 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);
}//************************************************************
// 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);//************************************************************
// 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");
});
#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);
//************************************************************
// 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);
#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";//************************************************************
// 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/**
* @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 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");
}//************************************************************
// 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;
}/**
* @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>();/**
* @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");//************************************************************
// 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//************************************************************
// 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
/**
* 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 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;
}/**
* 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()) {//************************************************************
// 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
}//************************************************************
// 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;
//************************************************************
// 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);