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

Add support for saving multiple wifi networks #221

Merged
merged 9 commits into from May 19, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
49 changes: 48 additions & 1 deletion html/accesspoint.html
Expand Up @@ -45,14 +45,31 @@
</style>
</head>
<body>
<form id="settings" action="/init" class="box" method="POST">
<form id="settings" action="#wifiConfig" class="box" method="POST" onsubmit="wifiConfig(); return false">
<h1 data-i18n="wifi.title">WiFi-configuration</h1>
<label for="ssid" data-i18n="wifi.ssid.title">SSID</label>:<br>
<input type="text" id="ssid" name="ssid" placeholder="SSID" required><br>
<label for="pwd" data-i18n="wifi.password.title">Password</label>:<br>
<input type="password" id="pwd" name="pwd" autocomplete="off" required><br>
<label for="hostname" data-i18n="wifi.hostname.title">Hostname</label>:<br>
<input type="text" id="hostname" name="hostname" value="espuino" required><br><br>

<input type="checkbox" id="static_enabled" name="static_enabled" value=false>
<label for="static_enabled" data-i18n="wifi.static.enabled">Static IP</label>

<div id="wifi_static_div" style="display:none">
<label for="static_addr" data-i18n="wifi.static.addr">Adresse für Statische IP-Konfiguration</label>:<br>
<input type="text" id="static_addr" name="static_addr" ><br><br>
<label for="static_gateway" data-i18n="wifi.static.gateway">Gateway für Statische IP-Konfiguration</label>:<br>
<input type="text" id="static_gateway" name="static_gateway" ><br><br>
<label for="static_subnet" data-i18n="wifi.static.subnet">Subnet für Statische IP-Konfiguration</label>:<br>
<input type="text" id="static_subnet" name="static_subnet" ><br><br>
<label for="static_dns1" data-i18n="wifi.static.dns1">DNS 1 für Statische IP-Konfiguration</label>:<br>
<input type="text" id="static_dns1" name="static_dns1" ><br><br>
<label for="static_dns2" data-i18n="wifi.static.dns2">DNS 2 für Statische IP-Konfiguration</label>:<br>
<input type="text" id="static_dns2" name="static_dns2" ><br><br>
</div>

<button type="submit" class="btn" id="save-button" data-i18n="submit">Submit</button>
</form>
<form action="/restart" class="box">
Expand All @@ -71,6 +88,36 @@ <h1 data-i18n="wifi.restartPrompt">Ready to go?</h1>
localize = locI18next.init(i18next);
localize('body');
});

// disable static input fields on toggle
document.getElementById('static_enabled').onchange = function() {
let new_style = this.checked ? null : "none";
document.getElementById("wifi_static_div").style.display = new_style;
};

async function wifiConfig() {
let static = document.getElementById('static_enabled').checked;

var myObj = {
ssid: document.getElementById('ssid').value,
pwd: document.getElementById('pwd').value,
static: static
};

if (static) {
myObj[static_addr] = document.getElementById('static_addr').value;
myObj[static_gateway] = document.getElementById('static_gateway').value;
myObj[static_subnet] = document.getElementById('static_subnet').value;
myObj[static_dns1] = document.getElementById('static_dns1').value;
myObj[static_dns2] = document.getElementById('static_dns2').value;
}

await fetch("/savedSSIDs", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(myObj)
});
}
</script>
</body>
</html>
10 changes: 10 additions & 0 deletions html/locales/de.json
Expand Up @@ -24,6 +24,8 @@
},
"wifi": {
"title": "WLAN-Einstellungen",
"networks": "Netzwerke",
"savedNetworks": "Gespeicherte Netzwerke",
"ssid": {
"title": "WLAN-Name (SSID)",
"placeholder": "SSID",
Expand All @@ -39,6 +41,14 @@
"placeholder": "espuino",
"validation": "Trage einen validen Hostnamen ein"
},
"static": {
"addr": "Statische IP-Adresse",
"enabled": "Statische IP-Konfiguration",
"gateway": "Gateway für Statische IP-Konfiguration",
"subnet": "Subnetz für Statische IP-Konfiguration",
"dns1": " DNS 1 für Statische IP-Konfiguration",
"dns2": "DNS 2 für Statische IP-Konfiguration"
},
"restartPrompt": "Fertig?"
},
"control": {
Expand Down
10 changes: 10 additions & 0 deletions html/locales/en.json
Expand Up @@ -24,6 +24,8 @@
},
"wifi": {
"title": "WiFi-configuration",
"networks": "Networks",
"savedNetworks": "Saved Networks",
"ssid": {
"title": "WiFi-name (SSID)",
"placeholder": "SSID",
Expand All @@ -39,6 +41,14 @@
"placeholder": "espuino",
"validation": "Enter a valid hostname"
},
"static": {
"addr": "Static IP-Address",
"enabled": "Static IP-Configuration",
"gateway": "Gateway for Static IP-Configuration",
"subnet": "Subnetz for Static IP-Configuration",
"dns1": " DNS 1 for Static IP-Configuration",
"dns2": "DNS 2 for Static IP-Configuration"
},
"restartPrompt": "Ready to go?"
},
"control": {
Expand Down
200 changes: 173 additions & 27 deletions html/management.html
Expand Up @@ -175,24 +175,58 @@
<div class="tab-content" id="nav-tabContent">
<div class="tab-pane fade" id="nav-wifi" role="tabpanel" aria-labelledby="nav-wifi-tab">
<div class="container" id="wifiConfig">
<form action="#wifiConfig" method="POST" onsubmit="wifiConfig('wifiConfig'); return false">
<div class="form-group col-md-12">
<legend data-i18n="wifi.title">WiFi-settings</legend>
<label for="ssid" data-i18n="[prepend]wifi.ssid.title">:</label>
<input type="text" class="form-control" id="ssid" data-i18n="[placeholder]wifi.ssid.placeholder" name="ssid" required>
<div class="invalid-feedback" data-i18n="wifi.ssid.validation"></div>
<label for="pwd" data-i18n="[prepend]wifi.password.title">:</label>
<input type="password" class="form-control" id="pwd" name="pwd" data-i18n="[placeholder]wifi.password.placeholder" required>
<label for="hostname" data-i18n="[prepend]wifi.hostname.title">:</label>
<input type="text" class="form-control" id="hostname" data-i18n="[placeholder]wifi.hostname.placeholder" name="hostname"
value="%HOSTNAME%" pattern="^[^-\.]{2,32}" required>
</div>
<br>
<div class="text-center">
<button type="reset" class="btn btn-secondary" data-i18n="reset"></button>&nbsp
<button type="submit" class="btn btn-primary" data-i18n="submit"></button>
</div>
</form>
<div>
<legend data-i18n="wifi.title">WiFi-settings</legend>
<form action="#globalWifiConfig" method="POST" onsubmit="globalWifiConfig('globalWifiConfig'); return false">
<div class="form-group col-md-12">
<label for="hostname" data-i18n="[prepend]wifi.hostname.title">:</label>
<input type="text" class="form-control" id="hostname" data-i18n="[placeholder]wifi.hostname.placeholder" name="hostname"
value="%HOSTNAME%" pattern="^[^-\.]{2,32}" required>
</div>
<br>
<div class="text-center">
<button type="reset" class="btn btn-secondary" data-i18n="reset"></button>&nbsp
<button type="submit" class="btn btn-primary" data-i18n="submit"></button>
</div>
</form>
</div>
<div style="margin-top: 20px;">
<legend data-i18n="wifi.networks">Networks</legend>
<form action="#wifiConfig" method="POST" onsubmit="wifiConfig('wifiConfig'); return false">
<div class="form-group col-md-12">
<label for="ssid" data-i18n="[prepend]wifi.ssid.title">:</label>
<input type="text" class="form-control" id="ssid" data-i18n="[placeholder]wifi.ssid.placeholder" name="ssid" required>
<div class="invalid-feedback" data-i18n="wifi.ssid.validation"></div>
<label for="pwd" data-i18n="[prepend]wifi.password.title">:</label>
<input type="password" class="form-control" id="pwd" name="pwd" data-i18n="[placeholder]wifi.password.placeholder" required>

<input type="checkbox" id="static_enabled" name="static_enabled" value=false>
<label for="static_enabled" data-i18n="[prepend]wifi.static.enabled">:</label>
<div id="wifi_static_div" style="display:none">
<label for="static_addr" data-i18n="[prepend]wifi.static.addr">:</label>
<input type="text" class="form-control" id="static_addr" name="static_addr" >
<label for="static_gateway" data-i18n="[prepend]wifi.static.gateway">:</label>
<input type="text" class="form-control" id="static_gateway" name="static_gateway" >
<label for="static_subnet" data-i18n="[prepend]wifi.static.subnet">:</label>
<input type="text" class="form-control" id="static_subnet" name="static_subnet" >
<label for="static_dns1" data-i18n="[prepend]wifi.static.dns1">:</label>
<input type="text" class="form-control" id="static_dns1" name="static_dns1" >
<label for="static_dns2" data-i18n="[prepend]wifi.static.dns2">:</label>
<input type="text" class="form-control" id="static_dns2" name="static_dns2" >
</div>

</div>
<br>
<div class="text-center">
<button type="submit" class="btn btn-primary" data-i18n="submit"></button>
</div>
</form>
</div>
<div class="col-md-12" style="margin-top: 20px;">
<legend data-i18n="wifi.savedNetworks">Saved Networks</legend>
<ul class="list-group" id="wifiListSavedSSIDs">
</ul>
</div>
</div>
</div>
<div class="tab-pane fade" id="nav-control" role="tabpanel" aria-labelledby="nav-control-tab">
Expand Down Expand Up @@ -1241,6 +1275,86 @@
};
}

const wifiListSavedSSIDs = document.getElementById("wifiListSavedSSIDs");
async function rebuildSSIDList() {
let ssidList = await (await fetch("/savedSSIDs")).json();
let ssidActiveObj = await (await fetch("/activeSSID")).json();

console.log(ssidActiveObj);
let ssidActive = ssidActiveObj.active;

console.log(ssidList);
console.log(ssidActive);

wifiListSavedSSIDs.innerHTML = "";

for (let ssid of ssidList) {
console.log("appending ssid", ssid);

let ssidElem = document.createElement("li");
ssidElem.appendChild(document.createTextNode(ssid));


ssidElem.classList.add("list-group-item");
console.log("comparing ssid vs active:", ssidActive, ssid);
if (ssidActive && ssidActive === ssid) {
ssidElem.classList.add("active");
}

let deleteSpan = document.createElement("span");
deleteSpan.classList.add("float-right");
deleteSpan.classList.add("button-group");

let deleteButton = document.createElement("button");
deleteButton.classList.add("btn");
deleteButton.classList.add("btn-danger");
deleteButton.classList.add("fa");
deleteButton.classList.add("fa-trash");

deleteButton.addEventListener("click", async () => {
console.log("deleting", ssid);
await fetch("/savedSSIDs/"+ssid, {method: "DELETE"});
await rebuildSSIDList();
});

deleteSpan.appendChild(deleteButton);
ssidElem.appendChild(deleteSpan);

wifiListSavedSSIDs.appendChild(ssidElem);
}
}

async function updateHostnameField() {
let hostnameElem = document.getElementById("hostname");

let hostname = await (await fetch("/hostname")).text();

if (hostname && hostname !== "") {
hostnameElem.value = hostname;
hostnameElem.defaultValue = hostname;
}
}

function onWifiTabOpened() {
console.log("wifi tab opened!")
rebuildSSIDList();

updateHostnameField();
}

const config = {attributes: true};
const wifiTab = document.getElementById("nav-wifi-tab");
var wifiTabWasActive = false;
const wifiTabObserver = new MutationObserver((mutationList, observer) => {
if (!wifiTabWasActive && wifiTab.classList.contains("active")) {
wifiTabWasActive = true;
onWifiTabOpened();
} else {
wifiTabWasActive = false;
}
})
wifiTabObserver.observe(wifiTab, config);


function ping() {
var myObj = {
Expand Down Expand Up @@ -1373,18 +1487,50 @@
socket.send(myJSON);
}

function wifiConfig(clickedId) {
async function globalWifiConfig(clickedId) {
lastIdclicked = clickedId;
var myObj = {
"wifiConfig": {
ssid: document.getElementById('ssid').value,
pwd: document.getElementById('pwd').value,
hostname: document.getElementById('hostname').value
}
let hostname = document.getElementById('hostname').value;

await fetch("/hostname", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(hostname)
});
}

// disable static input fields on toggle
document.getElementById('static_enabled').onchange = function() {
let new_style = this.checked ? null : "none";
document.getElementById("wifi_static_div").style.display = new_style;
};

async function wifiConfig(clickedId) {
lastIdclicked = clickedId;
let static = document.getElementById('static_enabled').checked;

var myObj = {
ssid: document.getElementById('ssid').value,
pwd: document.getElementById('pwd').value,
static: static
};
var myJSON = JSON.stringify(myObj);
socket.send(myJSON);

if (static) {
myObj[static_addr] = document.getElementById('static_addr').value;
myObj[static_gateway] = document.getElementById('static_gateway').value;
myObj[static_subnet] = document.getElementById('static_subnet').value;
myObj[static_dns1] = document.getElementById('static_dns1').value;
myObj[static_dns2] = document.getElementById('static_dns2').value;
}

await fetch("/savedSSIDs", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify(myObj)
});

await rebuildSSIDList();
}

function sendControl(cmd) {
var myObj = {
"controls": {
Expand Down
20 changes: 13 additions & 7 deletions src/LogMessages_DE.cpp
Expand Up @@ -107,8 +107,6 @@
const char modificatorDoesNotExist[] = "Ein Karten-Modifikator existiert nicht vom Typ %d!";
const char errorOccuredNvs[] = "Es ist ein Fehler aufgetreten beim Lesen aus dem NVS!";
const char statementsReceivedByServer[] = "Vom Server wurde Folgendes empfangen";
const char savedSsidInNvs[] = "Speichere SSID in NVS";
const char savedWifiPwdInNvs[] = "Speichere WLAN-Password in NVS";
const char apReady[] = "Access-Point geöffnet";
const char httpReady[] = "HTTP-Server gestartet.";
const char unableToMountSd[] = "SD-Karte konnte nicht gemountet werden.";
Expand Down Expand Up @@ -148,10 +146,9 @@
const char mqttWithPwd[] = "Verbinde zu MQTT-Server mit User und Passwort";
const char mqttWithoutPwd[] = "Verbinde zu MQTT-Server ohne User und Passwort";
const char ssidNotFoundInNvs[] = "SSID wurde im NVS nicht gefunden.";
const char wifiPwdNotFoundInNvs[] = "WLAN-Passwort wurde im NVS nicht gefunden.";
const char wifiStaticIpConfigNotFoundInNvs[] = "Statische WLAN-IP-Konfiguration wurde im NVS nicht gefunden.";
const char wifiHostnameNotSet[] = "Keine Hostname-Konfiguration im NVS gefunden.";
const char mqttConnFailed[] = "Verbindung fehlgeschlagen, versuche in Kürze erneut: rc=%i (%d / %d)";
const char mqttConnFailed[] = "Verbindung fehlgeschlagen, versuche in Kürze erneut: rc=%i (%d / %d)";
const char restoredHostnameFromNvs[] = "Hostname aus NVS geladen: %s";
const char currentVoltageMsg[] = "Aktuelle Batteriespannung: %.2f V";
const char currentChargeMsg[] = "Aktuelle Batterieladung: %.2f %%";
Expand All @@ -161,8 +158,8 @@
const char batteryLowMsg[] = "Batterieladung niedrig";
const char batteryCriticalMsg[] = "Batterieladung kritisch. Gehe in Deepsleep...";
const char sdBootFailedDeepsleep[] = "Bootgang wegen SD fehlgeschlagen. Gehe in Deepsleep...";
const char wifiEnabledAfterRestart[] = "WLAN wird aktiviert.";
const char wifiDisabledAfterRestart[] = "WLAN wird deaktiviert.";
const char wifiEnabledMsg[] = "WLAN wird aktiviert.";
const char wifiDisabledMsg[] = "WLAN wird deaktiviert.";
const char voltageIndicatorLowFromNVS[] = "Unterer Spannungslevel (Batterie) fuer Neopixel-Anzeige aus NVS geladen: %.2fV";
const char voltageIndicatorHighFromNVS[] = "Oberer Spannungslevel (Batterie) fuer Neopixel-Anzeige aus NVS geladen: %.2fV";
const char batteryCheckIntervalFromNVS[] = "Zyklus für Batteriemessung fuer Neopixel-Anzeige aus NVS geladen: %u Minuten";
Expand Down Expand Up @@ -230,7 +227,6 @@
const char hpOn[] = "Kopfhörer eingeschaltet";
const char hpOff[] = "Kopfhörer ausgeschaltet";
const char webTxCanceled[] = "Der Webtransfer wurde aufgrund von Inaktivität beendet.";
const char cantConnectToWifi[] = "Verbindung zum WLAN nicht möglich. Nächster Versuch...";
const char tryToPickRandomDir[] = "Versuche ein zufälliges Unterzeichnis zu finden aus: %s";
const char pickedRandomDir[] = "Zufällig ausgewähltes Unterverzeichnis: %s";
const char wrongWakeUpGpio[] = "Der gewählte GPIO ist nicht vom Typ RTC und unterstützt daher das Aufwecken des ESP32 nicht! (GPIO: %u)";
Expand All @@ -241,4 +237,14 @@
const char wifiConnectionInProgress[] = "Versuche mit WLAN '%s' zu verbinden...";
const char wifiCurrentIp[] = "Aktuelle IP: %s";
const char jsonErrorMsg[] = "deserializeJson() fehlgeschlagen: %s";
const char wifiDeleteNetwork[] = "Lösche gespeichertes WLan %s";
const char wifiNetworkLoaded[] = "SSID %d von NVS geladen: %s";
const char wifiTooManyNetworks[] = "Anzahl der WLan-Netze in NVS ist %d, aber es sind maximal %d erlaubt.";
const char wifiAddTooManyNetworks[] = "Kein Platz, weiteres WLan zu speichern!";
const char wifiAddNetwork[] = "Füge WLan hinzu: %s";
const char wifiUpdateNetwork[] = "Ändere Passwort für WLan %s";
const char wifiScanResult[] = "WLan mit SSID %s und Signalstärke %d auf channel %d gefunden.";
const char cantConnectToWifi[] = "WLan-Verbindung fehlgeschlagen.";
const char wifiSetLastSSID[] = "Schreibe letzte erfolgreiche SSID in NVS für WLan Schnellstart: %s";

#endif