MESH_TOPOLOGY_PROGRESS - Alteriom/painlessMesh GitHub Wiki
Start Date: October 12, 2025
Implementation Status: 🟢 Phase 1 & 2 Complete
Branch: copilot/start-phase-2-implementation
| Phase | Status | Tasks Complete | Total Tasks | Progress |
|---|---|---|---|---|
| Phase 1: Core Library | ✅ COMPLETE | 8/8 | 8 | 100% |
| Phase 2: Topology Reporter | ✅ COMPLETE | 2/2 | 2 | 100% |
| Phase 3: Integration | ⏳ PENDING | 0/4 | 4 | 0% |
| Phase 4: Testing | ⏳ PENDING | 0/2 | 2 | 0% |
| Phase 5: Documentation | ⏳ PENDING | 0/2 | 2 | 0% |
| TOTAL | 🟡 IN PROGRESS | 10/18 | 18 | 56% |
File: src/painlessmesh/mesh.hpp
struct ConnectionInfo {
uint32_t nodeId; // Connected node ID
uint32_t lastSeen; // Timestamp of last message (ms)
int rssi; // Signal strength (dBm)
int avgLatency; // Average round-trip time (ms)
int hopCount; // Hops from current node
int quality; // Connection quality (0-100)
uint32_t messagesRx; // Messages received
uint32_t messagesTx; // Messages sent
uint32_t messagesDropped; // Failed transmissions
};- Returns
std::vector<ConnectionInfo>of all direct connections - Includes quality metrics from Connection class
- Used by topology reporter
- Calculates hop count to specific node
- Returns -1 if unreachable
- Returns 1 for direct connections, 2 for indirect (simplified)
- Returns
std::map<uint32_t, uint32_t>(destination -> next hop) - Currently only populates direct connections
- TODO: Implement full multi-hop routing table lookup
Added to Connection class:
uint32_t messagesRx = 0;
uint32_t messagesTx = 0;
uint32_t messagesDropped = 0;
uint32_t timeLastReceived = 0;
std::vector<uint32_t> latencySamples;
static const size_t MAX_LATENCY_SAMPLES = 10;- Calculates average latency from rolling window (10 samples)
- Returns -1 if no samples available
- Used in quality calculation
- Calculates connection quality (0-100)
- Factors: latency, packet loss, RSSI
- Penalties:
- High latency (>100ms): -1 per 5ms over threshold
- Packet loss: -1 per 1% loss rate
- Weak RSSI (<-80 dBm): -1 per dBm below threshold
- Platform-specific RSSI retrieval
- ESP32/ESP8266: Returns WiFi.RSSI()
- Other platforms: Returns 0
- Uses
#ifdefguards for platform detection
File: examples/bridge/mesh_topology_reporter.hpp
Features:
- Generates schema-compliant topology messages (@alteriom/mqtt-schema v0.5.0)
-
generateFullTopology()- Complete mesh snapshot with nodes, connections, metrics -
generateIncrementalUpdate()- Node join/leave events -
hasTopologyChanged()- Change detection to avoid redundant publishes - Network metrics: diameter, avg quality, throughput
- ISO 8601 timestamps (placeholder, needs NTP integration)
- Alteriom device ID format: ALT-XXXXXXXXXXXX
JSON Structure:
{
"schema_version": 1,
"device_id": "ALT-6825DD341CA4",
"device_type": "gateway",
"timestamp": "2025-10-12T15:00:00Z",
"firmware_version": "GW 2.3.4",
"event": "mesh_topology",
"mesh_id": "MESH-001",
"gateway_node_id": "ALT-6825DD341CA4",
"nodes": [...],
"connections": [...],
"metrics": {...},
"update_type": "full"
}File: examples/bridge/mesh_event_publisher.hpp
Features:
- Publishes real-time mesh events (@alteriom/mqtt-schema v0.5.0)
-
publishNodeJoin()- New node entered mesh -
publishNodeLeave()- Node left mesh -
publishConnectionLost()- Direct connection failed -
publishConnectionRestored()- Connection recovered -
publishNetworkSplit()- Mesh partitioned -
publishNetworkMerged()- Partitions rejoined
Event Structure:
{
"event": "mesh_event",
"event_type": "node_join",
"mesh_id": "MESH-001",
"affected_nodes": ["ALT-441D64F804A0"],
"details": {
"total_nodes": 4,
"timestamp": "2025-10-12T15:00:00Z"
}
}Location: examples/mqttCommandBridge/mqttCommandBridge.ino
Changes Required:
- Add include:
#include "examples/bridge/mesh_topology_reporter.hpp" - Create global instance:
MeshTopologyReporter* topologyReporter; - Initialize in setup():
topologyReporter = new MeshTopologyReporter(mesh, "MESH-001"); - Update
taskTopologyto usetopologyReporter->generateFullTopology() - Change topic to:
alteriom/mesh/MESH-001/topology
Estimated Effort: 30 minutes
Changes Required:
- Add include:
#include "examples/bridge/mesh_event_publisher.hpp" - Create global instance:
MeshEventPublisher* eventPublisher; - Initialize in setup():
eventPublisher = new MeshEventPublisher(mesh, mqttClient, "MESH-001"); - Update
mesh.onNewConnection()callback to calleventPublisher->publishNodeJoin() - Update
mesh.onDroppedConnection()callback to calleventPublisher->publishNodeLeave()
Estimated Effort: 30 minutes
Changes Required:
- Create
taskTopologyIncremental(5 second interval) - Check
topologyReporter->hasTopologyChanged() - If changed, generate and publish incremental update
- Add task to scheduler in setup()
Estimated Effort: 20 minutes
Location: examples/bridge/mqtt_command_bridge.hpp
Changes Required:
- Add case 300 in command switch
- Call
topologyReporter->generateFullTopology() - Publish response to MQTT
- Send command response with success=true
Estimated Effort: 15 minutes
Location: examples/mqttTopologyTest/mqttTopologyTest.ino (NEW)
Requirements:
- 3-node mesh setup (1 gateway + 2 sensors)
- Verify full topology published every 60s
- Verify incremental updates on node join/leave
- Verify events published correctly
- Log all messages to Serial
Estimated Effort: 2 hours
Location: test/catch/catch_topology_schema.cpp (NEW)
Test Cases:
- Topology message has envelope fields
- Topology message has nodes array
- Topology message has connections array
- Topology message has metrics object
- Event message has correct structure
- Device IDs match Alteriom format
Estimated Effort: 3 hours
Location: docs/MQTT_BRIDGE_COMMANDS.md
Sections to Add:
- Mesh Topology Reporting
- Mesh Events
- Topology command (300)
- Message examples
Estimated Effort: 1 hour
Location: docs/MESH_TOPOLOGY_GUIDE.md (NEW)
Content:
- How topology reporting works
- How to visualize with D3.js
- Troubleshooting topology issues
- Performance considerations
Estimated Effort: 2 hours
-
NTP Time Integration
- Currently using millis()-based timestamps
- Should use painlessMesh time sync for accurate ISO 8601 timestamps
- Location:
getISO8601Timestamp()in both reporter and publisher
-
Multi-Hop Routing
-
getHopCount()currently simplified (1 for direct, 2 for indirect) - Need proper BFS traversal of mesh tree
-
getRoutingTable()only shows direct connections
-
-
Node Status from Messages
- Currently using placeholder values for non-gateway nodes
- Should parse StatusPackage messages to get actual uptime, memory, firmware
- Store in cache indexed by node ID
-
Throughput Tracking
-
calculateThroughput()returns placeholder value - Need to track messages per second over time window
- Add to Connection class metrics
-
-
Network Partition Detection
-
publishNetworkSplit()has TODO for partition detection - Need algorithm to detect when mesh splits into segments
-
-
Connection State Machine
- Track connection state changes for
publishConnectionRestored() - Need to distinguish between first connect and reconnect
- Track connection state changes for
Unit Tests (catch2):
- ✅ Command response tracking (already exists)
- ✅ Status package serialization (already exists)
- ⏳ Topology JSON schema validation (TODO)
- ⏳ Event JSON schema validation (TODO)
Integration Tests (hardware):
- ⏳ 3-node mesh topology (TODO)
- ⏳ Node join/leave events (TODO)
- ⏳ Connection quality metrics (TODO)
- ⏳ Full/incremental updates (TODO)
Manual Tests:
- ⏳ MQTT message inspection
- ⏳ Web dashboard visualization (D3.js)
- ⏳ Schema validation with ajv
- Update mqttCommandBridge.ino - Integrate topology reporter and event publisher
- Test compilation - Ensure no errors with new API methods
- Manual MQTT inspection - Subscribe to topics and verify JSON structure
- Add GET_TOPOLOGY command - Command 300 handler
- Create hardware test sketch - 3-node mesh validation
- Fix NTP timestamps - Use painlessMesh time sync
- Schema validation tests - Automated JSON schema checks
- Documentation updates - MQTT_BRIDGE_COMMANDS.md and MESH_TOPOLOGY_GUIDE.md
- Multi-hop routing - Proper hop count calculation
- Node status caching - Track actual node metrics from status messages
- ✅
src/painlessmesh/mesh.hpp- Added ConnectionInfo, API methods, Connection metrics
- ✅
examples/bridge/mesh_topology_reporter.hpp- Topology reporter class - ✅
examples/bridge/mesh_event_publisher.hpp- Event publisher class - ✅
docs/IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md- Implementation plan - ✅
docs/MQTT_SCHEMA_REVIEW.md- Schema review and recommendations (already existed) - ✅ THIS FILE - Progress tracking
- ⏳
examples/mqttCommandBridge/mqttCommandBridge.ino- Integrate reporters - ⏳
examples/bridge/mqtt_command_bridge.hpp- Add command 300 - ⏳
docs/MQTT_BRIDGE_COMMANDS.md- Add topology docs - ⏳
test/catch/catch_topology_schema.cpp- Add schema tests (new file) - ⏳
examples/mqttTopologyTest/mqttTopologyTest.ino- Hardware test (new file) - ⏳
docs/MESH_TOPOLOGY_GUIDE.md- Visualization guide (new file)
⏳ Not Yet Tested - Need to compile after integration
Expected issues:
- None (API changes are additive, backward compatible)
⏳ Not Yet Run - Integration pending
✅ Last CI Build: Passed (commit 81ba4bc - CI fixes)
| Phase | Estimated | Actual | Status |
|---|---|---|---|
| Phase 1: Core Library | 16h | ~2h | ✅ Done |
| Phase 2: Topology Reporter | 12h | ~1h | ✅ Done |
| Phase 3: Integration | 2h | 0h | ⏳ Pending |
| Phase 4: Testing | 5h | 0h | ⏳ Pending |
| Phase 5: Documentation | 3h | 0h | ⏳ Pending |
| Total | 38h | 3h | 8% Complete |
Efficiency Note: Implementation is progressing faster than estimated due to:
- Clear implementation plan (IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md)
- Well-defined schemas (MQTT_SCHEMA_REVIEW.md)
- Existing infrastructure (MqttCommandBridge, StatusPackage)
- Core API additions (backward compatible)
- New classes (no changes to existing code)
- Schema-compliant JSON generation
- Platform-specific RSSI (needs ESP32/ESP8266 testing)
- Memory usage (8KB JSON buffers on ESP8266)
- NTP timestamp integration
- None identified at this stage
-
Mesh ID Convention
- Currently hardcoded as "MESH-001"
- Should this be configurable?
- Should it be derived from gateway node ID?
-
Firmware Version
- Currently hardcoded as "GW 2.3.4"
- Should this come from library version?
- Should it be user-defined in setup()?
-
Node Role Detection
- Currently assumes all non-gateway nodes are "sensor"
- How to distinguish sensor vs repeater vs bridge?
- Should nodes self-report their role?
-
Topology Publish Frequency
- Full: Every 60 seconds
- Incremental: Every 5 seconds (if changed)
- Are these intervals appropriate?
- Should they be configurable?
Updated: October 12, 2025 15:30 UTC
Next Update: After Phase 3 integration complete