Salvatore ClemenzaIngegnere full-stack + IoT
← Tutti i progetti

01 in produzione 2024 → oggi

Madonnina — irrigazione di precisione

Dieci centraline in produzione 24/7 da due anni, dove la rete cade e i sensori costano poco. Firmware, AI a bordo, dashboard operativa.

Architettura, firmware, backend, frontend

  • Arduino Edge Control nRF52840
  • SIM7080G Cat-M
  • Node-RED / MQTT
  • InfluxDB
  • React 19 / Vite
  • Mapbox GL
  • PWA / Capacitor
  • Hetzner / Docker
  • 10 centraline in produzione 24/7 dal 2024
  • 35 settori irrigui e 3 pompe
  • Una dashboard legacy da 2.305 nodi sostituita
  • Lettura della pressione 8,6× più veloce della versione storica
01 Colpo d'occhio

Un'azienda agricola con 35 settori irrigui e tre pompe da gestire, su un impianto reale: rete cellulare al limite della copertura, alimentazione non sempre continua, sensori a basso costo, manutenzione scomoda. Una centralina installata in campo deve restare in piedi per mesi senza che qualcuno ci passi sopra.

Prima del sistema attuale c'era una dashboard Node-RED legacy con ventinove schede e oltre duemilatrecento nodi: funzionava, ma era diventata fragile e leggibile solo da chi l'aveva costruita.

A usarla sono tre persone, ognuna per cose diverse: chi pianifica i turni e regola le pressioni, chi fa debug e calibrazione sul campo, chi cura i filtri e la fertirrigazione. Una sola interfaccia che serviva male tre lavori distinti.

Il progetto si chiama S.A.I.A. ed è cofinanziato da Unione Europea e Regione Sicilia. Oggi sul campo ci sono dieci centraline che pilotano l'impianto in modo continuo: sulla scheda gira il firmware Arduino v5, in mano alle persone c'è una webapp in React.

Sul mercato non c'era un sistema pronto con queste caratteristiche — letture di pressione in tempo reale, gestione controllata delle pompe, affidabilità in campo per mesi senza intervento. Costruito su misura per quest'azienda, ma pensato fin dall'inizio come sistema replicabile e personalizzabile per altre realtà agricole simili.

Niente di quello che c'era già è stato buttato via. Tre stazioni meteo in campo (una Ecowitt, due SenseCAP) e i diciannove sensori di umidità del suolo della rete Weenat — componenti commerciali che l'azienda aveva già acquistato — sono integrati attraverso le loro API aperte. Alimentano un consiglio irriguo che suggerisce all'operatore quando e dove irrigare.

L'app è una PWA pensata prima per il telefono: una mappa che mostra in un attimo lo stato dell'impianto, una dashboard di diagnostica per ogni centralina, uno storico per indagare un'anomalia. Tre viste per i tre lavori distinti — turni e pressioni, debug, fertirrigazione.

Oltre alle viste, la webapp porta in tasca strumenti che prima non c'erano: una chat per dialogare col sistema in linguaggio naturale, un comando vocale per dare istruzioni senza tastiera quando si è in campo con le mani sporche, suggerimenti dell'AI che osservano lo stato dell'impianto e propongono cosa fare — fino a due alla volta, non invadenti.

Il sistema è raccontato anche in un video sul canale InCampagna Sicilia (link in fondo alla pagina).

02 Superficie

Il metodo viene prima dell'IA. Una specifica chiara di cosa serve, una scelta architettonica spiegata in poche righe, poi Claude Code fa il lavoro di scrittura. Senza il metodo l'IA avrebbe prodotto un sistema bello ma fragile; senza l'IA, da solo, non sarebbe stato fattibile in tempi accettabili.

Le abitudini sono scritte nel repo, non in slide. Ogni decisione importante — perché Arduino Edge Control, perché dual publish MQTT, perché la mediana invece della media — sta in un Architectural Decision Record di poche righe; ogni sessione lascia un log. Tornare sopra al codice dopo un mese significa ritrovare esattamente il ragionamento dell'epoca.

Un esempio. L'algoritmo che legge la pressione è stato iterato tre volte sul feedback di chi lo usa in campo: prima un clone della versione storica (*«è la v4.2 problematica»*), poi un downgrade alla v3 pulita (*«è solo un downgrade, dobbiamo migliorare»*), infine la versione che è finita in produzione — mediana di ventuno campioni. L'IA propone, l'operatore reagisce, si itera.

Quando un fix veloce non funziona, si ferma tutto. La regola è semplice: dopo due tentativi falliti sullo stesso bug si smette di indovinare e si leggono per intero i datasheet, le librerie, il codice. Il tempo speso a leggere è sempre minore di quello speso a tirare a indovinare.

Controllo totale dello stack, dal server al telefono — invece di servizi managed sul backend e di un'app nativa sul frontend.

Sul backend, l'intero sistema vive su un server Hetzner gestito in casa: Docker orchestra cinque container — Mosquitto come broker MQTT, Node-RED come cervello dell'irrigazione, InfluxDB per la telemetria, Grafana per il monitoraggio, un bridge per la stazione meteo Ecowitt. L'alternativa era comprare AWS IoT Core, InfluxDB Cloud, Grafana Cloud: più costo mensile, meno controllo, meno capacità di mettere le mani su quello che succede sotto. Quella stessa capacità — leggere i log del broker, riavviare un container in dieci secondi — su un altro progetto ha permesso di trovare cinque bug strutturali in una libreria di terze parti.

Sul frontend, la webapp è una PWA — React, costruita con Vite. Per pubblicare app native vere sugli store servirebbe l'iscrizione all'Apple Developer Program (99 dollari l'anno per restare attivi) e il passaggio dal Google Play Store con account sviluppatore e review: settimane di onboarding e un costo ricorrente per servire tre utenti che vivono sul telefono ogni giorno. Una PWA si installa dalla home del telefono con un tap, si aggiorna istantaneamente senza passare da nessuno store, e in più funziona anche da desktop quando l'operatore è davanti al computer in ufficio. Capacitor resta come carta di riserva: se un giorno servirà una versione store, la stessa codebase la produce.

Il compromesso è onesto: la responsabilità delle operations — backup, sicurezza, aggiornamenti — resta in casa, e alcune API hanno limiti rispetto al nativo puro. In cambio, un sistema che si capisce fino in fondo, costi predicibili, zero dipendenze da fornitori cloud.

03 Profondità
Il dettaglio tecnico Hardware, scelte di architettura, compromessi — per chi legge il codice

Hardware. Ogni centralina è un Arduino Edge Control con MCU nRF52840 e modulo M5Stack SIM7080G in Cat-M. La pressione idraulica si legge da sei canali analogici tramite un I/O expander TCA6424A; le elettrovalvole e le pompe si pilotano dalle uscite digitali del backplane Edge Control.

Firmware in nove librerie modulari. Il firmware v5 è scomposto in librerie con singola responsabilità: parser degli URC del modem, log persistente su scheda SD, recovery del modem a più stadi, diagnostica radio (RSSI, banda, eNB ID), sensore di pressione, configurazione a runtime via comandi MQTT, gestione dei comandi elettrovalvole, safety monitor (limiti idraulici e tempistiche di sicurezza), telemetria. Ogni libreria ha test in laboratorio e un changelog interno; il main si limita a orchestrare il polling delle librerie.

L'algoritmo della pressione. Un batch di sei canali si legge in 376 millisecondi — la versione storica impiegava 3,25 secondi (8,6× più veloce). Ogni canale produce ventuno campioni con un settling di 500 microsecondi fra una lettura e l'altra; sui campioni si calcola la mediana via insertion sort. La mediana (invece della media) blocca gli spike di rumore tipici dell'elettrovalvola in apertura, senza filtri software complessi. Stack-only 42 byte: niente heap, niente frammentazione.

Affidabilità in campo. La connessione MQTT è sorvegliata da cinque sentinelle indipendenti — verifica TCP raw via comando AT, ack di heartbeat applicativo, cambio IP, stato del client PubSubClient, keepalive. Sotto, una recovery del modem a più stadi che parte dal soft reset e arriva al power cycle hardware solo se serve. I comandi alle elettrovalvole hanno tre livelli di ACK: ricezione, esecuzione, conferma di stato. È robustezza pensata per chi non può andare a riavviare la centralina a mano.

Frontend. La webapp è React 19 + Vite, gestita per store (uno per dominio: settori, turni, pressioni, AI, connessione, storico, soil). La chat e il `VoiceFab` condividono lo stesso `useVoiceInput` basato su Web Speech API. I suggerimenti dell'AI partono da un polling a sessanta secondi su `/api/ai/suggestions` che riceve il contesto attuale (FSM, settori attivi, pompe in marcia) e ritorna massimo due suggerimenti, mostrati come toast non bloccanti.

La pipeline dati esterna. Le tre stazioni meteo parlano lingue diverse: la Ecowitt arriva via bridge UDP nel container `ecowitt2mqtt`, le due SenseCAP via NB-IoT alla piattaforma The Things Industries, da lì in MQTT; i diciannove sensori Weenat via API REST con cache lato Node-RED. Tutto converge sul broker Mosquitto, viene normalizzato da Node-RED, finisce in InfluxDB per lo storico (sei measurement nel bucket `madonnina`) e in Grafana per le dashboard di monitoraggio. La webapp legge dal WebSocket per il live e dalle API REST per lo storico.

I repository del progetto sono privati: non sono linkabili.

Dieci centraline lavorano in campo ventiquattr'ore su ventiquattro dal 2024. La dashboard operatore, che prima era costruita su una Node-RED legacy da oltre duemilatrecento nodi, oggi è una webapp React per il telefono; Node-RED resta in produzione come cervello del backend.

L'operatore gestisce turni di irrigazione, pressioni e settori dal telefono. Le tre persone che usano il sistema lo fanno ognuna dalla propria vista, senza pestarsi i piedi.

Il sistema continua a evolversi — sensori aggiunti, nuove versioni del firmware, nuove funzioni della webapp. È un sistema in esercizio.

← Tutti i progetti