FastLED 3.9.15
Loading...
Searching...
No Matches
RpcClient.ino
Go to the documentation of this file.
1// @filter: (platform is native)
2
19
20#include <FastLED.h>
21#include "fl/remote/remote.h"
23#include "fl/stl/unique_ptr.h"
31
32// Client configuration
33#define SERVER_HOST "localhost"
34#define SERVER_PORT 8080
35
36// LED configuration for visual feedback
37#define NUM_LEDS 10
38#define DATA_PIN 3
40
41// HTTP streaming client
44
45// Request ID counter
46int requestId = 1;
47
48// Timing
49uint32_t lastCallTime = 0;
50const uint32_t CALL_INTERVAL = 5000; // Call method every 5 seconds
51
52// Current test mode
54 TEST_SYNC, // Test SYNC mode (add)
55 TEST_ASYNC, // Test ASYNC mode (longTask)
56 TEST_ASYNC_STREAM // Test ASYNC_STREAM mode (streamData)
57};
59
60// Response tracking
61bool waitingForResponse = false;
63
64void setup() {
65 Serial.begin(115200);
66 while (!Serial && millis() < 3000) {
67 // Wait for serial or timeout
68 }
69
70 Serial.println("\n=== HTTP RPC Client Example ===\n");
71 Serial.println("This example connects to an HTTP RPC server");
72 Serial.println("and calls remote methods using all three RPC modes:");
73 Serial.println(" - SYNC: Immediate response");
74 Serial.println(" - ASYNC: ACK + later result");
75 Serial.println(" - ASYNC_STREAM: ACK + updates + final");
76 Serial.println();
77 fl::printf("Connecting to server at %s:%d...\n", SERVER_HOST, SERVER_PORT);
78
79 // Initialize LEDs
80 FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
81 FastLED.setBrightness(50);
83 FastLED.show();
84
85 // Create HTTP streaming client transport
87
88 // Configure heartbeat and timeout
89 transport->setHeartbeatInterval(30000); // 30 seconds
90 transport->setTimeout(60000); // 60 seconds
91
92 // Set connection state callbacks
93 transport->setOnConnect([]() {
94 Serial.println("[CALLBACK] Connected to server!");
95 // Visual feedback: turn first LED green
96 leds[0] = CRGB::Green;
97 FastLED.show();
98 });
99
100 transport->setOnDisconnect([]() {
101 Serial.println("[CALLBACK] Disconnected from server!");
102 // Visual feedback: turn first LED red
103 leds[0] = CRGB::Red;
104 FastLED.show();
105 waitingForResponse = false;
106 });
107
108 // Create Remote with transport callbacks
110 []() { return transport->readRequest(); },
111 [](const fl::json& response) { transport->writeResponse(response); }
112 );
113
114 // Connect to server
115 if (!transport->connect()) {
116 Serial.println("ERROR: Failed to connect to server!");
117 Serial.println("Make sure RpcServer example is running.");
118 leds[0] = CRGB::Red;
119 FastLED.show();
120 return;
121 }
122
123 Serial.println("Connected successfully!");
124 Serial.println();
125}
126
128 Serial.println("=== Testing SYNC mode: add(2, 3) ===");
129
130 // Create JSON-RPC request manually (client doesn't have Remote::call() yet)
131 fl::json request;
132 request["jsonrpc"] = "2.0";
133 request["method"] = "add";
134 fl::json params;
135 params.push_back(2);
136 params.push_back(3);
137 request["params"] = params;
138 request["id"] = requestId;
139
141 waitingForResponse = true;
142
143 // Send request via transport
144 transport->writeResponse(request); // writeResponse sends JSON to server
145
146 fl::printf("Sent request ID %d: add(2, 3)\n", expectedRequestId);
147 Serial.println("Waiting for response...");
148}
149
151 Serial.println("=== Testing ASYNC mode: longTask(2000) ===");
152
153 // Create JSON-RPC request
154 fl::json request;
155 request["jsonrpc"] = "2.0";
156 request["method"] = "longTask";
157 fl::json params;
158 params.push_back(2000); // 2 second task
159 request["params"] = params;
160 request["id"] = requestId;
161
163 waitingForResponse = true;
164
165 transport->writeResponse(request);
166
167 fl::printf("Sent request ID %d: longTask(2000)\n", expectedRequestId);
168 Serial.println("Expecting ACK immediately, then result after 2 seconds...");
169}
170
172 Serial.println("=== Testing ASYNC_STREAM mode: streamData(5) ===");
173
174 // Create JSON-RPC request
175 fl::json request;
176 request["jsonrpc"] = "2.0";
177 request["method"] = "streamData";
178 fl::json params;
179 params.push_back(5); // Request 5 updates
180 request["params"] = params;
181 request["id"] = requestId;
182
184 waitingForResponse = true;
185
186 transport->writeResponse(request);
187
188 fl::printf("Sent request ID %d: streamData(5)\n", expectedRequestId);
189 Serial.println("Expecting ACK, then 5 updates, then final result...");
190}
191
192void handleResponse(const fl::json& response) {
193 // Check if this is our expected response
194 if (response.contains("id")) {
195 const fl::json& idJson = response["id"];
196 if (idJson.is_number()) {
197 auto idOpt = idJson.as_int();
198 if (idOpt) {
199 int id = *idOpt;
200 if (id != expectedRequestId) {
201 fl::printf("Warning: Received response for ID %d, expected %d\n", id, expectedRequestId);
202 }
203 }
204 }
205 }
206
207 // Check for error
208 if (response.contains("error")) {
209 Serial.println("ERROR Response:");
210 Serial.println(response.to_string().c_str());
211 waitingForResponse = false;
212 return;
213 }
214
215 // Check for ACK (ASYNC/ASYNC_STREAM modes)
216 if (response.contains("result")) {
217 const fl::json& result = response["result"];
218
219 if (result.contains("ack")) {
220 auto ackOpt = result["ack"].as_bool();
221 if (ackOpt && *ackOpt == true) {
222 Serial.println("Received ACK - request accepted");
223 return; // Wait for actual result
224 }
225 }
226
227 // Check for streaming update (ASYNC_STREAM mode)
228 if (result.contains("update")) {
229 auto updateOpt = result["update"].as_int();
230 if (updateOpt) {
231 int update = *updateOpt;
232 fl::printf("Received update: %d\n", update);
233
234 // Visual feedback: show progress on LEDs
235 int ledIndex = (update % NUM_LEDS);
236 leds[ledIndex] = CRGB::Blue;
237 FastLED.show();
238 }
239 return; // Wait for more updates or final
240 }
241
242 // Check for final result (ASYNC_STREAM mode)
243 if (result.contains("stop")) {
244 auto stopOpt = result["stop"].as_bool();
245 if (stopOpt && *stopOpt == true) {
246 if (result.contains("value")) {
247 Serial.print("Received FINAL result: ");
248 Serial.println(result["value"].to_string().c_str());
249 } else {
250 Serial.println("Received FINAL marker (no value)");
251 }
252 waitingForResponse = false;
253 return;
254 }
255 }
256
257 // Regular result (SYNC or ASYNC final)
258 Serial.print("Received result: ");
259 Serial.println(result.to_string().c_str());
260 waitingForResponse = false;
261 } else {
262 Serial.println("Received response without result:");
263 Serial.println(response.to_string().c_str());
264 }
265}
266
267void loop() {
268 uint32_t now = millis();
269
270 // Update transport (handles heartbeat, reconnection, etc.)
271 transport->update(now);
272
273 // Update remote (processes incoming responses)
274 remote->update(now);
275
276 // Process any responses
277 fl::optional<fl::json> response = transport->readRequest();
278 if (response) {
279 handleResponse(*response);
280 }
281
282 // Send requests periodically (only when not waiting for response)
283 if (!waitingForResponse && (now - lastCallTime >= CALL_INTERVAL)) {
284 lastCallTime = now;
285
286 // Cycle through test modes
287 switch (currentMode) {
288 case TEST_SYNC:
290 currentMode = TEST_ASYNC; // Next mode
291 break;
292
293 case TEST_ASYNC:
295 currentMode = TEST_ASYNC_STREAM; // Next mode
296 break;
297
300 currentMode = TEST_SYNC; // Cycle back to start
301 Serial.println("\n--- Cycle complete, starting over ---\n");
302 break;
303 }
304 }
305
306 // Small delay to prevent busy-waiting
307 delay(10);
308}
309
310// Example curl commands to test manually:
311//
312// 1. SYNC mode (add):
313// curl -X POST http://localhost:8080/rpc \
314// -H "Content-Type: application/json" \
315// -H "Transfer-Encoding: chunked" \
316// -d '{"jsonrpc":"2.0","method":"add","params":[2,3],"id":1}'
317//
318// 2. ASYNC mode (longTask):
319// curl -X POST http://localhost:8080/rpc \
320// -H "Content-Type: application/json" \
321// -H "Transfer-Encoding: chunked" \
322// -d '{"jsonrpc":"2.0","method":"longTask","params":[2000],"id":2}'
323//
324// 3. ASYNC_STREAM mode (streamData):
325// curl -X POST http://localhost:8080/rpc \
326// -H "Content-Type: application/json" \
327// -H "Transfer-Encoding: chunked" \
328// -d '{"jsonrpc":"2.0","method":"streamData","params":[5],"id":3}'
#define NUM_LEDS
fl::CRGB leds[NUM_LEDS]
#define DATA_PIN
Definition ClientReal.h:82
#define SERVER_PORT
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
@ TEST_ASYNC_STREAM
@ TEST_ASYNC
@ TEST_SYNC
int requestId
TestMode currentMode
bool waitingForResponse
int expectedRequestId
Definition RpcClient.ino:62
fl::unique_ptr< fl::Remote > remote
Definition RpcClient.ino:43
uint32_t lastCallTime
Definition RpcClient.ino:49
void handleResponse(const fl::json &response)
fl::unique_ptr< fl::net::http::HttpStreamClient > transport
Definition RpcClient.ino:42
void setup()
Definition RpcClient.ino:64
void sendAsyncRequest()
#define SERVER_HOST
Definition RpcClient.ino:33
void sendSyncRequest()
const uint32_t CALL_INTERVAL
Definition RpcClient.ino:50
void sendAsyncStreamRequest()
void loop()
void push_back(const json &value) FL_NOEXCEPT
Definition json.h:745
fl::optional< i64 > as_int() const FL_NOEXCEPT
Definition json.h:255
bool is_number() const FL_NOEXCEPT
Definition json.h:244
void fill_solid(CRGB *targetArray, int numToFill, const CRGB &color) FL_NOEXCEPT
Fill a range of LEDs with a solid color.
Definition fill.cpp.hpp:9
constexpr EOrder GRB
Definition eorder.h:19
fl::CRGB CRGB
Definition crgb.h:25
void printf(const char *format, const Args &... args) FL_NOEXCEPT
Printf-like formatting function that prints directly to the platform output.
Definition stdio.h:635
fl::enable_if<!fl::is_array< T >::value, unique_ptr< T > >::type make_unique(Args &&... args) FL_NOEXCEPT
Definition unique_ptr.h:261
Optional< T > optional
Definition optional.h:16
@ Green
<div style='background:#008000;width:4em;height:4em;'></div>
Definition crgb.h:558
@ Red
<div style='background:#FF0000;width:4em;height:4em;'></div>
Definition crgb.h:622
@ Blue
<div style='background:#0000FF;width:4em;height:4em;'></div>
Definition crgb.h:512
@ Black
<div style='background:#000000;width:4em;height:4em;'></div>
Definition crgb.h:510
#define Serial
Definition serial.h:304