Il Fonometro nasce per dare la possibilità al relatore di una conferenza di capire se in fondo alla sala le persone sentono bene la sua voce o meno. Il dispositivo percepisce l'intensità sonora e accende delle luci in base al valore in decibel rilevato.
Questo progetto è open source, chiunque può scaricare i file necessari, ricreare il progetto e contribuire al suo miglioramento. Non ci sono restrizioni di licenza d'uso, ma si invita a citare che è stato realizzato dagli studenti ASIRID.
Tutto il materiale necessario si trova su Gitlab.
Il dispositivo è costituito da tre luci di colore diverse, che servono ad indicare la percezione uditiva: il rosso indica un’intensità bassa, il giallo un’intensità intermedia e il verde indica un’intensità ottimale. Il microcontrollore, una volta avviato, si connette al wifi e carica una pagina web dalla quale sarà possibile andare a modificare alcuni parametri di funzionamento. Di default il fonometro avrà dei valori di soglia prestabiliti, tuttavia è importante ricordare che tali valori di soglia varieranno da stanza in stanza e da relatore a relatore. Pertanto è possibile andare ad effettuare una calibrazione manuale tramite pulsanti e schermo direttamente sul dispositivo oppure tramite la pagina web. Il fonometro ha tre pulsanti, uno verde di MENU, tramite cui è possibile scorrere tra le varie schermate del menu; e due pulsanti gialli che corrispondono a “più” e “meno”.
Il menu ha 6 schermate: la prima visualizza il valore in decibel che il microfono sta rilevando in tempo reale*, la seconda permette di visualizzare e/o modificare la soglia bassa (ovvero la soglia tra il rosso e il giallo), la terza permette di visualizzare e/o modificare la soglia alta (ovvero la soglia tra giallo e verde), la quarta permette di visualizzare e/o modificare il valore di luminosità dei LED, la quinta visualizza l’IP Address della pagina web di configurazione, la sesta permette di SALVARE la configurazione modificata direttamente dal dispositivo nelle schermate precedenti.
-
Modulo per il controllo di carichi elevati tramite segnali a bassa potenza.
-
Pulsanti con cappucci colorati o protettivi per interazioni user-friendly.
-
Display I2C per la visualizzazione di informazioni.
-
Decibel Sound Level Meter (I2C)
Sensore per la misurazione dei livelli sonori con interfaccia I2C.
-
LED di diversi colori per indicazioni visive.
-
Filtri colorati per modificare l'aspetto della luce emessa dai LED.
-
Modulo per la riduzione della tensione di alimentazione.
-
Supporti per montaggio e prototipazione dei componenti elettronici.
-
Fonte di alimentazione per il sistema.
-
Connettori compatibili per collegare l'alimentatore ai circuiti.
-
Viti piccole per fissaggio componenti
Viti per montare e fissare in modo stabile i componenti sulla struttura.
Per lo sviluppo di questo progetto è stato utilizzato Arduino IDE, in particolare una versione legacy (1.8.X). Questa versione è fondamentale per il caricamento della cartella data
all'interno della memoria del microcontrollore.
Installare le seguenti librerie manualmente seguendo i link forniti di seguito oppure dall’IDE di Arduino tramite il Library Manager
. È importante che le librerie siano installate nelle versioni indicate:
- U8g2lib - v2.35.37
- AsyncTCP - v1.1.4
- ESPAsyncWebServer - v1.2.4
- ESPAsync_WiFiManager - v1.15.1
- ElegantOTA - v3.1.6
- ArduinoJson - v7.1.0
N.B.: Per la libreria ElegantOTA è stata utilizzata la modalità asincrona (Async). Per utilizzarla bisogna abiltarla attraverso i seguenti passaggi:
-
Vai nella directory in cui sono memorizzate le librerie Arduino
-
Apri la directory
ElegantOTA
e successivamentesrc
-
Individua la costante
ELEGANTOTA_USE_ASYNC_WEBSERVER
nel fileElegantOTA.h
e impostala ad 1:#define ELEGANTOTA_USE_ASYNC_WEBSERVER 1
Utilizzare la seguente board con la versione specificata; in caso contrario, potrebbero verificarsi problemi di incompatibilità tra le librerie installate e la board.
- Board ESP32 - v2.0.17
Seleziona le seguenti opzioni dal menù a tendina:
- Scheda: vai su ESP32 Arduino e seleziona ESP32 Dev Module
- Partition Scheme: seleziona Default 4MB with spiffs (1.2MB APP/1.5MB APP SPIFFS)
- Vai alla pagina delle release e clicca sul file ESP32FS-1.0.zip per scaricarlo.
- Trova il percorso della cartella degli sketch dalle impostazioni dell'IDE Arduino.
- Vai nella cartella degli sketch e crea una cartella tools.
- Decomprimi il file zip scaricato. Aprila la cartella decompressa e copia la cartella ESP32FS nella cartella tools creata nel passaggio precedente. la struttura delle cartelle dovrebbe essere simile a questa:
<Sketchbook-location>/tools/ESP32FS/tool/esp32fs.jar
- Riavvia Arduino IDE.
Per verificare se il plugin è stato installato correttamente, apri Arduino IDE. Seleziona la tua scheda ESP32, vai su Strumenti e verifica la presenza dell'opzione "ESP32 Data Upload".
All'interno della cartella del progetto, troverai una cartella denominata data
. Questa cartella contiene i file necessari per il funzionamento del server web, che è ospitato direttamente sul microcontrollore ESP32.
Il contenuto della cartella data
viene caricato nel file system del microcontrollore (SPIFFS
), permettendo al microcontrollore di gestire autonomamente i file del server web, come pagine HTML
, fogli di stile CSS
e file JavaScript
.
- Apri Arduino IDE e seleziona la scheda ESP32 Dev Module.
- Dal menù superiore, vai su Strumenti e seleziona ESP32 Data Upload. Questa opzione è disponibile solo se il tool è stato installato correttamente.
- Arduino IDE inizierà il processo di caricamento dei file presenti nella cartella
data
all'interno del file system del microcontrollore.
Il codice come già riportato sopra utilizza diverse librerie per gestire la funzionalità del dispositivo:
-
Wire.h
eU8g2lib.h
: Per la gestione dell'I2C e del display OLED. -
ESPAsyncWebServer.h
,AsyncTCP.h
eESPAsync_WiFiManager.h
: Per la gestione del server web e della connessione WiFi. -
ElegantOTA.h
: Per eseguire aggiornamenti OTA (Over-The-Air). -
SPIFFS.h
eArduinoJson.h
: Per la gestione del filesystem e delle configurazioni in formato JSON.
Nel setup
, vengono configurati:
- La seriale per il debug.
- La connessione WiFi tramite un manager interattivo.
- Il filesystem SPIFFS per leggere e salvare configurazioni.
- I pin dei LED e dei pulsanti.
- Il display OLED per la visualizzazione dei dati.
La funzione loop gestisce un menu interattivo sul display OLED:
- Schermata 0: Mostra il valore attuale dei decibel.
- Schermata 1: Permette di modificare la soglia bassa.
- Schermata 2: Permette di modificare la soglia alta.
- Schermata 3: Regola la luminosità del display.
- Schermata 4: Mostra l'indirizzo IP del dispositivo.
- Schermata 5: Consente di salvare la configurazione.
I LED indicano i livelli di decibel rispetto alle soglie impostate:
- Rosso: Livello sotto la soglia bassa.
- Giallo: Livello tra la soglia bassa e quella alta.
- Verde: Livello sopra la soglia alta.
I valori di luminosità vengono mappati con la funzione map() per gestire la PWM.
Le configurazioni vengono salvate e caricate da un file JSON su SPIFFS:
- La funzione
saveConfiguration()
salva le impostazioni. - La funzione
loadConfiguration()
le legge all'avvio del sistema.
#include <Wire.h>
#include <U8g2lib.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <ESPAsync_WiFiManager.h>
#include <ElegantOTA.h>
#include <FS.h>
#include <SPIFFS.h>
#include <ArduinoJson.h>
#define FORMAT_SPIFFS_IF_FAILED true
#define PIN_LED_GREEN 14
#define PIN_LED_RED 33
#define PIN_LED_YELLOW 32
#define PIN_BTN_PLUS 15
#define PIN_BTN_MINUS 13
#define PIN_BTN_ENTER 25
#define I2C_SDA 17
#define I2C_SCL 16
#define DBM_ADDR 0x48
#define DBM_REG_DECIBEL 0x0A
#define DBM_REG_VERSION 0x00
#define HTTP_PORT 80
#define MAX_CHARATERS 30
const char* config_filename = "/config.json";
String user;
const char* username = "admin";
String pass;
const char* password = "admin";
const char* hostName = "FONOMETRO";
int num_schermate = 5;
int menu_btn = 0;
uint8_t db = 0;
uint8_t th_val_low = 60;
uint8_t th_val_high = 65;
int8_t brightness = 20;
char buffer[45];
U8G2_SSD1306_128X64_NONAME_F_HW_I2C display(U8G2_R0, /* reset=*/U8X8_PIN_NONE);
TwoWire dbmeter = TwoWire(1);
AsyncWebServer server(HTTP_PORT);
AsyncDNSServer dns;
void setup() {
Serial.begin(115200);
Serial.println("Starting...");
Wire.setClock(10000);
Wire.begin();
display.begin();
display.setFont(u8g2_font_helvR14_tf);
display.drawStr(0, 15, "Fonometro");
display.sendBuffer();
ESPAsync_WiFiManager wifiManager(&server, &dns, hostName);
if (!wifiManager.autoConnect("ESP32-Config-AP")) {
Serial.println("Failed to connect to WiFi, restarting...");
delay(3000);
ESP.restart();
}
Serial.print("Connected successfully to network ");
Serial.println(WiFi.SSID());
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) {
Serial.println("\nSPIFFS mount failed");
return;
}
Serial.println("\nSPIFFS mounted successfully");
if (!SPIFFS.exists(config_filename)) writeDefaultConfig(config_filename);
loadConfiguration();
ElegantOTA.begin(&server);
init_server();
Serial.println(F("\nHTTP server started"));
pinMode(PIN_BTN_PLUS, INPUT_PULLUP);
pinMode(PIN_BTN_MINUS, INPUT_PULLUP);
pinMode(PIN_BTN_ENTER, INPUT_PULLUP);
pinMode(PIN_LED_GREEN, OUTPUT);
pinMode(PIN_LED_YELLOW, OUTPUT);
pinMode(PIN_LED_RED, OUTPUT);
digitalWrite(PIN_LED_RED, 1);
digitalWrite(PIN_LED_YELLOW, 1);
digitalWrite(PIN_LED_GREEN, 1);
delay(1000);
digitalWrite(PIN_LED_RED, 0);
digitalWrite(PIN_LED_YELLOW, 0);
digitalWrite(PIN_LED_GREEN, 0);
delay(3000);
dbmeter.begin (I2C_SDA, I2C_SCL, 10000);
}
void loop() {
if (WiFi.status() != WL_CONNECTED) ESP.restart();
ElegantOTA.loop();
display.clearBuffer();
db = dbmeter_readreg(&dbmeter, DBM_REG_DECIBEL);
if (digitalRead(PIN_BTN_ENTER) == 0) {
menu_btn++;
if (menu_btn > num_schermate) menu_btn = 0;
}
if (menu_btn == 0) {
display.drawStr(0, 15, "Value:");
snprintf(buffer, sizeof(buffer), "%d dB", db);
display.drawStr(0, 45, buffer);
display.sendBuffer();
delay(100);
} else if (menu_btn == 1) {
display.drawStr(0, 15, "Low_th_val:");
snprintf(buffer, sizeof(buffer), "%d dB", th_val_low);
display.drawStr(0, 45, buffer);
display.sendBuffer();
delay(100);
if (digitalRead(PIN_BTN_PLUS) == 0) th_val_low++;
else if (digitalRead(PIN_BTN_MINUS) == 0) th_val_low--;
} else if (menu_btn == 2) {
display.drawStr(0, 15, "High_th_val:");
snprintf(buffer, sizeof(buffer), "%d dB", th_val_high);
display.drawStr(0, 45, buffer);
display.sendBuffer();
delay(100);
if (digitalRead(PIN_BTN_PLUS) == 0) th_val_high++;
else if (digitalRead(PIN_BTN_MINUS) == 0) th_val_high--;
} else if (menu_btn == 3) {
display.drawStr(0, 15, "Brightness:");
snprintf(buffer, sizeof(buffer), "%d %", brightness);
display.drawStr(0, 45, buffer);
display.sendBuffer();
delay(100);
if (digitalRead(PIN_BTN_PLUS) == 0) {
brightness++;
if (brightness > 100) brightness = 100;
} else if (digitalRead(PIN_BTN_MINUS) == 0) {
brightness--;
if (brightness < 1) brightness = 1;
}
} else if (menu_btn == 4) {
display.drawStr(0, 15, "IP Address: ");
snprintf(buffer, sizeof(buffer), "%s", WiFi.localIP().toString().c_str());
display.drawStr(0, 45, buffer);
display.sendBuffer();
delay(100);
} else if (menu_btn == 5) {
display.drawStr(0, 15, "Do you want to save to memory?");
display.drawStr(0, 45, "Press ENTER to confirm");
display.sendBuffer();
delay(100);
if (digitalRead(PIN_BTN_ENTER) == 0) {
saveConfiguration();
printConfigFile(config_filename);
delay(1000);
menu_btn = 0;
}
}
uint8_t pwm_value = map(brightness, 0, 100, 0, 255);
if (db <= th_val_low) {
analogWrite(PIN_LED_RED, pwm_value);
analogWrite(PIN_LED_YELLOW, 0);
analogWrite(PIN_LED_GREEN, 0);
} else if (db <= th_val_high) {
analogWrite(PIN_LED_RED, 0);
analogWrite(PIN_LED_YELLOW, pwm_value);
analogWrite(PIN_LED_GREEN, 0);
} else {
analogWrite(PIN_LED_RED, 0);
analogWrite(PIN_LED_YELLOW, 0);
analogWrite(PIN_LED_GREEN, pwm_value);
}
}
- Avvia una trasmissione verso il dispositivo all'indirizzo I2C
DBM_ADDR
. - Scrive l'indirizzo del registro (
regaddr
) per specificare quale valore leggere. - Termina la trasmissione.
- Richiede 1 byte di dati dal dispositivo.
- Attende 10 ms con
delay(10)
per garantire il completamento della comunicazione. - Legge e restituisce il valore del registro.
uint8_t dbmeter_readreg (TwoWire *dev, uint8_t regaddr)
{
dev->beginTransmission (DBM_ADDR);
dev->write (regaddr);
dev->endTransmission();
dev->requestFrom (DBM_ADDR, 1);
delay (10);
return dev->read();
}
-
loadConfiguration()
Legge il file di configurazione dalla memoria SPIFFS. Se il file è presente e valido, deserializza i dati JSON nelle variabili globali e stampa la configurazione sul monitor seriale. -
writeDefaultConfig()
Scrive una configurazione predefinita nella memoria SPIFFS. Sovrascrive eventuali configurazioni esistenti. -
FS_readConfig()
Legge il contenuto del file di configurazione dalla memoria SPIFFS come stringa e lo restituisce. Restituisce una stringa vuota in caso di errore. -
printConfigFile()
Stampa il contenuto del file di configurazione sul monitor seriale. Segnala un errore se il file non è leggibile. -
saveConfiguration()
Serializza i valori delle variabili globali in un file JSON e li salva nella memoria SPIFFS. Sovrascrive la configurazione esistente e segnala eventuali errori.
void loadConfiguration() {
File file = SPIFFS.open(config_filename, "r");
if (!file) {
Serial.print(F("Error opening file: unable to open "));
Serial.println(config_filename);
return;
}
StaticJsonDocument<2048> doc;
DeserializationError error = deserializeJson(doc, file);
if (error) {
Serial.println(F("Error reading file: "));
Serial.println(error.c_str());
}
file.close();
JsonObject root = doc.as<JsonObject>();
user = root["Username"].as<String>();
pass = root["Password"].as<String>();
username = user.c_str();
password = pass.c_str();
th_val_low = root["LowThreshold"].as<int>();
th_val_high = root["HighThreshold"].as<int>();
brightness = root["Brightness"].as<int>();
Serial.print(F("\nUsername: "));
Serial.println(username);
Serial.print(F("Password: "));
Serial.println(password);
Serial.print(F("Low Threshold: "));
Serial.println(th_val_low);
Serial.print(F("High Threshold: "));
Serial.println(th_val_high);
Serial.print(F("Brightness: "));
Serial.println(brightness);
Serial.println(F("\nConfiguration loaded!"));
}
void writeDefaultConfig(const char *filename) {
Serial.println(F("Loading default configuration..."));
File file = SPIFFS.open(filename, "w");
if (!file) {
Serial.println(F("Error opening file"));
return;
}
String defaultConfig = "{"
"\"Username\": \"admin\","
"\"Password\": \"admin\","
"\"LowThreshold\": 60,"
"\"HighThreshold\": 65,"
"\"Brightness\": 20"
"}";
file.print(defaultConfig);
file.close();
Serial.println(F("Loaded default configuration!"));
}
String FS_readConfig() {
File file = SPIFFS.open(config_filename, "r");
if (!file) {
Serial.println(F("Error reading file"));
return "";
}
String fileContent = file.readString();
file.close();
return fileContent;
}
void printConfigFile(const char *filename) {
File file = SPIFFS.open(filename, "r");
if (!file) {
Serial.println(F("Error reading file"));
return;
}
while (file.available()) {
Serial.print((char)file.read());
}
Serial.println();
file.close();
}
void saveConfiguration() {
StaticJsonDocument<2048> doc;
JsonObject root = doc.to<JsonObject>();
root["Username"] = user;
root["Password"] = pass;
root["LowThreshold"] = th_val_low;
root["HighThreshold"] = th_val_high;
root["Brightness"] = brightness;
File file = SPIFFS.open(config_filename, "w");
if (!file) {
Serial.println(F("Error opening file"));
return;
}
serializeJson(doc, file);
file.close();
Serial.println(F("Configuration saved!"));
}
-
/
(GET)
Gestisce la pagina principale, autenticando l'utente con username e password. Carica e invia il fileindex.html
dalla memoria SPIFFS con una cache di 1 ora. -
/style.css
(GET)
Serve il file CSS per la pagina, caricato dalla memoria SPIFFS e con cache di 1 ora. -
/script.js
(GET)
Serve il file JavaScript per la pagina, caricato dalla memoria SPIFFS e con cache di 1 ora. -
/upload
(POST)
Riceve dati JSON dal client, deserializza i valori (soglie di luminosità e luminosità) e li salva in variabili globali. -
/saveToMemory
(POST)
Salva una nuova configurazione JSON nella memoria SPIFFS. Riavvia il dispositivo per applicare le modifiche se il salvataggio è avvenuto con successo. -
/getStartupConfig
(GET)
Restituisce il file di configurazione salvato in memoria SPIFFS in formato JSON. Segnala un errore se il file non è leggibile. -
/getRunningConfig
(GET)
Restituisce la configurazione attualmente in uso (variabili globali) in formato JSON. -
/restart
(GET)
Ricarica la pagina principale (index.html
) e riavvia il dispositivo. -
server.begin()
Avvia il server web per gestire tutte le richieste.
void init_server() {
server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
if (!request->authenticate(username, password))
return request->requestAuthentication();
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.html", "text/html");
response->addHeader("Cache-Control", "max-age=3600");
request->send(response);
});
server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest * request) {
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/style.css", "text/css");
response->addHeader("Cache-Control", "max-age=3600");
request->send(response);
});
server.on("/script.js", HTTP_GET, [](AsyncWebServerRequest * request) {
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/script.js", "application/javascript");
response->addHeader("Cache-Control", "max-age=3600");
request->send(response);
});
server.on("/upload", HTTP_POST, [](AsyncWebServerRequest * request) {
}, NULL, [](AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total) {
String jsondata;
for (size_t i = 0; i < len; i++) {
jsondata += (char)data[i];
}
DynamicJsonDocument doc(2048);
deserializeJson(doc, jsondata);
th_val_low = doc["LowThreshold"];
th_val_high = doc["HighThreshold"];
brightness = doc["Brightness"];
Serial.println("\nSaving data into variables");
Serial.print(F("Low Threshold: "));
Serial.println(th_val_low);
Serial.print(F("High Threshold: "));
Serial.println(th_val_high);
Serial.print(F("Brightness: "));
Serial.println(brightness);
request->send(200);
});
server.on("/saveToMemory", HTTP_POST, [](AsyncWebServerRequest * request) {
}, NULL, [](AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total) {
String new_config;
for (size_t i = 0; i < len; i++) {
new_config += (char)data[i];
}
Serial.println(F("\nWriting new configuration..."));
Serial.println(new_config);
if (SPIFFS.begin()) {
File f = SPIFFS.open(config_filename, "w"); // Assicurati che il nome del file sia corretto
if (f) {
f.print(new_config);
f.close();
request->send(200, "text/plain", "Configuration loaded successfully");
delay(1000);
ESP.restart(); // da vedere se riavviare
} else {
request->send(500, "text/plain", "Error during attempt to save configuration");
}
}
});
server.on("/getStartupConfig", HTTP_GET, [](AsyncWebServerRequest * request) {
String configData = FS_readConfig();
if (configData.length() > 0) {
request->send(200, "application/json", configData);
} else {
request->send(500, "text/plain", "Error during attempt to read the configuration");
}
});
server.on("/getRunningConfig", HTTP_GET, [](AsyncWebServerRequest * request) {
StaticJsonDocument<2048> doc;
JsonObject object = doc.to<JsonObject>();
object["Username"] = username;
object["Password"] = password;
object["LowThreshold"] = th_val_low;
object["HighThreshold"] = th_val_high;
object["Brightness"] = brightness;
String response;
serializeJson(object, response);
request->send(200, "application/json", response);
});
server.on("/restart", HTTP_GET, [](AsyncWebServerRequest * request) {
AsyncWebServerResponse *response = request->beginResponse(SPIFFS, "/index.html", "text/html");
request->send(response);
delay(1000);
ESP.restart();
});
server.begin();
}
-
Sezioni principali:
-
Intestazione
Contiene il titolo della pagina ("Fonometro") e un link al foglio di stile esternostyle.css
. -
Container
Un contenitore principale con elementi:-
Campi di configurazione
-
Low Threshold
,High Threshold
, eBrightness
(input numerici, inizialmente disabilitati). -
Username
ePassword
(input testuali per credenziali). - Una checkbox (
edit-switch
) per abilitare la modifica dei campi disabilitati.
-
-
Pulsanti di controllo
- Reset: Ripristina i valori predefiniti.
- Save: Salva i dati configurati (variabili globali).
- Save to memory: Salva i dati nella memoria del dispositivo.
- Restart: Riavvia il dispositivo.
-
Campi di configurazione
-
Intestazione
-
Script esterno
Il filescript.js
gestisce le funzionalità interattive della pagina.
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<title>Fonometro</title>
</head>
<body>
<div class="container">
<h1 style="text-align: center;">Device Configuration</h1>
<div class="field-group">
<label for="low-threshold">Low Threshold:</label>
<input type="number" id="low-threshold" disabled />
</div>
<div class="field-group">
<label for="high-threshold">High Threshold:</label>
<input type="number" id="high-threshold" disabled />
</div>
<div class="field-group">
<label for="brightness">Brightness:</label>
<input type="number" id="brightness" disabled />
</div>
<div class="field-group">
<label for="username">Username:</label>
<input type="text" id="username" />
</div>
<div class="field-group">
<label for="password">Password:</label>
<input type="password" id="password" />
</div>
<div class="field-group">
<label for="edit-switch">
<input type="checkbox" id="edit-switch" />
Enables changes to the fields
</label>
</div>
<div class="buttons">
<button class="reset" id="reset">Reset</button>
<button class="save" id="save">Save</button>
<button class="save-memory" id="save-memory">Salva to memory</button>
<button class="restart" id="restart">Restart</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
-
Variabile globale
intervalId
: Usata per gestire l'intervallo di aggiornamento della configurazione corrente. -
Funzioni principali:
-
toggleFields()
Abilita o disabilita i campi di input in base allo stato della checkboxedit-switch
. Interrompe o avvia il polling della configurazione corrente ogni 5 secondi. -
resetFields()
Reimposta i valori di tutti i campi di input a vuoti. -
saveFields()
Invia i valori dei campiLowThreshold
,HighThreshold
eBrightness
al server tramite una richiestaPOST
all'endpoint/upload
. Mostra un messaggio di successo o errore. -
saveToMemory()
Salva i valori di tutti i campi di input (incluse credenziali) nella memoria del dispositivo tramite una richiestaPOST
all'endpoint/saveToMemory
. -
restart()
Chiede conferma per riavviare il dispositivo. Invia una richiesta all'endpoint/restart
e aggiorna la pagina dopo 10 secondi se il riavvio è stato avviato con successo. -
getRunningConfig()
Recupera la configurazione corrente dal server tramite una richiestaGET
all'endpoint/getRunningConfig
e aggiorna i campi di input con i valori ricevuti.
-
-
Event Listeners:
- Cambiamento dello stato della checkbox
edit-switch
: chiamatoggleFields()
. - Click sui pulsanti:
-
Reset
: chiamaresetFields()
. -
Save
: chiamasaveFields()
. -
Save to memory
: chiamasaveToMemory()
. -
Restart
: chiamarestart()
.
-
- Cambiamento dello stato della checkbox
-
Polling della configurazione corrente
setInterval()
richiamagetRunningConfig()
ogni 5 secondi per mantenere aggiornati i valori dei campi.
let intervalId;
function toggleFields() {
const isEditable = document.getElementById("edit-switch").checked;
document.getElementById("low-threshold").disabled = !isEditable;
document.getElementById("high-threshold").disabled = !isEditable;
document.getElementById("brightness").disabled = !isEditable;
document
.getElementById("low-threshold")
.classList.toggle("disabled", !isEditable);
document
.getElementById("high-threshold")
.classList.toggle("disabled", !isEditable);
document
.getElementById("brightness")
.classList.toggle("disabled", !isEditable);
if (isEditable) {
clearInterval(intervalId);
} else {
intervalId = setInterval(getRunningConfig, 5000);
}
}
function resetFields() {
document.getElementById("low-threshold").value = "";
document.getElementById("high-threshold").value = "";
document.getElementById("brightness").value = "";
document.getElementById("username").value = "";
document.getElementById("password").value = "";
}
function saveFields() {
const lowThreshold = document.getElementById("low-threshold").value;
const highThreshold = document.getElementById("high-threshold").value;
const brightness = document.getElementById("brightness").value;
if (!lowThreshold || !highThreshold || !brightness) {
alert("Please fill in all the required fields");
return;
}
fetch("/upload", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
LowThreshold: lowThreshold,
HighThreshold: highThreshold,
Brightness: brightness,
}),
})
.then((response) => {
if (response.ok) {
alert("Configuration saved successfully");
} else {
throw new Error("Error during attempt to save configuration");
}
})
.catch((error) => {
alert(error.message);
});
}
function saveToMemory() {
fetch("/saveToMemory", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
LowThreshold: document.getElementById("low-threshold").value,
HighThreshold: document.getElementById("high-threshold").value,
Brightness: document.getElementById("brightness").value,
Username: document.getElementById("username").value,
Password: document.getElementById("password").value,
}),
})
.then((response) => {
if (response.ok) {
alert("Configuration saved to memory successfully");
} else {
throw new Error("Error during attempt to save configuration to memory");
}
})
.catch((error) => {
alert(error.message);
});
}
function restart() {
if (confirm("Are you sure you want to restart the device?")) {
fetch("/restart")
.then((response) => {
if (response.ok) {
alert("Device restart initiated successfully");
setTimeout(() => {
window.location.reload(true);
}, 10000);
} else {
throw new Error("Error during attempt to restart device");
}
})
.catch((error) => {
alert(error.message);
});
}
}
function getRunningConfig() {
fetch("/getRunningConfig")
.then((response) => response.json())
.then((data) => {
document.getElementById("low-threshold").value = data.LowThreshold;
document.getElementById("high-threshold").value = data.HighThreshold;
document.getElementById("brightness").value = data.Brightness;
document.getElementById("username").value = data.Username;
document.getElementById("password").value = data.Password;
})
.catch(() => {
alert("Error during attempt to get running configuration");
});
}
document.getElementById("edit-switch").addEventListener("change", toggleFields);
document.getElementById("reset").addEventListener("click", resetFields);
document.getElementById("save").addEventListener("click", saveFields);
document.getElementById("save-memory").addEventListener("click", saveToMemory);
document.getElementById("restart").addEventListener("click", restart);
intervalId = setInterval(getRunningConfig, 5000);
getRunningConfig();
Il progetto è stato terminato nel Dicembre 2024.
Giovanni Pompigna, Francesco Sparascio, Luca Pezzi