Przeglądaj źródła

Move FlipperHTTP to it's on repository

jblanked 1 rok temu
rodzic
commit
aa951ef320

BIN
assets/.DS_Store


BIN
assets/FlipperHTTP/.DS_Store


+ 0 - 1490
assets/FlipperHTTP/Arduino/FlipperHTTP.h

@@ -1,1490 +0,0 @@
-/* FlipperHTTP.h for flipper-http.ino
-Author: JBlanked
-Github: https://github.com/jblanked/WebCrawler-FlipperZero/tree/main/assets/FlipperHTTP
-Info: This library is a wrapper around the HTTPClient library and is used to communicate with the FlipperZero over serial.
-Created: 2024-09-30
-Updated: 2024-10-26
-
-Change Log:
-- 2024-09-30: Initial commit
-.
-.
-.
-- 2024-10-16: Fixed typos and added [GET/BYTES], [POST/BYTES], and [WIFI/SACN] commands
-- 2024-10-17: Added [LIST], [REBOOT], [PARSE], [PARSE/ARRAY], [LED/ON], and [LED/OFF], and [IP/ADDRESS] commands
-- 2024-10-19: Added [WIFI/IP] command
-- 2024-10-21: Removed unnecessary println
-- 2024-10-22: Updated Post Bytes and Get Bytes methods
-- 2024-10-25: Updated to automatically connect to WiFi on boot if settings are saved
-- 2024-10-26: Updated the saveWifiSettings and loadWifiSettings methods to save and load a list of wifi networks, and added [WIFI/LIST] command
-*/
-
-#include <WiFi.h>
-#include <HTTPClient.h>
-#include <WiFiClientSecure.h>
-#include "SPIFFS.h"
-#include <ArduinoJson.h>
-#include <Arduino.h>
-
-#define B_PIN 4 // Blue
-#define G_PIN 5 // Green
-#define R_PIN 6 // Red
-
-#define ON LOW
-#define OFF HIGH
-
-class FlipperHTTP
-{
-public:
-    // Constructor
-    FlipperHTTP()
-    {
-    }
-
-    // Main methods for flipper-http.ino
-    void loop();
-    void setup()
-    {
-        Serial.begin(115200);
-        // Initialize SPIFFS
-        if (!SPIFFS.begin(true))
-        {
-            Serial.println("[ERROR] SPIFFS initialization failed.");
-            ESP.restart();
-        }
-        this->useLED = true;
-        this->ledStart();
-        this->loadWifiSettings();
-        Serial.flush();
-    }
-
-    // HTTP Methods
-    String get(String url);
-    String get(String url, const char *headerKeys[], const char *headerValues[], int headerSize);
-    String post(String url, String payload);
-    String post(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize);
-    String put(String url, String payload);
-    String put(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize);
-    String delete_request(String url, String payload);
-    String delete_request(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize);
-
-    // stream data as bytes
-    bool get_bytes_to_file(String url, const char *headerKeys[], const char *headerValues[], int headerSize);
-    bool post_bytes_to_file(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize);
-
-    // Save and Load settings to and from SPIFFS
-    bool saveWifiSettings(String data);
-    bool loadWifiSettings();
-
-    // returns a string of all wifi networks
-    String scanWifiNetworks()
-    {
-        int n = WiFi.scanNetworks();
-        String networks = "";
-        for (int i = 0; i < n; ++i)
-        {
-            networks += WiFi.SSID(i);
-
-            if (i < n - 1)
-            {
-                networks += ", ";
-            }
-        }
-        return networks;
-    }
-
-    // Connect to Wifi using the loaded SSID and Password
-    bool connectToWifi();
-
-    // Check if the Dev Board is connected to Wifi
-    bool isConnectedToWifi() { return WiFi.status() == WL_CONNECTED; }
-
-    // Read serial data until newline character
-    String readSerialLine();
-
-    // Clear serial buffer to avoid any residual data
-    void clearSerialBuffer()
-    {
-        while (Serial.available() > 0)
-        {
-            Serial.read();
-        }
-    }
-
-    // Turn on and off the LED
-    void ledAction(int pin = G_PIN, int timeout = 250)
-    {
-        digitalWrite(pin, ON);
-        delay(timeout);
-        digitalWrite(pin, OFF);
-        delay(timeout);
-    }
-
-    // Display LED sequence when Wifi Board is first connected to the Flipper
-    void ledStart()
-    {
-        pinMode(B_PIN, OUTPUT); // Set Blue Pin mode as output
-        pinMode(G_PIN, OUTPUT); // Set Green Pin mode as output
-        pinMode(R_PIN, OUTPUT); // Set Red Pin mode as output
-
-        digitalWrite(B_PIN, OFF);
-        digitalWrite(R_PIN, OFF);
-
-        ledAction();
-        ledAction();
-        ledAction();
-    }
-
-    // Starting LED (Green only)
-    void ledStatus()
-    {
-        if (this->useLED)
-        {
-            digitalWrite(B_PIN, OFF);
-            digitalWrite(R_PIN, OFF);
-            digitalWrite(G_PIN, ON);
-        }
-    }
-
-    // Turn off all LEDs
-    void ledOff()
-    {
-        digitalWrite(B_PIN, OFF);
-        digitalWrite(G_PIN, OFF);
-        digitalWrite(R_PIN, OFF);
-    }
-
-    // get IP addresss
-    String getIPAddress()
-    {
-        return WiFi.localIP().toString();
-    }
-
-private:
-    const char *settingsFilePath = "/flipper-http.json"; // Path to the settings file in the SPIFFS file system
-    char loadedSSID[64] = {0};                           // Variable to store SSID
-    char loadedPassword[64] = {0};                       // Variable to store password
-    bool useLED = true;                                  // Variable to control LED usage
-
-    bool readSerialSettings(String receivedData, bool connectAfterSave);
-};
-
-//  Connect to Wifi using the loaded SSID and Password
-bool FlipperHTTP::connectToWifi()
-{
-    if (String(loadedSSID) == "" || String(loadedPassword) == "")
-    {
-        Serial.println("[ERROR] WiFi SSID or Password is empty.");
-        return false;
-    }
-
-    WiFi.disconnect(true); // Ensure WiFi is disconnected before reconnecting
-    WiFi.begin(loadedSSID, loadedPassword);
-
-    int i = 0;
-    while (!this->isConnectedToWifi() && i < 20)
-    {
-        delay(500);
-        i++;
-        Serial.print(".");
-    }
-    Serial.println(); // Move to next line after dots
-
-    if (this->isConnectedToWifi())
-    {
-        Serial.println("[SUCCESS] Successfully connected to Wifi.");
-        return true;
-    }
-    else
-    {
-        Serial.println("[ERROR] Failed to connect to Wifi.");
-        return false;
-    }
-}
-
-// Save WiFi settings to SPIFFS
-bool FlipperHTTP::saveWifiSettings(String jsonData)
-{
-    DynamicJsonDocument doc(1024);
-    DeserializationError error = deserializeJson(doc, jsonData);
-
-    if (error)
-    {
-        Serial.println("[ERROR] Failed to parse JSON data.");
-        return false;
-    }
-
-    const char *newSSID = doc["ssid"];
-    const char *newPassword = doc["password"];
-
-    // Load existing settings if they exist
-    DynamicJsonDocument existingDoc(2048);
-    File file = SPIFFS.open(settingsFilePath, FILE_READ);
-    if (file)
-    {
-        deserializeJson(existingDoc, file);
-        file.close();
-    }
-
-    // Check if SSID is already saved
-    bool found = false;
-    for (JsonObject wifi : existingDoc["wifi_list"].as<JsonArray>())
-    {
-        if (wifi["ssid"] == newSSID)
-        {
-            found = true;
-            break;
-        }
-    }
-
-    // Add new SSID and password if not found
-    if (!found)
-    {
-        JsonArray wifiList = existingDoc["wifi_list"].to<JsonArray>();
-        JsonObject newWifi = wifiList.createNestedObject();
-        newWifi["ssid"] = newSSID;
-        newWifi["password"] = newPassword;
-
-        // Save updated list to file
-        file = SPIFFS.open(settingsFilePath, FILE_WRITE);
-        if (!file)
-        {
-            Serial.println("[ERROR] Failed to open file for writing.");
-            return false;
-        }
-
-        serializeJson(existingDoc, file);
-        file.close();
-    }
-
-    Serial.print("[SUCCESS] Settings saved to SPIFFS.");
-    return true;
-}
-
-// Load WiFi settings from SPIFFS and attempt to connect
-bool FlipperHTTP::loadWifiSettings()
-{
-    File file = SPIFFS.open(settingsFilePath, FILE_READ);
-    if (!file)
-    {
-        return false;
-    }
-
-    // Read the entire file content
-    String fileContent = file.readString();
-    file.close();
-
-    DynamicJsonDocument doc(2048);
-    DeserializationError error = deserializeJson(doc, fileContent);
-
-    if (error)
-    {
-        return false;
-    }
-
-    JsonArray wifiList = doc["wifi_list"].as<JsonArray>();
-    for (JsonObject wifi : wifiList)
-    {
-        const char *ssid = wifi["ssid"];
-        const char *password = wifi["password"];
-
-        strlcpy(loadedSSID, ssid, sizeof(loadedSSID));
-        strlcpy(loadedPassword, password, sizeof(loadedPassword));
-
-        WiFi.begin(ssid, password);
-
-        int attempts = 0;
-        while (!this->isConnectedToWifi() && attempts < 4) // 2 seconds total, 500ms delay each
-        {
-            delay(500);
-            attempts++;
-        }
-
-        if (this->isConnectedToWifi())
-        {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-String FlipperHTTP::readSerialLine()
-{
-    String receivedData = "";
-
-    while (Serial.available() > 0)
-    {
-        char incomingChar = Serial.read();
-        if (incomingChar == '\n')
-        {
-            break;
-        }
-        receivedData += incomingChar;
-        delay(1); // Minimal delay to allow buffer to fill
-    }
-
-    receivedData.trim(); // Remove any leading/trailing whitespace
-
-    return receivedData;
-}
-
-bool FlipperHTTP::readSerialSettings(String receivedData, bool connectAfterSave)
-{
-    DynamicJsonDocument doc(1024);
-    DeserializationError error = deserializeJson(doc, receivedData);
-
-    if (error)
-    {
-        Serial.print("[ERROR] Failed to parse JSON: ");
-        Serial.println(error.c_str());
-        return false;
-    }
-
-    // Extract values from JSON
-    if (doc.containsKey("ssid") && doc.containsKey("password"))
-    {
-        strlcpy(loadedSSID, doc["ssid"], sizeof(loadedSSID));             // save ssid
-        strlcpy(loadedPassword, doc["password"], sizeof(loadedPassword)); // save password
-    }
-    else
-    {
-        Serial.println("[ERROR] JSON does not contain ssid and password.");
-        return false;
-    }
-
-    // Save to SPIFFS
-    if (!this->saveWifiSettings(receivedData))
-    {
-        Serial.println("[ERROR] Failed to save settings to file.");
-        return false;
-    }
-
-    // Attempt to reconnect with new settings
-    if (connectAfterSave && this->connectToWifi())
-    {
-        Serial.println("[SUCCESS] Connected to the new Wifi network.");
-    }
-
-    return true;
-}
-
-String FlipperHTTP::get(String url)
-{
-    WiFiClientSecure client;
-    client.setInsecure(); // Bypass certificate validation
-
-    HTTPClient http;
-    String payload = "";
-
-    if (http.begin(client, url))
-    {
-        int httpCode = http.GET();
-
-        if (httpCode > 0)
-        {
-            payload = http.getString();
-            http.end();
-            return payload;
-        }
-        else
-        {
-            Serial.print("[ERROR] GET Request Failed, error: ");
-            Serial.println(http.errorToString(httpCode).c_str());
-        }
-        http.end();
-    }
-    else
-    {
-        Serial.println("[ERROR] Unable to connect to the server.");
-    }
-
-    // Clear serial buffer to avoid any residual data
-    this->clearSerialBuffer();
-
-    return payload;
-}
-
-String FlipperHTTP::get(String url, const char *headerKeys[], const char *headerValues[], int headerSize)
-{
-    WiFiClientSecure client;
-    client.setInsecure(); // Bypass certificate
-
-    HTTPClient http;
-    String payload = "";
-
-    http.collectHeaders(headerKeys, headerSize);
-
-    if (http.begin(client, url))
-    {
-
-        for (int i = 0; i < headerSize; i++)
-        {
-            http.addHeader(headerKeys[i], headerValues[i]);
-        }
-
-        int httpCode = http.GET();
-
-        if (httpCode > 0)
-        {
-            payload = http.getString();
-            http.end();
-            return payload;
-        }
-        else
-        {
-            Serial.print("[ERROR] GET Request Failed, error: ");
-            Serial.println(http.errorToString(httpCode).c_str());
-        }
-        http.end();
-    }
-    else
-    {
-        Serial.println("[ERROR] Unable to connect to the server.");
-    }
-
-    // Clear serial buffer to avoid any residual data
-    this->clearSerialBuffer();
-
-    return payload;
-}
-
-String FlipperHTTP::delete_request(String url, String payload)
-{
-    WiFiClientSecure client;
-    client.setInsecure(); // Bypass certificate
-
-    HTTPClient http;
-    String response = "";
-
-    if (http.begin(client, url))
-    {
-        int httpCode = http.sendRequest("DELETE", payload);
-
-        if (httpCode > 0)
-        {
-            response = http.getString();
-            http.end();
-            return response;
-        }
-        else
-        {
-            Serial.print("[ERROR] DELETE Request Failed, error: ");
-            Serial.println(http.errorToString(httpCode).c_str());
-        }
-        http.end();
-    }
-
-    else
-    {
-        Serial.println("[ERROR] Unable to connect to the server.");
-    }
-
-    // Clear serial buffer to avoid any residual data
-    this->clearSerialBuffer();
-
-    return response;
-}
-
-String FlipperHTTP::delete_request(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize)
-{
-    WiFiClientSecure client;
-    client.setInsecure(); // Bypass certificate
-
-    HTTPClient http;
-    String response = "";
-
-    http.collectHeaders(headerKeys, headerSize);
-
-    if (http.begin(client, url))
-    {
-
-        for (int i = 0; i < headerSize; i++)
-        {
-            http.addHeader(headerKeys[i], headerValues[i]);
-        }
-
-        int httpCode = http.sendRequest("DELETE", payload);
-
-        if (httpCode > 0)
-        {
-            response = http.getString();
-            http.end();
-            return response;
-        }
-        else
-        {
-            Serial.print("[ERROR] DELETE Request Failed, error: ");
-            Serial.println(http.errorToString(httpCode).c_str());
-        }
-        http.end();
-    }
-
-    else
-    {
-        Serial.println("[ERROR] Unable to connect to the server.");
-    }
-
-    // Clear serial buffer to avoid any residual data
-    this->clearSerialBuffer();
-
-    return response;
-}
-
-String FlipperHTTP::post(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize)
-{
-    WiFiClientSecure client;
-    client.setInsecure(); // Bypass certificate
-
-    HTTPClient http;
-    String response = "";
-
-    http.collectHeaders(headerKeys, headerSize);
-
-    if (http.begin(client, url))
-    {
-
-        for (int i = 0; i < headerSize; i++)
-        {
-            http.addHeader(headerKeys[i], headerValues[i]);
-        }
-
-        int httpCode = http.POST(payload);
-
-        if (httpCode > 0)
-        {
-            response = http.getString();
-            http.end();
-            return response;
-        }
-        else
-        {
-            Serial.print("[ERROR] POST Request Failed, error: ");
-            Serial.println(http.errorToString(httpCode).c_str());
-        }
-        http.end();
-    }
-
-    else
-    {
-        Serial.println("[ERROR] Unable to connect to the server.");
-    }
-
-    // Clear serial buffer to avoid any residual data
-    this->clearSerialBuffer();
-
-    return response;
-}
-
-String FlipperHTTP::post(String url, String payload)
-{
-    WiFiClientSecure client;
-    client.setInsecure(); // Bypass certificate
-
-    HTTPClient http;
-    String response = "";
-
-    if (http.begin(client, url))
-    {
-
-        int httpCode = http.POST(payload);
-
-        if (httpCode > 0)
-        {
-            response = http.getString();
-            http.end();
-            return response;
-        }
-        else
-        {
-            Serial.print("[ERROR] POST Request Failed, error: ");
-            Serial.println(http.errorToString(httpCode).c_str());
-        }
-        http.end();
-    }
-
-    else
-    {
-        Serial.println("[ERROR] Unable to connect to the server.");
-    }
-
-    // Clear serial buffer to avoid any residual data
-    this->clearSerialBuffer();
-
-    return response;
-}
-
-String FlipperHTTP::put(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize)
-{
-    WiFiClientSecure client;
-    client.setInsecure(); // Bypass certificate
-
-    HTTPClient http;
-    String response = "";
-
-    http.collectHeaders(headerKeys, headerSize);
-
-    if (http.begin(client, url))
-    {
-
-        for (int i = 0; i < headerSize; i++)
-        {
-            http.addHeader(headerKeys[i], headerValues[i]);
-        }
-
-        int httpCode = http.PUT(payload);
-
-        if (httpCode > 0)
-        {
-            response = http.getString();
-            http.end();
-            return response;
-        }
-        else
-        {
-            Serial.print("[ERROR] PUT Request Failed, error: ");
-            Serial.println(http.errorToString(httpCode).c_str());
-        }
-        http.end();
-    }
-
-    else
-    {
-        Serial.println("[ERROR] Unable to connect to the server.");
-    }
-
-    // Clear serial buffer to avoid any residual data
-    this->clearSerialBuffer();
-
-    return response;
-}
-
-String FlipperHTTP::put(String url, String payload)
-{
-    WiFiClientSecure client;
-    client.setInsecure(); // Bypass certificate
-
-    HTTPClient http;
-    String response = "";
-
-    if (http.begin(client, url))
-    {
-        int httpCode = http.PUT(payload);
-
-        if (httpCode > 0)
-        {
-            response = http.getString();
-            http.end();
-            return response;
-        }
-        else
-        {
-            Serial.print("[ERROR] PUT Request Failed, error: ");
-            Serial.println(http.errorToString(httpCode).c_str());
-        }
-        http.end();
-    }
-
-    else
-    {
-        Serial.println("[ERROR] Unable to connect to the server.");
-    }
-
-    // Clear serial buffer to avoid any residual data
-    this->clearSerialBuffer();
-
-    return response;
-}
-
-bool FlipperHTTP::get_bytes_to_file(String url, const char *headerKeys[], const char *headerValues[], int headerSize)
-{
-    WiFiClientSecure client;
-    client.setInsecure(); // Bypass certificate
-
-    HTTPClient http;
-
-    http.collectHeaders(headerKeys, headerSize);
-
-    if (http.begin(client, url))
-    {
-        for (int i = 0; i < headerSize; i++)
-        {
-            http.addHeader(headerKeys[i], headerValues[i]);
-        }
-
-        int httpCode = http.GET();
-        if (httpCode > 0)
-        {
-            Serial.println("[GET/SUCCESS]");
-
-            int len = http.getSize();
-            uint8_t buff[512] = {0};
-
-            WiFiClient *stream = http.getStreamPtr();
-
-            // Check available heap memory before starting
-            size_t freeHeap = ESP.getFreeHeap();
-            const size_t minHeapThreshold = 1024; // Minimum heap space to avoid overflow
-            if (freeHeap < minHeapThreshold)
-            {
-                Serial.println("[ERROR] Not enough memory to start processing the response.");
-                http.end();
-                return false;
-            }
-
-            // Stream data while connected and available
-            while (http.connected() && (len > 0 || len == -1))
-            {
-                size_t size = stream->available();
-                if (size)
-                {
-                    int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
-                    Serial.write(buff, c); // Write data to serial
-                    if (len > 0)
-                    {
-                        len -= c;
-                    }
-                }
-                delay(1); // Yield control to the system
-            }
-
-            freeHeap = ESP.getFreeHeap();
-            if (freeHeap < minHeapThreshold)
-            {
-                Serial.println("[ERROR] Not enough memory to continue processing the response.");
-                http.end();
-                return false;
-            }
-
-            // Flush the serial buffer to ensure all data is sent
-            http.end();
-            Serial.flush();
-            Serial.println();
-            Serial.println("[GET/END]");
-
-            return true;
-        }
-        else
-        {
-            Serial.printf("[ERROR] GET request failed with error: %s\n", http.errorToString(httpCode).c_str());
-        }
-        http.end();
-    }
-    else
-    {
-        Serial.println("[ERROR] Unable to connect to the server.");
-    }
-    return false;
-}
-
-bool FlipperHTTP::post_bytes_to_file(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize)
-{
-    WiFiClientSecure client;
-    client.setInsecure(); // Bypass certificate
-
-    HTTPClient http;
-
-    http.collectHeaders(headerKeys, headerSize);
-
-    if (http.begin(client, url))
-    {
-        for (int i = 0; i < headerSize; i++)
-        {
-            http.addHeader(headerKeys[i], headerValues[i]);
-        }
-
-        int httpCode = http.POST(payload);
-        if (httpCode > 0)
-        {
-            Serial.println("[POST/SUCCESS]");
-
-            int len = http.getSize(); // Get the response content length
-            uint8_t buff[512] = {0};  // Buffer for reading data
-
-            WiFiClient *stream = http.getStreamPtr();
-
-            // Check available heap memory before starting
-            size_t freeHeap = ESP.getFreeHeap();
-            const size_t minHeapThreshold = 1024; // Minimum heap space to avoid overflow
-            if (freeHeap < minHeapThreshold)
-            {
-                Serial.println("[ERROR] Not enough memory to start processing the response.");
-                http.end();
-                return false;
-            }
-
-            // Stream data while connected and available
-            while (http.connected() && (len > 0 || len == -1))
-            {
-                size_t size = stream->available();
-                if (size)
-                {
-                    int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
-                    Serial.write(buff, c); // Write data to serial
-                    if (len > 0)
-                    {
-                        len -= c;
-                    }
-                }
-                delay(1); // Yield control to the system
-            }
-
-            freeHeap = ESP.getFreeHeap();
-            if (freeHeap < minHeapThreshold)
-            {
-                Serial.println("[ERROR] Not enough memory to continue processing the response.");
-                http.end();
-                return false;
-            }
-
-            http.end();
-            // Flush the serial buffer to ensure all data is sent
-            Serial.flush();
-            Serial.println();
-            Serial.println("[POST/END]");
-
-            return true;
-        }
-        else
-        {
-            Serial.printf("[ERROR] POST request failed with error: %s\n", http.errorToString(httpCode).c_str());
-        }
-        http.end();
-    }
-    else
-    {
-        Serial.println("[ERROR] Unable to connect to the server.");
-    }
-    return false;
-}
-
-// Main loop for flipper-http.ino that handles all of the commands
-void FlipperHTTP::loop()
-{
-    // Check if there's incoming serial data
-    if (Serial.available() > 0)
-    {
-        // Read the incoming serial data until newline
-        String _data = this->readSerialLine();
-
-        if (_data.length() == 0)
-        {
-            // No complete command received
-            return;
-        }
-
-        this->ledStatus();
-
-        // print the available commands
-        if (_data.startsWith("[LIST]"))
-        {
-            Serial.println("[LIST],[PING], [REBOOT], [WIFI/IP], [WIFI/SCAN], [WIFI/SAVE], [WIFI/CONNECT], [WIFI/DISCONNECT], [WIFI/LIST], [GET], [GET/HTTP], [POST/HTTP], [PUT/HTTP], [DELETE/HTTP], [GET/BYTES], [POST/BYTES], [PARSE], [PARSE/ARRAY], [LED/ON], [LED/OFF], [IP/ADDRESS]");
-        }
-        // handle [LED/ON] command
-        else if (_data.startsWith("[LED/ON]"))
-        {
-            this->useLED = true;
-        }
-        // handle [LED/OFF] command
-        else if (_data.startsWith("[LED/OFF]"))
-        {
-            this->useLED = false;
-        }
-        // handle [IP/ADDRESS] command (local IP)
-        else if (_data.startsWith("[IP/ADDRESS]"))
-        {
-            Serial.println(this->getIPAddress());
-        }
-        // handle [WIFI/IP] command ip of connected wifi
-        else if (_data.startsWith("[WIFI/IP]"))
-        {
-            if (!this->isConnectedToWifi() && !this->connectToWifi())
-            {
-                Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-                this->ledOff();
-                return;
-            }
-            // Get Request
-            String jsonData = this->get("https://httpbin.org/get");
-            if (jsonData == "")
-            {
-                Serial.println("[ERROR] GET request failed or returned empty data.");
-                return;
-            }
-            DynamicJsonDocument doc(1024);
-            DeserializationError error = deserializeJson(doc, jsonData);
-            if (error)
-            {
-                Serial.print("[ERROR] Failed to parse JSON.");
-                this->ledOff();
-                return;
-            }
-            if (!doc.containsKey("origin"))
-            {
-                Serial.println("[ERROR] JSON does not contain origin.");
-                this->ledOff();
-                return;
-            }
-            Serial.println(doc["origin"].as<String>());
-        }
-        // Ping/Pong to see if board/flipper is connected
-        else if (_data.startsWith("[PING]"))
-        {
-            Serial.println("[PONG]");
-        }
-        // Handle [REBOOT] command
-        else if (_data.startsWith("[REBOOT]"))
-        {
-            this->useLED = true;
-            ESP.restart();
-        }
-        // scan for wifi networks
-        else if (_data.startsWith("[WIFI/SCAN]"))
-        {
-            Serial.println(this->scanWifiNetworks());
-            Serial.flush();
-        }
-        // Handle Wifi list command
-        else if (_data.startsWith("[WIFI/LIST]"))
-        {
-            File file = SPIFFS.open(settingsFilePath, FILE_READ);
-            if (!file)
-            {
-                Serial.println("[ERROR] Failed to open file for reading.");
-                return;
-            }
-
-            // Read the entire file content
-            String fileContent = file.readString();
-            file.close();
-
-            Serial.println(fileContent);
-            Serial.flush();
-        }
-        // Handle [WIFI/SAVE] command
-        else if (_data.startsWith("[WIFI/SAVE]"))
-        {
-            // Extract JSON data by removing the command part
-            String jsonData = _data.substring(strlen("[WIFI/SAVE]"));
-            jsonData.trim(); // Remove any leading/trailing whitespace
-
-            // Parse and save the settings
-            if (this->readSerialSettings(jsonData, true))
-            {
-                Serial.println("[SUCCESS] Wifi settings saved.");
-            }
-            else
-            {
-                Serial.println("[ERROR] Failed to save Wifi settings.");
-            }
-        }
-        // Handle [WIFI/CONNECT] command
-        else if (_data == "[WIFI/CONNECT]")
-        {
-            // Check if WiFi is already connected
-            if (!this->isConnectedToWifi())
-            {
-                // Attempt to connect to Wifi
-                if (this->connectToWifi())
-                {
-                    Serial.println("[SUCCESS] Connected to Wifi.");
-                }
-                else
-                {
-                    Serial.println("[ERROR] Failed to connect to Wifi.");
-                }
-            }
-            else
-            {
-                Serial.println("[INFO] Already connected to Wifi.");
-            }
-        }
-        // Handle [WIFI/DISCONNECT] command
-        else if (_data == "[WIFI/DISCONNECT]")
-        {
-            WiFi.disconnect(true);
-            Serial.println("[DISCONNECTED] Wifi has been disconnected.");
-        }
-        // Handle [GET] command
-        else if (_data.startsWith("[GET]"))
-        {
-
-            if (!this->isConnectedToWifi() && !this->connectToWifi())
-            {
-                Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-                this->ledOff();
-                return;
-            }
-            // Extract URL by removing the command part
-            String url = _data.substring(strlen("[GET]"));
-            url.trim();
-
-            // GET request
-            String getData = this->get(url);
-            if (getData != "")
-            {
-                Serial.println("[GET/SUCCESS] GET request successful.");
-                Serial.println(getData);
-                Serial.flush();
-                Serial.println();
-                Serial.println("[GET/END]");
-            }
-            else
-            {
-                Serial.println("[ERROR] GET request failed or returned empty data.");
-            }
-        }
-        // Handle [GET/HTTP] command
-        else if (_data.startsWith("[GET/HTTP]"))
-        {
-            if (!this->isConnectedToWifi() && !this->connectToWifi())
-            {
-                Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract the JSON by removing the command part
-            String jsonData = _data.substring(strlen("[GET/HTTP]"));
-            jsonData.trim();
-
-            DynamicJsonDocument doc(1024);
-            DeserializationError error = deserializeJson(doc, jsonData);
-
-            if (error)
-            {
-                Serial.print("[ERROR] Failed to parse JSON.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract values from JSON
-            if (!doc.containsKey("url"))
-            {
-                Serial.println("[ERROR] JSON does not contain url.");
-                this->ledOff();
-                return;
-            }
-            String url = doc["url"];
-
-            // Extract headers if available
-            const char *headerKeys[10];
-            const char *headerValues[10];
-            int headerSize = 0;
-
-            if (doc.containsKey("headers"))
-            {
-                JsonObject headers = doc["headers"];
-                for (JsonPair header : headers)
-                {
-                    headerKeys[headerSize] = header.key().c_str();
-                    headerValues[headerSize] = header.value();
-                    headerSize++;
-                }
-            }
-
-            // GET request
-            String getData = this->get(url, headerKeys, headerValues, headerSize);
-            if (getData != "")
-            {
-                Serial.println("[GET/SUCCESS] GET request successful.");
-                Serial.println(getData);
-                Serial.flush();
-                Serial.println();
-                Serial.println("[GET/END]");
-            }
-            else
-            {
-                Serial.println("[ERROR] GET request failed or returned empty data.");
-            }
-        }
-        // Handle [POST/HTTP] command
-        else if (_data.startsWith("[POST/HTTP]"))
-        {
-            if (!this->isConnectedToWifi() && !this->connectToWifi())
-            {
-                Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract the JSON by removing the command part
-            String jsonData = _data.substring(strlen("[POST/HTTP]"));
-            jsonData.trim();
-
-            DynamicJsonDocument doc(1024);
-            DeserializationError error = deserializeJson(doc, jsonData);
-
-            if (error)
-            {
-                Serial.print("[ERROR] Failed to parse JSON.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract values from JSON
-            if (!doc.containsKey("url") || !doc.containsKey("payload"))
-            {
-                Serial.println("[ERROR] JSON does not contain url or payload.");
-                this->ledOff();
-                return;
-            }
-            String url = doc["url"];
-            String payload = doc["payload"];
-
-            // Extract headers if available
-            const char *headerKeys[10];
-            const char *headerValues[10];
-            int headerSize = 0;
-
-            if (doc.containsKey("headers"))
-            {
-                JsonObject headers = doc["headers"];
-                for (JsonPair header : headers)
-                {
-                    headerKeys[headerSize] = header.key().c_str();
-                    headerValues[headerSize] = header.value();
-                    headerSize++;
-                }
-            }
-
-            // POST request
-            String postData = this->post(url, payload, headerKeys, headerValues, headerSize);
-            if (postData != "")
-            {
-                Serial.println("[POST/SUCCESS] POST request successful.");
-                Serial.println(postData);
-                Serial.flush();
-                Serial.println();
-                Serial.println("[POST/END]");
-            }
-            else
-            {
-                Serial.println("[ERROR] POST request failed or returned empty data.");
-            }
-        }
-        // Handle [PUT/HTTP] command
-        else if (_data.startsWith("[PUT/HTTP]"))
-        {
-            if (!this->isConnectedToWifi() && !this->connectToWifi())
-            {
-                Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract the JSON by removing the command part
-            String jsonData = _data.substring(strlen("[PUT/HTTP]"));
-            jsonData.trim();
-
-            DynamicJsonDocument doc(1024);
-            DeserializationError error = deserializeJson(doc, jsonData);
-
-            if (error)
-            {
-                Serial.print("[ERROR] Failed to parse JSON.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract values from JSON
-            if (!doc.containsKey("url") || !doc.containsKey("payload"))
-            {
-                Serial.println("[ERROR] JSON does not contain url or payload.");
-                this->ledOff();
-                return;
-            }
-            String url = doc["url"];
-            String payload = doc["payload"];
-
-            // Extract headers if available
-            const char *headerKeys[10];
-            const char *headerValues[10];
-            int headerSize = 0;
-
-            if (doc.containsKey("headers"))
-            {
-                JsonObject headers = doc["headers"];
-                for (JsonPair header : headers)
-                {
-                    headerKeys[headerSize] = header.key().c_str();
-                    headerValues[headerSize] = header.value();
-                    headerSize++;
-                }
-            }
-
-            // PUT request
-            String putData = this->put(url, payload, headerKeys, headerValues, headerSize);
-            if (putData != "")
-            {
-                Serial.println("[PUT/SUCCESS] PUT request successful.");
-                Serial.println(putData);
-                Serial.flush();
-                Serial.println();
-                Serial.println("[PUT/END]");
-            }
-            else
-            {
-                Serial.println("[ERROR] PUT request failed or returned empty data.");
-            }
-        }
-        // Handle [DELETE/HTTP] command
-        else if (_data.startsWith("[DELETE/HTTP]"))
-        {
-            if (!this->isConnectedToWifi() && !this->connectToWifi())
-            {
-                Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract the JSON by removing the command part
-            String jsonData = _data.substring(strlen("[DELETE/HTTP]"));
-            jsonData.trim();
-
-            DynamicJsonDocument doc(1024);
-            DeserializationError error = deserializeJson(doc, jsonData);
-
-            if (error)
-            {
-                Serial.print("[ERROR] Failed to parse JSON.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract values from JSON
-            if (!doc.containsKey("url") || !doc.containsKey("payload"))
-            {
-                Serial.println("[ERROR] JSON does not contain url or payload.");
-                this->ledOff();
-                return;
-            }
-            String url = doc["url"];
-            String payload = doc["payload"];
-
-            // Extract headers if available
-            const char *headerKeys[10];
-            const char *headerValues[10];
-            int headerSize = 0;
-
-            if (doc.containsKey("headers"))
-            {
-                JsonObject headers = doc["headers"];
-                for (JsonPair header : headers)
-                {
-                    headerKeys[headerSize] = header.key().c_str();
-                    headerValues[headerSize] = header.value();
-                    headerSize++;
-                }
-            }
-
-            // DELETE request
-            String deleteData = this->delete_request(url, payload, headerKeys, headerValues, headerSize);
-            if (deleteData != "")
-            {
-                Serial.println("[DELETE/SUCCESS] DELETE request successful.");
-                Serial.println(deleteData);
-                Serial.flush();
-                Serial.println();
-                Serial.println("[DELETE/END]");
-            }
-            else
-            {
-                Serial.println("[ERROR] DELETE request failed or returned empty data.");
-            }
-        }
-        // Handle [GET/BYTES]
-        else if (_data.startsWith("[GET/BYTES]"))
-        {
-            if (!this->isConnectedToWifi() && !this->connectToWifi())
-            {
-                Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract the JSON by removing the command part
-            String jsonData = _data.substring(strlen("[GET/BYTES]"));
-            jsonData.trim();
-
-            DynamicJsonDocument doc(1024);
-            DeserializationError error = deserializeJson(doc, jsonData);
-
-            if (error)
-            {
-                Serial.print("[ERROR] Failed to parse JSON.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract values from JSON
-            if (!doc.containsKey("url"))
-            {
-                Serial.println("[ERROR] JSON does not contain url.");
-                this->ledOff();
-                return;
-            }
-            String url = doc["url"];
-
-            // Extract headers if available
-            const char *headerKeys[10];
-            const char *headerValues[10];
-            int headerSize = 0;
-
-            if (doc.containsKey("headers"))
-            {
-                JsonObject headers = doc["headers"];
-                for (JsonPair header : headers)
-                {
-                    headerKeys[headerSize] = header.key().c_str();
-                    headerValues[headerSize] = header.value();
-                    headerSize++;
-                }
-            }
-
-            // GET request
-            if (!this->get_bytes_to_file(url, headerKeys, headerValues, headerSize))
-            {
-                Serial.println("[ERROR] GET request failed or returned empty data.");
-            }
-        }
-        // handle [POST/BYTES]
-        else if (_data.startsWith("[POST/BYTES]"))
-        {
-            if (!this->isConnectedToWifi() && !this->connectToWifi())
-            {
-                Serial.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract the JSON by removing the command part
-            String jsonData = _data.substring(strlen("[POST/BYTES]"));
-            jsonData.trim();
-
-            DynamicJsonDocument doc(1024);
-            DeserializationError error = deserializeJson(doc, jsonData);
-
-            if (error)
-            {
-                Serial.print("[ERROR] Failed to parse JSON.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract values from JSON
-            if (!doc.containsKey("url") || !doc.containsKey("payload"))
-            {
-                Serial.println("[ERROR] JSON does not contain url or payload.");
-                this->ledOff();
-                return;
-            }
-            String url = doc["url"];
-            String payload = doc["payload"];
-
-            // Extract headers if available
-            const char *headerKeys[10];
-            const char *headerValues[10];
-            int headerSize = 0;
-
-            if (doc.containsKey("headers"))
-            {
-                JsonObject headers = doc["headers"];
-                for (JsonPair header : headers)
-                {
-                    headerKeys[headerSize] = header.key().c_str();
-                    headerValues[headerSize] = header.value();
-                    headerSize++;
-                }
-            }
-
-            // POST request
-            if (!this->post_bytes_to_file(url, payload, headerKeys, headerValues, headerSize))
-            {
-                Serial.println("[ERROR] POST request failed or returned empty data.");
-            }
-        }
-        // Handle [PARSE] command
-        // the user will append the key to read from the json
-        // example: [PARSE]{"key":"name","json":{"name":"John Doe"}}
-        else if (_data.startsWith("[PARSE]"))
-        {
-            // Extract the JSON by removing the command part
-            String jsonData = _data.substring(strlen("[PARSE]"));
-            jsonData.trim();
-
-            DynamicJsonDocument doc(1024);
-            DeserializationError error = deserializeJson(doc, jsonData);
-
-            if (error)
-            {
-                Serial.print("[ERROR] Failed to parse JSON.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract values from JSON
-            if (!doc.containsKey("key") || !doc.containsKey("json"))
-            {
-                Serial.println("[ERROR] JSON does not contain key or json.");
-                this->ledOff();
-                return;
-            }
-            String key = doc["key"];
-            JsonObject json = doc["json"];
-
-            if (json.containsKey(key))
-            {
-                Serial.println(json[key].as<String>());
-            }
-            else
-            {
-                Serial.println("[ERROR] Key not found in JSON.");
-            }
-        }
-        // Handle [PARSE/ARRAY] command
-        // the user will append the key to read and the index of the array to get it's key from the json
-        // example: [PARSE/ARRAY]{"key":"name","index":"1","json":{"name":["John Doe","Jane Doe"]}}
-        // this would return Jane Doe
-        // and in this example it would return {"flavor": "red"}:
-        // example: [PARSE/ARRAY]{"key":"flavor","index":"1","json":{"name":[{"flavor": "blue"},{"flavor": "red"}]}}
-        else if (_data.startsWith("[PARSE/ARRAY]"))
-        {
-            // Extract the JSON by removing the command part
-            String jsonData = _data.substring(strlen("[PARSE/ARRAY]"));
-            jsonData.trim();
-
-            DynamicJsonDocument doc(1024);
-            DeserializationError error = deserializeJson(doc, jsonData);
-
-            if (error)
-            {
-                Serial.print("[ERROR] Failed to parse JSON.");
-                this->ledOff();
-                return;
-            }
-
-            // Extract values from JSON
-            if (!doc.containsKey("key") || !doc.containsKey("index") || !doc.containsKey("json"))
-            {
-                Serial.println("[ERROR] JSON does not contain key, index, or json.");
-                this->ledOff();
-                return;
-            }
-            String key = doc["key"];
-            int index = doc["index"];
-            JsonArray json = doc["json"];
-
-            if (json[index].containsKey(key))
-            {
-                Serial.println(json[index][key].as<String>());
-            }
-            else
-            {
-                Serial.println("[ERROR] Key not found in JSON.");
-            }
-        }
-
-        this->ledOff();
-    }
-}

+ 0 - 1483
assets/FlipperHTTP/Arduino/FlipperHTTPPico.h

@@ -1,1483 +0,0 @@
-/* FlipperHTTPPico.h for flipper-http-pico.ino (for the Rasberry Pi Pico W)
-Author: JBlanked
-Github: https://github.com/jblanked/WebCrawler-FlipperZero/tree/main/assets/FlipperHTTP
-Info: This library is a wrapper around the HTTPClient library and is used to communicate with the FlipperZero over serial.
-Created: 2024-10-24
-Updated: 2024-10-26
-
-Change Log:
-- 2024-10-24: Initial commit
-- 2024-10-25: Updated the readSerialLine method to use readStringUntil instead of reading char by char, and added Auto connect
-  - Reading char by char worked on the dev board but was missing chars on the Pico
-- 2024-10-26: Updated the saveWifiSettings and loadWifiSettings methods to save and load a list of wifi networks, and added [WIFI/LIST] command
-*/
-
-#include <WiFi.h>
-#include <HTTPClient.h>
-#include <WiFiClientSecure.h>
-#include <ArduinoJson.h>
-#include <Arduino.h>
-#include <LittleFS.h> // replacement for SPIFFS
-
-// Define UART parameters
-#define BAUD_RATE 115200
-#define PICO_LED LED_BUILTIN
-#define ON HIGH
-#define OFF LOW
-
-SerialPIO SerialPico(0, 1);
-
-class FlipperHTTP
-{
-public:
-  // Constructor
-  FlipperHTTP()
-  {
-  }
-
-  // Main methods for flipper-http.ino
-  void loop();
-  void setup()
-  {
-    SerialPico.begin(BAUD_RATE);
-
-    if (!LittleFS.begin())
-    {
-      SerialPico.println("An Error has occurred while mounting LittleFS. Attempting to format...");
-      if (LittleFS.format())
-      {
-        SerialPico.println("File system formatted successfully. Re-mounting...");
-        if (!LittleFS.begin())
-        {
-          SerialPico.println("Failed to re-mount LittleFS after formatting.");
-          delay(1000);
-          return;
-        }
-      }
-      else
-      {
-        SerialPico.println("File system formatting failed.");
-        delay(1000);
-        return;
-      }
-    }
-    this->useLED = true;
-    this->ledStart();
-    this->loadWifiSettings();
-    SerialPico.flush();
-  }
-
-  // HTTP Methods
-  String get(String url);
-  String get(String url, const char *headerKeys[], const char *headerValues[], int headerSize);
-  String post(String url, String payload);
-  String post(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize);
-  String put(String url, String payload);
-  String put(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize);
-  String delete_request(String url, String payload);
-  String delete_request(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize);
-
-  // stream data as bytes
-  bool get_bytes_to_file(String url, const char *headerKeys[], const char *headerValues[], int headerSize);
-  bool post_bytes_to_file(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize);
-
-  // Save and Load settings to and from SPIFFS
-  bool saveWifiSettings(String data);
-  bool loadWifiSettings();
-
-  // returns a string of all wifi networks
-  String scanWifiNetworks()
-  {
-    int n = WiFi.scanNetworks();
-    String networks = "";
-    for (int i = 0; i < n; ++i)
-    {
-      networks += WiFi.SSID(i);
-
-      if (i < n - 1)
-      {
-        networks += ", ";
-      }
-    }
-    return networks;
-  }
-
-  // Connect to Wifi using the loaded SSID and Password
-  bool connectToWifi();
-
-  // Check if the Dev Board is connected to Wifi
-  bool isConnectedToWifi() { return WiFi.status() == WL_CONNECTED; }
-
-  // Read serial data until newline character
-  String readSerialLine();
-
-  // Clear serial buffer to avoid any residual data
-  void clearSerialBuffer()
-  {
-    while (SerialPico.available() > 0)
-    {
-      SerialPico.read();
-    }
-  }
-
-  // Function to flash the LED
-  void ledAction(int timeout = 250)
-  {
-    digitalWrite(PICO_LED, ON);
-    delay(timeout);
-    digitalWrite(PICO_LED, OFF);
-    delay(timeout);
-  }
-
-  // Display LED sequence when Wifi Board is first connected to the Flipper
-  void ledStart()
-  {
-    // Initialize LED pin
-    pinMode(PICO_LED, OUTPUT);
-
-    ledAction();
-    ledAction();
-    ledAction();
-  }
-
-  // Starting LED (Green only)
-  void ledStatus()
-  {
-    if (this->useLED)
-    {
-      digitalWrite(PICO_LED, ON);
-    }
-  }
-
-  // Turn off all LEDs
-  void ledOff()
-  {
-    digitalWrite(PICO_LED, OFF);
-  }
-
-  // get IP addresss
-  String getIPAddress()
-  {
-    return WiFi.localIP().toString();
-  }
-
-private:
-  const char *settingsFilePath = "/flipper-http.json"; // Path to the settings file in the SPIFFS file system
-  char loadedSSID[64] = {0};                           // Variable to store SSID
-  char loadedPassword[64] = {0};                       // Variable to store password
-  bool useLED = true;                                  // Variable to control LED usage
-
-  bool readSerialSettings(String receivedData, bool connectAfterSave);
-};
-
-//  Connect to Wifi using the loaded SSID and Password
-bool FlipperHTTP::connectToWifi()
-{
-  if (String(loadedSSID) == "" || String(loadedPassword) == "")
-  {
-    SerialPico.println("[ERROR] WiFi SSID or Password is empty.");
-    return false;
-  }
-
-  WiFi.disconnect(true); // Ensure WiFi is disconnected before reconnecting
-  WiFi.begin(loadedSSID, loadedPassword);
-
-  int i = 0;
-  while (!this->isConnectedToWifi() && i < 20)
-  {
-    delay(500);
-    i++;
-    SerialPico.print(".");
-  }
-  SerialPico.println(); // Move to next line after dots
-
-  if (this->isConnectedToWifi())
-  {
-    SerialPico.println("[SUCCESS] Successfully connected to Wifi.");
-    return true;
-  }
-  else
-  {
-    SerialPico.println("[ERROR] Failed to connect to Wifi.");
-    return false;
-  }
-}
-
-// Save WiFi settings to LittleFS
-bool FlipperHTTP::saveWifiSettings(String jsonData)
-{
-  DynamicJsonDocument doc(1024);
-  DeserializationError error = deserializeJson(doc, jsonData);
-
-  if (error)
-  {
-    SerialPico.println("[ERROR] Failed to parse JSON data.");
-    return false;
-  }
-
-  const char *newSSID = doc["ssid"];
-  const char *newPassword = doc["password"];
-
-  // Load existing settings if they exist
-  DynamicJsonDocument existingDoc(2048);
-  File file = LittleFS.open(settingsFilePath, "r");
-  if (file)
-  {
-    deserializeJson(existingDoc, file);
-    file.close();
-  }
-
-  // Check if SSID is already saved
-  bool found = false;
-  for (JsonObject wifi : existingDoc["wifi_list"].as<JsonArray>())
-  {
-    if (wifi["ssid"] == newSSID)
-    {
-      found = true;
-      break;
-    }
-  }
-
-  // Add new SSID and password if not found
-  if (!found)
-  {
-    JsonArray wifiList = existingDoc["wifi_list"].to<JsonArray>();
-    JsonObject newWifi = wifiList.createNestedObject();
-    newWifi["ssid"] = newSSID;
-    newWifi["password"] = newPassword;
-
-    // Save updated list to file
-    file = LittleFS.open(settingsFilePath, "w");
-    if (!file)
-    {
-      SerialPico.println("[ERROR] Failed to open file for writing.");
-      return false;
-    }
-
-    serializeJson(existingDoc, file);
-    file.close();
-  }
-
-  SerialPico.println("[SUCCESS] Settings saved to LittleFS.");
-  return true;
-}
-
-bool FlipperHTTP::loadWifiSettings()
-{
-  File file = LittleFS.open(settingsFilePath, "r");
-  if (!file)
-  {
-    return false;
-  }
-
-  String fileContent = file.readString();
-  file.close();
-
-  DynamicJsonDocument doc(2048);
-  DeserializationError error = deserializeJson(doc, fileContent);
-
-  if (error)
-  {
-    return false;
-  }
-
-  JsonArray wifiList = doc["wifi_list"].as<JsonArray>();
-  for (JsonObject wifi : wifiList)
-  {
-    const char *ssid = wifi["ssid"];
-    const char *password = wifi["password"];
-
-    strlcpy(loadedSSID, ssid, sizeof(loadedSSID));
-    strlcpy(loadedPassword, password, sizeof(loadedPassword));
-
-    WiFi.begin(ssid, password);
-
-    int attempts = 0;
-    while (!this->isConnectedToWifi() && attempts < 4) // 2 seconds total, 500ms delay each
-    {
-      delay(500);
-      attempts++;
-      SerialPico.print(".");
-    }
-
-    if (this->isConnectedToWifi())
-    {
-      return true;
-    }
-  }
-  return false;
-}
-String FlipperHTTP::readSerialLine()
-{
-  String receivedData = "";
-
-  // this worked on dev board but even with delay changes, it was missing chars
-  // while (SerialPico.available() > 0)
-  // {
-  //   char incomingChar = SerialPico.read();
-  //   if (incomingChar == '\n')
-  //   {
-  //     break;
-  //   }
-  //   receivedData += incomingChar;
-  //   delay(5); // Minimal delay to allow buffer to fill
-  // }
-  receivedData = SerialPico.readStringUntil('\n');
-
-  receivedData.trim(); // Remove any leading/trailing whitespace
-
-  return receivedData;
-}
-
-bool FlipperHTTP::readSerialSettings(String receivedData, bool connectAfterSave)
-{
-  DynamicJsonDocument doc(1024);
-  DeserializationError error = deserializeJson(doc, receivedData);
-
-  if (error)
-  {
-    SerialPico.print("[ERROR] Failed to parse JSON: ");
-    SerialPico.println(error.c_str());
-    return false;
-  }
-
-  // Extract values from JSON
-  if (doc.containsKey("ssid") && doc.containsKey("password"))
-  {
-    strlcpy(loadedSSID, doc["ssid"], sizeof(loadedSSID));
-    strlcpy(loadedPassword, doc["password"], sizeof(loadedPassword));
-  }
-  else
-  {
-    SerialPico.println("[ERROR] JSON does not contain ssid and password.");
-    return false;
-  }
-
-  // Save to SPIFFS
-  if (!this->saveWifiSettings(receivedData))
-  {
-    SerialPico.println("[ERROR] Failed to save settings to file.");
-    return false;
-  }
-
-  // Attempt to reconnect with new settings
-  if (connectAfterSave && this->connectToWifi())
-  {
-    SerialPico.println("[SUCCESS] Connected to the new Wifi network.");
-  }
-
-  return true;
-}
-
-String FlipperHTTP::get(String url)
-{
-  WiFiClientSecure client;
-  client.setInsecure(); // Bypass certificate validation
-
-  HTTPClient http;
-  String payload = "";
-
-  if (http.begin(client, url))
-  {
-    int httpCode = http.GET();
-
-    if (httpCode > 0)
-    {
-      payload = http.getString();
-      http.end();
-      return payload;
-    }
-    else
-    {
-      SerialPico.print("[ERROR] GET Request Failed, error: ");
-      SerialPico.println(http.errorToString(httpCode).c_str());
-    }
-    http.end();
-  }
-  else
-  {
-    SerialPico.println("[ERROR] Unable to connect to the server.");
-  }
-
-  // Clear serial buffer to avoid any residual data
-  this->clearSerialBuffer();
-
-  return payload;
-}
-
-String FlipperHTTP::get(String url, const char *headerKeys[], const char *headerValues[], int headerSize)
-{
-  WiFiClientSecure client;
-  client.setInsecure(); // Bypass certificate
-
-  HTTPClient http;
-  String payload = "";
-
-  http.collectHeaders(headerKeys, headerSize);
-
-  if (http.begin(client, url))
-  {
-
-    for (int i = 0; i < headerSize; i++)
-    {
-      http.addHeader(headerKeys[i], headerValues[i]);
-    }
-
-    int httpCode = http.GET();
-
-    if (httpCode > 0)
-    {
-      payload = http.getString();
-      http.end();
-      return payload;
-    }
-    else
-    {
-      SerialPico.print("[ERROR] GET Request Failed, error: ");
-      SerialPico.println(http.errorToString(httpCode).c_str());
-    }
-    http.end();
-  }
-  else
-  {
-    SerialPico.println("[ERROR] Unable to connect to the server.");
-  }
-
-  // Clear serial buffer to avoid any residual data
-  this->clearSerialBuffer();
-
-  return payload;
-}
-
-String FlipperHTTP::delete_request(String url, String payload)
-{
-  WiFiClientSecure client;
-  client.setInsecure(); // Bypass certificate
-
-  HTTPClient http;
-  String response = "";
-
-  if (http.begin(client, url))
-  {
-    int httpCode = http.sendRequest("DELETE", payload);
-
-    if (httpCode > 0)
-    {
-      response = http.getString();
-      http.end();
-      return response;
-    }
-    else
-    {
-      SerialPico.print("[ERROR] DELETE Request Failed, error: ");
-      SerialPico.println(http.errorToString(httpCode).c_str());
-    }
-    http.end();
-  }
-
-  else
-  {
-    SerialPico.println("[ERROR] Unable to connect to the server.");
-  }
-
-  // Clear serial buffer to avoid any residual data
-  this->clearSerialBuffer();
-
-  return response;
-}
-
-String FlipperHTTP::delete_request(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize)
-{
-  WiFiClientSecure client;
-  client.setInsecure(); // Bypass certificate
-
-  HTTPClient http;
-  String response = "";
-
-  http.collectHeaders(headerKeys, headerSize);
-
-  if (http.begin(client, url))
-  {
-
-    for (int i = 0; i < headerSize; i++)
-    {
-      http.addHeader(headerKeys[i], headerValues[i]);
-    }
-
-    int httpCode = http.sendRequest("DELETE", payload);
-
-    if (httpCode > 0)
-    {
-      response = http.getString();
-      http.end();
-      return response;
-    }
-    else
-    {
-      SerialPico.print("[ERROR] DELETE Request Failed, error: ");
-      SerialPico.println(http.errorToString(httpCode).c_str());
-    }
-    http.end();
-  }
-
-  else
-  {
-    SerialPico.println("[ERROR] Unable to connect to the server.");
-  }
-
-  // Clear serial buffer to avoid any residual data
-  this->clearSerialBuffer();
-
-  return response;
-}
-
-String FlipperHTTP::post(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize)
-{
-  WiFiClientSecure client;
-  client.setInsecure(); // Bypass certificate
-
-  HTTPClient http;
-  String response = "";
-
-  http.collectHeaders(headerKeys, headerSize);
-
-  if (http.begin(client, url))
-  {
-
-    for (int i = 0; i < headerSize; i++)
-    {
-      http.addHeader(headerKeys[i], headerValues[i]);
-    }
-
-    int httpCode = http.POST(payload);
-
-    if (httpCode > 0)
-    {
-      response = http.getString();
-      http.end();
-      return response;
-    }
-    else
-    {
-      SerialPico.print("[ERROR] POST Request Failed, error: ");
-      SerialPico.println(http.errorToString(httpCode).c_str());
-    }
-    http.end();
-  }
-
-  else
-  {
-    SerialPico.println("[ERROR] Unable to connect to the server.");
-  }
-
-  // Clear serial buffer to avoid any residual data
-  this->clearSerialBuffer();
-
-  return response;
-}
-
-String FlipperHTTP::post(String url, String payload)
-{
-  WiFiClientSecure client;
-  client.setInsecure(); // Bypass certificate
-
-  HTTPClient http;
-  String response = "";
-
-  if (http.begin(client, url))
-  {
-
-    int httpCode = http.POST(payload);
-
-    if (httpCode > 0)
-    {
-      response = http.getString();
-      http.end();
-      return response;
-    }
-    else
-    {
-      SerialPico.print("[ERROR] POST Request Failed, error: ");
-      SerialPico.println(http.errorToString(httpCode).c_str());
-    }
-    http.end();
-  }
-
-  else
-  {
-    SerialPico.println("[ERROR] Unable to connect to the server.");
-  }
-
-  // Clear serial buffer to avoid any residual data
-  this->clearSerialBuffer();
-
-  return response;
-}
-
-String FlipperHTTP::put(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize)
-{
-  WiFiClientSecure client;
-  client.setInsecure(); // Bypass certificate
-
-  HTTPClient http;
-  String response = "";
-
-  http.collectHeaders(headerKeys, headerSize);
-
-  if (http.begin(client, url))
-  {
-
-    for (int i = 0; i < headerSize; i++)
-    {
-      http.addHeader(headerKeys[i], headerValues[i]);
-    }
-
-    int httpCode = http.PUT(payload);
-
-    if (httpCode > 0)
-    {
-      response = http.getString();
-      http.end();
-      return response;
-    }
-    else
-    {
-      SerialPico.print("[ERROR] PUT Request Failed, error: ");
-      SerialPico.println(http.errorToString(httpCode).c_str());
-    }
-    http.end();
-  }
-
-  else
-  {
-    SerialPico.println("[ERROR] Unable to connect to the server.");
-  }
-
-  // Clear serial buffer to avoid any residual data
-  this->clearSerialBuffer();
-
-  return response;
-}
-
-String FlipperHTTP::put(String url, String payload)
-{
-  WiFiClientSecure client;
-  client.setInsecure(); // Bypass certificate
-
-  HTTPClient http;
-  String response = "";
-
-  if (http.begin(client, url))
-  {
-    int httpCode = http.PUT(payload);
-
-    if (httpCode > 0)
-    {
-      response = http.getString();
-      http.end();
-      return response;
-    }
-    else
-    {
-      SerialPico.print("[ERROR] PUT Request Failed, error: ");
-      SerialPico.println(http.errorToString(httpCode).c_str());
-    }
-    http.end();
-  }
-
-  else
-  {
-    SerialPico.println("[ERROR] Unable to connect to the server.");
-  }
-
-  // Clear serial buffer to avoid any residual data
-  this->clearSerialBuffer();
-
-  return response;
-}
-
-bool FlipperHTTP::get_bytes_to_file(String url, const char *headerKeys[], const char *headerValues[], int headerSize)
-{
-  WiFiClientSecure client;
-  client.setInsecure(); // Bypass certificate
-
-  HTTPClient http;
-
-  http.collectHeaders(headerKeys, headerSize);
-
-  if (http.begin(client, url))
-  {
-    for (int i = 0; i < headerSize; i++)
-    {
-      http.addHeader(headerKeys[i], headerValues[i]);
-    }
-
-    int httpCode = http.GET();
-    if (httpCode > 0)
-    {
-      SerialPico.println("[GET/SUCCESS]");
-
-      int len = http.getSize();
-      uint8_t buff[512] = {0};
-
-      WiFiClient *stream = http.getStreamPtr();
-
-      // Check available heap memory before starting
-      // size_t freeHeap = ESP.getFreeHeap();
-      // const size_t minHeapThreshold = 1024; // Minimum heap space to avoid overflow
-      // if (freeHeap < minHeapThreshold)
-      // {
-      //   SerialPico.println("[ERROR] Not enough memory to start processing the response.");
-      //   http.end();
-      //   return false;
-      // }
-
-      // Stream data while connected and available
-      while (http.connected() && (len > 0 || len == -1))
-      {
-        size_t size = stream->available();
-        if (size)
-        {
-          int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
-          SerialPico.write(buff, c); // Write data to serial
-          if (len > 0)
-          {
-            len -= c;
-          }
-        }
-        delay(1); // Yield control to the system
-      }
-
-      // freeHeap = ESP.getFreeHeap();
-      // if (freeHeap < minHeapThreshold)
-      // {
-      //   SerialPico.println("[ERROR] Not enough memory to continue processing the response.");
-      //   http.end();
-      //   return false;
-      // }
-
-      // Flush the serial buffer to ensure all data is sent
-      http.end();
-      SerialPico.flush();
-      SerialPico.println();
-      SerialPico.println("[GET/END]");
-
-      return true;
-    }
-    else
-    {
-      SerialPico.printf("[ERROR] GET request failed with error: %s\n", http.errorToString(httpCode).c_str());
-    }
-    http.end();
-  }
-  else
-  {
-    SerialPico.println("[ERROR] Unable to connect to the server.");
-  }
-  return false;
-}
-
-bool FlipperHTTP::post_bytes_to_file(String url, String payload, const char *headerKeys[], const char *headerValues[], int headerSize)
-{
-  WiFiClientSecure client;
-  client.setInsecure(); // Bypass certificate
-
-  HTTPClient http;
-
-  http.collectHeaders(headerKeys, headerSize);
-
-  if (http.begin(client, url))
-  {
-    for (int i = 0; i < headerSize; i++)
-    {
-      http.addHeader(headerKeys[i], headerValues[i]);
-    }
-
-    int httpCode = http.POST(payload);
-    if (httpCode > 0)
-    {
-      SerialPico.println("[POST/SUCCESS]");
-
-      int len = http.getSize(); // Get the response content length
-      uint8_t buff[512] = {0};  // Buffer for reading data
-
-      WiFiClient *stream = http.getStreamPtr();
-
-      // Check available heap memory before starting
-      // size_t freeHeap = ESP.getFreeHeap();
-      // const size_t minHeapThreshold = 1024; // Minimum heap space to avoid overflow
-      // if (freeHeap < minHeapThreshold)
-      // {
-      //   SerialPico.println("[ERROR] Not enough memory to start processing the response.");
-      //   http.end();
-      //   return false;
-      // }
-
-      // Stream data while connected and available
-      while (http.connected() && (len > 0 || len == -1))
-      {
-        size_t size = stream->available();
-        if (size)
-        {
-          int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
-          SerialPico.write(buff, c); // Write data to serial
-          if (len > 0)
-          {
-            len -= c;
-          }
-        }
-        delay(1); // Yield control to the system
-      }
-
-      // freeHeap = ESP.getFreeHeap();
-      // if (freeHeap < minHeapThreshold)
-      // {
-      //   SerialPico.println("[ERROR] Not enough memory to continue processing the response.");
-      //   http.end();
-      //   return false;
-      // }
-
-      http.end();
-      // Flush the serial buffer to ensure all data is sent
-      SerialPico.flush();
-      SerialPico.println();
-      SerialPico.println("[POST/END]");
-
-      return true;
-    }
-    else
-    {
-      SerialPico.printf("[ERROR] POST request failed with error: %s\n", http.errorToString(httpCode).c_str());
-    }
-    http.end();
-  }
-  else
-  {
-    SerialPico.println("[ERROR] Unable to connect to the server.");
-  }
-  return false;
-}
-
-// Main loop for flipper-http.ino that handles all of the commands
-void FlipperHTTP::loop()
-{
-  // Check if there's incoming serial data
-  if (SerialPico.available() > 0)
-  {
-    // Read the incoming serial data until newline
-    String _data = this->readSerialLine();
-
-    this->ledStatus();
-
-    // print the available commands
-    if (_data.startsWith("[LIST]"))
-    {
-      SerialPico.println("[LIST],[PING], [REBOOT], [WIFI/IP], [WIFI/SCAN], [WIFI/SAVE], [WIFI/CONNECT], [WIFI/DISCONNECT], [WIFI/LIST], [GET], [GET/HTTP], [POST/HTTP], [PUT/HTTP], [DELETE/HTTP], [GET/BYTES], [POST/BYTES], [PARSE], [PARSE/ARRAY], [LED/ON], [LED/OFF], [IP/ADDRESS]");
-    }
-    // handle [LED/ON] command
-    else if (_data.startsWith("[LED/ON]"))
-    {
-      this->useLED = true;
-    }
-    // handle [LED/OFF] command
-    else if (_data.startsWith("[LED/OFF]"))
-    {
-      this->useLED = false;
-    }
-    // handle [IP/ADDRESS] command (local IP)
-    else if (_data.startsWith("[IP/ADDRESS]"))
-    {
-      SerialPico.println(this->getIPAddress());
-    }
-    // handle [WIFI/IP] command ip of connected wifi
-    else if (_data.startsWith("[WIFI/IP]"))
-    {
-      if (!this->isConnectedToWifi() && !this->connectToWifi())
-      {
-        SerialPico.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-        this->ledOff();
-        return;
-      }
-      // Get Request
-      String jsonData = this->get("https://httpbin.org/get");
-      if (jsonData == "")
-      {
-        SerialPico.println("[ERROR] GET request failed or returned empty data.");
-        return;
-      }
-      DynamicJsonDocument doc(1024);
-      DeserializationError error = deserializeJson(doc, jsonData);
-      if (error)
-      {
-        SerialPico.print("[ERROR] Failed to parse JSON.");
-        this->ledOff();
-        return;
-      }
-      if (!doc.containsKey("origin"))
-      {
-        SerialPico.println("[ERROR] JSON does not contain origin.");
-        this->ledOff();
-        return;
-      }
-      SerialPico.println(doc["origin"].as<String>());
-    }
-    // Ping/Pong to see if board/flipper is connected
-    else if (_data.startsWith("[PING]"))
-    {
-      SerialPico.println("[PONG]");
-    }
-    // Handle [REBOOT] command
-    else if (_data.startsWith("[REBOOT]"))
-    {
-      this->useLED = true;
-      // ESP.restart();
-    }
-    // scan for wifi networks
-    else if (_data.startsWith("[WIFI/SCAN]"))
-    {
-      SerialPico.println(this->scanWifiNetworks());
-      SerialPico.flush();
-    }
-    // Handle Wifi list command
-    else if (_data.startsWith("[WIFI/LIST]"))
-    {
-      File file = LittleFS.open(settingsFilePath, "r");
-      if (!file)
-      {
-        SerialPico.println("[ERROR] Failed to open file for reading.");
-        return;
-      }
-
-      String fileContent = file.readString();
-      file.close();
-
-      SerialPico.println(fileContent);
-      SerialPico.flush();
-    }
-    // Handle [WIFI/SAVE] command
-    else if (_data.startsWith("[WIFI/SAVE]"))
-    {
-      // Extract JSON data by removing the command part
-      String jsonData = _data.substring(strlen("[WIFI/SAVE]"));
-      jsonData.trim(); // Remove any leading/trailing whitespace
-
-      // Parse and save the settings
-      if (this->readSerialSettings(jsonData, true))
-      {
-        SerialPico.println("[SUCCESS] Wifi settings saved.");
-      }
-      else
-      {
-        SerialPico.println("[ERROR] Failed to save Wifi settings.");
-      }
-    }
-    // Handle [WIFI/CONNECT] command
-    else if (_data == "[WIFI/CONNECT]")
-    {
-      // Check if WiFi is already connected
-      if (!this->isConnectedToWifi())
-      {
-        // Attempt to connect to Wifi
-        if (this->connectToWifi())
-        {
-          SerialPico.println("[SUCCESS] Connected to Wifi.");
-        }
-        else
-        {
-          SerialPico.println("[ERROR] Failed to connect to Wifi.");
-        }
-      }
-      else
-      {
-        SerialPico.println("[INFO] Already connected to Wifi.");
-      }
-    }
-    // Handle [WIFI/DISCONNECT] command
-    else if (_data == "[WIFI/DISCONNECT]")
-    {
-      WiFi.disconnect(true);
-      SerialPico.println("[DISCONNECTED] Wifi has been disconnected.");
-    }
-    // Handle [GET] command
-    else if (_data.startsWith("[GET]"))
-    {
-
-      if (!this->isConnectedToWifi() && !this->connectToWifi())
-      {
-        SerialPico.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-        this->ledOff();
-        return;
-      }
-      // Extract URL by removing the command part
-      String url = _data.substring(strlen("[GET]"));
-      url.trim();
-
-      // GET request
-      String getData = this->get(url);
-      if (getData != "")
-      {
-        SerialPico.println("[GET/SUCCESS] GET request successful.");
-        SerialPico.println(getData);
-        SerialPico.flush();
-        SerialPico.println();
-        SerialPico.println("[GET/END]");
-      }
-      else
-      {
-        SerialPico.println("[ERROR] GET request failed or returned empty data.");
-      }
-    }
-    // Handle [GET/HTTP] command
-    else if (_data.startsWith("[GET/HTTP]"))
-    {
-      if (!this->isConnectedToWifi() && !this->connectToWifi())
-      {
-        SerialPico.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract the JSON by removing the command part
-      String jsonData = _data.substring(strlen("[GET/HTTP]"));
-      jsonData.trim();
-
-      DynamicJsonDocument doc(1024);
-      DeserializationError error = deserializeJson(doc, jsonData);
-
-      if (error)
-      {
-        SerialPico.print("[ERROR] Failed to parse JSON.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract values from JSON
-      if (!doc.containsKey("url"))
-      {
-        SerialPico.println("[ERROR] JSON does not contain url.");
-        this->ledOff();
-        return;
-      }
-      String url = doc["url"];
-
-      // Extract headers if available
-      const char *headerKeys[10];
-      const char *headerValues[10];
-      int headerSize = 0;
-
-      if (doc.containsKey("headers"))
-      {
-        JsonObject headers = doc["headers"];
-        for (JsonPair header : headers)
-        {
-          headerKeys[headerSize] = header.key().c_str();
-          headerValues[headerSize] = header.value();
-          headerSize++;
-        }
-      }
-
-      // GET request
-      String getData = this->get(url, headerKeys, headerValues, headerSize);
-      if (getData != "")
-      {
-        SerialPico.println("[GET/SUCCESS] GET request successful.");
-        SerialPico.println(getData);
-        SerialPico.flush();
-        SerialPico.println();
-        SerialPico.println("[GET/END]");
-      }
-      else
-      {
-        SerialPico.println("[ERROR] GET request failed or returned empty data.");
-      }
-    }
-    // Handle [POST/HTTP] command
-    else if (_data.startsWith("[POST/HTTP]"))
-    {
-      if (!this->isConnectedToWifi() && !this->connectToWifi())
-      {
-        SerialPico.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract the JSON by removing the command part
-      String jsonData = _data.substring(strlen("[POST/HTTP]"));
-      jsonData.trim();
-
-      DynamicJsonDocument doc(1024);
-      DeserializationError error = deserializeJson(doc, jsonData);
-
-      if (error)
-      {
-        SerialPico.print("[ERROR] Failed to parse JSON.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract values from JSON
-      if (!doc.containsKey("url") || !doc.containsKey("payload"))
-      {
-        SerialPico.println("[ERROR] JSON does not contain url or payload.");
-        this->ledOff();
-        return;
-      }
-      String url = doc["url"];
-      String payload = doc["payload"];
-
-      // Extract headers if available
-      const char *headerKeys[10];
-      const char *headerValues[10];
-      int headerSize = 0;
-
-      if (doc.containsKey("headers"))
-      {
-        JsonObject headers = doc["headers"];
-        for (JsonPair header : headers)
-        {
-          headerKeys[headerSize] = header.key().c_str();
-          headerValues[headerSize] = header.value();
-          headerSize++;
-        }
-      }
-
-      // POST request
-      String postData = this->post(url, payload, headerKeys, headerValues, headerSize);
-      if (postData != "")
-      {
-        SerialPico.println("[POST/SUCCESS] POST request successful.");
-        SerialPico.println(postData);
-        SerialPico.flush();
-        SerialPico.println();
-        SerialPico.println("[POST/END]");
-      }
-      else
-      {
-        SerialPico.println("[ERROR] POST request failed or returned empty data.");
-      }
-    }
-    // Handle [PUT/HTTP] command
-    else if (_data.startsWith("[PUT/HTTP]"))
-    {
-      if (!this->isConnectedToWifi() && !this->connectToWifi())
-      {
-        SerialPico.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract the JSON by removing the command part
-      String jsonData = _data.substring(strlen("[PUT/HTTP]"));
-      jsonData.trim();
-
-      DynamicJsonDocument doc(1024);
-      DeserializationError error = deserializeJson(doc, jsonData);
-
-      if (error)
-      {
-        SerialPico.print("[ERROR] Failed to parse JSON.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract values from JSON
-      if (!doc.containsKey("url") || !doc.containsKey("payload"))
-      {
-        SerialPico.println("[ERROR] JSON does not contain url or payload.");
-        this->ledOff();
-        return;
-      }
-      String url = doc["url"];
-      String payload = doc["payload"];
-
-      // Extract headers if available
-      const char *headerKeys[10];
-      const char *headerValues[10];
-      int headerSize = 0;
-
-      if (doc.containsKey("headers"))
-      {
-        JsonObject headers = doc["headers"];
-        for (JsonPair header : headers)
-        {
-          headerKeys[headerSize] = header.key().c_str();
-          headerValues[headerSize] = header.value();
-          headerSize++;
-        }
-      }
-
-      // PUT request
-      String putData = this->put(url, payload, headerKeys, headerValues, headerSize);
-      if (putData != "")
-      {
-        SerialPico.println("[PUT/SUCCESS] PUT request successful.");
-        SerialPico.println(putData);
-        SerialPico.flush();
-        SerialPico.println();
-        SerialPico.println("[PUT/END]");
-      }
-      else
-      {
-        SerialPico.println("[ERROR] PUT request failed or returned empty data.");
-      }
-    }
-    // Handle [DELETE/HTTP] command
-    else if (_data.startsWith("[DELETE/HTTP]"))
-    {
-      if (!this->isConnectedToWifi() && !this->connectToWifi())
-      {
-        SerialPico.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract the JSON by removing the command part
-      String jsonData = _data.substring(strlen("[DELETE/HTTP]"));
-      jsonData.trim();
-
-      DynamicJsonDocument doc(1024);
-      DeserializationError error = deserializeJson(doc, jsonData);
-
-      if (error)
-      {
-        SerialPico.print("[ERROR] Failed to parse JSON.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract values from JSON
-      if (!doc.containsKey("url") || !doc.containsKey("payload"))
-      {
-        SerialPico.println("[ERROR] JSON does not contain url or payload.");
-        this->ledOff();
-        return;
-      }
-      String url = doc["url"];
-      String payload = doc["payload"];
-
-      // Extract headers if available
-      const char *headerKeys[10];
-      const char *headerValues[10];
-      int headerSize = 0;
-
-      if (doc.containsKey("headers"))
-      {
-        JsonObject headers = doc["headers"];
-        for (JsonPair header : headers)
-        {
-          headerKeys[headerSize] = header.key().c_str();
-          headerValues[headerSize] = header.value();
-          headerSize++;
-        }
-      }
-
-      // DELETE request
-      String deleteData = this->delete_request(url, payload, headerKeys, headerValues, headerSize);
-      if (deleteData != "")
-      {
-        SerialPico.println("[DELETE/SUCCESS] DELETE request successful.");
-        SerialPico.println(deleteData);
-        SerialPico.flush();
-        SerialPico.println();
-        SerialPico.println("[DELETE/END]");
-      }
-      else
-      {
-        SerialPico.println("[ERROR] DELETE request failed or returned empty data.");
-      }
-    }
-    // Handle [GET/BYTES]
-    else if (_data.startsWith("[GET/BYTES]"))
-    {
-      if (!this->isConnectedToWifi() && !this->connectToWifi())
-      {
-        SerialPico.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract the JSON by removing the command part
-      String jsonData = _data.substring(strlen("[GET/BYTES]"));
-      jsonData.trim();
-
-      DynamicJsonDocument doc(1024);
-      DeserializationError error = deserializeJson(doc, jsonData);
-
-      if (error)
-      {
-        SerialPico.print("[ERROR] Failed to parse JSON.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract values from JSON
-      if (!doc.containsKey("url"))
-      {
-        SerialPico.println("[ERROR] JSON does not contain url.");
-        this->ledOff();
-        return;
-      }
-      String url = doc["url"];
-
-      // Extract headers if available
-      const char *headerKeys[10];
-      const char *headerValues[10];
-      int headerSize = 0;
-
-      if (doc.containsKey("headers"))
-      {
-        JsonObject headers = doc["headers"];
-        for (JsonPair header : headers)
-        {
-          headerKeys[headerSize] = header.key().c_str();
-          headerValues[headerSize] = header.value();
-          headerSize++;
-        }
-      }
-
-      // GET request
-      if (!this->get_bytes_to_file(url, headerKeys, headerValues, headerSize))
-      {
-        SerialPico.println("[ERROR] GET request failed or returned empty data.");
-      }
-    }
-    // handle [POST/BYTES]
-    else if (_data.startsWith("[POST/BYTES]"))
-    {
-      if (!this->isConnectedToWifi() && !this->connectToWifi())
-      {
-        SerialPico.println("[ERROR] Not connected to Wifi. Failed to reconnect.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract the JSON by removing the command part
-      String jsonData = _data.substring(strlen("[POST/BYTES]"));
-      jsonData.trim();
-
-      DynamicJsonDocument doc(1024);
-      DeserializationError error = deserializeJson(doc, jsonData);
-
-      if (error)
-      {
-        SerialPico.print("[ERROR] Failed to parse JSON.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract values from JSON
-      if (!doc.containsKey("url") || !doc.containsKey("payload"))
-      {
-        SerialPico.println("[ERROR] JSON does not contain url or payload.");
-        this->ledOff();
-        return;
-      }
-      String url = doc["url"];
-      String payload = doc["payload"];
-
-      // Extract headers if available
-      const char *headerKeys[10];
-      const char *headerValues[10];
-      int headerSize = 0;
-
-      if (doc.containsKey("headers"))
-      {
-        JsonObject headers = doc["headers"];
-        for (JsonPair header : headers)
-        {
-          headerKeys[headerSize] = header.key().c_str();
-          headerValues[headerSize] = header.value();
-          headerSize++;
-        }
-      }
-
-      // POST request
-      if (!this->post_bytes_to_file(url, payload, headerKeys, headerValues, headerSize))
-      {
-        SerialPico.println("[ERROR] POST request failed or returned empty data.");
-      }
-    }
-    // Handle [PARSE] command
-    // the user will append the key to read from the json
-    // example: [PARSE]{"key":"name","json":{"name":"John Doe"}}
-    else if (_data.startsWith("[PARSE]"))
-    {
-      // Extract the JSON by removing the command part
-      String jsonData = _data.substring(strlen("[PARSE]"));
-      jsonData.trim();
-
-      DynamicJsonDocument doc(1024);
-      DeserializationError error = deserializeJson(doc, jsonData);
-
-      if (error)
-      {
-        SerialPico.print("[ERROR] Failed to parse JSON.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract values from JSON
-      if (!doc.containsKey("key") || !doc.containsKey("json"))
-      {
-        SerialPico.println("[ERROR] JSON does not contain key or json.");
-        this->ledOff();
-        return;
-      }
-      String key = doc["key"];
-      JsonObject json = doc["json"];
-
-      if (json.containsKey(key))
-      {
-        SerialPico.println(json[key].as<String>());
-      }
-      else
-      {
-        SerialPico.println("[ERROR] Key not found in JSON.");
-      }
-    }
-    // Handle [PARSE/ARRAY] command
-    // the user will append the key to read and the index of the array to get it's key from the json
-    // example: [PARSE/ARRAY]{"key":"name","index":"1","json":{"name":["John Doe","Jane Doe"]}}
-    // this would return Jane Doe
-    // and in this example it would return {"flavor": "red"}:
-    // example: [PARSE/ARRAY]{"key":"flavor","index":"1","json":{"name":[{"flavor": "blue"},{"flavor": "red"}]}}
-    else if (_data.startsWith("[PARSE/ARRAY]"))
-    {
-      // Extract the JSON by removing the command part
-      String jsonData = _data.substring(strlen("[PARSE/ARRAY]"));
-      jsonData.trim();
-
-      DynamicJsonDocument doc(1024);
-      DeserializationError error = deserializeJson(doc, jsonData);
-
-      if (error)
-      {
-        SerialPico.print("[ERROR] Failed to parse JSON.");
-        this->ledOff();
-        return;
-      }
-
-      // Extract values from JSON
-      if (!doc.containsKey("key") || !doc.containsKey("index") || !doc.containsKey("json"))
-      {
-        SerialPico.println("[ERROR] JSON does not contain key, index, or json.");
-        this->ledOff();
-        return;
-      }
-      String key = doc["key"];
-      int index = doc["index"];
-      JsonArray json = doc["json"];
-
-      if (json[index].containsKey(key))
-      {
-        SerialPico.println(json[index][key].as<String>());
-      }
-      else
-      {
-        SerialPico.println("[ERROR] Key not found in JSON.");
-      }
-    }
-
-    this->ledOff();
-  }
-}

+ 0 - 21
assets/FlipperHTTP/Arduino/flipper-http-pico.ino

@@ -1,21 +0,0 @@
-/* FlipperHTTP Library
-Author: JBlanked
-Github: https://github.com/jblanked/WebCrawler-FlipperZero/tree/main/assets/FlipperHTTP
-Info: This library is a wrapper around the HTTPClient library and is used to communicate with the FlipperZero over serial.
-Created: 2024-10-24
-Updated: 2024-10-26
-*/
-
-#include "FlipperHTTPPico.h"
-
-FlipperHTTP fhttp;
-
-void setup()
-{
-    fhttp.setup();
-}
-
-void loop()
-{
-    fhttp.loop();
-}

+ 0 - 21
assets/FlipperHTTP/Arduino/flipper-http.ino

@@ -1,21 +0,0 @@
-/* FlipperHTTP Library
-Author: JBlanked
-Github: https://github.com/jblanked/WebCrawler-FlipperZero/tree/main/assets/FlipperHTTP
-Info: This library is a wrapper around the HTTPClient library and is used to communicate with the FlipperZero over serial.
-Created: 2024-09-30
-Updated: 2024-10-26
-*/
-
-#include <FlipperHTTP.h>
-
-FlipperHTTP fhttp;
-
-void setup()
-{
-  fhttp.setup();
-}
-
-void loop()
-{
-  fhttp.loop();
-}

+ 2 - 112
assets/FlipperHTTP/README.md

@@ -1,114 +1,4 @@
 # FlipperHTTP
-HTTP library for Flipper Zero. Compatible with Wifi Dev Board for Flipper Zero (ESP32S2 Dev Module). View the extended documentation here: https://www.jblanked.com/api/FlipperHTTP/
+HTTP library for Flipper Zero. Compatible with Wifi Dev Board for Flipper Zero (ESP32S2 Dev Module) and the Raspberry Pi Pico W. 
 
-## Installation
-1. Download the `flipper_http_bootloader.bin`, `flipper_http_firmware_a.bin`, and `flipper_http_partitions.bin` files.
-2. Unplug your Wifi Dev Board and connect your Flipper Zero to your computer.
-3. Open up qFlipper.
-4. Click on the `File manager`.
-5. Naviate to `SD Card/apps_data/esp_flasher/`
-6. Drag all three bin files (or the entire folder) into the directory.
-7. Disconnect your Flipper from your computer then turn off your Flipper.
-8. Plug your Wi-Fi Devboard into the Flipper then turn on your Flipper.
-9. Open the ESP Flasher app on your Flipper, it should be located under `Apps->GPIO` from the main menu. If not, download it from the Flipper App Store.
-10. In the ESP Flasher app, select the following options:
-    - "Reset Board": wait a few seconds, then go back.
-    - "Enter Bootloader": wait until the 'waiting for download' message appears, then go back.
-11. Click on Manual Flash.
-12. Click on Bootloader and select the `flipper_http_bootloader.bin` that you downloaded earlier.
-13. Click on Part Table and select the `flipper_http_partitions.bin` that you downloaded earlier.
-14. Click on FirmwareA and select the `flipper_http_firmware_a.bin` that you downloaded earlier.
-15. Click on FLASH - slow. If successful, you will see three green LED blinks on the Dev board.
-16. On the Dev Board, press the RESET button once.
-
-You are all set. Here's the initial guide: [https://www.youtube.com/watch?v=AZfbrLKJMpM](https://www.youtube.com/watch?v=AZfbrLKJMpM)
-
-Star the repository (https://github.com/jblanked/WebCrawler-FlipperZero) and follow me for updates and upcoming Flipper apps.
-
-## Apps That Utilize FlipperHTTP
-The following apps have integrated FlipperHTTP to enhance their functionalities:
-
-- **FlipStore** - A marketplace for downloading and managing apps and software on your Flipper Zero: https://github.com/jblanked/FlipStore
-- **FlipSocial** - Social media platform for the Flipper Zero: https://github.com/jblanked/FlipSocial
-- **FlipLibrary** - A Flipper Zero app with a dictionary, random facts, and more: https://github.com/jblanked/FlipLibrary
-- **Web Crawler** - Allows your Flipper Zero to crawl and interact with websites directly: https://github.com/jblanked/WebCrawler-FlipperZero
-- **FlipWeather** - Use WiFi to get GPS and Weather information on your Flipper Zero: https://github.com/jblanked/FlipWeather
-- **FlipTrader** - Use WiFi to get the price of stocks and currency pairs on your Flipper Zero: https://github.com/jblanked/FlipTrader
-
-
-## Usage in `C` (flipper_http.h)
-
-| **Function Name**                                | **Return Value** | **Parameters**                                                                                                | **Description**                                                                                   |
-|--------------------------------------------------|------------------|----------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
-| `flipper_http_init`                              | `bool`           | `FlipperHTTP_Callback callback`, `void *context`                                                               | Initializes the HTTP module with a callback and context.                                           |
-| `flipper_http_deinit`                            | `void`           | None                                                                                                           | Deinitializes the HTTP module.                                                                    |
-| `flipper_http_connect_wifi`                      | `bool`           | None                                                                                                           | Connects to WiFi using previously saved credentials.                                               |
-| `flipper_http_disconnect_wifi`                   | `bool`           | None                                                                                                           | Disconnects from the current WiFi network.                                                         |
-| `flipper_http_ping`                              | `bool`           | None                                                                                                           | Sends a ping request to test connectivity.                                                         |
-| `flipper_http_scan_wifi`                         | `bool`           | `const char *ssid`, `const char *password`                                                                     | Scans for nearby WiFi networks.                                                                    |
-| `flipper_http_save_wifi`                         | `bool`           | `const char *ssid`, `const char *password`                                                                     | Saves WiFi credentials for future connections.                                                     |
-| `flipper_http_ip_wifi`                           | `bool`           | None                                                                                                           | Retrieves the IP address of the connected WiFi network.                                            |
-| `flipper_http_ip_address`                        | `bool`           | None                                                                                                           | Retrieves the IP address of the WiFi Devboard.                                                     |
-| `flipper_http_list_commands`                     | `bool`           | None                                                                                                           | Lists all available commands.                                                                      |
-| `flipper_http_led_on`                            | `bool`           | None                                                                                                           | Allow the LED to display while processing.                                                         |
-| `flipper_http_led_off`                           | `bool`           | None                                                                                                           | Disable the LED from displaying while processing.                                                  |
-| `flipper_http_parse_json`                        | `bool`           | `const char *key`, `const char *json_data`                                                                     | Parses JSON data for a specified key.                                                              |
-| `flipper_http_parse_json_array`                  | `bool`           | `const char *key`, `int index`, `const char *json_data`                                                        | Parses an array within JSON data for a specified key and index.                                    |
-| `flipper_http_send_data`                         | `bool`           | `const char *data`                                                                                             | Sends the specified data to the server.                                                            |
-| `flipper_http_rx_callback`                       | `void`           | `const char *line`, `void *context`                                                                            | Callback function for handling received data.                                                      |
-| `flipper_http_get_request`                       | `bool`           | `const char *url`                                                                                              | Sends a GET request to the specified URL.                                                          |
-| `flipper_http_get_request_with_headers`          | `bool`           | `const char *url`, `const char *headers`                                                                       | Sends a GET request with custom headers to the specified URL.                                      |
-| `flipper_http_post_request_with_headers`         | `bool`           | `const char *url`, `const char *headers`, `const char *payload`                                                | Sends a POST request with custom headers and a payload to the specified URL.                       |
-| `flipper_http_put_request_with_headers`          | `bool`           | `const char *url`, `const char *headers`, `const char *payload`                                                | Sends a PUT request with custom headers and a payload to the specified URL.                        |
-| `flipper_http_delete_request_with_headers`       | `bool`           | `const char *url`, `const char *headers`, `const char *payload`                                                | Sends a DELETE request with custom headers and a payload to the specified URL.                     |
-| `flipper_http_save_received_data`                | `bool`           | `size_t bytes_received`, `const char line_buffer[]`                                                            | Saves the received data to the SD card, with the specified size and buffer.                        |
-
-`In C, fhttp.received_data holds the received data from HTTP requests. In JavaScript and mPython, the response is returned directly from the function.`
-
-## Usage in `JavaScript` (flipper_http.js):
-| **Function Name**                      | **Return Value** | **Parameters**                                       | **Description**                                                                                      |
-|----------------------------------------|------------------|-----------------------------------------------------|------------------------------------------------------------------------------------------------------|
-| `fhttp.init`                           | `void`           | None                                                | Initializes the serial connection with the correct settings.                                          |
-| `fhttp.deinit`                         | `void`           | None                                                | Deinitializes and ends the serial connection.                                                         |
-| `fhttp.connect_wifi`                   | `bool`           | None                                                | Sends a command to connect to WiFi and returns whether the connection was successful.                 |
-| `fhttp.disconnect_wifi`                | `bool`           | None                                                | Sends a command to disconnect from WiFi and returns whether the disconnection was successful.          |
-| `fhttp.ping`                           | `bool`           | None                                                | Sends a ping request to test connectivity and returns whether a response was received.                |
-| `fhttp.scan_wifi`                      | `string`         | None                                                | Scans for nearby WiFi access points and returns a string with each access point separated by a comma.  |
-| `fhttp.save_wifi`                      | `bool`           | `ssid: string`, `password: string`                  | Saves WiFi credentials and returns whether the save operation was successful.                         |
-| `fhttp.ip_wifi`                        | `string`         | None                                                | Gets the IP address of the connected WiFi network and returns it as a string.                      |
-| `fhttp.ip_address`                     | `string`         | None                                                | Gets the IP address of the WiFi Devboard and returns it as a string.                                  |
-| `fhttp.list_commands`                  | `string`         | None                                                | Lists all available commands and returns them as a string.                                            |
-| `fhttp.led_on`                         | `void`           | None                                                | Sends a command to allow the LED to display while processing.                                         |
-| `fhttp.led_off`                        | `void`           | None                                                | Sends a command to disable the LED from displaying while processing.                                  |
-| `fhttp.parse_json`                     | `string`         | `key: string`, `data: string`                       | Parses JSON data for a specified key and returns the corresponding value as a string.                 |
-| `fhttp.parse_json_array`               | `string`         | `key: string`, `index: number`, `data: string`      | Parses an array within JSON data for a specified key and index, returning the corresponding value.    |
-| `fhttp.send_data`                      | `void`           | `data: string`                                      | Sends the specified data to the serial port.                                                          |
-| `fhttp.read_data`                      | `string`         | `delay_ms: number`                                  | Reads data from the serial port with a specified delay and returns the response received.             |
-| `fhttp.get_request`                    | `string`         | `url: string`                                       | Sends a GET request to the specified URL and returns the response.                                    |
-| `fhttp.get_request_with_headers`       | `string`         | `url: string`, `headers: string`                    | Sends a GET request with specified headers and returns the response.                                  |
-| `fhttp.post_request_with_headers`      | `string`         | `url: string`, `headers: string`, `payload: string` | Sends a POST request with specified headers and payload, returning the response.                      |
-| `fhttp.put_request_with_headers`       | `string`         | `url: string`, `headers: string`, `payload: string` | Sends a PUT request with specified headers and payload, returning the response.                       |
-| `fhttp.delete_request_with_headers`    | `string`         | `url: string`, `headers: string`, `payload: string` | Sends a DELETE request with specified headers and payload, returning the response.                    |
-
-## Usage in `Python` (flipper_http.py):
-| **Function Name**                      | **Return Value** | **Parameters**                                       | **Description**                                                                                      |
-|----------------------------------------|------------------|-----------------------------------------------------|------------------------------------------------------------------------------------------------------|
-| `flipper_http_connect_wifi`                   | `bool`           | None                                                | Sends a command to connect to WiFi and returns whether the connection was successful.                 |
-| `flipper_http_disconnect_wifi`                | `bool`           | None                                                | Sends a command to disconnect from WiFi and returns whether the disconnection was successful.          |
-| `flipper_http_ping`                           | `bool`           | None                                                | Sends a ping request to test connectivity and returns whether a response was received.                |
-| `flipper_http_save_wifi`                      | `bool`           | `ssid: str`, `password: str`                  | Saves WiFi credentials and returns whether the save operation was successful.                         |
-| `flipper_http_scan_wifi`                      | `str`            | None                                          | Scans for nearby WiFi access points and returns a string listing each access point, separated by commas.  |
-| `flipper_http_ip_wifi`                        | `str`            | None                                          | Gets the IP address of the connected WiFi network and returns it as a string.                       |
-| `flipper_http_ip_address`                     | `str`            | None                                          | Gets the IP address of the WiFi Devboard and returns it as a string.                                  |
-| `flipper_http_list_commands`                  | `str`            | None                                          | Lists all available commands and returns them as a string.                                            |
-| `flipper_http_led_on`                         | `void`           | None                                          | Sends a command to allow the LED to display while processing.                                         |
-| `flipper_http_led_off`                        | `void`           | None                                          | Sends a command to disable the LED from displaying while processing.                                  |
-| `flipper_http_parse_json`                     | `str`            | `key: str`, `json_data: str`                   | Parses JSON data for a specified key and returns the corresponding value as a string.                 |
-| `flipper_http_parse_json_array`               | `str`            | `key: str`, `index: int`, `json_data: str`       | Parses an array within JSON data for a specified key and index, returning the corresponding value.    |
-| `flipper_http_send_data`                      | `void`           | `data: str`                                      | Sends the specified data to the serial port.                                                          |
-| `flipper_http_read_data`                      | `str`            | `sleep_ms: int`                                  | Reads data from the serial port with a specified delay and returns the response received.             |
-| `flipper_http_get_request`                    | `str`            | `url: str`                                       | Sends a GET request to the specified URL and returns the response.                                    |
-| `flipper_http_get_request_with_headers`       | `str`            | `url: str`, `headers: str`                      | Sends a GET request with specified headers and returns the response.                                  |
-| `flipper_http_post_request_with_headers`      | `str`            | `url: str`, `headers: str`, `data: str`         | Sends a POST request with specified headers and data, returning the response.                         |
-| `flipper_http_put_request_with_headers`       | `str`            | `url: str`, `headers: str`, `data: str`         | Sends a PUT request with specified headers and data, returning the response.                          |
-| `flipper_http_delete_request_with_headers`    | `str`            | `url: str`, `headers: str`, `data: str`         | Sends a DELETE request with specified headers and data, returning the response.                       |
+This library has been moved to: https://www.github.com/jblanked/FlipperHTTP

+ 0 - 1563
assets/FlipperHTTP/flipper_http.h

@@ -1,1563 +0,0 @@
-// flipper_http.h
-#ifndef FLIPPER_HTTP_H
-#define FLIPPER_HTTP_H
-
-#include <furi.h>
-#include <furi_hal.h>
-#include <furi_hal_gpio.h>
-#include <furi_hal_serial.h>
-#include <storage/storage.h>
-
-// STORAGE_EXT_PATH_PREFIX is defined in the Furi SDK as /ext
-
-#define HTTP_TAG "FlipperHTTP"            // change this to your app name
-#define http_tag "flipper_http"           // change this to your app id
-#define UART_CH (FuriHalSerialIdUsart)    // UART channel
-#define TIMEOUT_DURATION_TICKS (5 * 1000) // 5 seconds
-#define BAUDRATE (115200)                 // UART baudrate
-#define RX_BUF_SIZE 1024                  // UART RX buffer size
-#define RX_LINE_BUFFER_SIZE 3000          // UART RX line buffer size (increase for large responses)
-
-// Forward declaration for callback
-typedef void (*FlipperHTTP_Callback)(const char *line, void *context);
-
-// Functions
-bool flipper_http_init(FlipperHTTP_Callback callback, void *context);
-void flipper_http_deinit();
-//---
-void flipper_http_rx_callback(const char *line, void *context);
-bool flipper_http_send_data(const char *data);
-//---
-bool flipper_http_connect_wifi();
-bool flipper_http_disconnect_wifi();
-bool flipper_http_ping();
-bool flipper_http_scan_wifi();
-bool flipper_http_save_wifi(const char *ssid, const char *password);
-bool flipper_http_ip_wifi();
-bool flipper_http_ip_address();
-//---
-bool flipper_http_list_commands();
-bool flipper_http_led_on();
-bool flipper_http_led_off();
-bool flipper_http_parse_json(const char *key, const char *json_data);
-bool flipper_http_parse_json_array(const char *key, int index, const char *json_data);
-//---
-bool flipper_http_get_request(const char *url);
-bool flipper_http_get_request_with_headers(const char *url, const char *headers);
-bool flipper_http_post_request_with_headers(const char *url, const char *headers, const char *payload);
-bool flipper_http_put_request_with_headers(const char *url, const char *headers, const char *payload);
-bool flipper_http_delete_request_with_headers(const char *url, const char *headers, const char *payload);
-//---
-bool flipper_http_get_request_bytes(const char *url, const char *headers);
-bool flipper_http_post_request_bytes(const char *url, const char *headers, const char *payload);
-//
-bool flipper_http_save_received_data(size_t bytes_received, const char line_buffer[]);
-static char *trim(const char *str);
-//
-bool flipper_http_process_response_async(
-    bool (*http_request)(void),
-    bool (*parse_json)(void));
-
-// State variable to track the UART state
-typedef enum
-{
-    INACTIVE,  // Inactive state
-    IDLE,      // Default state
-    RECEIVING, // Receiving data
-    SENDING,   // Sending data
-    ISSUE,     // Issue with connection
-} SerialState;
-
-// Event Flags for UART Worker Thread
-typedef enum
-{
-    WorkerEvtStop = (1 << 0),
-    WorkerEvtRxDone = (1 << 1),
-} WorkerEvtFlags;
-
-// FlipperHTTP Structure
-typedef struct
-{
-    FuriStreamBuffer *flipper_http_stream;  // Stream buffer for UART communication
-    FuriHalSerialHandle *serial_handle;     // Serial handle for UART communication
-    FuriThread *rx_thread;                  // Worker thread for UART
-    uint8_t rx_buf[RX_BUF_SIZE];            // Buffer for received data
-    FuriThreadId rx_thread_id;              // Worker thread ID
-    FlipperHTTP_Callback handle_rx_line_cb; // Callback for received lines
-    void *callback_context;                 // Context for the callback
-    SerialState state;                      // State of the UART
-
-    // variable to store the last received data from the UART
-    char *last_response;
-
-    // Timer-related members
-    FuriTimer *get_timeout_timer; // Timer for HTTP request timeout
-    char *received_data;          // Buffer to store received data
-
-    bool started_receiving_get; // Indicates if a GET request has started
-    bool just_started_get;      // Indicates if GET data reception has just started
-
-    bool started_receiving_post; // Indicates if a POST request has started
-    bool just_started_post;      // Indicates if POST data reception has just started
-
-    bool started_receiving_put; // Indicates if a PUT request has started
-    bool just_started_put;      // Indicates if PUT data reception has just started
-
-    bool started_receiving_delete; // Indicates if a DELETE request has started
-    bool just_started_delete;      // Indicates if DELETE data reception has just started
-
-    // Buffer to hold the raw bytes received from the UART
-    uint8_t *received_bytes;
-    size_t received_bytes_len; // Length of the received bytes
-
-    // File path to save the bytes received
-    char file_path[256];
-
-    bool save_data; // Flag to save the received data
-
-    bool is_bytes_request; // trigger for bytes request
-} FlipperHTTP;
-
-static FlipperHTTP fhttp;
-// Global static array for the line buffer
-static char rx_line_buffer[RX_LINE_BUFFER_SIZE];
-#define FILE_BUFFER_SIZE 512
-static uint8_t file_buffer[FILE_BUFFER_SIZE];
-
-// fhttp.received_data holds the received data from HTTP requests
-// fhttp.last_response holds the last received data from the UART, which could be [GET/END], [POST/END], [PUT/END], [DELETE/END], etc
-
-// Function to append received data to file
-// make sure to initialize the file path before calling this function
-static bool append_to_file(const char *file_path, const void *data, size_t data_size)
-{
-    Storage *storage = furi_record_open(RECORD_STORAGE);
-    File *file = storage_file_alloc(storage);
-
-    // Open the file in append mode
-    if (!storage_file_open(file, file_path, FSAM_WRITE, FSOM_OPEN_APPEND))
-    {
-        FURI_LOG_E(HTTP_TAG, "Failed to open file for appending: %s", file_path);
-        storage_file_free(file);
-        furi_record_close(RECORD_STORAGE);
-        return false;
-    }
-
-    // Write the data to the file
-    if (storage_file_write(file, data, data_size) != data_size)
-    {
-        FURI_LOG_E(HTTP_TAG, "Failed to append data to file");
-        storage_file_close(file);
-        storage_file_free(file);
-        furi_record_close(RECORD_STORAGE);
-        return false;
-    }
-
-    storage_file_close(file);
-    storage_file_free(file);
-    furi_record_close(RECORD_STORAGE);
-
-    return true;
-}
-
-// UART worker thread
-/**
- * @brief      Worker thread to handle UART data asynchronously.
- * @return     0
- * @param      context   The context to pass to the callback.
- * @note       This function will handle received data asynchronously via the callback.
- */
-// UART worker thread
-static int32_t flipper_http_worker(void *context)
-{
-    UNUSED(context);
-    size_t rx_line_pos = 0;
-    static size_t file_buffer_len = 0;
-
-    while (1)
-    {
-        uint32_t events = furi_thread_flags_wait(WorkerEvtStop | WorkerEvtRxDone, FuriFlagWaitAny, FuriWaitForever);
-        if (events & WorkerEvtStop)
-            break;
-        if (events & WorkerEvtRxDone)
-        {
-            // Continuously read from the stream buffer until it's empty
-            while (!furi_stream_buffer_is_empty(fhttp.flipper_http_stream))
-            {
-                // Read one byte at a time
-                char c = 0;
-                size_t received = furi_stream_buffer_receive(fhttp.flipper_http_stream, &c, 1, 0);
-
-                if (received == 0)
-                {
-                    // No more data to read
-                    break;
-                }
-
-                // Append the received byte to the file if saving is enabled
-                if (fhttp.save_data)
-                {
-                    // Add byte to the buffer
-                    file_buffer[file_buffer_len++] = c;
-                    // Write to file if buffer is full
-                    if (file_buffer_len >= FILE_BUFFER_SIZE)
-                    {
-                        if (!append_to_file(fhttp.file_path, file_buffer, file_buffer_len))
-                        {
-                            FURI_LOG_E(HTTP_TAG, "Failed to append data to file");
-                        }
-                        file_buffer_len = 0;
-                    }
-                }
-
-                // Handle line buffering only if callback is set (text data)
-                if (fhttp.handle_rx_line_cb)
-                {
-                    // Handle line buffering
-                    if (c == '\n' || rx_line_pos >= RX_LINE_BUFFER_SIZE - 1)
-                    {
-                        rx_line_buffer[rx_line_pos] = '\0'; // Null-terminate the line
-
-                        // Invoke the callback with the complete line
-                        fhttp.handle_rx_line_cb(rx_line_buffer, fhttp.callback_context);
-
-                        // Reset the line buffer position
-                        rx_line_pos = 0;
-                    }
-                    else
-                    {
-                        rx_line_buffer[rx_line_pos++] = c; // Add character to the line buffer
-                    }
-                }
-            }
-        }
-    }
-
-    if (fhttp.save_data)
-    {
-        // Write the remaining data to the file
-        if (file_buffer_len > 0)
-        {
-            if (!append_to_file(fhttp.file_path, file_buffer, file_buffer_len))
-            {
-                FURI_LOG_E(HTTP_TAG, "Failed to append remaining data to file");
-            }
-        }
-    }
-
-    // remove [POST/END] and/or [GET/END] from the file
-    if (fhttp.save_data)
-    {
-        char *end = NULL;
-        if ((end = strstr(fhttp.file_path, "[POST/END]")) != NULL)
-        {
-            *end = '\0';
-        }
-        else if ((end = strstr(fhttp.file_path, "[GET/END]")) != NULL)
-        {
-            *end = '\0';
-        }
-    }
-
-    // remove newline from the from the end of the file
-    if (fhttp.save_data)
-    {
-        char *end = NULL;
-        if ((end = strstr(fhttp.file_path, "\n")) != NULL)
-        {
-            *end = '\0';
-        }
-    }
-
-    // Reset the file buffer length
-    file_buffer_len = 0;
-
-    return 0;
-}
-// Timer callback function
-/**
- * @brief      Callback function for the GET timeout timer.
- * @return     0
- * @param      context   The context to pass to the callback.
- * @note       This function will be called when the GET request times out.
- */
-void get_timeout_timer_callback(void *context)
-{
-    UNUSED(context);
-    FURI_LOG_E(HTTP_TAG, "Timeout reached: 2 seconds without receiving the end.");
-
-    // Reset the state
-    fhttp.started_receiving_get = false;
-    fhttp.started_receiving_post = false;
-    fhttp.started_receiving_put = false;
-    fhttp.started_receiving_delete = false;
-
-    // Free received data if any
-    if (fhttp.received_data)
-    {
-        free(fhttp.received_data);
-        fhttp.received_data = NULL;
-    }
-
-    // Update UART state
-    fhttp.state = ISSUE;
-}
-
-// UART RX Handler Callback (Interrupt Context)
-/**
- * @brief      A private callback function to handle received data asynchronously.
- * @return     void
- * @param      handle    The UART handle.
- * @param      event     The event type.
- * @param      context   The context to pass to the callback.
- * @note       This function will handle received data asynchronously via the callback.
- */
-static void _flipper_http_rx_callback(FuriHalSerialHandle *handle, FuriHalSerialRxEvent event, void *context)
-{
-    UNUSED(context);
-    if (event == FuriHalSerialRxEventData)
-    {
-        uint8_t data = furi_hal_serial_async_rx(handle);
-        furi_stream_buffer_send(fhttp.flipper_http_stream, &data, 1, 0);
-        furi_thread_flags_set(fhttp.rx_thread_id, WorkerEvtRxDone);
-    }
-}
-
-// UART initialization function
-/**
- * @brief      Initialize UART.
- * @return     true if the UART was initialized successfully, false otherwise.
- * @param      callback  The callback function to handle received data (ex. flipper_http_rx_callback).
- * @param      context   The context to pass to the callback.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_init(FlipperHTTP_Callback callback, void *context)
-{
-    if (!context)
-    {
-        FURI_LOG_E(HTTP_TAG, "Invalid context provided to flipper_http_init.");
-        return false;
-    }
-    if (!callback)
-    {
-        FURI_LOG_E(HTTP_TAG, "Invalid callback provided to flipper_http_init.");
-        return false;
-    }
-    fhttp.flipper_http_stream = furi_stream_buffer_alloc(RX_BUF_SIZE, 1);
-    if (!fhttp.flipper_http_stream)
-    {
-        FURI_LOG_E(HTTP_TAG, "Failed to allocate UART stream buffer.");
-        return false;
-    }
-
-    fhttp.rx_thread = furi_thread_alloc();
-    if (!fhttp.rx_thread)
-    {
-        FURI_LOG_E(HTTP_TAG, "Failed to allocate UART thread.");
-        furi_stream_buffer_free(fhttp.flipper_http_stream);
-        return false;
-    }
-
-    furi_thread_set_name(fhttp.rx_thread, "FlipperHTTP_RxThread");
-    furi_thread_set_stack_size(fhttp.rx_thread, 1024);
-    furi_thread_set_context(fhttp.rx_thread, &fhttp);
-    furi_thread_set_callback(fhttp.rx_thread, flipper_http_worker);
-
-    fhttp.handle_rx_line_cb = callback;
-    fhttp.callback_context = context;
-
-    furi_thread_start(fhttp.rx_thread);
-    fhttp.rx_thread_id = furi_thread_get_id(fhttp.rx_thread);
-
-    // handle when the UART control is busy to avoid furi_check failed
-    if (furi_hal_serial_control_is_busy(UART_CH))
-    {
-        FURI_LOG_E(HTTP_TAG, "UART control is busy.");
-        return false;
-    }
-
-    fhttp.serial_handle = furi_hal_serial_control_acquire(UART_CH);
-    if (!fhttp.serial_handle)
-    {
-        FURI_LOG_E(HTTP_TAG, "Failed to acquire UART control - handle is NULL");
-        // Cleanup resources
-        furi_thread_free(fhttp.rx_thread);
-        furi_stream_buffer_free(fhttp.flipper_http_stream);
-        return false;
-    }
-
-    // Initialize UART with acquired handle
-    furi_hal_serial_init(fhttp.serial_handle, BAUDRATE);
-
-    // Enable RX direction
-    furi_hal_serial_enable_direction(fhttp.serial_handle, FuriHalSerialDirectionRx);
-
-    // Start asynchronous RX with the callback
-    furi_hal_serial_async_rx_start(fhttp.serial_handle, _flipper_http_rx_callback, &fhttp, false);
-
-    // Wait for the TX to complete to ensure UART is ready
-    furi_hal_serial_tx_wait_complete(fhttp.serial_handle);
-
-    // Allocate the timer for handling timeouts
-    fhttp.get_timeout_timer = furi_timer_alloc(
-        get_timeout_timer_callback, // Callback function
-        FuriTimerTypeOnce,          // One-shot timer
-        &fhttp                      // Context passed to callback
-    );
-
-    if (!fhttp.get_timeout_timer)
-    {
-        FURI_LOG_E(HTTP_TAG, "Failed to allocate HTTP request timeout timer.");
-        // Cleanup resources
-        furi_hal_serial_async_rx_stop(fhttp.serial_handle);
-        furi_hal_serial_disable_direction(fhttp.serial_handle, FuriHalSerialDirectionRx);
-        furi_hal_serial_control_release(fhttp.serial_handle);
-        furi_hal_serial_deinit(fhttp.serial_handle);
-        furi_thread_flags_set(fhttp.rx_thread_id, WorkerEvtStop);
-        furi_thread_join(fhttp.rx_thread);
-        furi_thread_free(fhttp.rx_thread);
-        furi_stream_buffer_free(fhttp.flipper_http_stream);
-        return false;
-    }
-
-    // Set the timer thread priority if needed
-    furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated);
-
-    FURI_LOG_I(HTTP_TAG, "UART initialized successfully.");
-    return true;
-}
-
-// Deinitialize UART
-/**
- * @brief      Deinitialize UART.
- * @return     void
- * @note       This function will stop the asynchronous RX, release the serial handle, and free the resources.
- */
-void flipper_http_deinit()
-{
-    if (fhttp.serial_handle == NULL)
-    {
-        FURI_LOG_E(HTTP_TAG, "UART handle is NULL. Already deinitialized?");
-        return;
-    }
-    // Stop asynchronous RX
-    furi_hal_serial_async_rx_stop(fhttp.serial_handle);
-
-    // Release and deinitialize the serial handle
-    furi_hal_serial_disable_direction(fhttp.serial_handle, FuriHalSerialDirectionRx);
-    furi_hal_serial_control_release(fhttp.serial_handle);
-    furi_hal_serial_deinit(fhttp.serial_handle);
-
-    // Signal the worker thread to stop
-    furi_thread_flags_set(fhttp.rx_thread_id, WorkerEvtStop);
-    // Wait for the thread to finish
-    furi_thread_join(fhttp.rx_thread);
-    // Free the thread resources
-    furi_thread_free(fhttp.rx_thread);
-
-    // Free the stream buffer
-    furi_stream_buffer_free(fhttp.flipper_http_stream);
-
-    // Free the timer
-    if (fhttp.get_timeout_timer)
-    {
-        furi_timer_free(fhttp.get_timeout_timer);
-        fhttp.get_timeout_timer = NULL;
-    }
-
-    // Free received data if any
-    if (fhttp.received_data)
-    {
-        free(fhttp.received_data);
-        fhttp.received_data = NULL;
-    }
-
-    // Free the last response
-    if (fhttp.last_response)
-    {
-        free(fhttp.last_response);
-        fhttp.last_response = NULL;
-    }
-
-    FURI_LOG_I("FlipperHTTP", "UART deinitialized successfully.");
-}
-
-// Function to send data over UART with newline termination
-/**
- * @brief      Send data over UART with newline termination.
- * @return     true if the data was sent successfully, false otherwise.
- * @param      data  The data to send over UART.
- * @note       The data will be sent over UART with a newline character appended.
- */
-bool flipper_http_send_data(const char *data)
-{
-    size_t data_length = strlen(data);
-    if (data_length == 0)
-    {
-        FURI_LOG_E("FlipperHTTP", "Attempted to send empty data.");
-        return false;
-    }
-
-    // Create a buffer with data + '\n'
-    size_t send_length = data_length + 1; // +1 for '\n'
-    if (send_length > 256)
-    { // Ensure buffer size is sufficient
-        FURI_LOG_E("FlipperHTTP", "Data too long to send over FHTTP.");
-        return false;
-    }
-
-    char send_buffer[257]; // 256 + 1 for safety
-    strncpy(send_buffer, data, 256);
-    send_buffer[data_length] = '\n';     // Append newline
-    send_buffer[data_length + 1] = '\0'; // Null-terminate
-
-    if (fhttp.state == INACTIVE && ((strstr(send_buffer, "[PING]") == NULL) && (strstr(send_buffer, "[WIFI/CONNECT]") == NULL)))
-    {
-        FURI_LOG_E("FlipperHTTP", "Cannot send data while INACTIVE.");
-        fhttp.last_response = "Cannot send data while INACTIVE.";
-        return false;
-    }
-
-    fhttp.state = SENDING;
-    furi_hal_serial_tx(fhttp.serial_handle, (const uint8_t *)send_buffer, send_length);
-
-    // Uncomment below line to log the data sent over UART
-    // FURI_LOG_I("FlipperHTTP", "Sent data over UART: %s", send_buffer);
-    fhttp.state = IDLE;
-    return true;
-}
-
-// Function to send a PING request
-/**
- * @brief      Send a PING request to check if the Wifi Dev Board is connected.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- * @note       This is best used to check if the Wifi Dev Board is connected.
- * @note       The state will remain INACTIVE until a PONG is received.
- */
-bool flipper_http_ping()
-{
-    const char *command = "[PING]";
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send PING command.");
-        return false;
-    }
-    // set state as INACTIVE to be made IDLE if PONG is received
-    fhttp.state = INACTIVE;
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-
-// Function to list available commands
-/**
- * @brief      Send a command to list available commands.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_list_commands()
-{
-    const char *command = "[LIST]";
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send LIST command.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-
-// Function to turn on the LED
-/**
- * @brief      Allow the LED to display while processing.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_led_on()
-{
-    const char *command = "[LED/ON]";
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send LED ON command.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-
-// Function to turn off the LED
-/**
- * @brief      Disable the LED from displaying while processing.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_led_off()
-{
-    const char *command = "[LED/OFF]";
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send LED OFF command.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-
-// Function to parse JSON data
-/**
- * @brief      Parse JSON data.
- * @return     true if the JSON data was parsed successfully, false otherwise.
- * @param      key       The key to parse from the JSON data.
- * @param      json_data The JSON data to parse.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_parse_json(const char *key, const char *json_data)
-{
-    if (!key || !json_data)
-    {
-        FURI_LOG_E("FlipperHTTP", "Invalid arguments provided to flipper_http_parse_json.");
-        return false;
-    }
-
-    char buffer[256];
-    int ret = snprintf(buffer, sizeof(buffer), "[PARSE]{\"key\":\"%s\",\"json\":%s}", key, json_data);
-    if (ret < 0 || ret >= (int)sizeof(buffer))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to format JSON parse command.");
-        return false;
-    }
-
-    if (!flipper_http_send_data(buffer))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send JSON parse command.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-
-// Function to parse JSON array data
-/**
- * @brief      Parse JSON array data.
- * @return     true if the JSON array data was parsed successfully, false otherwise.
- * @param      key       The key to parse from the JSON array data.
- * @param      index     The index to parse from the JSON array data.
- * @param      json_data The JSON array data to parse.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_parse_json_array(const char *key, int index, const char *json_data)
-{
-    if (!key || !json_data)
-    {
-        FURI_LOG_E("FlipperHTTP", "Invalid arguments provided to flipper_http_parse_json_array.");
-        return false;
-    }
-
-    char buffer[256];
-    int ret = snprintf(buffer, sizeof(buffer), "[PARSE/ARRAY]{\"key\":\"%s\",\"index\":%d,\"json\":%s}", key, index, json_data);
-    if (ret < 0 || ret >= (int)sizeof(buffer))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to format JSON parse array command.");
-        return false;
-    }
-
-    if (!flipper_http_send_data(buffer))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send JSON parse array command.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-
-// Function to scan for WiFi networks
-/**
- * @brief      Send a command to scan for WiFi networks.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_scan_wifi()
-{
-    const char *command = "[WIFI/SCAN]";
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send WiFi scan command.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-
-// Function to save WiFi settings (returns true if successful)
-/**
- * @brief      Send a command to save WiFi settings.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_save_wifi(const char *ssid, const char *password)
-{
-    if (!ssid || !password)
-    {
-        FURI_LOG_E("FlipperHTTP", "Invalid arguments provided to flipper_http_save_wifi.");
-        return false;
-    }
-    char buffer[256];
-    int ret = snprintf(buffer, sizeof(buffer), "[WIFI/SAVE]{\"ssid\":\"%s\",\"password\":\"%s\"}", ssid, password);
-    if (ret < 0 || ret >= (int)sizeof(buffer))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to format WiFi save command.");
-        return false;
-    }
-
-    if (!flipper_http_send_data(buffer))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send WiFi save command.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-
-// Function to get IP address of WiFi Devboard
-/**
- * @brief      Send a command to get the IP address of the WiFi Devboard
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_ip_address()
-{
-    const char *command = "[IP/ADDRESS]";
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send IP address command.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-
-// Function to get IP address of the connected WiFi network
-/**
- * @brief      Send a command to get the IP address of the connected WiFi network.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_ip_wifi()
-{
-    const char *command = "[WIFI/IP]";
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send WiFi IP command.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-
-// Function to disconnect from WiFi (returns true if successful)
-/**
- * @brief      Send a command to disconnect from WiFi.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_disconnect_wifi()
-{
-    const char *command = "[WIFI/DISCONNECT]";
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send WiFi disconnect command.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-
-// Function to connect to WiFi (returns true if successful)
-/**
- * @brief      Send a command to connect to WiFi.
- * @return     true if the request was successful, false otherwise.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_connect_wifi()
-{
-    const char *command = "[WIFI/CONNECT]";
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send WiFi connect command.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-
-// Function to send a GET request
-/**
- * @brief      Send a GET request to the specified URL.
- * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the GET request to.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_get_request(const char *url)
-{
-    if (!url)
-    {
-        FURI_LOG_E("FlipperHTTP", "Invalid arguments provided to flipper_http_get_request.");
-        return false;
-    }
-
-    // Prepare GET request command
-    char command[256];
-    int ret = snprintf(command, sizeof(command), "[GET]%s", url);
-    if (ret < 0 || ret >= (int)sizeof(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to format GET request command.");
-        return false;
-    }
-
-    // Send GET request via UART
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send GET request command.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-// Function to send a GET request with headers
-/**
- * @brief      Send a GET request to the specified URL.
- * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the GET request to.
- * @param      headers  The headers to send with the GET request.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_get_request_with_headers(const char *url, const char *headers)
-{
-    if (!url || !headers)
-    {
-        FURI_LOG_E("FlipperHTTP", "Invalid arguments provided to flipper_http_get_request_with_headers.");
-        return false;
-    }
-
-    // Prepare GET request command with headers
-    char command[256];
-    int ret = snprintf(command, sizeof(command), "[GET/HTTP]{\"url\":\"%s\",\"headers\":%s}", url, headers);
-    if (ret < 0 || ret >= (int)sizeof(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to format GET request command with headers.");
-        return false;
-    }
-
-    // Send GET request via UART
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send GET request command with headers.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-// Function to send a GET request with headers and return bytes
-/**
- * @brief      Send a GET request to the specified URL.
- * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the GET request to.
- * @param      headers  The headers to send with the GET request.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_get_request_bytes(const char *url, const char *headers)
-{
-    if (!url || !headers)
-    {
-        FURI_LOG_E("FlipperHTTP", "Invalid arguments provided to flipper_http_get_request_bytes.");
-        return false;
-    }
-
-    // Prepare GET request command with headers
-    char command[256];
-    int ret = snprintf(command, sizeof(command), "[GET/BYTES]{\"url\":\"%s\",\"headers\":%s}", url, headers);
-    if (ret < 0 || ret >= (int)sizeof(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to format GET request command with headers.");
-        return false;
-    }
-
-    // Send GET request via UART
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send GET request command with headers.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-// Function to send a POST request with headers
-/**
- * @brief      Send a POST request to the specified URL.
- * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the POST request to.
- * @param      headers  The headers to send with the POST request.
- * @param      data  The data to send with the POST request.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_post_request_with_headers(const char *url, const char *headers, const char *payload)
-{
-    if (!url || !headers || !payload)
-    {
-        FURI_LOG_E("FlipperHTTP", "Invalid arguments provided to flipper_http_post_request_with_headers.");
-        return false;
-    }
-
-    // Prepare POST request command with headers and data
-    char command[256];
-    int ret = snprintf(command, sizeof(command), "[POST/HTTP]{\"url\":\"%s\",\"headers\":%s,\"payload\":%s}", url, headers, payload);
-    if (ret < 0 || ret >= (int)sizeof(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to format POST request command with headers and data.");
-        return false;
-    }
-
-    // Send POST request via UART
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send POST request command with headers and data.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-// Function to send a POST request with headers and return bytes
-/**
- * @brief      Send a POST request to the specified URL.
- * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the POST request to.
- * @param      headers  The headers to send with the POST request.
- * @param      payload  The data to send with the POST request.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_post_request_bytes(const char *url, const char *headers, const char *payload)
-{
-    if (!url || !headers || !payload)
-    {
-        FURI_LOG_E("FlipperHTTP", "Invalid arguments provided to flipper_http_post_request_bytes.");
-        return false;
-    }
-
-    // Prepare POST request command with headers and data
-    char command[256];
-    int ret = snprintf(command, sizeof(command), "[POST/BYTES]{\"url\":\"%s\",\"headers\":%s,\"payload\":%s}", url, headers, payload);
-    if (ret < 0 || ret >= (int)sizeof(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to format POST request command with headers and data.");
-        return false;
-    }
-
-    // Send POST request via UART
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send POST request command with headers and data.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-// Function to send a PUT request with headers
-/**
- * @brief      Send a PUT request to the specified URL.
- * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the PUT request to.
- * @param      headers  The headers to send with the PUT request.
- * @param      data  The data to send with the PUT request.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_put_request_with_headers(const char *url, const char *headers, const char *payload)
-{
-    if (!url || !headers || !payload)
-    {
-        FURI_LOG_E("FlipperHTTP", "Invalid arguments provided to flipper_http_put_request_with_headers.");
-        return false;
-    }
-
-    // Prepare PUT request command with headers and data
-    char command[256];
-    int ret = snprintf(command, sizeof(command), "[PUT/HTTP]{\"url\":\"%s\",\"headers\":%s,\"payload\":%s}", url, headers, payload);
-    if (ret < 0 || ret >= (int)sizeof(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to format PUT request command with headers and data.");
-        return false;
-    }
-
-    // Send PUT request via UART
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send PUT request command with headers and data.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-// Function to send a DELETE request with headers
-/**
- * @brief      Send a DELETE request to the specified URL.
- * @return     true if the request was successful, false otherwise.
- * @param      url  The URL to send the DELETE request to.
- * @param      headers  The headers to send with the DELETE request.
- * @param      data  The data to send with the DELETE request.
- * @note       The received data will be handled asynchronously via the callback.
- */
-bool flipper_http_delete_request_with_headers(const char *url, const char *headers, const char *payload)
-{
-    if (!url || !headers || !payload)
-    {
-        FURI_LOG_E("FlipperHTTP", "Invalid arguments provided to flipper_http_delete_request_with_headers.");
-        return false;
-    }
-
-    // Prepare DELETE request command with headers and data
-    char command[256];
-    int ret = snprintf(command, sizeof(command), "[DELETE/HTTP]{\"url\":\"%s\",\"headers\":%s,\"payload\":%s}", url, headers, payload);
-    if (ret < 0 || ret >= (int)sizeof(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to format DELETE request command with headers and data.");
-        return false;
-    }
-
-    // Send DELETE request via UART
-    if (!flipper_http_send_data(command))
-    {
-        FURI_LOG_E("FlipperHTTP", "Failed to send DELETE request command with headers and data.");
-        return false;
-    }
-
-    // The response will be handled asynchronously via the callback
-    return true;
-}
-// Function to handle received data asynchronously
-/**
- * @brief      Callback function to handle received data asynchronously.
- * @return     void
- * @param      line     The received line.
- * @param      context  The context passed to the callback.
- * @note       The received data will be handled asynchronously via the callback and handles the state of the UART.
- */
-void flipper_http_rx_callback(const char *line, void *context)
-{
-
-    if (!line || !context)
-    {
-        FURI_LOG_E(HTTP_TAG, "Invalid arguments provided to flipper_http_rx_callback.");
-        return;
-    }
-
-    // Trim the received line to check if it's empty
-    char *trimmed_line = trim(line);
-    if (trimmed_line != NULL && trimmed_line[0] != '\0')
-    {
-        fhttp.last_response = (char *)line;
-    }
-    free(trimmed_line); // Free the allocated memory for trimmed_line
-
-    if (fhttp.state != INACTIVE && fhttp.state != ISSUE)
-    {
-        fhttp.state = RECEIVING;
-    }
-
-    // Uncomment below line to log the data received over UART
-    // FURI_LOG_I(HTTP_TAG, "Received UART line: %s", line);
-
-    // Check if we've started receiving data from a GET request
-    if (fhttp.started_receiving_get)
-    {
-        // Restart the timeout timer each time new data is received
-        furi_timer_restart(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
-
-        if (strstr(line, "[GET/END]") != NULL)
-        {
-            FURI_LOG_I(HTTP_TAG, "GET request completed.");
-            // Stop the timer since we've completed the GET request
-            furi_timer_stop(fhttp.get_timeout_timer);
-
-            if (fhttp.received_data)
-            {
-                /* uncomment if you want to save the received data to the external storage
-                if (!fhttp.is_bytes_request)
-                {
-                    flipper_http_save_received_data(strlen(fhttp.received_data), fhttp.received_data);
-                }
-                */
-                fhttp.started_receiving_get = false;
-                fhttp.just_started_get = false;
-                fhttp.state = IDLE;
-                return;
-            }
-            else
-            {
-                FURI_LOG_E(HTTP_TAG, "No data received.");
-                fhttp.started_receiving_get = false;
-                fhttp.just_started_get = false;
-                fhttp.state = IDLE;
-                return;
-            }
-        }
-
-        // Append the new line to the existing data
-        if (fhttp.received_data == NULL)
-        {
-            fhttp.received_data = (char *)malloc(strlen(line) + 2); // +2 for newline and null terminator
-            if (fhttp.received_data)
-            {
-                strcpy(fhttp.received_data, line);
-                fhttp.received_data[strlen(line)] = '\n';     // Add newline
-                fhttp.received_data[strlen(line) + 1] = '\0'; // Null terminator
-            }
-        }
-        else
-        {
-            size_t current_len = strlen(fhttp.received_data);
-            size_t new_size = current_len + strlen(line) + 2; // +2 for newline and null terminator
-            fhttp.received_data = (char *)realloc(fhttp.received_data, new_size);
-            if (fhttp.received_data)
-            {
-                memcpy(fhttp.received_data + current_len, line, strlen(line)); // Copy line at the end of the current data
-                fhttp.received_data[current_len + strlen(line)] = '\n';        // Add newline
-                fhttp.received_data[current_len + strlen(line) + 1] = '\0';    // Null terminator
-            }
-        }
-
-        if (!fhttp.just_started_get)
-        {
-            fhttp.just_started_get = true;
-        }
-        return;
-    }
-
-    // Check if we've started receiving data from a POST request
-    else if (fhttp.started_receiving_post)
-    {
-        // Restart the timeout timer each time new data is received
-        furi_timer_restart(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
-
-        if (strstr(line, "[POST/END]") != NULL)
-        {
-            FURI_LOG_I(HTTP_TAG, "POST request completed.");
-            // Stop the timer since we've completed the POST request
-            furi_timer_stop(fhttp.get_timeout_timer);
-
-            if (fhttp.received_data)
-            {
-                /* uncomment if you want to save the received data to the external storage
-                if (!fhttp.is_bytes_request)
-                {
-                    flipper_http_save_received_data(strlen(fhttp.received_data), fhttp.received_data);
-                }
-                */
-                fhttp.started_receiving_post = false;
-                fhttp.just_started_post = false;
-                fhttp.state = IDLE;
-                return;
-            }
-            else
-            {
-                FURI_LOG_E(HTTP_TAG, "No data received.");
-                fhttp.started_receiving_post = false;
-                fhttp.just_started_post = false;
-                fhttp.state = IDLE;
-                return;
-            }
-        }
-
-        // Append the new line to the existing data
-        if (fhttp.received_data == NULL)
-        {
-            fhttp.received_data = (char *)malloc(strlen(line) + 2); // +2 for newline and null terminator
-            if (fhttp.received_data)
-            {
-                strcpy(fhttp.received_data, line);
-                fhttp.received_data[strlen(line)] = '\n';     // Add newline
-                fhttp.received_data[strlen(line) + 1] = '\0'; // Null terminator
-            }
-        }
-        else
-        {
-            size_t current_len = strlen(fhttp.received_data);
-            size_t new_size = current_len + strlen(line) + 2; // +2 for newline and null terminator
-            fhttp.received_data = (char *)realloc(fhttp.received_data, new_size);
-            if (fhttp.received_data)
-            {
-                memcpy(fhttp.received_data + current_len, line, strlen(line)); // Copy line at the end of the current data
-                fhttp.received_data[current_len + strlen(line)] = '\n';        // Add newline
-                fhttp.received_data[current_len + strlen(line) + 1] = '\0';    // Null terminator
-            }
-        }
-
-        if (!fhttp.just_started_post)
-        {
-            fhttp.just_started_post = true;
-        }
-        return;
-    }
-
-    // Check if we've started receiving data from a PUT request
-    else if (fhttp.started_receiving_put)
-    {
-        // Restart the timeout timer each time new data is received
-        furi_timer_restart(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
-
-        if (strstr(line, "[PUT/END]") != NULL)
-        {
-            FURI_LOG_I(HTTP_TAG, "PUT request completed.");
-            // Stop the timer since we've completed the PUT request
-            furi_timer_stop(fhttp.get_timeout_timer);
-
-            if (fhttp.received_data)
-            {
-                // uncomment if you want to save the received data to the external storage
-                // flipper_http_save_received_data(strlen(fhttp.received_data), fhttp.received_data);
-                fhttp.started_receiving_put = false;
-                fhttp.just_started_put = false;
-                fhttp.state = IDLE;
-                return;
-            }
-            else
-            {
-                FURI_LOG_E(HTTP_TAG, "No data received.");
-                fhttp.started_receiving_put = false;
-                fhttp.just_started_put = false;
-                fhttp.state = IDLE;
-                return;
-            }
-        }
-
-        // Append the new line to the existing data
-        if (fhttp.received_data == NULL)
-        {
-            fhttp.received_data = (char *)malloc(strlen(line) + 2); // +2 for newline and null terminator
-            if (fhttp.received_data)
-            {
-                strcpy(fhttp.received_data, line);
-                fhttp.received_data[strlen(line)] = '\n';     // Add newline
-                fhttp.received_data[strlen(line) + 1] = '\0'; // Null terminator
-            }
-        }
-        else
-        {
-            size_t current_len = strlen(fhttp.received_data);
-            size_t new_size = current_len + strlen(line) + 2; // +2 for newline and null terminator
-            fhttp.received_data = (char *)realloc(fhttp.received_data, new_size);
-            if (fhttp.received_data)
-            {
-                memcpy(fhttp.received_data + current_len, line, strlen(line)); // Copy line at the end of the current data
-                fhttp.received_data[current_len + strlen(line)] = '\n';        // Add newline
-                fhttp.received_data[current_len + strlen(line) + 1] = '\0';    // Null terminator
-            }
-        }
-
-        if (!fhttp.just_started_put)
-        {
-            fhttp.just_started_put = true;
-        }
-        return;
-    }
-
-    // Check if we've started receiving data from a DELETE request
-    else if (fhttp.started_receiving_delete)
-    {
-        // Restart the timeout timer each time new data is received
-        furi_timer_restart(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
-
-        if (strstr(line, "[DELETE/END]") != NULL)
-        {
-            FURI_LOG_I(HTTP_TAG, "DELETE request completed.");
-            // Stop the timer since we've completed the DELETE request
-            furi_timer_stop(fhttp.get_timeout_timer);
-
-            if (fhttp.received_data)
-            {
-                // uncomment if you want to save the received data to the external storage
-                // flipper_http_save_received_data(strlen(fhttp.received_data), fhttp.received_data);
-                fhttp.started_receiving_delete = false;
-                fhttp.just_started_delete = false;
-                fhttp.state = IDLE;
-                return;
-            }
-            else
-            {
-                FURI_LOG_E(HTTP_TAG, "No data received.");
-                fhttp.started_receiving_delete = false;
-                fhttp.just_started_delete = false;
-                fhttp.state = IDLE;
-                return;
-            }
-        }
-
-        // Append the new line to the existing data
-        if (fhttp.received_data == NULL)
-        {
-            fhttp.received_data = (char *)malloc(strlen(line) + 2); // +2 for newline and null terminator
-            if (fhttp.received_data)
-            {
-                strcpy(fhttp.received_data, line);
-                fhttp.received_data[strlen(line)] = '\n';     // Add newline
-                fhttp.received_data[strlen(line) + 1] = '\0'; // Null terminator
-            }
-        }
-        else
-        {
-            size_t current_len = strlen(fhttp.received_data);
-            size_t new_size = current_len + strlen(line) + 2; // +2 for newline and null terminator
-            fhttp.received_data = (char *)realloc(fhttp.received_data, new_size);
-            if (fhttp.received_data)
-            {
-                memcpy(fhttp.received_data + current_len, line, strlen(line)); // Copy line at the end of the current data
-                fhttp.received_data[current_len + strlen(line)] = '\n';        // Add newline
-                fhttp.received_data[current_len + strlen(line) + 1] = '\0';    // Null terminator
-            }
-        }
-
-        if (!fhttp.just_started_delete)
-        {
-            fhttp.just_started_delete = true;
-        }
-        return;
-    }
-
-    // Handle different types of responses
-    if (strstr(line, "[SUCCESS]") != NULL || strstr(line, "[CONNECTED]") != NULL)
-    {
-        FURI_LOG_I(HTTP_TAG, "Operation succeeded.");
-    }
-    else if (strstr(line, "[INFO]") != NULL)
-    {
-        FURI_LOG_I(HTTP_TAG, "Received info: %s", line);
-
-        if (fhttp.state == INACTIVE && strstr(line, "[INFO] Already connected to Wifi.") != NULL)
-        {
-            fhttp.state = IDLE;
-        }
-    }
-    else if (strstr(line, "[GET/SUCCESS]") != NULL)
-    {
-        FURI_LOG_I(HTTP_TAG, "GET request succeeded.");
-        fhttp.started_receiving_get = true;
-        furi_timer_start(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
-        fhttp.state = RECEIVING;
-        fhttp.received_data = NULL;
-
-        // for GET request, save data only if it's a bytes request
-        fhttp.save_data = fhttp.is_bytes_request;
-        return;
-    }
-    else if (strstr(line, "[POST/SUCCESS]") != NULL)
-    {
-        FURI_LOG_I(HTTP_TAG, "POST request succeeded.");
-        fhttp.started_receiving_post = true;
-        furi_timer_start(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
-        fhttp.state = RECEIVING;
-        fhttp.received_data = NULL;
-
-        // for POST request, save data only if it's a bytes request
-        fhttp.save_data = fhttp.is_bytes_request;
-        return;
-    }
-    else if (strstr(line, "[PUT/SUCCESS]") != NULL)
-    {
-        FURI_LOG_I(HTTP_TAG, "PUT request succeeded.");
-        fhttp.started_receiving_put = true;
-        furi_timer_start(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
-        fhttp.state = RECEIVING;
-        fhttp.received_data = NULL;
-        return;
-    }
-    else if (strstr(line, "[DELETE/SUCCESS]") != NULL)
-    {
-        FURI_LOG_I(HTTP_TAG, "DELETE request succeeded.");
-        fhttp.started_receiving_delete = true;
-        furi_timer_start(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
-        fhttp.state = RECEIVING;
-        fhttp.received_data = NULL;
-        return;
-    }
-    else if (strstr(line, "[DISCONNECTED]") != NULL)
-    {
-        FURI_LOG_I(HTTP_TAG, "WiFi disconnected successfully.");
-    }
-    else if (strstr(line, "[ERROR]") != NULL)
-    {
-        FURI_LOG_E(HTTP_TAG, "Received error: %s", line);
-        fhttp.state = ISSUE;
-        return;
-    }
-    else if (strstr(line, "[PONG]") != NULL)
-    {
-        FURI_LOG_I(HTTP_TAG, "Received PONG response: Wifi Dev Board is still alive.");
-
-        // send command to connect to WiFi
-        if (fhttp.state == INACTIVE)
-        {
-            fhttp.state = IDLE;
-            return;
-        }
-    }
-
-    if (fhttp.state == INACTIVE && strstr(line, "[PONG]") != NULL)
-    {
-        fhttp.state = IDLE;
-    }
-    else if (fhttp.state == INACTIVE && strstr(line, "[PONG]") == NULL)
-    {
-        fhttp.state = INACTIVE;
-    }
-    else
-    {
-        fhttp.state = IDLE;
-    }
-}
-// Function to save received data to a file
-/**
- * @brief      Save the received data to a file.
- * @return     true if the data was saved successfully, false otherwise.
- * @param      bytes_received  The number of bytes received.
- * @param      line_buffer     The buffer containing the received data.
- * @note       The data will be saved to a file in the STORAGE_EXT_PATH_PREFIX "/apps_data/" http_tag "/received_data.txt" directory.
- */
-bool flipper_http_save_received_data(size_t bytes_received, const char line_buffer[])
-{
-    const char *output_file_path = STORAGE_EXT_PATH_PREFIX "/apps_data/" http_tag "/received_data.txt";
-
-    // Ensure the directory exists
-    char directory_path[128];
-    snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/" http_tag);
-
-    Storage *_storage = NULL;
-    File *_file = NULL;
-    // Open the storage if not opened already
-    // Initialize storage and create the directory if it doesn't exist
-    _storage = furi_record_open(RECORD_STORAGE);
-    storage_common_mkdir(_storage, directory_path); // Create directory if it doesn't exist
-    _file = storage_file_alloc(_storage);
-
-    // Open file for writing and append data line by line
-    if (!storage_file_open(_file, output_file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS))
-    {
-        FURI_LOG_E(HTTP_TAG, "Failed to open output file for writing.");
-        storage_file_free(_file);
-        furi_record_close(RECORD_STORAGE);
-        return false;
-    }
-
-    // Write each line received from the UART to the file
-    if (bytes_received > 0 && _file)
-    {
-        storage_file_write(_file, line_buffer, bytes_received);
-        storage_file_write(_file, "\n", 1); // Add a newline after each line
-    }
-    else
-    {
-        FURI_LOG_E(HTTP_TAG, "No data received.");
-        return false;
-    }
-
-    if (_file)
-    {
-        storage_file_close(_file);
-        storage_file_free(_file);
-        _file = NULL;
-    }
-    if (_storage)
-    {
-        furi_record_close(RECORD_STORAGE);
-        _storage = NULL;
-    }
-
-    return true;
-}
-// Function to trim leading and trailing spaces and newlines from a constant string
-char *trim(const char *str)
-{
-    const char *end;
-    char *trimmed_str;
-    size_t len;
-
-    // Trim leading space
-    while (isspace((unsigned char)*str))
-        str++;
-
-    // All spaces?
-    if (*str == 0)
-        return strdup(""); // Return an empty string if all spaces
-
-    // Trim trailing space
-    end = str + strlen(str) - 1;
-    while (end > str && isspace((unsigned char)*end))
-        end--;
-
-    // Set length for the trimmed string
-    len = end - str + 1;
-
-    // Allocate space for the trimmed string and null terminator
-    trimmed_str = (char *)malloc(len + 1);
-    if (trimmed_str == NULL)
-    {
-        return NULL; // Handle memory allocation failure
-    }
-
-    // Copy the trimmed part of the string into trimmed_str
-    strncpy(trimmed_str, str, len);
-    trimmed_str[len] = '\0'; // Null terminate the string
-
-    return trimmed_str;
-}
-
-/**
- * @brief Process requests and parse JSON data asynchronously
- * @param http_request The function to send the request
- * @param parse_json The function to parse the JSON
- * @return true if successful, false otherwise
- */
-bool flipper_http_process_response_async(
-    bool (*http_request)(void),
-    bool (*parse_json)(void))
-{
-    if (http_request()) // start the async request
-    {
-        furi_timer_start(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
-        fhttp.state = RECEIVING;
-    }
-    else
-    {
-        FURI_LOG_E(HTTP_TAG, "Failed to send request");
-        return false;
-    }
-    while (fhttp.state == RECEIVING && furi_timer_is_running(fhttp.get_timeout_timer) > 0)
-    {
-        // Wait for the request to be received
-        furi_delay_ms(100);
-    }
-    furi_timer_stop(fhttp.get_timeout_timer);
-    if (!parse_json()) // parse the JSON before switching to the view (synchonous)
-    {
-        FURI_LOG_E(HTTP_TAG, "Failed to parse the JSON...");
-        return false;
-    }
-    furi_timer_stop(fhttp.get_timeout_timer);
-    return true;
-}
-
-#endif // FLIPPER_HTTP_H

+ 0 - 370
assets/FlipperHTTP/flipper_http.js

@@ -1,370 +0,0 @@
-// Description: Flipper HTTP API for the Flipper Wifi Developer Board.
-// Global: flipper_http_init, flipper_http_deinit, flipper_http_rx_callback(), flipper_http_send_data, flipper_http_connect_wifi, flipper_http_disconnect_wifi, flipper_http_ping, flipper_http_save_wifi, flipper_http_get_request
-// License: MIT
-// Author: JBlanked
-// File: flipper_http.js
-
-let serial = require("serial");
-
-// Define the global `fhttp` object with all the functions
-let fhttp = {
-    // Constructor
-    init: function () {
-        serial.setup("usart", 115200);
-    },
-    // Deconstructor
-    deinit: function () {
-        serial.end();
-    },
-    // Read data from the serial port and return it line by line
-    read_data: function (delay_ms) {
-        let line = serial.readln(delay_ms);
-        let i = 5;
-        while (line === undefined && i > 0) {
-            line = serial.readln(delay_ms);
-            i--;
-        }
-        return line;
-    },
-    // Send data to the serial port
-    send_data: function (data) {
-        if (data === "") {
-            return;
-        }
-        serial.write(data);
-    },
-    // Clear the incoming serial by up to 10 lines
-    clear_buffer: function (search_for_success) {
-        let data = this.read_data(100);
-        let sdata = this.to_string(data);
-        let i = 0;
-        // clear all data until we get an expected response
-        while (i < 5 &&
-            (data !== undefined &&
-                (!search_for_success || (search_for_success && !this.includes(sdata, "[SUCCESS]"))) &&
-                !this.includes(sdata, "[ERROR]") &&
-                !this.includes(sdata, "[INFO]") &&
-                !this.includes(sdata, "[PONG]") &&
-                !this.includes(sdata, "[DISCONNECTED]") &&
-                !this.includes(sdata, "[CONNECTED]") &&
-                !this.includes(sdata, "[GET/STARTED]") &&
-                !this.includes(sdata, "[GET/END]"))) {
-            data = this.read_data(100);
-            sdata = this.to_string(data);
-            i++;
-        }
-    },
-    // Connect to wifi
-    connect_wifi: function () {
-        serial.write("[WIFI/CONNECT]");
-        let response = this.read_data(500);
-        if (response === undefined) {
-            return false;
-        }
-        this.clear_buffer(true); // Clear the buffer
-        return this.includes(this.to_string(response), "[SUCCESS]") || this.includes(this.to_string(response), "[CONNECTED]") || this.includes(this.to_string(response), "[INFO]");
-    },
-    // Disconnect from wifi
-    disconnect_wifi: function () {
-        serial.write("[WIFI/DISCONNECT]");
-        let response = this.read_data(500);
-        if (response === undefined) {
-            return false;
-        }
-        this.clear_buffer(true); // Clear the buffer
-        return this.includes(this.to_string(response), "[DISCONNECTED]") || this.includes(this.to_string(response), "WiFi stop");
-    },
-    // Send a ping to the board
-    ping: function () {
-        serial.write("[PING]");
-        let response = this.read_data(100);
-        if (response === undefined) {
-            return false;
-        }
-        this.clear_buffer(true); // Clear the buffer
-        return this.includes(this.to_string(response), "[PONG]");
-    },
-    // list available commands
-    list_commands: function () {
-        serial.write("[LIST]");
-        let response = this.read_data(500);
-        if (response === undefined) {
-            return "";
-        }
-        return this.to_string(response);
-    },
-    // Allow the LED to display while processing
-    led_on: function () {
-        serial.write("[LED/ON]");
-    },
-    // Disable the LED from displaying while processing
-    led_off: function () {
-        serial.write("[LED/OFF]");
-    },
-    // parse JSON data
-    parse_json: function (key, data) {
-        serial.write('[PARSE]{"key":"' + key + '","data":' + data + '}');
-        let response = this.read_data(500);
-        if (response === undefined) {
-            return "";
-        }
-        return this.to_string(response);
-    },
-    // parse JSON array
-    parse_json_array: function (key, index, data) {
-        serial.write('[PARSE/ARRAY]{"key":"' + key + '","index":' + index + ',"data":' + data + '}');
-        let response = this.read_data(500);
-        if (response === undefined) {
-            return "";
-        }
-        return this.to_string(response);
-    },
-    // Get Wifi network list
-    scan_wifi: function () {
-        serial.write("[WIFI/SCAN]");
-        let response = this.read_data(500);
-        if (response === undefined) {
-            return "";
-        }
-        return this.to_string(response);
-    },
-    // Save wifi settings
-    save_wifi: function (ssid, password) {
-        if (ssid === "" || password === "") {
-            return false;
-        }
-        let command = '[WIFI/SAVE]{"ssid":"' + ssid + '","password":"' + password + '"}';
-        serial.write(command);
-        let response = this.read_data(500);
-        if (response === undefined) {
-            this.clear_buffer(false); // Clear the buffer
-            return false;
-        }
-        let sresponse = this.to_string(response);
-        if (this.includes(sresponse, "[SUCCESS]")) {
-            this.clear_buffer(false); // Clear the buffer
-            this.clear_buffer(false); // Clear the buffer
-            return true;
-        }
-        else {
-            print("Failed to save: " + response);
-            this.clear_buffer(false); // Clear the buffer
-            return false;
-        }
-    },
-    // Get the IP address of the WiFi Devboard
-    ip_address: function () {
-        serial.write("[IP/ADDRESS]");
-        let response = this.read_data(500);
-        if (response === undefined) {
-            return "";
-        }
-        return this.to_string(response);
-    },
-    // Get the IP address of the connected WiFi network
-    ip_wifi: function () {
-        serial.write("[WIFI/IP]");
-        let response = this.read_data(500);
-        if (response === undefined) {
-            return "";
-        }
-        return this.to_string(response);
-    },
-    // Send a GET request to the board
-    // I reduced this to return the first line of the response that isnt undefined
-    // You'll also get 'out of memory' errors if you try to read/return too much data
-    // As mjs is updated, this can be improved
-    get_request: function (url) {
-        serial.write('[GET]' + url);
-        if (this.read_data(500) === "[GET/SUCCESS] GET request successful.") {
-            while (true) {
-                let line = this.read_data(500);
-                if (line === "[GET/END]") {
-                    break;
-                }
-                if (line !== undefined) {
-                    this.clear_buffer(false); // Clear the buffer
-                    return line;
-                }
-            }
-        }
-        else {
-            print("GET request failed");
-        }
-        this.clear_buffer(); // Clear the buffer
-        return "";
-    },
-    // another GET request but with headers
-    get_request_with_headers: function (url, headers) {
-        serial.write('[GET/HTTP]{url:"' + url + '",headers:' + headers + '}');
-        if (this.read_data(500) === "[GET/SUCCESS] GET request successful.") {
-            while (true) {
-                let line = this.read_data(500);
-                if (line === "[GET/END]") {
-                    break;
-                }
-                if (line !== undefined) {
-                    this.clear_buffer(false); // Clear the buffer
-                    return line;
-                }
-            }
-        }
-        else {
-            print("GET request failed");
-        }
-        this.clear_buffer(); // Clear the buffer
-        return "";
-    },
-    // send POST request with headers
-    post_request_with_headers: function (url, headers, data) {
-        serial.write('[POST/HTTP]{"url":"' + url + '","headers":' + headers + ',"payload":' + data + '}');
-        if (this.read_data(500) === "[POST/SUCCESS] POST request successful.") {
-            while (true) {
-                let line = this.read_data(500);
-                if (line === "[POST/END]") {
-                    break;
-                }
-                if (line !== undefined) {
-                    this.clear_buffer(false); // Clear the buffer
-                    return line;
-                }
-            }
-        }
-        else {
-            print("POST request failed");
-        }
-        this.clear_buffer(); // Clear the buffer
-        return "";
-    },
-    // send PUT request with headers
-    put_request_with_headers: function (url, headers, data) {
-        serial.write('[PUT/HTTP]{"url":"' + url + '","headers":' + headers + ',"payload":' + data + '}');
-        if (this.read_data(500) === "[PUT/SUCCESS] PUT request successful.") {
-            while (true) {
-                let line = this.read_data(500);
-                if (line === "[PUT/END]") {
-                    break;
-                }
-                if (line !== undefined) {
-                    this.clear_buffer(false); // Clear the buffer
-                    return line;
-                }
-            }
-        }
-        else {
-            print("PUT request failed");
-        }
-        this.clear_buffer(); // Clear the buffer
-        return "";
-    },
-    // send DELETE request with headers
-    delete_request_with_headers: function (url, headers, data) {
-        serial.write('[DELETE/HTTP]{"url":"' + url + '","headers":' + headers + ',"payload":' + data + '}');
-        if (this.read_data(500) === "[DELETE/SUCCESS] DELETE request successful.") {
-            while (true) {
-                let line = this.read_data(500);
-                if (line === "[DELETE/END]") {
-                    break;
-                }
-                if (line !== undefined) {
-                    this.clear_buffer(false); // Clear the buffer
-                    return line;
-                }
-            }
-        }
-        else {
-            print("DELETE request failed");
-        }
-        this.clear_buffer(); // Clear the buffer
-        return "";
-    },
-    // Helper function to check if a string contains another string
-    includes: function (text, search) {
-        let stringLength = text.length;
-        let searchLength = search.length;
-        if (stringLength < searchLength) {
-            return false;
-        }
-        for (let i = 0; i < stringLength; i++) {
-            if (text[i] === search[0]) {
-                let found = true;
-                for (let j = 1; j < searchLength; j++) {
-                    if (text[i + j] !== search[j]) {
-                        found = false;
-                        break;
-                    }
-                }
-                if (found) {
-                    return true;
-                }
-            }
-        }
-    },
-    // Convert an array of characters to a string
-    to_string: function (text) {
-        if (text === undefined) {
-            return "";
-        }
-        let return_text = "";
-        for (let i = 0; i < text.length; i++) {
-            return_text += text[i];
-        }
-        return return_text;
-    }
-};
-
-/* Example Usage:
-
-let textbox = require("textbox");
-textbox.setConfig("end", "text");
-textbox.show();
-textbox.addText("Flipper HTTP Example:\n\n");
-// Initialize the flipper http object
-fhttp.init();
-textbox.addText("Initialized!\n");
-// Send ping to the board
-let response = fhttp.ping();
-
-if (response) {
-    textbox.addText("Ping successful\nSaving wifi settings...\n");
-    let success = fhttp.save_wifi("JBlanked", "maingirl");
-    if (success) {
-        textbox.addText("Wifi settings saved\nSending GET request..\n");
-        let url = "https://catfact.ninja/fact";
-        let data = fhttp.get_request_with_headers(url, '{"User-Agent":"curl/7.64.1","Content-Type":"application/json"}');
-        if (data !== undefined && data !== "") {
-            textbox.addText("GET request successful!\n\nReturned Data: \n\n" + data + "\n\nDisconnecting from wifi...\n");
-            if (fhttp.disconnect_wifi()) {
-                textbox.addText("Disconnected from wifi.\n");
-            }
-            else {
-                textbox.addText("Failed to disconnect from wifi.\n");
-            }
-
-        }
-        else {
-            textbox.addText("GET request failed.\nDisconnecting from wifi...\n");
-            if (fhttp.disconnect_wifi()) {
-                textbox.addText("Disconnected from wifi.\n");
-            }
-            else {
-                textbox.addText("Failed to disconnect from wifi.\n");
-            }
-        }
-    }
-    else {
-        textbox.addText("Wifi settings failed to save.\n");
-    }
-}
-else {
-    textbox.addText("Ping failed.\n");
-}
-textbox.addText("Press BACK twice to exit..\n");
-delay(100000); // Wait for user to hit back
-textbox.addText("\nTimeout exceeded.\nExiting...\n");
-delay(5000);
-// Destructor
-fhttp.deinit();
-
-textbox.addText("Deinitialized!\n");
-/*

+ 0 - 310
assets/FlipperHTTP/flipper_http.py

@@ -1,310 +0,0 @@
-"""
-This is only available in uPython in version 1.5.0. and above: https://ofabel.github.io/mp-flipper/reference.html#classes
-Author - JBlanked
-For use with Flipper Zero and the FlipperHTTP flash: https://github.com/jblanked/WebCrawler-FlipperZero/tree/main/assets/FlipperHTTP
-Individual functions to save memory (uPython has already pushed the limits)
-Lastly, be careful looping in the requests, you'll get a furi check error. I'm assuming it's a memory issue and will be fixed in future updates.
-"""
-
-import time
-import flipperzero as f0
-
-
-def flipper_print(*args, sep=" ", end="\n", clear_screen=True, y_start=0):
-    """Print text to the Flipper Zero screen since print() doesn't show on the screen"""
-    # Combine all arguments into a single string, manually joining without using splitlines
-    text = sep.join(map(str, args)) + end
-
-    # Optionally clear the screen before printing
-    if clear_screen:
-        f0.canvas_clear()
-        f0.canvas_update()  # Ensure the screen is cleared
-
-    # Manually handle line breaks by splitting on "\n"
-    lines = []
-    current_line = ""
-    for char in text:
-        if char == "\n":
-            lines.append(current_line)
-            current_line = ""
-        else:
-            current_line += char
-
-    lines.append(current_line)  # Add the last line
-
-    # Display each line on the screen
-    y_position = y_start
-    for line in lines:
-        f0.canvas_set_text(0, y_position, line)  # Display each line
-        y_position += 10  # Adjust line spacing
-
-    # Update the display to show the text
-    f0.canvas_update()
-
-
-def flipper_http_read_data(sleep_ms: int = 100) -> str:
-    """Read data from the Flipper Zero UART"""
-    with f0.uart_open(f0.UART_MODE_USART, 115200) as uart:
-        raw_data = uart.readline()
-        i = 0
-        while len(raw_data) == 0 and i < 5:
-            raw_data = uart.readline()
-
-            if len(raw_data) > 0:
-                data = raw_data.decode()
-                # flipper_print(data)
-                return data
-
-            i += 1
-
-            time.sleep_ms(sleep_ms)
-
-        return None
-
-
-def flipper_http_send_data(value: str):
-    """Send data to the Flipper Zero UART"""
-    if value is None:
-        return
-    with f0.uart_open(f0.UART_MODE_USART, 115200) as uart:
-        uart.write(value.encode())
-        uart.flush()
-
-
-def clear_buffer():
-    """Clear the buffer of the Flipper Zero UART"""
-    data = flipper_http_read_data()
-    while data is not None:
-        data = flipper_http_read_data()
-
-
-def flipper_http_ping() -> bool:
-    """Ping the WiFi Devboard to check if it is connected"""
-    flipper_http_send_data("[PING]")
-    data = flipper_http_read_data()
-    clear_buffer()
-    return "[PONG]" in data
-
-
-def flipper_http_connect_wifi() -> bool:
-    """Connect to WiFi"""
-    flipper_http_send_data("[WIFI/CONNECT]")
-    data = flipper_http_read_data()
-    clear_buffer()
-    # had to write it this way due to mPython limitations
-    if "[SUCCESS]" in data:
-        return True
-    if "[CONNECTED]" in data:
-        return True
-    elif "[INFO]" in data:
-        return True
-    return False
-
-
-def flipper_http_disconnect_wifi() -> bool:
-    """Disconnect from WiFi"""
-    flipper_http_send_data("[WIFI/DISCONNECT]")
-    data = flipper_http_read_data()
-    clear_buffer()
-    if "[DISCONNECTED]" in data:
-        return True
-    if "WiFi stop" in data:
-        return True
-    return False
-
-
-def flipper_http_list_commands() -> str:
-    """List all available commands"""
-    flipper_http_send_data("[LIST]")
-    data = flipper_http_read_data(500)
-    clear_buffer()
-    return data
-
-
-def flipper_http_led_on():
-    """Allow the LED to display while processing"""
-    flipper_http_send_data("[LED/ON]")
-
-
-def flipper_http_led_off():
-    """Disable the LED from displaying while processing"""
-    flipper_http_send_data("[LED/OFF]")
-
-
-def flipper_http_parse_json(key: str, json_data: str) -> str:
-    """Parse JSON data"""
-    flipper_http_send_data('[PARSE]{"key":"' + key + '","json":' + json_data + "}")
-
-    data = flipper_http_read_data(500)
-    clear_buffer()
-    return data
-
-
-def flipper_http_parse_json_array(key: str, index: int, json_data: str) -> str:
-    """Parse JSON data"""
-    flipper_http_send_data(
-        '[PARSE/ARRAY]{"key":"'
-        + key
-        + '","index":"'
-        + index
-        + '","json":'
-        + json_data
-        + "}"
-    )
-    data = flipper_http_read_data(500)
-    clear_buffer()
-    return data
-
-
-def flipper_http_scan_wifi() -> str:
-    """Scan for WiFi networks"""
-    flipper_http_send_data("[WIFI/SCAN]")
-    data = flipper_http_read_data(500)
-    clear_buffer()
-    return data
-
-
-def flipper_http_save_wifi(ssid: str, password: str) -> bool:
-    """Save WiFi credentials"""
-    if ssid is None or password is None:
-        return False
-    flipper_http_send_data(
-        '[WIFI/SAVE]{"ssid":"' + ssid + '","password":"' + password + '"}'
-    )
-    data = flipper_http_read_data()
-    clear_buffer()
-    return "[SUCCESS]" in data
-
-
-def flipper_http_ip_address() -> str:
-    """Get the IP address of the WiFi Devboard"""
-    flipper_http_send_data("[IP/ADDRESS]")
-    data = flipper_http_read_data()
-    clear_buffer()
-    return data
-
-
-def flipper_http_ip_wifi() -> str:
-    """Get the IP address of the connected WiFi network"""
-    flipper_http_send_data("[WIFI/IP]")
-    data = flipper_http_read_data()
-    clear_buffer()
-    return data
-
-
-def flipper_http_get_request(url: str) -> str:
-    """Send a GET request to the specified URL"""
-    if url is None:
-        return ""
-    flipper_http_send_data("[GET]" + url)
-    if "[GET/SUCCESS]" in flipper_http_read_data():
-        data = flipper_http_read_data()
-        clear_buffer()
-        return data
-    clear_buffer()
-    return ""
-
-
-def flipper_http_get_request_with_headers(url: str, headers: str) -> str:
-    """Send a GET request to the specified URL with headers"""
-    if url is None:
-        return ""
-    flipper_http_send_data('[GET/HTTP]{url:"' + url + '",headers:' + headers + "}")
-    if "[GET/SUCCESS]" in flipper_http_read_data():
-        data = flipper_http_read_data(500)
-        clear_buffer()
-        return data
-    clear_buffer()
-    return ""
-
-
-def flipper_http_post_request_with_headers(url: str, headers: str, data: str):
-    """Send a POST request to the specified URL with headers and data"""
-    if url is None:
-        return ""
-    flipper_http_send_data(
-        '[POST/HTTP]{"url":"'
-        + url
-        + '","headers":'
-        + headers
-        + ',"payload":'
-        + data
-        + "}"
-    )
-    if "[POST/SUCCESS]" in flipper_http_read_data():
-        data = flipper_http_read_data(500)
-        clear_buffer()
-        return data
-    clear_buffer()
-    return ""
-
-
-def flipper_http_put_request_with_headers(url: str, headers: str, data: str):
-    """Send a PUT request to the specified URL with headers and data"""
-    if url is None:
-        return ""
-    flipper_http_send_data(
-        '[PUT/HTTP]{"url":"'
-        + url
-        + '","headers":'
-        + headers
-        + ',"payload":'
-        + data
-        + "}"
-    )
-    if "[PUT/SUCCESS]" in flipper_http_read_data():
-        data = flipper_http_read_data(500)
-        clear_buffer()
-        return data
-    clear_buffer()
-    return ""
-
-
-def flipper_http_delete_request_with_headers(url: str, headers: str, data: str):
-    """Send a DELETE request to the specified URL with headers and data"""
-    if url is None:
-        return ""
-    flipper_http_send_data(
-        '[DELETE/HTTP]{"url":"'
-        + url
-        + '","headers":'
-        + headers
-        + ',"payload":'
-        + data
-        + "}"
-    )
-    if "[DELETE/SUCCESS]" in flipper_http_read_data():
-        data = flipper_http_read_data(500)
-        clear_buffer()
-        return data
-    clear_buffer()
-    return ""
-
-
-# Example of how to use the functions
-""" uncomment to run the example
-flipper_print("Starting HTTP example")
-clear_buffer()  # Clear the buffer before starting
-time.sleep(1)
-if flipper_http_ping() and flipper_http_save_wifi("JBlanked", "maingirl"):
-    flipper_print("WiFi saved successfully!")
-    time.sleep(2)
-    if flipper_http_connect_wifi():
-        flipper_print("WiFi connected successfully!")
-        time.sleep(2)
-        flipper_print(
-            flipper_http_get_request_with_headers(
-                "https://httpbin.org/get", "{Content-Type: application/json}"
-            )
-        )
-        time.sleep(2)
-
-        if flipper_http_disconnect_wifi():
-            flipper_print("WiFi disconnected successfully!")
-            time.sleep(2)
-else:
-    flipper_print("Failed to save WiFi credentials")
-    time.sleep(2)
-    flipper_print("Exiting...")
-    time.sleep(2)
-"""  # uncomment to run the example

BIN
assets/FlipperHTTP/flipper_http_bootloader.bin


BIN
assets/FlipperHTTP/flipper_http_firmware_a.bin


BIN
assets/FlipperHTTP/flipper_http_partitions.bin


BIN
assets/FlipperHTTP/flipper_http_pico_c++.uf2