NanoLux (Device) 3.0
Codebase for the open-source AudioLux device.
Loading...
Searching...
No Matches
api.h
Go to the documentation of this file.
1#include <iterator>
2#include <algorithm>
3
13#pragma once
14
15/*
16 * Use https://arduinojson.org/v6/assistant/ to calculate the size
17 * required for the StaticJsonDocument.
18 */
19
20using namespace ARDUINOJSON_NAMESPACE;
21
22
23/*
24 * HTTP_OK, etc.
25 * CONTENT_JSON, etc. come from WebServer.h
26 */
27
28
29constexpr int PATTERN_BUFFER_SIZE = 4096;
30static char patterns_list[PATTERN_BUFFER_SIZE];
31
37 // Holds roughly 50 patterns.
38 DynamicJsonDocument patterns(PATTERN_BUFFER_SIZE);
39
40 for (int i = 0; i < NUM_PATTERNS; i++) {
41 const JsonObject pattern = patterns.createNestedObject();
42 pattern["index"] = mainPatterns[i].index;
43 pattern["name"] = mainPatterns[i].pattern_name;
44 }
45 serializeJson(patterns, patterns_list);
46}
47
48
49/*
50 * Handle Settings request
51 * (Simple value list API example.)
52 */
53
56inline void handle_patterns_list_request(AsyncWebServerRequest* request) {
57 static bool initialized = false;
58
59 if (!initialized) {
61 initialized = true;
62 }
63
64 request->send(HTTP_OK, CONTENT_JSON, patterns_list);
65}
66
67/*
68 * Handle Pattern request or selection
69 * (Single-value API example.)
70 * Assume payload is JSON:
71 * { "patten": "<80-char-max-string>" }
72 */
73
81inline void handle_pattern_get_request(AsyncWebServerRequest* request) {
82
83 uint8_t pattern_num = request->getParam(0)->value().toInt();
84 bound_byte(&pattern_num, 0, PATTERN_LIMIT);
85
86 Pattern_Data p = loaded_patterns.pattern[pattern_num];
87
88 // Create response substrings
89 String idx = String(" \"idx\": ") + p.idx;
90 String bright = String(", \"brightness\": ") + p.brightness;
91 String smooth = String(", \"smoothing\": ") + p.smoothing;
92 String minhue = String(", \"hue_min\": ") + p.minhue;
93 String maxhue = String(", \"hue_max\": ") + p.maxhue;
94 String conf = String(", \"config\": ") + p.config;
95 String postprocess = String(", \"postprocess\": ") + p.postprocessing_mode;
96
97 // Build and send the final response
98 const String response = String("{") + idx + bright + smooth + minhue + maxhue + conf + postprocess + String(" }");
99 request->send(HTTP_OK, CONTENT_JSON, response);
100}
101
108inline void handle_strip_get_request(AsyncWebServerRequest* request) {
109
110 // Create response substrings
111 String count = String(" \"pattern_count\": ") + loaded_patterns.pattern_count;
112 String alpha = String(", \"alpha\": ") + loaded_patterns.alpha;
113 String mode = String(", \"mode\": ") + loaded_patterns.mode;
114 String noise = String(", \"noise\": ") + loaded_patterns.noise_thresh;
115
116 // Build and send the final response
117 const String response = String("{") + count + alpha + mode + String(" }");
118 request->send(HTTP_OK, CONTENT_JSON, response);
119}
120
127inline void handle_strip_put_request(AsyncWebServerRequest* request, JsonVariant& json) {
128 if (request->method() == HTTP_PUT) {
129 const JsonObject& payload = json.as<JsonObject>();
130
131 int status = HTTP_OK;
132
133 uint8_t count = payload["pattern_count"];
134 uint8_t alpha = payload["alpha"];
135 uint8_t mode = payload["mode"];
136 uint8_t noise = payload["noise"];
137
138 bound_byte(&count, 1, 4);
139 bound_byte(&alpha, 0, 255);
140 bound_byte(&mode, 0, 1);
141 bound_byte(&noise, 0, 100);
142
143 if(count != loaded_patterns.pattern_count)
144 pattern_changed = true;
145
146 if(mode != loaded_patterns.mode)
147 pattern_changed = true;
148
150 loaded_patterns.alpha = alpha;
152 loaded_patterns.mode = mode;
153
155
156 request->send(
157 HTTP_OK,
158 CONTENT_TEXT,
159 build_response(
160 true,
161 "success",
162 nullptr));
163 } else {
164 request->send(HTTP_METHOD_NOT_ALLOWED);
165 }
166}
167
175inline void handle_pattern_put_request(AsyncWebServerRequest* request, JsonVariant& json) {
176 if (request->method() == HTTP_PUT) {
177 const JsonObject& payload = json.as<JsonObject>();
178
179 int status = HTTP_OK;
180
181 uint8_t pattern_num = request->getParam(0)->value().toInt();
182
183 const uint8_t idx = payload["idx"];
184 const uint8_t bright = payload["brightness"];
185 const uint8_t smooth = payload["smoothing"];
186 const uint8_t minhue = payload["hue_min"];
187 const uint8_t maxhue = payload["hue_max"];
188 const uint8_t conf = payload["config"];
189 const uint8_t postprocess = payload["postprocess"];
190
191 if(idx != loaded_patterns.pattern[pattern_num].idx)
192 pattern_changed = true;
193
194 loaded_patterns.pattern[pattern_num].idx = idx;
195 loaded_patterns.pattern[pattern_num].brightness = bright;
196 loaded_patterns.pattern[pattern_num].smoothing = smooth;
197 loaded_patterns.pattern[pattern_num].minhue = minhue;
198 loaded_patterns.pattern[pattern_num].maxhue = maxhue;
199 loaded_patterns.pattern[pattern_num].config = conf;
200 loaded_patterns.pattern[pattern_num].postprocessing_mode = postprocess;
201
203
204 request->send(
205 HTTP_OK,
206 CONTENT_TEXT,
207 build_response(
208 true,
209 "success",
210 nullptr));
211 } else {
212 request->send(HTTP_METHOD_NOT_ALLOWED);
213 }
214}
215
222inline void handle_load_save_slot_put_request(AsyncWebServerRequest* request, JsonVariant& json) {
223 if (request->method() == HTTP_PUT) {
224 const JsonObject& payload = json.as<JsonObject>();
225
226 int status = HTTP_OK;
227
228 const uint8_t slot = payload["slot"];
229
230 if (slot > NUM_SAVES || slot < 0) {
231
232 request->send(
233 HTTP_OK,
234 CONTENT_TEXT,
235 build_response(
236 false,
237 "failure",
238 nullptr));
239
240 } else {
241
242 load_slot(slot);
243 pattern_changed = true;
245
246 request->send(
247 HTTP_OK,
248 CONTENT_TEXT,
249 build_response(
250 true,
251 "success",
252 nullptr));
253 }
254 request->send(
255 HTTP_OK,
256 CONTENT_TEXT,
257 build_response(
258 true,
259 "success",
260 nullptr));
261 } else {
262 request->send(HTTP_METHOD_NOT_ALLOWED);
263 }
264}
265
272inline void handle_save_to_slot_put_request(AsyncWebServerRequest* request, JsonVariant& json) {
273 if (request->method() == HTTP_PUT) {
274 const JsonObject& payload = json.as<JsonObject>();
275
276 int status = HTTP_OK;
277
278 const uint8_t slot = payload["slot"];
279
280 if (slot > NUM_SAVES || slot < 0) {
281
282 request->send(
283 HTTP_OK,
284 CONTENT_TEXT,
285 build_response(
286 false,
287 "failure",
288 nullptr));
289
290 } else {
291
292 set_slot(slot);
293 save_to_nvs();
294
295 request->send(
296 HTTP_OK,
297 CONTENT_TEXT,
298 build_response(
299 true,
300 "success",
301 nullptr));
302 }
303 request->send(
304 HTTP_OK,
305 CONTENT_TEXT,
306 build_response(
307 true,
308 "success",
309 nullptr));
310 } else {
311 request->send(HTTP_METHOD_NOT_ALLOWED);
312 }
313}
314
320inline void handle_system_settings_put_request(AsyncWebServerRequest* request, JsonVariant& json) {
321 if (request->method() == HTTP_PUT) {
322 const JsonObject& payload = json.as<JsonObject>();
323
324 int status = HTTP_OK;
325
326 uint8_t length = payload["length"];
327 uint8_t loop = payload["loop"];
328 uint8_t debug = payload["debug"];
329
330 bound_byte(&length, 30, MAX_LEDS);
331 bound_byte(&loop, 15, 100);
332 bound_byte(&debug, 0, 2);
333
334 if(config.length != length)
335 pattern_changed = true;
336
337 config.length = length;
339 config.debug_mode = debug;
340
342
343 request->send(
344 HTTP_OK,
345 CONTENT_TEXT,
346 build_response(
347 true,
348 "success",
349 nullptr));
350 } else {
351 request->send(HTTP_METHOD_NOT_ALLOWED);
352 }
353}
354
359inline void handle_system_settings_get_request(AsyncWebServerRequest* request) {
360
361 // Create response substrings
362 String length = String(" \"length\": ") + config.length;
363 String loop = String(", \"loop\": ") + config.loop_ms;
364 String debug = String(", \"debug\": ") + config.debug_mode;
365
366 // Build and send the final response
367 const String response = String("{") + length + loop + debug + String(" }");
368 request->send(HTTP_OK, CONTENT_JSON, response);
369}
370
371inline void handle_new_password_put_request(AsyncWebServerRequest* request, JsonVariant& json){
372
373 if (request->method() == HTTP_PUT) {
374 const JsonObject& payload = json.as<JsonObject>();
375
376 int status = HTTP_OK;
377
378 const char * new_password = payload["new_password"];
379
380 // Reject if password is under 8 characters.
381 bool over = true;
382 for(uint8_t i = 0; i < 7; i++){
383 if(new_password[i] == 0)
384 over = false;
385 }
386
387 // Fail if under 8 characters
388 if(!over){
389 request->send(
390 HTTP_OK,
391 CONTENT_TEXT,
392 build_response(
393 false,
394 "too short",
395 nullptr));
396 }
397
398 // Reject if over 15 characters
399 bool under = false;
400 for(uint8_t i = 0; i < 16; i++){
401 if(new_password[i] == 0)
402 under = true;
403 }
404
405 // Send a fail message if over 15 characters
406 if(!under){
407 request->send(
408 HTTP_OK,
409 CONTENT_TEXT,
410 build_response(
411 false,
412 "too long",
413 nullptr));
414 }
415
416 for(uint8_t i = 0; i < 16; i++){
417 config.pass[i] = new_password[i];
418 if(new_password[i] == '\0')
419 break;
420 }
421 Serial.println(config.pass);
423
424 request->send(
425 HTTP_OK,
426 CONTENT_TEXT,
427 build_response(
428 true,
429 "success",
430 nullptr));
431 } else {
432 request->send(HTTP_METHOD_NOT_ALLOWED);
433 }
434
435}
436
439 { "/api/patterns", handle_patterns_list_request },
440 { "/api/getPattern", handle_pattern_get_request },
441 { "/api/getStrip", handle_strip_get_request },
442 { "/api/getSettings", handle_system_settings_get_request },
443};
444constexpr int API_GET_HOOK_COUNT = 4;
445
448 { "/api/putPattern", handle_pattern_put_request },
449 { "/api/putStrip", handle_strip_put_request },
450 { "/api/load", handle_load_save_slot_put_request },
451 { "/api/save", handle_save_to_slot_put_request },
452 { "/api/putSettings", handle_system_settings_put_request },
453 { "/api/updatePassword", handle_new_password_put_request },
454};
455constexpr int API_PUT_HOOK_COUNT = 6;
APIPutHook apiPutHooks[]
The currently active put requests.
Definition api.h:447
void handle_system_settings_put_request(AsyncWebServerRequest *request, JsonVariant &json)
Handler function for updating system settings.
Definition api.h:320
void handle_pattern_put_request(AsyncWebServerRequest *request, JsonVariant &json)
Handler function for updating pattern data.
Definition api.h:175
APIGetHook apiGetHooks[]
The currently active get requests.
Definition api.h:438
void initialize_pattern_list()
Creates a JSON file with the list of patterns.
Definition api.h:36
void handle_load_save_slot_put_request(AsyncWebServerRequest *request, JsonVariant &json)
Handler function for loading a saved pattern.
Definition api.h:222
void handle_pattern_get_request(AsyncWebServerRequest *request)
Handler function for getting pattern data.
Definition api.h:81
void handle_strip_put_request(AsyncWebServerRequest *request, JsonVariant &json)
Handler function for updating strip data.
Definition api.h:127
void handle_system_settings_get_request(AsyncWebServerRequest *request)
Handler function for getting system settings.
Definition api.h:359
void handle_save_to_slot_put_request(AsyncWebServerRequest *request, JsonVariant &json)
Handler function for saving the currently-running pattern.
Definition api.h:272
void handle_patterns_list_request(AsyncWebServerRequest *request)
Handles sending the JSON of patterns to other devices.
Definition api.h:56
void handle_strip_get_request(AsyncWebServerRequest *request)
Handler function for getting pattern data.
Definition api.h:108
int NUM_PATTERNS
The number of patterns that can be shown, externed from globals.h.
Definition globals.h:75
Pattern mainPatterns[]
The current list of patterns, externed from globals.h.
Definition globals.h:58
Config_Data config
The currently-loaded device config.
Definition main.ino:61
volatile bool manual_control_enabled
MANUAL CONTROL VARIABLES.
Definition main.ino:70
Strip_Data loaded_patterns
The current strip configuration being ran by the device.
Definition main.ino:55
volatile bool pattern_changed
Updated to "true" when the web server changes significant pattern settings.
Definition main.ino:52
void loop()
Runs the main program loop.
Definition main.ino:399
void bound_byte(uint8_t *val, int lower, int upper)
Bounds a byte between an upper and a lower value.
Definition nanolux_util.cpp:71
void save_config_to_nvs()
Saves configuration data to the NVS.
Definition storage.cpp:157
void load_slot(int slot)
Move patterns in a slot to the main buffer.
Definition storage.cpp:94
void set_slot(int slot)
Saves the currently-loaded pattern to a save slot.
Definition storage.cpp:111
void save_to_nvs()
Saves all currently-loaded patterns to NVS.
Definition storage.cpp:127
#define PATTERN_LIMIT
The number of patterns that can run at maximum.
Definition storage.h:37
#define NUM_SAVES
The number of saved strip configs the ESP32 is able to address.
Definition storage.h:34
Definition webServer.h:126
Definition webServer.h:131
char pass[16]
If the loaded config data is valid.
Definition storage.h:72
uint8_t debug_mode
The number of milliseconds one program loop takes.
Definition storage.h:70
uint8_t loop_ms
The length of the LED strip.
Definition storage.h:69
Definition storage.h:41
uint8_t smoothing
The pattern's brightness.
Definition storage.h:45
uint8_t minhue
How smoothed pattern light changes are.
Definition storage.h:46
uint8_t brightness
The selected pattern name to run.
Definition storage.h:44
uint8_t noise_thresh
How transparent the top pattern is in Z-layering.
Definition storage.h:58
uint8_t mode
The minimum noise floor to consider as audio.
Definition storage.h:59
Pattern_Data pattern[PATTERN_LIMIT]
The number of patterns this config has.
Definition storage.h:61
uint8_t pattern_count
The currently-running pattern mode (splitting vs layering).
Definition storage.h:60