@alteriom/painlessmesh 1.6.1 → 1.7.2

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 (129) hide show
  1. package/CHANGELOG.md +380 -143
  2. package/LICENSE +674 -674
  3. package/README.md +477 -434
  4. package/RELEASE_GUIDE.md +504 -418
  5. package/docs/DOCUMENTATION_MIGRATION_PLAN.md +175 -175
  6. package/docs/IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md +1062 -0
  7. package/docs/MESH_TOPOLOGY_GUIDE.md +992 -0
  8. package/docs/MESH_TOPOLOGY_PROGRESS.md +422 -0
  9. package/docs/MQTT_BRIDGE_COMMANDS.md +894 -0
  10. package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +324 -0
  11. package/docs/MQTT_COMMAND_SCHEMA_PROPOSAL.md +576 -0
  12. package/docs/MQTT_SCHEMA_COMPLIANCE.md +285 -0
  13. package/docs/MQTT_SCHEMA_PROPOSALS.md +446 -0
  14. package/docs/MQTT_SCHEMA_REVIEW.md +690 -0
  15. package/docs/OTA_COMMANDS_REFERENCE.md +554 -0
  16. package/docs/PHASE1_GUIDE.md +349 -0
  17. package/docs/PHASE2_GUIDE.md +543 -0
  18. package/docs/README.md +77 -70
  19. package/docs/SCHEMA_VALIDATION_CHECKLIST.md +222 -0
  20. package/docs/alteriom/overview.md +507 -507
  21. package/docs/api/core-api.md +606 -606
  22. package/docs/architecture/mesh-architecture.md +378 -378
  23. package/docs/architecture/plugin-system.md +516 -516
  24. package/docs/getting-started/first-mesh.md +409 -409
  25. package/docs/getting-started/installation.md +274 -274
  26. package/docs/getting-started/quickstart.md +157 -157
  27. package/docs/improvements/FEATURE_PROPOSALS.md +337 -0
  28. package/docs/improvements/PHASE1_IMPLEMENTATION.md +325 -0
  29. package/docs/improvements/PHASE2_IMPLEMENTATION.md +567 -0
  30. package/docs/improvements/README.md +86 -68
  31. package/docs/improvements/ota-and-status-enhancements.md +911 -0
  32. package/docs/improvements/ota-status-architecture-diagrams.md +658 -0
  33. package/docs/improvements/ota-status-quick-reference.md +284 -0
  34. package/docs/platformio-publishing.md +255 -0
  35. package/docs/platformio-setup-summary.md +121 -0
  36. package/docs/troubleshooting/common-issues.md +520 -520
  37. package/docs/troubleshooting/faq.md +472 -472
  38. package/docs/tutorials/basic-examples.md +717 -717
  39. package/docs/wiki/API-Reference.md +245 -245
  40. package/docs/wiki/Complete-Documentation.md +122 -122
  41. package/examples/alteriom/README.md +139 -81
  42. package/examples/alteriom/alteriom.ino +186 -185
  43. package/examples/alteriom/alteriom_sensor_package.hpp +240 -127
  44. package/examples/alteriom/platformio.ini +24 -24
  45. package/examples/alteriomImproved/alteriom_sensor_package.hpp +224 -0
  46. package/examples/{alteriom → alteriomImproved}/improved_sensor_node.ino +245 -245
  47. package/examples/alteriomImproved/platformio.ini +25 -0
  48. package/examples/alteriomPhase1/alteriom_sensor_package.hpp +224 -0
  49. package/examples/alteriomPhase1/phase1_features.ino +242 -0
  50. package/examples/alteriomPhase1/platformio.ini +25 -0
  51. package/examples/alteriomPhase2/alteriom_sensor_package.hpp +224 -0
  52. package/examples/alteriomPhase2/phase2_features.ino +186 -0
  53. package/examples/alteriomPhase2/platformio.ini +25 -0
  54. package/examples/{alteriom → alteriomSensorNode}/alteriom_sensor_node.ino +183 -183
  55. package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +224 -0
  56. package/examples/alteriomSensorNode/platformio.ini +25 -0
  57. package/examples/basic/basic.ino +66 -66
  58. package/examples/basic/platformio.ini +25 -25
  59. package/examples/bridge/bridge.ino +51 -51
  60. package/examples/bridge/mesh_event_publisher.hpp +253 -0
  61. package/examples/bridge/mesh_topology_reporter.hpp +303 -0
  62. package/examples/bridge/mqtt_command_bridge.hpp +459 -0
  63. package/examples/bridge/mqtt_status_bridge.hpp +519 -0
  64. package/examples/bridge/platformio.ini +25 -25
  65. package/examples/echoNode/echoNode.ino +33 -33
  66. package/examples/echoNode/platformio.ini +25 -25
  67. package/examples/logClient/logClient.ino +109 -109
  68. package/examples/logClient/platformio.ini +25 -25
  69. package/examples/logServer/logServer.ino +81 -81
  70. package/examples/logServer/platformio.ini +25 -25
  71. package/examples/meshCommandNode/alteriom_sensor_package.hpp +235 -0
  72. package/examples/meshCommandNode/meshCommandNode.ino +263 -0
  73. package/examples/meshCommandNode/platformio.ini +25 -0
  74. package/examples/mqttBridge/mqttBridge.ino +118 -118
  75. package/examples/mqttBridge/platformio.ini +26 -26
  76. package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +235 -0
  77. package/examples/mqttCommandBridge/mesh_event_publisher.hpp +253 -0
  78. package/examples/mqttCommandBridge/mesh_topology_reporter.hpp +303 -0
  79. package/examples/mqttCommandBridge/mqttCommandBridge.ino +252 -0
  80. package/examples/mqttCommandBridge/mqtt_command_bridge.hpp +459 -0
  81. package/examples/mqttCommandBridge/platformio.ini +26 -0
  82. package/examples/mqttStatusBridge/mqttStatusBridge.ino +216 -0
  83. package/examples/mqttStatusBridge/mqtt_status_bridge.hpp +522 -0
  84. package/examples/mqttStatusBridge/platformio.ini +26 -0
  85. package/examples/mqttTopologyTest/README.md +467 -0
  86. package/examples/mqttTopologyTest/mqttTopologyTest.ino +748 -0
  87. package/examples/mqttTopologyTest/platformio.ini +26 -0
  88. package/examples/namedMesh/namedMesh.ino +97 -97
  89. package/examples/namedMesh/platformio.ini +25 -25
  90. package/examples/otaReceiver/otaReceiver.ino +79 -79
  91. package/examples/otaReceiver/platformio.ini +25 -25
  92. package/examples/otaSender/otaSender.ino +160 -151
  93. package/examples/otaSender/platformio.ini +25 -25
  94. package/examples/startHere/platformio.ini +25 -25
  95. package/examples/startHere/startHere.ino +159 -159
  96. package/examples/webServer/platformio.ini +27 -27
  97. package/examples/webServer/webServer.ino +89 -89
  98. package/keywords.txt +48 -48
  99. package/library.json +55 -34
  100. package/library.properties +10 -10
  101. package/package.json +86 -78
  102. package/src/AlteriomPainlessMesh.h +97 -97
  103. package/src/arduino/wifi.hpp +365 -365
  104. package/src/boost/asynctcp.hpp +279 -279
  105. package/src/painlessMesh.h +70 -70
  106. package/src/painlessMeshSTA.cpp +236 -236
  107. package/src/painlessMeshSTA.h +58 -58
  108. package/src/painlessTaskOptions.h +4 -4
  109. package/src/painlessmesh/base64.hpp +111 -111
  110. package/src/painlessmesh/buffer.hpp +229 -229
  111. package/src/painlessmesh/callback.hpp +91 -91
  112. package/src/painlessmesh/configuration.hpp +77 -77
  113. package/src/painlessmesh/connection.hpp +192 -192
  114. package/src/painlessmesh/layout.hpp +188 -188
  115. package/src/painlessmesh/logger.hpp +158 -158
  116. package/src/painlessmesh/memory.hpp +119 -119
  117. package/src/painlessmesh/mesh.hpp +761 -560
  118. package/src/painlessmesh/metrics.hpp +322 -322
  119. package/src/painlessmesh/ntp.hpp +263 -263
  120. package/src/painlessmesh/ota.hpp +582 -553
  121. package/src/painlessmesh/plugin.hpp +188 -188
  122. package/src/painlessmesh/protocol.hpp +813 -813
  123. package/src/painlessmesh/router.hpp +322 -322
  124. package/src/painlessmesh/tcp.hpp +71 -71
  125. package/src/painlessmesh/validation.hpp +238 -238
  126. package/src/plugin/performance.hpp +214 -214
  127. package/src/plugin/remote.hpp +64 -64
  128. package/src/scheduler.cpp +10 -10
  129. package/src/wifi.cpp +2 -2
@@ -0,0 +1,235 @@
1
+ #ifndef ALTERIOM_SENSOR_PACKAGE_HPP
2
+ #define ALTERIOM_SENSOR_PACKAGE_HPP
3
+
4
+ #include "painlessmesh/plugin.hpp"
5
+
6
+ namespace alteriom {
7
+
8
+ /**
9
+ * @brief Sensor data package for broadcasting environmental measurements
10
+ *
11
+ * This package is designed for Alteriom's IoT sensor network requirements,
12
+ * allowing nodes to share environmental data across the mesh.
13
+ */
14
+ class SensorPackage : public painlessmesh::plugin::BroadcastPackage {
15
+ public:
16
+ double temperature = 0.0; // Temperature in Celsius
17
+ double humidity = 0.0; // Relative humidity percentage
18
+ double pressure = 0.0; // Atmospheric pressure in hPa
19
+ uint32_t sensorId = 0; // Unique sensor identifier
20
+ uint32_t timestamp = 0; // Unix timestamp of measurement
21
+ uint8_t batteryLevel = 0; // Battery level percentage
22
+
23
+ SensorPackage()
24
+ : BroadcastPackage(200) {} // Type ID 200 for Alteriom sensors
25
+
26
+ SensorPackage(JsonObject jsonObj) : BroadcastPackage(jsonObj) {
27
+ temperature = jsonObj["temp"];
28
+ humidity = jsonObj["hum"];
29
+ pressure = jsonObj["press"];
30
+ sensorId = jsonObj["sid"];
31
+ timestamp = jsonObj["ts"];
32
+ batteryLevel = jsonObj["bat"];
33
+ }
34
+
35
+ JsonObject addTo(JsonObject&& jsonObj) const {
36
+ jsonObj = BroadcastPackage::addTo(std::move(jsonObj));
37
+ jsonObj["temp"] = temperature;
38
+ jsonObj["hum"] = humidity;
39
+ jsonObj["press"] = pressure;
40
+ jsonObj["sid"] = sensorId;
41
+ jsonObj["ts"] = timestamp;
42
+ jsonObj["bat"] = batteryLevel;
43
+ return jsonObj;
44
+ }
45
+
46
+ #if ARDUINOJSON_VERSION_MAJOR < 7
47
+ size_t jsonObjectSize() const { return JSON_OBJECT_SIZE(noJsonFields + 6); }
48
+ #endif
49
+ };
50
+
51
+ /**
52
+ * @brief Command package for controlling Alteriom devices
53
+ *
54
+ * Single-destination package for sending specific commands to individual nodes.
55
+ */
56
+ class CommandPackage : public painlessmesh::plugin::SinglePackage {
57
+ public:
58
+ uint8_t command = 0; // Command type
59
+ uint32_t targetDevice = 0; // Target device ID
60
+ TSTRING parameters = ""; // Command parameters as JSON string
61
+ uint32_t commandId = 0; // Unique command identifier for tracking
62
+
63
+ CommandPackage() : SinglePackage(201) {} // Type ID 201 for Alteriom commands
64
+
65
+ CommandPackage(JsonObject jsonObj) : SinglePackage(jsonObj) {
66
+ command = jsonObj["cmd"];
67
+ targetDevice = jsonObj["target"];
68
+ parameters = jsonObj["params"].as<TSTRING>();
69
+ commandId = jsonObj["cid"];
70
+ }
71
+
72
+ JsonObject addTo(JsonObject&& jsonObj) const {
73
+ jsonObj = SinglePackage::addTo(std::move(jsonObj));
74
+ jsonObj["cmd"] = command;
75
+ jsonObj["target"] = targetDevice;
76
+ jsonObj["params"] = parameters;
77
+ jsonObj["cid"] = commandId;
78
+ return jsonObj;
79
+ }
80
+
81
+ #if ARDUINOJSON_VERSION_MAJOR < 7
82
+ size_t jsonObjectSize() const {
83
+ return JSON_OBJECT_SIZE(noJsonFields + 4) + parameters.length();
84
+ }
85
+ #endif
86
+ };
87
+
88
+ /**
89
+ * @brief Status report package for device health monitoring
90
+ */
91
+ class StatusPackage : public painlessmesh::plugin::BroadcastPackage {
92
+ public:
93
+ uint8_t deviceStatus = 0; // Device status flags
94
+ uint32_t uptime = 0; // Device uptime in seconds
95
+ uint16_t freeMemory = 0; // Free memory in KB
96
+ uint8_t wifiStrength = 0; // WiFi signal strength
97
+ TSTRING firmwareVersion = ""; // Current firmware version
98
+
99
+ // Command response fields (for MQTT bridge)
100
+ uint32_t responseToCommand = 0; // CommandId this is responding to
101
+ TSTRING responseMessage = ""; // Success/error message
102
+
103
+ StatusPackage() : BroadcastPackage(202) {} // Type ID 202 for Alteriom status
104
+
105
+ StatusPackage(JsonObject jsonObj) : BroadcastPackage(jsonObj) {
106
+ deviceStatus = jsonObj["status"];
107
+ uptime = jsonObj["uptime"];
108
+ freeMemory = jsonObj["mem"];
109
+ wifiStrength = jsonObj["wifi"];
110
+ firmwareVersion = jsonObj["fw"].as<TSTRING>();
111
+ responseToCommand = jsonObj["respTo"] | 0;
112
+ responseMessage = jsonObj["respMsg"].as<TSTRING>();
113
+ }
114
+
115
+ JsonObject addTo(JsonObject&& jsonObj) const {
116
+ jsonObj = BroadcastPackage::addTo(std::move(jsonObj));
117
+ jsonObj["status"] = deviceStatus;
118
+ jsonObj["uptime"] = uptime;
119
+ jsonObj["mem"] = freeMemory;
120
+ jsonObj["wifi"] = wifiStrength;
121
+ jsonObj["fw"] = firmwareVersion;
122
+ if (responseToCommand > 0) {
123
+ jsonObj["respTo"] = responseToCommand;
124
+ jsonObj["respMsg"] = responseMessage;
125
+ }
126
+ return jsonObj;
127
+ }
128
+
129
+ #if ARDUINOJSON_VERSION_MAJOR < 7
130
+ size_t jsonObjectSize() const {
131
+ return JSON_OBJECT_SIZE(noJsonFields + 7) + firmwareVersion.length() +
132
+ responseMessage.length();
133
+ }
134
+ #endif
135
+ };
136
+
137
+ /**
138
+ * @brief Enhanced status package with comprehensive health metrics (Phase 1)
139
+ *
140
+ * This is an extended version of StatusPackage that includes additional
141
+ * mesh statistics, performance metrics, and alerting capabilities.
142
+ * Type ID 203 is used to distinguish from the basic StatusPackage (202).
143
+ */
144
+ class EnhancedStatusPackage : public painlessmesh::plugin::BroadcastPackage {
145
+ public:
146
+ // Device Health (from original StatusPackage)
147
+ uint8_t deviceStatus = 0; // Device status flags
148
+ uint32_t uptime = 0; // Device uptime in seconds
149
+ uint16_t freeMemory = 0; // Free memory in KB
150
+ uint8_t wifiStrength = 0; // WiFi signal strength
151
+ TSTRING firmwareVersion = ""; // Current firmware version
152
+ TSTRING firmwareMD5 = ""; // Firmware hash for OTA verification
153
+
154
+ // Mesh Statistics
155
+ uint16_t nodeCount = 0; // Number of known nodes in mesh
156
+ uint8_t connectionCount = 0; // Number of direct connections
157
+ uint32_t messagesReceived = 0; // Total messages received
158
+ uint32_t messagesSent = 0; // Total messages sent
159
+ uint32_t messagesDropped = 0; // Total messages dropped/failed
160
+
161
+ // Performance Metrics
162
+ uint16_t avgLatency = 0; // Average message latency in ms
163
+ uint8_t packetLossRate = 0; // Packet loss rate percentage (0-100)
164
+ uint16_t throughput = 0; // Network throughput in bytes/sec
165
+
166
+ // Warnings/Alerts
167
+ uint8_t alertFlags = 0; // Bit flags for various alert conditions
168
+ TSTRING lastError = ""; // Last error message for diagnostics
169
+
170
+ EnhancedStatusPackage()
171
+ : BroadcastPackage(203) {} // Type ID 203 for enhanced status
172
+
173
+ EnhancedStatusPackage(JsonObject jsonObj) : BroadcastPackage(jsonObj) {
174
+ deviceStatus = jsonObj["status"];
175
+ uptime = jsonObj["uptime"];
176
+ freeMemory = jsonObj["mem"];
177
+ wifiStrength = jsonObj["wifi"];
178
+ firmwareVersion = jsonObj["fw"].as<TSTRING>();
179
+ firmwareMD5 = jsonObj["fwMD5"].as<TSTRING>();
180
+
181
+ nodeCount = jsonObj["nodes"];
182
+ connectionCount = jsonObj["conns"];
183
+ messagesReceived = jsonObj["msgRx"];
184
+ messagesSent = jsonObj["msgTx"];
185
+ messagesDropped = jsonObj["msgDrop"];
186
+
187
+ avgLatency = jsonObj["latency"];
188
+ packetLossRate = jsonObj["loss"];
189
+ throughput = jsonObj["throughput"];
190
+
191
+ alertFlags = jsonObj["alerts"];
192
+ lastError = jsonObj["lastErr"].as<TSTRING>();
193
+ }
194
+
195
+ JsonObject addTo(JsonObject&& jsonObj) const {
196
+ jsonObj = BroadcastPackage::addTo(std::move(jsonObj));
197
+
198
+ // Device Health
199
+ jsonObj["status"] = deviceStatus;
200
+ jsonObj["uptime"] = uptime;
201
+ jsonObj["mem"] = freeMemory;
202
+ jsonObj["wifi"] = wifiStrength;
203
+ jsonObj["fw"] = firmwareVersion;
204
+ jsonObj["fwMD5"] = firmwareMD5;
205
+
206
+ // Mesh Statistics
207
+ jsonObj["nodes"] = nodeCount;
208
+ jsonObj["conns"] = connectionCount;
209
+ jsonObj["msgRx"] = messagesReceived;
210
+ jsonObj["msgTx"] = messagesSent;
211
+ jsonObj["msgDrop"] = messagesDropped;
212
+
213
+ // Performance Metrics
214
+ jsonObj["latency"] = avgLatency;
215
+ jsonObj["loss"] = packetLossRate;
216
+ jsonObj["throughput"] = throughput;
217
+
218
+ // Alerts
219
+ jsonObj["alerts"] = alertFlags;
220
+ jsonObj["lastErr"] = lastError;
221
+
222
+ return jsonObj;
223
+ }
224
+
225
+ #if ARDUINOJSON_VERSION_MAJOR < 7
226
+ size_t jsonObjectSize() const {
227
+ return JSON_OBJECT_SIZE(noJsonFields + 18) + firmwareVersion.length() +
228
+ firmwareMD5.length() + lastError.length();
229
+ }
230
+ #endif
231
+ };
232
+
233
+ } // namespace alteriom
234
+
235
+ #endif // ALTERIOM_SENSOR_PACKAGE_HPP
@@ -0,0 +1,263 @@
1
+ #include "painlessMesh.h"
2
+ #include "alteriom_sensor_package.hpp"
3
+
4
+ // Define LED_BUILTIN for ESP32 boards that don't have it predefined
5
+ #ifndef LED_BUILTIN
6
+ #define LED_BUILTIN 2
7
+ #endif
8
+
9
+ #define MESH_PREFIX "AlteriomMesh"
10
+ #define MESH_PASSWORD "somethingSneaky"
11
+ #define MESH_PORT 5555
12
+
13
+ using namespace alteriom;
14
+
15
+ Scheduler userScheduler;
16
+ painlessMesh mesh;
17
+
18
+ // Command handlers
19
+ void handleCommand(const CommandPackage& cmd);
20
+ void sendStatusResponse(uint32_t commandId, String message, uint8_t status = 0);
21
+ void sendConfiguration();
22
+ void sendStatus();
23
+
24
+ // Command definitions (matching mqtt_command_bridge.hpp)
25
+ enum Commands {
26
+ RESET = 1,
27
+ SLEEP = 2,
28
+ WAKE = 3,
29
+ LED_CONTROL = 10,
30
+ RELAY_SWITCH = 11,
31
+ PWM_SET = 12,
32
+ GET_CONFIG = 100,
33
+ SET_CONFIG = 101,
34
+ GET_STATUS = 200,
35
+ GET_METRICS = 201
36
+ };
37
+
38
+ void setup() {
39
+ Serial.begin(115200);
40
+
41
+ pinMode(LED_BUILTIN, OUTPUT);
42
+
43
+ mesh.setDebugMsgTypes(ERROR | STARTUP | CONNECTION);
44
+ mesh.init(MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT);
45
+
46
+ mesh.onReceive([](uint32_t from, String& msg) {
47
+ Serial.printf("Received from %u\n", from);
48
+
49
+ // Parse message
50
+ JsonDocument doc;
51
+ DeserializationError error = deserializeJson(doc, msg);
52
+
53
+ if (error) {
54
+ Serial.printf("JSON parse error: %s\n", error.c_str());
55
+ return;
56
+ }
57
+
58
+ uint8_t msgType = doc["type"];
59
+
60
+ if (msgType == 201) {
61
+ // CommandPackage
62
+ JsonObject obj = doc.as<JsonObject>();
63
+ CommandPackage cmd(obj);
64
+
65
+ // Check if command is for this node
66
+ if (cmd.targetDevice == 0 || cmd.targetDevice == mesh.getNodeId()) {
67
+ handleCommand(cmd);
68
+ }
69
+ }
70
+ });
71
+
72
+ mesh.onNewConnection([](uint32_t nodeId) {
73
+ Serial.printf("New connection: %u\n", nodeId);
74
+ });
75
+
76
+ mesh.onChangedConnections([]() {
77
+ Serial.printf("Connections changed - nodes: %d\n", mesh.getNodeList().size());
78
+ });
79
+
80
+ Serial.printf("Mesh node initialized: %u\n", mesh.getNodeId());
81
+ Serial.println("Ready to receive commands");
82
+ }
83
+
84
+ void loop() {
85
+ mesh.update();
86
+ }
87
+
88
+ /**
89
+ * @brief Handle incoming command
90
+ */
91
+ void handleCommand(const CommandPackage& cmd) {
92
+ Serial.printf("Command received: cmd=%d, id=%u\n", cmd.command, cmd.commandId);
93
+
94
+ switch(cmd.command) {
95
+ case RESET:
96
+ sendStatusResponse(cmd.commandId, "Rebooting...");
97
+ delay(1000);
98
+ ESP.restart();
99
+ break;
100
+
101
+ case SLEEP: {
102
+ JsonDocument params;
103
+ deserializeJson(params, cmd.parameters);
104
+ uint32_t duration = params["duration_ms"];
105
+
106
+ sendStatusResponse(cmd.commandId, "Entering sleep for " + String(duration) + "ms");
107
+ delay(100);
108
+
109
+ ESP.deepSleep(duration * 1000);
110
+ break;
111
+ }
112
+
113
+ case LED_CONTROL: {
114
+ JsonDocument params;
115
+ deserializeJson(params, cmd.parameters);
116
+
117
+ bool state = params["state"];
118
+ uint8_t brightness = params["brightness"] | 255;
119
+
120
+ digitalWrite(LED_BUILTIN, state ? LOW : HIGH);
121
+
122
+ String msg = "LED " + String(state ? "ON" : "OFF");
123
+ if (brightness < 255) {
124
+ msg += " (brightness: " + String(brightness) + ")";
125
+ }
126
+
127
+ sendStatusResponse(cmd.commandId, msg);
128
+ Serial.println(msg);
129
+ break;
130
+ }
131
+
132
+ case RELAY_SWITCH: {
133
+ JsonDocument params;
134
+ deserializeJson(params, cmd.parameters);
135
+
136
+ uint8_t channel = params["channel"];
137
+ bool state = params["state"];
138
+
139
+ // Control relay (GPIO configuration needed)
140
+ String msg = "Relay " + String(channel) + " " + String(state ? "ON" : "OFF");
141
+ sendStatusResponse(cmd.commandId, msg);
142
+ Serial.println(msg);
143
+ break;
144
+ }
145
+
146
+ case PWM_SET: {
147
+ JsonDocument params;
148
+ deserializeJson(params, cmd.parameters);
149
+
150
+ uint8_t pin = params["pin"];
151
+ uint16_t duty = params["duty"];
152
+
153
+ // Set PWM (example - adjust for your hardware)
154
+ String msg = "PWM pin " + String(pin) + " set to " + String(duty);
155
+ sendStatusResponse(cmd.commandId, msg);
156
+ Serial.println(msg);
157
+ break;
158
+ }
159
+
160
+ case GET_CONFIG:
161
+ sendConfiguration();
162
+ break;
163
+
164
+ case GET_STATUS:
165
+ sendStatus();
166
+ break;
167
+
168
+ case GET_METRICS: {
169
+ // Send enhanced status
170
+ EnhancedStatusPackage metrics;
171
+ metrics.from = mesh.getNodeId();
172
+ metrics.deviceStatus = 0;
173
+ metrics.uptime = millis() / 1000;
174
+ metrics.freeMemory = ESP.getFreeHeap() / 1024;
175
+ metrics.wifiStrength = WiFi.RSSI();
176
+ metrics.firmwareVersion = "1.0.0";
177
+
178
+ auto nodeList = mesh.getNodeList();
179
+ metrics.nodeCount = nodeList.size();
180
+ metrics.connectionCount = nodeList.size();
181
+
182
+ auto variant = painlessmesh::protocol::Variant(&metrics);
183
+ String msg;
184
+ variant.printTo(msg);
185
+
186
+ mesh.sendBroadcast(msg);
187
+ Serial.println("Metrics sent");
188
+ break;
189
+ }
190
+
191
+ case SET_CONFIG: {
192
+ JsonDocument params;
193
+ deserializeJson(params, cmd.parameters);
194
+
195
+ JsonObject config = params.as<JsonObject>();
196
+
197
+ if (config["deviceName"].is<String>()) {
198
+ String name = config["deviceName"];
199
+ Serial.printf("Config: deviceName=%s\n", name.c_str());
200
+ }
201
+
202
+ if (config["sampleRate"].is<uint32_t>()) {
203
+ uint32_t rate = config["sampleRate"];
204
+ Serial.printf("Config: sampleRate=%u\n", rate);
205
+ }
206
+
207
+ sendStatusResponse(cmd.commandId, "Configuration updated");
208
+ break;
209
+ }
210
+
211
+ default:
212
+ sendStatusResponse(cmd.commandId, "Unknown command: " + String(cmd.command), 2);
213
+ Serial.printf("Unknown command: %d\n", cmd.command);
214
+ }
215
+ }
216
+
217
+ /**
218
+ * @brief Send status response
219
+ */
220
+ void sendStatusResponse(uint32_t commandId, String message, uint8_t status) {
221
+ StatusPackage response;
222
+ response.from = mesh.getNodeId();
223
+ response.deviceStatus = status;
224
+ response.uptime = millis() / 1000;
225
+ response.freeMemory = ESP.getFreeHeap() / 1024;
226
+ response.wifiStrength = WiFi.RSSI();
227
+ response.firmwareVersion = "1.0.0";
228
+ response.responseToCommand = commandId;
229
+ response.responseMessage = message;
230
+
231
+ auto variant = painlessmesh::protocol::Variant(&response);
232
+ String msg;
233
+ variant.printTo(msg);
234
+
235
+ mesh.sendBroadcast(msg);
236
+ Serial.printf("Response sent: %s\n", message.c_str());
237
+ }
238
+
239
+ /**
240
+ * @brief Send configuration
241
+ */
242
+ void sendConfiguration() {
243
+ JsonDocument config;
244
+ config["deviceName"] = "Sensor-" + String(mesh.getNodeId());
245
+ config["firmwareVersion"] = "1.0.0";
246
+ config["role"] = "sensor";
247
+ config["sampleRate"] = 60000;
248
+ config["ledEnabled"] = true;
249
+
250
+ String configStr;
251
+ serializeJson(config, configStr);
252
+
253
+ sendStatusResponse(0, configStr);
254
+ Serial.println("Configuration sent");
255
+ }
256
+
257
+ /**
258
+ * @brief Send basic status
259
+ */
260
+ void sendStatus() {
261
+ sendStatusResponse(0, "OK");
262
+ Serial.println("Status sent");
263
+ }
@@ -0,0 +1,25 @@
1
+ [platformio]
2
+ src_dir = .
3
+
4
+ [env]
5
+ lib_deps =
6
+ bblanchon/ArduinoJson
7
+ arkhipenko/TaskScheduler
8
+
9
+ [env:esp8266]
10
+ platform = espressif8266
11
+ board = nodemcuv2
12
+ framework = arduino
13
+ lib_extra_dirs = ../../
14
+ lib_deps =
15
+ ${env.lib_deps}
16
+ me-no-dev/ESPAsyncTCP
17
+
18
+ [env:esp32]
19
+ platform = espressif32
20
+ board = esp32dev
21
+ framework = arduino
22
+ lib_extra_dirs = ../../
23
+ lib_deps =
24
+ ${env.lib_deps}
25
+ mathieucarbou/AsyncTCP