Skip to content
This repository was archived by the owner on Mar 17, 2025. It is now read-only.

Added network scanning to config portal. #223

Merged
merged 2 commits into from
Nov 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 62 additions & 2 deletions src/thing/Portal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@

namespace thing {

Portal::Portal(const Config& config) : config_(config), callback_([](const Config&){}) {}
Portal::Portal(const Config& config)
: config_(config),
callback_([](const Config&){}),
debug_([](const char*){}) {}

void Portal::SetDebugHandler(std::function<void(const char* message)> handler) {
debug_ = handler;
}

void Portal::Start() {
server_.on("/", [&] () {
Expand Down Expand Up @@ -50,13 +57,44 @@ void Portal::Start() {
}
}
}
function scan() {
document.getElementById('scanning').style.display='inline';
var xhr = new XMLHttpRequest();
xhr.open("GET", "/wifi/scan", true);
xhr.onreadystatechange = function () {
if (xhr.readyState==4 && xhr.status==200) {
load_networks(JSON.parse(xhr.responseText));
document.getElementById('scanning').style.display='none';
}
}
xhr.send();
}
function load_networks(networks) {
select = document.getElementById('networks');
select.innerHtml = '';
networks.sort(function(a, b) {
return b.rssi - a.rssi;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we should choose a more predictable sorting to avoid the list from being re-ordered on every scan.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like the sorting that would be most desirable, you get the strongest networks first. This is how OSX, Android, iOS, Windows, ChromeOS, etc.. sort.

The appeal of this sorting is that the most relevant networks are most likely to be on top. For example when I used to live in downtown LA I had roughly 20 networks I could see at a time but my home network was always the first or second because it was the strongest in my house.

});
networks.forEach(function(network) {
option = document.createElement('option');
option.value = network.ssid;
option.text = network.ssid + ' (' + network.rssi + ')';
select.add(option);
});
select.style.display='inline';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something you could consider is setting a .class with the state ('scanning', 'selection', 'connected') on a parent div for the ui, and having some css that configure the visibility of all elements for each one instead of having the js show/hide them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I follow what you are proposing. It may just be beyond my CSS knowledge. The UI is very much in a "working but unstyled" state. I was planning on going back at the end and making things look good, add some CSS to try to match the feel of the firebase console, stuff like that but if someone wanted to jump in and start styling it now I wouldn't complain :)

}
function set_network(select) {
document.getElementById('ssid').value = select[select.selectedIndex].value;
}
</script>
</head>
<body>
<div>Host: <input id='host'></div>
<div>Auth: <input id='auth'></div>
<div>Path: <input id='path'></div>
<div>Wifi SSID: <input id='ssid'></div>
<div>Wifi SSID: <input id='ssid'><button onclick='scan();'>scan</button></div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you consider attaching the onclick from the js and keeping the js free?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not really, what would the advantage be?

Seems like more work, we would need a window.onload handler (might be nice to put the random "fetch_config()" call at the end of the document there too. then you would need to add an id here, fetch this button and add the onload, or just put it inline here. This seems cleaner.

If we had a strong reason for separation, like if the JS was loaded from another file and we wanted to play with loading different JS for the same html or something like that but as this is a small file with everything inline it seems to just stick with that and mix it all together. I could be convinced otherwise though.

<div id='scanning' style='display:none'>Scanning...</div>
<div><select size=10 id='networks' style='display:none' onchange='set_network(this);'></select></div>
<div>Wifi Key: <input id='key'></div>
<div><button onclick='send_config();'>Save</button></div>
<div id='loading'>Loading....</div>
Expand All @@ -67,6 +105,7 @@ void Portal::Start() {
static const PROGMEM char type[] = "text/html";

server_.send_P(200, type, page);
debug_("served root page.");
});

server_.on("/config", [&] () {
Expand All @@ -82,9 +121,11 @@ void Portal::Start() {
String buffer;
root.printTo(buffer);
server_.send(200, "application/json", buffer);
debug_("config retrieved");
} else if (server_.method() == HTTP_POST) {
if (!server_.hasArg("config")) {
server_.send(500, "text/plain", "Missing config.\r\n");
debug_("Config updated called without param.");
return;
}
String config = server_.arg("config");
Expand All @@ -96,9 +137,28 @@ void Portal::Start() {
config_.wifi_key = root["wifi_key"].asString();
callback_(config_);
server_.send(200, "text/plain", "");
debug_("config updated.");
}
});

server_.on("/wifi/scan", [&] () {
int net_count = WiFi.scanNetworks();
DynamicJsonBuffer json_buffer;
JsonArray& data = json_buffer.createArray();
for (int i=0; i < net_count; i++) {
JsonObject& entry = data.createNestedObject();
entry["ssid"] = WiFi.SSID(i);
entry["rssi"] = WiFi.RSSI(i);
}

String buffer;
data.printTo(buffer);
server_.send(200, "application/json", buffer);
debug_("served networks.");
});

server_.begin();
debug_("Portal started.");
}

void Portal::Loop() {
Expand Down
3 changes: 3 additions & 0 deletions src/thing/Portal.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ class Portal {
void Loop();
void NotifyOnUpdate(std::function<void(const Config& config)> cb);

void SetDebugHandler(std::function<void(const char* message)> handler);

private:
Config config_;
ESP8266WebServer server_;
std::function<void(const Config& config)> callback_;
std::function<void(const char* message)> debug_;

};

Expand Down
6 changes: 5 additions & 1 deletion src/thing/Transcriber.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

#include "thing/Transcriber.h"
#include <ESP8266WiFi.h>

namespace thing {
namespace {
Expand Down Expand Up @@ -37,6 +37,10 @@ void Transcriber::SetValue(const std::string& path, const std::string& value) {
}

void Transcriber::Loop() {
if (WiFi.status() != WL_CONNECTED) {
return;
}

// Read incoming data
if (stream_->available()) {
std::string event_str;
Expand Down