Can Particle (Photon) provide a WiFi network!?

I had never tried this before, so I gave it a shot and it works. Quite well, actually, even with just the basic SoftAP support in 0.5.1!

Here’s my test circuit, just a potentiometer connected to A0. You can’t tell from the picture, but it’s in blinking blue (listening mode).

Here’s a screenshot of the web browser. Note that it’s connecting to http://192.168.0.1/index.html. The little box updates 10 times per second as you adjust the potentiometer!

And here’s the code:

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

// Hardware connections for demo:
// Potentiometer: A0 to center. Outsides to GND and 3V3.

SYSTEM_THREAD(ENABLED);

const int VALUE_PIN = A0;



// [start d1872940-586d-44a9-b719-4a67e8a29213]
// name=/index.html contentType=text/html size=700 modified=2016-08-26 07:30:43
const char fileData0[] = 
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
"<!DOCTYPE html>\n"
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
"<head>\n"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n"
"\n"
"<title>SoftAP Sample 1</title>\n"
"\n"
"<script src=\"https://code.jquery.com/jquery-3.1.0.min.js\"   integrity=\"sha256-cCueBR6CsyA4/9szpP"
"frX3s49M9vUU5BgtiJj06wt/s=\"   crossorigin=\"anonymous\"></script>\n"
"<script type=\"text/javascript\" src=\"main.js\"></script>   \n"
"<link rel=\"stylesheet\" type=\"text/css\" href=\"main.css\" />\n"
"\n"
"</head>\n"
"<body>\n"
"\n"
"<div id=\"main\">\n"
"\n"
"<h2>SoftAP Sample 1</h2>\n"
"\n"
"<form>\n"
"\n"
"<p>Current value: <input type=\"text\" id=\"valueText\" size=\"6\" value=\"0\" disabled=\"disabled\" /></p"
">\n"
"\n"
"</form>\n"
"\n"
"</div> <!-- main -->\n"
"\n"
"</body>\n"
"</html>\n"
"";

// name=/main.css contentType=text/css size=222 modified=2016-08-26 07:20:50
const char fileData1[] = 
"@CHARSET \"UTF-8\";\n"
"\n"
"body\n"
"{\n"
"background-color:#ffffff;\n"
"max-width:1000px;\n"
"}\n"
"\n"
"p,h1,h2,h3,li,td,div\n"
"{ \n"
"font-family: helvetica, sans-serif;\n"
"color:#000000;\n"
"font-size: small; \n"
"}\n"
"\n"
"p\n"
"{\n"
"max-width:1000px;\n"
"}\n"
"\n"
".hidden \n"
"{\n"
"display:none;\n"
"}\n"
"";

// name=/main.js contentType=application/javascript size=527 modified=2016-08-26 07:39:44
const char fileData2[] = 
"\n"
"var timerId;\n"
"\n"
"$(document).ready(function() {\n"
"\ttimerId = window.setInterval(timerCallback, 100);\n"
"});\n"
"\n"
"\n"
"function timerCallback() {\n"
"\t$.ajax({\n"
"\t\ttype : 'GET',\n"
"\t\turl : '/value',\n"
"\t\tdataType : 'json',\n"
"\t\tsuccess : getValueCallback,\n"
"\t\terror : dataError\n"
"\t});\n"
"\n"
"}\n"
"\n"
"function getValueCallback(values) {\t\n"
"\t$('#valueText').val(values.value.toString());\n"
"}\n"
"\n"
"\n"
"function dataError(jqXHR, textStatus, errorThrown) {\n"
"\tconsole.log(\"dataError \" + textStatus);\n"
"\tif (timerId != undefined) {\n"
"\t\twindow.clearTimeout(timerId);\n"
"\t\ttimerId = undefined;\n"
"\t}\n"
"}\n"
"\n"
"\n"
"";

typedef struct {
	const char *name;
	const char *mimeType;
	const uint8_t *data;
	size_t dataSize;
	unsigned long modified;
	bool isBinary;
} FileInfo;

const FileInfo fileInfo[] = {
	{"/index.html", "text/html", (const uint8_t *)fileData0, sizeof(fileData0) - 1, 1472211043, FALSE},
	{"/main.css", "text/css", (const uint8_t *)fileData1, sizeof(fileData1) - 1, 1472210450, FALSE},
	{"/main.js", "application/javascript", (const uint8_t *)fileData2, sizeof(fileData2) - 1, 1472211584, FALSE},
	{NULL, NULL, 0, 0, FALSE}
};
// [end d1872940-586d-44a9-b719-4a67e8a29213]

void pageHandler(const char* url, ResponseCallback* cb, void* cbArg, Reader* body, Writer* result, void* reserved); // forward declaration
void valuePageHandler(const char* url, ResponseCallback* cb, void* cbArg, Reader* body, Writer* result, void* reserved); // forward declaration

STARTUP(softap_set_application_page_handler(pageHandler, nullptr));


void setup() {
	Serial.begin(9600);
}

void loop() {

}

void pageHandler(const char* url, ResponseCallback* cb, void* cbArg, Reader* body, Writer* result, void* reserved) {

	if (strcmp(url, "/value") == 0) {
		valuePageHandler(url, cb, cbArg, body, result, reserved);
		return;
	}
    if (strcmp(url,"/index") == 0) {
        Serial.println("sending redirect to index.html");
        Header h("Location: /index.html\r\n");
        cb(cbArg, 0, 301, "text/plain", &h);
        return;
    }


	int index = -1;
	for(size_t ii = 0; fileInfo[ii].name != NULL; ii++) {
		if (strcmp(fileInfo[ii].name, url) == 0) {
			index = (int) ii;
			break;
		}
	}
	if (index >= 0) {
		cb(cbArg, 0, 200, fileInfo[index].mimeType, nullptr);
		result->write(fileInfo[index].data, fileInfo[index].dataSize);
		Serial.printlnf("returned url=%s dataSize=%d mimeType=%s", url, fileInfo[index].dataSize, fileInfo[index].mimeType);
	}
	else {
	    Serial.printlnf("404 url=%s", url);
		cb(cbArg, 0, 404, nullptr, nullptr);
	}
}

void valuePageHandler(const char* url, ResponseCallback* cb, void* cbArg, Reader* body, Writer* result, void* reserved) {
	cb(cbArg, 0, 200, "text/json", nullptr);

	int value = (int) analogRead(VALUE_PIN);

	char buf[64];
	snprintf(buf, sizeof(buf), "{\"value\":%d}", value);

	Serial.printlnf("returning /value: %s", buf);

	result->write(buf);
}


6 Likes