Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

11
voti

Web Stazione Meteo con Arduino [6] : Il Sito Web

Bando alle ciance e iniziamo a parlare della parte puramente software del mio progetto. Come avevo detto nella prima puntata, volevo creare un sito che permettesse di raccogliere i dati dei sensori e poterli poi visualizzare assieme a vari grafici e simili, quindi un cosiddetto sito dinamico, per far ciò dobbiamo usare un linguaggio di scripting lato server e un gestore di database, per non parlare di un WebServer che è ovviamente necessario.

Indice

I linguaggi

In ambito WEB per la gestione dei siti dinamici ci affidiamo solitamente a delle squadre di programmi, che ormai sono diventati la norma:

  • Apache – MySQL – PHP (Piattaforma LAMP)
  • IIS – MSSQL – ASP

La prima è composta da programmi OpenSource, la seconda è la suite di Web Developing di Microsoft.

<premessa> Non sono una di quelle persone fissate con l’open-source che vede in ogni prodotto Microsoft il Male, ansi sono un assiduo programmatore Microsoft.</premessa>

La mia scelta è ricaduta su la prima terna di programmi, per questi motivi:

  1. Sono Open-Source e quindi gratuiti.
  2. Volendo usare come servizio di Hosting Altervista, questa piattaforma supporta solo PHP e MySQL.
  3. Conosco meglio il PHP che l’ASP.

Come avevo accennato in un puntata precedente, un’ ottima piattaforma per lo sviluppo di siti dinamici con questa accoppiata di programmi è EasyPHP, lo consiglio perché installandolo abbiamo subito disponibili tutti e tre i programmi correttamente configurati e quindi ci possiamo dedicare subito allo sviluppo del nostro sito.

Il PHP

Il PHP (Hypertext Preprocessor) è un linguaggio di scripting lato server che, come l’ASP, restituisce a chi fa richiesta di un pagina PHP, a seguito di una elaborazione lato server, un codice HTML. Il PHP riprende per molti versi la sintassi del C e alcuni elementi di Perl, è un linguaggio Debolmente Tipizzato, cioè le variabili presenti nel programma possono assumere varie forme, senza necessità di dichiarazione del tipo. Come abbiamo visto precedentemente, possiamo passare alle pagine PHP dei parametri tramite GET, POST, etc. Per questo sono implementati degli array Superglobali (cioè comuni non solo a tutta una pagina, ma ad un’intera sessione o comunicazione) che sono : • $_GET : viene passato tramite la stringa che compare nella barra dell'indirizzo del browser. • $_POST : viene passato in background • $_SESSION : rimane persistente durante la sessione Peculiarità degli array in PHP, è l’ammissione indice non solo di un numero, ma anche di un chiave formata da una stringa. Altra nota sul PHP che ci servirà per comprendere i vari listati, le variabili sono individuate dal carattere chiave $.

SQL

L’SQL (Structured Query Language) è un linguaggio di interrogazione per database progettato per leggere, modificare e gestire dati memorizzati in un sistema di gestione di basi di dati basato sul modello relazionale (RDBMS), per creare e modificare schemi di database, per creare e gestire strumenti di controllo ed accesso ai dati. SQL è un linguaggio per interrogare e gestire basi di dati mediante l'utilizzo di costrutti di programmazione denominati Query. Le query più utilizzate, tralasciando quelle necessarie alla creazione del database e della tabelle sono:

  • SELECT (selezione dei dati dal database)
  • INSERT (inserzione dei dati nel database)
  • UPDATE (modifica dei dati del database)
  • DELETE (eliminazione dei dati dal database)

Per la loro sintassi e una migliore comprensione rimando alla guida che ho inserito nella Sitografia.

Il MySQL

Il MySQL è un RDBMS (Relational DataBase Management System) composto da un client testuale e un server entrambi disponibili per le piattaforme Unix, Windows e GNU/Linux. Da diverso tempo riesce a interpretare il linguaggio SQL per l’interazione con i database relazionali e risulta una componente fondamentale della cosiddetta piattaforma LAMP che andrò a usare per il mio progetto. (spunti tratti da Wikipedia)

I Compiti del Sito

Come dicevamo il mio sito dovrà andare a gestire prevalentemente due cose :

  • Raccolta Dati
  • Visualizzazione Dati

Andiamo con ordine e vediamole entrambe.

Raccolta Dati

Analiziamo la struttura del database, il passaggio dei parametri e il codice della pagina che farà il lavoro.

Il database

I dati raccolti saranno immagazzinati in un database, quindi passiamo subito a spiegarne la struttura e le motivazioni del progetto.

Struttura database

Struttura database

Come vediamo il database è composto essenzialmente da 3 tabelle:

  • Utente : Contiene i dati di ogni utente del sito che contribuisce a fornire dati dei propri sensori
  • Sensore : Per ogni utente ci sono n sensori, che sono caratterizzati da un loro nome, una grandezza misurata e un range entro il quale il sensore opera (necessario per i limiti dei grafici).
  • Lettura : Per ogni sensore abbiamo n letture, caratterizzate dal dato letto e dalla data e ora in cui sono state effettuate (inserita in automatico dal database).

Il linguaggio SQL permetterebbe anche di creare chiavi esterne con cui la connessione logica delle tabelle verrebbe implementata in automatico con aggiornamenti e cancellazioni in cascata, però altervista ha disabilitato il motore di database con la quale sono implementabili (InnoDB), quindi farò senza, gestendole in modo manuale. Le relazioni tra le tabelle sono di tipo 1:n ramificate, cioè allontanandoci dalla tabella utente (radice) i rami dell’albero del database aumentano.

Il codice PHP

Per passare i dati al sito dobbiamo usare quegli array superglobali di cui parlavamo prima. Per adesso e per semplicità ci affidiamo all’array $_GET, che ci permette di riempirlo aggiungendo in coda all’URL, una serie di parametri, vediamo come riempirlo. In coda all’URL inseriamo:

  1. il carattere ‘?
  2. il nome della chiave da dare al campo dell’array
  3. il carattere ‘=’,
  4. il valore del campo dell’array (non dobbiamo specificare se si tratta di numeri o caratteri dato che PHP è debolmente tipizzato)

Per aggiungere un altro campo inseriamo il carattere ‘&’ e ricominciamo dal punto 2.

Es. www.miosito.it/raccolta_dati.php?id=1&val=3.6

Nota : attualmente ho abbandonato il passaggio dei valori con GET, spostandomi su POST, per avere una protezione migliore dei dati, dato che vengono passati “di nascosto”. In un futuro post farò un elenco delle migliorie apportate al progetto finale, ma adesso ho voluto mantenere il vecchio metodo per poterlo far funzionare con il programma dei passati post.

Adesso che abbiamo riempito l’array GET con l’id del sensore da aggiornare e il valore della lettura, non ci resta altro che scrivere la pagina PHP con la query SQL per inserire questo dato nel database. Da notare che impostando la trasmissione dei dati in questo modo, chiunque che digiti nella barra dell’indirizzo del browser un URL del genere potrebbe inserire una nuova lettura ad un sensore, quindi nella versione definitiva passerò alla pagina anche l’username e la password dell’utente a cui è associato il sensore da aggiornare per fare una verifica. Per prima cosa dobbiamo connetterci al database, per far ciò abbiamo bisogno di 4 informazioni, che ci vengono fornite da Altervista una volta attivato sul nostro dominio un servizio di database, e sono:

  • Nome database
  • Username
  • Password
  • Host

Inseriamo queste impostazioni in cima ad ogni pagina PHP assegnandole ad una variabile.

$host="localhost"; // Host name
$username="my_username"; // Mysql username
$password="my_password"; // Mysql password
$db_name="db_name"; // Database name

Dopo di che inseriamo il codice necessario per connetterci al database con queste credenziali.

mysql_connect("$host", "$username", "$password") or die ("cannot connect");
mysql_select_db("$db_name") or die ("cannot select DB");

la clausola “or die” in PHP serve per il controllo degli errori, in quanto se la funzione non va a buon fine termina l’esecuzione di tutta la pagina e stampa la frase inserita tra parentesi. Dopo essersi connessi possiamo effettuare le query sul database, ecco come fare:

$sql="SELECT * FROM utente";
$result = mysql_query($sql);

Nella prima riga componiamo la stringa contenente la query da eseguire e la memoriziamo in $sql. Nella seconda riga eseguiamo la query inserendo in $result i dati forniti dalla sua esecuzione. Nel caso di una query di SELECT in result troverà posto una tabella che conterrà tutti i dati selezionati, che potranno essere letti oppure contati. Per leggere :

while($array = mysql_fetch_array($result))
{ echo ($array[‘username’]);}

nell’array $array ad ogni ciclo del while sarà presente una riga della tabella fornita dalla query, ogni campo della riga attuale è recuperabile dall’array usando come indice il nome del campo della tabella che vogliamo. L’esempio stampa a video tutti gli username del database. Per contare:

$count=mysql_num_rows($result);

Dopo questo comando, in $count, troviamo il numero di righe della tabella restituita dalla query. Nel caso in cui la query che andiamo a fare non sia una select, ci interessa solamente se questa è andata a buon fine. Controllo esecuzione :

 >$sql="INSERT INTO lettura SET idsensore = 1 , lettura = 5.2";
if(mysql_query($sql))
echo("ok");
else
	echo(“errore”);

A seguito di questo codice verrà stampato a schermo OK, se la query è stata eseguita, ERRORE altrimenti.

La pagina di ricezione

Nella pagina definitiva passiamo tramite URL, l’username, la password, l’id del sensore e la sua lettura.

<?php
		
	$mypassword=$_GET['password'];
	$myusername=$_GET['username'];
	
	$host="localhost"; // Host name
        $username="my_username"; // Mysql username
        $password="my_password"; // Mysql password
        $db_name="db_name"; // Database name
	// Connect to server and select databse.
	mysql_connect("$host", "$username", "$password")or die("cannot connect");
	mysql_select_db("$db_name")or die("cannot select DB");
	
	$sql="SELECT * FROM utente WHERE username = '$myusername' AND password='$mypassword'";//controllo che l’utente esista
	$result = mysql_query($sql);
	$count=mysql_num_rows($result);
	
	if($count==1)
	{
		$array=mysql_fetch_array($result);
		$id_utente=$array['id_utente'];//recupero l’id_utente
		//inserire contenuto pagina
		if(isset($_GET['sensore']))//se la variabile è stata impostata
		{
			$id_sensore = $_GET['sensore'];
			if(isset($_GET['dato']) && is_numeric($_GET['dato']))
			{
				$valore = $_GET['dato'];
				$sql="SELECT * FROM sensore WHERE id_utente = '$id_utente' AND id_sensore = '$id_sensore'";//controllo che esista il sensore
				$result = mysql_query($sql);
				$count=mysql_num_rows($result);
				
				if($count==1)
				{			
					$sql1="INSERT INTO lettura SET id_sensore = '$id_sensore', lettura='$valore'";//inserisco il dato
					if(mysql_query($sql1))
					{
						echo("ok");
					}
					else
						{
							echo ('errore db');
						}
				}
				else
					echo("codice sensore errato");
			}
			else
				echo("formato valore non corretto");
		}
		else
			echo("codice sensore mancante");
	}
	else
	{
		echo "<h1>Area riservata - accesso negato</h1>";
		die;
	}
	mysql_close();//chiudo la connessione
	ob_end_flush();
?>

Visualizzazione Dati

Adesso la parte di facciata del sito, lascio a voi creare una homepage e delle pagina carine (a me non è mai riuscito, sono per le cose pratiche), parliamo della visualizzazione dei dati. Essendo una mole considerevole di informazioni, la cosa migliore è raggrupparle in un grafico per poterle esaminare nel loro insieme. Adesso quindi vi farò vedere come impostare una pagina contenente un grafico e una tabella con i dati che compongono il grafico. Per realizzare il grafico ho utilizzato un javascript chiamato dygraphs (link nella sitografia) che contiene molte funzioni per zoomare, annotare, etc. Basta fornirgli i dati e le impostazioni e al resto pensa lui. Ovviamente dobbiamo inserire nella directory del sito il file contenente lo script.

<?php
	ob_start();
	$host="localhost"; // Host name
	$username="myUsername"; // Mysql username
	$password="myPassword"; // Mysql password
	$db_name="dbName"; // Database name
	// Connect to server and select databse.
	mysql_connect("$host", "$username", "$password")or die("cannot connect");
	mysql_select_db("$db_name")or die("cannot select DB");
	if(isset($_GET['sensore']))
	{
		$id_sensore = $_GET['sensore'];

		$sql="SELECT nome,grandezza,valoreMax,valoreMin FROM sensore WHERE id_sensore='$id_sensore'";
		$result = mysql_query($sql);
		$count=mysql_num_rows($result);
		$array=mysql_fetch_array($result);

		$nome = $array['nome'];
		$grandezza = $array['grandezza'];
		$ValMax = $array['valoreMax'];
		$ValMin = $array['valoreMin'];
		$giorni_grafico = $_GET['giorni'];//giorni dei dati da visualizzare

		if($count==1)
		{?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
			<title>Dati + Grafico</title>
			<script type="text/javascript"  src="dygraph-combined.js"></script>	
		</head>
		 <body style="font-family: Arial;border: 0 none;">
			<a href="http://tempduino.altervista.org/"><h1>TempDuino</h1></a>
                      <hr>
			<div id="graphdiv" style="width:1000px; height:500px;">></div>
          		<script type="text/javascript">
				g = new Dygraph(						
					// containing div
					document.getElementById("graphdiv"),"Date,<?php echo($nome)?>\n"
					<?php
						$tabella = "";//conterra il codice per la tabella
						$sql="SELECT TRUNCATE(lettura,2) as lettura, YEAR(data) as anno, MONTH(data) as mese, DAY(data) as giorno, HOUR(data) as ora, MINUTE(data) as minuti, data FROM lettura WHERE id_sensore = '$id_sensore' ORDER BY data DESC";
						$result = mysql_query($sql);
						while($array=mysql_fetch_array($result))
						{
							$tabella = $tabella."<td>".$array['data']."<td>".$array['lettura']."</tr>\n";
							echo(" + ");
							echo "\"".$array['anno']."-".$array['mese']."-".$array['giorno']." ".$array['ora'].":".$array['minuti'].",".$array['lettura']."\\n\"";
						} ?>
	
					,{valueRange: [<?php echo($ValMin);?>,<?php echo($ValMax);?>],
                  			 title: "<?php echo($nome." (".$grandezza.")");?>"
                			});
			</script>
                      <hr>
	            <p>
	              <?php
			echo("letture di ".$giorni_grafico." giorni del sensore : ");
			echo($nome." (".$grandezza.")");?>
	            <br>
                	<table border="1">
	        	<tr><td>data<td >lettura</tr>
				<?php
                		echo $tabella;
				echo("</table>");
			}
			else
				echo("codice sensore errato");
		}
		else
			echo("codice sensore mancante");
	mysql_close();
	ob_end_flush();
?>
  </body>
</html>

Possiamo notare che la pagina è composta da parti in PHP e altre in semplice HTML, questa cosa è utilissima, se non consigliata quando vogliamo inserire degli elementi statici nella pagina e soprattutto quando ne vogliamo definire la struttura. Per far ciò basta inserire i tag di inizio e fine del linguaggio PHP (<?php e ?>) per racchiudere il codice che il server deve interpretare come script. La parte interessante del codice si trova circa alla metà dove facciamo un SELECT di tutti dati di un sensore (il cui id ci è stato passato tramite $_GET) estraendo singolarmente anno, mese, giorno, ora e minuti dalla data per poter scrivere i dati così come vuole lo script, cioè: YYYY-MM-DD hh:mm, assieme al dato della lettura. Successivamente nel ciclo While, vado a comporre i dati per il grafico stampandoli sulla pagina nel giusto formato e riempiendo una variabile $tabella, con il codice per comporre una tabella che useremo poche righe dopo. Per la sintassi estesa del grafico rimando al sito dello sviluppatore.

Il Sito Finale

TempDuino

TempDuino

Questo è il sito che sto sviluppando assieme a un mio amico, è in continua evoluzione, quindi se incontrate della pagine temporaneamente non funzionanti è colpa nostra, oppure se trovate dei bug segnalateceli così da risolverli. Altra richiesta, spero che non vada contro il regolamento, se visitate il sito e avete un filtro per la pubblicità, vi pregherei di disattivarlo sul mio sito perchè ho inserito UN SOLO banner nella homepage per cercare di ottenere qualche altercents (la valuta virtuale di Altervista) per mantenere un database con prestazioni leggermente migliori rispetto al minimo. Grazie!

tempduino.altervista.org

Conclusioni

Siamo arrivati a destinazione, il progetto è completo, spero che vi sia piaciuto, ma soprattuto spero sia stata un’occasione per crescere e per imparare cose nuove, per me è stata un’esperienza magnifica che mi ha permesso di ampliare le mie conoscenze e di condividerle con gli altri.

Vogli ringraziare tutti gli utenti che mi hanno seguito e che si sono fatti sentire tramite commenti o tramite messaggi e con il quale mi sono potuto confrontare.

Il ringraziamento più grande va alla community di ElectroYou che mi ha permesso di imbarcarmi in questo progetto e che mi ha sostenuto.

Ultimo, ma non meno importante, voglio nominare gohan e angus che mi hanno dato delle dritte non da poco sul metodo POST per la comunicazione http, di cui vi parlerò in futuro.

Questo non è un addio, ci mancherebbe, è un arrivederci, perché ho intenzione di pubblicare dei brevi post sulle migliorie che ho apportato al sistema e sulla community di sensori che potrebbe nascere (ho un amico che si è da poco imbarcato nel progetto, quindi il sito è in evoluzione).

Quindi CIAO a tutti!!!

Sitografia

PHP

Guida PHP

MySQL

Guida MySQL

Grafico Javascript Dygraphs

Link agli articoli del progetto

Web Stazione Meteo con Arduino [1] - L'idea

Web Stazione Meteo con Arduino [2] - La Rilevazione dei Dati

Web Stazione Meteo con Arduino [3] - Il Primo Circuito di Prova

Web Stazione Meteo con Arduino [4] - Il circuito definitivo e la comunicazione http

Web Stazione Meteo con Arduino [5] - Appendice 1 : Le Reti spiegate a mia Nonna

Web Stazione Meteo con Arduino [7] : Bug Fixing

22

Commenti e note

Inserisci un commento

di ,

Ciao Davide, Il codice non lo copio ed è proprio questo: voglio capirlo in quanto mi serve come base per un progetto domotico che voglio ampliare con sensori PIR e altro. Non sono un programmatore (ho studiato Pascal e Visual Basic ma ... cca. 20 anni fa) e per questo magari faccio domande banali. I dati li stai inviado al server con: void InvioHttpSeriale (String server, int porta, String pagina, String username, String password, int id[], float dati[], int len) Mi servirebbe solo il pezzo di codice dove valorizzi id[], dati[] e len. (tipo: id[]= ... , dati[]= ....) prima di chiamare InvioHttpSeriale. Posso inviarti il mio email in PM. Grazi

Rispondi

di ,

La variabile len è il numero di sensori, se usi il dht22, sono 2, uno per temperatura e uno per umidità, se ne hai di più o di meno basta che vari quel valore. Non copiare solamente, cerca di capire cosa fa' il codice così riesci a farlo funzionare e impari anche qualcosa di nuovo.

Rispondi

di ,

Ciao Davide, Ci ho provato a fare le modifiche nello sketch ma non sono riuscito. Sarebbe possibile avere l'ultima versione dello sketch (quella con l'invio della stringa con i valori dei sensori)? Grazie

Rispondi

di ,

Nel vecchio sketch (GET) fai: InvioHttp(serverName,serverPort,pageName,username,password,id_sensore_umid,avg_umid); Mi manca la chiamata InvioHTTP nel nuovo sketch con il metodo POST. (pratticamente non so come passi len ... come lo calcoli nello sketch).

Rispondi

di ,

Se vedi bene ho implementato l'invio multiplo di letture, passando un vettore delle letture a invioHTTP, la variabile len è semplicemente la lunghezza del lettore, infatti se vedi la uso nel ciclo for.

Rispondi

di ,

Se vedi bene ho implementato l'invio multiplo di letture, passando un vettore delle letture a invioHTTP, la variabile ken è semplicemente la lunghezza del lettore, infatti se vedi la uso nel ciclo for.

Rispondi

di ,

Ciao Davide! Inanzitutto, grazie per la risposta. Il codice "Bug fix" l'ho visto solo che nella funzione InvioHTTP con il metodo POST c'è un nuovo parametro "len" che non so cosa sia. Per questo motivo avevo chiesto il nuovo sketch.

Rispondi

di ,

Per il codice processing trovi tutto nell'ultimo post, il numero [7], mi sono accorto adesso che non l'ho inserito nell'indice, ma se vai nel mio blog lo trovi. Per il codice PHP, le modifiche sono poche, basta che sostituisci il vettore GET con POST.

Rispondi

di ,

Ciao Davide! Trovo molto interessante il tuo progetto. Volevo chiederti se fosse possibile aggiornare il codice con le ultime modifiche che hai fatto (utilizzo del metodo POST invece di GET). Grazie

Rispondi

di ,

Per adesso rilevo i dati solo a casa mia. Se vai sul sito e clicchi sulle coordinate geografiche ti apre google maps con la posizione del sensore. Grazie mille console6!

Rispondi

di ,

Il sito è ottimo, veramente complimenti! Ma non capisco in quale località vengono rilevati questi dati? Forse devi ancora implementare altre parti del progetto? In Italia c'è bisogno di gente come te, buon lavoro!

Rispondi

di ,

Ci Vorrà ancora del tempo perché lo facciamo a tempo perso ed adesso con gli esami ne rimane poco....xD

Rispondi

di ,

Bravissimo! Ho visitato il sito aspetto che sia ultimato!

Rispondi

di ,

Quando mi metto in testa di fare una cosa non mi ferma nessuno!!! xD Grazie Mille Paolino!!!

Rispondi

di ,

Beh, direi che ci sei riuscito! Bravo!

Rispondi

di ,

Grazie mille! Cerco di risponderti: 1)Nel progetto finale sto usando il $_POST invece che il $_GET quindi risolvo parzialmente il fatto della password in chiaro. La cosa migliore sarebbe inviare l'MD5 o simili della password. 2)Intendi per gli eventuali attachi SQL injection? Se sì, solitamente uso queste due funzioni per filtrare eventuali attacchi (stripslashes() e mysql_real_escape_string()). In un prossimo articolo sulle varie migliorie apportate al progetto parlerò anche di questo. Per adesso volevo dare uno strumento basilare per le prime interazioni tra un sito e Arduino.

Rispondi

di ,

Complimenti per il progetto! Ma il codice è un po' da rivedere... Due cose che si vedono subito subito: 1) la password in chiaro via GET... 2) la variabili via GET usate brutalmente nella query SQL...

Rispondi

di ,

Ci avevamo pensato, è nella lista delle cose da fare, assieme a una homepage più decente e una migliore gestione dei dati con la possibilità di vedere le caratteristiche di ogni sensore. Per adesso ho voluto dare il necessario affinché ognuno possa sviluppare qualcosa di simile. Grazie per i complimenti.

Rispondi

di ,

Fantastico! Ancora meglio sarebbe se per ogni utente si potesse visualizzare una posizione (città, provincia ecc.) scritta al momento dell'iscrizione...

Rispondi

di ,

Grazie a voi per i complimenti!!

Rispondi

di ,

Bravissimo!

Rispondi

di ,

Grazie per il nuovo aggiornamento , complimenti bel lavoro =) Younes.

Rispondi

Inserisci un commento

Per inserire commenti è necessario iscriversi ad ElectroYou. Se sei già iscritto, effettua il login.