Browse Source

Option to disable network scanning (#392, #399). Scan networks from web UI

i18n
Xose Pérez 7 years ago
parent
commit
a5df00b569
14 changed files with 3380 additions and 3247 deletions
  1. +1
    -0
      code/espurna/config/general.h
  2. +1
    -1
      code/espurna/config/prototypes.h
  3. BIN
      code/espurna/data/index.html.gz
  4. +1
    -1
      code/espurna/light.ino
  5. +1
    -1
      code/espurna/relay.ino
  6. +1
    -1
      code/espurna/rfbridge.ino
  7. +4
    -5
      code/espurna/settings.ino
  8. +3158
    -3118
      code/espurna/static/index.html.gz.h
  9. +161
    -117
      code/espurna/wifi.ino
  10. +1
    -1
      code/espurna/ws.ino
  11. +14
    -0
      code/html/custom.css
  12. +12
    -2
      code/html/custom.js
  13. BIN
      code/html/images/loading.gif
  14. +25
    -0
      code/html/index.html

+ 1
- 0
code/espurna/config/general.h View File

@ -308,6 +308,7 @@ PROGMEM const char* const custom_reset_string[] = {
#define WIFI_MAX_NETWORKS 5 // Max number of WIFI connection configurations
#define WIFI_AP_MODE AP_MODE_ALONE
#define WIFI_SLEEP_ENABLED 1 // Enable WiFi light sleep
#define WIFI_SCAN_NETWORKS 1 // Perform a network scan before connecting
// Optional hardcoded configuration (up to 2 different networks)
//#define WIFI1_SSID "..."


+ 1
- 1
code/espurna/config/prototypes.h View File

@ -27,7 +27,7 @@ typedef std::function<void(JsonObject&)> ws_on_send_callback_f;
void wsOnSendRegister(ws_on_send_callback_f callback);
void wsSend(ws_on_send_callback_f sender);
typedef std::function<void(const char *, JsonObject&)> ws_on_action_callback_f;
typedef std::function<void(uint32_t, const char *, JsonObject&)> ws_on_action_callback_f;
void wsOnActionRegister(ws_on_action_callback_f callback);
typedef std::function<void(void)> ws_on_after_parse_callback_f;


BIN
code/espurna/data/index.html.gz View File


+ 1
- 1
code/espurna/light.ino View File

@ -732,7 +732,7 @@ void _lightWebSocketOnSend(JsonObject& root) {
}
}
void _lightWebSocketOnAction(const char * action, JsonObject& data) {
void _lightWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {
if (_light_has_color) {


+ 1
- 1
code/espurna/relay.ino View File

@ -428,7 +428,7 @@ void _relayWebSocketOnStart(JsonObject& root) {
}
void _relayWebSocketOnAction(const char * action, JsonObject& data) {
void _relayWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {
if (strcmp(action, "relay") != 0) return;


+ 1
- 1
code/espurna/rfbridge.ino View File

@ -60,7 +60,7 @@ void _rfbWebSocketOnSend(JsonObject& root) {
}
}
void _rfbWebSocketOnAction(const char * action, JsonObject& data) {
void _rfbWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {
if (strcmp(action, "rfblearn") == 0) rfbLearn(data["id"], data["status"]);
if (strcmp(action, "rfbforget") == 0) rfbForget(data["id"], data["status"]);
if (strcmp(action, "rfbsend") == 0) rfbStore(data["id"], data["status"], data["data"].as<const char*>());


+ 4
- 5
code/espurna/settings.ino View File

@ -108,9 +108,9 @@ void _settingsHelp() {
}
// Output the list
DEBUG_MSG_P(PSTR("\nAvailable commands:\n\n"));
DEBUG_MSG_P(PSTR("Available commands:\n"));
for (unsigned char i=0; i<commands.size(); i++) {
DEBUG_MSG_P(PSTR("* %s\n"), (commands[i]).c_str());
DEBUG_MSG_P(PSTR("> %s\n"), (commands[i]).c_str());
}
}
@ -143,12 +143,11 @@ void _settingsKeys() {
}
// Write key-values
DEBUG_MSG_P(PSTR("\n"));
DEBUG_MSG_P(PSTR("Current settings:\n"));
for (unsigned int i=0; i<keys.size(); i++) {
String value = getSetting(keys[i]);
DEBUG_MSG_P(PSTR("+%s => %s\n"), (keys[i]).c_str(), value.c_str());
DEBUG_MSG_P(PSTR("> %s => %s\n"), (keys[i]).c_str(), value.c_str());
}
DEBUG_MSG_P(PSTR("\n"));
unsigned long freeEEPROM = SPI_FLASH_SEC_SIZE - _settingsSize();
DEBUG_MSG_P(PSTR("Number of keys: %d\n"), keys.size());


+ 3158
- 3118
code/espurna/static/index.html.gz.h
File diff suppressed because it is too large
View File


+ 161
- 117
code/espurna/wifi.ino View File

@ -7,75 +7,15 @@ Copyright (C) 2016-2018 by Xose Pérez <xose dot perez at gmail dot com>
*/
#include "JustWifi.h"
#include <Ticker.h>
uint32_t _wifi_scan_client_id = 0;
// -----------------------------------------------------------------------------
// WIFI
// PRIVATE
// -----------------------------------------------------------------------------
void _wifiWebSocketOnSend(JsonObject& root) {
root["maxNetworks"] = WIFI_MAX_NETWORKS;
JsonArray& wifi = root.createNestedArray("wifi");
for (byte i=0; i<WIFI_MAX_NETWORKS; i++) {
if (!hasSetting("ssid", i)) break;
JsonObject& network = wifi.createNestedObject();
network["ssid"] = getSetting("ssid", i, "");
network["pass"] = getSetting("pass", i, "");
network["ip"] = getSetting("ip", i, "");
network["gw"] = getSetting("gw", i, "");
network["mask"] = getSetting("mask", i, "");
network["dns"] = getSetting("dns", i, "");
}
}
String getIP() {
if (WiFi.getMode() == WIFI_AP) {
return WiFi.softAPIP().toString();
}
return WiFi.localIP().toString();
}
String getNetwork() {
if (WiFi.getMode() == WIFI_AP) {
return jw.getAPSSID();
}
return WiFi.SSID();
}
double wifiDistance(int rssi) {
double exponent = (double) (WIFI_RSSI_1M - rssi) / WIFI_PROPAGATION_CONST / 10.0;
return round(pow(10, exponent));
}
void wifiDisconnect() {
jw.disconnect();
}
void resetConnectionTimeout() {
jw.resetReconnectTimeout();
}
bool wifiConnected() {
return jw.connected();
}
bool createAP() {
jw.disconnect();
jw.resetReconnectTimeout();
return jw.createAP();
}
void wifiReconnectCheck() {
bool connected = false;
#if WEB_SUPPORT
if (wsConnected()) connected = true;
#endif
#if TELNET_SUPPORT
if (telnetConnected()) connected = true;
#endif
jw.setReconnectTimeout(connected ? 0 : WIFI_RECONNECT_INTERVAL);
}
void wifiConfigure() {
void _wifiConfigure() {
jw.setHostname(getSetting("hostname").c_str());
#if USE_PASSWORD
@ -94,7 +34,7 @@ void wifiConfigure() {
#endif
// Clean settings
wifiClean(WIFI_MAX_NETWORKS);
_wifiClean(WIFI_MAX_NETWORKS);
int i;
for (i = 0; i< WIFI_MAX_NETWORKS; i++) {
@ -116,60 +56,23 @@ void wifiConfigure() {
}
}
jw.scanNetworks(true);
}
void wifiStatus() {
if (WiFi.getMode() == WIFI_AP_STA) {
DEBUG_MSG_P(PSTR("[WIFI] MODE AP + STA --------------------------------\n"));
} else if (WiFi.getMode() == WIFI_AP) {
DEBUG_MSG_P(PSTR("[WIFI] MODE AP --------------------------------------\n"));
} else if (WiFi.getMode() == WIFI_STA) {
DEBUG_MSG_P(PSTR("[WIFI] MODE STA -------------------------------------\n"));
} else {
DEBUG_MSG_P(PSTR("[WIFI] MODE OFF -------------------------------------\n"));
DEBUG_MSG_P(PSTR("[WIFI] No connection\n"));
}
if ((WiFi.getMode() & WIFI_AP) == WIFI_AP) {
DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), jw.getAPSSID().c_str());
DEBUG_MSG_P(PSTR("[WIFI] PASS %s\n"), getSetting("adminPass", ADMIN_PASS).c_str());
DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.softAPIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.softAPmacAddress().c_str());
}
if ((WiFi.getMode() & WIFI_STA) == WIFI_STA) {
uint8_t * bssid = WiFi.BSSID();
DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), WiFi.SSID().c_str());
DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.localIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.macAddress().c_str());
DEBUG_MSG_P(PSTR("[WIFI] GW %s\n"), WiFi.gatewayIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] DNS %s\n"), WiFi.dnsIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] MASK %s\n"), WiFi.subnetMask().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] HOST %s\n"), WiFi.hostname().c_str());
DEBUG_MSG_P(PSTR("[WIFI] BSSID %02X:%02X:%02X:%02X:%02X:%02X\n"),
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], bssid[6]
);
DEBUG_MSG_P(PSTR("[WIFI] CH %d\n"), WiFi.channel());
DEBUG_MSG_P(PSTR("[WIFI] RSSI %d\n"), WiFi.RSSI());
}
DEBUG_MSG_P(PSTR("[WIFI] ----------------------------------------------\n"));
jw.scanNetworks(getSetting("wifiScan", WIFI_SCAN_NETWORKS).toInt() == 1);
}
void wifiScan() {
void _wifiScan(uint32_t client_id = 0) {
DEBUG_MSG_P(PSTR("[WIFI] Start scanning\n"));
String output;
unsigned char result = WiFi.scanNetworks();
if (result == WIFI_SCAN_FAILED) {
DEBUG_MSG_P(PSTR("[WIFI] Scan failed\n"));
output = String("Failed scan");
} else if (result == 0) {
DEBUG_MSG_P(PSTR("[WIFI] No networks found\n"));
output = String("No networks found");
} else {
DEBUG_MSG_P(PSTR("[WIFI] %d networks found:\n"), result);
@ -183,10 +86,12 @@ void wifiScan() {
uint8_t* BSSID_scan;
int32_t chan_scan;
bool hidden_scan;
char buffer[128];
WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, chan_scan, hidden_scan);
DEBUG_MSG_P(PSTR("[WIFI] - BSSID: %02X:%02X:%02X:%02X:%02X:%02X SEC: %s RSSI: %3d CH: %2d SSID: %s\n"),
snprintf_P(buffer, sizeof(buffer),
PSTR("BSSID: %02X:%02X:%02X:%02X:%02X:%02X SEC: %s RSSI: %3d CH: %2d SSID: %s"),
BSSID_scan[1], BSSID_scan[2], BSSID_scan[3], BSSID_scan[4], BSSID_scan[5], BSSID_scan[6],
(sec_scan != ENC_TYPE_NONE ? "YES" : "NO "),
rssi_scan,
@ -194,15 +99,23 @@ void wifiScan() {
(char *) ssid_scan.c_str()
);
DEBUG_MSG_P(PSTR("[WIFI] > %s\n"), buffer);
if (client_id > 0) output = output + String(buffer) + String("<br />");
}
}
if (client_id > 0) {
output = String("{\"scanResult\": \"") + output + String("\"}");
wsSend(client_id, output.c_str());
}
WiFi.scanDelete();
}
bool wifiClean(unsigned char num) {
bool _wifiClean(unsigned char num) {
bool changed = false;
int i = 0;
@ -244,7 +157,7 @@ bool wifiClean(unsigned char num) {
}
// Inject hardcoded networks
void wifiInject() {
void _wifiInject() {
#ifdef WIFI1_SSID
if (getSetting("ssid", 0, "").length() == 0) setSetting("ssid", 0, WIFI1_SSID);
@ -346,18 +259,22 @@ void _wifiDebug(justwifi_messages_t code, char * parameter) {
#endif // DEBUG_SUPPORT
// -----------------------------------------------------------------------------
// SETTINGS
// -----------------------------------------------------------------------------
#if TERMINAL_SUPPORT
void _wifiInitCommands() {
settingsRegisterCommand(F("WIFI.RESET"), [](Embedis* e) {
wifiConfigure();
_wifiConfigure();
wifiDisconnect();
DEBUG_MSG_P(PSTR("+OK\n"));
});
settingsRegisterCommand(F("WIFI.SCAN"), [](Embedis* e) {
wifiScan();
_wifiScan();
DEBUG_MSG_P(PSTR("+OK\n"));
});
@ -365,27 +282,147 @@ void _wifiInitCommands() {
#endif
// -----------------------------------------------------------------------------
// WEB
// -----------------------------------------------------------------------------
#if WEB_SUPPORT
void _wifiWebSocketOnSend(JsonObject& root) {
root["maxNetworks"] = WIFI_MAX_NETWORKS;
JsonArray& wifi = root.createNestedArray("wifi");
for (byte i=0; i<WIFI_MAX_NETWORKS; i++) {
if (!hasSetting("ssid", i)) break;
JsonObject& network = wifi.createNestedObject();
network["ssid"] = getSetting("ssid", i, "");
network["pass"] = getSetting("pass", i, "");
network["ip"] = getSetting("ip", i, "");
network["gw"] = getSetting("gw", i, "");
network["mask"] = getSetting("mask", i, "");
network["dns"] = getSetting("dns", i, "");
}
}
void _wifiWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {
if (strcmp(action, "scan") == 0) _wifi_scan_client_id = client_id;
}
#endif
// -----------------------------------------------------------------------------
// API
// -----------------------------------------------------------------------------
String getIP() {
if (WiFi.getMode() == WIFI_AP) {
return WiFi.softAPIP().toString();
}
return WiFi.localIP().toString();
}
String getNetwork() {
if (WiFi.getMode() == WIFI_AP) {
return jw.getAPSSID();
}
return WiFi.SSID();
}
double wifiDistance(int rssi) {
double exponent = (double) (WIFI_RSSI_1M - rssi) / WIFI_PROPAGATION_CONST / 10.0;
return round(pow(10, exponent));
}
bool wifiConnected() {
return jw.connected();
}
void wifiDisconnect() {
jw.disconnect();
}
bool createAP() {
jw.disconnect();
jw.resetReconnectTimeout();
return jw.createAP();
}
void wifiReconnectCheck() {
bool connected = false;
#if WEB_SUPPORT
if (wsConnected()) connected = true;
#endif
#if TELNET_SUPPORT
if (telnetConnected()) connected = true;
#endif
jw.setReconnectTimeout(connected ? 0 : WIFI_RECONNECT_INTERVAL);
}
void wifiStatus() {
if (WiFi.getMode() == WIFI_AP_STA) {
DEBUG_MSG_P(PSTR("[WIFI] MODE AP + STA --------------------------------\n"));
} else if (WiFi.getMode() == WIFI_AP) {
DEBUG_MSG_P(PSTR("[WIFI] MODE AP --------------------------------------\n"));
} else if (WiFi.getMode() == WIFI_STA) {
DEBUG_MSG_P(PSTR("[WIFI] MODE STA -------------------------------------\n"));
} else {
DEBUG_MSG_P(PSTR("[WIFI] MODE OFF -------------------------------------\n"));
DEBUG_MSG_P(PSTR("[WIFI] No connection\n"));
}
if ((WiFi.getMode() & WIFI_AP) == WIFI_AP) {
DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), jw.getAPSSID().c_str());
DEBUG_MSG_P(PSTR("[WIFI] PASS %s\n"), getSetting("adminPass", ADMIN_PASS).c_str());
DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.softAPIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.softAPmacAddress().c_str());
}
if ((WiFi.getMode() & WIFI_STA) == WIFI_STA) {
uint8_t * bssid = WiFi.BSSID();
DEBUG_MSG_P(PSTR("[WIFI] SSID %s\n"), WiFi.SSID().c_str());
DEBUG_MSG_P(PSTR("[WIFI] IP %s\n"), WiFi.localIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] MAC %s\n"), WiFi.macAddress().c_str());
DEBUG_MSG_P(PSTR("[WIFI] GW %s\n"), WiFi.gatewayIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] DNS %s\n"), WiFi.dnsIP().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] MASK %s\n"), WiFi.subnetMask().toString().c_str());
DEBUG_MSG_P(PSTR("[WIFI] HOST %s\n"), WiFi.hostname().c_str());
DEBUG_MSG_P(PSTR("[WIFI] BSSID %02X:%02X:%02X:%02X:%02X:%02X\n"),
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], bssid[6]
);
DEBUG_MSG_P(PSTR("[WIFI] CH %d\n"), WiFi.channel());
DEBUG_MSG_P(PSTR("[WIFI] RSSI %d\n"), WiFi.RSSI());
}
DEBUG_MSG_P(PSTR("[WIFI] ----------------------------------------------\n"));
}
void wifiRegister(wifi_callback_f callback) {
jw.subscribe(callback);
}
// -----------------------------------------------------------------------------
// INITIALIZATION
// -----------------------------------------------------------------------------
void wifiSetup() {
#if WIFI_SLEEP_ENABLED
wifi_set_sleep_type(LIGHT_SLEEP_T);
#endif
wifiInject();
wifiConfigure();
_wifiInject();
_wifiConfigure();
// Message callbacks
#if DEBUG_SUPPORT
wifiRegister(_wifiDebug);
wifiRegister(_wifiDebug);
#endif
#if WEB_SUPPORT
wsOnSendRegister(_wifiWebSocketOnSend);
wsOnAfterParseRegister(wifiConfigure);
wsOnAfterParseRegister(_wifiConfigure);
wsOnActionRegister(_wifiWebSocketOnAction);
#endif
#if TERMINAL_SUPPORT
@ -395,5 +432,12 @@ void wifiSetup() {
}
void wifiLoop() {
jw.loop();
if (_wifi_scan_client_id > 0) {
_wifiScan(_wifi_scan_client_id);
_wifi_scan_client_id = 0;
}
}

+ 1
- 1
code/espurna/ws.ino View File

@ -101,7 +101,7 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) {
// Callbacks
for (unsigned char i = 0; i < _ws_on_action_callbacks.size(); i++) {
(_ws_on_action_callbacks[i])(action, data);
(_ws_on_action_callbacks[i])(client_id, action, data);
}
// Restore configuration via websockets


+ 14
- 0
code/html/custom.css View File

@ -76,6 +76,7 @@
.button-more-network,
.button-more-schedule,
.button-wifi-scan,
.button-rfb-send {
background: rgb(223, 117, 20);
}
@ -213,3 +214,16 @@ hr {
margin: 1em 0;
padding: 0;
}
#scanResult {
margin-top: 10px;
font-size: 60%;
color: #888;
font-family: 'Courier New', monospace;
}
div.loading {
background-image: url('images/loading.gif');
width: 20px;
height: 20px;
margin: 8px 0 0 10px;
display: none;
}

+ 12
- 2
code/html/custom.js View File

@ -386,6 +386,13 @@ function doToggle(element, value) {
return false;
}
function doScan() {
$("#scanResult").html("");
$("div.scan.loading").show();
websock.send(JSON.stringify({'action': 'scan', 'data': {}}));
return false;
}
// -----------------------------------------------------------------------------
// Visualization
// -----------------------------------------------------------------------------
@ -726,8 +733,6 @@ function rfbSend() {
function processData(data) {
console.log(data);
// title
if ("app_name" in data) {
var title = data.app_name;
@ -862,6 +867,10 @@ function processData(data) {
return;
}
if (key == "scanResult") {
$("div.scan.loading").hide();
}
// -----------------------------------------------------------------------------
// Relays scheduler
// -----------------------------------------------------------------------------
@ -1110,6 +1119,7 @@ $(function() {
$(".button-update-password").on('click', doUpdatePassword);
$(".button-reboot").on('click', doReboot);
$(".button-reconnect").on('click', doReconnect);
$(".button-wifi-scan").on('click', doScan);
$(".button-settings-backup").on('click', doBackup);
$(".button-settings-restore").on('click', doRestore);
$('#uploader').on('change', onFileUpload);


BIN
code/html/images/loading.gif View File

Before After
Width: 20  |  Height: 20  |  Size: 433 B

+ 25
- 0
code/html/index.html View File

@ -543,6 +543,31 @@
<fieldset>
<legend>General</legend>
<div class="pure-g">
<div class="pure-u-1 pure-u-lg-1-4"><label>Scan networks</label></div>
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="wifiScan" tabindex="1" /></div>
<div class="pure-u-0 pure-u-lg-1-2"></div>
<div class="pure-u-0 pure-u-lg-1-4"></div>
<div class="pure-u-1 pure-u-lg-3-4 hint">
ESPurna will scan for visible WiFi SSIDs and try to connect to networks defined below in order of <strong>signal strength</strong>, even if multiple AP share the same SSID.
When disabled, ESPurna will try to connect to the networks in the same order they are listed below.
Disable this option if you are <strong>connecting to a single access point</strong> (or router) or to a <strong>hidden SSID</strong>.
</thead>
</div>
<div class="pure-u-0 pure-u-lg-1-4"></div>
<button class="pure-button button-wifi-scan" type="button">Scan now</button>
<div class="pure-u-0 pure-u-lg-1-4 scan loading"></div>
</div>
<div class="pure-g">
<div class="pure-u-0 pure-u-lg-1-4"></div>
<span class="pure-u-1 pure-u-lg-3-4 terminal" id="scanResult" name="scanResult"></span>
</div>
<legend>Networks</legend>
<div id="networks"></div>
<button type="button" class="pure-button button-add-network">Add network</button>


Loading…
Cancel
Save