Using new SoftAP Http pages to configure other settings

Hi,

I was wondering how would it be possible to program other parameters with the SoftAP HTTP page on the particle photon.
I’m using currently the example of the documentation: https://docs.particle.io/reference/firmware/photon/#softap-http-pages

I would like to be able to configure my device this way because I might not have an internet access so I dont want to use the cloud functions. With a webpage like that, it would be possible to configure the photon with a phone, tablet and computer very easily.

I looked at the code and to send the password and ssid to the particle photon, the webpage call configure-ap.

Can anybody point me what should I look for to do that?
Is there a way to modifiy configure-ap to accept more parameters or create an other function like configure-ap or to do something directly inside the “myPage” Function?

Thanks!

@Suprazz, running SoftAP to provide a local configuration web page for user apps (not just wifi creds) is coming to v0.6.0 of the firmware with a nice API. :grinning:

4 Likes

I’m really happy to hear that!

What is the time frame for v0.6.0?

1 Like

In the meantime, you can communicate between the webpage and the photon using HTTP requests, handled by the “myPage” function, so long as SYSTEM_THREAD(ENABLED) is called. Here’s my code to control the color of an Internet Button using a simple SoftAP webpage.

#pragma SPARK_NO_PREPROCESSOR

#include "Particle.h"
#include "softap_http.h"
#include "InternetButton.h"

SYSTEM_THREAD(ENABLED);

int r, g, b = 0;

struct Page
{
    const char* url;
    const char* mime_type;
    const char* data;
};


const char index_html[] = "<html><div align=\"center\"><form action=\"color\" method=\"get\"><input id=\"background-color\" name=\"color\" type=\"color\"/><input type=\"submit\" value=\"Go!\"/></form></div></html>";

Page myPages[] = {
     { "/index.html", "text/html", index_html },
     { nullptr }
};

void myPage(const char* url, ResponseCallback* cb, void* cbArg, Reader* body, Writer* result, void* reserved)
{
    String urlString = String(url);
    Serial.printlnf("handling page %s", url);
    char* data = body->fetch_as_string();
    Serial.println(String(data));
    free(data);

    if (strcmp(url,"/index")==0) {
        Serial.println("sending redirect");
        Header h("Location: /index.html\r\n");
        cb(cbArg, 0, 301, "text/plain", &h);
        return;
    }
    if (urlString.indexOf("/color") != -1) {
        r = (int)strtol(urlString.substring(14, 16).c_str(), nullptr, 16);
        g = (int)strtol(urlString.substring(16, 18).c_str(), nullptr, 16);
        b = (int)strtol(urlString.substring(18).c_str(), nullptr, 16);
        Serial.println(r);
        Serial.println(g);
        Serial.println(b);

    }

    int8_t idx = 0;
    for (;;idx++) {
        Page& p = myPages[idx];
        if (!p.url) {
            idx = -1;
            break;
        }
        else if (strcmp(url, p.url)==0) {
            break;
        }
    }

    if (idx==-1) {
        Header h("Location: /index.html\r\n");
        cb(cbArg, 0, 301, "text/plain", &h);
    }
    else {
        cb(cbArg, 0, 200, myPages[idx].mime_type, nullptr);
        result->write(myPages[idx].data);
    }
}

unsigned long t = 0;
InternetButton button = InternetButton();

STARTUP(softap_set_application_page_handler(myPage, nullptr));

void setup() {
    WiFi.listen();
    button.begin();
}

void loop() {
    if (millis()-t >= 200) {
        button.allLedsOn(r, g, b);
        t = millis();
    }
}
1 Like

Thanks! So simple!

I have an issue if I try to load a lot of data.
I’m trying to send a firmware upgrade via a form to the device in softap mode.
I’m able to receive around half of data (11k over 27k) and after that the connection close and body->read return zero but body->bytes_left return 14863.

I did a wireshark and I can see that all the data is send correctly to the photon.

I’m doing this code in myPage function.

I’m not sure what else I can do because I’m in listening mode and the main loop is not executed
I tried to add delays and Particle.Process() without success…

btw I tried with 0.5.2 and 0.6.0 rc2

if (urlString.indexOf("/upgrade") != -1) {
//Serial.println(body->bytes_left, DEC);

// voici le output:
/*
POST Data: ------WebKitFormBoundaryEEbsS0VLVz50qOeT
Content-Disposition: form-data; name="myfile"; filename="binfile"
Content-Type: application/octet-stream

content file here...
*/

uint8_t contentData[512];
int dataPos;
int datalength = body->read(contentData, sizeof(contentData));
String contentString = String((const char*)contentData);
Serial.print((const char*)&contentData[0]);

dataPos = contentString.indexOf("filename=");
Serial.printlnf("Index of filename: %d", dataPos);

if(dataPos != -1)
{
    // Get filename here if we want
    String filename = contentString.substring(dataPos + 10, contentString.indexOf("Content-Type")-1);
    Serial.printlnf("Filename: %s", filename.c_str());
}


dataPos = contentString.indexOf("octet-stream");
Serial.printlnf("Index of octet-stream: %d", dataPos);
if(dataPos != -1)
{
    dataPos += 12 + 4;            
    Serial.println("Data start here:");
    datalength -= dataPos;

    while (body->bytes_left)
{
                // dump data on serial port for now
                Serial.printf("%.2x", contentData[dataPos]);
                dataPos++;
                if (dataPos == datalength)
                {
                    //for (uint32_t ms = millis(); millis() - ms <= 100; Particle.process());
                    datalength = body->read(contentData, sizeof(contentData));
                    do
                    {
                        if(datalength == -1)
                            Serial.println("Datalength -1");
                        delay(50);
                        datalength = body->read(contentData, sizeof(contentData));
                        if (datalength == 0)
                        {
                            Serial.printlnf("Length = 0, Bytes left: %d", body->bytes_left);
                        }
                    } while (datalength <= 0 && body->bytes_left);
                    dataPos = 0;
                }
            }
        Serial.println("No more data");
        delay(20);    
    }

Thanks!

Issue is documented here: https://github.com/spark/firmware/issues/1131