FlipperHTTP.h 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305
  1. /* FlipperHTTP.h for flipper-http.ino
  2. Author: JBlanked
  3. Github: https://github.com/jblanked/WebCrawler-FlipperZero/tree/main/assets/FlipperHTTP
  4. Info: This library is a wrapper around the HTTPClient library and is used to communicate with the FlipperZero over serial.
  5. Created: 2024-09-30
  6. Updated: 2024-10-17
  7. Change Log:
  8. - 2024-09-30: Initial commit
  9. .
  10. .
  11. .
  12. - 2024-10-16: Fixed typos and added [GET/BYTES], [POST/BYTES], and [WIFI/SACN] commands
  13. - 2024-10-17: Added [LIST], [REBOOT], and [PARSE], and [PARSE/ARRAY] commands
  14. */
  15. #include <WiFi.h>
  16. #include <HTTPClient.h>
  17. #include <WiFiClientSecure.h>
  18. #include "SPIFFS.h"
  19. #include <ArduinoJson.h>
  20. #include <Arduino.h>
  21. #include <ArduinoHttpClient.h>
  22. #define B_PIN 4 // Blue
  23. #define G_PIN 5 // Green
  24. #define R_PIN 6 // Red
  25. #define ON LOW
  26. #define OFF HIGH
  27. class FlipperHTTP
  28. {
  29. public:
  30. // Constructor
  31. FlipperHTTP()
  32. {
  33. }
  34. // Main methods for flipper-http.ino
  35. void loop();
  36. void setup()
  37. {
  38. Serial.begin(115200);
  39. // Initialize SPIFFS
  40. if (!SPIFFS.begin(true))
  41. {
  42. Serial.println("[ERROR] SPIFFS initialization failed.");
  43. ESP.restart();
  44. }
  45. this->ledStart();
  46. Serial.flush();
  47. }
  48. // HTTP Methods
  49. String get(String url);
  50. String get(String url, const char *headerKeys[], const char *headerValues[], int headerSize);
  51. String post(String url, String payload);
  52. String post(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize);
  53. String put(String url, String payload);
  54. String put(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize);
  55. String delete_request(String url, String payload);
  56. String delete_request(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize);
  57. // stream data as bytes
  58. bool get_bytes_to_file(String url, const char *headerKeys[], const char *headerValues[], int headerSize);
  59. bool post_bytes_to_file(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize);
  60. // send bytes from file to serial
  61. void print_bytes_file()
  62. {
  63. File file = SPIFFS.open("/test.txt", FILE_READ);
  64. if (!file)
  65. {
  66. Serial.println("[ERROR] Failed to open file for reading.");
  67. return;
  68. }
  69. while (file.available())
  70. {
  71. Serial.write(file.read());
  72. }
  73. Serial.flush();
  74. Serial.println();
  75. file.close();
  76. }
  77. // Save and Load settings to and from SPIFFS
  78. bool saveWifiSettings(String data);
  79. bool loadWifiSettings();
  80. // returns a string of all wifi networks
  81. String scanWifiNetworks()
  82. {
  83. int n = WiFi.scanNetworks();
  84. String networks = "";
  85. for (int i = 0; i < n; ++i)
  86. {
  87. networks += WiFi.SSID(i);
  88. if (i < n - 1)
  89. {
  90. networks += ", ";
  91. }
  92. }
  93. return networks;
  94. }
  95. // Connect to Wifi using the loaded SSID and Password
  96. bool connectToWifi();
  97. // Check if the Dev Board is connected to Wifi
  98. bool isConnectedToWifi() { return WiFi.status() == WL_CONNECTED; }
  99. // Read serial data until newline character
  100. String readSerialLine();
  101. // Clear serial buffer to avoid any residual data
  102. void clearSerialBuffer()
  103. {
  104. while (Serial.available() > 0)
  105. {
  106. Serial.read();
  107. }
  108. }
  109. // Turn on and off the LED
  110. void ledAction(int pin = G_PIN, int timeout = 250)
  111. {
  112. digitalWrite(pin, ON);
  113. delay(timeout);
  114. digitalWrite(pin, OFF);
  115. delay(timeout);
  116. }
  117. // Display LED sequence when Wifi Board is first connected to the Flipper
  118. void ledStart()
  119. {
  120. pinMode(B_PIN, OUTPUT); // Set Blue Pin mode as output
  121. pinMode(G_PIN, OUTPUT); // Set Green Pin mode as output
  122. pinMode(R_PIN, OUTPUT); // Set Red Pin mode as output
  123. digitalWrite(B_PIN, OFF);
  124. digitalWrite(R_PIN, OFF);
  125. ledAction();
  126. ledAction();
  127. ledAction();
  128. }
  129. // Starting LED (Green only)
  130. void ledStatus()
  131. {
  132. digitalWrite(B_PIN, OFF);
  133. digitalWrite(R_PIN, OFF);
  134. digitalWrite(G_PIN, ON);
  135. }
  136. // Turn off all LEDs
  137. void ledOff()
  138. {
  139. digitalWrite(B_PIN, OFF);
  140. digitalWrite(G_PIN, OFF);
  141. digitalWrite(R_PIN, OFF);
  142. }
  143. private:
  144. const char *settingsFilePath = "/flipper-http.json"; // Path to the settings file in the SPIFFS file system
  145. char loadedSSID[64] = {0}; // Variable to store SSID
  146. char loadedPassword[64] = {0}; // Variable to store password
  147. bool readSerialSettings(String receivedData, bool connectAfterSave);
  148. };
  149. // Connect to Wifi using the loaded SSID and Password
  150. bool FlipperHTTP::connectToWifi()
  151. {
  152. if (String(loadedSSID) == "" || String(loadedPassword) == "")
  153. {
  154. Serial.println("[ERROR] WiFi SSID or Password is empty.");
  155. return false;
  156. }
  157. WiFi.disconnect(true); // Ensure WiFi is disconnected before reconnecting
  158. WiFi.begin(loadedSSID, loadedPassword);
  159. int i = 0;
  160. while (!this->isConnectedToWifi() && i < 20)
  161. {
  162. delay(500);
  163. i++;
  164. Serial.print(".");
  165. }
  166. Serial.println(); // Move to next line after dots
  167. if (this->isConnectedToWifi())
  168. {
  169. Serial.println("[SUCCESS] Successfully connected to Wifi.");
  170. return true;
  171. }
  172. else
  173. {
  174. Serial.println("[ERROR] Failed to connect to Wifi.");
  175. return false;
  176. }
  177. }
  178. // Save Wifi settings to SPIFFS
  179. bool FlipperHTTP::saveWifiSettings(String jsonData)
  180. {
  181. File file = SPIFFS.open(settingsFilePath, FILE_WRITE);
  182. if (!file)
  183. {
  184. Serial.println("[ERROR] Failed to open file for writing.");
  185. return false;
  186. }
  187. file.print(jsonData);
  188. file.close();
  189. Serial.println("[SUCCESS] Settings saved to SPIFFS.");
  190. return true;
  191. }
  192. // Load Wifi settings from SPIFFS
  193. bool FlipperHTTP::loadWifiSettings()
  194. {
  195. File file = SPIFFS.open(settingsFilePath, FILE_READ);
  196. if (!file)
  197. {
  198. Serial.println("[ERROR] Failed to open file for reading.");
  199. return "";
  200. }
  201. // Read the entire file content
  202. String fileContent = file.readString();
  203. file.close();
  204. return fileContent;
  205. }
  206. String FlipperHTTP::readSerialLine()
  207. {
  208. String receivedData = "";
  209. while (Serial.available() > 0)
  210. {
  211. char incomingChar = Serial.read();
  212. if (incomingChar == '\n')
  213. {
  214. break;
  215. }
  216. receivedData += incomingChar;
  217. delay(1); // Minimal delay to allow buffer to fill
  218. }
  219. receivedData.trim(); // Remove any leading/trailing whitespace
  220. return receivedData;
  221. }
  222. bool FlipperHTTP::readSerialSettings(String receivedData, bool connectAfterSave)
  223. {
  224. DynamicJsonDocument doc(1024);
  225. DeserializationError error = deserializeJson(doc, receivedData);
  226. if (error)
  227. {
  228. Serial.print("[ERROR] Failed to parse JSON: ");
  229. Serial.println(error.c_str());
  230. return false;
  231. }
  232. // Extract values from JSON
  233. if (doc.containsKey("ssid") && doc.containsKey("password"))
  234. {
  235. strlcpy(loadedSSID, doc["ssid"], sizeof(loadedSSID));
  236. strlcpy(loadedPassword, doc["password"], sizeof(loadedPassword));
  237. }
  238. else
  239. {
  240. Serial.println("[ERROR] JSON does not contain ssid and password.");
  241. return false;
  242. }
  243. // Save to SPIFFS
  244. if (!this->saveWifiSettings(receivedData))
  245. {
  246. Serial.println("[ERROR] Failed to save settings to file.");
  247. return false;
  248. }
  249. // Attempt to reconnect with new settings
  250. if (connectAfterSave && this->connectToWifi())
  251. {
  252. Serial.println("[SUCCESS] Connected to the new Wifi network.");
  253. }
  254. return true;
  255. }
  256. String FlipperHTTP::get(String url)
  257. {
  258. WiFiClientSecure client;
  259. client.setInsecure(); // Bypass certificate validation
  260. HTTPClient http;
  261. String payload = "";
  262. if (http.begin(client, url))
  263. {
  264. int httpCode = http.GET();
  265. if (httpCode > 0)
  266. {
  267. payload = http.getString();
  268. http.end();
  269. return payload;
  270. }
  271. else
  272. {
  273. Serial.print("[ERROR] GET Request Failed, error: ");
  274. Serial.println(http.errorToString(httpCode).c_str());
  275. }
  276. http.end();
  277. }
  278. else
  279. {
  280. Serial.println("[ERROR] Unable to connect to the server.");
  281. }
  282. // Clear serial buffer to avoid any residual data
  283. this->clearSerialBuffer();
  284. return payload;
  285. }
  286. String FlipperHTTP::get(String url, const char *headerKeys[], const char *headerValues[], int headerSize)
  287. {
  288. WiFiClientSecure client;
  289. client.setInsecure(); // Bypass certificate
  290. HTTPClient http;
  291. String payload = "";
  292. http.collectHeaders(headerKeys, headerSize);
  293. if (http.begin(client, url))
  294. {
  295. for (int i = 0; i < headerSize; i++)
  296. {
  297. http.addHeader(headerKeys[i], headerValues[i]);
  298. }
  299. int httpCode = http.GET();
  300. if (httpCode > 0)
  301. {
  302. payload = http.getString();
  303. http.end();
  304. return payload;
  305. }
  306. else
  307. {
  308. Serial.print("[ERROR] GET Request Failed, error: ");
  309. Serial.println(http.errorToString(httpCode).c_str());
  310. }
  311. http.end();
  312. }
  313. else
  314. {
  315. Serial.println("[ERROR] Unable to connect to the server.");
  316. }
  317. // Clear serial buffer to avoid any residual data
  318. this->clearSerialBuffer();
  319. return payload;
  320. }
  321. String FlipperHTTP::delete_request(String url, String payload)
  322. {
  323. WiFiClientSecure client;
  324. client.setInsecure(); // Bypass certificate
  325. HTTPClient http;
  326. String response = "";
  327. if (http.begin(client, url))
  328. {
  329. int httpCode = http.sendRequest("DELETE", payload);
  330. if (httpCode > 0)
  331. {
  332. response = http.getString();
  333. http.end();
  334. return response;
  335. }
  336. else
  337. {
  338. Serial.print("[ERROR] DELETE Request Failed, error: ");
  339. Serial.println(http.errorToString(httpCode).c_str());
  340. }
  341. http.end();
  342. }
  343. else
  344. {
  345. Serial.println("[ERROR] Unable to connect to the server.");
  346. }
  347. // Clear serial buffer to avoid any residual data
  348. this->clearSerialBuffer();
  349. return response;
  350. }
  351. String FlipperHTTP::delete_request(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize)
  352. {
  353. WiFiClientSecure client;
  354. client.setInsecure(); // Bypass certificate
  355. HTTPClient http;
  356. String response = "";
  357. http.collectHeaders(headerKeys, headerSize);
  358. if (http.begin(client, url))
  359. {
  360. for (int i = 0; i < headerSize; i++)
  361. {
  362. http.addHeader(headerKeys[i], headerValues[i]);
  363. }
  364. int httpCode = http.sendRequest("DELETE", payload);
  365. if (httpCode > 0)
  366. {
  367. response = http.getString();
  368. http.end();
  369. return response;
  370. }
  371. else
  372. {
  373. Serial.print("[ERROR] DELETE Request Failed, error: ");
  374. Serial.println(http.errorToString(httpCode).c_str());
  375. }
  376. http.end();
  377. }
  378. else
  379. {
  380. Serial.println("[ERROR] Unable to connect to the server.");
  381. }
  382. // Clear serial buffer to avoid any residual data
  383. this->clearSerialBuffer();
  384. return response;
  385. }
  386. String FlipperHTTP::post(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize)
  387. {
  388. WiFiClientSecure client;
  389. client.setInsecure(); // Bypass certificate
  390. HTTPClient http;
  391. String response = "";
  392. http.collectHeaders(headerKeys, headerSize);
  393. if (http.begin(client, url))
  394. {
  395. for (int i = 0; i < headerSize; i++)
  396. {
  397. http.addHeader(headerKeys[i], headerValues[i]);
  398. }
  399. int httpCode = http.POST(payload);
  400. if (httpCode > 0)
  401. {
  402. response = http.getString();
  403. http.end();
  404. return response;
  405. }
  406. else
  407. {
  408. Serial.print("[ERROR] POST Request Failed, error: ");
  409. Serial.println(http.errorToString(httpCode).c_str());
  410. }
  411. http.end();
  412. }
  413. else
  414. {
  415. Serial.println("[ERROR] Unable to connect to the server.");
  416. }
  417. // Clear serial buffer to avoid any residual data
  418. this->clearSerialBuffer();
  419. return response;
  420. }
  421. String FlipperHTTP::post(String url, String payload)
  422. {
  423. WiFiClientSecure client;
  424. client.setInsecure(); // Bypass certificate
  425. HTTPClient http;
  426. String response = "";
  427. if (http.begin(client, url))
  428. {
  429. int httpCode = http.POST(payload);
  430. if (httpCode > 0)
  431. {
  432. response = http.getString();
  433. http.end();
  434. return response;
  435. }
  436. else
  437. {
  438. Serial.print("[ERROR] POST Request Failed, error: ");
  439. Serial.println(http.errorToString(httpCode).c_str());
  440. }
  441. http.end();
  442. }
  443. else
  444. {
  445. Serial.println("[ERROR] Unable to connect to the server.");
  446. }
  447. // Clear serial buffer to avoid any residual data
  448. this->clearSerialBuffer();
  449. return response;
  450. }
  451. String FlipperHTTP::put(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize)
  452. {
  453. WiFiClientSecure client;
  454. client.setInsecure(); // Bypass certificate
  455. HTTPClient http;
  456. String response = "";
  457. http.collectHeaders(headerKeys, headerSize);
  458. if (http.begin(client, url))
  459. {
  460. for (int i = 0; i < headerSize; i++)
  461. {
  462. http.addHeader(headerKeys[i], headerValues[i]);
  463. }
  464. int httpCode = http.PUT(payload);
  465. if (httpCode > 0)
  466. {
  467. response = http.getString();
  468. http.end();
  469. return response;
  470. }
  471. else
  472. {
  473. Serial.print("[ERROR] PUT Request Failed, error: ");
  474. Serial.println(http.errorToString(httpCode).c_str());
  475. }
  476. http.end();
  477. }
  478. else
  479. {
  480. Serial.println("[ERROR] Unable to connect to the server.");
  481. }
  482. // Clear serial buffer to avoid any residual data
  483. this->clearSerialBuffer();
  484. return response;
  485. }
  486. String FlipperHTTP::put(String url, String payload)
  487. {
  488. WiFiClientSecure client;
  489. client.setInsecure(); // Bypass certificate
  490. HTTPClient http;
  491. String response = "";
  492. if (http.begin(client, url))
  493. {
  494. int httpCode = http.PUT(payload);
  495. if (httpCode > 0)
  496. {
  497. response = http.getString();
  498. http.end();
  499. return response;
  500. }
  501. else
  502. {
  503. Serial.print("[ERROR] PUT Request Failed, error: ");
  504. Serial.println(http.errorToString(httpCode).c_str());
  505. }
  506. http.end();
  507. }
  508. else
  509. {
  510. Serial.println("[ERROR] Unable to connect to the server.");
  511. }
  512. // Clear serial buffer to avoid any residual data
  513. this->clearSerialBuffer();
  514. return response;
  515. }
  516. bool FlipperHTTP::get_bytes_to_file(String url, const char *headerKeys[], const char *headerValues[], int headerSize)
  517. {
  518. WiFiClientSecure client;
  519. client.setInsecure(); // Bypass certificate
  520. HTTPClient http;
  521. File file = SPIFFS.open("/test.txt", FILE_WRITE);
  522. if (!file)
  523. {
  524. Serial.println("[ERROR] Failed to open file for writing.");
  525. return false;
  526. }
  527. http.collectHeaders(headerKeys, headerSize);
  528. if (http.begin(client, url))
  529. {
  530. for (int i = 0; i < headerSize; i++)
  531. {
  532. http.addHeader(headerKeys[i], headerValues[i]);
  533. }
  534. int httpCode = http.GET();
  535. if (httpCode > 0)
  536. {
  537. Serial.println("[GET/SUCCESS] GET request successful.");
  538. http.writeToStream(&file);
  539. file.close();
  540. return true;
  541. }
  542. else
  543. {
  544. Serial.print("[ERROR] GET Request Failed, error: ");
  545. Serial.println(http.errorToString(httpCode).c_str());
  546. }
  547. http.end();
  548. }
  549. else
  550. {
  551. Serial.println("[ERROR] Unable to connect to the server.");
  552. }
  553. return false;
  554. }
  555. bool FlipperHTTP::post_bytes_to_file(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize)
  556. {
  557. WiFiClientSecure client;
  558. client.setInsecure(); // Bypass certificate
  559. HTTPClient http;
  560. File file = SPIFFS.open("/test.txt", FILE_WRITE);
  561. if (!file)
  562. {
  563. Serial.println("[ERROR] Failed to open file for writing.");
  564. return false;
  565. }
  566. http.collectHeaders(headerKeys, headerSize);
  567. if (http.begin(client, url))
  568. {
  569. for (int i = 0; i < headerSize; i++)
  570. {
  571. http.addHeader(headerKeys[i], headerValues[i]);
  572. }
  573. int httpCode = http.POST(payload);
  574. if (httpCode > 0)
  575. {
  576. Serial.println("[POST/SUCCESS] POST request successful.");
  577. http.writeToStream(&file);
  578. file.close();
  579. return true;
  580. }
  581. else
  582. {
  583. Serial.print("[ERROR] POST Request Failed, error: ");
  584. Serial.println(http.errorToString(httpCode).c_str());
  585. }
  586. http.end();
  587. }
  588. else
  589. {
  590. Serial.println("[ERROR] Unable to connect to the server.");
  591. }
  592. return false;
  593. }
  594. void FlipperHTTP::loop()
  595. {
  596. // Check if there's incoming serial data
  597. if (Serial.available() > 0)
  598. {
  599. // Read the incoming serial data until newline
  600. String _data = this->readSerialLine();
  601. if (_data.length() == 0)
  602. {
  603. // No complete command received
  604. return;
  605. }
  606. this->ledStatus();
  607. // print the available commands
  608. if (_data.startsWith("[LIST]"))
  609. {
  610. Serial.println("[LIST],[PING], [REBOOT], [WIFI/SCAN], [WIFI/SAVE], [WIFI/CONNECT], [WIFI/DISCONNECT], [GET], [GET/HTTP], [POST/HTTP], [PUT/HTTP], [DELETE/HTTP], [GET/BYTES], [POST/BYTES], [PARSE], [PARSE/ARRAY]");
  611. }
  612. // Ping/Pong to see if board/flipper is connected
  613. else if (_data.startsWith("[PING]"))
  614. {
  615. Serial.println("[PONG]");
  616. }
  617. // Handle [REBOOT] command
  618. else if (_data.startsWith("[REBOOT]"))
  619. {
  620. ESP.restart();
  621. }
  622. // scan for wifi networks
  623. else if (_data.startsWith("[WIFI/SCAN]"))
  624. {
  625. Serial.println(this->scanWifiNetworks());
  626. Serial.flush();
  627. Serial.println();
  628. }
  629. // Handle [WIFI/SAVE] command
  630. else if (_data.startsWith("[WIFI/SAVE]"))
  631. {
  632. // Extract JSON data by removing the command part
  633. String jsonData = _data.substring(strlen("[WIFI/SAVE]"));
  634. jsonData.trim(); // Remove any leading/trailing whitespace
  635. // Parse and save the settings
  636. if (this->readSerialSettings(jsonData, true))
  637. {
  638. Serial.println("[SUCCESS] Wifi settings saved.");
  639. }
  640. else
  641. {
  642. Serial.println("[ERROR] Failed to save Wifi settings.");
  643. }
  644. }
  645. // Handle [WIFI/CONNECT] command
  646. else if (_data == "[WIFI/CONNECT]")
  647. {
  648. // Check if WiFi is already connected
  649. if (!this->isConnectedToWifi())
  650. {
  651. // Attempt to connect to Wifi
  652. if (this->connectToWifi())
  653. {
  654. Serial.println("[SUCCESS] Connected to Wifi.");
  655. }
  656. else
  657. {
  658. Serial.println("[ERROR] Failed to connect to Wifi.");
  659. }
  660. }
  661. else
  662. {
  663. Serial.println("[INFO] Already connected to Wifi.");
  664. }
  665. }
  666. // Handle [WIFI/DISCONNECT] command
  667. else if (_data == "[WIFI/DISCONNECT]")
  668. {
  669. WiFi.disconnect(true);
  670. Serial.println("[DISCONNECTED] Wifi has been disconnected.");
  671. }
  672. // Handle [GET] command
  673. else if (_data.startsWith("[GET]"))
  674. {
  675. if (!this->isConnectedToWifi() && !this->connectToWifi())
  676. {
  677. Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
  678. this->ledOff();
  679. return;
  680. }
  681. // Extract URL by removing the command part
  682. String url = _data.substring(strlen("[GET]"));
  683. url.trim();
  684. // GET request
  685. String getData = this->get(url);
  686. if (getData != "")
  687. {
  688. Serial.println("[GET/SUCCESS] GET request successful.");
  689. Serial.println(getData);
  690. Serial.flush();
  691. Serial.println();
  692. Serial.println("[GET/END]");
  693. }
  694. else
  695. {
  696. Serial.println("[ERROR] GET request failed or returned empty data.");
  697. }
  698. }
  699. // Handle [GET/HTTP] command
  700. else if (_data.startsWith("[GET/HTTP]"))
  701. {
  702. if (!this->isConnectedToWifi() && !this->connectToWifi())
  703. {
  704. Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
  705. this->ledOff();
  706. return;
  707. }
  708. // Extract the JSON by removing the command part
  709. String jsonData = _data.substring(strlen("[GET/HTTP]"));
  710. jsonData.trim();
  711. DynamicJsonDocument doc(1024);
  712. DeserializationError error = deserializeJson(doc, jsonData);
  713. if (error)
  714. {
  715. Serial.print("[ERROR] Failed to parse JSON.");
  716. this->ledOff();
  717. return;
  718. }
  719. // Extract values from JSON
  720. if (!doc.containsKey("url"))
  721. {
  722. Serial.println("[ERROR] JSON does not contain url.");
  723. this->ledOff();
  724. return;
  725. }
  726. String url = doc["url"];
  727. // Extract headers if available
  728. const char *headerKeys[10];
  729. const char *headerValues[10];
  730. int headerSize = 0;
  731. if (doc.containsKey("headers"))
  732. {
  733. JsonObject headers = doc["headers"];
  734. for (JsonPair header : headers)
  735. {
  736. headerKeys[headerSize] = header.key().c_str();
  737. headerValues[headerSize] = header.value();
  738. headerSize++;
  739. }
  740. }
  741. // GET request
  742. String getData = this->get(url, headerKeys, headerValues, headerSize);
  743. if (getData != "")
  744. {
  745. Serial.println("[GET/SUCCESS] GET request successful.");
  746. Serial.println(getData);
  747. Serial.flush();
  748. Serial.println();
  749. Serial.println("[GET/END]");
  750. }
  751. else
  752. {
  753. Serial.println("[ERROR] GET request failed or returned empty data.");
  754. }
  755. }
  756. // Handle [POST/HTTP] command
  757. else if (_data.startsWith("[POST/HTTP]"))
  758. {
  759. if (!this->isConnectedToWifi() && !this->connectToWifi())
  760. {
  761. Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
  762. this->ledOff();
  763. return;
  764. }
  765. // Extract the JSON by removing the command part
  766. String jsonData = _data.substring(strlen("[POST/HTTP]"));
  767. jsonData.trim();
  768. DynamicJsonDocument doc(1024);
  769. DeserializationError error = deserializeJson(doc, jsonData);
  770. if (error)
  771. {
  772. Serial.print("[ERROR] Failed to parse JSON.");
  773. this->ledOff();
  774. return;
  775. }
  776. // Extract values from JSON
  777. if (!doc.containsKey("url") || !doc.containsKey("payload"))
  778. {
  779. Serial.println("[ERROR] JSON does not contain url or payload.");
  780. this->ledOff();
  781. return;
  782. }
  783. String url = doc["url"];
  784. String payload = doc["payload"];
  785. // Extract headers if available
  786. const char *headerKeys[10];
  787. const char *headerValues[10];
  788. int headerSize = 0;
  789. if (doc.containsKey("headers"))
  790. {
  791. JsonObject headers = doc["headers"];
  792. for (JsonPair header : headers)
  793. {
  794. headerKeys[headerSize] = header.key().c_str();
  795. headerValues[headerSize] = header.value();
  796. headerSize++;
  797. }
  798. }
  799. // POST request
  800. String postData = this->post(url, payload, headerKeys, headerValues, headerSize);
  801. if (postData != "")
  802. {
  803. Serial.println("[POST/SUCCESS] POST request successful.");
  804. Serial.println(postData);
  805. Serial.flush();
  806. Serial.println();
  807. Serial.println("[POST/END]");
  808. }
  809. else
  810. {
  811. Serial.println("[ERROR] POST request failed or returned empty data.");
  812. }
  813. }
  814. // Handle [PUT/HTTP] command
  815. else if (_data.startsWith("[PUT/HTTP]"))
  816. {
  817. if (!this->isConnectedToWifi() && !this->connectToWifi())
  818. {
  819. Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
  820. this->ledOff();
  821. return;
  822. }
  823. // Extract the JSON by removing the command part
  824. String jsonData = _data.substring(strlen("[PUT/HTTP]"));
  825. jsonData.trim();
  826. DynamicJsonDocument doc(1024);
  827. DeserializationError error = deserializeJson(doc, jsonData);
  828. if (error)
  829. {
  830. Serial.print("[ERROR] Failed to parse JSON.");
  831. this->ledOff();
  832. return;
  833. }
  834. // Extract values from JSON
  835. if (!doc.containsKey("url") || !doc.containsKey("payload"))
  836. {
  837. Serial.println("[ERROR] JSON does not contain url or payload.");
  838. this->ledOff();
  839. return;
  840. }
  841. String url = doc["url"];
  842. String payload = doc["payload"];
  843. // Extract headers if available
  844. const char *headerKeys[10];
  845. const char *headerValues[10];
  846. int headerSize = 0;
  847. if (doc.containsKey("headers"))
  848. {
  849. JsonObject headers = doc["headers"];
  850. for (JsonPair header : headers)
  851. {
  852. headerKeys[headerSize] = header.key().c_str();
  853. headerValues[headerSize] = header.value();
  854. headerSize++;
  855. }
  856. }
  857. // PUT request
  858. String putData = this->put(url, payload, headerKeys, headerValues, headerSize);
  859. if (putData != "")
  860. {
  861. Serial.println("[PUT/SUCCESS] PUT request successful.");
  862. Serial.println(putData);
  863. Serial.flush();
  864. Serial.println();
  865. Serial.println("[PUT/END]");
  866. }
  867. else
  868. {
  869. Serial.println("[ERROR] PUT request failed or returned empty data.");
  870. }
  871. }
  872. // Handle [DELETE/HTTP] command
  873. else if (_data.startsWith("[DELETE/HTTP]"))
  874. {
  875. if (!this->isConnectedToWifi() && !this->connectToWifi())
  876. {
  877. Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
  878. this->ledOff();
  879. return;
  880. }
  881. // Extract the JSON by removing the command part
  882. String jsonData = _data.substring(strlen("[DELETE/HTTP]"));
  883. jsonData.trim();
  884. DynamicJsonDocument doc(1024);
  885. DeserializationError error = deserializeJson(doc, jsonData);
  886. if (error)
  887. {
  888. Serial.print("[ERROR] Failed to parse JSON.");
  889. this->ledOff();
  890. return;
  891. }
  892. // Extract values from JSON
  893. if (!doc.containsKey("url") || !doc.containsKey("payload"))
  894. {
  895. Serial.println("[ERROR] JSON does not contain url or payload.");
  896. this->ledOff();
  897. return;
  898. }
  899. String url = doc["url"];
  900. String payload = doc["payload"];
  901. // Extract headers if available
  902. const char *headerKeys[10];
  903. const char *headerValues[10];
  904. int headerSize = 0;
  905. if (doc.containsKey("headers"))
  906. {
  907. JsonObject headers = doc["headers"];
  908. for (JsonPair header : headers)
  909. {
  910. headerKeys[headerSize] = header.key().c_str();
  911. headerValues[headerSize] = header.value();
  912. headerSize++;
  913. }
  914. }
  915. // DELETE request
  916. String deleteData = this->delete_request(url, payload, headerKeys, headerValues, headerSize);
  917. if (deleteData != "")
  918. {
  919. Serial.println("[DELETE/SUCCESS] DELETE request successful.");
  920. Serial.println(deleteData);
  921. Serial.flush();
  922. Serial.println();
  923. Serial.println("[DELETE/END]");
  924. }
  925. else
  926. {
  927. Serial.println("[ERROR] DELETE request failed or returned empty data.");
  928. }
  929. }
  930. // Handle [GET/BYTES]
  931. else if (_data.startsWith("[GET/BYTES]"))
  932. {
  933. if (!this->isConnectedToWifi() && !this->connectToWifi())
  934. {
  935. Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
  936. this->ledOff();
  937. return;
  938. }
  939. // Extract the JSON by removing the command part
  940. String jsonData = _data.substring(strlen("[GET/BYTES]"));
  941. jsonData.trim();
  942. DynamicJsonDocument doc(1024);
  943. DeserializationError error = deserializeJson(doc, jsonData);
  944. if (error)
  945. {
  946. Serial.print("[ERROR] Failed to parse JSON.");
  947. this->ledOff();
  948. return;
  949. }
  950. // Extract values from JSON
  951. if (!doc.containsKey("url"))
  952. {
  953. Serial.println("[ERROR] JSON does not contain url.");
  954. this->ledOff();
  955. return;
  956. }
  957. String url = doc["url"];
  958. // Extract headers if available
  959. const char *headerKeys[10];
  960. const char *headerValues[10];
  961. int headerSize = 0;
  962. if (doc.containsKey("headers"))
  963. {
  964. JsonObject headers = doc["headers"];
  965. for (JsonPair header : headers)
  966. {
  967. headerKeys[headerSize] = header.key().c_str();
  968. headerValues[headerSize] = header.value();
  969. headerSize++;
  970. }
  971. }
  972. // GET request
  973. if (this->get_bytes_to_file(url, headerKeys, headerValues, headerSize))
  974. {
  975. // Serial.println("[GET/SUCCESS] GET request successful.");
  976. // moved this locally since we're streaming
  977. this->print_bytes_file();
  978. Serial.println("[GET/END]");
  979. }
  980. else
  981. {
  982. Serial.println("[ERROR] GET request failed or returned empty data.");
  983. }
  984. }
  985. // handle [POST/BYTES]
  986. else if (_data.startsWith("[POST/BYTES]"))
  987. {
  988. if (!this->isConnectedToWifi() && !this->connectToWifi())
  989. {
  990. Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
  991. this->ledOff();
  992. return;
  993. }
  994. // Extract the JSON by removing the command part
  995. String jsonData = _data.substring(strlen("[POST/BYTES]"));
  996. jsonData.trim();
  997. DynamicJsonDocument doc(1024);
  998. DeserializationError error = deserializeJson(doc, jsonData);
  999. if (error)
  1000. {
  1001. Serial.print("[ERROR] Failed to parse JSON.");
  1002. this->ledOff();
  1003. return;
  1004. }
  1005. // Extract values from JSON
  1006. if (!doc.containsKey("url") || !doc.containsKey("payload"))
  1007. {
  1008. Serial.println("[ERROR] JSON does not contain url or payload.");
  1009. this->ledOff();
  1010. return;
  1011. }
  1012. String url = doc["url"];
  1013. String payload = doc["payload"];
  1014. // Extract headers if available
  1015. const char *headerKeys[10];
  1016. const char *headerValues[10];
  1017. int headerSize = 0;
  1018. if (doc.containsKey("headers"))
  1019. {
  1020. JsonObject headers = doc["headers"];
  1021. for (JsonPair header : headers)
  1022. {
  1023. headerKeys[headerSize] = header.key().c_str();
  1024. headerValues[headerSize] = header.value();
  1025. headerSize++;
  1026. }
  1027. }
  1028. // POST request
  1029. if (this->post_bytes_to_file(url, payload, headerKeys, headerValues, headerSize))
  1030. {
  1031. // Serial.println("[POST/SUCCESS] POST request successful.");
  1032. // moved the success message locally since it's streaming the data
  1033. this->print_bytes_file();
  1034. Serial.println("[POST/END]");
  1035. }
  1036. else
  1037. {
  1038. Serial.println("[ERROR] POST request failed or returned empty data.");
  1039. }
  1040. }
  1041. // Handle [PARSE] command
  1042. // the user will append the key to read from the json
  1043. // example: [PARSE]{"key":"name","json":{"name":"John Doe"}}
  1044. else if (_data.startsWith("[PARSE]"))
  1045. {
  1046. // Extract the JSON by removing the command part
  1047. String jsonData = _data.substring(strlen("[PARSE]"));
  1048. jsonData.trim();
  1049. DynamicJsonDocument doc(1024);
  1050. DeserializationError error = deserializeJson(doc, jsonData);
  1051. if (error)
  1052. {
  1053. Serial.print("[ERROR] Failed to parse JSON.");
  1054. this->ledOff();
  1055. return;
  1056. }
  1057. // Extract values from JSON
  1058. if (!doc.containsKey("key") || !doc.containsKey("json"))
  1059. {
  1060. Serial.println("[ERROR] JSON does not contain key or json.");
  1061. this->ledOff();
  1062. return;
  1063. }
  1064. String key = doc["key"];
  1065. JsonObject json = doc["json"];
  1066. if (json.containsKey(key))
  1067. {
  1068. Serial.println(json[key].as<String>());
  1069. }
  1070. else
  1071. {
  1072. Serial.println("[ERROR] Key not found in JSON.");
  1073. }
  1074. }
  1075. // Handle [PARSE/ARRAY] command
  1076. // the user will append the key to read and the index of the array to get it's key from the json
  1077. // example: [PARSE/ARRAY]{"key":"name","index":"1","json":{"name":["John Doe","Jane Doe"]}}
  1078. // this would return Jane Doe
  1079. // and in this example it would return {"flavor": "red"}:
  1080. // example: [PARSE/ARRAY]{"key":"flavor","index":"1","json":{"name":[{"flavor": "blue"},{"flavor": "red"}]}}
  1081. else if (_data.startsWith("[PARSE/ARRAY]"))
  1082. {
  1083. // Extract the JSON by removing the command part
  1084. String jsonData = _data.substring(strlen("[PARSE/ARRAY]"));
  1085. jsonData.trim();
  1086. DynamicJsonDocument doc(1024);
  1087. DeserializationError error = deserializeJson(doc, jsonData);
  1088. if (error)
  1089. {
  1090. Serial.print("[ERROR] Failed to parse JSON.");
  1091. this->ledOff();
  1092. return;
  1093. }
  1094. // Extract values from JSON
  1095. if (!doc.containsKey("key") || !doc.containsKey("index") || !doc.containsKey("json"))
  1096. {
  1097. Serial.println("[ERROR] JSON does not contain key, index, or json.");
  1098. this->ledOff();
  1099. return;
  1100. }
  1101. String key = doc["key"];
  1102. int index = doc["index"];
  1103. JsonArray json = doc["json"];
  1104. if (json[index].containsKey(key))
  1105. {
  1106. Serial.println(json[index][key].as<String>());
  1107. }
  1108. else
  1109. {
  1110. Serial.println("[ERROR] Key not found in JSON.");
  1111. }
  1112. }
  1113. else
  1114. {
  1115. Serial.println("[ERROR] Invalid command.");
  1116. }
  1117. this->ledOff();
  1118. }
  1119. }