Photon SoftAP Inputs

I’ve been working through the SoftAP example, trying to parse out which portions of the code are responsible for various actions, but i’m clearly boxing above my weight class here with all the HTML and JS code. The end goal is to take the SoftAP example as it currently exists, and adding maybe one or two additional text inputs to later be used in the looping software. Does the firmware as it currently stands have this capability, and if so how difficult is it to configure? I’m only looking to prompt for a string input to be stored as a variable.

The end goal here is to be able to ship out Photons that can be completely configured via the SoftAP page, but for now adding/changing inputs on the SoftAP index page would be enough.

Anyone got any ideas, or willing to explain how SoftAP handles variable inputs? Thanks.

There would be multiple ways to do that, but I just needed a quick and dirty “extension” of the SoftAP demo to take an input and pass that back for my application task.
So I just added an extra /control.html which contained the extra settings I desired as a <form>...</form>. But you can do that just as well in the original /index.html.

The only thing you’d have to do is to capture the const char* url and distill the form data you are interested in out of the URL and then strip off that extra stuff.

As said, quick and dirty :wink:

void myPage(const char* url, ResponseCallback* cb, void* cbArg, Reader* body, Writer* result, void* reserved)
{
    char  _url[strlen(url)+1];
    char* query;
    char* value;
 
    strcpy(_url, url);    // create a working copy of url
    if (strcmp(strtok_r(_url, "?&", &query), myPages[0].url) == 0)   
    { // is it my page (which I put to the front of myPages
      for(; query; strtok_r(NULL, "?&", &query)) 
      { // iterate over possibly query parameters?
        if(strcmp(strtok_r(query, "=", &value), "myValue") == 0) 
        { // I'm only interested in this specific key
          char* val = strtok_r(NULL, "?&=", &value);
          doSomethingWith(val);
        }
      }
    }
    ... // rest of original sample
}
1 Like

Damn ScruffR, you’re all over this place.

So let me see if i grasp what you’ve done here:

  • You edit the HTML file to include a space to add an input section for whatever the desired input is
    ( Im not really sure how this is done, but i grasp the concept)
  • That input is then fed into the URL
  • The section of code that you posted parses through the URL to get the variable that had been posted, then feeds it into the doSomethingWith() function (Presumably to be saved or used later once the SoftAP has quit and the main() loop is running)

Sound accurate?

Pretty much so.
But since I use SYSTEM_THREAD(ENABLED) the main loop() keeps running alongside the SoftAP stuff in Listening Mode.

One thing I forgot to show in my original snippet is that each subsequent instance of url needs to be replaced with _url.

@ScruffR @peekay123 @BulldogLowell

Based on your current knowledge base is the Soft AP code still working just fine on all current and old iOS & Android web browsers? I think I remember some of the newer iOS browsers had issues connecting for some reason and I was not sure if that got fixed or not.

I’m looking at different ways to program a product that has a digital display but no input buttons.

The devices will have a Photon built in and I need to be able to program it without the need for WiFi access so I’m thinking some modified Soft AP code may be the ticket.

I need to use the Soft AP to do what it’s intended to do which is setup the WiFi access point if there is one. I also need the ability to setup a few variables for the device to operate properly like:

  • Location Latitude & Longitude
  • UTC Time to Program if RTC Ever Looses Power and no WiFi is available to do it via web time.

I will have a digital display built into the product to provide system status after the Wifi Credentials & Latitude & Longitude have been set.

The Soft AP is the cheapest of all the available solutions. I’ve looked at LCD touch screens to touch screen inputs but they are at a minimum add an extra $40+ to the BOM which is less than desirable.

Sometimes the Longitude is a - number so I would need to pass that back to a variable successfully.

Do you see any reason this would not work or shouldn’t be relied upon on a consumer product?

AFAIK the problem is not the browsers but the mobile OS itself which - under some conditions and/or settings - just refuses to connect to an AP that does not also provide access to the internet, which the Photon will never be able to in SoftAP. So there isn't anything that can be done from Particle side IMO.
The owners of devices that refuse to connect to isolated APs need to find out how their device can be set up to accept such APs.

But for the Photon side of your intended use, that's definetly doable and has been done before.

Good to know.

Worst case they will need to just connect from a Laptop PC or Mac for the setup which shouldn’t be to hard to find.

Looks like recent sales shows Andriod has 80% of the market share these days anyways which is also good considering I think the Soft AP issue was just with iOS devices.

I feel good about that.

Now it looks like I’m going to need some sort of reed switch and a magnet to get the units into this Soft AP mode considering I do not want to add an external switch to prevent water intrusion as much as possible.

Do you know of any examples on the forum showing some modified Soft AP coding doing what I’m asking about?

For now I’ll try your example and see what I can figure out from it.

I have posted such an example once, but I can't find it just now.
I can boil down a bigger project tho' - or find the post :wink:


Update
Found it

1 Like

Cool, I’ll add that to the Soft AP code I’ve tested in the past and see what I can learn.

I’m sure I’ll have some questions and need some help although it doesn’t look terribly complicated at first glance.

I added your code but now I see I need to actually create another HTML page or add the <form>...</form> to the main Index page

I think that your modified void myPage code just looks for certain data in the www address string after it’s submitted and then pulls that data out from that www address string and saves it as a variable.

I have never created or edited the Soft AP page but I have seen @BulldogLowell post an example of how he did it.

I’m kinda lost as to how to move forward with adding a <form>...</form> to the main Index page to gather the needed data. I’ve made websites before so I figured I could edit the HTML in a web page editor maybe.

If you have any example code that demo’s how a single form is added to the index or config page I might be able to get the gist of it, right now I’m lost on what exactly needs to be done but it sounds simple enough :smile:

It’s not really complicated.
I can post my clumsy html page to give you a starter.
I usually first write the HTML on my PC in a plain text editor and open the file on the PC with a browser to see how it looks an once I’m “satisfied” replace " with \" (and some other minor things like wrapping it in double quotes to fit in a char[]) and copy that to my SoftAP code.

Here’s my control.html

const char ctrl[] = {
"<!DOCTYPE html>"
"<html lang=\"en\">"
"<head>"
"<meta charset=\"utf-8\">"
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0;\" />"
"<title>MikeStand</title>"
"<style>"
"form{"
"font: bold 15px/30px Georgia;"
"width: 100%;"
"height: 100%;"
"margin: 0 auto;"
"}"
"input[type=\"range\"].vertikal {"
"writing-mode: bt-lr; /* IE */"
"-webkit-appearance: slider-vertical; /* WebKit */"
"width: 10%;"
"height: 70%;"
"}"
"output {"
"position:absolute;"
"top:calc(50% - 2em);"
"width: 75%;"
"height: 2em;"
"text-align: center;"
"color: white;" 
"background-image: linear-gradient(160deg, white, lightgrey 10%, grey );"
"border-radius: 1em;"
"margin:0 auto;"
"padding:1em 0.5em;"
"display: inline-block;"
"}"
"output:after {"
"content: \"cm\";"
"width:2em;"
"}"
"</style>"
"</head>"
"<body>"
"<h1 style=\"text-align : center;\">HeightSetting</h1>"
"<form oninput=\"x.value=parseInt(dheight.value)\">"
"<div style=\"position:relative;\">"
"<input class=\"vertikal\" name=\"myValue\" id=\"dheight\" type=\"range\" min=\"-20\" value=\"0\" max=\"20\" orient=\"vertical\" >"
"<output name=\"x\" for=\"dheight\">0</output>"
"</div>"
"<br/>"
"<button submit style=\"width:100%;padding:0.5em;\">Go!</button>"
"</form>"
"</body>"
"</html>"
};

It features s slider to select a value -20cm ~ +20cm and a submit button and some CSS settings.
The only “interesting” part is the one between the <body>...</body> tags (and that could be made even simpler).

1 Like

I was able to figure out the other steps to get your control.html page to work :smile:

The page is nice clean and simple, I like it.

So I figured out that you just add the HTML for the new page in the same area where the index_html page data is stored as shown in the screenshot below from the SOFT AP demo code.

I added ScruffR’s control_html page code on the top line :

Next, I figured out that you have to add the web page link info for your new page as shown in the screenshot below. I added the /control.html page URL by just copying the style of the index page above it.

Now I know I need to figure out how to use your custom code to parse the URL string which contains the submitted form data after the submit form data button is pressed :slight_smile:

Same as the guy who started this thread says, I have this understanding of what is supposed to be going on here:

So if I’m following correctly I just need to add this highlighted snippet to the top of the code that is already in the void myPage function?

Can you elaborate on what exactly you mean by this or show what your code would look like we were phrase data from 2 different form boxes?

I'm not sure exactly how much of your code snippet needs to be duplicated when parsing more than pieces of data via the URL.

Thanks for your help with this. It's a powerful feature for sure.

I'll try to look up each function and see if I can figure it out myself in the mean time.

If you look at the preexisting part of myPage() you’ll see references to url. These need to be swapped for _url (the bare URL without the encoded form data).

To parse multiple key/value pairs you’d just add an else if() block inside the for() loop to check for anything other than myValue.

OK. So just to be clear there is only 3 references to URL in the myPage() function after adding your parsing code to the top of the function.

So below your parsing code, I find the 3 URL references circled in RED. Are these the references that need to be changed to _URL?


In your example, Microphone Stand Height after I hit the GO button I can see the number in the form in the URL which is nice. I understand were parsing the data we want out of the URL but in the example the next screen is blank. Can we tell it what page to load after we hit the GO button?

Also, I assume we can, but I should ask to be sure, can we insert variable data into the web page?

Like can the page that shows up after we hit the go button actually show the current state of that variable?

And another question. Since the device was connecting to the Photon with will probably not have internet access what functions are available to us when writing the HTML pages? Like how did you get the Slider in your example to show up? Are these just basic widgets available on current web browsers? I need to learn what is possible when creating these HTML pages.

This is the part that will send the next page

    if (idx==-1) {
      cb(cbArg, 0, 404, nullptr, nullptr);
    }
    else {  // here we prepare the next page to be sent
      cb(cbArg, 0, 200, myPages[idx].mime_type, nullptr);
      result->write(myPages[idx].data);
    }

So when you set idx of the page you want to be sent next you can control where to go after you received the form via code.
Alternatively - and more commonly - you could prepare the target URL for the submit button via the dedicated <form action="/whereToGo.html"> attribute. In this case you'd not check for control.html (which I do via myPages[0].url assuming that control.html is the first page in the list, you've added it as second) but for whereToGo.html in the parameter decoding block.

You can also modify the page, by copying a template page into a non-const char[] and inject the desired data via standard string manipulation.

In regards to my comment about adding an else if() block, you need to take the strtok_r() part out of the initial if() statement and only execute it once, per iteration of for() and check the one result against all your possible options.

As you correctly assumed, in my page I only use standard HTML5.0 features present in most modern browsers, but as shown in the original SoftAP demo, you can also extend your options by supplying extra packages like these application/javascript entries in myPages[] (and the respective implementation strings).
For more elaborate tasks (or even images) you'd maybe want to go for an SD card to hold these extra packages.

Thanks again for the good info. I’ll see what I can work up with what you have given me and report back.

Any luck? I had essentially the same problem to tackle but this HTML coding is pretty far outside my wheelhouse.

Yea, no matter how much I tried to understand the HTML and linking functions it kept frying my brain :smile:

I decided to add a $20 LCD screen with resistive touch panel for data input vs the SOFT AP input method because it’s just so much easier for me to work with for now.

If I wanted to go the Soft AP route in the future I would just pay somebody to do what I wanted.

Yeah, i hear ya. Embedded HTML claims another victim :dizzy_face: