added logic for loading available networks

This commit is contained in:
RaffaelW 2024-11-09 22:38:37 +01:00
parent 5c5e8e9e5a
commit 12aa87ac90
7 changed files with 145 additions and 11 deletions

1
data/icons/refresh.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#FFF"><path d="M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z"/></svg>

After

Width:  |  Height:  |  Size: 330 B

View file

@ -8,6 +8,7 @@
<script type="module" src="/input-visibility.js" defer></script> <script type="module" src="/input-visibility.js" defer></script>
<script type="module" src="/loading-screen.js" defer></script> <script type="module" src="/loading-screen.js" defer></script>
<script type="module" src="/load-data.js" defer></script> <script type="module" src="/load-data.js" defer></script>
<script type="module" src="/networks.js" defer></script>
<script type="module" src="/submit.js" defer></script> <script type="module" src="/submit.js" defer></script>
<script type="module" src="/reset.js" defer></script> <script type="module" src="/reset.js" defer></script>
</head> </head>
@ -32,8 +33,8 @@
<h1>Konfiguration</h1> <h1>Konfiguration</h1>
<fieldset> <fieldset>
<legend>Verbindung</legend> <legend>Verbindung</legend>
<label for="ip-method" <label>
>IP-Zuweisung: <span>IP-Zuweisung:</span>
<select <select
name="ip-method" name="ip-method"
id="input-ip-method" id="input-ip-method"
@ -45,7 +46,7 @@
</label> </label>
<div data-field="input-ip-method" data-values="0"> <div data-field="input-ip-method" data-values="0">
<label> <label>
IP-Adresse: <span>IP-Adresse:</span>
<input <input
type="text" type="text"
name="ip" name="ip"
@ -54,7 +55,7 @@
/> />
</label> </label>
<label> <label>
Subnetzmaske: <span>Subnetzmaske:</span>
<input <input
type="text" type="text"
name="subnet" name="subnet"
@ -63,7 +64,7 @@
/> />
</label> </label>
<label> <label>
Gateway: <span>Gateway:</span>
<input <input
type="text" type="text"
name="gateway" name="gateway"
@ -73,7 +74,7 @@
</label> </label>
</div> </div>
<label> <label>
Verbindungsmethode: <span>Verbindungsmethode:</span>
<select <select
name="connection" name="connection"
id="input-connection" id="input-connection"
@ -86,7 +87,7 @@
</label> </label>
<div data-field="input-connection" data-values="0"> <div data-field="input-connection" data-values="0">
<label> <label>
SSID: <span>SSID:</span>
<input <input
type="text" type="text"
name="ssid" name="ssid"
@ -97,17 +98,24 @@
</div> </div>
<div data-field="input-connection" data-values="1"> <div data-field="input-connection" data-values="1">
<label> <label>
Netzwerk: <span>Netzwerk:</span>
<select <select
name="ssid" name="ssid"
id="input-network" id="select-network"
title="Netzwerk" title="Netzwerk"
></select> ></select>
<button
type="button"
id="refresh-networks"
class="icon-button"
>
<img src="/icons/refresh.svg" alt="Neu laden" />
</button>
</label> </label>
</div> </div>
<div data-field="input-connection" data-values="0|1"> <div data-field="input-connection" data-values="0|1">
<label> <label>
Password: <span>Password:</span>
<input <input
type="password" type="password"
name="password" name="password"

60
data/networks.js Normal file
View file

@ -0,0 +1,60 @@
const networkDropdown = document.querySelector("#select-network");
const refreshButton = document.querySelector("#refresh-networks");
const refreshIcon = refreshButton.querySelector("img");
let isLoading = false;
refreshButton.addEventListener("click", async () => {
updateNetworks();
});
function insertNetworks(networks) {
networks.unshift(""); // add empty option
networkDropdown.textContent = ""; // clear dropdown
for (const ssid of networks) {
const option = document.createElement("option");
option.value = ssid;
option.innerText = ssid;
networkDropdown.appendChild(option);
}
}
async function loadNetworks() {
if (isLoading) return;
isLoading = true;
refreshButton.classList.remove("error-bg");
refreshIcon.classList.add("spinning");
try {
const res = await fetch("/networks", {
method: "GET",
});
if (!res.ok) {
throw Error(`response status: ${res.status}`);
}
const networks = await res.json();
refreshIcon.classList.remove("spinning");
isLoading = false;
// remove duplicate values
return Array.from(new Set(networks));
} catch (e) {
refreshIcon.classList.remove("spinning");
refreshButton.classList.add("error-bg");
isLoading = false;
return [];
}
}
async function updateNetworks() {
const networks = await loadNetworks();
if (networks) {
insertNetworks(networks);
}
}
updateNetworks();

View file

@ -3,6 +3,7 @@
--color-on-primary: white; --color-on-primary: white;
--color-background: #222; --color-background: #222;
--color-danger: #fa2b58; --color-danger: #fa2b58;
--icon-button-size: 2.5rem;
} }
body { body {
@ -38,11 +39,16 @@ fieldset {
label { label {
display: block; display: block;
display: flex; display: flex;
gap: 8px;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
flex-wrap: wrap; flex-wrap: wrap;
} }
label span {
flex-grow: 1;
}
input, input,
select { select {
width: clamp(200px, 100%, 400px); width: clamp(200px, 100%, 400px);
@ -60,6 +66,10 @@ select:focus {
border-color: var(--color-primary); border-color: var(--color-primary);
} }
select:has(+ .icon-button) {
width: calc(clamp(200px, 100%, 400px) - var(--icon-button-size) - 8px);
}
button { button {
border: none; border: none;
inset: none; inset: none;
@ -143,10 +153,14 @@ label.switch input:checked + .slider::before {
justify-content: center; justify-content: center;
} }
h2.error { .error {
color: var(--color-danger); color: var(--color-danger);
} }
.error-bg {
background-color: var(--color-danger) !important;
}
button.reload { button.reload {
display: block; display: block;
margin: 0 auto; margin: 0 auto;
@ -195,3 +209,17 @@ button.reload {
transform: rotate(360deg); transform: rotate(360deg);
} }
} }
.icon-button {
padding: 8px;
font-size: 0;
width: var(--icon-button-size);
height: var(--icon-button-size);
}
.spinning {
animation-name: spin;
animation-duration: 0.5s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}

View file

@ -46,6 +46,7 @@ void setup()
// WiFi.begin(ssid, pwd); // WiFi.begin(ssid, pwd);
WiFi.softAP(ssid, pwd); WiFi.softAP(ssid, pwd);
WiFi.softAPConfig(ip, gateway, subnet); WiFi.softAPConfig(ip, gateway, subnet);
WiFi.scanNetworks(true);
// WiFi.config(ip, gateway, subnet); // WiFi.config(ip, gateway, subnet);
// while (WiFi.status() != WL_CONNECTED) { // while (WiFi.status() != WL_CONNECTED) {
// Serial.print("."); // Serial.print(".");
@ -54,6 +55,8 @@ void setup()
// Serial.print("WiFi connected, IP = "); // Serial.print("WiFi connected, IP = ");
// Serial.println(WiFi.localIP()); // Serial.println(WiFi.localIP());
delay(5000);
// Initialize Art-Net // Initialize Art-Net
artnet.begin(); artnet.begin();
@ -94,6 +97,9 @@ void setup()
ESP.restart(); }); ESP.restart(); });
server.on("/networks", HTTP_GET, [](AsyncWebServerRequest *request)
{ onGetNetworks(request); });
server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)
{ {
if (request->url() == "/config" && request->method() == HTTP_PUT) { if (request->url() == "/config" && request->method() == HTTP_PUT) {

View file

@ -1,6 +1,7 @@
#include "config.h" #include "config.h"
#include <stdexcept> #include <stdexcept>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include "WiFi.h"
Preferences config; Preferences config;
@ -161,3 +162,31 @@ void onPutConfig(AsyncWebServerRequest *request, uint8_t *data, size_t len, size
request->send(400, "text/plain", e.what()); request->send(400, "text/plain", e.what());
} }
} }
void onGetNetworks(AsyncWebServerRequest *request)
{
JsonDocument doc;
JsonArray array = doc.to<JsonArray>();
int numberOfNetworks = WiFi.scanComplete();
if (numberOfNetworks == WIFI_SCAN_FAILED)
{
WiFi.scanNetworks(true);
}
else if (numberOfNetworks)
{
for (int i = 0; i < numberOfNetworks; ++i)
{
array.add(WiFi.SSID(i));
}
WiFi.scanDelete();
if (WiFi.scanComplete() == WIFI_SCAN_FAILED)
{
WiFi.scanNetworks(true);
}
}
String jsonString;
serializeJson(doc, jsonString);
request->send(200, "application/json", jsonString);
}

View file

@ -35,4 +35,6 @@ void onGetConfig(AsyncWebServerRequest *request);
void onPutConfig(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total); void onPutConfig(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total);
void onGetNetworks(AsyncWebServerRequest *request);
// #endif // #endif