Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTML for Apple devices to mitigate POST fragmentation #3069

Merged
merged 3 commits into from
Apr 25, 2020
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
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