FastLED 3.9.15
Loading...
Searching...
No Matches
NetTestReal.h
Go to the documentation of this file.
1
72
73#include "fl/fetch.h" // FastLED HTTP fetch API
74#include "fl/warn.h" // FastLED logging system
75#include "fl/async.h" // FastLED async utilities (await_top_level, etc.)
76#include <FastLED.h> // FastLED core library
77
78using namespace fl; // Use FastLED namespace for cleaner code
79
80// LED CONFIGURATION
81#define NUM_LEDS 10 // Number of LEDs in our strip
82#define DATA_PIN 2 // Arduino pin connected to LED data line
83
85
86// Timing and approach control variables for tutorial cycling
87static u32 last_request_time = 0; // Track last request time for 10-second intervals
88static int approach_counter = 0; // Cycle through 4 different approaches
89
90void setup() {
91 // Initialize LED strip
93
94 // Set all LEDs to dark red initially (indicates waiting/starting state)
95 fill_solid(leds, NUM_LEDS, CRGB(64, 0, 0)); // Dark red = starting up
96 FastLED.show();
97
98 // Tutorial introduction messages
99 FL_WARN("FastLED Networking Tutorial started - 10 LEDs set to dark red");
100 FL_WARN("Learning HTTP fetch API with TWO different async patterns:");
101 FL_WARN(" APPROACH 1: Promise-based (.then/.catch_) with explicit types");
102 FL_WARN(" APPROACH 2: fl::await_top_level pattern with explicit types");
103 FL_WARN("Toggles between approaches every 10 seconds for comparison...");
104 FL_WARN("LED colors indicate status: Red=Error, Green=Promise Success, Blue=Await Success");
105}
106
107// APPROACH 1: Promise-based async pattern (JavaScript-like)
108// This approach uses method chaining and callbacks - very common in web development
110 FL_WARN("APPROACH 1: Promise-based pattern with explicit types");
111
112 // TUTORIAL: fetch_get() returns fl::promise<fl::response> (not auto!)
113 // The promise represents a future HTTP response that may succeed or fail
114 // Chain .then() for success handling and the lambda receives a
115 // const fl::response& when the fetch succeeds. error_ will handle network device
116 // failures (no connection, DNS failure, etc, but not HTTP errors like 404, 500, etc.)
117 fl::fetch_get("http://fastled.io").then([](const fl::response& response) {
118 // TUTORIAL: Check if HTTP request was successful
119 if (response.ok()) {
120 FL_WARN("SUCCESS [Promise] HTTP fetch successful! Status: "
121 << response.status() << " " << response.status_text());
122
123 // TUTORIAL: get_content_type() returns fl::optional<fl::string>
124 // Optional types may or may not contain a value - always check!
126 if (content_type.has_value()) {
127 FL_WARN("CONTENT [Promise] Content-Type: " << *content_type);
128 }
129
130 // TUTORIAL: response.text() returns fl::string with response body
131 const fl::string& response_body = response.text();
132 if (response_body.length() >= 100) {
133 FL_WARN("RESPONSE [Promise] First 100 characters: " << response_body.substr(0, 100));
134 } else {
135 FL_WARN("RESPONSE [Promise] Full response (" << response_body.length()
136 << " chars): " << response_body);
137 }
138
139 // Visual feedback: Green LEDs indicate promise-based success
140 fill_solid(leds, NUM_LEDS, CRGB(0, 64, 0)); // Green for promise success
141 } else {
142 // HTTP error (like 404, 500, etc.) - still a valid response, just an error status
143 FL_WARN("ERROR [Promise] HTTP Error! Status: "
144 << response.status() << " " << response.status_text());
145 FL_WARN("CONTENT [Promise] Error content: " << response.text());
146
147 // Visual feedback: Orange LEDs indicate HTTP error
148 fill_solid(leds, NUM_LEDS, CRGB(64, 32, 0)); // Orange for HTTP error
149 }
150 })
151 // TUTORIAL: Chain .catch_() for network/connection error handling
152 // The lambda receives a const fl::Error& when the fetch fails completely
153 .catch_([](const fl::Error& network_error) {
154 // Network error (no connection, DNS failure, etc.)
155 FL_WARN("ERROR [Promise] Network Error: " << network_error.message);
156
157 // Visual feedback: Red LEDs indicate network failure
158 fill_solid(leds, NUM_LEDS, CRGB(64, 0, 0)); // Red for network error
159 });
160}
161
162// APPROACH 2: fl::await_top_level() pattern (synchronous-style async code)
163// This approach blocks until completion - feels like traditional programming
165 FL_WARN("APPROACH 2: await_top_level pattern with explicit types");
166
167 // TUTORIAL: Create a fetch_options object to configure the HTTP request
168 // fetch_options is a data container - you can set timeout, headers, etc.
169 fl::fetch_options request_config(""); // Empty URL - will use the URL passed to fetch_get()
170 request_config.timeout(5000) // 5 second timeout
171 .header("User-Agent", "FastLED/NetTest-Tutorial"); // Custom user agent
172
173 // TUTORIAL: fetch_get() returns fl::promise<fl::response> (explicit type!)
174 // This promise represents the future HTTP response
175 fl::promise<fl::response> http_promise = fl::fetch_get("http://fastled.io", request_config);
176
177 // TUTORIAL: await_top_level() returns fl::result<fl::response>
178 // result wraps either a successful response OR an Error - never both!
179 // CRITICAL: await_top_level() blocks until completion - ONLY safe in Arduino loop()!
181
182 // TUTORIAL: Check if the result contains a successful response
183 if (result.ok()) {
184 // TUTORIAL: Extract the response from the result
185 // result.value() returns const fl::response& - the actual HTTP response
186 const fl::response& http_response = result.value();
187
188 FL_WARN("SUCCESS [Await] HTTP fetch successful! Status: "
189 << http_response.status() << " " << http_response.status_text());
190
191 // TUTORIAL: Check for optional Content-Type header
192 // get_content_type() returns fl::optional<fl::string> - may be empty!
193 fl::optional<fl::string> content_type = http_response.get_content_type();
194 if (content_type.has_value()) {
195 FL_WARN("CONTENT [Await] Content-Type: " << *content_type);
196 }
197
198 // TUTORIAL: Get the response body as fl::string
199 const fl::string& response_body = http_response.text();
200 if (response_body.length() >= 100) {
201 FL_WARN("RESPONSE [Await] First 100 characters: " << response_body.substr(0, 100));
202 } else {
203 FL_WARN("RESPONSE [Await] Full response (" << response_body.length()
204 << " chars): " << response_body);
205 }
206
207 // Visual feedback: Blue LEDs indicate await-based success (different from promise)
208 fill_solid(leds, NUM_LEDS, CRGB(0, 0, 64)); // Blue for await success
209 } else {
210 // Either HTTP error OR network error - both end up here
211 // TUTORIAL: result.error_message() is a convenience method for getting error text
212 FL_WARN("ERROR [Await] Request failed: " << result.error_message());
213
214 // Visual feedback: Red LEDs for any await error
215 fill_solid(leds, NUM_LEDS, CRGB(64, 0, 0)); // Red for any error
216 }
217}
218
222 FL_WARN("APPROACH 3: JSON Response handling with fl::Json integration");
223
224 // TUTORIAL: Fetch a JSON API endpoint (httpbin.org provides test JSON)
225 // This endpoint returns JSON with request information
226 fl::fetch_get("https://httpbin.org/json").then([](const fl::response& response) {
227 if (response.ok()) {
228 FL_WARN("SUCCESS [JSON Promise] HTTP fetch successful! Status: "
229 << response.status() << " " << response.status_text());
230
231 // TUTORIAL: Check if response contains JSON content
232 // is_json() checks Content-Type header and body content
233 if (response.is_json()) {
234 FL_WARN("DETECTED [JSON Promise] Response contains JSON data");
235
236 // TUTORIAL: response.json() returns fl::Json with FastLED's ideal API
237 // Automatic parsing, caching, and safe access with defaults using operator|
238 fl::Json data = response.json();
239
240 // TUTORIAL: Safe JSON access with defaults - never crashes!
241 // Uses FastLED's proven pattern: json["path"]["to"]["key"] | default_value
242 fl::string slideshow_url = data["slideshow"]["author"] | fl::string("unknown");
243 fl::string slideshow_title = data["slideshow"]["title"] | fl::string("untitled");
244 int slide_count = data["slideshow"]["slides"].size();
245
246 FL_WARN("JSON [Promise] Slideshow Author: " << slideshow_url);
247 FL_WARN("JSON [Promise] Slideshow Title: " << slideshow_title);
248 FL_WARN("JSON [Promise] Slide Count: " << slide_count);
249
250 // TUTORIAL: Access nested arrays safely
251 if (data.contains("slideshow") && data["slideshow"].contains("slides")) {
252 fl::Json slides = data["slideshow"]["slides"];
253 if (slides.is_array() && slides.size() > 0) {
254 // Get first slide information with safe defaults
255 fl::string first_slide_title = slides[0]["title"] | fl::string("no title");
256 fl::string first_slide_type = slides[0]["type"] | fl::string("unknown");
257 FL_WARN("JSON [Promise] First slide: " << first_slide_title << " (" << first_slide_type << ")");
258 }
259 }
260
261 // Visual feedback: Blue LEDs for successful JSON parsing
262 fill_solid(leds, NUM_LEDS, CRGB(0, 0, 128)); // Blue for JSON success
263
264 } else {
265 FL_WARN("INFO [JSON Promise] Response is not JSON format");
266 // Visual feedback: Yellow for non-JSON response
267 fill_solid(leds, NUM_LEDS, CRGB(64, 64, 0)); // Yellow for non-JSON
268 }
269 } else {
270 FL_WARN("ERROR [JSON Promise] HTTP error: " << response.status()
271 << " " << response.status_text());
272 // Visual feedback: Red LEDs for HTTP error
273 fill_solid(leds, NUM_LEDS, CRGB(64, 0, 0)); // Red for HTTP error
274 }
275 }).catch_([](const fl::Error& error) {
276 FL_WARN("ERROR [JSON Promise] Network error: " << error.message);
277 // Visual feedback: Purple LEDs for network error
278 fill_solid(leds, NUM_LEDS, CRGB(64, 0, 64)); // Purple for network error
279 });
280
281 FastLED.show();
282}
283
287 FL_WARN("APPROACH 4: JSON Response with await pattern");
288
289 // TUTORIAL: Using await pattern with JSON responses
290 // fl::fetch_get() returns fl::promise<fl::response>
291 fl::promise<fl::response> json_promise = fl::fetch_get("https://httpbin.org/get");
292
293 // TUTORIAL: await_top_level() converts promise to result
294 // fl::result<fl::response> contains either response or error
296
297 if (result.ok()) {
298 // TUTORIAL: Extract the response from the result
299 const fl::response& http_response = result.value();
300
301 FL_WARN("SUCCESS [JSON Await] HTTP fetch successful! Status: "
302 << http_response.status() << " " << http_response.status_text());
303
304 // TUTORIAL: Check for JSON content and parse if available
305 if (http_response.is_json()) {
306 FL_WARN("DETECTED [JSON Await] Response contains JSON data");
307
308 // TUTORIAL: Parse JSON with automatic caching
309 fl::Json data = http_response.json();
310
311 // TUTORIAL: httpbin.org/get returns information about the request
312 // Extract data with safe defaults using FastLED's ideal JSON API
313 fl::string origin_ip = data["origin"] | fl::string("unknown");
314 fl::string request_url = data["url"] | fl::string("unknown");
315
316 FL_WARN("JSON [Await] Request Origin IP: " << origin_ip);
317 FL_WARN("JSON [Await] Request URL: " << request_url);
318
319 // TUTORIAL: Access nested headers object safely
320 if (data.contains("headers")) {
321 fl::Json headers = data["headers"];
322 fl::string user_agent = headers["User-Agent"] | fl::string("unknown");
323 fl::string accept = headers["Accept"] | fl::string("unknown");
324
325 FL_WARN("JSON [Await] User-Agent: " << user_agent);
326 FL_WARN("JSON [Await] Accept: " << accept);
327 }
328
329 // TUTORIAL: Access query parameters (if any)
330 if (data.contains("args")) {
331 fl::Json args = data["args"];
332 if (args.size() > 0) {
333 FL_WARN("JSON [Await] Query parameters found: " << args.size());
334 } else {
335 FL_WARN("JSON [Await] No query parameters in request");
336 }
337 }
338
339 // Visual feedback: Cyan LEDs for successful await JSON processing
340 fill_solid(leds, NUM_LEDS, CRGB(0, 128, 128)); // Cyan for await JSON success
341
342 } else {
343 FL_WARN("INFO [JSON Await] Response is not JSON format");
344 // Visual feedback: Orange for non-JSON with await
345 fill_solid(leds, NUM_LEDS, CRGB(128, 32, 0)); // Orange for non-JSON await
346 }
347
348 } else {
349 // TUTORIAL: Handle request failures (network or HTTP errors)
350 FL_WARN("ERROR [JSON Await] Request failed: " << result.error_message());
351 // Visual feedback: Red LEDs for any await error
352 fill_solid(leds, NUM_LEDS, CRGB(128, 0, 0)); // Red for await error
353 }
354
355 FastLED.show();
356}
357
358void loop() {
359 // TUTORIAL: Cycle between different async approaches every 10 seconds
360 // This allows you to see both promise-based and await-based patterns in action
361 // The LEDs provide visual feedback about which approach succeeded
362
363 unsigned long current_time = millis();
364
365 // Switch approaches every 10 seconds
366 // 4 different approaches: Promise, Await, JSON Promise, JSON Await
367 if (current_time - last_request_time >= 10000) {
368 last_request_time = current_time;
369
370 // Cycle through 4 different approaches
371 if (approach_counter % 4 == 0) {
373 FL_WARN("CYCLE: Demonstrated Promise-based pattern (Green LEDs on success)");
374 } else if (approach_counter % 4 == 1) {
376 FL_WARN("CYCLE: Demonstrated Await-based pattern (Blue LEDs on success)");
377 } else if (approach_counter % 4 == 2) {
379 FL_WARN("CYCLE: Demonstrated JSON Promise pattern (Blue LEDs on success)");
380 } else if (approach_counter % 4 == 3) {
382 FL_WARN("CYCLE: Demonstrated JSON Await pattern (Cyan LEDs on success)");
383 }
384
386
387 FL_WARN("NEXT: Will switch to next approach in 10 seconds...");
388 }
389
390 // TUTORIAL NOTE: Async operations are automatically managed!
391 // * On WASM: delay() pumps async tasks every 1ms automatically
392 // * On all platforms: FastLED.show() triggers async updates via engine events
393 // * No manual async updates needed - everything happens behind the scenes!
394
395
396 // TUTORIAL: This delay automatically pumps async tasks on WASM!
397 // The delay is broken into 1ms chunks with async processing between chunks.
398 // This isn't necessary when calling the await approach, but is critical
399 // the standard promise.then() approach.
400 // Note: In the future loop() may become a macro to inject auto pumping
401 // of the async tasks.
402 delay(10);
403}
CRGB leds[NUM_LEDS]
#define NUM_LEDS
#define DATA_PIN
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
Definition FastLED.cpp:74
central include file for FastLED, defines the CFastLED class/object
static u32 last_request_time
Definition NetTestReal.h:87
void setup()
Definition NetTestReal.h:90
void test_promise_approach()
void test_json_await()
APPROACH 4: JSON Response with await pattern Same JSON handling but using await_top_level for synch...
void test_await_approach()
void test_json_response()
APPROACH 3: JSON Response Handling with FastLED's ideal JSON API This demonstrates fetch responses wi...
static int approach_counter
Definition NetTestReal.h:88
void loop()
WS2812 controller class.
Definition FastLED.h:218
bool is_array() const
Definition json.h:1736
bool contains(size_t idx) const
Definition json.h:2078
size_t size() const
Definition json.h:2086
bool has_value() const
Definition optional.h:30
StrN substr(fl::size start, fl::size length) const
Definition str.h:543
fl::size length() const
Definition str.h:325
fetch_options & timeout(int timeout_ms)
Set timeout in milliseconds.
Definition fetch.h:232
fetch_options & header(const fl::string &name, const fl::string &value)
Add header.
Definition fetch.h:213
Fetch options builder (fluent interface)
Definition fetch.h:200
Promise class that provides fluent .then() and .catch_() semantics This is a lightweight wrapper arou...
Definition promise.h:72
fl::Json json() const
Response body parsed as JSON (JavaScript-like API)
Definition fetch.cpp:319
fl::optional< fl::string > get_content_type() const
Get content type convenience method.
Definition fetch.h:112
const fl::string & status_text() const
HTTP status text (like JavaScript response.statusText)
Definition fetch.h:94
int status() const
HTTP status code (like JavaScript response.status)
Definition fetch.h:91
bool ok() const
Check if response is successful (like JavaScript response.ok)
Definition fetch.h:97
const fl::string & text() const
Response body as text (like JavaScript response.text())
Definition fetch.h:100
bool is_json() const
Check if response appears to contain JSON content.
Definition fetch.h:127
HTTP response class (unified interface)
Definition fetch.h:83
const T & value() const
Get the success value (const)
bool ok() const
Check if the result is successful.
fl::string error_message() const
Get the error message as a convenience.
Result type for promise operations.
Unified HTTP fetch API for FastLED (cross-platform)
void fill_solid(struct CRGB *targetArray, int numToFill, const struct CRGB &color)
Fill a range of LEDs with a solid color.
Definition fill.cpp:9
fl::result< T > await_top_level(fl::promise< T > promise)
Synchronously wait for a promise to complete (ONLY safe in top-level contexts)
Definition async.h:175
Optional< T > optional
Definition optional.h:14
@ GRB
Green, Red, Blue (0102)
Definition eorder.h:16
fl::promise< response > fetch_get(const fl::string &url, const fetch_options &request)
HTTP GET request.
Definition fetch.cpp:180
IMPORTANT!
Definition crgb.h:20
corkscrew_args args
Definition old.h:150
Generic asynchronous task management for FastLED.
Representation of an RGB pixel (Red, Green, Blue)
Definition crgb.h:86
fl::string message
Definition promise.h:54
Error type for promises.
Definition promise.h:53
#define FL_WARN
Definition warn.h:12