Sensore di livello dell'acqua Arduino: taratura, allarme, pompa
Sensore di livello dell'acqua con Arduino: taratura vuoto/metà/pieno, alimentazione da pin contro la corrosione, allarme con buzzer, pompa e codice ESP32/Pico.
Un sensore di livello dell'acqua è il modo più economico e semplice per capire con Arduino fin dove arriva l'acqua in un bicchiere, in un acquario, nel sottovaso di una pianta o in un piccolo serbatoio. Man mano che le piste conduttive scoperte della scheda finiscono sott'acqua, la tensione sulla sua uscita analogica sale; Arduino legge questa tensione con analogRead() e decide se il contenitore è «vuoto», «a metà» o «pieno». Si collega con tre fili, funziona con poche righe di codice ed è la base di molti progetti, dall'allarme di traboccamento al controllo automatico di una pompa.
In questa guida scoprirai cosa c'è dentro il modulo, perché la lettura non arriva mai a 1023, come fare la taratura vuoto/metà/pieno e come evitare la corrosione che consuma il sensore in poche settimane. Poi costruirai un allarme di traboccamento con buzzer e un controllo della pompa che riempie un serbatoio da solo, confronterai brevemente il sensore con un interruttore a galleggiante e con l'XKC-Y25 senza contatto e, infine, vedrai come fare lo stesso con l'ESP32 e il Raspberry Pi Pico.

Che cos'è un sensore di livello dell'acqua e come funziona?
La parte inferiore del modulo ospita dieci piste conduttive che non si toccano e si incastrano come i denti di due pettini. Cinque sono piste di alimentazione collegate al +, le altre cinque sono piste di rilevamento che vanno alla base del transistor NPN S8050 sulla parte alta della scheda. Quando la scheda è asciutta tra le piste c'è solo aria, il transistor è spento e il pin S resta vicino a 0 V. Quando la scheda va in acqua, l'acqua fa da ponte tra le piste di alimentazione e quelle di rilevamento; una piccola corrente entra nella base, il transistor comincia a condurre e la tensione dell'uscita S, presa dall'emettitore, sale. Più l'acqua sale, più cresce la lunghezza di pista bagnata, più diminuisce la resistenza tra le piste e più aumenta la tensione di uscita.
Questo modo di funzionare ha tre conseguenze importanti. La prima è che il sensore non misura davvero l'acqua ma la sua conducibilità: i minerali disciolti nell'acqua del rubinetto alzano la lettura, mentre l'acqua pura (distillata) non dà quasi nulla. La seconda è che l'uscita proviene da un transistor in configurazione a inseguitore di emettitore, quindi la tensione non raggiunge mai quella di alimentazione; un sensore completamente bagnato e alimentato a 5 V di solito legge circa 500–650 su un Arduino Uno e non si avvicina mai a 1023. La terza è che la relazione non è lineare: il valore sale in fretta nei primi millimetri e poi sempre più lentamente. Per questo il sensore non è un righello con precisione al millimetro, ma un indicatore pratico che distingue in modo affidabile pochi livelli.
| Caratteristica | Valore |
|---|---|
| Tensione di funzionamento | 3,3–5 V DC |
| Corrente di funzionamento | Meno di 20 mA (massima quando è completamente bagnato) |
| Uscita | Tensione analogica (pin S), aumenta al salire dell'acqua |
| Area di rilevamento | Circa 40 × 16 mm, cioè al massimo circa 4 cm di altezza d'acqua |
| Dimensioni della scheda | Circa 62 × 20 mm |
| Temperatura di funzionamento | 10–30 °C (dato del produttore) |
| Pin | S (segnale), + (VCC), − (GND) |
Collegamento del sensore di livello dell'acqua: Arduino Uno, ESP32 e Pico
| Pin del sensore | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| S (segnale) | A0 | GPIO 34 (ADC1) | GP26 (ADC0) |
| + (VCC) | D7 (lo alimenta solo durante la misura) | GPIO 25 | GP15 |
| − (GND) | GND | GND | GND |
Il modo più semplice per evitare la corrosione è alimentare il sensore da un pin digitale, come vedi nella tabella: il codice porta il pin a HIGH subito prima della misura, attende 10 ms, legge il valore e riporta il pin a LOW. In un sistema che misura una volta al secondo le piste restano sotto tensione solo l'1 per cento del tempo, e l'usura rallenta di circa cento volte. Completamente bagnato, il modulo assorbe al massimo una ventina di mA. Il limite consigliato per un pin di Arduino Uno è 20 mA e quello assoluto 40 mA, e il pin resta acceso solo pochi millisecondi, quindi questo collegamento è sicuro; anche i pin dell'ESP32 forniscono questa corrente senza problemi. I pin del Pico, invece, lavorano di default con una corrente di uscita più bassa, perciò con il sensore completamente bagnato la tensione del pin cala un po' e le letture si riducono. Finché fai la taratura con lo stesso collegamento non è un problema; se vuoi valori più stabili puoi commutare il + del sensore con un piccolo transistor PNP come il BC557: l'emettitore va al pin 3V3 della scheda, il collettore al + del sensore e la base al pin GPIO tramite una resistenza da 1 kΩ; in questo caso il sensore si accende quando il pin è LOW. Per scegliere il transistor giusto dai un'occhiata allo strumento transistor.
Passo dopo passo: la prima lettura con Arduino
- Collega il pin S del sensore ad A0, il pin + a D7 e il pin − a GND. Tieni la scheda in verticale, con le piste rivolte verso il basso.
- Apri il codice qui sotto nell'Arduino IDE, scegli Arduino Uno come scheda e la porta corretta e caricalo.
- Apri il Monitor seriale e impostalo a 9600 baud. Verifica che con il sensore asciutto il valore sia vicino a 0.
- Immergi lentamente il sensore in un bicchiere d'acqua: prima solo la punta, poi fino a metà, poi fino alla linea dove finiscono le piste. A ogni passo attendi qualche secondo e annota il valore.
1const int SENSOR_PIN = A0; // S → A0
2const int POWER_PIN = 7; // + → D7 (yalnızca ölçerken besle / power only while measuring)
3
4int readSensor() {
5 digitalWrite(POWER_PIN, HIGH); // sensörü aç / power the sensor
6 delay(10); // değerin oturmasını bekle / let the reading settle
7 long sum = 0;
8 for (int i = 0; i < 8; i++) { // 8 ölçümün ortalaması / average of 8 readings
9 sum += analogRead(SENSOR_PIN);
10 }
11 digitalWrite(POWER_PIN, LOW); // sensörü kapat / power off
12 return sum / 8;
13}
14
15void setup() {
16 pinMode(POWER_PIN, OUTPUT);
17 digitalWrite(POWER_PIN, LOW); // kapalı başla / start powered off
18 Serial.begin(9600);
19}
20
21void loop() {
22 int raw = readSensor();
23 Serial.print("Ham deger / Raw value: ");
24 Serial.println(raw);
25 delay(1000); // saniyede bir ölç / measure once a second
26}La funzione readSensor() tiene acceso il sensore solo per circa 11 ms a ogni misura. L'attesa di 10 ms permette al transistor e all'acqua tra le piste di assestarsi su un valore stabile; poi la media di 8 letture smussa le piccole oscillazioni dei singoli campioni. Sull'Uno ogni analogRead() richiede circa 0,1 ms, quindi 8 letture durano meno di 1 ms. Se mescoli l'acqua o muovi il bicchiere vedrai i valori ballare nel Monitor seriale; è normale, perché la superficie in movimento cambia di continuo la lunghezza bagnata delle piste.
Vuoto, metà, pieno: come tarare il sensore
Non usare così come sono le soglie dei codici trovati online: ogni sensore, ogni tipo d'acqua e ogni tensione di alimentazione danno valori diversi. Esegui la taratura nel contenitore dove il sensore verrà davvero usato e con la stessa acqua: acqua dell'acquario per l'acquario, acqua con fertilizzante per un serbatoio di irrigazione fertilizzato. Traccia con un pennarello delle linee a 0, 10, 20, 30 e 40 mm sul sensore, immergi la scheda fino a ogni linea, aspetta 3–4 secondi che il valore si stabilizzi e annota il numero del Monitor seriale. La tabella mostra intervalli tipici per l'acqua del rubinetto e 5 V; scrivi accanto i tuoi valori.
| Livello | Profondità di immersione | Valore tipico su Uno (5 V, acqua del rubinetto) |
|---|---|---|
| Vuoto | 0 mm (asciutto) | 0–20 |
| Basso | Circa 5–10 mm | 250–400 |
| Metà | Circa 20 mm | 400–480 |
| Pieno | Circa 40 mm (linea dove finiscono le piste) | 480–650 |
Ciò che salta all'occhio nella tabella è quanto rapidamente i valori salgono nel primo centimetro e quanto poi si comprimono: tra 0 e 10 mm ci possono essere alcune centinaia di unità di differenza, ma tra 20 e 40 mm solo qualche decina. Per questo, invece di tracciare un'unica retta con map(), l'interpolazione lineare a tratti, che usa un rapporto diverso tra ogni coppia di punti misurati, dà un risultato molto più preciso. Il codice seguente conserva i cinque punti che hai misurato in due array, converte il valore grezzo in millimetri e scrive il livello con il suo nome. Ti basta inserire le tue letture nell'array RAW in ordine crescente.
1const int SENSOR_PIN = A0;
2const int POWER_PIN = 7;
3
4// Kendi kalibrasyon ölçümlerin / your own calibration readings
5const int N = 5;
6const int RAW[N] = {0, 330, 440, 490, 520}; // ham değer, küçükten büyüğe / raw value, ascending
7const int MM[N] = {0, 10, 20, 30, 40}; // batma derinliği (mm) / immersion depth (mm)
8
9int readSensor() {
10 digitalWrite(POWER_PIN, HIGH);
11 delay(10);
12 long sum = 0;
13 for (int i = 0; i < 8; i++) sum += analogRead(SENSOR_PIN);
14 digitalWrite(POWER_PIN, LOW);
15 return sum / 8;
16}
17
18int rawToMm(int raw) {
19 if (raw <= RAW[0]) return MM[0];
20 for (int i = 1; i < N; i++) {
21 if (raw <= RAW[i]) { // iki nokta arasında oran kur / interpolate between two points
22 return map(raw, RAW[i - 1], RAW[i], MM[i - 1], MM[i]);
23 }
24 }
25 return MM[N - 1]; // en üst noktanın üstü / above the top point
26}
27
28const char* levelName(int mm) {
29 if (mm < 3) return "Bos / Empty";
30 if (mm < 15) return "Az / Low";
31 if (mm < 30) return "Yarim / Half";
32 return "Dolu / Full";
33}
34
35void setup() {
36 pinMode(POWER_PIN, OUTPUT);
37 digitalWrite(POWER_PIN, LOW);
38 Serial.begin(9600);
39}
40
41void loop() {
42 int raw = readSensor();
43 int mm = rawToMm(raw);
44 Serial.print(raw);
45 Serial.print(" -> ");
46 Serial.print(mm);
47 Serial.print(" mm, ");
48 Serial.println(levelName(mm));
49 delay(1000);
50}Allarme di traboccamento con buzzer
Uno dei compiti più utili di un sensore di livello dell'acqua è avvisarti di un traboccamento: messo sotto la lavatrice o la caldaia, in un sottovaso, nella vaschetta della condensa del condizionatore o sul bordo di un secchio che si sta riempiendo, il sensore fa partire l'allarme appena l'acqua ne tocca la punta. Per questo basta perfino il livello «basso» della tabella di taratura. Il codice qui sotto usa un buzzer attivo e il LED integrato dell'Uno; quando il valore supera ALARM_ON il buzzer suona ogni quarto di secondo, quando scende sotto ALARM_OFF tace. Poiché per i tempi si usa millis() invece di delay(), la misura e il buzzer non si bloccano a vicenda. Per i tipi di buzzer leggi Che cos'è un buzzer?, per il principio di millis() millis() e delay().
1const int SENSOR_PIN = A0; // S → A0
2const int POWER_PIN = 7; // + → D7
3const int BUZZER_PIN = 8; // aktif buzzer + ucu / active buzzer +
4const int LED_PIN = 13; // Uno'nun dahili LED'i / Uno's built-in LED
5
6const int ALARM_ON = 200; // bu değer ve üstü taşma / at or above: overflow (kendin ölç / measure yours)
7const int ALARM_OFF = 100; // bunun altına inince alarm biter / alarm clears below this
8
9bool alarmActive = false;
10bool buzzerOn = false;
11unsigned long lastRead = 0;
12unsigned long lastBeep = 0;
13
14int readSensor() {
15 digitalWrite(POWER_PIN, HIGH);
16 delay(10);
17 long sum = 0;
18 for (int i = 0; i < 8; i++) sum += analogRead(SENSOR_PIN);
19 digitalWrite(POWER_PIN, LOW);
20 return sum / 8;
21}
22
23void setup() {
24 pinMode(POWER_PIN, OUTPUT);
25 pinMode(BUZZER_PIN, OUTPUT);
26 pinMode(LED_PIN, OUTPUT);
27 digitalWrite(POWER_PIN, LOW);
28 Serial.begin(9600);
29}
30
31void loop() {
32 unsigned long now = millis();
33
34 if (now - lastRead >= 1000) { // saniyede bir ölç / measure once a second
35 lastRead = now;
36 int level = readSensor();
37 if (!alarmActive && level >= ALARM_ON) alarmActive = true; // taşma başladı / overflow started
38 if (alarmActive && level < ALARM_OFF) alarmActive = false; // su çekildi / water receded
39 Serial.print("Seviye / Level: ");
40 Serial.println(level);
41 }
42
43 if (alarmActive) {
44 if (now - lastBeep >= 250) { // 250 ms öt, 250 ms sus / 250 ms on, 250 ms off
45 lastBeep = now;
46 buzzerOn = !buzzerOn;
47 digitalWrite(BUZZER_PIN, buzzerOn ? HIGH : LOW);
48 }
49 } else if (buzzerOn) {
50 buzzerOn = false;
51 digitalWrite(BUZZER_PIN, LOW);
52 }
53 digitalWrite(LED_PIN, alarmActive ? HIGH : LOW);
54}Controllo della pompa: riempire un serbatoio da solo
La seconda applicazione classica è il rabbocco automatico che mantiene il livello entro una fascia. Magari vuoi reintegrare l'acqua che evapora da un acquario prendendola da un secchio di riserva, tenere pieno l'abbeveratoio del tuo animale o alimentare il serbatoio di una serra. La logica è semplice: quando il livello scende sotto START_BELOW la pompa parte, quando raggiunge STOP_ABOVE si ferma. Lo spazio tra queste due soglie è l'isteresi che impedisce alla pompa di accendersi e spegnersi di continuo. Ricorda che il sensore ha un'area di rilevamento di soli 4 cm circa; fissa la scheda a un'altezza in cui la fascia d'acqua che vuoi mantenere cada all'interno di quei 4 cm.

La pompa assorbe molta più corrente di quella che un pin di Arduino può fornire: comandala quindi con un modulo relè oppure con un MOSFET a livello logico e un diodo di ricircolo, alimentala con una fonte separata e collega insieme le GND delle due alimentazioni. Trovi i dettagli in Che cos'è un modulo relè?, come usare un MOSFET e la mini pompa per acqua. La parte più importante del codice è una misura di sicurezza: se la pompa funziona per tutto il tempo MAX_RUN_MS e il livello non raggiunge ancora l'obiettivo, il sistema blocca la pompa e ti avvisa con brevi bip. Forse il tubo si è sfilato, il secchio di riserva è vuoto o il sensore si è spostato; senza questo blocco la pompa potrebbe girare a secco per ore o allagare tutto.
1const int SENSOR_PIN = A0;
2const int POWER_PIN = 7;
3const int PUMP_PIN = 8; // röle IN / relay IN
4const int BUZZER_PIN = 9; // aktif buzzer / active buzzer
5const bool RELAY_ACTIVE_LOW = true; // çoğu röle modülü LOW ile çeker / most relay modules switch on LOW
6
7const int START_BELOW = 300; // bunun altında doldur / start filling below this (kendin ölç / measure yours)
8const int STOP_ABOVE = 480; // bu değerde dur / stop at this value
9const unsigned long MAX_RUN_MS = 30000; // en uzun çalışma 30 sn / max run time 30 s
10
11bool pumpOn = false;
12bool fault = false;
13unsigned long pumpStart = 0;
14
15int readSensor() {
16 digitalWrite(POWER_PIN, HIGH);
17 delay(10);
18 long sum = 0;
19 for (int i = 0; i < 8; i++) sum += analogRead(SENSOR_PIN);
20 digitalWrite(POWER_PIN, LOW);
21 return sum / 8;
22}
23
24void setPump(bool on) {
25 pumpOn = on;
26 bool pinHigh = RELAY_ACTIVE_LOW ? !on : on;
27 digitalWrite(PUMP_PIN, pinHigh ? HIGH : LOW);
28}
29
30void setup() {
31 setPump(false); // pin çıkış olmadan önce kapalı konuma al / set off before the pin becomes an output
32 pinMode(PUMP_PIN, OUTPUT);
33 pinMode(POWER_PIN, OUTPUT);
34 pinMode(BUZZER_PIN, OUTPUT);
35 digitalWrite(POWER_PIN, LOW);
36 Serial.begin(9600);
37}
38
39void loop() {
40 if (fault) { // arıza: pompa kilitli, kesik kesik öt / fault: pump locked out, beep
41 digitalWrite(BUZZER_PIN, HIGH);
42 delay(200);
43 digitalWrite(BUZZER_PIN, LOW);
44 delay(1800);
45 return; // yeniden başlatmak için reset / press reset to restart
46 }
47
48 int level = readSensor();
49
50 if (!pumpOn && level < START_BELOW) {
51 setPump(true); // seviye düştü, doldur / level low, start filling
52 pumpStart = millis();
53 } else if (pumpOn && level >= STOP_ABOVE) {
54 setPump(false); // istenen seviyeye ulaşıldı / target level reached
55 } else if (pumpOn && millis() - pumpStart > MAX_RUN_MS) {
56 setPump(false); // süre doldu, seviye yükselmedi / timed out, level did not rise
57 fault = true;
58 }
59
60 Serial.print("Seviye / Level: ");
61 Serial.print(level);
62 Serial.println(pumpOn ? " pompa / pump ON" : " pompa / pump OFF");
63 delay(500);
64}Sensore di livello dell'acqua, interruttore a galleggiante e XKC-Y25 a confronto
| Caratteristica | Sensore di livello dell'acqua (piste conduttive) | Interruttore a galleggiante | XKC-Y25 (senza contatto) |
|---|---|---|---|
| Principio di rilevamento | Conducibilità dell'acqua | Magnete galleggiante e contatto reed | Variazione di capacità dietro la parete del contenitore |
| Uscita | Analogica (pochi livelli) | Contatto aperto o chiuso | Digitale (liquido presente o no) |
| Campo di misura | Circa 0–4 cm | Un punto (altezza di montaggio) | Un punto (altezza di montaggio) |
| Contatto con l'acqua | Sì, piste in acqua | Sì, corpo in acqua | No, si incolla all'esterno del contenitore |
| Corrosione | Sì; alimentarlo da un pin è indispensabile | Praticamente nessuna | Nessuna |
| Alimentazione | 3,3–5 V | Non serve (contatto passivo) | 5–24 V, circa 5 mA |
| Ideale per | Esperimenti, allarmi di traboccamento, piccoli contenitori | Serbatoi fissi, protezione della pompa | Serbatoi chiusi in plastica o vetro, liquidi corrosivi |
| Prezzo | Il più economico | Economico | Più caro degli altri |
Un interruttore a galleggiante è formato da uno stelo con un contatto reed all'interno e da un galleggiante con magnete che scorre lungo di esso. Quando l'acqua sale, il galleggiante si solleva, il magnete arriva all'altezza del contatto reed e il contatto si chiude o si apre. Montando il galleggiante capovolto sullo stelo puoi passare da normalmente aperto (NO) a normalmente chiuso (NC). Per collegarlo ad Arduino basta portare un filo a un pin digitale e l'altro a GND e impostare il pin come INPUT_PULLUP; non soffrendo dell'usura da elettrolisi, dura molto di più nelle installazioni fisse. I contatti dei modelli piccoli sono in genere limitati a circa 0,5 A e 10 W, quindi comanda la pompa tramite un relè e non direttamente. Per capire come funziona un contatto reed leggi l'articolo Interruttore reed.

1const int FLOAT_PIN = 2; // bir kablo D2'ye, diğeri GND'ye / one wire to D2, the other to GND
2
3void setup() {
4 pinMode(FLOAT_PIN, INPUT_PULLUP); // dahili pull-up direnci / internal pull-up resistor
5 Serial.begin(9600);
6}
7
8void loop() {
9 // Kontak kapalıyken pin LOW okunur / the pin reads LOW when the contact is closed
10 if (digitalRead(FLOAT_PIN) == LOW) {
11 Serial.println("Kontak kapali / Contact closed");
12 } else {
13 Serial.println("Kontak acik / Contact open");
14 }
15 delay(500);
16}L'XKC-Y25, invece, è un sensore capacitivo che non tocca mai l'acqua: si incolla all'esterno di un serbatoio di plastica o di vetro e rileva se dietro la parete c'è del liquido. Secondo il produttore funziona a 5–24 V, assorbe circa 5 mA, rileva attraverso pareti non metalliche spesse fino a 13 mm e risponde in circa 500 ms. Il livello alto della sua uscita è pari alla tensione di alimentazione, quindi se colleghi a un ESP32 o a un Pico un XKC-Y25 alimentato a 5 V devi usare un partitore di tensione (lo strumento partitore di tensione calcola le resistenze giuste). Spieghiamo in dettaglio la regolazione della sensibilità e i modelli con uscite diverse nell'articolo sensore di livello senza contatto XKC-Y25.

Controllare il livello dell'acqua dal telefono con l'ESP32
Con l'ESP32 puoi portare la misura sul telefono tramite Wi-Fi. Collega sempre il pin S del sensore a un pin dell'ADC1 (GPIO 32–39); i pin dell'ADC2 non si possono leggere con il Wi-Fi attivo. L'ADC dell'ESP32 è a 12 bit, quindi i valori vanno da 0 a 4095, e poiché il sensore è alimentato a 3,3 V i numeri non sono confrontabili con quelli dell'Uno: dovrai ripetere la taratura. L'ADC dell'ESP32 non è del tutto lineare vicino a 0 V e vicino al fondo scala, ma dato che qui conta la differenza tra i livelli e non la tensione assoluta, non è un problema. Il codice seguente misura ogni due secondi e offre una piccola pagina web che si aggiorna da sola ogni cinque secondi e che puoi aprire dal telefono sulla stessa rete.
1#include <WiFi.h>
2#include <WebServer.h>
3
4const char* WIFI_SSID = "WIFI_ADIN"; // ağ adın / your network name
5const char* WIFI_PASS = "WIFI_SIFREN"; // ağ şifren / your network password
6
7const int SENSOR_PIN = 34; // S → GPIO 34 (ADC1, Wi-Fi ile çalışır / works with Wi-Fi)
8const int POWER_PIN = 25; // + → GPIO 25
9const int HALF = 1500; // yarım eşiği / half threshold (kendin ölç / measure yours)
10const int FULL = 2000; // dolu eşiği / full threshold (kendin ölç / measure yours)
11
12WebServer server(80);
13int lastRaw = 0;
14unsigned long lastRead = 0;
15
16int readSensor() {
17 digitalWrite(POWER_PIN, HIGH);
18 delay(10);
19 long sum = 0;
20 for (int i = 0; i < 16; i++) sum += analogRead(SENSOR_PIN); // 0–4095
21 digitalWrite(POWER_PIN, LOW);
22 return sum / 16;
23}
24
25const char* levelName(int raw) {
26 if (raw < 100) return "Bos / Empty";
27 if (raw < HALF) return "Az / Low";
28 if (raw < FULL) return "Yarim / Half";
29 return "Dolu / Full";
30}
31
32void handleRoot() {
33 String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>"
34 "<meta name='viewport' content='width=device-width'>"
35 "<meta http-equiv='refresh' content='5'></head><body>"
36 "<h1>Su seviyesi / Water level</h1><h2>";
37 html += levelName(lastRaw);
38 html += "</h2><p>Ham deger / Raw: ";
39 html += lastRaw;
40 html += "</p></body></html>";
41 server.send(200, "text/html", html);
42}
43
44void setup() {
45 Serial.begin(115200);
46 pinMode(POWER_PIN, OUTPUT);
47 digitalWrite(POWER_PIN, LOW);
48 WiFi.begin(WIFI_SSID, WIFI_PASS);
49 while (WiFi.status() != WL_CONNECTED) { // bağlanana kadar bekle / wait until connected
50 delay(500);
51 Serial.print(".");
52 }
53 Serial.println();
54 Serial.print("Adres / Address: http://");
55 Serial.println(WiFi.localIP());
56 server.on("/", handleRoot);
57 server.begin();
58}
59
60void loop() {
61 server.handleClient();
62 if (millis() - lastRead >= 2000) { // 2 sn'de bir ölç / measure every 2 s
63 lastRead = millis();
64 lastRaw = readSensor();
65 }
66}Prima di caricare il codice sostituisci WIFI_SSID e WIFI_PASS con i dati della tua rete; l'ESP32 si collega solo a reti a 2,4 GHz. Aprendo il Monitor seriale a 115200 baud, ti basta digitare l'indirizzo che compare nel browser del telefono. Se vuoi ricevere una notifica sul telefono quando il livello è «pieno», puoi trasformare la stessa lettura in un messaggio con il metodo dell'articolo bot Telegram con ESP32.
Allarme di traboccamento con Raspberry Pi Pico e MicroPython
Sul Raspberry Pi Pico per le letture analogiche si usano i pin GP26, GP27 e GP28. La funzione read_u16() di MicroPython riporta la misura a 12 bit del Pico nell'intervallo 0–65535, quindi le tue soglie saranno numeri molto più grandi che sull'Uno. Il codice qui sotto alimenta il sensore da GP15, legge l'uscita S su GP26 e segnala il traboccamento con tre brevi bip di un buzzer attivo collegato a GP14. Come nel primo sketch, fissa le soglie in base alle tue misure.
1from machine import ADC, Pin
2import time
3
4sensor = ADC(26) # GP26 (ADC0) → S
5power = Pin(15, Pin.OUT, value=0) # GP15 → sensör + / sensor +
6buzzer = Pin(14, Pin.OUT, value=0) # GP14 → aktif buzzer / active buzzer
7
8ALARM_ON = 20000 # bu değer ve üstü taşma / at or above: overflow (kendin ölç / measure yours)
9ALARM_OFF = 10000 # bunun altında alarm biter / alarm clears below this
10
11def read_level(samples=8):
12 power.value(1)
13 time.sleep_ms(10) # değerin oturmasını bekle / let the reading settle
14 total = 0
15 for _ in range(samples):
16 total += sensor.read_u16() # 0–65535
17 power.value(0)
18 return total // samples
19
20alarm = False
21while True:
22 level = read_level()
23 if not alarm and level >= ALARM_ON:
24 alarm = True
25 elif alarm and level < ALARM_OFF:
26 alarm = False
27 print("Seviye / Level:", level, "ALARM" if alarm else "")
28 if alarm:
29 for _ in range(3): # üç kısa bip / three short beeps
30 buzzer.value(1)
31 time.sleep_ms(150)
32 buzzer.value(0)
33 time.sleep_ms(150)
34 else:
35 time.sleep(1)Idee di progetto con un sensore di livello dell'acqua
- Avviso di traboccamento del sottovaso: Un buzzer che suona quando dopo l'irrigazione si accumula acqua nel sottovaso; abbinato a un sensore di umidità del terreno diventa un impianto di irrigazione completo.
- Rabbocco automatico dell'acquario: Un sistema di riempimento a tempo limitato che reintegra con una mini pompa l'acqua evaporata prendendola da un secchio di riserva.
- Ciotola dell'acqua per animali: Un promemoria che accende un LED o invia una notifica al telefono tramite l'ESP32 quando l'acqua sta finendo.
- Rilevatore di allagamento: Un allarme perdite con il sensore appoggiato in orizzontale sul pavimento sotto la lavatrice, vicino alla caldaia o in cantina.
- Serbatoio intelligente per la serra: Una protezione che controlla il livello del serbatoio di irrigazione e blocca la pompa quando si svuota; si aggiunge facilmente al progetto di serra intelligente.
- Indicatore per il bidone dell'acqua piovana: Un pannello che mostra il livello come vuoto, metà o pieno su un display LCD I2C; puoi aggiungere anche un sensore di pioggia per capire quando inizia a piovere.
Errori comuni e soluzioni
| Sintomo | Causa probabile | Soluzione |
|---|---|---|
| Il valore è sempre 0, anche in acqua | Il pin + non è alimentato (POWER_PIN non va mai a HIGH) oppure S è sul pin sbagliato | Controlla le righe con pinMode e digitalWrite e che S sia su un pin analogico |
| Il valore salta a caso anche da asciutto | Il pin S è scollegato oppure manca la GND | Controlla tutti e tre i fili; la GND deve essere in comune |
| Non arriva mai a 1023, nemmeno del tutto immerso | È normale; l'uscita viene da un inseguitore di emettitore | Imposta le soglie in base al valore più alto che hai misurato tu |
| Nell'acqua pura non si legge nulla | L'acqua distillata o depurata conduce pochissimo | Con quest'acqua usa un XKC-Y25 o un interruttore a galleggiante |
| I valori calano o si spostano nel giro di qualche settimana | Elettrolisi e depositi sulle piste | Alimenta il sensore da un pin, pulisci le piste con uno spazzolino morbido e, se serve, sostituisci il sensore |
| Pompa o buzzer si accendono e spengono di continuo sulla soglia | C'è una sola soglia; la superficie in movimento fa oscillare il valore | Usa due soglie distinte per accensione e spegnimento (isteresi) e fai la media delle letture |
| Sull'ESP32 il valore non si legge più quando si collega il Wi-Fi | Il sensore è su un pin dell'ADC2 | Sposta S su un pin dell'ADC1 tra GPIO 32 e 39 |
Il sensore di livello dell'acqua insegna letture analogiche, taratura, isteresi e problemi reali come la corrosione con un solo modulo economico. Se devi misurare centimetro per centimetro il livello di un grande serbatoio, puoi passare a una soluzione a ultrasuoni come il sensore di distanza HC-SR04. Nell'app BlueGrays trovi la stazione di irrigazione intelligente e progetti di allarme con buzzer, con schemi e codice passo dopo passo, e puoi aggiungervi facilmente il sensore di livello dell'acqua.
Domande frequenti
Come funziona un sensore di livello dell'acqua?
Quando le piste conduttive intrecciate della scheda finiscono in acqua, l'acqua le collega e una corrente scorre verso la base del transistor S8050 del modulo. Più il transistor conduce, più sale la tensione sul pin S; Arduino legge questa tensione con analogRead() per capire fin dove arriva l'acqua.
Perché il mio sensore di livello dell'acqua si corrode?
Quando una corrente continua attraversa senza sosta le piste bagnate inizia l'elettrolisi e il rivestimento delle piste collegate al + si scioglie. Se alimenti il sensore da un pin digitale invece che dai 5V e lo accendi solo per pochi millisecondi a ogni lettura, l'usura rallenta moltissimo e il sensore dura mesi.
Il sensore di livello dell'acqua funziona con l'acqua distillata?
Quasi per niente. Poiché il sensore misura la conducibilità dell'acqua, l'acqua distillata o depurata, priva di minerali disciolti, dà letture molto basse. Per quest'acqua è meglio scegliere sensori che non dipendono dalla conducibilità, come l'XKC-Y25 senza contatto o un interruttore a galleggiante.
Perché il sensore di livello dell'acqua non arriva a 1023?
L'uscita S è presa dall'emettitore del transistor, quindi la tensione resta sotto quella di alimentazione, e la corrente di base è limitata dalla resistenza dell'acqua. Su un Arduino Uno a 5 V un sensore completamente bagnato di solito legge circa 500–650; imposta le soglie partendo da questo massimo.
Si può immergere completamente un sensore di livello dell'acqua?
No. Solo la parte bassa con le piste conduttive deve andare in acqua; se si bagna la parte alta con il transistor, il LED e i pin, si crea un cortocircuito e il sensore legge male o si guasta. Proteggere l'elettronica con colla a caldo o vernice ne allunga la vita.
Come si misura il livello di un grande serbatoio d'acqua?
Questo sensore copre solo circa 4 cm, quindi non è adatto ai grandi serbatoi. Per misurare il livello in modo continuo si usano sensori a ultrasuoni impermeabili come il JSN-SR04T montati sul coperchio del serbatoio; per controllare solo alcuni punti critici si mettono interruttori a galleggiante a diverse altezze.
Progetti da realizzare dopo questo articolo
Vedi tutti i progetti
Uso del cicalino
Ti sei mai chiesto come fa un campanello o un allarme a suonare? L'Arduino fa suonare un piccolo cicalino a intervalli brevi: bip, pausa, bip, pausa. Vedi come l'elettricità diventa suono e fai il pri

Misurare l'intensità luminosa con LDR
Vuoi vedere quanto è luminosa la tua stanza sotto forma di numero? L'LDR, un piccolo componente sensibile alla luce, misura la luce ambiente e l'Arduino scrive il valore sullo schermo del computer ogn

Lettura dell'intensità luminosa con il modulo LDR ESP32
Monitoraggio in tempo reale sul Serial Monitor del valore grezzo dell'ADC del modulo LDR e della percentuale relativa di luce calcolata dai valori di riferimento al buio e alla luce. Questa percentuale non è una misurazione in lux. Spiega il principio di calibrazione del modulo. È consigliabile eseguirlo prima del Progetto 10, poiché serve a determinare il valore di soglia.

Stazione di irrigazione intelligente
Un giardiniere che annaffia le tue piante da solo, così non si seccano mentre sei in vacanza. Un sensore di umidità misura quanto è bagnata la terra; quando diventa secca, l'Arduino accende la pompa d

Lettura di un sensore reed
Ti sei mai chiesto come funziona l'interruttore magnetico degli allarmi per porte e finestre? Quando una calamita si avvicina al modulo relè reed, il minuscolo interruttore al suo interno si chiude; l

Server web asincrono ESP32 (con indicazione dell'IP sul display LCD)
In questo progetto trasformiamo l'ESP32 in un server web asincrono che potrete controllare dal vostro telefono o computer collegato alla stessa rete Wi-Fi. Grazie alla libreria ESPAsyncWebServer, il server è in grado di elaborare più richieste contemporaneamente (a differenza del classico WebServer.h, che si blocca su una singola richiesta).

Sistema di Allarme Movimento ESP32 (PIR + Buzzer + LED + Telegram)
Un sistema di allarme di sicurezza intelligente che attiva buzzer e LED quando il sensore PIR rileva movimento, inviando contemporaneamente una notifica istantanea al proprietario tramite Telegram. Dispone di un tempo di attesa di 30 secondi per limitare la frequenza degli allarmi ripetuti; questo meccanismo non verifica la validità dei rilevamenti del sensore PIR né elimina le false attivazioni. Adatto a sicurezza domestica, monitoraggio di garage, magazzini o studi. Con l'ESP32-CAM è possibile
Altri articoli
App BlueGrays
Costruisci questo circuito passo passo sul telefono
Schema, codice ed elenco componenti in un’unica schermata. Oltre 200 progetti Arduino, ESP32 e Pico da realizzare.
Inquadra con il telefono
Punta la fotocamera sul codice: si apre lo store del tuo telefono.
oppure apri lo store

