Presentazione di ThermoWeb - Domotica IP - c/php/js/sql

Complimenti bella cosa davvero. Però perché il tuo progetto possa restare qui devi fornire tutti i sorgenti e gli schemi del lavoro nonché la documentazione, altrimenti va spostato in "Software".

leo72: Complimenti bella cosa davvero. Però perché il tuo progetto possa restare qui devi fornire tutti i sorgenti e gli schemi del lavoro nonché la documentazione, altrimenti va spostato in "Software".

Concordo con Leo. Andrea, mi associo ai complimenti ma ci siamo sempre dati la regola che questa sezione va usata come "condivisione" dei propri lavori, in modo che tutti possano usufruirne, così com'è tu stai facendo solo "vetrina". Comunque ti basta riaprire il Topic in Software e poi eliminare questo con il pulsante posto in basso a sinistra nella pagina "remove topic". Grazie. :)

Ho aperto la discussione qui perchè credevo che era per i progetti funzionanti e non per richieste :blush:

Questo è il codice per arduino, non pensavo di pubblicarlo e quindi non è il massimo da leggere…

#include <Wire.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EEPROM.h>

#define pinRele 14
#define defMode 1
#define defTMin 15
#define defTMax 25
#define defIsteresi 2
#define defCrono 1;

byte time[7], crono[168], mode, tMin, tMax, tSet, isteresi, info;
byte mac = { 0x90, 0xA2, 0xDA, 0x00, 0xFF, 0x41 };
byte ip = { 192, 168, 1, 232 };
byte gateway = { 192, 168, 1, 254 };
byte subnet = { 255, 255, 255, 0 };
byte id = { 1, 2, 3, 4 };
float temp;

EthernetServer server(80);

void setup()
{
Ethernet.begin(mac, ip, gateway, subnet);
server.begin();

Wire.begin();

// temperatura

Wire.beginTransmission(0x48);
Wire.write(0xAC);
Wire.write(0x00);
Wire.endTransmission();

delay(100);

Wire.beginTransmission(0x48);
Wire.write(0xEE);
Wire.endTransmission();

// fine temperatura

pinMode (pinRele, OUTPUT);

mode = EEPROM.read(0);

if (mode < 0 || mode > 2)
{
mode = defMode;
EEPROM.write(0, mode);
}

tMin = EEPROM.read(1);

if (tMin < 10 || tMin > 20)
{
tMin = defTMin;
EEPROM.write(1, tMin);
}

tMax = EEPROM.read(2);

if (tMax < 20 || tMax > 30)
{
tMax = defTMax;
EEPROM.write(2, tMax);
}

tSet = EEPROM.read(3);

if (tSet < tMin || tSet > tMax)
{
tSet = tMin;
EEPROM.write(3, tSet);
}

isteresi = EEPROM.read(4);

if (isteresi < 0 || isteresi > 3)
{
isteresi = defIsteresi;
EEPROM.write(4, isteresi);
}

for (byte x1 = 0; x1 < 168; x1++)
{
crono[x1] = EEPROM.read(x1 + 5);

if (crono[x1] < 0 || crono[x1] > 1)
{
crono[x1] = defCrono;
EEPROM.write(x1 + 5, crono[x1]);
}
}
}

void loop()
{
check();

EthernetClient client = server.available();

if (client)
{
boolean currentLineIsBlank = true;
byte get[18] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int x1 = 0;

while (client.connected())
{

if (client.available())
{
char c = client.read();

if (x1 > 5 && x1 < 24)
{
get[x1 - 6] = c & 15;
}

x1++;

if (c == ‘\n’ && currentLineIsBlank)
{

if (get[0] == id[0] && get[1] == id[1] && get[2] == id[2] && get[3] == id[3])
{
client.println(“HTTP/1.1 200 OK”);
client.println(“Content-Type: text/html”);
client.println(“Connnection: close”);
client.println();

switch (get[4])
{
case 3 : if (get[5] == 1)
{
x1 = get[6] * 10 + get[7];

if (x1 >= 10 && x1 <= 20)
{
tMin = x1;
EEPROM.write(1, tMin);
}
}

if (get[8] == 1)
{
x1 = get[9] * 10 + get[10];

if (x1 >= 20 && x1 <= 30)
{
tMax = x1;
EEPROM.write(2, tMax);
}
}

if (get[11] == 1)
{

if (get[12] >= 0 && get[12] <= 3)
{
isteresi = get[12];
EEPROM.write(4, isteresi);
}
}

case 4 : client.print("{“id”:");
client.print(id[0]);
client.print(id[1]);
client.print(id[2]);
client.print(id[3]);
client.print(",“tMin”:");
client.print(tMin);
client.print(",“tMax”:");
client.print(tMax);
client.print(",“isteresi”:");
client.print(isteresi);
client.println("}");
break;

case 5 : time[0] = get[9] * 16 + get[10];
time[1] = get[7] * 16 + get[8];
time[2] = get[5] * 16 + get[6];
time[3] = get[11];
time[4] = get[12] * 16 + get[13];
time[5] = get[14] * 16 + get[15];
time[6] = get[16] * 16 + get[17];

seconda parte ( tagliato in due per pubblicarlo )

Wire.beginTransmission(0x68);

Wire.write(0x00);
for (byte x2 = 0; x2 < 7; x2++)
{
Wire.write(time[x2]);
}
Wire.endTransmission();

case 6 : getTime();
client.print("{“ore”:");
client.print(time[2], HEX);
client.print(",“minuti”:");
client.print(time[1], HEX);
client.print(",“secondi”:");
client.print(time[0], HEX);
client.print(",“gSettimana”:");
client.print(time[3], HEX);
client.print(",“gMese”:");
client.print(time[4], HEX);
client.print(",“mese”:");
client.print(time[5], HEX);
client.print(",“anno”:");
client.print(time[6], HEX);
client.println("}");
break;

case 7 : if (get[8] >= 0 && get[8] <= 1)
{
x1 = get[5] * 24 + (get[6] * 10 + get[7]);
crono[x1] = get[8];
EEPROM.write(x1 + 5, crono[x1]);
}

case 8 : client.print("[");
for (byte x2 = 0; x2 < 167; x2++)
{
client.print(crono[x2]);
client.print(",");
}
client.print(crono[167]);
client.println("]");
break;

case 9 : if (get[5] == 1)
{
if (get[6] >= 0 && get[6] <= 2)
{
mode = get[6];
EEPROM.write(0, mode);
}
}

if (get[7] == 1)
{
x1 = get[8] * 10 + get[9];

if (x1 >= tMin && x1 <= tMax)
{
tSet = x1;
EEPROM.write(3, tSet);
}
}

default : check();

client.print("{“temp”:");
client.print(temp);
client.print(",“tSet”:");
client.print(tSet);
client.print(",“tMin”:");
client.print(tMin);
client.print(",“tMax”:");
client.print(tMax);
client.print(",“mode”:");
client.print(mode);
client.print(",“info”:");
client.print(info);
client.print("}");
}
}

break;
}

if (c == ‘\n’)
{
currentLineIsBlank = true;
}

else if (c != ‘\r’)
{
currentLineIsBlank = false;
}
}
}
delay(1);
client.stop();
}
}

void getTemp()
{
byte msByte;
byte lsByte;

Wire.beginTransmission(0x48);
Wire.write(0xAA);
Wire.endTransmission();

Wire.requestFrom(0x48, 2);
if (Wire.available())
{
lsByte = Wire.read();
}
if (Wire.available())
{
msByte = Wire.read();
}
temp = float(lsByte) + float(msByte >> 3) * 0.03125;
}

void getTime()
{

Wire.beginTransmission(0x68);
Wire.write(0x00);
Wire.endTransmission();

Wire.requestFrom(0x68, 7);

for (byte x1 = 0; x1 < 7; x1++)
{
if (Wire.available())
{
time[x1] = Wire.read();
}
}
}

void check()
{
getTemp();

switch(mode)
{
case 0 : digitalWrite(pinRele, LOW);
info = 0;
break;

case 1 : if (temp < float(tSet))
{
digitalWrite(pinRele, HIGH);
info = 1;
}

else if (temp >= float(tSet + isteresi))
{
digitalWrite(pinRele, LOW);
info = 0;
}

break;

case 2 : getTime();
byte x1 = (time[3] - 1) * 24 + ((time[2] >> 4) * 10) + (time[2] & 15);

if (crono[x1] != 0 && temp < float(tSet))
{
digitalWrite(pinRele, HIGH);
info = 1;
}

else if (crono[x1] == 0 || temp >= float(tSet + isteresi))
{
digitalWrite(pinRele, LOW);
info = 0;
}
}
}

Ci aggiungo anche la pagina in .php che contiene la parte ajax per la visualizzazione dinamica dei parametri:

<?php

	session_start();
	
	if (!isset($_SESSION['id'])) {
		
		header('location:session_expired.php');
		exit;
		
	}
	
	else

		$userId = $_SESSION['id'];

	$dbHostname = "";
	$dbUsername = "";
	$dbPassword = "";
	$dbDatabase = "";
	
	$con = mysql_connect($dbHostname, $dbUsername, $dbPassword);
	
	if (!$con)
	
		die("Unable to connect to MySQL: " . mysql_error());
		
	mysql_select_db($dbDatabase, $con) or die("Unable to select database: " . mysql_error());
	
	$sql = "SELECT host.addr, host.proto, host.rqst, host.desc FROM host, rela WHERE rela.userId = " . $userId . " AND rela.hostId = host.id";
	
	$result = mysql_query($sql);
	
	if (!$result)
	
		die("Database access failed: " . mysql_error());
		
	$numRows = mysql_num_rows($result);
	
	mysql_free_result($result);
	
	if (empty($_GET['place']))
	
		$place = 0;
		
	else
	
		$place = $_GET['place'];
		
	$sql = "SELECT host.id, host.addr, host.proto, host.rqst, host.desc FROM host, rela WHERE rela.userId = " . $userId . " AND rela.hostId = host.id LIMIT " . $place . ", 1";
		
	$result = mysql_query($sql);
	
	if (!$result)
	
		die("Database access failed: " . mysql_error());
		
	$obj = mysql_fetch_object($result);
	
	mysql_free_result($result);
	
	mysql_close($con);

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<meta name="viewport" content="user-scalable=no, width=device-width, minimum-scale=1.0, maximum-scale=1.0" />
	<title>ThermoWeb 1.0</title>
	<link href="css/default.css" rel="stylesheet" type="text/css" />
	<script type="text/javascript">
	
		var url = "get.php?addr=<?php echo $obj->addr; ?>&proto=<?php echo $obj->proto; ?>&rqst=<?php echo $obj->rqst; ?>";
		var set;
		
		function ajaxRequest() {

			var xmlhttp = new XMLHttpRequest();

			xmlhttp.onreadystatechange = function() {
				
				if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {

					var json=eval("("+xmlhttp.responseText+")");

					document.getElementById("temp").innerHTML = Math.round(json.temp * 10) / 10 + "&deg;C";
					document.getElementById("tSet").innerHTML = json.tSet;

					switch (json.mode) {

						case 0: document.getElementById("offOff").style.visibility = "hidden";
								document.getElementById("onOff").style.visibility = "visible";
								document.getElementById("autoOff").style.visibility = "visible"; break;
								
						case 1: document.getElementById("offOff").style.visibility = "visible";
								document.getElementById("onOff").style.visibility = "hidden";
								document.getElementById("autoOff").style.visibility = "visible"; break;
								
						case 2: document.getElementById("offOff").style.visibility = "visible";
								document.getElementById("onOff").style.visibility = "visible";
								document.getElementById("autoOff").style.visibility = "hidden";

					}

					switch (json.info) {

						case 0: document.getElementById("info").innerHTML = "St-By"; break;

						case 1: document.getElementById("info").innerHTML = "Run";

					}

					set = json.tSet;

					if (set <= json.tMin) {
						
						document.getElementById("mOn").style.visibility = "hidden";

					}
			
					else {
					
						document.getElementById("mOn").style.visibility = "visible";
					
					}
			
					if (set >= json.tMax) {

						document.getElementById("pOn").style.visibility = "hidden";

					}
			
					else {
						
						document.getElementById("pOn").style.visibility = "visible";

					}
			
				}

			}
  
			xmlhttp.open("GET", url, true);
			
			xmlhttp.send();

		}

		function setMode(val) {

			var oldUrl = url;
			url = url + "91" + val + "000";
			
			ajaxRequest();
			
			url = oldUrl;

		}

		function setTemp(val) {

			var oldUrl = url;
	
			if (val == 0)
		
				set--;
		
			if (val == 1)

				set++;
	
			url = url + "9001" + set;
			
			ajaxRequest();
			
			url = oldUrl;

		}

		window.onLoad = ajaxRequest();
		setInterval(ajaxRequest, 1000);

	</script>
</head>
<body>
	<div class="container">
		<h1><?php
				
        		if ($place != 0) {
				
					echo '<a href="show.php?place=';
					echo $place - 1;
					echo '">&lt;</a>';
			
				}
				
				else
				
					echo '&lt;';
				
				echo ' ' . $obj->desc . ' ';
				
				if ($place + 1 < $numRows) {
				
					echo ' <a href="show.php?place=';
					echo $place + 1;
					echo '">&gt;</a>';
				
				}
				
				else
				
					echo '&gt;';
				
			?></h1>
		<div class="content">
			<h1 id="temp">00.0&deg;C</h1>
			<div class="barElements">
				<h1>Set</h1>
				<div id="mOff">
					<a id="mOn" href="javascript:setTemp(0)"><img src="images/mOn.png" width="30" height="30" alt="-" /></a>
				</div>
				<h2 id="tSet">00</h2>
				<div id="pOff">
					<a id="pOn" href="javascript:setTemp(1)"><img src="images/pOn.png" width="30" height="30" alt="+" /></a>
				</div>
			</div>
			<div class="barElements">
				<h1>Mode</h1>
				<div id="offOn">
					<a id="offOff" href="javascript:setMode(0)"><img src="images/offOff.png" width="30" height="30" alt="Off" /></a>
				</div>
				<div id="onOn">
					<a id="onOff" href="javascript:setMode(1)"><img src="images/onOff.png" width="30" height="30" alt="On" /></a>
				</div>
				<div id="autoOn">
					<a id="autoOff" href="javascript:setMode(2)"><img src="images/autoOff.png" width="30" height="30" alt="Auto" /></a>
				</div>
			</div>
			<div class="barElements">
				<h1>Status</h1>
				<h2 id="info">null</h2>
			</div>
			<div class="barElements">
				<h1>Preferences</h1>
				<div class="ico">
					<a href="crono.php?hostId=<?php echo $obj->id; ?>"><img src="images/crono.png" width="30" height="30" alt="Crono" /></a>
				</div>
				<div class="ico">
					<a href="#"><img src="images/pref.png" width="30" height="30" alt="Preferences" /></a>
				</div>
			</div>
		</div>
		<div class="footer">
			<p>&copy; ThermoWeb <?php echo date("Y"); ?> | <a href="#">help</a> |</p>
		</div>
	</div>
</body>
</html>

E lo script in .php più importante, serve come proxy per aggirare le limitazioni del ajax:

<?php

	echo file_get_contents("http://".$_GET['addr'].":".$_GET['proto']."/?".$_GET['rqst']);

?>

Andrea, NON devi giustificarti, ti abbiamo spiegato una regola, ora tu hai completato la pubblicazione ed hai condiviso il tuo lavoro, non ti preoccupare della "bellezza", se qualcuno avrà dei dubbi ti chiederà, a questo serve aprire un Topic. Grazie!

complimenti d'avvero! ottimo lavoro! :astonished:

bel lavoro!

edit: non capisco bene il sistema che usi per comunicare i tempi di accensione (non ho visto il codice ma solo la stringa di risposta)

Se hai la precisione di un'ora e devi solo indicare acceso/spento, allora ti serve un array di 24 byte (1 byte per ora, dove i bit rappresentano i giorni: il bit 0 è il lunedì, il bit 1 il martedì, etc... e ti avanza pure un bit!) invece usi un array di 128 e non capisco il perchè

lesto: 1 byte per ora, dove i bit rappresentano i giorni: il bit 0 è il lunedì, il bit 1 il martedì, etc... e ti avanza pure un bit!

Per le festività :stuck_out_tongue_closed_eyes:

[quote author=Michele Menniti link=topic=141183.msg1060954#msg1060954 date=1357557003] Andrea, NON devi giustificarti, ti abbiamo spiegato una regola, ora tu hai completato la pubblicazione ed hai condiviso il tuo lavoro, non ti preoccupare della "bellezza", se qualcuno avrà dei dubbi ti chiederà, a questo serve aprire un Topic. Grazie! [/quote] E sono ben felice anch'io della condivisione.

E ti do pure un suggerimento. Raccogli tutto dentro ad un unico archivio compresso così faciliti il download a chi volesse scaricare il tuo lavoro per replicarlo o prendere spunti.

lesto: bel lavoro!

edit: non capisco bene il sistema che usi per comunicare i tempi di accensione (non ho visto il codice ma solo la stringa di risposta)

Se hai la precisione di un'ora e devi solo indicare acceso/spento, allora ti serve un array di 24 byte (1 byte per ora, dove i bit rappresentano i giorni: il bit 0 è il lunedì, il bit 1 il martedì, etc... e ti avanza pure un bit!) invece usi un array di 128 e non capisco il perchè

Ciao, se ho capito bene la tua domanda è come fa arduino a capire quale ora di quale giorno deve accendere il riscaldamento?

Lo script proxy in .php invia ad arduino "http://192.168.1.232:80/?123476121", dove 1234 è un controllo che ho aggiunto, non fa sicurezza ma evita risposte ad una richiesta che ha ricevuto erroneamente. Scusa nel primo post non c'era. Il micro elimina già i primi 5 caratteri che sono GET/? e incomincia dal 6° a convertire i caratteri che seguono. Per la conversione sfrutto il fatto che in ASCII i caratteri numerici da 0 a 9 sono il valore BCD preceduto da "0011" e quindi uso il comando "c & 15" per mascherare i primi 4 bit dal MSB. Puoi anche usare int(c) e sottrarre 48 in decimale.

Per la gestione oraria/giornaliera uso un array da 168 elementi di tipo byte ( 24 ore x 7 giorni ) ed effettivamente spreco 7 bit per elemento. Però risparmio in cicli macchina o almeno credo! :D

bhe sicuramente risparmi in mal di testa :)

però tolto 1234 ti rimane 76121, sono 5 numeri mentre ci sono 7 giorni... cosa mi sfugge?

Puoi anche usare int(c) e sottrarre 48 in decimale.

char e byte sono la stessa cosa, puoi fare c-48 senza fare cast, al massimo ti becchi un warning :)

lesto: bhe sicuramente risparmi in mal di testa :)

però tolto 1234 ti rimane 76121, sono 5 numeri mentre ci sono 7 giorni... cosa mi sfugge?

Puoi anche usare int(c) e sottrarre 48 in decimale.

char e byte sono la stessa cosa, puoi fare c-48 senza fare cast, al massimo ti becchi un warning :)

7 è per il case dello switchcase

6 è per il giorno della settimana dove lunedì = 0, martedì = 1 ecc fino a domenica = 6

1 e 2 sono decine e unità ricomposte e corrispondo alla fascia oraria 12.00 - 12.59

1 è acceso ( se 0 spento )

ah ok, pensavo che impostassi tutto un giorno in un colpo solo. invece col sistema dei bit rappresentanti il giorno è comodo lato programamzione impostare tutti i giorni di un orario. Un pò antiintuitivo per un umano :)

Consigli: Nel setup magari metti una specie di client ntp così orari sempre perfetti ;-) Poi non ho letto bene il codice (su un tablet é quasi impossibile) ma mi pare di aver capito che ogni volta salvi le programmazioni su EEPROM, avendo un PC a disposizione potresti fare una cosa lato server e mentre tieni delle programmazioni back up sulla EEPROM le altre le invia il server all'Arduino Certo non hai un sistema indipendente ma potresti anche gestire ogni cosa secondo per secondo ed anche gestire più cose (luci, temperature, prese ecc) con poche modifiche al codice

superlol: Consigli: Nel setup magari metti una specie di client ntp così orari sempre perfetti ;-) Poi non ho letto bene il codice (su un tablet é quasi impossibile) ma mi pare di aver capito che ogni volta salvi le programmazioni su EEPROM, avendo un PC a disposizione potresti fare una cosa lato server e mentre tieni delle programmazioni back up sulla EEPROM le altre le invia il server all'Arduino Certo non hai un sistema indipendente ma potresti anche gestire ogni cosa secondo per secondo ed anche gestire più cose (luci, temperature, prese ecc) con poche modifiche al codice

Per ntp ci avevo pensato, però non mi piace molto la libreria ethernet, non la trovo molto affidabile e meno la uso meglio è... però per aggiornare l' ora basta inviare una richiesta del tipo "http://192.168.1.232:80/?12345ssmmhhwddmmaa" e lo può fare uno script in .php

Per me la totale indipendenza di ogni nodo è veramente importante e la scelta di salvare ogni volta su EEPROM è praticamente obbligata.

Come da richiesta via MP allego anche la parte di crono.php. Non l’ ho pubblicata perchè non ancora completa.

        $json = json_decode(file_get_contents($url));
	
	$cnt = 0;
	
	for ($d = 0; $d < 7; $d++)
	
		for ($h = 0; $h < 24; $h++) {

			$prog[$d][$h] = $json[$cnt];
			$cnt++;
		
		}
		
	$days = array("<p>Luned&igrave;</p>", "<p>Marted&igrave;</p>", "<p>Mercoled&igrave;</p>", "<p>Gioved&igrave;</p>", "<p>Venerd&igrave;</p>", "<p>Sabato</p>", "<p>Domenica</p>");
	
	for ($d = 0; $d < 7; $d++) {

		echo "		" . $days[$d] . "\n";
		echo "		<table>\n";
			
		for ($x = 0; $x < 24; $x = $x + 6) {
					
			echo "			<tr>\n";
		
			for ($h = $x; $h < $x + 6; $h++) {
						
				if ($prog[$d][$h] == 0)
				
					echo '				<td>';
					
				elseif ($arduino->gSettimana - 1 == $d && $arduino->ore == $h)
				
					echo '				<td class="now">';
					
				else
					
					echo '				<td class="on">';
				
				echo '<a href="crono.php?hostId=' . $hostId . '&day=' . $d . '&hour=' . $h . '&ena=';
				
				if ($prog[$d][$h] == 0)
				
					echo '1">';
					
				else 
				
					echo '0">';
				
				if ($h < 10)
				
					echo '0';
				
				echo $h."</a></td>\n";
			}
			
			echo "			</tr>\n";
	
		}
		
		echo "		</table>\n";
	
	}

Complimenti andrea per il lavoro e la condivisione.

due domande, 1. dovresti postare anche lo schema elettrico dello shield da te progettato, altrimenti resta cmq un progetto monco

  1. secondo la tua esperienza (ed anche di altri che sono intervenuti), fare una cosa del genere tenendola tutta su arduino uno e' impossibile ? cioe' usando arduino+ethernet shield come webserver ? Non intendo come funzionalita', che credo sia replicabile, ma come grafica (la tua mi piace molto), il 328+wiz ha le potenzialita' necessarie ?

2(B). se non si puo' con arduino uno, si potrebbe forse con la Due ?

grazie

Per la grafica non è un problema, è solo css e le icone ( orologio, +, - ecc ). Il problema è il database utenti<->località e password per l’ autenticazione.