FlipperHTTP.h 39 KB

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