Repository navigation
Examples
github-actions[bot] edited this page Sep 7, 2026
·
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();//************************************************************
// 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 & Resilient Initialization
//
// This example demonstrates the bridge-centric architecture that
// automatically detects the router's WiFi channel and configures the
// mesh network accordingly.
//
// Features:
// - Resilient initialization: Works even if router is unavailable at boot
// - Automatically detects router channel when available
// - Creates mesh network immediately (default channel if needed)
// - No manual channel configuration required
// - Automatically sets itself as root node
// - Retries router connection in background if initially unavailable
// - 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
//
// POWER-UP ORDER INDEPENDENCE (v1.9.7+):
// The bridge now initializes successfully regardless of power-up order:
// - Bridge can boot before router is ready
// - Mesh nodes can connect immediately to bridge
// - Router connection is established automatically when available
// - No need to restart bridge when router becomes ready
//
// For more details, see BRIDGE_TO_INTERNET.md
//
// EXTERNAL DEVICE CONNECTIONS:
// ----------------------------
// External devices (phones, computers) can connect to the bridge's WiFi
// AP for debugging and testing purposes. The AP will broadcast the mesh
// SSID (e.g., "whateverYouLike") with the configured password.
//
// Connection details:
// - SSID: Your MESH_PREFIX value
// - Password: Your MESH_PASSWORD value
// - IP Range: 10.x.x.x (automatically assigned via DHCP)
// - Gateway: 10.x.x.1 (the bridge node itself)
//
// Note: ESP32 AP mode supports up to 10 concurrent connections by default,
// ESP8266 supports up to 4. If mesh nodes are already connected, fewer
// slots will be available for external devices.
//
// Troubleshooting external connections:
// 1. Ensure the bridge has successfully initialized (check serial output)
// 2. Wait a few seconds after boot for the AP to fully start
// 3. Check for channel conflicts with other WiFi networks
// 4. Try forgetting the network on your device and reconnecting
// 5. Monitor serial output with CONNECTION debug level enabled//************************************************************
// 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.
//
// EXTERNAL DEVICE CONNECTIONS FOR DEBUGGING:
// -------------------------------------------
// You can connect phones, computers, or test devices to the mesh network
// for debugging purposes. The bridge node broadcasts the mesh SSID as a
// WiFi Access Point.
//
// Connection details:
// - SSID: "FishFarmMesh" (or your MESH_PREFIX value)
// - Password: "securepass" (or your MESH_PASSWORD value)
// - IP Range: 10.x.x.x/24 (automatically assigned via DHCP)
// - Gateway: 10.x.x.1 (the bridge node itself)
//
// Important notes:
// 1. ESP32 supports up to 10 concurrent AP connections (ESP8266: 4)
// 2. Each mesh node connection uses one slot, leaving fewer for external devices
// 3. After boot, wait 5-10 seconds for the AP to fully initialize
// 4. If you can't connect, try these troubleshooting steps:
// - Check serial output for "AP configured" message
// - Verify the channel matches (bridge auto-detects router's channel)
// - Forget the network on your device and reconnect
// - Check for WiFi channel conflicts with other networks
// 5. External devices get DHCP but have no internet routing by default
// (they can only communicate with the mesh network itself)
//
// IMPORTANT - UNDERSTANDING INTERNET CONNECTIVITY:
// ================================================
// The mesh.hasInternetConnection() method checks if a GATEWAY (bridge) node
// has Internet access - it does NOT mean THIS node can make HTTP requests!
//
// Regular mesh nodes do NOT have direct IP routing to the Internet.
// They only communicate via the painlessMesh protocol (node-to-node).
//
// To send data to the Internet from a regular node:
// 1. Use mesh.sendToInternet() to route through a gateway
// - Call mesh.enableSendToInternet() AFTER mesh.init() on SENDING nodes only
// - Bridge nodes automatically handle routing via initAsBridge()
// - See examples/sendToInternet/sendToInternet.ino for complete usage
// 2. Use initAsSharedGateway() so all nodes have router access
// NOTE: initAsSharedGateway() requires ROUTER credentials:
// mesh.initAsSharedGateway(MESH_PREFIX, MESH_PASSWORD,
// ROUTER_SSID, ROUTER_PASSWORD, // Router creds required!
// &userScheduler, MESH_PORT);
// 3. Send mesh messages to bridge node which handles Internet comms//************************************************************
// Command/control with delivery confirmation (issue #379)
//
// A controller node periodically broadcasts a command to all nodes and
// tracks, per node, whether the command was delivered. Nodes execute
// the command in their onReceive callback; the acknowledgment is sent
// automatically by the library.
//
// The broadcast ack overload requires includeSelf to be passed
// explicitly:
// mesh.sendBroadcast(msg, false, callback, timeoutMs);
// The callback fires once per mesh node (excluding this node).
//************************************************************
#include <painlessMesh.h>
#define MESH_SSID "whateverYouLike"
#define MESH_PASSWORD "somethingSneaky"
#define MESH_PORT 5555
// Define CONTROLLER on exactly one node to make it send the commands
// #define CONTROLLER
Scheduler userScheduler;
painlessMesh mesh;
uint32_t commandsSent = 0;
uint32_t nodesConfirmed = 0;
uint32_t nodesMissed = 0;
uint32_t resultsReceived = 0;
uint32_t expectedResults = 0;
void sendCommand();
Task taskSendCommand(TASK_SECOND * 15, TASK_FOREVER, &sendCommand);
void sendCommand() {
#ifdef CONTROLLER
String cmd = String("{\"cmd\":\"setInterval\",\"seconds\":") +
String(random(5, 60)) + String("}");
++commandsSent;
nodesConfirmed = 0;
nodesMissed = 0;
resultsReceived = 0;
expectedResults = mesh.getNodeList(false).size();
bool queued = mesh.sendBroadcast(
cmd, false,
[](uint32_t nodeId, bool delivered, uint32_t latencyMs) {
if (delivered) {
++nodesConfirmed;
Serial.printf("Node %u confirmed command in %u ms\n", nodeId,//************************************************************
// 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");
});
//************************************************************
// 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>
// Requires the "PubSubClient" library by Nick O'Leary. Arduino IDE users:
// install it via Library Manager (Tools > Manage Libraries... > search
// "PubSubClient"); PlatformIO users already get it automatically from this
// example's platformio.ini.
#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);//************************************************************
// 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;
}//************************************************************
// 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
// SD card chip-select. The D0..D8 aliases only exist on the NodeMCU/Wemos
// ESP8266 variants; the "generic" ESP8266 variant does not define them, so
// D8 fails to compile there. SS is GPIO15 on every ESP8266 variant, which is
// the exact pin D8 maps to on NodeMCU, so this is portable and equivalent.
#define CS_PIN SS
#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);/**
* Advanced Priority Example with Message Queue Integration
*
* Demonstrates how to use priority messaging with the message queue
* for offline/Internet-unavailable scenarios.
*
* This example shows:
* - Priority-based message sending
* - Message queueing when Internet is unavailable
* - Automatic queue flushing when Internet becomes available
* - Priority ordering during queue flush
*
* Hardware: ESP32 or ESP8266
*/
#include "painlessMesh.h"
#define MESH_PREFIX "PriorityQueueMesh"
#define MESH_PASSWORD "somethingSneaky"
#define MESH_PORT 5555
Scheduler userScheduler;
painlessMesh mesh;
// The queue types live in the painlessmesh namespace
using painlessmesh::MessagePriority;
using painlessmesh::QueueState;
using painlessmesh::PRIORITY_CRITICAL;
using painlessmesh::PRIORITY_HIGH;
using painlessmesh::PRIORITY_NORMAL;
using painlessmesh::PRIORITY_LOW;
using painlessmesh::QUEUE_EMPTY;
using painlessmesh::QUEUE_NORMAL;
using painlessmesh::QUEUE_75_PERCENT;
using painlessmesh::QUEUE_FULL;
// Forward declarations: Arduino's auto-prototype generation does not see
// past the global lambdas below
void sendMessage(String message, uint8_t priority);
void flushQueuedMessages();
void queueStateChanged(QueueState state, uint32_t count);
bool internetAvailable = false;
uint32_t bridgeNodeId = 0;
// Task to check bridge status
Task taskCheckBridge(5000, TASK_FOREVER, []() {
bool hasInternet = mesh.hasInternetConnection();
if (hasInternet != internetAvailable) {//************************************************************
// Reliable sensor logging with delivery confirmation (issue #379)
//
// Demonstrates the per-message acknowledgment API:
// 1. every 10 seconds a sensor reading is sent to a gateway node
// 2. the reading stays in a small retry buffer until the gateway
// confirms delivery (delivered == true)
// 3. unconfirmed readings are retried up to MAX_ATTEMPTS times
//
// Run one node with GATEWAY defined and one or more sensor nodes. The
// gateway announces its node id; only sensor nodes generate readings.
//************************************************************
#include <painlessMesh.h>
#define MESH_SSID "whateverYouLike"
#define MESH_PASSWORD "somethingSneaky"
#define MESH_PORT 5555
// Define GATEWAY on exactly one node.
// #define GATEWAY
// How long to wait for a delivery confirmation
#define ACK_TIMEOUT_MS 3000
// How often a reading is retried before it is dropped
#define MAX_ATTEMPTS 3
Scheduler userScheduler;
painlessMesh mesh;
// The node we log readings to. In a real deployment you would discover
// this via a broadcast announcement or hardcode your gateway's node id.
uint32_t gatewayId = 0;
// A single buffered reading awaiting confirmation
struct PendingReading {
String payload;
uint8_t attempts = 0;
bool inFlight = false;
};
PendingReading pending;
void sendReading();
Task taskSendReading(TASK_SECOND * 10, TASK_FOREVER, &sendReading);
#ifdef GATEWAY
void announceGateway();
Task taskAnnounceGateway(TASK_SECOND * 5, TASK_FOREVER, &announceGateway);
#endif
void transmitPending() {
if (gatewayId == 0 || pending.payload.length() == 0 || pending.inFlight)//************************************************************
// Mock HTTP Server Integration Example
//
// This example demonstrates how to use the mock HTTP server
// for testing sendToInternet() functionality without requiring
// actual Internet connectivity.
//
// Setup:
// 1. Start the mock server on your development machine:
// cd test/mock-http-server
// python3 server.py
//
// 2. Update MOCK_SERVER_IP below with your computer's IP address
//
// 3. Upload this sketch to your ESP32/ESP8266
//
// 4. Watch the serial output and mock server logs
//
// The sketch will automatically run through various test scenarios
// and report pass/fail results for each test case.
//************************************************************
#include "painlessMesh.h"
// ============================================
// Configuration
// ============================================
#define MESH_PREFIX "TestMesh"
#define MESH_PASSWORD "testpass123"
#define MESH_PORT 5555
// Router credentials (for bridge node)
#define ROUTER_SSID "YourRouterSSID"
#define ROUTER_PASSWORD "YourRouterPassword"
// Mock HTTP Server Configuration
// Replace with your computer's IP address where mock server is running
#define MOCK_SERVER_IP "192.168.1.100" // ← CHANGE THIS
#define MOCK_SERVER_PORT 8080
// Set to true if this node should be the bridge
#define IS_BRIDGE true
// ============================================
// Global Objects
// ============================================
Scheduler userScheduler;
painlessMesh mesh;
// Test tracking//************************************************************
// Shared Gateway Example
//
// This example demonstrates the Shared Gateway Mode feature of painlessMesh.
// Unlike the Bridge Mode where only one node connects to the router,
// Shared Gateway Mode allows ALL nodes to connect to the same WiFi router
// while maintaining mesh connectivity.
//
// Key Features:
// - All nodes operate in AP+STA mode simultaneously
// - All nodes connect to the same WiFi router
// - Mesh and router operate on the same channel for reliability
// - Automatic router reconnection if connection is lost
// - Each node can independently access the Internet
//
// Use Cases:
// - Industrial sensor networks where all nodes are within router range
// - Smart building systems requiring redundant Internet access
// - Fish farm monitoring where any node can send critical alarms to cloud
// - Remote monitoring stations with shared WiFi infrastructure
//
// Hardware Requirements:
// - ESP32 or ESP8266
// - WiFi router within range of all nodes
//
// How It Works:
// 1. Each node connects to the router to detect its WiFi channel
// 2. Mesh network is initialized on the same channel as the router
// 3. Router connection is re-established using stationManual()
// 4. Periodic monitoring ensures automatic reconnection if router is lost
//
// For more details, see docs/design/SHARED_GATEWAY_DESIGN.md
//
//************************************************************
#include "painlessMesh.h"
// ============================================
// Mesh Network Configuration
// ============================================
// These settings must match across all nodes in your mesh network
#define MESH_PREFIX "SharedGatewayMesh" // Mesh network name (SSID prefix)
#define MESH_PASSWORD "meshPassword123" // Mesh network password
#define MESH_PORT 5555 // TCP port for mesh communication
// ============================================
// Router Configuration
// ============================================
// Configure these to match your WiFi router settings
// All nodes in the mesh will connect to this same router
#define ROUTER_SSID "YourRouterSSID" // Your WiFi router name//************************************************************
// 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;
//************************************************************
// Tuning the TCP connection retry behaviour (issue #378)
//
// painlessMesh retries a failed TCP connection with exponential backoff
// before giving up and falling back to a full WiFi reconnect. The defaults
// (5 retries, 1s base delay -> 1s, 2s, 4s, 8s, 8s) are tuned for general
// purpose meshes and deliberately favour reliability over speed.
//
// setTcpRetryConfig() lets you pick a different trade-off. Three ready-made
// profiles are shown below; switch between them with ACTIVE_PROFILE.
//
// Read examples/tcpRetryConfig/README.md before changing these values - the
// defaults exist because 1.9.x raised them to fix real mesh instability.
//************************************************************
#include <painlessMesh.h>
#define MESH_SSID "whateverYouLike"
#define MESH_PASSWORD "somethingSneaky"
#define MESH_PORT 5555
// ---------------------------------------------------------------------------
// Profiles
// ---------------------------------------------------------------------------
#define PROFILE_REALTIME 1 // low latency: fail fast, reconnect fast
#define PROFILE_RELIABLE 2 // industrial: many retries, long backoff
#define PROFILE_BATTERY 3 // conserve power: few retries, long block
// >>> Change this line to try a different profile <<<
#define ACTIVE_PROFILE PROFILE_REALTIME
// Prototypes
void sendMessage();
void receivedCallback(uint32_t from, String &msg);
void newConnectionCallback(uint32_t nodeId);
void droppedConnectionCallback(uint32_t nodeId);
Scheduler userScheduler;
painlessMesh mesh;
Task taskSendMessage(TASK_SECOND * 5, TASK_FOREVER, &sendMessage);
// Build the retry configuration for the selected profile.
painlessmesh::tcp::TcpRetryConfig buildRetryConfig() {
painlessmesh::tcp::TcpRetryConfig cfg; // starts at the library defaults
#if ACTIVE_PROFILE == PROFILE_REALTIME
// Real-time sensor / LED meshes: a stalled node is worse than a dropped
// one. Give up on the TCP handshake almost immediately and go straight
// back to scanning for another parent.
cfg.maxRetries = 1; // default 5//************************************************************
// 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);