@alteriom/painlessmesh 1.7.6 → 1.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/README.md +81 -6
  3. package/RELEASE_GUIDE.md +36 -0
  4. package/docs/MQTT_BRIDGE_COMMANDS.md +10 -10
  5. package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +1 -1
  6. package/docs/MQTT_SCHEMA_COMPLIANCE.md +57 -2
  7. package/docs/PHASE1_GUIDE.md +1 -1
  8. package/docs/alteriom/overview.md +2 -2
  9. package/docs/architecture/plugin-system.md +1 -1
  10. package/docs/archive/RELEASE_SUMMARY.md +1 -1
  11. package/docs/releases/RELEASE_CHECKLIST_v1.7.6.md +389 -0
  12. package/docs/releases/RELEASE_SUMMARY_v1.7.7.md +391 -0
  13. package/docs/v1.7.7_MQTT_IMPROVEMENTS.md +776 -0
  14. package/docs/wiki/API-Reference.md +2 -2
  15. package/docs/wiki/Complete-Documentation.md +1 -1
  16. package/examples/alteriom/README.md +137 -3
  17. package/examples/alteriom/alteriom.ino +1 -1
  18. package/examples/alteriom/alteriom_sensor_package.hpp +557 -2
  19. package/examples/alteriomImproved/alteriom_sensor_package.hpp +1 -1
  20. package/examples/alteriomImproved/improved_sensor_node.ino +1 -1
  21. package/examples/alteriomMetricsHealth/alteriom_sensor_package.hpp +796 -0
  22. package/examples/alteriomMetricsHealth/metrics_health_node.ino +418 -0
  23. package/examples/alteriomMetricsHealth/platformio.ini +26 -0
  24. package/examples/alteriomPhase1/alteriom_sensor_package.hpp +1 -1
  25. package/examples/alteriomPhase1/phase1_features.ino +2 -2
  26. package/examples/alteriomPhase2/alteriom_sensor_package.hpp +1 -1
  27. package/examples/alteriomSensorNode/alteriom_sensor_node.ino +1 -1
  28. package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +1 -1
  29. package/examples/bridge/enhanced_mqtt_bridge.hpp +610 -0
  30. package/examples/bridge/enhanced_mqtt_bridge_example.ino +226 -0
  31. package/examples/meshCommandNode/alteriom_sensor_package.hpp +1 -1
  32. package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +1 -1
  33. package/examples/mqttTopologyTest/mqttTopologyTest.ino +5 -1
  34. package/library.json +1 -1
  35. package/library.properties +1 -1
  36. package/package.json +2 -2
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Enhanced MQTT Bridge Example - painlessMesh v1.7.7
3
+ *
4
+ * Demonstrates the enhanced MQTT bridge with:
5
+ * - Command handlers for requesting metrics and health checks
6
+ * - Aggregated network statistics
7
+ * - Real-time metric collection from mesh nodes
8
+ * - Health monitoring with alerting
9
+ *
10
+ * This gateway node bridges between MQTT and the mesh network,
11
+ * enabling remote monitoring and control.
12
+ *
13
+ * Hardware: ESP32 with WiFi (ESP8266 also supported)
14
+ *
15
+ * MQTT Topics:
16
+ * Subscribe (Commands):
17
+ * - mesh/command/request_metrics {"node_id": 0} // 0 = all nodes
18
+ * - mesh/command/request_health {"node_id": 12345}
19
+ * - mesh/command/get_aggregated {}
20
+ *
21
+ * Publish (Data):
22
+ * - mesh/metrics/{node_id} // Individual node metrics
23
+ * - mesh/health/{node_id} // Individual node health
24
+ * - mesh/aggregated/metrics // Aggregated mesh-wide metrics
25
+ * - mesh/aggregated/health // Aggregated mesh health summary
26
+ * - mesh/alerts/critical // Critical health alerts
27
+ */
28
+
29
+ #include "painlessMesh.h"
30
+ #include <WiFi.h>
31
+ #include <PubSubClient.h>
32
+ #include "enhanced_mqtt_bridge.hpp"
33
+
34
+ // Mesh Configuration
35
+ #define MESH_PREFIX "AlteriomMesh"
36
+ #define MESH_PASSWORD "your_password"
37
+ #define MESH_PORT 5555
38
+
39
+ // WiFi Station Configuration (for MQTT connection)
40
+ #define STATION_SSID "your_wifi_ssid"
41
+ #define STATION_PASSWORD "your_wifi_password"
42
+
43
+ // MQTT Configuration
44
+ #define MQTT_BROKER "192.168.1.100" // Your MQTT broker IP
45
+ #define MQTT_PORT 1883
46
+ #define MQTT_USER "mqtt_user" // Leave empty if no auth
47
+ #define MQTT_PASSWORD "mqtt_password" // Leave empty if no auth
48
+
49
+ Scheduler userScheduler;
50
+ painlessMesh mesh;
51
+ WiFiClient espClient;
52
+ PubSubClient mqttClient(espClient);
53
+ EnhancedMqttBridge* bridge = nullptr;
54
+
55
+ // Task for reconnecting to MQTT
56
+ Task taskReconnectMQTT(5000, TASK_FOREVER, &reconnectMQTT);
57
+
58
+ void setup() {
59
+ Serial.begin(115200);
60
+ Serial.println("\n\n=== Enhanced MQTT Bridge for painlessMesh v1.7.7 ===");
61
+
62
+ // Initialize mesh
63
+ mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
64
+ mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
65
+
66
+ // Configure mesh callbacks
67
+ mesh.onNewConnection(&newConnectionCallback);
68
+ mesh.onChangedConnections(&changedConnectionCallback);
69
+ mesh.onDroppedConnection(&droppedConnectionCallback);
70
+
71
+ // Connect to WiFi for MQTT
72
+ WiFi.mode(WIFI_AP_STA);
73
+ WiFi.begin(STATION_SSID, STATION_PASSWORD);
74
+
75
+ Serial.print("Connecting to WiFi");
76
+ while (WiFi.status() != WL_CONNECTED) {
77
+ delay(500);
78
+ Serial.print(".");
79
+ }
80
+ Serial.println(" Connected!");
81
+ Serial.printf("IP Address: %s\n", WiFi.localIP().toString().c_str());
82
+
83
+ // Configure MQTT
84
+ mqttClient.setServer(MQTT_BROKER, MQTT_PORT);
85
+ mqttClient.setCallback(mqttCallback);
86
+ mqttClient.setBufferSize(2048); // Increase buffer for large messages
87
+
88
+ // Connect to MQTT
89
+ connectMQTT();
90
+
91
+ // Create and initialize enhanced bridge
92
+ bridge = new EnhancedMqttBridge(mesh, mqttClient);
93
+ bridge->setTopicPrefix("mesh/");
94
+ bridge->setDeviceId("GATEWAY-" + String(mesh.getNodeId(), HEX));
95
+ bridge->enableAggregation(true);
96
+ bridge->setAggregationInterval(60000); // 60 seconds
97
+ bridge->begin();
98
+
99
+ // Add MQTT reconnect task
100
+ userScheduler.addTask(taskReconnectMQTT);
101
+ taskReconnectMQTT.enable();
102
+
103
+ Serial.printf("Gateway Node ID: %u\n", mesh.getNodeId());
104
+ Serial.println("Enhanced MQTT Bridge ready!");
105
+ Serial.println("\nAvailable MQTT commands:");
106
+ Serial.println(" mesh/command/request_metrics {\"node_id\": 0}");
107
+ Serial.println(" mesh/command/request_health {\"node_id\": 12345}");
108
+ Serial.println(" mesh/command/get_aggregated {}");
109
+ }
110
+
111
+ void loop() {
112
+ mesh.update();
113
+
114
+ // Handle MQTT
115
+ if (mqttClient.connected()) {
116
+ mqttClient.loop();
117
+ }
118
+
119
+ // Update bridge (handles aggregation)
120
+ if (bridge) {
121
+ bridge->update();
122
+ }
123
+ }
124
+
125
+ /**
126
+ * MQTT callback - receives commands from MQTT
127
+ */
128
+ void mqttCallback(char* topic, byte* payload, unsigned int length) {
129
+ // Convert to String
130
+ String topicStr = String(topic);
131
+ String payloadStr = "";
132
+ for (unsigned int i = 0; i < length; i++) {
133
+ payloadStr += (char)payload[i];
134
+ }
135
+
136
+ Serial.printf("\n[MQTT] Message on topic: %s\n", topic);
137
+ Serial.printf("Payload: %s\n", payloadStr.c_str());
138
+
139
+ // Forward to bridge for handling
140
+ if (bridge) {
141
+ bridge->handleMQTTMessage(topicStr, payloadStr);
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Connect to MQTT broker
147
+ */
148
+ void connectMQTT() {
149
+ Serial.print("Connecting to MQTT broker...");
150
+
151
+ String clientId = "painlessMesh-" + String(mesh.getNodeId());
152
+
153
+ bool connected = false;
154
+ if (strlen(MQTT_USER) > 0) {
155
+ connected = mqttClient.connect(clientId.c_str(), MQTT_USER, MQTT_PASSWORD);
156
+ } else {
157
+ connected = mqttClient.connect(clientId.c_str());
158
+ }
159
+
160
+ if (connected) {
161
+ Serial.println(" Connected!");
162
+
163
+ // Subscribe to command topics
164
+ mqttClient.subscribe("mesh/command/request_metrics");
165
+ mqttClient.subscribe("mesh/command/request_health");
166
+ mqttClient.subscribe("mesh/command/get_aggregated");
167
+
168
+ Serial.println("Subscribed to command topics");
169
+
170
+ // Publish connection announcement
171
+ String topic = "mesh/gateway/status";
172
+ String payload = "{\"status\":\"connected\",\"node_id\":" + String(mesh.getNodeId()) + "}";
173
+ mqttClient.publish(topic.c_str(), payload.c_str());
174
+ } else {
175
+ Serial.printf(" Failed! (rc=%d)\n", mqttClient.state());
176
+ Serial.println("Will retry in 5 seconds...");
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Reconnect to MQTT if disconnected
182
+ */
183
+ void reconnectMQTT() {
184
+ if (!mqttClient.connected() && WiFi.status() == WL_CONNECTED) {
185
+ Serial.println("\nMQTT disconnected, attempting to reconnect...");
186
+ connectMQTT();
187
+ }
188
+ }
189
+
190
+ // Mesh callbacks
191
+ void newConnectionCallback(uint32_t nodeId) {
192
+ Serial.printf("\n[Mesh] New connection: %u\n", nodeId);
193
+ Serial.printf("Total nodes in mesh: %d\n", mesh.getNodeList().size() + 1);
194
+
195
+ // Publish to MQTT
196
+ if (mqttClient.connected()) {
197
+ String topic = "mesh/events/connection";
198
+ String payload = "{\"event\":\"new_connection\",\"node_id\":" + String(nodeId) +
199
+ ",\"total_nodes\":" + String(mesh.getNodeList().size() + 1) + "}";
200
+ mqttClient.publish(topic.c_str(), payload.c_str());
201
+ }
202
+ }
203
+
204
+ void changedConnectionCallback() {
205
+ Serial.println("\n[Mesh] Topology changed");
206
+
207
+ // Publish to MQTT
208
+ if (mqttClient.connected()) {
209
+ auto nodes = mesh.getNodeList();
210
+ String topic = "mesh/events/topology_change";
211
+ String payload = "{\"event\":\"topology_changed\",\"node_count\":" +
212
+ String(nodes.size() + 1) + "}";
213
+ mqttClient.publish(topic.c_str(), payload.c_str());
214
+ }
215
+ }
216
+
217
+ void droppedConnectionCallback(uint32_t nodeId) {
218
+ Serial.printf("\n[Mesh] Connection dropped: %u\n", nodeId);
219
+
220
+ // Publish to MQTT
221
+ if (mqttClient.connected()) {
222
+ String topic = "mesh/events/disconnection";
223
+ String payload = "{\"event\":\"connection_dropped\",\"node_id\":" + String(nodeId) + "}";
224
+ mqttClient.publish(topic.c_str(), payload.c_str());
225
+ }
226
+ }
@@ -60,7 +60,7 @@ class CommandPackage : public painlessmesh::plugin::SinglePackage {
60
60
  TSTRING parameters = ""; // Command parameters as JSON string
61
61
  uint32_t commandId = 0; // Unique command identifier for tracking
62
62
 
63
- CommandPackage() : SinglePackage(201) {} // Type ID 201 for Alteriom commands
63
+ CommandPackage() : SinglePackage(400) {} // Type ID 201 for Alteriom commands
64
64
 
65
65
  CommandPackage(JsonObject jsonObj) : SinglePackage(jsonObj) {
66
66
  command = jsonObj["cmd"];
@@ -60,7 +60,7 @@ class CommandPackage : public painlessmesh::plugin::SinglePackage {
60
60
  TSTRING parameters = ""; // Command parameters as JSON string
61
61
  uint32_t commandId = 0; // Unique command identifier for tracking
62
62
 
63
- CommandPackage() : SinglePackage(201) {} // Type ID 201 for Alteriom commands
63
+ CommandPackage() : SinglePackage(400) {} // Type ID 201 for Alteriom commands
64
64
 
65
65
  CommandPackage(JsonObject jsonObj) : SinglePackage(jsonObj) {
66
66
  command = jsonObj["cmd"];
@@ -130,9 +130,13 @@ unsigned long lastTopologyUpdate = 0;
130
130
  * Format: ALT-XXXXXXXXXXXX (uppercase hex)
131
131
  */
132
132
  String getDeviceId() {
133
+ #ifdef ESP32
133
134
  uint64_t chipid = ESP.getEfuseMac(); // ESP32 unique ID
135
+ #else
136
+ uint32_t chipid = ESP.getChipId(); // ESP8266 chip ID
137
+ #endif
134
138
  char deviceId[17];
135
- snprintf(deviceId, sizeof(deviceId), "ALT-%012llX", chipid);
139
+ snprintf(deviceId, sizeof(deviceId), "ALT-%012llX", (uint64_t)chipid);
136
140
  return String(deviceId);
137
141
  }
138
142
 
package/library.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "type": "git",
7
7
  "url": "https://github.com/Alteriom/painlessMesh"
8
8
  },
9
- "version": "1.7.6",
9
+ "version": "1.7.7",
10
10
  "frameworks": ["arduino"],
11
11
  "platforms": ["espressif8266", "espressif32"],
12
12
  "srcDir": "src",
@@ -1,5 +1,5 @@
1
1
  name=AlteriomPainlessMesh
2
- version=1.7.6
2
+ version=1.7.7
3
3
  author=Coopdis,Scotty Franzyshen,Edwin van Leeuwen,Germán Martín,Maximilian Schwarz,Doanh Doanh,Alteriom
4
4
  maintainer=Alteriom
5
5
  sentence=A painless way to setup a mesh with ESP8266 and ESP32 devices with Alteriom extensions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alteriom/painlessmesh",
3
- "version": "1.7.6",
3
+ "version": "1.7.7",
4
4
  "description": "painlessMesh is a user-friendly library for creating mesh networks with ESP8266 and ESP32 devices. This Alteriom fork includes additional packages for sensor data (SensorPackage), device commands (CommandPackage), and status monitoring (StatusPackage). It handles routing and network management automatically, so you can focus on your application. The library uses JSON-based messaging and syncs time across all nodes, making it ideal for coordinated behaviour like synchronized light displays or sensor networks reporting to a central node.",
5
5
  "keywords": [
6
6
  "arduino",
@@ -39,7 +39,7 @@
39
39
  "url": "https://github.com/Alteriom/painlessMesh/issues"
40
40
  },
41
41
  "devDependencies": {
42
- "@alteriom/mqtt-schema": "^0.5.0",
42
+ "@alteriom/mqtt-schema": "^0.7.2",
43
43
  "@eslint/js": "^9.0.0",
44
44
  "ajv": "^8.17.1",
45
45
  "ajv-formats": "^3.0.1",