Skip to content

Commit

Permalink
HTML for Apple devices to mitigate POST fragmentation (#3069)
Browse files Browse the repository at this point in the history
  • Loading branch information
HHHartmann authored Apr 25, 2020
1 parent e47c267 commit 3c3bec9
Show file tree
Hide file tree
Showing 2 changed files with 329 additions and 0 deletions.
322 changes: 322 additions & 0 deletions app/modules/enduser_setup/enduser_setup_apple.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,322 @@
<!DOCTYPE html>
<html>

<head>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>WiFi Login</title>
<style type=text/css>
* {
margin: 0;
padding: 0;
}

html,
body {
height: 100%;
font-family: sans-serif;
text-align: center;
background: #444d44;
}

#content {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 320px;
height: 480px;
margin: auto;
}

input,
button,
select {
-webkit-appearance: none;
border-radius: 0;
}

fieldset {
border: 0;
box-shadow: 0 0 15px 1px rgba(0, 0, 0, .4);
box-sizing: border-box;
padding: 20px 30px;
background: #fff;
min-height: 320px;
margin: -1px;
}

input {
border: 1px solid #ccc;
margin-bottom: 10px;
width: 100%;
box-sizing: border-box;
color: #222;
font: 16px monospace;
padding: 15px;
}

select {
font: 16px monospace;
background-color: transparent;
padding: 15px;
}

button {
color: #fff;
border: 0;
border-radius: 3px;
cursor: pointer;
display: block;
font: 16px sans-serif;
text-decoration: none;
padding: 10px 5px;
background: #31b457;
width: 100%;
}

button:focus,
button:hover {
box-shadow: 0 0 0 2px #fff, 0 0 0 3px #31b457;
}

h3 {
font-size: 16px;
color: #666;
margin-bottom: 20px;
}

h4 {
color: #ccc;
padding: 10px;
}

.utility {
float: right;
clear: both;
max-width: 75%;
font-size: 13px;
color: #222;
margin: 10px 0;
padding: 5px 10px;
background: #ccc;
}

.utility:focus,
.utility:hover {
box-shadow: 0 0 0 2px #fff, 0 0 0 3px #ccc;
}

#dropdown,
#f2,
#f3,
#bk2 {
display: none;
}

#dropdown {
position: relative;
width: 100%;
overflow: auto;
height: 51px;
margin-bottom: 10px;
}

#aplist {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
bottom: 0;
border: 1px solid #ccc;
font-family: monospace;
padding: 10px 5px;
}

#arrow {
color: #888;
position: absolute;
right: 8px;
top: 15px;
}

#i {
text-align: center;
}
</style>
</head>

<body>
<div id=content>
<fieldset>
<div id=deviceId></div>
<div id=f1>
<h3>Connect device to your Wi-Fi</h3>
<button id=networks type=button class=utility></button>
<div id=dropdown>
<span id=arrow>&#x25bc;</span>
<select id=aplist name=aplist></select>
</div>
<input id=ssid type=text autocorrect=off autocapitalize=none placeholder='Wi-Fi Name' />
<input id=wifi_password type=text autocorrect=off autocapitalize=none autocomplete=off placeholder=Password />
<button id=submit type=button>Save</button>
</div>
<div id=f2>
<h1>Success!</h1>
<div id=i>
<h3>Your device has successfully connected to the Wi-Fi network.<br /><br/>You may now close this web page.</h3>
</div>
</div>
<div id=f3>
<h2>Trying...</h2>
<button id=bk2 type=button class='utility'>Go Back to Wi-Fi Setup</button>
</div>
</fieldset>
<h4 id='st'>Updating Status...</h4>
</div>
<script>
var $ = function (selector) { return document.querySelector(selector); };
var ab = $('#networks'), ap = $('#aplist');
var stopAll = false, ra, rs, submitted = false;

function show(f, y) {
if (y == null) y = f;
$(f).style.display = y == f ? 'block' : 'none';
}
function hide(f) {
$(f).style.display = 'none';
}
function to(cb, x) {
return setTimeout(cb, 1000 * x);
}
function refr() {
if (!stopAll)
fetch('/status.json?n=' + Math.random(), 'GET', newSt, 2);
}
function cur(f) {
show('#f1', f);
show('#f2', f);
show('#f3', f);
}
function newSt(s, d) {
clearTimeout(rs);
rs = to(refr, 3);

if (s != 200) {
$('#st').innerText = 'Awaiting Status (' + s + ')';
} else {
if (typeof d === 'string') {
d = JSON.parse(d);
}

$('#deviceId').innerText = "Device: " + d.deviceid;

var c = d.pairing;

var st = [
'Idle',
'Connecting...',
'Failed - wrong password',
'Failed - network not found',
'Failed',
'Wi-Fi successfully connected!'
][d.status];

if (st == null)
st = "";

if (!submitted && d.status > 1 && d.status < 5)
st = "Need a valid Network and Password";

$('#st').innerText = st;

if (d.status === 5) {
cur('#f2');
stopAll = true;
clearTimeout(ra);
} else if (d.status > 1) {
cur('#f1');
}
}
}
function submit() {
submitted = true;
var url = '/update?wifi_ssid=' + encodeURIComponent($('#ssid').value) + '&wifi_password=' + encodeURIComponent($('#wifi_password').value);
clearTimeout(rs);
fetch(url, 'GET', refr, 2);
cur('#f3');
}
function fetch(url, method, callback, time_out) {
var xhr = new XMLHttpRequest();
xhr.onloadend = function () {
callback(xhr.status, xhr.responseText);
}
xhr.ontimeout = function () {
callback(-1, null);
}
xhr.open(method, url, true);
xhr.setRequestHeader('Accept', 'application/json');
xhr.timeout = (time_out || 10) * 1000;
xhr.send();
}
function gotAp(s, json) {
var list;
if (s === 200 && json != null) {
if (typeof json === 'string' && json.length > 0) {
list = JSON.parse(json);
} else if (typeof json === 'object') {
list = json;
}

list.sort(function (a, b) {
return b.rssi - a.rssi;
});
var ops = '<option>Select a Network...</option>';
for (var i = 0; i < list.length; ++i) {
ops += '<option>' + list[i].ssid + '</option>';
}
ap.innerHTML = ops;
ab.disabled = false;
togAp(null, true);
ab.onclick = togAp;
} else {
ab.innerText = 'No networks found (' + s + ')';
ra = to(refrAp, 5);
}
}
function togAp(ev, force) {
if (!force || ap.style.display == 'block') {
hide('#dropdown');
show('#ssid');
ab.innerText = 'Scan for Networks';
ab.onclick = refrAp;
} else {
show('#dropdown');
hide('#ssid');
ab.innerText = 'Manual Entry';
}
}
function refrAp() {
ab.innerText = 'Searching for networks...';
ab.disabled = true;
ap.innerHTML = '<option disabled>Scanning...</option>';
if (!stopAll)
fetch('/aplist?n=' + Math.random(), 'GET', gotAp, 10);
}
window.onload = function() {
ab.innerText = 'Scan for Networks';
ab.onclick = refrAp;
$('#aplist').onchange = function () {
$('#ssid').value = $('#aplist').value;
};
$('#submit').onclick = submit;
$('#bk2').onclick = function () {
cur('#f1')
}
rs = to(refr, 0.5);
}
</script>
</body>

</html>
7 changes: 7 additions & 0 deletions docs/modules/enduser-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
This module provides a simple way of configuring ESP8266 chips without using a
serial interface or pre-programming WiFi credentials onto the chip.

!!! attention "ATTENTION Apple users"

Due to bug [#2931](https://github.com/nodemcu/nodemcu-firmware/issues/2931) the configuration does currently not work for many Safari browsers (iOS & macOS).
As a **workaround** there is alternative HTML file which uses another method to transfer the login credentials. It does not support sending arbitrary additional configuration parameters and likewise no `eus_params.lua` will be written. The WiFi credentials will be stored in the ESP flash.

Just copy [enduser_setup_apple.html](../../app/modules/enduser_setup/enduser_setup_apple.html) to the ESP file system and rename it to `enduser_setup.html`.

After running [`enduser_setup.start()`](#enduser_setupstart), a wireless
network named "SetupGadget_XXXXXX" will starting. This prefix can be overridden
in `user_config.h` by defining `ENDUSER_SETUP_AP_SSID`. Connect to that SSID
Expand Down

0 comments on commit 3c3bec9

Please sign in to comment.