@alteriom/painlessmesh 1.7.9 → 1.8.0

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 (34) hide show
  1. package/CHANGELOG.md +94 -2
  2. package/README.md +108 -1
  3. package/docs/BRIDGE_FAILOVER.md +512 -0
  4. package/docs/BRIDGE_HEALTH_MONITORING.md +293 -0
  5. package/docs/CREATE_MISSING_RELEASES.md +321 -0
  6. package/docs/releases/RELEASE_SUMMARY_v1.7.8.md +523 -0
  7. package/docs/releases/RELEASE_SUMMARY_v1.7.9.md +542 -0
  8. package/examples/alteriom/alteriom_sensor_package.hpp +213 -0
  9. package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +1014 -11
  10. package/examples/basic/basic.ino +6 -2
  11. package/examples/bridge/bridge.ino +44 -23
  12. package/examples/bridge/bridge_health_monitoring_example.ino +188 -0
  13. package/examples/bridgeAwareSensorNode/alteriom_sensor_package.hpp +1227 -0
  14. package/examples/bridgeAwareSensorNode/bridgeAwareSensorNode.ino +343 -0
  15. package/examples/bridgeAwareSensorNode/platformio.ini +26 -0
  16. package/examples/bridge_failover/README.md +358 -0
  17. package/examples/bridge_failover/bridge_failover.ino +180 -0
  18. package/examples/bridge_failover/platformio.ini +27 -0
  19. package/examples/diagnosticsExample/diagnosticsExample.ino +171 -0
  20. package/examples/diagnosticsExample/platformio.ini +26 -0
  21. package/examples/ntpTimeSyncBridge/alteriom_sensor_package.hpp +1383 -0
  22. package/examples/ntpTimeSyncBridge/ntpTimeSyncBridge.ino +81 -0
  23. package/examples/ntpTimeSyncNode/alteriom_sensor_package.hpp +1383 -0
  24. package/examples/ntpTimeSyncNode/ntpTimeSyncNode.ino +109 -0
  25. package/examples/rtcIntegration/README.md +235 -0
  26. package/examples/rtcIntegration/rtcIntegration.ino +196 -0
  27. package/library.json +1 -1
  28. package/library.properties +1 -1
  29. package/package.json +1 -1
  30. package/src/arduino/wifi.hpp +572 -0
  31. package/src/painlessMeshSTA.cpp +63 -0
  32. package/src/painlessMeshSTA.h +3 -0
  33. package/src/painlessmesh/mesh.hpp +1127 -4
  34. package/src/painlessmesh/rtc.hpp +203 -0
@@ -1165,6 +1165,219 @@ class MeshBridgePackage : public painlessmesh::plugin::BroadcastPackage {
1165
1165
  #endif
1166
1166
  };
1167
1167
 
1168
+ /**
1169
+ * @brief Bridge status package for monitoring Internet connectivity (Type 610
1170
+ * - BRIDGE_STATUS)
1171
+ *
1172
+ * This package is broadcast by bridge nodes to inform the mesh about their
1173
+ * Internet connectivity status. Regular nodes can use this information to
1174
+ * decide whether to send data, queue messages, or failover to backup bridges.
1175
+ *
1176
+ * Broadcast interval: Configurable, default 30 seconds
1177
+ * Timeout threshold: 60 seconds (nodes consider bridge offline if no heartbeat)
1178
+ *
1179
+ * Type ID 610 for BRIDGE_STATUS per mqtt-schema v0.7.3+.
1180
+ */
1181
+ class BridgeStatusPackage : public painlessmesh::plugin::BroadcastPackage {
1182
+ public:
1183
+ // Bridge connectivity status
1184
+ bool internetConnected = false; // Is the bridge connected to Internet?
1185
+ int8_t routerRSSI = 0; // Router WiFi signal strength in dBm
1186
+ uint8_t routerChannel = 0; // Router WiFi channel
1187
+ uint32_t uptime = 0; // Bridge uptime in milliseconds
1188
+ TSTRING gatewayIP = ""; // Router gateway IP address
1189
+ uint32_t timestamp = 0; // Timestamp of status check
1190
+
1191
+ // MQTT Schema v0.7.3+ message_type
1192
+ uint16_t messageType = 610; // BRIDGE_STATUS
1193
+
1194
+ BridgeStatusPackage() : BroadcastPackage(610) {}
1195
+
1196
+ BridgeStatusPackage(JsonObject jsonObj) : BroadcastPackage(jsonObj) {
1197
+ internetConnected = jsonObj["internetConnected"] | false;
1198
+ routerRSSI = jsonObj["routerRSSI"] | 0;
1199
+ routerChannel = jsonObj["routerChannel"] | 0;
1200
+ uptime = jsonObj["uptime"] | 0;
1201
+ gatewayIP = jsonObj["gatewayIP"].as<TSTRING>();
1202
+ timestamp = jsonObj["timestamp"] | 0;
1203
+ messageType = jsonObj["message_type"] | 610;
1204
+ }
1205
+
1206
+ JsonObject addTo(JsonObject&& jsonObj) const {
1207
+ jsonObj = BroadcastPackage::addTo(std::move(jsonObj));
1208
+ jsonObj["internetConnected"] = internetConnected;
1209
+ jsonObj["routerRSSI"] = routerRSSI;
1210
+ jsonObj["routerChannel"] = routerChannel;
1211
+ jsonObj["uptime"] = uptime;
1212
+ jsonObj["gatewayIP"] = gatewayIP;
1213
+ jsonObj["timestamp"] = timestamp;
1214
+ jsonObj["message_type"] = messageType;
1215
+ return jsonObj;
1216
+ }
1217
+
1218
+ #if ARDUINOJSON_VERSION_MAJOR < 7
1219
+ size_t jsonObjectSize() const {
1220
+ return JSON_OBJECT_SIZE(noJsonFields + 7) + gatewayIP.length();
1221
+ }
1222
+ #endif
1223
+ };
1224
+
1225
+ /**
1226
+ * @brief Bridge election package for automatic failover (Type 611 -
1227
+ * BRIDGE_ELECTION)
1228
+ *
1229
+ * When a bridge node goes offline, regular nodes with router credentials can
1230
+ * participate in an election to become the new bridge. Each candidate
1231
+ * broadcasts its RSSI to the router, uptime, and available memory. The node
1232
+ * with the best RSSI wins the election.
1233
+ *
1234
+ * Election process:
1235
+ * 1. Bridge failure detected (no heartbeat for 60+ seconds)
1236
+ * 2. Nodes broadcast BridgeElectionPackage with their router RSSI
1237
+ * 3. 5-second collection window for all candidates
1238
+ * 4. Each node evaluates all candidates locally (deterministic)
1239
+ * 5. Winner promotes itself to bridge, others remain as regular nodes
1240
+ *
1241
+ * Type ID 611 for BRIDGE_ELECTION per mqtt-schema v0.7.3+.
1242
+ */
1243
+ class BridgeElectionPackage : public painlessmesh::plugin::BroadcastPackage {
1244
+ public:
1245
+ int8_t routerRSSI = 0; // Router WiFi signal strength in dBm (-127 to 0)
1246
+ uint32_t uptime = 0; // Node uptime in milliseconds
1247
+ uint32_t freeMemory = 0; // Free memory in bytes
1248
+ uint32_t timestamp = 0; // Election timestamp
1249
+ TSTRING routerSSID = ""; // Router SSID (for verification)
1250
+
1251
+ // MQTT Schema v0.7.3+ message_type
1252
+ uint16_t messageType = 611; // BRIDGE_ELECTION
1253
+
1254
+ BridgeElectionPackage() : BroadcastPackage(611) {}
1255
+
1256
+ BridgeElectionPackage(JsonObject jsonObj) : BroadcastPackage(jsonObj) {
1257
+ routerRSSI = jsonObj["routerRSSI"] | 0;
1258
+ uptime = jsonObj["uptime"] | 0;
1259
+ freeMemory = jsonObj["freeMemory"] | 0;
1260
+ timestamp = jsonObj["timestamp"] | 0;
1261
+ routerSSID = jsonObj["routerSSID"].as<TSTRING>();
1262
+ messageType = jsonObj["message_type"] | 611;
1263
+ }
1264
+
1265
+ JsonObject addTo(JsonObject&& jsonObj) const {
1266
+ jsonObj = BroadcastPackage::addTo(std::move(jsonObj));
1267
+ jsonObj["routerRSSI"] = routerRSSI;
1268
+ jsonObj["uptime"] = uptime;
1269
+ jsonObj["freeMemory"] = freeMemory;
1270
+ jsonObj["timestamp"] = timestamp;
1271
+ jsonObj["routerSSID"] = routerSSID;
1272
+ jsonObj["message_type"] = messageType;
1273
+ return jsonObj;
1274
+ }
1275
+
1276
+ #if ARDUINOJSON_VERSION_MAJOR < 7
1277
+ size_t jsonObjectSize() const {
1278
+ return JSON_OBJECT_SIZE(noJsonFields + 6) + routerSSID.length();
1279
+ }
1280
+ #endif
1281
+ };
1282
+
1283
+ /**
1284
+ * @brief Bridge takeover announcement package (Type 612 - BRIDGE_TAKEOVER)
1285
+ *
1286
+ * After winning the bridge election, the new bridge node broadcasts this
1287
+ * package to inform all mesh nodes that it is now the primary bridge.
1288
+ * This allows nodes to update their bridge tracking and routing tables.
1289
+ *
1290
+ * Type ID 612 for BRIDGE_TAKEOVER per mqtt-schema v0.7.3+.
1291
+ */
1292
+ class BridgeTakeoverPackage : public painlessmesh::plugin::BroadcastPackage {
1293
+ public:
1294
+ uint32_t previousBridge = 0; // Previous bridge node ID (0 if none)
1295
+ TSTRING reason =
1296
+ ""; // Reason for takeover (e.g., "Election winner - best router signal")
1297
+ int8_t routerRSSI = 0; // New bridge's router signal strength
1298
+ uint32_t timestamp = 0; // Takeover timestamp
1299
+
1300
+ // MQTT Schema v0.7.3+ message_type
1301
+ uint16_t messageType = 612; // BRIDGE_TAKEOVER
1302
+
1303
+ BridgeTakeoverPackage() : BroadcastPackage(612) {}
1304
+
1305
+ BridgeTakeoverPackage(JsonObject jsonObj) : BroadcastPackage(jsonObj) {
1306
+ previousBridge = jsonObj["previousBridge"] | 0;
1307
+ reason = jsonObj["reason"].as<TSTRING>();
1308
+ routerRSSI = jsonObj["routerRSSI"] | 0;
1309
+ timestamp = jsonObj["timestamp"] | 0;
1310
+ messageType = jsonObj["message_type"] | 612;
1311
+ }
1312
+
1313
+ JsonObject addTo(JsonObject&& jsonObj) const {
1314
+ jsonObj = BroadcastPackage::addTo(std::move(jsonObj));
1315
+ jsonObj["previousBridge"] = previousBridge;
1316
+ jsonObj["reason"] = reason;
1317
+ jsonObj["routerRSSI"] = routerRSSI;
1318
+ jsonObj["timestamp"] = timestamp;
1319
+ jsonObj["message_type"] = messageType;
1320
+ return jsonObj;
1321
+ }
1322
+
1323
+ #if ARDUINOJSON_VERSION_MAJOR < 7
1324
+ size_t jsonObjectSize() const {
1325
+ return JSON_OBJECT_SIZE(noJsonFields + 5) + reason.length();
1326
+ }
1327
+ #endif
1328
+ };
1329
+
1330
+ /**
1331
+ * @brief NTP time synchronization package (Type 614 - TIME_SYNC_NTP)
1332
+ *
1333
+ * Broadcast by bridge nodes to distribute authoritative NTP time to the mesh.
1334
+ * When a bridge has Internet connectivity, it can provide NTP time to improve
1335
+ * accuracy across the entire mesh network.
1336
+ *
1337
+ * Regular nodes should:
1338
+ * 1. Accept time from bridge nodes (verify sender is bridge)
1339
+ * 2. Update local time with mesh.setTimeFromNTP(ntpTime)
1340
+ * 3. Optionally sync RTC modules if available
1341
+ *
1342
+ * Type ID 614 for TIME_SYNC_NTP.
1343
+ */
1344
+ class NTPTimeSyncPackage : public painlessmesh::plugin::BroadcastPackage {
1345
+ public:
1346
+ uint32_t ntpTime = 0; // Unix timestamp from NTP server
1347
+ uint16_t accuracy = 0; // Milliseconds uncertainty/precision
1348
+ TSTRING source = ""; // NTP server source (e.g., "pool.ntp.org")
1349
+ uint32_t timestamp = 0; // Collection timestamp
1350
+
1351
+ // MQTT Schema message_type
1352
+ uint16_t messageType = 614; // TIME_SYNC_NTP
1353
+
1354
+ NTPTimeSyncPackage() : BroadcastPackage(614) {}
1355
+
1356
+ NTPTimeSyncPackage(JsonObject jsonObj) : BroadcastPackage(jsonObj) {
1357
+ ntpTime = jsonObj["ntpTime"];
1358
+ accuracy = jsonObj["accuracy"];
1359
+ source = jsonObj["source"].as<TSTRING>();
1360
+ timestamp = jsonObj["timestamp"];
1361
+ messageType = jsonObj["message_type"] | 614;
1362
+ }
1363
+
1364
+ JsonObject addTo(JsonObject&& jsonObj) const {
1365
+ jsonObj = BroadcastPackage::addTo(std::move(jsonObj));
1366
+ jsonObj["ntpTime"] = ntpTime;
1367
+ jsonObj["accuracy"] = accuracy;
1368
+ jsonObj["source"] = source;
1369
+ jsonObj["timestamp"] = timestamp;
1370
+ jsonObj["message_type"] = messageType;
1371
+ return jsonObj;
1372
+ }
1373
+
1374
+ #if ARDUINOJSON_VERSION_MAJOR < 7
1375
+ size_t jsonObjectSize() const {
1376
+ return JSON_OBJECT_SIZE(noJsonFields + 5) + source.length();
1377
+ }
1378
+ #endif
1379
+ };
1380
+
1168
1381
  } // namespace alteriom
1169
1382
 
1170
1383
  #endif // ALTERIOM_SENSOR_PACKAGE_HPP